Переглянути джерело

Adding full manuscript maangement

Pierre-Yves Barriat 1 рік тому
батько
коміт
692de0a30c
100 змінених файлів з 13723 додано та 10 видалено
  1. 7 8
      MarkDown.md
  2. BIN
      MarkDown.pdf
  3. 103 0
      example/Makefile
  4. 7 0
      example/assets/base.yaml
  5. 14 0
      example/assets/biblio.bib
  6. BIN
      example/assets/example-image.png
  7. 62 0
      example/assets/inkscape-convert.py
  8. BIN
      example/assets/pandoc-crossref.exe
  9. 1 0
      example/assets/pandoc-scholar/.github/FUNDING.yml
  10. 48 0
      example/assets/pandoc-scholar/.github/workflows/ci.yml
  11. 59 0
      example/assets/pandoc-scholar/.github/workflows/release-docker.yml
  12. 96 0
      example/assets/pandoc-scholar/.github/workflows/release.yml
  13. 170 0
      example/assets/pandoc-scholar/ChangeLog.md
  14. 339 0
      example/assets/pandoc-scholar/LICENSE
  15. 126 0
      example/assets/pandoc-scholar/Makefile
  16. 326 0
      example/assets/pandoc-scholar/README.md
  17. 30 0
      example/assets/pandoc-scholar/archives.inc.mk
  18. 648 0
      example/assets/pandoc-scholar/csl/chicago-author-date.csl
  19. 203 0
      example/assets/pandoc-scholar/csl/jats.csl
  20. 19 0
      example/assets/pandoc-scholar/docker/alpine.Dockerfile
  21. 24 0
      example/assets/pandoc-scholar/docker/ubuntu.Dockerfile
  22. 1 0
      example/assets/pandoc-scholar/example/.gitignore
  23. 5 0
      example/assets/pandoc-scholar/example/Makefile
  24. 1916 0
      example/assets/pandoc-scholar/example/apa.csl
  25. 138 0
      example/assets/pandoc-scholar/example/article.md
  26. 13 0
      example/assets/pandoc-scholar/example/bibliography.bib
  27. 173 0
      example/assets/pandoc-scholar/example/rmarkdown-scholarpandoc.Rmd
  28. 21 0
      example/assets/pandoc-scholar/lua-filters/LICENSE
  29. 40 0
      example/assets/pandoc-scholar/lua-filters/README.md
  30. 37 0
      example/assets/pandoc-scholar/lua-filters/abstract-to-meta/README.md
  31. 55 0
      example/assets/pandoc-scholar/lua-filters/abstract-to-meta/abstract-to-meta.lua
  32. 59 0
      example/assets/pandoc-scholar/lua-filters/author-info-blocks/README.md
  33. 176 0
      example/assets/pandoc-scholar/lua-filters/author-info-blocks/author-info-blocks.lua
  34. 39 0
      example/assets/pandoc-scholar/lua-filters/bibexport/README.md
  35. 89 0
      example/assets/pandoc-scholar/lua-filters/bibexport/bibexport.lua
  36. 85 0
      example/assets/pandoc-scholar/lua-filters/cito/README.md
  37. 138 0
      example/assets/pandoc-scholar/lua-filters/cito/cito.lua
  38. 252 0
      example/assets/pandoc-scholar/lua-filters/diagram-generator/README.md
  39. 316 0
      example/assets/pandoc-scholar/lua-filters/diagram-generator/diagram-generator.lua
  40. 70 0
      example/assets/pandoc-scholar/lua-filters/include-files/README.md
  41. 48 0
      example/assets/pandoc-scholar/lua-filters/include-files/include-files.lua
  42. 49 0
      example/assets/pandoc-scholar/lua-filters/latex-hyphen/README.md
  43. 81 0
      example/assets/pandoc-scholar/lua-filters/latex-hyphen/latex-hyphen.lua
  44. 81 0
      example/assets/pandoc-scholar/lua-filters/lilypond/README.md
  45. 189 0
      example/assets/pandoc-scholar/lua-filters/lilypond/lilypond.lua
  46. 316 0
      example/assets/pandoc-scholar/lua-filters/minted/README.md
  47. 456 0
      example/assets/pandoc-scholar/lua-filters/minted/minted.lua
  48. 33 0
      example/assets/pandoc-scholar/lua-filters/multiple-bibliographies/README.md
  49. 110 0
      example/assets/pandoc-scholar/lua-filters/multiple-bibliographies/multiple-bibliographies.lua
  50. 68 0
      example/assets/pandoc-scholar/lua-filters/pagebreak/README.md
  51. 100 0
      example/assets/pandoc-scholar/lua-filters/pagebreak/pagebreak.lua
  52. 19 0
      example/assets/pandoc-scholar/lua-filters/pandoc-quotes.lua/LICENSE.txt
  53. 110 0
      example/assets/pandoc-scholar/lua-filters/pandoc-quotes.lua/README.md
  54. 474 0
      example/assets/pandoc-scholar/lua-filters/pandoc-quotes.lua/pandoc-quotes.lua
  55. 56 0
      example/assets/pandoc-scholar/lua-filters/plantuml/plantuml.lua
  56. 30 0
      example/assets/pandoc-scholar/lua-filters/plantuml/readme.md
  57. 91 0
      example/assets/pandoc-scholar/lua-filters/scholarly-metadata/README.md
  58. 185 0
      example/assets/pandoc-scholar/lua-filters/scholarly-metadata/scholarly-metadata.lua
  59. 60 0
      example/assets/pandoc-scholar/lua-filters/scrlttr2/README.md
  60. 161 0
      example/assets/pandoc-scholar/lua-filters/scrlttr2/scrlttr2.lua
  61. 47 0
      example/assets/pandoc-scholar/lua-filters/section-refs/README.md
  62. 137 0
      example/assets/pandoc-scholar/lua-filters/section-refs/section-refs.lua
  63. 52 0
      example/assets/pandoc-scholar/lua-filters/short-captions/README.md
  64. 37 0
      example/assets/pandoc-scholar/lua-filters/short-captions/short-captions.lua
  65. 42 0
      example/assets/pandoc-scholar/lua-filters/spellcheck/README.md
  66. 70 0
      example/assets/pandoc-scholar/lua-filters/spellcheck/spellcheck.lua
  67. 66 0
      example/assets/pandoc-scholar/lua-filters/table-short-captions/README.md
  68. 160 0
      example/assets/pandoc-scholar/lua-filters/table-short-captions/table-short-captions.lua
  69. 18 0
      example/assets/pandoc-scholar/lua-filters/track-changes/README.md
  70. 247 0
      example/assets/pandoc-scholar/lua-filters/track-changes/track-changes.lua
  71. 11 0
      example/assets/pandoc-scholar/lua-filters/wordcount/README.md
  72. 29 0
      example/assets/pandoc-scholar/lua-filters/wordcount/wordcount.lua
  73. 50 0
      example/assets/pandoc-scholar/pandoc-options.inc.mk
  74. 714 0
      example/assets/pandoc-scholar/scholar-filters/dkjson.lua
  75. 234 0
      example/assets/pandoc-scholar/scholar-filters/json-ld.lua
  76. 48 0
      example/assets/pandoc-scholar/scholar-filters/template-helper.lua
  77. BIN
      example/assets/pandoc-scholar/templates/images/arrow-down.png
  78. BIN
      example/assets/pandoc-scholar/templates/images/octocat-small.png
  79. BIN
      example/assets/pandoc-scholar/templates/images/pdf.png
  80. 119 0
      example/assets/pandoc-scholar/templates/pandoc-scholar.html
  81. 118 0
      example/assets/pandoc-scholar/templates/pandoc-scholar.jats
  82. 399 0
      example/assets/pandoc-scholar/templates/pandoc-scholar.latex
  83. 478 0
      example/assets/pandoc-scholar/templates/styles/pandoc-scholar.css
  84. BIN
      example/assets/pandoc-scholar/templates/template.docx
  85. 14 0
      example/assets/pandoc-scholar/writers/jsonld.lua
  86. 19 0
      example/assets/pd-chem-filter.lua
  87. 21 0
      example/assets/pd-image-filter.lua
  88. 109 0
      example/assets/pd-meta.py
  89. 54 0
      example/assets/pd-ref-filter.lua
  90. 28 0
      example/assets/submit-clean.py
  91. 311 0
      example/assets/submit-condense.py
  92. 68 0
      example/assets/submit-zip.py
  93. BIN
      example/docx_templates/template.docx
  94. 684 0
      example/html_templates/template.css
  95. 207 0
      example/html_templates/template.html
  96. 91 0
      example/manuscript.md
  97. 0 0
      example/old_makefile
  98. 0 2
      example/slides.md
  99. 386 0
      example/tex_templates/ieee.csl
  100. 33 0
      example/tex_templates/manuscript-SI.tex

+ 7 - 8
MarkDown.md

@@ -292,7 +292,7 @@ Some features are rendered only for PDF or HTML :
 
 ---
 
-# Markdown slides: Marp
+# Markdown for slides
 
 Replace `pandoc` command with `marp`
 
@@ -304,16 +304,11 @@ marp --bespoke.progress slides.md -o slides.html
 
 > don't forget to add `--bespoke.progress` if you want a progress status
 
----
-
-# A bigger document ? a report maybe ?
+Now you can take a look of the Markdown code of these **current slides** !
 
 ---
 
-# My last example: a scientific paper !
-
-#marp --allow-local-files --theme tum.css git_elic.md -o git_elic.pdf
-#marp --template bespoke --bespoke.progress --allow-local-files --theme tum.css git_elic.md -o git_elic.html
+# Markdown for a paper ?
 
 https://jaantollander.com/post/scientific-writing-with-markdown/
 
@@ -322,3 +317,7 @@ https://curvenote.com/blog/writing-a-scientific-paper-faster-myst-markdown
 https://github.com/MartinHeroux/pandoc_article_template
 
 https://phd.row1.ca/phd
+
+https://github.com/MartinHeroux/latex-paper-template
+
+https://github.com/MartinHeroux/markdown-latex-template


+ 103 - 0
example/Makefile

@@ -0,0 +1,103 @@
+# References to main files
+TEX_FILE_MASTER     = tex_templates/manuscript.tex
+TEX_FILE_SI         = tex_templates/manuscript-si.tex
+TEX_FILE_PANDOC     = tex_templates/manuscript-pd.tex
+ARTICLE_FILE        = manuscript.md
+TEX_META_FILE       = tex_templates/metadata.tex
+PANDOC_META_FILE    = tex_templates/metadata-pd.yaml
+
+# Programs used
+TEX_ENGINE 	        = xelatex
+TEX                 = latexmk -$(TEX_ENGINE) -interaction=nonstopmode -file-line-error -pdf
+PYTHON 	            = python3
+
+# Paths to templates
+CUSTOM_REFERENCE_PATH   = tex_templates
+TEMPLATE_FILE_HTML      = html_templates/template.html
+TEMPLATE_STYLE_HTML     = html_templates/template.css
+DOCX_REFERENCE_FILE     = docx_templates/template.docx
+TEMPLATE_FILE_LATEX     = tex_templates/manuscript-pd.tex
+CLASS_FILE_LATEX        = tex_templates/pi-article
+PANDOC_SCHOLAR_PATH     = assets/pandoc-scholar
+
+# Options for pandoc-scholar
+PANDOC_READER_OPTIONS   = --data-dir=assets
+PANDOC_READER_OPTIONS  += --defaults=assets/base
+
+PANDOC_LATEX_OPTIONS    = --pdf-engine=$(TEX_ENGINE)
+PANDOC_LATEX_OPTIONS   += --variable=documentclass:$(CLASS_FILE_LATEX)
+PANDOC_LATEX_OPTIONS   += --natbib
+PANDOC_LATEX_OPTIONS   += --citeproc
+
+# PANDOC_HTML_OPTIONS     = --toc --self-contained
+PANDOC_HTML_OPTIONS     = --toc
+PANDOC_EPUB_OPTIONS     = --toc
+
+# Filter for converting chemical formulas
+PANDOC_DOCX_OPTIONS	   := --lua-filter=./assets/pd-chem-filter.lua $(PANDOC_WRITER_OPTIONS)
+
+OUTFILE_PREFIX          = index
+DEFAULT_EXTENSIONS     ?= html doc
+
+include $(PANDOC_SCHOLAR_PATH)/Makefile
+
+# Must be prepended to the options, as has to come before citeproc
+# PANDOC_WRITER_OPTIONS := --filter=pandoc-xnos $(PANDOC_WRITER_OPTIONS)
+PANDOC_WRITER_OPTIONS := --filter=pandoc-crossref $(PANDOC_WRITER_OPTIONS)
+PANDOC_WRITER_OPTIONS += --lua-filter=./assets/pd-image-filter.lua
+PANDOC_WRITER_OPTIONS += --csl=$(CUSTOM_REFERENCE_PATH)/ieee.csl
+
+# Building with latexmk
+.PHONY: build
+build: $(TEX_FILE_SI) $(TEX_FILE_MASTER)
+	$(TEX) $(TEX_FILE_SI)
+	$(TEX) $(TEX_FILE_MASTER)
+
+# Converting all svgs to png using inkscape
+SVGS = $(wildcard figs/*.svg)
+
+.PHONY: svg2fig
+svg2fig: $(SVGS)
+	$(PYTHON) ./scripts/inkscape-convert.py $(SVGS)
+
+# Making a pandoc markdown file
+.PHONY: tex2md
+tex2md:
+	$(PYTHON) ./assets/pd-meta.py --tex $(TEX_META_FILE) --yaml $(PANDOC_META_FILE)
+	pandoc -s $(TEX_FILE_PANDOC) -o $(ARTICLE_FILE) \
+	--from latex --to markdown+smart+grid_tables \
+	--metadata-file $(PANDOC_META_FILE) \
+	--lua-filter=./assets/pd-image-filter.lua \
+	--lua-filter=./assets/pd-chem-filter.lua \
+	--lua-filter=./assets/pd-ref-filter.lua \
+	--default-image-extension=".png" \
+	--verbose --columns=100 \
+	--citeproc
+
+# Making a diff of the manuscript with latexdiff
+.PHONY: diff
+diff:
+	git latexdiff HEAD -- --main $(TEX_FILE_MASTER) \
+	--no-view --latexmk --ignore-makefile \
+	--packages=amsmath,hyperref,siunitx,cleveref,mhchem \
+	--exclude-safecmd=pubSI -o manuscript-diff.pdf --verbose
+
+# Custom make commands for pandoc-scholar
+tex:	$(addprefix $(OUTFILE_PREFIX).,latex)
+pdf:	$(addprefix $(OUTFILE_PREFIX).,pdf)
+docx:	$(addprefix $(OUTFILE_PREFIX).,docx)
+html:	$(addprefix $(OUTFILE_PREFIX).,html)
+epub:	$(addprefix $(OUTFILE_PREFIX).,epub)
+
+# Submission scripts
+.PHONY: submit-condense
+submit-condense:
+	$(PYTHON) ./assets/submit-condense.py
+
+.PHONY: submit-zip
+submit-zip:
+	$(PYTHON) ./assets/submit-zip.py
+
+.PHONY: submit-clean
+submit-clean:
+	$(PYTHON) ./assets/submit-clean.py --dir ./condensed

+ 7 - 0
example/assets/base.yaml

@@ -0,0 +1,7 @@
+verbosity: INFO
+
+# none, references, or javascript
+email-obfuscation: references
+
+# accept, reject, or all
+track-changes: all

+ 14 - 0
example/assets/biblio.bib

@@ -0,0 +1,14 @@
+
+@article{example,
+  title = {Example title},
+  volume = {1},
+  issn = {26256161},
+  number = {38},
+  journal = {Random journal},
+  doi = {10.1002/doi56261656},
+  author = {One, Author and Two, Author},
+  month = sep,
+  year = {2000},
+  pages = {111--112},
+  pmid = {26352027}
+}

BIN
example/assets/example-image.png


+ 62 - 0
example/assets/inkscape-convert.py

@@ -0,0 +1,62 @@
+import os
+import pathlib
+import sys
+import subprocess
+
+inkscape = None
+
+if os.name == 'nt':
+    # Possible paths to check for the installation
+    inkscapePaths = [
+        r"C:\Program Files\Inkscape\bin\inkscape.exe",
+        r"C:\Program Files\Inkscape\inkscape.exe",
+        r"C:\Program Files (x86)\Inkscape\bin\inkscape.exe",
+        r"C:\Program Files (x86)\Inkscape\inkscape.exe",
+    ]
+    for path in inkscapePaths:
+        if pathlib.Path(path).exists():
+            inkscape = path
+    if not inkscape:
+        print("Can't find Inkscape installation, aborting.")
+        sys.exit()
+
+elif os.name == 'posix':
+    inkscape = 'inkscape'
+
+print("Conversion started")
+
+for f in sys.argv[1:]:
+    fullpath = pathlib.Path(f)
+    if fullpath.exists() and fullpath.suffix == '.svg':
+        print(f"Converting {fullpath} to PNG")
+        p = subprocess.run([
+            inkscape,
+            "--export-background-opacity=1",
+            "--export-type=png",
+            "--export-dpi=400",
+            f"--export-filename={fullpath.with_suffix('.png')}",
+            fullpath,
+        ],
+                           stdin=subprocess.PIPE,
+                           stdout=subprocess.PIPE,
+                           stderr=subprocess.STDOUT,
+                           universal_newlines=True)
+
+        print(f"Converting {fullpath} to PDF")
+        subprocess.run([
+            inkscape,
+            "-T",
+            "--export-background-opacity=1",
+            "--export-type=pdf",
+            "--export-dpi=400",
+            f"--export-filename={fullpath.with_suffix('.pdf')}",
+            fullpath,
+        ],
+                       stdin=subprocess.PIPE,
+                       stdout=subprocess.PIPE,
+                       stderr=subprocess.STDOUT,
+                       universal_newlines=True)
+    else:
+        print(f"Path {f} does not exist")
+
+print("Complete")

BIN
example/assets/pandoc-crossref.exe


+ 1 - 0
example/assets/pandoc-scholar/.github/FUNDING.yml

@@ -0,0 +1 @@
+github: tarleb

+ 48 - 0
example/assets/pandoc-scholar/.github/workflows/ci.yml

@@ -0,0 +1,48 @@
+name: CI
+
+on:
+  pull_request:
+    paths-ignore:
+      - README.md
+      - ChangeLog.md
+      - LICENSE
+  push:
+    paths-ignore:
+      - README.md
+      - ChangeLog.md
+      - LICENSE
+
+jobs:
+  docker:
+    runs-on: ubuntu-18.04
+    strategy:
+      fail-fast: true
+      matrix:
+        distro:
+          - ubuntu
+          - alpine
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v2
+
+      - name: Create Docker image
+        run: |
+          docker build \
+              --tag pandocscholar/${{ matrix.distro }}:dev \
+              --file docker/${{ matrix.distro }}.Dockerfile \
+              .
+
+      - name: Run Docker on example
+        run: |
+          docker run --rm \
+                 --user "$(id -u):$(id -g)" \
+                 --volume "$(pwd)/example:/data" \
+                 pandocscholar/${{ matrix.distro }}:dev
+
+      - name: Login to Docker Hub
+        run: >-
+          echo "${{ secrets.DOCKER_HUB_TOKEN }}" |
+            docker login -u ${{ secrets.DOCKER_HUB_USERNAME }} --password-stdin
+
+      - name: Push dev image
+        run: docker push pandocscholar/${{ matrix.distro }}:dev

+ 59 - 0
example/assets/pandoc-scholar/.github/workflows/release-docker.yml

@@ -0,0 +1,59 @@
+name: Manual Docker release
+
+on:
+  workflow_dispatch:
+    inputs:
+      tag:
+        name: tag name
+        required: true
+        default: latest
+        description: Tag under which the images should be published.
+      is-latest:
+        name: "is latest?"
+        required: true
+        default: false
+        description: Whether the build is also the latest version.
+
+jobs:
+  docker:
+    name: Docker release
+    runs-on: ubuntu-18.04
+    strategy:
+      fail-fast: false
+      matrix:
+        distro:
+          - ubuntu
+          - alpine
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v2
+
+      - name: Create Docker image
+        run: |
+          docker build \
+              --tag pandocscholar/${{ matrix.distro }}:latest \
+              --file docker/${{ matrix.distro }}.Dockerfile \
+              .
+
+      - name: Run Docker on example
+        run: |
+          docker run --rm \
+                 --user "$(id -u):$(id -g)" \
+                 --volume "$(pwd)/example:/data" \
+                 pandocscholar/${{ matrix.distro }}:latest
+
+      - name: Login to Docker Hub
+        run: >-
+          echo "${{ secrets.DOCKER_HUB_TOKEN }}" |
+            docker login -u ${{ secrets.DOCKER_HUB_USERNAME }} --password-stdin
+
+      - name: Push image as latest
+        if: github.event.inputs.is-latest != false
+        run: docker push pandocscholar/${{ matrix.distro }}:latest
+
+      - name: Push image as tag
+        run: |
+          docker tag \
+              pandocscholar/${{ matrix.distro }}:latest \
+              pandocscholar/${{ matrix.distro }}:${{ github.event.inputs.tag }}
+          docker push pandocscholar/${{ matrix.distro }}:${{ github.event.inputs.tag }}

+ 96 - 0
example/assets/pandoc-scholar/.github/workflows/release.yml

@@ -0,0 +1,96 @@
+name: Release
+
+on:
+  push:
+    tags:
+      - v*
+
+jobs:
+  release:
+    name: Release Artifacts
+    runs-on: ubuntu-18.04
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v2
+
+      - name: Build collection
+        run: make archives
+
+      - name: Create release
+        id: create_release
+        uses: actions/create-release@v1
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        with:
+          tag_name: ${{ github.ref }}
+          release_name: pandoc-scholar ${{ github.ref }}
+          draft: false
+          prerelease: false
+
+      - name: Add zip archive to release
+        uses: actions/upload-release-asset@v1
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        with:
+          upload_url: ${{ steps.create_release.outputs.upload_url }}
+          asset_path: ./dist/pandoc-scholar.zip
+          asset_name: pandoc-scholar.zip
+          asset_content_type: application/zip
+
+      - name: Add tar archive to release
+        uses: actions/upload-release-asset@v1
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        with:
+          upload_url: ${{ steps.create_release.outputs.upload_url }}
+          asset_path: ./dist/pandoc-scholar.tar.gz
+          asset_name: pandoc-scholar.tar.gz
+          asset_content_type: application/x-gtar
+
+  docker:
+    name: Docker release
+    runs-on: ubuntu-18.04
+    strategy:
+      fail-fast: false
+      matrix:
+        distro:
+          - ubuntu
+          - alpine
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v2
+
+      - name: Create Docker image
+        run: |
+          docker build \
+              --tag pandocscholar/${{ matrix.distro }}:latest \
+              --file docker/${{ matrix.distro }}.Dockerfile \
+              .
+
+      - name: Run Docker on example
+        run: |
+          docker run --rm \
+                 --user "$(id -u):$(id -g)" \
+                 --volume "$(pwd)/example:/data" \
+                 pandocscholar/${{ matrix.distro }}:latest
+
+      - name: Login to Docker Hub
+        run: >-
+          echo "${{ secrets.DOCKER_HUB_TOKEN }}" |
+            docker login -u ${{ secrets.DOCKER_HUB_USERNAME }} --password-stdin
+
+      - name: Push image as latest
+        run: docker push pandocscholar/${{ matrix.distro }}:latest
+
+      - name: Push image as version
+        run: |
+          version=$(printf "${{ github.ref }}" | sed 's#.*v\(.*\)$#\1#')
+          if [ -n "${version}" ]; then
+              docker tag \
+                  pandocscholar/${{ matrix.distro }}:latest \
+                  pandocscholar/${{ matrix.distro }}:${version}
+              docker push pandocscholar/${{ matrix.distro }}:${version}
+          else
+              printf "Could not determine version" >&2
+              exit 1
+          fi

+ 170 - 0
example/assets/pandoc-scholar/ChangeLog.md

@@ -0,0 +1,170 @@
+ChangeLog
+=========
+
+v2.3.0
+------
+
+Released 2020-12-01
+
+- Turned `example` dir into standalone example. The example is now
+  clearer about how pandoc-scholar can be used when it was installed
+  in a central location.
+
+- Provide Docker images. Each new release is now accompanied by
+  Docker images bundling all basic requirements into a single
+  container. See the README for more info.
+
+- Updated the LaTeX template. The template incorporates improvements
+  from the latest pandoc version and will now also work with pandoc
+  2.11.
+  
+- Renamed class given to the `<div>` wrapper around author
+  affiliations. The class was named `author_affiliations`, but the
+  CSS styles assumed `author-affiliations`. The HTML markup has been
+  updated to match the CSS.
+
+- Removed unneeded files from lua-filters. Files for testing have
+  been dropped; only the filter files and docs are kept. The next
+  major version will also change the directory structure below
+  `lua-filters` and get rid of the separate subdirectories for each
+  filter.
+
+v2.2.2
+------
+
+Released 2020-06-17
+
+- Update Lua filters to their most recent versions. This includes
+  a fix to the abstract-to-meta filter, which would sometimes
+  produce wrong results when used with pandoc 2.8 or newer.
+
+v2.2.1
+------
+
+Released 2020-04-25
+
+- Fixed incorrect path in JATS target: a file in the dependency
+  list of the JATS target was missing was missing a path prefix,
+  causing make to fail the Makefile was included in a different
+  directory.
+
+- Fixed bibliography and citation handling in JATS: citations
+  were formatted incorrectly if no CSL file was given. We also
+  make sure that `PANDOC_READER_OPTIONS` are respected for JATS.
+
+- Simplify bibliography handling for JSON-LD: it is now
+  sufficient to define a bibliography field in the article
+  metadata. Previously, JSON-LD generation failed unless the
+  `BIBLIOGRAPHY_FILE` variable was set; the requirement for this
+  variable has been removed.
+
+v2.2.0
+------
+
+Released 2020-04-21
+
+- Running `make clean` is now ensured to only remove generated
+  files (Sam Hiatt).
+
+- JATS support has been improved and produces valid JATS 1.2
+  documents using the Journal Archiving and Interchange tag set.
+  Bibliography entries in the documents are formatted with the
+  given CSL style.
+
+- The default LaTeX template has been updated to work with pandoc
+  2.9.
+
+  + The options for the natbib package can be passed via the
+    `natbiboptions` variable.
+
+  + A new environment `cslreferences` is defined. It is used to
+    contain pandoc-citeproc generated bibliographies.
+
+- New make target `default` has been introduced. It is run
+  instead of target `all` when make is called a specific target.
+
+- The example is now generated with links between examples and
+  references. Furthermore, the CSL file is explicitly defined to
+  make it clearer how an alternative style can be used.
+
+- The pandoc and pandoc-citeproc executables can now be set via
+  the `PANDOC` and `PANDOC_CITEPROC` variables, respectively.
+  The default is to use the binaries in the user's PATH.
+
+v2.1.1
+------
+
+Released 2019-04-16
+
+### Lua filters
+
+- Fix a bug which caused separators to be inserted even for
+  single authors. (#33)
+
+v2.1.0
+------
+
+Released 2019-01-16.
+
+### Templates
+
+- Removed a newline in the HTML template which caused an extra
+  space be inserted before institute addresses (Benjamin Lee).
+
+- Include subtitle in PDF output (solution taken from pandoc,
+  courtesy of Andrew Dunning).
+
+v2.0.1
+------
+
+Released 2018-12-26.
+
+### Makefile
+
+- Fix option for docx reference documents. (Mitchell Paulus)
+
+- Fix option for odt reference documents.
+
+### Lua filters
+
+- Fix filters for pandoc 2.3 and later; older versions should
+  continue to work.
+
+- author-info-blocks:
+
+  + Fix LaTeX output, surround `\dagger` with dollars.
+
+  + Keep authors as a list instead of joining them into a single
+    entry when the output is LaTeX. This fixes LaTeX layout
+    issues when many authors are given.
+
+- pagebreak: New filter to convert `\newpage` commands into
+  target-format appropriate page breaks. Not enabled by default.
+
+- multiple-bibliographies: a filter which allows the creation of
+  multiple bibliographies using `pandoc-citeproc`.
+  Not enabled by default.
+
+
+v2.0.0
+------
+
+- Update to pandoc 2. Pandoc scholar now requires pandoc 2.1 or later.
+
+- The internal document transformation system has been mostly
+  rewritten. Instead of custom writers based on panlunatic, the
+  new version now uses pandoc Lua filters. This builds on a
+  well-tested system and removes some bugs due caused by
+  panlunatic. Lua filters are also easier to use separately.
+  E.g., using Lua filters allows to integrate desired
+  functionality into a RMarkdown workflow.
+
+- Added support for CiTO property
+  *cites\_as\_recommended\_reading*.
+
+- Add missing author affiliations in HTML output (Thomas Sibley).
+
+- JATS support no longer relies on a custom writer; output is
+  generated directly via pandoc.
+
+- Fixed sub/sup styling in HTML output

+ 339 - 0
example/assets/pandoc-scholar/LICENSE

@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.

+ 126 - 0
example/assets/pandoc-scholar/Makefile

@@ -0,0 +1,126 @@
+## The path to the directory in which this file resides. This allows users to
+## include this Makefile into theirs and to reuse all rules, given that they set
+## this variable to the correct value.
+PANDOC_SCHOLAR_PATH   ?= $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
+
+# include local makefile to allow easy overwriting of variables
+-include local.mk
+include $(PANDOC_SCHOLAR_PATH)/pandoc-options.inc.mk
+
+LUA_FILTERS_PATH      ?= $(PANDOC_SCHOLAR_PATH)/lua-filters
+
+PANDOC ?= pandoc
+
+# Configuration (overwrite using Makefile.local.in if necessary)
+ARTICLE_FILE          ?= example/article.md
+OUTFILE_PREFIX        ?= outfile
+DEFAULT_EXTENSIONS    ?= latex pdf docx odt epub html
+ADDITIONAL_EXTENSIONS ?= xml jats jsonld txt
+JSON_FILE             ?= $(OUTFILE_PREFIX).enriched.json
+FLATTENED_JSON_FILE   ?= $(OUTFILE_PREFIX).flattened.json
+LUA_FILTERS           ?= $(LUA_FILTERS_PATH)/cito/cito.lua \
+                         $(LUA_FILTERS_PATH)/abstract-to-meta/abstract-to-meta.lua \
+                         $(LUA_FILTERS_PATH)/scholarly-metadata/scholarly-metadata.lua
+
+default: $(addprefix $(OUTFILE_PREFIX).,$(DEFAULT_EXTENSIONS))
+
+all: $(addprefix $(OUTFILE_PREFIX).,$(DEFAULT_EXTENSIONS)) \
+     $(addprefix $(OUTFILE_PREFIX).,$(ADDITIONAL_EXTENSIONS))
+
+$(JSON_FILE): $(ARTICLE_FILE) $(LUA_FILTERS)
+	$(PANDOC) $(PANDOC_READER_OPTIONS) \
+		     $(foreach filter, $(LUA_FILTERS), --lua-filter=$(filter)) \
+	       --to=json \
+	       --output=$@ $<
+
+$(OUTFILE_PREFIX).pdf $(OUTFILE_PREFIX).latex: \
+		$(JSON_FILE) \
+		$(TEMPLATE_FILE_LATEX) \
+		$(PANDOC_SCHOLAR_PATH)/scholar-filters/template-helper.lua
+	$(PANDOC) $(PANDOC_WRITER_OPTIONS) \
+	       $(PANDOC_LATEX_OPTIONS) \
+	       --lua-filter=$(PANDOC_SCHOLAR_PATH)/scholar-filters/template-helper.lua \
+	       --output $@ $<
+
+$(OUTFILE_PREFIX).docx: $(JSON_FILE) \
+		$(DOCX_REFERENCE_FILE) \
+		$(LUA_FILTERS_PATH)/author-info-blocks/author-info-blocks.lua
+	$(PANDOC) $(PANDOC_WRITER_OPTIONS) \
+	       $(PANDOC_DOCX_OPTIONS) \
+	       --lua-filter=$(LUA_FILTERS_PATH)/author-info-blocks/author-info-blocks.lua \
+	       --output $@ $<
+
+$(OUTFILE_PREFIX).odt: $(JSON_FILE) \
+		$(ODT_REFERENCE_FILE) \
+		$(LUA_FILTERS_PATH)/author-info-blocks/author-info-blocks.lua
+	$(PANDOC) $(PANDOC_WRITER_OPTIONS) \
+	       $(PANDOC_ODT_OPTIONS) \
+	       --lua-filter=$(LUA_FILTERS_PATH)/author-info-blocks/author-info-blocks.lua \
+	       --output $@ $<
+
+$(OUTFILE_PREFIX).epub: $(JSON_FILE) \
+		$(TEMPLATE_FILE_EPUB) \
+		$(LUA_FILTERS_PATH)/author-info-blocks/author-info-blocks.lua
+	$(PANDOC) $(PANDOC_WRITER_OPTIONS) \
+	       $(PANDOC_EPUB_OPTIONS) \
+	       --lua-filter=$(LUA_FILTERS_PATH)/author-info-blocks/author-info-blocks.lua \
+	       --output $@ $<
+
+$(OUTFILE_PREFIX).html: $(JSON_FILE) \
+		$(TEMPLATE_FILE_HTML) \
+		$(TEMPLATE_STYLE_HTML) \
+		$(PANDOC_SCHOLAR_PATH)/scholar-filters/template-helper.lua
+	$(PANDOC) $(PANDOC_WRITER_OPTIONS) \
+	       $(PANDOC_HTML_OPTIONS) \
+	       --lua-filter=$(PANDOC_SCHOLAR_PATH)/scholar-filters/template-helper.lua \
+	       --css=$(TEMPLATE_STYLE_HTML) \
+	       --mathjax \
+	       --output $@ $<
+
+$(OUTFILE_PREFIX).jsonld: $(JSON_FILE) \
+		$(BIBLIOGRAPHY_FILE) \
+		$(PANDOC_SCHOLAR_PATH)/scholar-filters/json-ld.lua \
+		$(PANDOC_SCHOLAR_PATH)/writers/jsonld.lua
+	$(PANDOC) --to $(PANDOC_SCHOLAR_PATH)/writers/jsonld.lua \
+	       --lua-filter=$(PANDOC_SCHOLAR_PATH)/scholar-filters/json-ld.lua \
+	       --output=$@ $<
+
+$(OUTFILE_PREFIX).txt: $(ARTICLE_FILE)
+	$(PANDOC) $(PANDOC_WRITER_OPTIONS) \
+	       --output $@ $<
+
+## The JSON file is required only for metadata (csl) extraction
+## by the jats-fixes.lua script, as pandoc overrides the CSL
+## field when converting to JATS.
+$(OUTFILE_PREFIX).jats $(OUTFILE_PREFIX).xml: $(ARTICLE_FILE) \
+		$(JSON_FILE) \
+		$(PANDOC_SCHOLAR_PATH)/templates/pandoc-scholar.jats \
+		$(PANDOC_SCHOLAR_PATH)/scholar-filters/jats-fixes.lua \
+		$(PANDOC_SCHOLAR_PATH)/scholar-filters/template-helper.lua \
+		$(PANDOC_SCHOLAR_PATH)/csl/chicago-author-date.csl \
+		$(PANDOC_SCHOLAR_PATH)/csl/jats.csl
+	$(PANDOC) \
+	       $(PANDOC_WRITER_OPTIONS) \
+	       $(PANDOC_JATS_OPTIONS) \
+		     $(foreach filter, $(LUA_FILTERS), --lua-filter=$(filter)) \
+	       --lua-filter=$(PANDOC_SCHOLAR_PATH)/scholar-filters/template-helper.lua \
+	       --to=jats_articleauthoring+element_citations \
+	       --output $@ $<
+
+clean:
+ifeq ($(OS),Windows_NT)
+	del $(OUTFILE_PREFIX).docx $(OUTFILE_PREFIX).epub $(OUTFILE_PREFIX).html
+	del $(OUTFILE_PREFIX).odt $(OUTFILE_PREFIX).latex $(OUTFILE_PREFIX).pdf
+	del $(JSON_FILE) $(FLATTENED_JSON_FILE)
+else
+	for ext in $(DEFAULT_EXTENSIONS) $(ADDITIONAL_EXTENSIONS); do\
+		rm -f $(OUTFILE_PREFIX).$$ext;\
+	done
+	rm -f $(JSON_FILE) $(FLATTENED_JSON_FILE)
+endif
+
+.PHONY: all clean
+
+# Include archive-generating targets. This makefile is not included in the
+# distributed archives
+-include archives.inc.mk

+ 326 - 0
example/assets/pandoc-scholar/README.md

@@ -0,0 +1,326 @@
+pandoc-scholar
+==============
+
+[![release shield]](https://github.com/pandoc-scholar/pandoc-scholar/releases)
+[![DOI]](https://zenodo.org/badge/latestdoi/82204858)
+[![license shield]](./LICENSE)
+[![Build status][GitHub Actions badge]][GitHub Actions]
+
+Create beautiful, semantically enriched articles with pandoc. This
+package provides utilities to make publishing of scientific articles as
+simple and pleasant as possible. It simplifies setting authors' metadata
+in YAML blocks, allows to add semantic annotation to citations, and only
+requires the programs pandoc and make.
+
+[release shield]: https://img.shields.io/github/release/pandoc-scholar/pandoc-scholar.svg
+[license shield]: https://img.shields.io/github/license/pandoc-scholar/pandoc-scholar.svg
+[GitHub Actions badge]: https://img.shields.io/github/workflow/status/pandoc-scholar/pandoc-scholar/CI?logo=github
+[GitHub Actions]: https://github.com/pandoc-scholar/pandoc-scholar/actions
+[DOI]: https://zenodo.org/badge/82204858.svg
+
+Overview
+--------
+
+Plain pandoc is already excellent at document conversion, but it lacks
+in metadata handling. Pandoc-scholar offers simple ways to include
+metadata on authors, affiliations, contact details, and citations. The
+data is included into the final output as document headers. Additionally
+all entries can be exported as [JSON-LD], a standardized format for the
+semantic web.
+
+The background leading to the development of pandoc-scholar is described
+in the [paper published in PeerJ Computer Science][paper].
+
+Note that since version 2.0, most of the functionality of pandoc-scholar
+is now provided via [pandoc Lua filters]. If you prefer to mix-and-match
+selected functionalities provided by pandoc-scholar, you can now use the
+respective Lua filters directly. Integration with tools like RMarkdown
+is possible this way.
+
+[paper]: https://peerj.com/articles/cs-112/
+[JSON-LD]: https://en.wikipedia.org/wiki/JSON-LD
+[pandoc Lua filters]: https://github.com/pandoc/lua-filters
+
+### Demo
+
+An example document plus bibliography is provided in the *example*
+folder. Running `make` in the *example* folder will process the
+example article, generating output like below:
+
+![example article screenshot](https://pandoc-scholar.github.io/example/header.png)
+
+Get the full output as [pdf], [docx], or [epub], or take a look at the
+metadata in [JSON-LD] format.
+
+[pdf]: https://pandoc-scholar.github.io/example/example.pdf
+[docx]: https://pandoc-scholar.github.io/example/example.docx
+[epub]: https://pandoc-scholar.github.io/example/example.epub
+[JSON-LD]: https://pandoc-scholar.github.io/example/example.jsonld
+
+Usage via Docker
+----------------
+
+A very easy way to use pandoc-scholar is via Docker. The ready-made
+images contain all necessary software to generate a paper in
+multiple formats. This avoids any compatibility concerns; only
+Docker is required.
+
+The official images are in the [pandocscholar/ubuntu] and
+[pandocscholar/alpine] images. The Alpine image is a bit smaller,
+while the Ubuntu image may be more familiar for people looking to
+extend the image. Both images come with pandoc, pandoc-citeproc,
+pandoc-crossref, and LaTeX.
+
+### Example call
+
+Docker commands are often unwieldly due to the additional arguments.
+We recommend to define an alias or short script to simplify its use.
+
+Given an article in file `my-research-article.md` and a simple
+Makefile like
+
+```makefile
+ARTICLE_FILE = my-research-article.md
+OUTFILE_PREFIX = out
+include $(PANDOC_SCHOLAR_PATH)/Makefile
+```
+
+the conversion can be performed by running
+
+    docker run --rm -v "$(pwd):/data" -u "$(id -u)" pandocscholar/alpine
+
+This will generate a set of files whose names all start with `out.`.
+Please be aware that existing files of the same name will be
+overwritten. The pandoc-scholar container calls `make` internally;
+additional commands and options can be passed by appending them the
+above command.
+
+The images are based upon the official pandoc images; for more info
+and usage examples, see the [pandoc/dockerfiles] GitHub repo. The
+Docker images can easily be used in automatic document conversion
+pipelines; [pandoc-actions-example] gives a good overview.
+
+A major difference between pandoc and pandoc-scholar images is that
+pandoc-scholar doesn't use `pandoc` but `make` as entrypoint. A
+basic Makefile must be present in the article directory when running
+pandoc-scholar.
+
+[pandoc/dockerfiles]: https://github.com/pandoc/dockerfiles
+[pandoc-actions-example]: https://github.com/pandoc/pandoc-action-example
+
+Prerequisites
+-------------
+
+This package builds on [pandoc](http://pandoc.org/), the universal
+document converter. See the pandoc website for [installation
+instructions](http://pandoc.org/installing.html) and suggestions for
+LaTeX packages, which we use for PDF generation.
+
+Starting with pandoc-scholar 3.0.0, the minimum required pandoc version
+is 2.11. If you have to use an older pandoc, please combine it with the
+last 2.* release of pandoc-scholar.
+
+Also note that pandoc's JATS support, especially citation handling, was
+buggy prior to pandoc v2.11.4. Please use that or a newer version when
+producing JATS XML.
+
+Installation
+------------
+
+Archives containing all required files are provided for each release.
+Use the *release* button above (or directly go to the [latest release])
+and download a `pandoc-scholar` archive; both archive files, `.zip` and
+`.tar.gz`, contain the same files. Choose the filetype that is the
+easiest to unpack on you system.
+
+A `pandoc-scholar` folder will be created on unpacking. The folder
+contains all required scripts and templates.
+
+[latest release]: https://github.com/pandoc-scholar/pandoc-scholar/releases/latest
+
+
+Usage
+-----
+
+### Quickstart
+
+Run `make` to convert the example article into all supported output formats. The
+markdown file used to create the output files can be configured via the
+`ARTICLE_FILE` variable, either directly in the Makefile or by specifying the
+value on the command line.
+
+    make ARTICLE_FILE=your-file.md
+
+### Includable Makefile
+
+The *Makefile*, which does most of the work, is written in a style that makes it
+simple to include it from within other Makefiles. This method allows to keep
+`pandoc-scholar` installed in a central location and to use the same instance
+for multiple projects. The `ARTICLE_FILE` and `PANDOC_SCHOLAR_PATH` variables
+must be defined in the including Makefile:
+
+``` Makefile
+ARTICLE_FILE        = your-file.md
+PANDOC_SCHOLAR_PATH = ../path-to-pandoc-scholar-folder
+include $(PANDOC_SCHOLAR_PATH)/Makefile
+```
+
+Calling `make` as usual will create all configured output formats. Per default,
+this creates *pdf*, *latex*, *docx*, *odt*, *epub*, *html*, and *jats* output.
+The set of output files can be reduced by setting the `DEFAULT_EXTENSIONS`
+variable to a subset of the aforementioned formats. For example `DEFAULT_EXTENSIONS = pdf odt docx`
+
+Alternative template files can be set using `TEMPLATE_FILE_<FORMAT>` variables,
+where `<FORMAT>` is one of *HTML*, *EPUB*, *JATS*, or *LATEX*. The reference
+files for ODT and DOCX output can be changed using `ODT_REFERENCE_FILE` and
+`DOCX_REFERENCE_FILE`, respectively.
+
+Additional pandoc options can be given on a per-format basis using
+`PANDOC_<FORMAT>_OPTIONS` variables. The following uses an actual Makefile as an
+example to demonstrate usage of those options.
+
+``` Makefile
+ARTICLE_FILE        = open-science-formatting.md
+
+PANDOC_LATEX_OPTIONS  = --latex-engine=xelatex
+PANDOC_LATEX_OPTIONS += --csl=peerj.csl
+PANDOC_LATEX_OPTIONS += --filter=pandoc-citeproc
+PANDOC_LATEX_OPTIONS += -M fontsize=10pt
+PANDOC_LATEX_OPTIONS += -M classoption=fleqn
+
+PANDOC_HTML_OPTIONS   = --toc
+PANDOC_EPUB_OPTIONS   = --toc
+
+DOCX_REFERENCE_FILE   = pandoc-manuscript.docx
+ODT_REFERENCE_FILE    = pandoc-manuscript.odt
+TEMPLATE_FILE_LATEX   = pandoc-peerj.latex
+
+PANDOC_SCHOLAR_PATH = pandoc-scholar
+include $(PANDOC_SCHOLAR_PATH)/Makefile
+```
+
+
+Metadata Features
+-----------------
+
+Pandoc-scholar supports additional functionality via metadata fields. Most
+notably, the augmentation of articles with author and affiliation data, which is
+essential for academic publishing, is greatly simplified when using
+pandoc-scholar.
+
+### Authors and affiliations
+
+Most metadata should be specified in the YAML block at the top of the article.
+Author data and affiliations are taken from the *author* and *institute* field,
+respectively. Institutes can be given via user-defined abbreviations, saving
+unnecessary repetitions while preserving readability.
+
+Example:
+
+``` yaml
+author:
+  - James Dewey Watson:
+      institute: cavendish
+  - Francis Harry Compton Crick:
+      institute: cavendish
+institute:
+  - cavendish: Cavendish Laboratory, Cambridge
+```
+
+Authors are given in the order in which they are listed, while institute order
+follows from author order.
+
+The separate institute field may add unwanted complexity in some cases. It is
+hence possible to omit it and to give the affiliations name directly in the
+author entry:
+
+``` yaml
+author:
+  - John MacFarlane:
+      institute: University of California, Berkeley
+```
+
+### Institute address
+
+Often it is not enough to give just a name for institutes. It is hence possible
+to add arbitrary fields. The name must then explicitly be set via the *name*
+field of the institute entry:
+
+``` yaml
+author:
+  - Robert Winkler:
+      institute: cinvestav
+institute:
+  - cinvestav:
+      name: 'CINVESTAV Unidad Irapuato, Department of Biochemistry and Biotechnology'
+      address: 'Km. 9.6 Libramiento Norte Carr. Irapuato-León, 36821 Irapuato Gto. México'
+      phone: +52 (462) 623 9635
+```
+
+Currently only the institute's address is used in the default template, but
+future extensions will be based on this convention.
+
+### Semantic citations
+
+Understanding the reason a citations is included in scholarly articles usually
+requires natural language processing of the article. However, navigating the
+current literature landscape can be improved and by having that information
+accesible and in a machine-readable form. Pandoc-scholar supports the CiTO
+ontology, allowing authors to specify important meta-information on the citation
+directly while writing the text. The property is simply prepended to the
+citation key, separated by a colon: `@<property>:citationKey`.
+
+The following table contains all supported keywords and the respective
+CiTO properties. Authors are free to use the short-form, the full-length
+property, or any of the alternatives listed below (i.e., all word in a
+row denote the property and have the same effect).
+
+CiTO property                  | Keyword             | alternatives
+------------------------------ | ------------------- | ---------------------
+agrees\_with                   | agrees\_with        | agree\_with
+citation                       |                     |
+cites                          |                     |
+cites\_as\_authority           | authority           | as\_authority
+cites\_as\_data\_source        | data\_source        | as\_data_source
+cites\_as\_evidence            | evidence            | as\_evidence
+cites\_as\_metadata\_document  | metadata            | as\_metadata_document
+cites\_as\_recommended_reading | recommended_reading | as\_recommended\_reading
+disputes                       |                     |
+documents                      |                     |
+extends                        |                     |
+includes\_excerpt\_from        | excerpt             | excerpt\_from
+includes\_quotation\_from      | quotation           | quotation\_from
+obtaines\_background\_from     | background          | background\_from
+refutes                        |                     |
+replies\_to                    |                     |
+updates                        |                     |
+uses\_data\_from               | data\_from          | data
+uses\_method\_in               | method              | method\_in
+
+Example:
+
+    DNA strands form a double-helix [@evidence:watson_crick_1953].
+
+
+License
+-------
+
+Copyright © 2016–2021 Albert Krewinkel and Robert Winkler except for the
+following components:
+
+- HTML template: © 2016 Andrew G. York and Diana Mounter
+- dkjson: © 2010-2013 David Heiko Kolf
+- lua-filters: © 2017-2021 Albert Krewinkel, John MacFarlane, and contributors.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
+Street, Fifth Floor, Boston, MA 02110-1301 USA.

+ 30 - 0
example/assets/pandoc-scholar/archives.inc.mk

@@ -0,0 +1,30 @@
+# Generate Archives for distribution
+# ==================================
+
+archives: dist/pandoc-scholar.zip dist/pandoc-scholar.tar.gz
+
+dist/pandoc-scholar: \
+		csl \
+		$(LUA_FILTERS_PATH) \
+		scholar-filters \
+		LICENSE README.md \
+		Makefile pandoc-options.inc.mk \
+		example templates writers
+	rm -rf $@
+	mkdir -p $@
+	cp -av $^ $@
+
+dist/pandoc-scholar.tar.gz: dist/pandoc-scholar
+	rm -f $@
+	tar zvcf $@ -C $(dir $<) $(notdir $<)
+
+dist/pandoc-scholar.zip: dist/pandoc-scholar
+	rm -f $@
+	(cd $(dir $<) && zip -r $(notdir $@) $(notdir $<))
+
+clean-archives:
+	rm -rf dist
+
+dist-clean: clean-archives
+
+.PHONY: archives clean-archives dist-clean

+ 648 - 0
example/assets/pandoc-scholar/csl/chicago-author-date.csl

@@ -0,0 +1,648 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="display-and-sort" page-range-format="chicago">
+  <info>
+    <title>Chicago Manual of Style 17th edition (author-date)</title>
+    <id>http://www.zotero.org/styles/chicago-author-date</id>
+    <link href="http://www.zotero.org/styles/chicago-author-date" rel="self"/>
+    <link href="http://www.chicagomanualofstyle.org/tools_citationguide.html" rel="documentation"/>
+    <author>
+      <name>Julian Onions</name>
+      <email>julian.onions@gmail.com</email>
+    </author>
+    <contributor>
+      <name>Sebastian Karcher</name>
+    </contributor>
+    <contributor>
+      <name>Richard Karnesky</name>
+      <email>karnesky+zotero@gmail.com</email>
+      <uri>http://arc.nucapt.northwestern.edu/Richard_Karnesky</uri>
+    </contributor>
+    <contributor>
+      <name>Andrew Dunning</name>
+      <email>andrew.dunning@utoronto.ca</email>
+      <uri>https://orcid.org/0000-0003-0464-5036</uri>
+    </contributor>
+    <contributor>
+      <name>Matthew Roth</name>
+      <email>matthew.g.roth@yale.edu</email>
+      <uri> https://orcid.org/0000-0001-7902-6331</uri>
+    </contributor>
+    <category citation-format="author-date"/>
+    <category field="generic-base"/>
+    <summary>The author-date variant of the Chicago style</summary>
+    <updated>2018-01-24T12:00:00+00:00</updated>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
+  </info>
+  <locale xml:lang="en">
+    <terms>
+      <term name="editor" form="verb-short">ed.</term>
+      <term name="container-author" form="verb">by</term>
+      <term name="translator" form="verb-short">trans.</term>
+      <term name="editortranslator" form="verb">edited and translated by</term>
+      <term name="translator" form="short">trans.</term>
+    </terms>
+  </locale>
+  <macro name="secondary-contributors">
+    <choose>
+      <if type="chapter entry-dictionary entry-encyclopedia paper-conference" match="none">
+        <group delimiter=". ">
+          <names variable="editor translator" delimiter=". ">
+            <label form="verb" text-case="capitalize-first" suffix=" "/>
+            <name and="text" delimiter=", "/>
+          </names>
+          <names variable="director" delimiter=". ">
+            <label form="verb" text-case="capitalize-first" suffix=" "/>
+            <name and="text" delimiter=", "/>
+          </names>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="container-contributors">
+    <choose>
+      <if type="chapter entry-dictionary entry-encyclopedia paper-conference" match="any">
+        <group prefix=", " delimiter=", ">
+          <names variable="container-author" delimiter=", ">
+            <label form="verb" suffix=" "/>
+            <name and="text" delimiter=", "/>
+          </names>
+          <names variable="editor translator" delimiter=", ">
+            <label form="verb" suffix=" "/>
+            <name and="text" delimiter=", "/>
+          </names>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="editor">
+    <names variable="editor">
+      <name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
+      <label form="short" prefix=", "/>
+    </names>
+  </macro>
+  <macro name="translator">
+    <names variable="translator">
+      <name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
+      <label form="short" prefix=", "/>
+    </names>
+  </macro>
+  <macro name="recipient">
+    <choose>
+      <if type="personal_communication">
+        <choose>
+          <if variable="genre">
+            <text variable="genre" text-case="capitalize-first"/>
+          </if>
+          <else>
+            <text term="letter" text-case="capitalize-first"/>
+          </else>
+        </choose>
+      </if>
+    </choose>
+    <names variable="recipient" delimiter=", ">
+      <label form="verb" prefix=" " text-case="lowercase" suffix=" "/>
+      <name and="text" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="substitute-title">
+    <choose>
+      <if type="article-magazine article-newspaper review review-book" match="any">
+        <text macro="container-title"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="contributors">
+    <group delimiter=". ">
+      <names variable="author">
+        <name and="text" name-as-sort-order="first" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
+        <label form="short" prefix=", "/>
+        <substitute>
+          <names variable="editor"/>
+          <names variable="translator"/>
+          <names variable="director"/>
+          <text macro="substitute-title"/>
+          <text macro="title"/>
+        </substitute>
+      </names>
+      <text macro="recipient"/>
+    </group>
+  </macro>
+  <macro name="contributors-short">
+    <names variable="author">
+      <name form="short" and="text" delimiter=", " initialize-with=". "/>
+      <substitute>
+        <names variable="editor"/>
+        <names variable="translator"/>
+        <names variable="director"/>
+        <text macro="substitute-title"/>
+        <text macro="title"/>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="interviewer">
+    <names variable="interviewer" delimiter=", ">
+      <label form="verb" prefix=" " text-case="capitalize-first" suffix=" "/>
+      <name and="text" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="archive">
+    <group delimiter=". ">
+      <text variable="archive_location" text-case="capitalize-first"/>
+      <text variable="archive"/>
+      <text variable="archive-place"/>
+    </group>
+  </macro>
+  <macro name="access">
+    <group delimiter=". ">
+      <choose>
+        <if type="graphic report" match="any">
+          <text macro="archive"/>
+        </if>
+        <else-if type="article-journal bill book chapter legal_case legislation motion_picture paper-conference" match="none">
+          <text macro="archive"/>
+        </else-if>
+      </choose>
+      <choose>
+        <if type="webpage post-weblog" match="any">
+          <date variable="issued" form="text"/>
+        </if>
+      </choose>
+      <choose>
+        <if variable="issued" match="none">
+          <group delimiter=" ">
+            <text term="accessed" text-case="capitalize-first"/>
+            <date variable="accessed" form="text"/>
+          </group>
+        </if>
+      </choose>
+      <choose>
+        <if type="legal_case" match="none">
+          <choose>
+            <if variable="DOI">
+              <text variable="DOI" prefix="https://doi.org/"/>
+            </if>
+            <else>
+              <text variable="URL"/>
+            </else>
+          </choose>
+        </if>
+      </choose>
+    </group>
+  </macro>
+  <macro name="title">
+    <choose>
+      <if variable="title" match="none">
+        <choose>
+          <if type="personal_communication" match="none">
+            <text variable="genre" text-case="capitalize-first"/>
+          </if>
+        </choose>
+      </if>
+      <else-if type="bill book graphic legislation motion_picture song" match="any">
+        <text variable="title" text-case="title" font-style="italic"/>
+        <group prefix=" (" suffix=")" delimiter=" ">
+          <text term="version"/>
+          <text variable="version"/>
+        </group>
+      </else-if>
+      <else-if variable="reviewed-author">
+        <choose>
+          <if variable="reviewed-title">
+            <group delimiter=". ">
+              <text variable="title" text-case="title" quotes="true"/>
+              <group delimiter=", ">
+                <text variable="reviewed-title" text-case="title" font-style="italic" prefix="Review of "/>
+                <names variable="reviewed-author">
+                  <label form="verb-short" text-case="lowercase" suffix=" "/>
+                  <name and="text" delimiter=", "/>
+                </names>
+              </group>
+            </group>
+          </if>
+          <else>
+            <group delimiter=", ">
+              <text variable="title" text-case="title" font-style="italic" prefix="Review of "/>
+              <names variable="reviewed-author">
+                <label form="verb-short" text-case="lowercase" suffix=" "/>
+                <name and="text" delimiter=", "/>
+              </names>
+            </group>
+          </else>
+        </choose>
+      </else-if>
+      <else-if type="legal_case interview patent" match="any">
+        <text variable="title"/>
+      </else-if>
+      <else>
+        <text variable="title" text-case="title" quotes="true"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="edition">
+    <choose>
+      <if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+        <choose>
+          <if is-numeric="edition">
+            <group delimiter=" " prefix=". ">
+              <number variable="edition" form="ordinal"/>
+              <text term="edition" form="short" strip-periods="true"/>
+            </group>
+          </if>
+          <else>
+            <text variable="edition" text-case="capitalize-first" prefix=". "/>
+          </else>
+        </choose>
+      </if>
+      <else-if type="chapter entry-dictionary entry-encyclopedia paper-conference" match="any">
+        <choose>
+          <if is-numeric="edition">
+            <group delimiter=" " prefix=", ">
+              <number variable="edition" form="ordinal"/>
+              <text term="edition" form="short"/>
+            </group>
+          </if>
+          <else>
+            <text variable="edition" prefix=", "/>
+          </else>
+        </choose>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="locators">
+    <choose>
+      <if type="article-journal">
+        <choose>
+          <if variable="volume">
+            <text variable="volume" prefix=" "/>
+            <group prefix=" (" suffix=")">
+              <choose>
+                <if variable="issue">
+                  <text variable="issue"/>
+                </if>
+                <else>
+                  <date variable="issued">
+                    <date-part name="month"/>
+                  </date>
+                </else>
+              </choose>
+            </group>
+          </if>
+          <else-if variable="issue">
+            <group delimiter=" " prefix=", ">
+              <text term="issue" form="short"/>
+              <text variable="issue"/>
+              <date variable="issued" prefix="(" suffix=")">
+                <date-part name="month"/>
+              </date>
+            </group>
+          </else-if>
+          <else>
+            <date variable="issued" prefix=", ">
+              <date-part name="month"/>
+            </date>
+          </else>
+        </choose>
+      </if>
+      <else-if type="legal_case">
+        <text variable="volume" prefix=", "/>
+        <text variable="container-title" prefix=" "/>
+        <text variable="page" prefix=" "/>
+      </else-if>
+      <else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+        <group prefix=". " delimiter=". ">
+          <group>
+            <text term="volume" form="short" text-case="capitalize-first" suffix=" "/>
+            <number variable="volume" form="numeric"/>
+          </group>
+          <group>
+            <number variable="number-of-volumes" form="numeric"/>
+            <text term="volume" form="short" prefix=" " plural="true"/>
+          </group>
+        </group>
+      </else-if>
+      <else-if type="chapter entry-dictionary entry-encyclopedia paper-conference" match="any">
+        <choose>
+          <if variable="page" match="none">
+            <group prefix=". ">
+              <text term="volume" form="short" text-case="capitalize-first" suffix=" "/>
+              <number variable="volume" form="numeric"/>
+            </group>
+          </if>
+        </choose>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="locators-chapter">
+    <choose>
+      <if type="chapter entry-dictionary entry-encyclopedia paper-conference" match="any">
+        <choose>
+          <if variable="page">
+            <group prefix=", ">
+              <text variable="volume" suffix=":"/>
+              <text variable="page"/>
+            </group>
+          </if>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="locators-article">
+    <choose>
+      <if type="article-newspaper">
+        <group prefix=", " delimiter=", ">
+          <group delimiter=" ">
+            <text variable="edition"/>
+            <text term="edition"/>
+          </group>
+          <group>
+            <text term="section" form="short" suffix=" "/>
+            <text variable="section"/>
+          </group>
+        </group>
+      </if>
+      <else-if type="article-journal">
+        <choose>
+          <if variable="volume issue" match="any">
+            <text variable="page" prefix=": "/>
+          </if>
+          <else>
+            <text variable="page" prefix=", "/>
+          </else>
+        </choose>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="point-locators">
+    <choose>
+      <if variable="locator">
+        <choose>
+          <if locator="page" match="none">
+            <choose>
+              <if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+                <choose>
+                  <if variable="volume">
+                    <group>
+                      <text term="volume" form="short" suffix=" "/>
+                      <number variable="volume" form="numeric"/>
+                      <label variable="locator" form="short" prefix=", " suffix=" "/>
+                    </group>
+                  </if>
+                  <else>
+                    <label variable="locator" form="short" suffix=" "/>
+                  </else>
+                </choose>
+              </if>
+              <else>
+                <label variable="locator" form="short" suffix=" "/>
+              </else>
+            </choose>
+          </if>
+          <else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+            <number variable="volume" form="numeric" suffix=":"/>
+          </else-if>
+        </choose>
+        <text variable="locator"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="container-prefix">
+    <text term="in" text-case="capitalize-first"/>
+  </macro>
+  <macro name="container-title">
+    <choose>
+      <if type="chapter entry-dictionary entry-encyclopedia paper-conference" match="any">
+        <text macro="container-prefix" suffix=" "/>
+      </if>
+    </choose>
+    <choose>
+      <if type="webpage">
+        <text variable="container-title" text-case="title"/>
+      </if>
+      <else-if type="legal_case" match="none">
+        <group delimiter=" ">
+          <text variable="container-title" text-case="title" font-style="italic"/>
+          <choose>
+            <if type="post-weblog">
+              <text value="(blog)"/>
+            </if>
+          </choose>
+        </group>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="publisher">
+    <group delimiter=": ">
+      <text variable="publisher-place"/>
+      <text variable="publisher"/>
+    </group>
+  </macro>
+  <macro name="date">
+    <choose>
+      <if variable="issued">
+        <group delimiter=" ">
+          <date variable="original-date" form="text" date-parts="year" prefix="(" suffix=")"/>
+          <date variable="issued">
+            <date-part name="year"/>
+          </date>
+        </group>
+      </if>
+      <else-if variable="status">
+        <text variable="status" text-case="capitalize-first"/>
+      </else-if>
+      <else>
+        <text term="no date" form="short"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="date-in-text">
+    <choose>
+      <if variable="issued">
+        <group delimiter=" ">
+          <date variable="original-date" form="text" date-parts="year" prefix="[" suffix="]"/>
+          <date variable="issued">
+            <date-part name="year"/>
+          </date>
+        </group>
+      </if>
+      <else-if variable="status">
+        <text variable="status"/>
+      </else-if>
+      <else>
+        <text term="no date" form="short"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="day-month">
+    <date variable="issued">
+      <date-part name="month"/>
+      <date-part name="day" prefix=" "/>
+    </date>
+  </macro>
+  <macro name="collection-title">
+    <choose>
+      <if match="none" type="article-journal">
+        <choose>
+          <if match="none" is-numeric="collection-number">
+            <group delimiter=", ">
+              <text variable="collection-title" text-case="title"/>
+              <text variable="collection-number"/>
+            </group>
+          </if>
+          <else>
+            <group delimiter=" ">
+              <text variable="collection-title" text-case="title"/>
+              <text variable="collection-number"/>
+            </group>
+          </else>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="collection-title-journal">
+    <choose>
+      <if type="article-journal">
+        <group delimiter=" ">
+          <text variable="collection-title"/>
+          <text variable="collection-number"/>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="event">
+    <group>
+      <text term="presented at" suffix=" "/>
+      <text variable="event"/>
+    </group>
+  </macro>
+  <macro name="description">
+    <choose>
+      <if type="interview">
+        <group delimiter=". ">
+          <text macro="interviewer"/>
+          <text variable="medium" text-case="capitalize-first"/>
+        </group>
+      </if>
+      <else-if type="patent">
+        <group delimiter=" " prefix=". ">
+          <text variable="authority"/>
+          <text variable="number"/>
+        </group>
+      </else-if>
+      <else>
+        <text variable="medium" text-case="capitalize-first" prefix=". "/>
+      </else>
+    </choose>
+    <choose>
+      <if variable="title" match="none"/>
+      <else-if type="thesis personal_communication speech" match="any"/>
+      <else>
+        <group delimiter=" " prefix=". ">
+          <text variable="genre" text-case="capitalize-first"/>
+          <choose>
+            <if type="report">
+              <text variable="number"/>
+            </if>
+          </choose>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="issue">
+    <choose>
+      <if type="legal_case">
+        <text variable="authority" prefix=". "/>
+      </if>
+      <else-if type="speech">
+        <group prefix=". " delimiter=", ">
+          <group delimiter=" ">
+            <text variable="genre" text-case="capitalize-first"/>
+            <text macro="event"/>
+          </group>
+          <text variable="event-place"/>
+          <text macro="day-month"/>
+        </group>
+      </else-if>
+      <else-if type="article-newspaper article-magazine personal_communication" match="any">
+        <date variable="issued" form="text" prefix=", "/>
+      </else-if>
+      <else-if type="patent">
+        <group delimiter=", " prefix=", ">
+          <group delimiter=" ">
+            <!--Needs Localization-->
+            <text value="filed"/>
+            <date variable="submitted" form="text"/>
+          </group>
+          <group delimiter=" ">
+            <choose>
+              <if variable="issued submitted" match="all">
+                <text term="and"/>
+              </if>
+            </choose>
+            <!--Needs Localization-->
+            <text value="issued"/>
+            <date variable="issued" form="text"/>
+          </group>
+        </group>
+      </else-if>
+      <else-if type="article-journal" match="any"/>
+      <else>
+        <group prefix=". " delimiter=", ">
+          <choose>
+            <if type="thesis">
+              <text variable="genre" text-case="capitalize-first"/>
+            </if>
+          </choose>
+          <text macro="publisher"/>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <citation et-al-min="4" et-al-use-first="1" disambiguate-add-year-suffix="true" disambiguate-add-names="true" disambiguate-add-givenname="true" givenname-disambiguation-rule="primary-name" collapse="year" after-collapse-delimiter="; ">
+    <layout prefix="(" suffix=")" delimiter="; ">
+      <group delimiter=", ">
+        <choose>
+          <if variable="issued accessed" match="any">
+            <group delimiter=" ">
+              <text macro="contributors-short"/>
+              <text macro="date-in-text"/>
+            </group>
+          </if>
+          <!---comma before forthcoming and n.d.-->
+          <else>
+            <group delimiter=", ">
+              <text macro="contributors-short"/>
+              <text macro="date-in-text"/>
+            </group>
+          </else>
+        </choose>
+        <text macro="point-locators"/>
+      </group>
+    </layout>
+  </citation>
+  <bibliography hanging-indent="true" et-al-min="11" et-al-use-first="7" subsequent-author-substitute="&#8212;&#8212;&#8212;" entry-spacing="0">
+    <sort>
+      <key macro="contributors"/>
+      <key variable="issued"/>
+      <key variable="title"/>
+    </sort>
+    <layout suffix=".">
+      <group delimiter=". ">
+        <text macro="contributors"/>
+        <text macro="date"/>
+        <text macro="title"/>
+      </group>
+      <text macro="description"/>
+      <text macro="secondary-contributors" prefix=". "/>
+      <text macro="container-title" prefix=". "/>
+      <text macro="container-contributors"/>
+      <text macro="edition"/>
+      <text macro="locators-chapter"/>
+      <text macro="collection-title-journal" prefix=", " suffix=", "/>
+      <text macro="locators"/>
+      <text macro="collection-title" prefix=". "/>
+      <text macro="issue"/>
+      <text macro="locators-article"/>
+      <text macro="access" prefix=". "/>
+    </layout>
+  </bibliography>
+</style>

+ 203 - 0
example/assets/pandoc-scholar/csl/jats.csl

@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" default-locale="en-US">
+  <info>
+    <title>Journal Article Tag Suite</title>
+    <title-short>JATS</title-short>
+    <id>http://www.zotero.org/styles/journal-article-tag-suite</id>
+    <link href="https://github.com/MartinPaulEve/JATS-CSL/blob/master/jats.csl" rel="self"/>
+    <link rel="documentation" href="http://jats.nlm.nih.gov/archiving/tag-library/1.0/index.html"/>
+    <author>
+      <name>Martin Paul Eve</name>
+      <email>martin@martineve.com</email>
+    </author>
+    <category citation-format="numeric"/>
+    <category field="medicine"/>
+    <category field="biology"/>
+    <summary>Use this style to generate bibliographic data in Journal Article Tagging Suite (JATS) 1.0 XML format</summary>
+    <updated>2014-06-21T17:41:26+00:00</updated>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License. Originally by Martin Fenner.</rights>
+  </info>
+  <locale xml:lang="en">
+    <terms>
+        <term name="et-al">{{jats}}&lt;etal/&gt;{{/jats}}</term>
+    </terms>
+  </locale>
+  <macro name="citation-number">
+    <text variable="citation-number" prefix="{{jats}}id=&quot;ref-{{/jats}}" suffix="{{jats}}&quot;&gt;{{/jats}}"/>
+  </macro>
+  <macro name="author">
+    <names variable="author" delimiter=" ">
+        <name prefix="{{jats}}&lt;name&gt;{{/jats}}" suffix="{{jats}}&lt;/name&gt;{{/jats}}" name-as-sort-order="all" sort-separator=" ">
+            <name-part name="family" text-case="capitalize-first" prefix="{{jats}}&lt;surname&gt;{{/jats}}" suffix="{{jats}}&lt;/surname&gt;{{/jats}}"/>
+            <name-part name="given" text-case="capitalize-first" prefix="{{jats}}&lt;given-names&gt;{{/jats}}" suffix="{{jats}}&lt;/given-names&gt;{{/jats}}"/>
+      </name>
+      <substitute>
+        <names variable="editor"/>
+      </substitute>
+    </names>
+  </macro>
+
+  <macro name="editor" delimiter=" ">
+    <names variable="editor" prefix="{{jats}}&lt;person-group person-group-type=&quot;editor&quot;&gt;{{/jats}}" suffix="{{jats}}&lt;/person-group&gt;{{/jats}}">
+      <name prefix="{{jats}}&lt;name&gt;{{/jats}}" suffix="{{jats}}&lt;/name&gt;{{/jats}}" name-as-sort-order="all" sort-separator=" ">
+        <name-part name="family" text-case="capitalize-first" prefix="{{jats}}&lt;surname&gt;{{/jats}}" suffix="{{jats}}&lt;/surname&gt;{{/jats}}"/>
+        <name-part name="given" text-case="capitalize-first" prefix="{{jats}}&lt;given-names&gt;{{/jats}}" suffix="{{jats}}&lt;/given-names&gt;{{/jats}}"/>
+      </name>
+      <substitute>
+        <names variable="editor"/>
+      </substitute>
+    </names>
+  </macro>
+
+  <macro name="editor">
+    <group delimiter=": ">
+      <names variable="editor">
+        <name prefix="{{jats}}&lt;name&gt;{{/jats}}" suffix="{{jats}}&lt;/name&gt;{{/jats}}" name-as-sort-order="all" sort-separator="">
+          <name-part name="family" text-case="capitalize-first" prefix="{{jats}}&lt;surname&gt;{{/jats}}" suffix="{{jats}}&lt;/surname&gt;{{/jats}}"/>
+          <name-part name="given" text-case="capitalize-first" prefix="{{jats}}&lt;given-names&gt;{{/jats}}" suffix="{{jats}}&lt;given-names&gt;{{/jats}}"/>
+        </name>
+      </names>
+    </group>
+  </macro>
+  <macro name="title">
+    <choose>
+      <if type="book" match="any">
+        <group prefix="{{jats}}&lt;source&gt;{{/jats}}" suffix="{{jats}}&lt;/source&gt;{{/jats}}">
+	        <text variable="title"/>
+				</group>
+			</if>
+      <else>
+        <group prefix="{{jats}}&lt;article-title&gt;{{/jats}}" suffix="{{jats}}&lt;/article-title&gt;{{/jats}}">
+	        <text variable="title"/>
+				</group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="container-title">
+    <text variable="container-title" form="short" prefix="{{jats}}&lt;source&gt;{{/jats}}" suffix="{{jats}}&lt;/source&gt;{{/jats}}"/>
+  </macro>
+  <macro name="publisher">
+    <text variable="publisher" prefix="{{jats}}&lt;publisher-name&gt;{{/jats}}" suffix="{{jats}}&lt;/publisher-name&gt;{{/jats}}"/>
+    <text variable="publisher-place" prefix="{{jats}}&lt;publisher-loc&gt;{{/jats}}" suffix="{{jats}}&lt;/publisher-loc&gt;{{/jats}}"/>
+  </macro>
+  <macro name="link">
+    <choose>
+      <if match="any" variable="DOI">
+        <group prefix="{{jats}}&lt;pub-id pub-id-type=&quot;doi&quot;&gt;{{/jats}}" suffix="{{jats}}&lt;/pub-id&gt;{{/jats}}">
+          <text variable="DOI"/>
+        </group>
+      </if>
+    </choose>
+    <choose>
+      <if match="any" variable="PMID">
+        <group prefix="{{jats}}&lt;pub-id pub-id-type=&quot;pmid&quot;&gt;{{/jats}}" suffix="{{jats}}&lt;/pub-id&gt;{{/jats}}">
+          <text variable="PMID"/>
+        </group>
+      </if>
+    </choose>
+    <choose>
+      <if variable="URL" match="any">
+        <text variable="URL" />
+      </if>
+    </choose>
+  </macro>
+  <macro name="date">
+    <choose>
+      <if type="article-journal article-magazine article-newspaper report patent book" match="any">
+        <group prefix="{{jats}}&lt;date&gt;{{/jats}}" suffix="{{jats}}&lt;/date&gt;{{/jats}}">
+          <date variable="issued">
+            <date-part name="day" form="numeric-leading-zeros" prefix="{{jats}}&lt;day&gt;{{/jats}}" suffix="{{jats}}&lt;/day&gt;{{/jats}}"/>
+            <date-part name="month" form="numeric-leading-zeros" prefix="{{jats}}&lt;month&gt;{{/jats}}" suffix="{{jats}}&lt;/month&gt;{{/jats}}"/>
+            <date-part name="year" prefix="{{jats}}&lt;year&gt;{{/jats}}" suffix="{{jats}}&lt;/year&gt;{{/jats}}"/>
+          </date>
+        </group>
+      </if>
+      <else>
+        <group prefix="{{jats}}&lt;date-in-citation content-type=&quot;access-date&quot;{{/jats}}" suffix="{{jats}}&lt;/date-in-citation&gt;{{/jats}}">
+          <date variable="accessed" prefix="{{jats}} iso-8601-date=&quot;{{/jats}}" suffix="{{jats}}&quot;&gt;{{/jats}}">
+            <date-part name="year"/>
+            <date-part name="month" form="numeric-leading-zeros" prefix="{{jats}}-{{/jats}}"/>
+            <date-part name="day" form="numeric-leading-zeros" prefix="{{jats}}-{{/jats}}"/>
+          </date>
+          <date variable="accessed">
+            <date-part name="day" prefix="{{jats}}&lt;day&gt;{{/jats}}" suffix="{{jats}}&lt;/day&gt;{{/jats}}"/>
+            <date-part name="month" form="numeric-leading-zeros" prefix="{{jats}}&lt;month&gt;{{/jats}}" suffix="{{jats}}&lt;/month&gt;{{/jats}}"/>
+            <date-part name="year" prefix="{{jats}}&lt;year&gt;{{/jats}}" suffix="{{jats}}&lt;/year&gt;{{/jats}}"/>
+          </date>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="location">
+    <choose>
+      <if type="article-journal article-magazine" match="any">
+        <text variable="volume" prefix="{{jats}}&lt;volume&gt;{{/jats}}" suffix="{{jats}}&lt;/volume&gt;{{/jats}}"/>
+        <text variable="issue" prefix="{{jats}}&lt;issue&gt;{{/jats}}" suffix="{{jats}}&lt;/issue&gt;{{/jats}}"/>
+      </if>
+    </choose>
+    <choose>
+      <if type="article-journal article-magazine article-newspaper chapter" match="any">
+        <text variable="page-first" prefix="{{jats}}&lt;fpage&gt;{{/jats}}" suffix="{{jats}}&lt;/fpage&gt;{{/jats}}"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="publication-type">
+    <group prefix="{{jats}} publication-type=&quot;{{/jats}}" suffix="{{jats}}&quot;&gt;{{/jats}}">
+      <choose>
+        <if type="article-journal article-magazine article-newspaper" match="any">
+          <text value="journal"/>
+        </if>
+        <else-if type="book" match="any">
+          <text value="book"/>
+        </else-if>
+        <else-if type="chapter" match="any">
+          <text value="bookchapter"/>
+        </else-if>
+        <else-if type="dataset" match="any">
+          <text value="dataset"/>
+        </else-if>
+        <else-if type="patent" match="any">
+          <text value="patent"/>
+        </else-if>
+        <else-if type="report" match="any">
+          <text value="report"/>
+        </else-if>
+        <else-if type="review" match="any">
+          <text value="review"/>
+        </else-if>
+        <else>
+          <text value="standard"/>
+        </else>
+      </choose>
+    </group>
+  </macro>
+  <citation collapse="citation-number">
+    <sort>
+      <key variable="citation-number"/>
+    </sort>
+    <layout delimiter=",">
+      <group prefix="{{jats}}&lt;xref ref-type=&quot;bibr&quot; rid=&quot;{{/jats}}" suffix="{{jats}}&lt;/xref&gt;{{/jats}}">
+        <text variable="citation-number" prefix="{{jats}}ref-{{/jats}}" suffix="{{jats}}&quot;&gt;{{/jats}}"/>
+        <text variable="citation-number"/>
+      </group>
+    </layout>
+  </citation>
+  <bibliography sort-separator="">
+    <layout>
+      <group prefix="{{jats}}&lt;ref {{/jats}}" suffix="{{jats}}&lt;/ref&gt;{{/jats}}">
+        <text macro="citation-number"/>
+        <group prefix="{{jats}}&lt;element-citation{{/jats}}" suffix="{{jats}}&lt;/element-citation&gt;{{/jats}}">
+          <text macro="publication-type"/>
+          <text macro="author" prefix="{{jats}}&lt;person-group person-group-type=&quot;author&quot;&gt;{{/jats}}" suffix="{{jats}}&lt;/person-group&gt;{{/jats}}"/>
+          <text macro="title" />
+          <text macro="container-title"/>
+          <text macro="editor"/>
+          <text macro="publisher"/>
+          <text macro="date"/>
+          <text macro="location"/>
+          <text macro="link"/>
+        </group>
+      </group>
+    </layout>
+  </bibliography>
+</style>

+ 19 - 0
example/assets/pandoc-scholar/docker/alpine.Dockerfile

@@ -0,0 +1,19 @@
+FROM alpine:3.12 AS builder
+RUN apk --no-cache add ca-certificates curl make zip
+
+WORKDIR /app
+COPY . /app
+env NO_GNU_TAR=true
+RUN make archives
+
+
+FROM pandoc/latex:2.10.1
+
+RUN apk --no-cache add make \
+  && tlmgr install preprint
+
+COPY --from=builder /app/dist/pandoc-scholar /opt/pandoc-scholar
+
+ENV PANDOC_SCHOLAR_PATH=/opt/pandoc-scholar
+
+ENTRYPOINT ["/usr/bin/make"]

+ 24 - 0
example/assets/pandoc-scholar/docker/ubuntu.Dockerfile

@@ -0,0 +1,24 @@
+FROM ubuntu:focal AS builder
+RUN apt-get -q --no-allow-insecure-repositories update \
+  && DEBIAN_FRONTEND=noninteractive \
+     apt-get install --assume-yes --no-install-recommends \
+       ca-certificates curl make zip
+
+WORKDIR /app
+COPY . /app
+RUN make archives
+
+
+FROM pandoc/ubuntu-latex:2.10.1
+
+RUN apt-get -q --no-allow-insecure-repositories update \
+  && DEBIAN_FRONTEND=noninteractive \
+     apt-get install --assume-yes --no-install-recommends make \
+  && rm -rf /var/lib/apt/lists/* \
+  && tlmgr install preprint
+
+COPY --from=builder /app/dist/pandoc-scholar /opt/pandoc-scholar
+
+ENV PANDOC_SCHOLAR_PATH=/opt/pandoc-scholar
+
+ENTRYPOINT ["/usr/bin/make"]

+ 1 - 0
example/assets/pandoc-scholar/example/.gitignore

@@ -0,0 +1 @@
+/outfile.*

+ 5 - 0
example/assets/pandoc-scholar/example/Makefile

@@ -0,0 +1,5 @@
+# Assume pandoc-scholar is in the parent directory.
+# Should usually be overwritten or configured via an environment variable.
+PANDOC_SCHOLAR_PATH   ?= $(shell dirname $(PWD))
+ARTICLE_FILE=article.md
+include $(PANDOC_SCHOLAR_PATH)/Makefile

+ 1916 - 0
example/assets/pandoc-scholar/example/apa.csl

@@ -0,0 +1,1916 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="never" page-range-format="expanded">
+  <info>
+    <title>American Psychological Association 7th edition</title>
+    <title-short>APA</title-short>
+    <id>http://www.zotero.org/styles/apa</id>
+    <link href="http://www.zotero.org/styles/apa" rel="self"/>
+    <link href="http://www.zotero.org/styles/apa-6th-edition" rel="template"/>
+    <link href="https://apastyle.apa.org/style-grammar-guidelines/references/examples" rel="documentation"/>
+    <author>
+      <name>Brenton M. Wiernik</name>
+      <email>zotero@wiernik.org</email>
+    </author>
+    <category citation-format="author-date"/>
+    <category field="psychology"/>
+    <category field="generic-base"/>
+    <updated>2019-12-04T13:09:49+00:00</updated>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
+  </info>
+  <locale xml:lang="en">
+    <terms>
+      <term name="editortranslator" form="short">
+        <single>ed. &amp; trans.</single>
+        <multiple>eds. &amp; trans.</multiple>
+      </term>
+      <term name="translator" form="short">trans.</term>
+      <term name="interviewer" form="short">
+        <single>interviewer</single>
+        <multiple>interviewers</multiple>
+      </term>
+      <term name="collection-editor" form="short">
+        <single>ed.</single>
+        <multiple>eds.</multiple>
+      </term>
+      <term name="circa" form="short">ca.</term>
+      <term name="bc"> B.C.E.</term>
+      <term name="ad"> C.E.</term>
+      <term name="letter">personal communication</term>
+      <term name="letter" form="short">letter</term>
+      <term name="issue" form="long">
+        <single>issue</single>
+        <multiple>issues</multiple>
+      </term>
+    </terms>
+  </locale>
+  <locale xml:lang="af">
+    <terms>
+      <term name="letter">persoonlike kommunikasie</term>
+      <term name="letter" form="short">brief</term>
+    </terms>
+  </locale>
+  <locale xml:lang="ar">
+    <terms>
+      <term name="letter">اتصال شخصي</term>
+      <term name="letter" form="short">خطاب</term>
+    </terms>
+  </locale>
+  <locale xml:lang="bg">
+    <terms>
+      <term name="letter">лична комуникация</term>
+      <term name="letter" form="short">писмо</term>
+    </terms>
+  </locale>
+  <locale xml:lang="ca">
+    <terms>
+      <term name="letter">comunicació personal</term>
+      <term name="letter" form="short">carta</term>
+    </terms>
+  </locale>
+  <locale xml:lang="cs">
+    <terms>
+      <term name="letter">osobní komunikace</term>
+      <term name="letter" form="short">dopis</term>
+    </terms>
+  </locale>
+  <locale xml:lang="cy">
+    <terms>
+      <term name="letter">cyfathrebu personol</term>
+      <term name="letter" form="short">llythyr</term>
+    </terms>
+  </locale>
+  <locale xml:lang="da">
+    <terms>
+      <term name="et-al">et al.</term>
+      <term name="letter">personlig kommunikation</term>
+      <term name="letter" form="short">brev</term>
+    </terms>
+  </locale>
+  <locale xml:lang="de">
+    <terms>
+      <term name="et-al">et al.</term>
+      <term name="letter">persönliche Kommunikation</term>
+      <term name="letter" form="short">Brief</term>
+    </terms>
+  </locale>
+  <locale xml:lang="el">
+    <terms>
+      <term name="letter">προσωπική επικοινωνία</term>
+      <term name="letter" form="short">επιστολή</term>
+    </terms>
+  </locale>
+  <locale xml:lang="es">
+    <terms>
+      <term name="from">de</term>
+      <term name="letter">comunicación personal</term>
+      <term name="letter" form="short">carta</term>
+    </terms>
+  </locale>
+  <locale xml:lang="et">
+    <terms>
+      <term name="letter">isiklik suhtlus</term>
+      <term name="letter" form="short">kiri</term>
+    </terms>
+  </locale>
+  <locale xml:lang="eu">
+    <terms>
+      <term name="letter">komunikazio pertsonala</term>
+      <term name="letter" form="short">gutuna</term>
+    </terms>
+  </locale>
+  <locale xml:lang="fa">
+    <terms>
+      <term name="letter">ارتباط شخصی</term>
+      <term name="letter" form="short">نامه</term>
+    </terms>
+  </locale>
+  <locale xml:lang="fi">
+    <terms>
+      <term name="letter">henkilökohtainen viestintä</term>
+      <term name="letter" form="short">kirje</term>
+    </terms>
+  </locale>
+  <locale xml:lang="fr">
+    <terms>
+      <term name="letter">communication personnelle</term>
+      <term name="letter" form="short">lettre</term>
+      <term name="editor" form="short">
+        <single>éd.</single>
+        <multiple>éds.</multiple>
+      </term>
+    </terms>
+  </locale>
+  <locale xml:lang="he">
+    <terms>
+      <term name="letter">תקשורת אישית</term>
+      <term name="letter" form="short">מכתב</term>
+    </terms>
+  </locale>
+  <locale xml:lang="hr">
+    <terms>
+      <term name="letter">osobna komunikacija</term>
+      <term name="letter" form="short">pismo</term>
+    </terms>
+  </locale>
+  <locale xml:lang="hu">
+    <terms>
+      <term name="letter">személyes kommunikáció</term>
+      <term name="letter" form="short">levél</term>
+    </terms>
+  </locale>
+  <locale xml:lang="id">
+    <terms>
+      <term name="letter">komunikasi pribadi</term>
+      <term name="letter" form="short">surat</term>
+    </terms>
+  </locale>
+  <locale xml:lang="is">
+    <terms>
+      <term name="letter">persónuleg samskipti</term>
+      <term name="letter" form="short">bréf</term>
+    </terms>
+  </locale>
+  <locale xml:lang="it">
+    <terms>
+      <term name="letter">comunicazione personale</term>
+      <term name="letter" form="short">lettera</term>
+    </terms>
+  </locale>
+  <locale xml:lang="ja">
+    <terms>
+      <term name="letter">個人的なやり取り</term>
+      <term name="letter" form="short">手紙</term>
+    </terms>
+  </locale>
+  <locale xml:lang="ko">
+    <terms>
+      <term name="letter">개인 서신</term>
+      <term name="letter" form="short">편지</term>
+    </terms>
+  </locale>
+  <locale xml:lang="la">
+    <terms>
+      <term name="letter"/>
+      <term name="letter" form="short">epistula</term>
+    </terms>
+  </locale>
+  <locale xml:lang="lt">
+    <terms>
+      <term name="letter">communicationis personalis</term>
+      <term name="letter" form="short"/>
+    </terms>
+  </locale>
+  <locale xml:lang="lv">
+    <terms>
+      <term name="letter">personīga komunikācija</term>
+      <term name="letter" form="short">vēstule</term>
+    </terms>
+  </locale>
+  <locale xml:lang="mn">
+    <terms>
+      <term name="letter">хувийн харилцаа холбоо</term>
+      <term name="letter" form="short">захиа</term>
+    </terms>
+  </locale>
+  <locale xml:lang="nb">
+    <terms>
+      <term name="et-al">et al.</term>
+      <term name="letter">personlig kommunikasjon</term>
+      <term name="letter" form="short">brev</term>
+    </terms>
+  </locale>
+  <locale xml:lang="nl">
+    <terms>
+      <term name="et-al">et al.</term>
+      <term name="letter">persoonlijke communicatie</term>
+      <term name="letter" form="short">brief</term>
+    </terms>
+  </locale>
+  <locale xml:lang="nn">
+    <terms>
+      <term name="et-al">et al.</term>
+      <term name="letter">personlig kommunikasjon</term>
+      <term name="letter" form="short">brev</term>
+    </terms>
+  </locale>
+  <locale xml:lang="pl">
+    <terms>
+      <term name="letter">osobista komunikacja</term>
+      <term name="letter" form="short">list</term>
+    </terms>
+  </locale>
+  <locale xml:lang="pt">
+    <terms>
+      <term name="letter">comunicação pessoal</term>
+      <term name="letter" form="short">carta</term>
+    </terms>
+  </locale>
+  <locale xml:lang="ro">
+    <terms>
+      <term name="letter">comunicare personală</term>
+      <term name="letter" form="short">scrisoare</term>
+    </terms>
+  </locale>
+  <locale xml:lang="ru">
+    <terms>
+      <term name="letter">личная переписка</term>
+      <term name="letter" form="short">письмо</term>
+    </terms>
+  </locale>
+  <locale xml:lang="sk">
+    <terms>
+      <term name="letter">osobná komunikácia</term>
+      <term name="letter" form="short">list</term>
+    </terms>
+  </locale>
+  <locale xml:lang="sl">
+    <terms>
+      <term name="letter">osebna komunikacija</term>
+      <term name="letter" form="short">pismo</term>
+    </terms>
+  </locale>
+  <locale xml:lang="sr">
+    <terms>
+      <term name="letter">лична комуникација</term>
+      <term name="letter" form="short">писмо</term>
+    </terms>
+  </locale>
+  <locale xml:lang="sv">
+    <terms>
+      <term name="letter">personlig kommunikation</term>
+      <term name="letter" form="short">brev</term>
+    </terms>
+  </locale>
+  <locale xml:lang="th">
+    <terms>
+      <term name="letter">การสื่อสารส่วนบุคคล</term>
+      <term name="letter" form="short">จดหมาย</term>
+    </terms>
+  </locale>
+  <locale xml:lang="tr">
+    <terms>
+      <term name="letter">kişisel iletişim</term>
+      <term name="letter" form="short">mektup</term>
+    </terms>
+  </locale>
+  <locale xml:lang="uk">
+    <terms>
+      <term name="letter">особисте спілкування</term>
+      <term name="letter" form="short">лист</term>
+    </terms>
+  </locale>
+  <locale xml:lang="vi">
+    <terms>
+      <term name="letter">giao tiếp cá nhân</term>
+      <term name="letter" form="short">thư</term>
+    </terms>
+  </locale>
+  <locale xml:lang="zh-CN">
+    <terms>
+      <term name="letter">的私人交流</term>
+      <term name="letter" form="short">信函</term>
+    </terms>
+  </locale>
+  <locale xml:lang="zh-TW">
+    <terms>
+      <term name="letter">私人通訊</term>
+      <term name="letter" form="short">信函</term>
+    </terms>
+  </locale>
+  <!-- General categories of item types:
+       Periodical: article-journal article-magazine article-newspaper post-weblog review review-book
+       Periodical or Booklike: paper-conference
+       Booklike: article book broadcast chapter dataset entry entry-dictionary entry-encyclopedia figure 
+                 graphic interview manuscript map motion_picture musical_score pamphlet patent 
+                 personal_communication report song speech thesis post webpage
+       Legal: bill legal_case legislation treaty
+  -->
+  <!-- APA references contain four parts: author, date, title, source -->
+  <macro name="author-bib">
+    <names variable="composer" delimiter=", ">
+      <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+      <substitute>
+        <names variable="author"/>
+        <names variable="illustrator"/>
+        <names variable="director">
+          <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+          <label form="long" prefix=" (" suffix=")" text-case="title"/>
+        </names>
+        <choose>
+          <if variable="container-title">
+            <choose>
+              <if type="book entry entry-dictionary entry-encyclopedia" match="any">
+                <choose>
+                  <if variable="title">
+                    <group delimiter=" ">
+                      <text macro="title"/>
+                      <text macro="parenthetical"/>
+                    </group>
+                  </if>
+                  <else>
+                    <text macro="title-and-descriptions"/>
+                  </else>
+                </choose>
+              </if>
+            </choose>
+          </if>
+        </choose>
+        <!-- Test for editortranslator and put that first as that becomes available -->
+        <names variable="editor" delimiter=", ">
+          <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+          <label form="short" prefix=" (" suffix=")" text-case="title"/>
+        </names>
+        <names variable="editorial-director">
+          <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+          <label form="short" prefix=" (" suffix=")" text-case="title"/>
+        </names>
+        <names variable="collection-editor">
+          <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+          <label form="short" prefix=" (" suffix=")" text-case="title"/>
+        </names>
+        <choose>
+          <if variable="title">
+            <group delimiter=" ">
+              <text macro="title"/>
+              <text macro="parenthetical"/>
+            </group>
+          </if>
+          <else>
+            <text macro="title-and-descriptions"/>
+          </else>
+        </choose>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="author-intext">
+    <choose>
+      <if type="bill legal_case legislation treaty" match="any">
+        <text macro="title-intext"/>
+      </if>
+      <else-if type="interview personal_communication" match="any">
+        <choose>
+          <!-- These variables indicate that the letter is retrievable by the reader. 
+                If not, then use the APA in-text-only personal communication format -->
+          <if variable="archive container-title DOI publisher URL" match="none">
+            <group delimiter=", ">
+              <names variable="author">
+                <name and="symbol" delimiter=", " initialize-with=". "/>
+                <substitute>
+                  <text macro="title-intext"/>
+                </substitute>
+              </names>
+              <!-- Replace with term="personal-communication" if that becomes available -->
+              <text term="letter"/>
+            </group>
+          </if>
+          <else>
+            <names variable="author" delimiter=", ">
+              <name form="short" and="symbol" delimiter=", " initialize-with=". "/>
+              <substitute>
+                <text macro="title-intext"/>
+              </substitute>
+            </names>
+          </else>
+        </choose>
+      </else-if>
+      <else>
+        <names variable="composer" delimiter=", ">
+          <name form="short" and="symbol" delimiter=", " initialize-with=". "/>
+          <substitute>
+            <names variable="author"/>
+            <names variable="illustrator"/>
+            <names variable="director"/>
+            <choose>
+              <if variable="container-title">
+                <choose>
+                  <if type="book entry entry-dictionary entry-encyclopedia" match="any">
+                    <text macro="title-intext"/>
+                  </if>
+                </choose>
+              </if>
+            </choose>
+            <names variable="editor"/>
+            <names variable="editorial-director"/>
+            <text macro="title-intext"/>
+          </substitute>
+        </names>
+      </else>
+    </choose>
+  </macro>
+  <macro name="date-bib">
+    <group delimiter=" " prefix="(" suffix=")">
+      <choose>
+        <if is-uncertain-date="issued">
+          <text term="circa" form="short"/>
+        </if>
+      </choose>
+      <group>
+        <choose>
+          <if variable="issued">
+            <date variable="issued">
+              <date-part name="year"/>
+            </date>
+            <text variable="year-suffix"/>
+            <choose>
+              <if type="article-magazine article-newspaper broadcast interview motion_picture pamphlet personal_communication post post-weblog song speech webpage" match="any">
+                <!-- Many video and audio examples in manual give full dates. Err on the side of too much information. -->
+                <date variable="issued">
+                  <date-part prefix=", " name="month"/>
+                  <date-part prefix=" " name="day"/>
+                </date>
+              </if>
+              <else-if type="paper-conference">
+                <!-- Capture 'speech' stored as 'paper-conference' -->
+                <choose>
+                  <if variable="collection-editor editor editorial-director issue page volume" match="none">
+                    <date variable="issued">
+                      <date-part prefix=", " name="month"/>
+                      <date-part prefix=" " name="day"/>
+                    </date>
+                  </if>
+                </choose>
+              </else-if>
+              <!-- Only year: article article-journal book chapter entry entry-dictionary entry-encyclopedia dataset figure graphic 
+                   manuscript map musical_score paper-conference[published] patent report review review-book thesis -->
+            </choose>
+          </if>
+          <else-if variable="status">
+            <group>
+              <text variable="status" text-case="lowercase"/>
+              <text variable="year-suffix" prefix="-"/>
+            </group>
+          </else-if>
+          <else>
+            <group>
+              <text term="no date" form="short"/>
+              <text variable="year-suffix" prefix="-"/>
+            </group>
+          </else>
+        </choose>
+      </group>
+    </group>
+  </macro>
+  <macro name="date-sort-group">
+    <choose>
+      <if variable="issued">
+        <text value="1"/>
+      </if>
+      <else-if variable="status">
+        <text value="2"/>
+      </else-if>
+      <else>
+        <text value="0"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="date-sort-date">
+    <choose>
+      <if type="article-magazine article-newspaper broadcast interview pamphlet personal_communication post post-weblog speech treaty webpage" match="any">
+        <date variable="issued" form="numeric"/>
+      </if>
+      <else-if type="paper-conference">
+        <!-- Capture 'speech' stored as 'paper-conference' -->
+        <choose>
+          <if variable="collection-editor editor editorial-director issue page volume" match="none">
+            <date variable="issued" form="numeric"/>
+          </if>
+        </choose>
+      </else-if>
+      <else>
+        <date variable="issued" form="numeric"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="date-intext">
+    <choose>
+      <if variable="issued">
+        <group delimiter="/">
+          <group delimiter=" ">
+            <choose>
+              <if is-uncertain-date="original-date">
+                <text term="circa" form="short"/>
+              </if>
+            </choose>
+            <date variable="original-date">
+              <date-part name="year"/>
+            </date>
+          </group>
+          <group delimiter=" ">
+            <choose>
+              <if is-uncertain-date="issued">
+                <text term="circa" form="short"/>
+              </if>
+            </choose>
+            <group>
+              <choose>
+                <if type="interview personal_communication" match="any">
+                  <choose>
+                    <if variable="archive container-title DOI publisher URL" match="none">
+                      <!-- These variables indicate that the communication is retrievable by the reader. 
+                           If not, then use the in-text-only personal communication format -->
+                      <date variable="issued" form="text"/>
+                    </if>
+                    <else>
+                      <date variable="issued">
+                        <date-part name="year"/>
+                      </date>
+                    </else>
+                  </choose>
+                </if>
+                <else>
+                  <date variable="issued">
+                    <date-part name="year"/>
+                  </date>
+                </else>
+              </choose>
+              <text variable="year-suffix"/>
+            </group>
+          </group>
+        </group>
+      </if>
+      <else-if variable="status">
+        <text variable="status" text-case="lowercase"/>
+        <text variable="year-suffix" prefix="-"/>
+      </else-if>
+      <else>
+        <text term="no date" form="short"/>
+        <text variable="year-suffix" prefix="-"/>
+      </else>
+    </choose>
+  </macro>
+  <!-- APA has two description elements following the title:
+       title (parenthetical) [bracketed]  -->
+  <macro name="title-and-descriptions">
+    <choose>
+      <if variable="title">
+        <group delimiter=" ">
+          <text macro="title"/>
+          <text macro="parenthetical"/>
+          <text macro="bracketed"/>
+        </group>
+      </if>
+      <else>
+        <group delimiter=" ">
+          <text macro="bracketed"/>
+          <text macro="parenthetical"/>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="title">
+    <choose>
+      <if type="post webpage" match="any">
+        <!-- Webpages are always italicized -->
+        <text variable="title" font-style="italic"/>
+      </if>
+      <else-if variable="container-title" match="any">
+        <!-- Other types are italicized based on presence of container-title.
+             Assume that review and review-book are published in periodicals/blogs,
+             not just on a web page (ex. 69) -->
+        <text variable="title"/>
+      </else-if>
+      <else>
+        <choose>
+          <if type="article-journal article-magazine article-newspaper post-weblog review review-book" match="any">
+            <text variable="title" font-style="italic"/>
+          </if>
+          <else-if type="paper-conference">
+            <choose>
+              <if variable="collection-editor editor editorial-director" match="any">
+                <group delimiter=": " font-style="italic">
+                  <text variable="title"/>
+                  <!-- Replace with volume-title as that becomes available -->
+                  <choose>
+                    <if is-numeric="volume" match="none">
+                      <group delimiter=" ">
+                        <label variable="volume" form="short" text-case="capitalize-first"/>
+                        <text variable="volume"/>
+                      </group>
+                    </if>
+                  </choose>
+                </group>
+              </if>
+              <else>
+                <text variable="title" font-style="italic"/>
+              </else>
+            </choose>
+          </else-if>
+          <else>
+            <group delimiter=": " font-style="italic">
+              <text variable="title"/>
+              <!-- Replace with volume-title as that becomes available -->
+              <choose>
+                <if is-numeric="volume" match="none">
+                  <group delimiter=" ">
+                    <label variable="volume" form="short" text-case="capitalize-first"/>
+                    <text variable="volume"/>
+                  </group>
+                </if>
+              </choose>
+            </group>
+          </else>
+        </choose>
+      </else>
+    </choose>
+  </macro>
+  <macro name="title-intext">
+    <choose>
+      <if variable="title" match="none">
+        <text macro="bracketed-intext" prefix="[" suffix="]"/>
+      </if>
+      <else-if type="bill">
+        <!-- If a bill has no number or container-title, assume it is a hearing; italic -->
+        <choose>
+          <if variable="number container-title" match="none">
+            <text variable="title" form="short" font-style="italic" text-case="title"/>
+          </if>
+          <else-if variable="title">
+            <text variable="title" form="short" text-case="title"/>
+          </else-if>
+          <else>
+            <group delimiter=" ">
+              <text variable="genre"/>
+              <group delimiter=" ">
+                <choose>
+                  <if variable="chapter-number container-title" match="none">
+                    <!-- Replace with label variable="number" as that becomes available -->
+                    <text term="issue" form="short"/>
+                  </if>
+                </choose>
+                <text variable="number"/>
+              </group>
+            </group>
+          </else>
+        </choose>
+      </else-if>
+      <else-if type="legal_case" match="any">
+        <!-- Cases are italicized -->
+        <text variable="title" font-style="italic"/>
+      </else-if>
+      <else-if type="legislation treaty" match="any">
+        <!-- Legislation and treaties not italicized or quoted -->
+        <text variable="title" form="short" text-case="title"/>
+      </else-if>
+      <else-if type="post webpage" match="any">
+        <!-- Webpages are always italicized -->
+        <text variable="title" form="short" font-style="italic" text-case="title"/>
+      </else-if>
+      <else-if variable="container-title" match="any">
+        <!-- Other types are italicized or quoted based on presence of container-title. As in title macro. -->
+        <text variable="title" form="short" quotes="true" text-case="title"/>
+      </else-if>
+      <else>
+        <text variable="title" form="short" font-style="italic" text-case="title"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="parenthetical">
+    <!-- (Secondary contributors; Database location; Genre no. 123; Report Series 123, Version, Edition, Volume, Page) -->
+    <group prefix="(" suffix=")">
+      <choose>
+        <if type="patent">
+          <!-- authority: U.S. ; genre: patent ; number: 123,445 -->
+          <group delimiter=" ">
+            <text variable="authority" form="short"/>
+            <choose>
+              <if variable="genre">
+                <text variable="genre" text-case="capitalize-first"/>
+              </if>
+              <else>
+                <!-- This should be localized -->
+                <text value="patent" text-case="capitalize-first"/>
+              </else>
+            </choose>
+            <group delimiter=" ">
+              <!-- Replace with label variable="number" if that becomes available -->
+              <text term="issue" form="short" text-case="capitalize-first"/>
+              <text variable="number"/>
+            </group>
+          </group>
+        </if>
+        <else-if type="post webpage" match="any">
+          <!-- For post webpage, container-title is treated as publisher -->
+          <group delimiter="; ">
+            <text macro="secondary-contributors"/>
+            <text macro="database-location"/>
+            <text macro="number"/>
+            <text macro="locators-booklike"/>
+          </group>
+        </else-if>
+        <else-if variable="container-title">
+          <group delimiter="; ">
+            <text macro="secondary-contributors"/>
+            <choose>
+              <if type="broadcast graphic map motion_picture song" match="any">
+                <!-- For audiovisual media, number information comes after title, not container-title -->
+                <text macro="number"/>
+              </if>
+            </choose>
+          </group>
+        </else-if>
+        <else>
+          <group delimiter="; ">
+            <text macro="secondary-contributors"/>
+            <text macro="database-location"/>
+            <text macro="number"/>
+            <text macro="locators-booklike"/>
+          </group>
+        </else>
+      </choose>
+    </group>
+  </macro>
+  <macro name="parenthetical-container">
+    <choose>
+      <if variable="container-title" match="any">
+        <group prefix="(" suffix=")">
+          <group delimiter="; ">
+            <text macro="database-location"/>
+            <choose>
+              <if type="broadcast graphic map motion_picture song" match="none">
+                <!-- For audiovisual media, number information comes after title, not container-title -->
+                <text macro="number"/>
+              </if>
+            </choose>
+            <text macro="locators-booklike"/>
+          </group>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="bracketed">
+    <!-- [Descriptive information] -->
+    <!-- If there is a number, genre is already printed in macro="number" -->
+    <group prefix="[" suffix="]">
+      <choose>
+        <if variable="reviewed-author reviewed-title" type="review review-book" match="any">
+          <!-- Reviewed item -->
+          <group delimiter="; ">
+            <group delimiter=", ">
+              <group delimiter=" ">
+                <!-- Assume that genre is entered as 'Review of the book' or similar -->
+                <choose>
+                  <if variable="number" match="none">
+                    <choose>
+                      <if variable="genre">
+                        <text variable="genre" text-case="capitalize-first"/>
+                      </if>
+                      <else-if variable="medium">
+                        <text variable="medium" text-case="capitalize-first"/>
+                      </else-if>
+                      <else>
+                        <!-- Replace with term="review" as that becomes available -->
+                        <text value="Review of"/>
+                      </else>
+                    </choose>
+                  </if>
+                  <else>
+                    <choose>
+                      <if variable="medium">
+                        <text variable="medium" text-case="capitalize-first"/>
+                      </if>
+                      <else>
+                        <!-- Replace with term="review" as that becomes available -->
+                        <text value="Review of"/>
+                      </else>
+                    </choose>
+                  </else>
+                </choose>
+                <text macro="reviewed-title"/>
+              </group>
+              <names variable="reviewed-author">
+                <label form="verb-short" suffix=" "/>
+                <name and="symbol" initialize-with=". " delimiter=", "/>
+              </names>
+            </group>
+            <choose>
+              <if variable="genre" match="any">
+                <choose>
+                  <if variable="number" match="none">
+                    <text variable="medium" text-case="capitalize-first"/>
+                  </if>
+                </choose>
+              </if>
+            </choose>
+          </group>
+        </if>
+        <else-if type="thesis">
+          <!-- Thesis type and institution -->
+          <group delimiter="; ">
+            <choose>
+              <if variable="number" match="none">
+                <group delimiter=", ">
+                  <text variable="genre" text-case="capitalize-first"/>
+                  <choose>
+                    <if variable="archive DOI URL" match="any">
+                      <!-- Include the university in brackets if thesis is published -->
+                      <text variable="publisher"/>
+                    </if>
+                  </choose>
+                </group>
+              </if>
+            </choose>
+            <text variable="medium" text-case="capitalize-first"/>
+          </group>
+        </else-if>
+        <else-if variable="interviewer" type="interview" match="any">
+          <!-- Interview information -->
+          <choose>
+            <if variable="title">
+              <text macro="format"/>
+            </if>
+            <else-if variable="genre">
+              <group delimiter="; ">
+                <group delimiter=" ">
+                  <text variable="genre" text-case="capitalize-first"/>
+                  <group delimiter=" ">
+                    <text term="author" form="verb"/>
+                    <names variable="interviewer">
+                      <name and="symbol" initialize-with=". " delimiter=", "/>
+                    </names>
+                  </group>
+                </group>
+              </group>
+            </else-if>
+            <else-if variable="interviewer">
+              <group delimiter="; ">
+                <names variable="interviewer">
+                  <label form="verb" suffix=" " text-case="capitalize-first"/>
+                  <name and="symbol" initialize-with=". " delimiter=", "/>
+                </names>
+                <text variable="medium" text-case="capitalize-first"/>
+              </group>
+            </else-if>
+            <else>
+              <text macro="format"/>
+            </else>
+          </choose>
+        </else-if>
+        <else-if type="personal_communication">
+          <!-- Letter information -->
+          <choose>
+            <if variable="recipient">
+              <group delimiter="; ">
+                <group delimiter=" ">
+                  <choose>
+                    <if variable="number" match="none">
+                      <choose>
+                        <if variable="genre">
+                          <text variable="genre" text-case="capitalize-first"/>
+                        </if>
+                        <else-if variable="medium">
+                          <text variable="medium" text-case="capitalize-first"/>
+                        </else-if>
+                        <else>
+                          <text term="letter" form="short" text-case="capitalize-first"/>
+                        </else>
+                      </choose>
+                    </if>
+                    <else>
+                      <choose>
+                        <if variable="medium">
+                          <text variable="medium" text-case="capitalize-first"/>
+                        </if>
+                        <else>
+                          <text term="letter" form="short" text-case="capitalize-first"/>
+                        </else>
+                      </choose>
+                    </else>
+                  </choose>
+                  <names variable="recipient" delimiter=", ">
+                    <label form="verb" suffix=" "/>
+                    <name and="symbol" delimiter=", "/>
+                  </names>
+                </group>
+                <choose>
+                  <if variable="genre" match="any">
+                    <choose>
+                      <if variable="number" match="none">
+                        <text variable="medium" text-case="capitalize-first"/>
+                      </if>
+                    </choose>
+                  </if>
+                </choose>
+              </group>
+            </if>
+            <else>
+              <text macro="format"/>
+            </else>
+          </choose>
+        </else-if>
+        <else-if variable="composer" type="song" match="all">
+          <!-- Performer of classical music works -->
+          <group delimiter="; ">
+            <choose>
+              <if variable="number" match="none">
+                <group delimiter=" ">
+                  <choose>
+                    <if variable="genre">
+                      <text variable="genre" text-case="capitalize-first"/>
+                      <!-- Replace prefix with performer label as that becomes available -->
+                      <names variable="author" prefix="recorded by ">
+                        <name and="symbol" initialize-with=". " delimiter=", "/>
+                      </names>
+                    </if>
+                    <else-if variable="medium">
+                      <text variable="medium" text-case="capitalize-first"/>
+                      <!-- Replace prefix with performer label as that becomes available -->
+                      <names variable="author" prefix="recorded by ">
+                        <name and="symbol" initialize-with=". " delimiter=", "/>
+                      </names>
+                    </else-if>
+                    <else>
+                      <!-- Replace prefix with performer label as that becomes available -->
+                      <names variable="author" prefix="Recorded by ">
+                        <name and="symbol" initialize-with=". " delimiter=", "/>
+                      </names>
+                    </else>
+                  </choose>
+                </group>
+              </if>
+              <else>
+                <group delimiter=" ">
+                  <choose>
+                    <if variable="medium">
+                      <text variable="medium" text-case="capitalize-first"/>
+                      <!-- Replace prefix with performer label as that becomes available -->
+                      <names variable="author" prefix="recorded by ">
+                        <name and="symbol" initialize-with=". " delimiter=", "/>
+                      </names>
+                    </if>
+                    <else>
+                      <!-- Replace prefix with performer label as that becomes available -->
+                      <names variable="author" prefix="Recorded by ">
+                        <name and="symbol" initialize-with=". " delimiter=", "/>
+                      </names>
+                    </else>
+                  </choose>
+                </group>
+              </else>
+            </choose>
+            <choose>
+              <if variable="genre" match="any">
+                <choose>
+                  <if variable="number" match="none">
+                    <text variable="medium" text-case="capitalize-first"/>
+                  </if>
+                </choose>
+              </if>
+            </choose>
+          </group>
+        </else-if>
+        <else-if variable="container-title" match="none">
+          <!-- Other description -->
+          <text macro="format"/>
+        </else-if>
+        <else>
+          <!-- For conference presentations, chapters in reports, software, place bracketed after the container title -->
+          <choose>
+            <if type="paper-conference speech" match="any">
+              <choose>
+                <if variable="collection-editor editor editorial-director issue page volume" match="any">
+                  <text macro="format"/>
+                </if>
+              </choose>
+            </if>
+            <else-if type="book">
+              <choose>
+                <if variable="version" match="none">
+                  <text macro="format"/>
+                </if>
+              </choose>
+            </else-if>
+            <else-if type="report" match="none">
+              <text macro="format"/>
+            </else-if>
+          </choose>
+        </else>
+      </choose>
+    </group>
+  </macro>
+  <macro name="bracketed-intext">
+    <group prefix="[" suffix="]">
+      <choose>
+        <if variable="reviewed-author reviewed-title" type="review review-book" match="any">
+          <!-- This should be localized -->
+          <text macro="reviewed-title-intext" prefix="Review of "/>
+        </if>
+        <else-if variable="interviewer" type="interview" match="any">
+          <names variable="interviewer">
+            <label form="verb" suffix=" " text-case="capitalize-first"/>
+            <name and="symbol" initialize-with=". " delimiter=", "/>
+            <substitute>
+              <text macro="format-intext"/>
+            </substitute>
+          </names>
+        </else-if>
+        <else-if type="personal_communication">
+          <!-- Letter information -->
+          <choose>
+            <if variable="recipient">
+              <group delimiter=" ">
+                <choose>
+                  <if variable="number" match="none">
+                    <text variable="genre" text-case="capitalize-first"/>
+                  </if>
+                  <else>
+                    <text term="letter" form="short" text-case="capitalize-first"/>
+                  </else>
+                </choose>
+                <names variable="recipient" delimiter=", ">
+                  <label form="verb" suffix=" "/>
+                  <name and="symbol" delimiter=", "/>
+                </names>
+              </group>
+            </if>
+            <else>
+              <text macro="format-intext"/>
+            </else>
+          </choose>
+        </else-if>
+        <else>
+          <text macro="format-intext"/>
+        </else>
+      </choose>
+    </group>
+  </macro>
+  <macro name="bracketed-container">
+    <group prefix="[" suffix="]">
+      <choose>
+        <if type="paper-conference speech" match="any">
+          <!-- Conference presentations should describe the session [container] in bracketed unless published in a proceedings -->
+          <choose>
+            <if variable="collection-editor editor editorial-director issue page volume" match="none">
+              <text macro="format"/>
+            </if>
+          </choose>
+        </if>
+        <else-if type="book" variable="version" match="all">
+          <!-- For entries in mobile app reference works, place bracketed after the container-title -->
+          <text macro="format"/>
+        </else-if>
+        <else-if type="report">
+          <!-- For chapters in reports, place bracketed after the container title -->
+          <text macro="format"/>
+        </else-if>
+      </choose>
+    </group>
+  </macro>
+  <macro name="secondary-contributors">
+    <choose>
+      <if type="article-journal article-magazine article-newspaper post-weblog review review-book" match="any">
+        <text macro="secondary-contributors-periodical"/>
+      </if>
+      <else-if type="paper-conference">
+        <choose>
+          <if variable="collection-editor editor editorial-director" match="any">
+            <text macro="secondary-contributors-booklike"/>
+          </if>
+          <else>
+            <text macro="secondary-contributors-periodical"/>
+          </else>
+        </choose>
+      </else-if>
+      <else>
+        <text macro="secondary-contributors-booklike"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="secondary-contributors-periodical">
+    <group delimiter="; ">
+      <choose>
+        <if variable="title">
+          <names variable="interviewer" delimiter="; ">
+            <name and="symbol" initialize-with=". " delimiter=", "/>
+            <label form="short" prefix=", " text-case="title"/>
+          </names>
+        </if>
+      </choose>
+      <names variable="translator" delimiter="; ">
+        <name and="symbol" initialize-with=". " delimiter=", "/>
+        <label form="short" prefix=", " text-case="title"/>
+      </names>
+    </group>
+  </macro>
+  <macro name="secondary-contributors-booklike">
+    <group delimiter="; ">
+      <choose>
+        <if variable="title">
+          <names variable="interviewer">
+            <name and="symbol" initialize-with=". " delimiter=", "/>
+            <label form="short" prefix=", " text-case="title"/>
+          </names>
+        </if>
+      </choose>
+      <!-- When editortranslator becomes available, add a test: variable="editortranslator" match="none"; then print translator -->
+      <choose>
+        <if type="post webpage" match="none">
+          <!-- Webpages treat container-title like publisher -->
+          <choose>
+            <if variable="container-title" match="none">
+              <group delimiter="; ">
+                <names variable="container-author">
+                  <label form="verb-short" suffix=" " text-case="title"/>
+                  <name and="symbol" initialize-with=". " delimiter=", "/>
+                </names>
+                <names variable="editor translator" delimiter="; ">
+                  <name and="symbol" initialize-with=". " delimiter=", "/>
+                  <label form="short" prefix=", " text-case="title"/>
+                </names>
+              </group>
+            </if>
+          </choose>
+        </if>
+        <else>
+          <group delimiter="; ">
+            <names variable="container-author">
+              <label form="verb-short" suffix=" " text-case="title"/>
+              <name and="symbol" initialize-with=". " delimiter=", "/>
+            </names>
+            <names variable="editor translator" delimiter="; ">
+              <name and="symbol" initialize-with=". " delimiter=", "/>
+              <label form="short" prefix=", " text-case="title"/>
+            </names>
+          </group>
+        </else>
+      </choose>
+    </group>
+  </macro>
+  <macro name="database-location">
+    <choose>
+      <if variable="archive-place" match="none">
+        <!-- With `archive-place`: physical archives. Without: online archives. -->
+        <!-- Add archive_collection as that becomes available -->
+        <text variable="archive_location"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="number">
+    <choose>
+      <if variable="number">
+        <group delimiter=", ">
+          <group delimiter=" ">
+            <text variable="genre" text-case="title"/>
+            <choose>
+              <if is-numeric="number">
+                <!-- Replace with label variable="number" if that becomes available -->
+                <text term="issue" form="short" text-case="capitalize-first"/>
+                <text variable="number"/>
+              </if>
+              <else>
+                <text variable="number"/>
+              </else>
+            </choose>
+          </group>
+          <choose>
+            <if type="thesis">
+              <choose>
+                <!-- Include the university in brackets if thesis is published -->
+                <if variable="archive DOI URL" match="any">
+                  <text variable="publisher"/>
+                </if>
+              </choose>
+            </if>
+          </choose>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="locators-booklike">
+    <choose>
+      <if type="article-journal article-magazine article-newspaper broadcast interview patent post post-weblog review review-book speech webpage" match="any"/>
+      <else-if type="paper-conference">
+        <choose>
+          <if variable="collection-editor editor editorial-director" match="any">
+            <group delimiter=", ">
+              <text macro="version"/>
+              <text macro="edition"/>
+              <text macro="volume-booklike"/>
+            </group>
+          </if>
+        </choose>
+      </else-if>
+      <else>
+        <group delimiter=", ">
+          <text macro="version"/>
+          <text macro="edition"/>
+          <text macro="volume-booklike"/>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="version">
+    <choose>
+      <if is-numeric="version">
+        <group delimiter=" ">
+          <!-- replace with label variable="version" if that becomes available -->
+          <text term="version" text-case="capitalize-first"/>
+          <text variable="version"/>
+        </group>
+      </if>
+      <else>
+        <text variable="version"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="edition">
+    <choose>
+      <if is-numeric="edition">
+        <group delimiter=" ">
+          <number variable="edition" form="ordinal"/>
+          <label variable="edition" form="short"/>
+        </group>
+      </if>
+      <else>
+        <text variable="edition"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="volume-booklike">
+    <group delimiter=", ">
+      <!-- Report series [ex. 52] -->
+      <choose>
+        <if type="report">
+          <group delimiter=" ">
+            <text variable="collection-title" text-case="title"/>
+            <text variable="collection-number"/>
+          </group>
+        </if>
+      </choose>
+      <choose>
+        <if variable="volume" match="any">
+          <choose>
+            <!-- Non-numeric volumes are already printed as part of the book title -->
+            <if is-numeric="volume" match="none"/>
+            <else>
+              <group delimiter=" ">
+                <label variable="volume" form="short" text-case="capitalize-first"/>
+                <number variable="volume" form="numeric"/>
+              </group>
+            </else>
+          </choose>
+        </if>
+        <else>
+          <group>
+            <!-- Replace with label variable="number-of-volumes" if that becomes available -->
+            <text term="volume" form="short" text-case="capitalize-first" suffix=" "/>
+            <text term="page-range-delimiter" prefix="1"/>
+            <number variable="number-of-volumes" form="numeric"/>
+          </group>
+        </else>
+      </choose>
+      <group delimiter=" ">
+        <label variable="issue" text-case="capitalize-first"/>
+        <text variable="issue"/>
+      </group>
+      <group delimiter=" ">
+        <label variable="page" form="short" suffix=" "/>
+        <text variable="page"/>
+      </group>
+    </group>
+  </macro>
+  <macro name="reviewed-title">
+    <choose>
+      <if variable="reviewed-title">
+        <!-- Not possible to distinguish TV series episode from other reviewed 
+              works [Ex. 69] -->
+        <text variable="reviewed-title" font-style="italic"/>
+      </if>
+      <else>
+        <!-- Assume title is title of reviewed work -->
+        <text variable="title" font-style="italic"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="reviewed-title-intext">
+    <choose>
+      <if variable="reviewed-title">
+        <!-- Not possible to distinguish TV series episode from other reviewed works [Ex. 69] -->
+        <text variable="reviewed-title" form="short" font-style="italic" text-case="title"/>
+      </if>
+      <else>
+        <!-- Assume title is title of reviewed work -->
+        <text variable="title" form="short" font-style="italic" text-case="title"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="format">
+    <choose>
+      <if variable="genre medium" match="any">
+        <group delimiter="; ">
+          <choose>
+            <if variable="number" match="none">
+              <text variable="genre" text-case="capitalize-first"/>
+            </if>
+          </choose>
+          <text variable="medium" text-case="capitalize-first"/>
+        </group>
+      </if>
+      <!-- Generic labels for specific types -->
+      <!-- These should be localized when possible -->
+      <else-if type="dataset">
+        <text value="Data set"/>
+      </else-if>
+      <else-if type="book" variable="version" match="all">
+        <!-- Replace with type="software" and term="software" as that becomes available -->
+        <text value="Computer software"/>
+      </else-if>
+      <else-if type="interview personal_communication" match="any">
+        <choose>
+          <if variable="archive container-title DOI publisher URL" match="none">
+            <text term="letter" text-case="capitalize-first"/>
+          </if>
+          <else-if type="interview">
+            <text term="interview" text-case="capitalize-first"/>
+          </else-if>
+        </choose>
+      </else-if>
+      <else-if type="map">
+        <text value="Map"/>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="format-intext">
+    <choose>
+      <if variable="genre" match="any">
+        <text variable="genre" text-case="capitalize-first"/>
+      </if>
+      <else-if variable="medium">
+        <text variable="medium" text-case="capitalize-first"/>
+      </else-if>
+      <!-- Generic labels for specific types -->
+      <!-- These should be localized when possible -->
+      <else-if type="dataset">
+        <text value="Data set"/>
+      </else-if>
+      <else-if type="book" variable="version" match="all">
+        <!-- Replace with type="software" and term="software" as that becomes available -->
+        <text value="Computer software"/>
+      </else-if>
+      <else-if type="interview personal_communication" match="any">
+        <choose>
+          <if variable="archive container-title DOI publisher URL" match="none">
+            <text term="letter" text-case="capitalize-first"/>
+          </if>
+          <else-if type="interview">
+            <text term="interview" text-case="capitalize-first"/>
+          </else-if>
+        </choose>
+      </else-if>
+      <else-if type="map">
+        <text value="Map"/>
+      </else-if>
+    </choose>
+  </macro>
+  <!-- APA 'source' element contains four parts:
+       container, event, publisher, access -->
+  <macro name="container">
+    <choose>
+      <if type="article-journal article-magazine article-newspaper post-weblog review review-book" match="any">
+        <!-- Periodical items -->
+        <text macro="container-periodical"/>
+      </if>
+      <else-if type="paper-conference">
+        <!-- Determine if paper-conference is a periodical or booklike -->
+        <choose>
+          <if variable="editor editorial-director collection-editor container-author" match="any">
+            <text macro="container-booklike"/>
+          </if>
+          <else>
+            <text macro="container-periodical"/>
+          </else>
+        </choose>
+      </else-if>
+      <else-if type="post webpage" match="none">
+        <!-- post and webpage treat container-title like publisher -->
+        <text macro="container-booklike"/>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="container-periodical">
+    <group delimiter=". ">
+      <group delimiter=", ">
+        <text variable="container-title" font-style="italic" text-case="title"/>
+        <choose>
+          <if variable="volume">
+            <group>
+              <text variable="volume" font-style="italic"/>
+              <text variable="issue" prefix="(" suffix=")"/>
+            </group>
+          </if>
+          <else>
+            <text variable="issue" font-style="italic"/>
+          </else>
+        </choose>
+        <choose>
+          <if variable="page">
+            <text variable="page"/>
+          </if>
+          <else>
+            <!-- Ex. 6: Journal article with article number or eLocator -->
+            <!-- This should be localized -->
+            <text variable="number" prefix="Article "/>
+          </else>
+        </choose>
+      </group>
+      <choose>
+        <if variable="issued">
+          <choose>
+            <if variable="issue page volume" match="none">
+              <text variable="status" text-case="capitalize-first"/>
+            </if>
+          </choose>
+        </if>
+      </choose>
+    </group>
+  </macro>
+  <macro name="container-booklike">
+    <choose>
+      <if variable="container-title" match="any">
+        <group delimiter=" ">
+          <text term="in" text-case="capitalize-first"/>
+          <group delimiter=", ">
+            <names variable="editor translator" delimiter=", &amp; ">
+              <!-- Change to editortranslator and move editor to substitute as that becomes available -->
+              <name and="symbol" initialize-with=". " delimiter=", "/>
+              <label form="short" text-case="title" prefix=" (" suffix=")"/>
+              <substitute>
+                <names variable="editorial-director"/>
+                <names variable="collection-editor"/>
+                <names variable="container-author"/>
+              </substitute>
+            </names>
+            <group delimiter=": " font-style="italic">
+              <text variable="container-title"/>
+              <!-- Replace with volume-title as that becomes available -->
+              <choose>
+                <if is-numeric="volume" match="none">
+                  <group delimiter=" ">
+                    <label variable="volume" form="short" text-case="capitalize-first"/>
+                    <text variable="volume"/>
+                  </group>
+                </if>
+              </choose>
+            </group>
+          </group>
+          <text macro="parenthetical-container"/>
+          <text macro="bracketed-container"/>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="publisher">
+    <group delimiter="; ">
+      <choose>
+        <if type="thesis">
+          <choose>
+            <if variable="archive DOI URL" match="none">
+              <text variable="publisher"/>
+            </if>
+          </choose>
+        </if>
+        <else-if type="post webpage" match="any">
+          <!-- For websites, treat container title like publisher -->
+          <group delimiter="; ">
+            <text variable="container-title" text-case="title"/>
+            <text variable="publisher"/>
+          </group>
+        </else-if>
+        <else-if type="paper-conference">
+          <!-- For paper-conference, don't print publisher if in a journal-like proceedings -->
+          <choose>
+            <if variable="collection-editor editor editorial-director" match="any">
+              <text variable="publisher"/>
+            </if>
+          </choose>
+        </else-if>
+        <else-if type="article-journal article-magazine article-newspaper post-weblog" match="none">
+          <text variable="publisher"/>
+        </else-if>
+      </choose>
+      <group delimiter=", ">
+        <choose>
+          <if variable="archive-place">
+            <!-- With `archive-place`: physical archives. Without: online archives. -->
+            <!-- For physical archives, print the location before the archive name.
+                For electronic archives, these are printed in macro="description". -->
+            <!-- Split "archive_location" into "archive_collection" and "archive_location" as that becomes available -->
+            <!-- Must test for archive_collection:
+                With collection: archive_collection (archive_location), archive, archive-place
+                No collection: archive (archive_location), archive-place
+            -->
+            <text variable="archive_location"/>
+          </if>
+        </choose>
+        <text variable="archive"/>
+        <text variable="archive-place"/>
+      </group>
+    </group>
+  </macro>
+  <macro name="access">
+    <choose>
+      <if variable="DOI" match="any">
+        <text variable="DOI" prefix="https://doi.org/"/>
+      </if>
+      <else-if variable="URL">
+        <group delimiter=" ">
+          <choose>
+            <if variable="issued status" match="none">
+              <group delimiter=" ">
+                <text term="retrieved" text-case="capitalize-first"/>
+                <date variable="accessed" form="text" suffix=","/>
+                <text term="from"/>
+              </group>
+            </if>
+          </choose>
+          <text variable="URL"/>
+        </group>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="event">
+    <choose>
+      <if variable="event">
+        <!-- To prevent Zotero from printing event-place due to its double-mapping of all 'place' to
+             both publisher-place and event-place. Remove this 'choose' when that is changed. -->
+        <choose>
+          <if variable="collection-editor editor editorial-director issue page volume" match="none">
+            <!-- Don't print event info if published in a proceedings -->
+            <group delimiter=", ">
+              <text variable="event"/>
+              <text variable="event-place"/>
+            </group>
+          </if>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <!-- After 'source', APA also prints publication history (original publication, reprint info, retraction info) -->
+  <macro name="publication-history">
+    <choose>
+      <if type="patent" match="none">
+        <group prefix="(" suffix=")">
+          <choose>
+            <if variable="references">
+              <!-- This provides the option for more elaborate description 
+                   of publication history, such as full "reprinted" references
+                   (examples 11, 43, 44) or retracted references -->
+              <text variable="references"/>
+            </if>
+            <else>
+              <group delimiter=" ">
+                <text value="Original work published"/>
+                <choose>
+                  <if is-uncertain-date="original-date">
+                    <text term="circa" form="short"/>
+                  </if>
+                </choose>
+                <date variable="original-date">
+                  <date-part name="year"/>
+                </date>
+              </group>
+            </else>
+          </choose>
+        </group>
+      </if>
+      <else>
+        <text variable="references" prefix="(" suffix=")"/>
+      </else>
+    </choose>
+  </macro>
+  <!-- Legal citations have their own rules -->
+  <macro name="legal-cites">
+    <choose>
+      <if type="legal_case">
+        <group delimiter=". ">
+          <group delimiter=", ">
+            <text variable="title"/>
+            <group delimiter=" ">
+              <text macro="container-legal"/>
+              <text macro="date-legal"/>
+            </group>
+            <text variable="references"/>
+          </group>
+          <text macro="access"/>
+        </group>
+      </if>
+      <else-if type="bill">
+        <!-- Currently designed to handle bills, resolutions, hearings, rederal reports. -->
+        <group delimiter=". ">
+          <group delimiter=", ">
+            <choose>
+              <if variable="number container-title" match="none">
+                <!-- If no number or container-title, then assume it is a hearing -->
+                <text variable="title" font-style="italic"/>
+              </if>
+              <else>
+                <text variable="title"/>
+              </else>
+            </choose>
+            <group delimiter=" ">
+              <text macro="container-legal"/>
+              <text macro="date-legal"/>
+              <choose>
+                <if variable="number container-title" match="none">
+                  <!-- If no number or container-title, then assume it is a hearing -->
+                  <names variable="author" prefix="(testimony of " suffix=")">
+                    <name and="symbol" delimiter=", "/>
+                  </names>
+                </if>
+                <else>
+                  <text variable="status" prefix="(" suffix=")"/>
+                </else>
+              </choose>
+            </group>
+            <text variable="references"/>
+          </group>
+          <text macro="access"/>
+        </group>
+      </else-if>
+      <else-if type="legislation">
+        <!-- Currently designed to handle statutes, codified regulations, executive orders.
+             For uncodified regulations, assume future code section is in status. -->
+        <group delimiter=". ">
+          <group delimiter=", ">
+            <text variable="title"/>
+            <group delimiter=" ">
+              <text macro="container-legal"/>
+              <text macro="date-legal"/>
+              <text variable="status" prefix="(" suffix=")"/>
+            </group>
+            <text variable="references"/>
+          </group>
+          <text macro="access"/>
+        </group>
+      </else-if>
+      <else-if type="treaty">
+        <!-- APA generally defers to Bluebook for legal citations, but diverges without
+             explanation for treaty items. The Bluebook format that was used in APA 6th
+             ed. is used here. -->
+        <group delimiter=", ">
+          <text variable="title" text-case="title"/>
+          <names variable="author">
+            <name initialize-with="." form="short" delimiter="-"/>
+          </names>
+          <text macro="date-legal"/>
+          <text macro="container-legal"/>
+          <text macro="access"/>
+        </group>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="date-legal">
+    <choose>
+      <if type="legal_case">
+        <group prefix="(" suffix=")" delimiter=" ">
+          <text variable="authority"/>
+          <choose>
+            <if variable="container-title" match="any">
+              <!-- Print only year for cases published in reporters-->
+              <date variable="issued" form="numeric" date-parts="year"/>
+            </if>
+            <else>
+              <date variable="issued" form="text"/>
+            </else>
+          </choose>
+        </group>
+      </if>
+      <else-if type="bill legislation" match="any">
+        <group prefix="(" suffix=")" delimiter=" ">
+          <group delimiter=" ">
+            <date variable="original-date">
+              <date-part name="year"/>
+            </date>
+            <text term="and" form="symbol"/>
+          </group>
+          <date variable="issued">
+            <date-part name="year"/>
+          </date>
+        </group>
+      </else-if>
+      <else-if type="treaty">
+        <date variable="issued" form="text"/>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="container-legal">
+    <!-- Expect legal item container-titles to be stored in short form -->
+    <choose>
+      <if type="legal_case">
+        <group delimiter=" ">
+          <choose>
+            <if variable="container-title">
+              <group delimiter=" ">
+                <text variable="volume"/>
+                <text variable="container-title"/>
+                <group delimiter=" ">
+                  <!-- Change to label variable="section" as that becomes available -->
+                  <text term="section" form="symbol"/>
+                  <text variable="section"/>
+                </group>
+                <choose>
+                  <if variable="page page-first" match="any">
+                    <text variable="page-first"/>
+                  </if>
+                  <else>
+                    <text value="___"/>
+                  </else>
+                </choose>
+              </group>
+            </if>
+            <else>
+              <group delimiter=" ">
+                <choose>
+                  <if is-numeric="number">
+                    <!-- Replace with label variable="number" if that becomes available -->
+                    <text term="issue" form="short" text-case="capitalize-first"/>
+                  </if>
+                </choose>
+                <text variable="number"/>
+              </group>
+            </else>
+          </choose>
+        </group>
+      </if>
+      <else-if type="bill">
+        <group delimiter=", ">
+          <group delimiter=" ">
+            <text variable="genre"/>
+            <group delimiter=" ">
+              <choose>
+                <if variable="chapter-number container-title" match="none">
+                  <!-- Replace with label variable="number" as that becomes available -->
+                  <text term="issue" form="short"/>
+                </if>
+              </choose>
+              <text variable="number"/>
+            </group>
+          </group>
+          <text variable="authority"/>
+          <text variable="chapter-number"/>
+          <group delimiter=" ">
+            <text variable="volume"/>
+            <text variable="container-title"/>
+            <text variable="page-first"/>
+          </group>
+        </group>
+      </else-if>
+      <else-if type="legislation">
+        <choose>
+          <if variable="number">
+            <!--There's a public law number-->
+            <group delimiter=", ">
+              <text variable="number" prefix="Pub. L. No. "/>
+              <group delimiter=" ">
+                <text variable="volume"/>
+                <text variable="container-title"/>
+                <text variable="page-first"/>
+              </group>
+            </group>
+          </if>
+          <else>
+            <group delimiter=" ">
+              <text variable="volume"/>
+              <text variable="container-title"/>
+              <choose>
+                <if variable="section">
+                  <group delimiter=" ">
+                    <!-- Change to label variable="section" as that becomes available -->
+                    <text term="section" form="symbol"/>
+                    <text variable="section"/>
+                  </group>
+                </if>
+                <else>
+                  <text variable="page-first"/>
+                </else>
+              </choose>
+            </group>
+          </else>
+        </choose>
+      </else-if>
+      <else-if type="treaty">
+        <group delimiter=" ">
+          <number variable="volume"/>
+          <text variable="container-title"/>
+          <choose>
+            <if variable="page page-first" match="any">
+              <text variable="page-first"/>
+            </if>
+            <else>
+              <group delimiter=" ">
+                <!-- Replace with label variable="number" if that becomes available -->
+                <text term="issue" form="short" text-case="capitalize-first"/>
+                <text variable="number"/>
+              </group>
+            </else>
+          </choose>
+        </group>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="citation-locator">
+    <group delimiter=" ">
+      <choose>
+        <if locator="chapter">
+          <label variable="locator" text-case="capitalize-first"/>
+        </if>
+        <else>
+          <label variable="locator" form="short"/>
+        </else>
+      </choose>
+      <text variable="locator"/>
+    </group>
+  </macro>
+  <citation et-al-min="3" et-al-use-first="1" disambiguate-add-year-suffix="true" disambiguate-add-names="true" disambiguate-add-givenname="true" collapse="year" givenname-disambiguation-rule="primary-name">
+    <sort>
+      <key macro="author-bib" names-min="3" names-use-first="1"/>
+      <key macro="date-sort-group"/>
+      <key macro="date-sort-date" sort="ascending"/>
+      <key variable="status"/>
+    </sort>
+    <layout prefix="(" suffix=")" delimiter="; ">
+      <group delimiter=", ">
+        <text macro="author-intext"/>
+        <text macro="date-intext"/>
+        <text macro="citation-locator"/>
+      </group>
+    </layout>
+  </citation>
+  <bibliography hanging-indent="true" et-al-min="21" et-al-use-first="19" et-al-use-last="true" entry-spacing="0" line-spacing="2">
+    <sort>
+      <key macro="author-bib"/>
+      <key macro="date-sort-group"/>
+      <key macro="date-sort-date" sort="ascending"/>
+      <key variable="status"/>
+      <key macro="title"/>
+    </sort>
+    <layout>
+      <choose>
+        <if type="bill legal_case legislation treaty" match="any">
+          <!-- Legal items have different orders and delimiters -->
+          <choose>
+            <if variable="DOI URL" match="any">
+              <text macro="legal-cites"/>
+            </if>
+            <else>
+              <text macro="legal-cites" suffix="."/>
+            </else>
+          </choose>
+        </if>
+        <else>
+          <group delimiter=" ">
+            <group delimiter=". " suffix=".">
+              <text macro="author-bib"/>
+              <text macro="date-bib"/>
+              <text macro="title-and-descriptions"/>
+              <text macro="container"/>
+              <text macro="event"/>
+              <text macro="publisher"/>
+            </group>
+            <text macro="access"/>
+            <text macro="publication-history"/>
+          </group>
+        </else>
+      </choose>
+    </layout>
+  </bibliography>
+</style>

+ 138 - 0
example/assets/pandoc-scholar/example/article.md

@@ -0,0 +1,138 @@
+---
+title: Example article written in pandoc-flavored Markdown
+author:
+  - Jane Doe:
+      institute:
+        - fosg
+        - fop
+      email: jane.doe@example.com
+      orcid: 0000-0000-0000-0000
+      equal_contributor: "yes"
+      correspondence: "yes"
+  - John Q. Doe:
+      institute: fosg
+      equal_contributor: "yes"
+  - Peder Ås:
+      institute: fosg
+  - Juan Pérez:
+      institute: acme
+      email: juan.perez@example.edu
+      correspondence: "yes"
+institute:
+  - fosg:
+      name: Formatting Open Science Group
+      address: 23 Science Street, Eureka, Mississippi, USA
+      phone: +1 (555) 423 1338
+      email: '{firstname}.{lastname}\@fosg.example.com'
+  - fop: Federation of Planets
+  - acme:
+      name: Acme Corporation
+bibliography: bibliography.bib
+csl: apa.csl
+link-citations: true
+project:
+  title: Pandoc Scholar Example
+  zip-url: https://github.com/pandoc-scholar/pandoc-scholar/releases
+  github-url: https://github.com/pandoc-scholar/pandoc-scholar/
+...
+
+# Abstract
+
+This is an example article.  There is not much to see but filler text.
+
+
+# Further reading
+
+See the [pandoc manual](http://pandoc.org/MANUAL.html) for more information on
+pandoc.
+
+Authors struggling to fill this document with content are referred to
+@Upper_writers_1974.
+
+
+# Lorem Ipsum
+
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
+incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
+nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
+fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
+culpa qui officia deserunt mollit anim id est laborum.
+
+
+## Dolor sit amet
+
+Deserunt excepturi commodi sit qui velit quis. Delectus sit omnis culpa
+accusamus repellat iusto vel. Quod deserunt quasi nisi dolor. Quo eum id
+reiciendis dolor. Est qui illum et.
+
+Quo dolore molestiae et laboriosam occaecati explicabo corrupti. Earum expedita
+ducimus quaerat est quam ut molestiae. Illum deleniti vel labore facilis et cum
+est. Est nemo est vel ad. Assumenda consequatur rerum officiis atque officia.
+Est nihil iste cumque ad qui.
+
+Eaque sed sit totam enim. Et explicabo illum rerum aut. Aspernatur sit dolor
+animi tempora cum. Maxime in soluta aut. Explicabo id maiores voluptates aut
+voluptas id. Dolore sed labore voluptatem omnis doloribus mollitia aliquid
+cupiditate.
+
+In rerum saepe placeat. Deleniti suscipit sed quam fugit assumenda sit et
+tempora. Veniam illum expedita quia error qui quibusdam rerum. Qui ut sunt est
+eos.
+
+Recusandae et sit ut. Impedit deserunt consequatur et dignissimos vel et.
+Eveniet voluptatem magni quis est dolore excepturi officia nihil. Debitis quae
+commodi error.
+
+Modi debitis et ut saepe saepe dolorem. Quis sed autem expedita est voluptate
+esse neque. Quod aspernatur quam velit placeat nihil omnis debitis. Corporis sit
+rerum consectetur possimus rerum consequuntur. Rerum quas ut repellendus
+tenetur. Consequuntur adipisci dolores eveniet qui est ipsum.
+
+Atque deserunt necessitatibus unde facere amet molestiae. Ipsam at quia placeat
+aliquam autem. Enim corporis accusamus consequatur.
+
+Et vitae unde perferendis tenetur cupiditate non exercitationem. Aut molestiae
+sed est. Deserunt repudiandae non quia esse ad vitae vel in. Et reprehenderit
+dolore et aut distinctio.
+
+Vel quia molestiae quod sint fuga omnis est fuga. Minus quaerat repellat quod.
+Rerum rerum enim repellendus rerum consequatur non perspiciatis. Illo sapiente
+sed natus ipsa quia temporibus. Est nostrum fugit odio non voluptatem odit
+rerum. Et consequatur aut nostrum accusamus earum.
+
+Sit explicabo iure eligendi consequatur. Consequatur atque praesentium
+consequatur dolores quam. Neque eius provident harum placeat. Quo aut pariatur
+illum laborum porro minima. Dolorem nobis esse laudantium. Perspiciatis
+voluptate deleniti voluptatem et.
+
+Quos assumenda magnam non inventore. Adipisci repellendus eligendi possimus
+voluptate numquam voluptatem natus. Deleniti cupiditate facilis commodi aliquid
+voluptatem laudantium autem similique. Vel sunt cupiditate consequatur. Dolorum
+voluptatem nihil culpa fugiat non itaque animi iusto. Unde incidunt numquam
+vitae.
+
+Eius provident voluptatem animi quidem quia. Velit omnis voluptas atque.
+Voluptatem accusamus atque blanditiis commodi aspernatur ullam ad. Nulla quidem
+fugiat explicabo quo dolor hic.
+
+Rerum dolore quo ratione sed aspernatur doloremque. Ut neque laudantium quae
+enim dolores et. Laudantium dolores id assumenda autem aspernatur. Accusamus
+doloribus nihil rerum et atque est aut delectus.
+
+Nulla itaque mollitia vitae accusamus. Eveniet soluta praesentium dolore harum
+culpa. Totam voluptatem non aspernatur.
+
+Eveniet in illo consequatur. Fugiat et totam unde nihil quis. Non et velit
+recusandae blanditiis unde. Eaque fugiat id pariatur. Non numquam minima aut.
+Iste eos et autem et exercitationem velit officiis vero.
+
+Ullam minima quisquam est ducimus iste. Commodi occaecati inventore provident
+voluptatem repudiandae. Quia est qui dolore sit nisi officia doloremque dolor.
+Perspiciatis tempore laudantium quia repellendus quia deleniti. Sed consequuntur
+autem quisquam aliquam.
+
+Ut dolores natus et sunt delectus nulla. Ipsum eum quia ex est ut quia. Ratione
+et eius consequatur veritatis hic expedita ea.
+
+# References

+ 13 - 0
example/assets/pandoc-scholar/example/bibliography.bib

@@ -0,0 +1,13 @@
+@article {Upper_writers_1974,
+  author = {Upper, Dennis},
+  title = {The unsuccessful self-treatment of a case of “writer's block”},
+  journal = {Journal of Applied Behavior Analysis},
+  volume = {7},
+  number = {3},
+  publisher = {Blackwell Publishing Ltd},
+  issn = {1938-3703},
+  url = {http://dx.doi.org/10.1901/jaba.1974.7-497a},
+  doi = {10.1901/jaba.1974.7-497a},
+  pages = {497--497},
+  year = {1974},
+}

+ 173 - 0
example/assets/pandoc-scholar/example/rmarkdown-scholarpandoc.Rmd

@@ -0,0 +1,173 @@
+---
+title: "Testing author list with scholarpandoc"
+author:
+- Jane Doe:
+    institute:
+    - fosg
+    - fop
+    email: jane.doe@example.com
+    orcid: 0000-0000-0000-0000
+    equal_contributor: 'yes'
+    correspondence: 'yes'
+- John Q. Doe:
+    institute: fosg
+    equal_contributor: 'yes'
+- Peder Ås:
+    institute: fosg
+- Juan Pérez:
+    institute: acme
+    email: juan.perez@example.edu
+    correspondence: 'yes'
+date: "1/20/2020"
+output:
+  bookdown::word_document2:
+    fig_caption: yes
+    reference_docx: ../templates/template.docx
+    pandoc_args:
+    - --lua-filter=../lua-filters/scholarly-metadata/scholarly-metadata.lua
+    - --lua-filter=../lua-filters/author-info-blocks/author-info-blocks.lua
+    - --lua-filter=../lua-filters/abstract-to-meta/abstract-to-meta.lua
+    - --lua-filter=../lua-filters/pagebreak/pagebreak.lua
+  bookdown::html_document2:    
+    fig_caption: yes
+    template: ../templates/pandoc-scholar.html
+    css: ../templates/styles/pandoc-scholar.css
+    self_contained: true
+    pandoc_args:
+      - --lua-filter=../lua-filters/cito/cito.lua
+      - --lua-filter=../lua-filters/abstract-to-meta/abstract-to-meta.lua
+      - --lua-filter=../lua-filters/scholarly-metadata/scholarly-metadata.lua
+      - --lua-filter=../scholar-filters/template-helper.lua
+  bookdown::pdf_document2:
+    keep_tex: true
+    toc: false
+    fig_caption: yes
+    template: ../templates/pandoc-scholar.latex
+    pandoc_args:
+      - --lua-filter=../lua-filters/cito/cito.lua
+      - --lua-filter=../lua-filters/abstract-to-meta/abstract-to-meta.lua
+      - --lua-filter=../lua-filters/scholarly-metadata/scholarly-metadata.lua
+      - --lua-filter=../scholar-filters/template-helper.lua  
+institute:
+- fosg:
+    name: Formatting Open Science Group
+    address: 23 Science Street, Eureka, Mississippi, USA
+    phone: +1 (555) 423 1338
+    email: '{firstname}.{lastname}\@fosg.example.com'
+- fop: Federation of Planets
+- acme:
+    name: Acme Corporation
+bibliography: ../example/bibliography.bib
+csl: ../csl/chicago-author-date.csl
+link-citations: yes
+project:
+  title: Pandoc Scholar Example
+  zip-url: https://github.com/pandoc-scholar/pandoc-scholar/releases
+  github-url: https://github.com/pandoc-scholar/pandoc-scholar/
+...
+
+# Abstract
+
+This is an example article.  There is not much to see but filler text.
+
+
+# Further reading
+
+See the [pandoc manual](http://pandoc.org/MANUAL.html) for more information on
+pandoc.
+
+Authors struggling to fill this document with content are referred to
+@Upper_writers_1974.
+
+
+# Lorem Ipsum
+
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
+incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
+nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
+fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
+culpa qui officia deserunt mollit anim id est laborum.
+
+
+## Dolor sit amet
+
+Deserunt excepturi commodi sit qui velit quis. Delectus sit omnis culpa
+accusamus repellat iusto vel. Quod deserunt quasi nisi dolor. Quo eum id
+reiciendis dolor. Est qui illum et.
+
+Quo dolore molestiae et laboriosam occaecati explicabo corrupti. Earum expedita
+ducimus quaerat est quam ut molestiae. Illum deleniti vel labore facilis et cum
+est. Est nemo est vel ad. Assumenda consequatur rerum officiis atque officia.
+Est nihil iste cumque ad qui.
+
+Eaque sed sit totam enim. Et explicabo illum rerum aut. Aspernatur sit dolor
+animi tempora cum. Maxime in soluta aut. Explicabo id maiores voluptates aut
+voluptas id. Dolore sed labore voluptatem omnis doloribus mollitia aliquid
+cupiditate.
+
+In rerum saepe placeat. Deleniti suscipit sed quam fugit assumenda sit et
+tempora. Veniam illum expedita quia error qui quibusdam rerum. Qui ut sunt est
+eos.
+
+Recusandae et sit ut. Impedit deserunt consequatur et dignissimos vel et.
+Eveniet voluptatem magni quis est dolore excepturi officia nihil. Debitis quae
+commodi error.
+
+Modi debitis et ut saepe saepe dolorem. Quis sed autem expedita est voluptate
+esse neque. Quod aspernatur quam velit placeat nihil omnis debitis. Corporis sit
+rerum consectetur possimus rerum consequuntur. Rerum quas ut repellendus
+tenetur. Consequuntur adipisci dolores eveniet qui est ipsum.
+
+Atque deserunt necessitatibus unde facere amet molestiae. Ipsam at quia placeat
+aliquam autem. Enim corporis accusamus consequatur.
+
+Et vitae unde perferendis tenetur cupiditate non exercitationem. Aut molestiae
+sed est. Deserunt repudiandae non quia esse ad vitae vel in. Et reprehenderit
+dolore et aut distinctio.
+
+Vel quia molestiae quod sint fuga omnis est fuga. Minus quaerat repellat quod.
+Rerum rerum enim repellendus rerum consequatur non perspiciatis. Illo sapiente
+sed natus ipsa quia temporibus. Est nostrum fugit odio non voluptatem odit
+rerum. Et consequatur aut nostrum accusamus earum.
+
+Sit explicabo iure eligendi consequatur. Consequatur atque praesentium
+consequatur dolores quam. Neque eius provident harum placeat. Quo aut pariatur
+illum laborum porro minima. Dolorem nobis esse laudantium. Perspiciatis
+voluptate deleniti voluptatem et.
+
+Quos assumenda magnam non inventore. Adipisci repellendus eligendi possimus
+voluptate numquam voluptatem natus. Deleniti cupiditate facilis commodi aliquid
+voluptatem laudantium autem similique. Vel sunt cupiditate consequatur. Dolorum
+voluptatem nihil culpa fugiat non itaque animi iusto. Unde incidunt numquam
+vitae.
+
+Eius provident voluptatem animi quidem quia. Velit omnis voluptas atque.
+Voluptatem accusamus atque blanditiis commodi aspernatur ullam ad. Nulla quidem
+fugiat explicabo quo dolor hic.
+
+Rerum dolore quo ratione sed aspernatur doloremque. Ut neque laudantium quae
+enim dolores et. Laudantium dolores id assumenda autem aspernatur. Accusamus
+doloribus nihil rerum et atque est aut delectus.
+
+Nulla itaque mollitia vitae accusamus. Eveniet soluta praesentium dolore harum
+culpa. Totam voluptatem non aspernatur.
+
+Eveniet in illo consequatur. Fugiat et totam unde nihil quis. Non et velit
+recusandae blanditiis unde. Eaque fugiat id pariatur. Non numquam minima aut.
+Iste eos et autem et exercitationem velit officiis vero.
+
+Ullam minima quisquam est ducimus iste. Commodi occaecati inventore provident
+voluptatem repudiandae. Quia est qui dolore sit nisi officia doloremque dolor.
+Perspiciatis tempore laudantium quia repellendus quia deleniti. Sed consequuntur
+autem quisquam aliquam.
+
+Ut dolores natus et sunt delectus nulla. Ipsum eum quia ex est ut quia. Ratione
+et eius consequatur veritatis hic expedita ea.
+
+# References
+
+pandoc_args:
+    - --lua-filter=../lua-filters/scholarly-metadata/scholarly-metadata.lua
+    - --lua-filter=../lua-filters/author-info-blocks/author-info-blocks.lua
+    - --lua-filter=../lua-filters/abstract-to-meta/abstract-to-meta.lua

+ 21 - 0
example/assets/pandoc-scholar/lua-filters/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017-2020 John MacFarlane and contributors
+
+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.

+ 40 - 0
example/assets/pandoc-scholar/lua-filters/README.md

@@ -0,0 +1,40 @@
+[![travis build
+status](https://img.shields.io/travis/pandoc/lua-filters/master.svg?label=travis+build)](https://travis-ci.org/pandoc/lua-filters)
+
+# Lua Filters
+
+This repository collects Lua filters for pandoc.
+
+To learn about Lua filters, see the
+[documentation](http://pandoc.org/lua-filters.html).
+
+Structure
+---------
+
+Each filter goes in its own subdirectory.  Each subdirectory contains:
+
+- the filter itself (e.g. `wordcount.lua`)
+- a `README.md` describing the use of the filter
+- a `Makefile` with a `test` target to test the filter
+- some data files used for the tests, which may also serve
+  as examples
+
+Requirements
+------------
+
+Filters are tested against the latest pandoc version.  There is
+no guarantee that filters will work with older versions, but
+many do.
+
+Some filters depend on external programs, which must be installed
+separately.  Refer to the filters' README for detailed
+requirements.
+
+Contributing
+------------
+
+PRs for new filters are welcome, provided they conform to these
+guidelines. Lua code should ideally follow the Olivine Labs [Lua
+style guide].
+
+[Lua style guide]: https://github.com/Olivine-Labs/lua-style-guide

+ 37 - 0
example/assets/pandoc-scholar/lua-filters/abstract-to-meta/README.md

@@ -0,0 +1,37 @@
+# abstract-to-meta
+
+This moves a document's abstract from the main text into the
+metadata. Metadata elements usually allow for finer placement
+control in the final output, but writing body text is easier and
+more natural.
+
+## Defining an Abstract
+
+A document abstract can either be put directly in the document
+metadata, for example by inserting an *abstract* attribute into a
+YAML block.
+
+    ---
+    abstract: |
+      Place abstract here.
+
+      Multiple paragraphs are possible.
+    ---
+
+The additional indentation and formatting requirements in YAML
+headers can be confusing or annoying for authors. It is hence
+preferable to allow abstracts be written as normal sections.
+
+    # Abstract
+
+    Place abstract here.
+
+    Multiple paragraphs are possible.
+
+This filter turns the latter into the former by looking for a
+top-level header whose ID is `abstract`. Pandoc auto-creates IDs
+based on header contents, so a header titled *Abstract* will
+satisfy this condition.^[1]
+
+[1]: This requires the `auto_identifier` extension. It is
+     enabled by default.

+ 55 - 0
example/assets/pandoc-scholar/lua-filters/abstract-to-meta/abstract-to-meta.lua

@@ -0,0 +1,55 @@
+--[[
+abstract-to-meta – move an "abstract" section into document metadata
+
+Copyright: © 2017–2020 Albert Krewinkel
+License:   MIT – see LICENSE file for details
+]]
+local abstract = {}
+
+--- Extract abstract from a list of blocks.
+function abstract_from_blocklist (blocks)
+  local body_blocks = {}
+  local looking_at_abstract = false
+
+  for _, block in ipairs(blocks) do
+    if block.t == 'Header' and block.level == 1 then
+      if block.identifier == 'abstract' then
+        looking_at_abstract = true
+      else
+        looking_at_abstract = false
+        body_blocks[#body_blocks + 1] = block
+      end
+    elseif looking_at_abstract then
+      abstract[#abstract + 1] = block
+    else
+      body_blocks[#body_blocks + 1] = block
+    end
+  end
+
+  return body_blocks
+end
+
+if PANDOC_VERSION >= {2,9,2} then
+  -- Check all block lists with pandoc 2.9.2 or later
+  return {{
+      Blocks = abstract_from_blocklist,
+      Meta = function (meta)
+        if not meta.abstract and #abstract > 0 then
+          meta.abstract = pandoc.MetaBlocks(abstract)
+        end
+        return meta
+      end
+  }}
+else
+  -- otherwise, just check the top-level block-list
+  return {{
+      Pandoc = function (doc)
+        local meta = doc.meta
+        local other_blocks = abstract_from_blocklist(doc.blocks)
+        if not meta.abstract and #abstract > 0 then
+          meta.abstract = pandoc.MetaBlocks(abstract)
+        end
+        return pandoc.Pandoc(other_blocks, meta)
+      end,
+  }}
+end

+ 59 - 0
example/assets/pandoc-scholar/lua-filters/author-info-blocks/README.md

@@ -0,0 +1,59 @@
+# author-info-blocks
+
+This filter adds author-related header blocks usually included in
+scholarly articles, such as a list of author affiliations,
+correspondence information, and on notes equal contributors.
+
+
+## Dependencies
+
+This filter assumes metadata in the canonical format generated by
+the [scholarly-metadata filter](../scholarly-metadata).
+
+## Usage
+
+The filter should be run after *scholarly-metadata.lua*:
+
+    pandoc --lua-filter=scholarly-metadata/scholarly-metadata.lua \
+           --lua-filter=author-info-blocks/author-inffo-blocks.lua \
+           --output=outfile.pdf --pdf-engine=xelatex \
+           article.md
+
+The ways in which affiliation data should be given is described
+in the docs for **scholarly-metadata.lua*. Additionally, authors
+who contributed equally to an article can be marked by adding
+`equal_contributor: yes` to the respective YAML objects.
+Similarly, corresponding authors should be marked with
+`correspondence: yes` and have an `email` listed.
+
+### Example
+
+Take the following example YAML block:
+
+``` yaml
+---
+title: Affiliation Blocks Example 
+author:
+  - Jane Doe:
+      institute:
+        - federation
+      equal_contributor: "yes"
+      correspondence: "yes"
+      email: jane.doe@example.com
+  - John Q. Doe:
+      institute: [federation, acme]
+      equal_contributor: "yes"
+  - Juan Pérez:
+      institute: acme
+institute:
+  - federation: Federation of Planets
+  - acme:
+      name: Acme Corporation
+---
+```
+
+This will mark Jane Doe and John Q. Doe as equal contributors and
+Jane Doe as the sole corresponding author. Below is a screenshot
+of a document header created from this metadata.
+
+![sample output](sample.png)

+ 176 - 0
example/assets/pandoc-scholar/lua-filters/author-info-blocks/author-info-blocks.lua

@@ -0,0 +1,176 @@
+--[[
+affiliation-blocks – generate title components
+
+Copyright © 2017–2020 Albert Krewinkel
+
+Permission to use, copy, modify, and/or distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright notice
+and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+]]
+local List = require 'pandoc.List'
+local utils = require 'pandoc.utils'
+local stringify = utils.stringify
+
+local default_marks
+local default_marks = {
+  corresponding_author = FORMAT == 'latex'
+    and {pandoc.RawInline('latex', '*')}
+    or {pandoc.Str '✉'},
+  equal_contributor = FORMAT == 'latex'
+    and {pandoc.RawInline('latex', '$\\dagger{}$')}
+    or {pandoc.Str '*'},
+}
+
+local function intercalate(lists, elem)
+  local result = List:new{}
+  for i = 1, (#lists - 1) do
+    result:extend(lists[i])
+    result:extend(elem)
+  end
+  if #lists > 0 then
+    result:extend(lists[#lists])
+  end
+  return result
+end
+
+--- Check whether the given author is a corresponding author
+local function is_corresponding_author(author)
+  return author.correspondence and author.email
+end
+
+--- Create inlines for a single author (includes all author notes)
+local function author_inline_generator (get_mark)
+  return function (author)
+    local author_marks = List:new{}
+    if author.equal_contributor then
+      author_marks[#author_marks + 1] = get_mark 'equal_contributor'
+    end
+    local idx_str
+    for _, idx in ipairs(author.institute) do
+      if type(idx) ~= 'table' then
+        idx_str = tostring(idx)
+      else
+        idx_str = stringify(idx)
+      end
+      author_marks[#author_marks + 1] = {pandoc.Str(idx_str)}
+    end
+    if is_corresponding_author(author) then
+      author_marks[#author_marks + 1] = get_mark 'corresponding_author'
+    end
+    local res = List.clone(author.name)
+    res[#res + 1] = pandoc.Superscript(intercalate(author_marks, {pandoc.Str ','}))
+    return res
+  end
+end
+
+local function is_equal_contributor (author)
+  return author.equal_contributor
+end
+
+--- Create equal contributors note.
+local function create_equal_contributors_block(authors, mark)
+  local has_equal_contribs = List:new(authors):find_if(is_equal_contributor)
+  if not has_equal_contribs then
+    return nil
+  end
+  local contributors = {
+    pandoc.Superscript(mark'equal_contributor'),
+    pandoc.Space(),
+    pandoc.Str 'These authors contributed equally to this work.'
+  }
+  return List:new{pandoc.Para(contributors)}
+end
+
+--- Generate a block list all affiliations, marked with arabic numbers.
+local function create_affiliations_blocks(affiliations)
+  local affil_lines = List:new(affiliations):map(
+    function (affil, i)
+      local num_inlines = List:new{
+        pandoc.Superscript{pandoc.Str(tostring(i))},
+        pandoc.Space()
+      }
+      return num_inlines .. affil.name
+    end
+                                                )
+  return {pandoc.Para(intercalate(affil_lines, {pandoc.LineBreak()}))}
+end
+
+--- Generate a block element containing the correspondence information
+local function create_correspondence_blocks(authors, mark)
+  local corresponding_authors = List:new{}
+  for _, author in ipairs(authors) do
+    if is_corresponding_author(author) then
+      local mailto = 'mailto:' .. pandoc.utils.stringify(author.email)
+      local author_with_mail = List:new(
+        author.name .. List:new{pandoc.Space(),  pandoc.Str '<'} ..
+        author.email .. List:new{pandoc.Str '>'}
+      )
+      local link = pandoc.Link(author_with_mail, mailto)
+      table.insert(corresponding_authors, {link})
+    end
+  end
+  if #corresponding_authors == 0 then
+    return nil
+  end
+  local correspondence = List:new{
+    pandoc.Superscript(mark'corresponding_author'),
+    pandoc.Space(),
+    pandoc.Str'Correspondence:',
+    pandoc.Space()
+  }
+  local sep = List:new{pandoc.Str',',  pandoc.Space()}
+  return {
+    pandoc.Para(correspondence .. intercalate(corresponding_authors, sep))
+  }
+end
+
+--- Generate a list of inlines containing all authors.
+local function create_authors_inlines(authors, mark)
+  local inlines_generator = author_inline_generator(mark)
+  local inlines = List:new(authors):map(inlines_generator)
+  local and_str = List:new{pandoc.Space(), pandoc.Str'and', pandoc.Space()}
+
+  local last_author = inlines[#inlines]
+  inlines[#inlines] = nil
+  local result = intercalate(inlines, {pandoc.Str ',', pandoc.Space()})
+  if #authors > 1 then
+    result:extend(List:new{pandoc.Str ","} .. and_str)
+  end
+  result:extend(last_author)
+  return result
+end
+
+return {
+  {
+    Pandoc = function (doc)
+      local meta = doc.meta
+      local body = List:new{}
+
+      local mark = function (mark_name) return default_marks[mark_name] end
+
+      body:extend(create_equal_contributors_block(doc.meta.author, mark) or {})
+      body:extend(create_affiliations_blocks(doc.meta.institute) or {})
+      body:extend(create_correspondence_blocks(doc.meta.author, mark) or {})
+      body:extend(doc.blocks)
+
+      -- Overwrite authors with formatted values. We use a single, formatted
+      -- string for most formats. LaTeX output, however, looks nicer if we
+      -- provide a authors as a list.
+      meta.author = FORMAT:match 'latex'
+        and pandoc.MetaList(doc.meta.author):map(author_inline_generator(mark))
+        or pandoc.MetaInlines(create_authors_inlines(doc.meta.author, mark))
+      -- Institute info is now baked into the affiliations block.
+      meta.institute = nil
+
+      return pandoc.Pandoc(body, meta)
+    end
+  }
+}

+ 39 - 0
example/assets/pandoc-scholar/lua-filters/bibexport/README.md

@@ -0,0 +1,39 @@
+# bibexport
+
+Export all cited references into a single bibtex file. This is
+most useful when writing collaboratively while using a large,
+private bibtex collection. Using the bibexport filter allows to
+create a reduced bibtex file suitable for sharing with
+collaborators.
+
+## Prerequisites
+
+This filter expects the `bibexport` executable to be installed
+and in the user's PATH. Installation differs across systems.
+Users of the TeX Live distribution can install the [bibexport]
+package by running
+
+    tlmgr install bibexport
+
+Windows appears to be unsupported at the moment.
+
+[bibexport]: https://www.ctan.org/pkg/bibexport
+
+## Usage
+
+The filter runs `bibexport` on a temporary *aux* file, creating
+the file *bibexport.bib* on success. The name of the temporary
+*.aux* file can be set via the `auxfile` meta value; if no value
+is specified, *bibexport.aux* will be used as filename.
+
+Please note that `bibexport` prints messages to stdout. Pandoc
+should be called with the `-o` or `--output` option instead of
+redirecting stdout to a file. E.g.
+
+    pandoc --lua-filter=bibexport.lua article.md -o article.html
+
+or, when the filter is called in a one-off fashion
+
+    pandoc --lua-filter=bibexport.lua article.md -o /dev/null
+    
+

+ 89 - 0
example/assets/pandoc-scholar/lua-filters/bibexport/bibexport.lua

@@ -0,0 +1,89 @@
+local utils = require 'pandoc.utils'
+local List = require 'pandoc.List'
+
+local citation_id_set = {}
+
+-- Collect all citation IDs.
+function Cite (c)
+  local cs = c.citations
+  for i = 1, #cs do
+    citation_id_set[cs[i].id or cs[i].citationId] = true
+  end
+end
+
+--- Return a list of citation IDs
+function citation_ids ()
+  local citations = {};
+  for cid, _ in pairs(citation_id_set) do
+    citations[#citations + 1] = cid
+  end
+  return citations
+end
+
+--- stringify meta inline elements. Pandoc prior to version 2.8
+-- didn't properly tag MetaInline values, so making it necessary to use an
+-- auxiliary Span.
+local stringifyMetaInlines = function (el)
+  return el.t
+    and utils.stringify(el)
+    or utils.stringify(pandoc.Span(el))
+end
+
+function bibdata (bibliography)
+  function bibname (bibitem)
+    return type(bibitem) == 'string'
+      and bibitem:gsub('%.bib$', '')
+      -- bibitem is assumed to be a list of inlines or MetaInlines element
+      or stringifyMetaInlines(bibitem):gsub('%.bib$', '')
+  end
+
+  local bibs = bibliography.t == 'MetaList'
+    and List.map(bibliography, bibname)
+    or {bibname(bibliography)}
+  return table.concat(bibs, ',')
+end
+
+function aux_content(bibliography)
+  local cites = citation_ids()
+  table.sort(cites)
+  local citations = table.concat(cites, ',')
+  return table.concat(
+    {
+      '\\bibstyle{alpha}',
+      '\\bibdata{' .. bibdata(bibliography) .. '}',
+      '\\citation{' .. citations .. '}',
+      '',
+    },
+    '\n'
+  )
+end
+
+function write_dummy_aux (bibliography, auxfile)
+  local filename
+  if type(auxfile) == 'string' then
+    filename = auxfile
+  elseif type(auxfile) == 'table' then
+    -- assume list of inlines
+    filename = utils.stringify(pandoc.Span(auxfile))
+  else
+    filename = 'bibexport.aux'
+  end
+  local fh = io.open(filename, 'w')
+  fh:write(aux_content(bibliography))
+  fh:close()
+  io.stdout:write('Aux written to ' .. filename .. '\n')
+  return filename
+end
+
+function Pandoc (doc)
+  local meta = doc.meta
+  if not meta.bibliography then
+    return nil
+  else
+    -- create a dummy .aux file
+    local auxfile_name = write_dummy_aux(meta.bibliography, meta.auxfile)
+    os.execute('bibexport ' .. auxfile_name)
+    io.stdout:write('Output written to bibexport.bib\n')
+    return nil
+  end
+end

+ 85 - 0
example/assets/pandoc-scholar/lua-filters/cito/README.md

@@ -0,0 +1,85 @@
+# cito
+
+This filter extracts optional CiTO (Citation Typing Ontology)
+information from citations and stores the information in the
+document's metadata. The extracted info is intended to be used in
+combination with other filters, templates, or custom writers. It
+is mandatory to run pandoc-citeproc *after* this filter if CiTO
+data is embedded in the document; otherwise pandoc-citeproc will
+interpret CiTO properties as part of the citation ID.
+
+## Using the Citation Typing Ontology
+
+The [citation typing ontology] (CiTO) allows authors to specify the
+reason a citation is given. This is helpful for the authors and
+their co-authors, and furthermore adds data that can be used by
+readers to search and navigate relevant publications.
+
+A CiTO annotation must come before the citation key and be
+followed by a colon. E.g., `@method_in:towbin_1979` signifies
+that the citation with ID *towbin_1979* is cited because the
+method described in that paper has been used in the paper at
+hand.
+
+[citation typing ontology]: http://purl.org/spar/cito
+
+## Recognized CiTO properties
+
+Below is the list of CiTO properties recognized by the filter,
+together with the aliases that can be used as shorthands.
+
+- agrees_with
+  - agree_with
+- citation
+- cites
+- cites_as_authority
+  - as_authority
+  - authority
+- cites_as_data_source
+- cites_as_evidence
+  - as_evidence
+  - evidence
+- cites_as_metadata_document
+  - as_metadata_document
+  - metadata_document
+  - metadata
+- cites_as_recommended_reading
+  - as_recommended_reading
+  - recommended_reading
+- disagrees_with
+  - disagree
+  - disagrees
+- disputes
+- documents
+- extends
+- includes_excerpt_from
+  - excerpt
+  - excerpt_from
+- includes_quotation_from
+  - quotation
+  - quotation_from
+- obtains_background_from
+  - background
+  - background_from
+- refutes
+- replies_to
+- updates
+- uses_data_from
+  - data
+  - data_from
+- uses_method_in
+  - method
+  - method_in
+
+## Filter interactions
+
+Note that the [pandoc-crossref] filter uses citations to link to
+other elements. The crossref extensions are not understood by
+cito.lua. pandoc-crossref, if used, should always be invoked
+first: `pandoc --lua-filter=cito.lua --filter=pandoc-crossref …`
+
+[pandoc-crossref]: https://lierdakil.github.io/pandoc-crossref/
+
+## References
+
+This approach was described in <https://doi.org/10.7717/peerj-cs.112>.

+ 138 - 0
example/assets/pandoc-scholar/lua-filters/cito/cito.lua

@@ -0,0 +1,138 @@
+-- Copyright © 2017–2020 Albert Krewinkel, Robert Winkler
+--
+-- This library is free software; you can redistribute it and/or modify it
+-- under the terms of the MIT license. See LICENSE for details.
+
+local _version = '1.0.0'
+local properties_and_aliases = {
+  agrees_with = {
+    'agree_with'
+  },
+  citation = {
+  },
+  cites = {
+  },
+  cites_as_authority = {
+    'as_authority',
+    'authority'
+  },
+  cites_as_data_source = {
+    "as_data_source",
+    "data_source"
+  },
+  cites_as_evidence = {
+    'as_evidence',
+    'evidence'
+  },
+  cites_as_metadata_document = {
+    'as_metadata_document',
+    'metadata_document',
+    'metadata'
+  },
+  cites_as_recommended_reading = {
+    'as_recommended_reading',
+    'recommended_reading'
+  },
+  disagrees_with = {
+    'disagree',
+    'disagrees'
+  },
+  disputes = {
+  },
+  documents = {
+  },
+  extends = {
+  },
+  includes_excerpt_from = {
+    'excerpt',
+    'excerpt_from'
+  },
+  includes_quotation_from = {
+    'quotation',
+    'quotation_from'
+  },
+  obtains_background_from = {
+    'background',
+    'background_from'
+  },
+  refutes = {
+  },
+  replies_to = {
+  },
+  updates = {
+  },
+  uses_data_from = {
+    'data',
+    'data_from'
+  },
+  uses_method_in = {
+    'method',
+    'method_in'
+  },
+}
+
+local default_cito_property = 'citation'
+
+--- Map from cito aliases to the actual cito property.
+local properties_by_alias = {}
+for property, aliases in pairs(properties_and_aliases) do
+  -- every property is an alias for itself
+  properties_by_alias[property] = property
+  for _, alias in pairs(aliases) do
+    properties_by_alias[alias] = property
+  end
+end
+
+--- Split citation ID into cito property and the actual citation ID. If
+--- the ID does not seem to contain a CiTO property, the
+--- `default_cito_property` will be returned, together with the
+--- unchanged input ID.
+local function split_cito_from_id (citation_id)
+  local pattern = '^(.+):(.+)$'
+  local prop_alias, split_citation_id = citation_id:match(pattern)
+
+  if properties_by_alias[prop_alias] then
+    return properties_by_alias[prop_alias], split_citation_id
+  end
+
+  return default_cito_property, citation_id
+end
+
+--- Citations by CiTO properties.
+local function store_cito (cito_cites, prop, cite_id)
+  if not prop then
+    return
+  end
+  if not cito_cites[prop] then
+    cito_cites[prop] = {}
+  end
+  table.insert(cito_cites[prop], cite_id)
+end
+
+--- Returns a Cite filter function which extracts CiTO information and
+--- add it to the given collection table.
+local function extract_cito (cito_cites)
+  return function (cite)
+    for k, citation in pairs(cite.citations) do
+      local cito_prop, cite_id = split_cito_from_id(citation.id)
+      store_cito(cito_cites, cito_prop, cite_id)
+      citation.id = cite_id
+    end
+    return cite
+  end
+end
+
+--- Lists of citation IDs, indexed by CiTO properties.
+local citations_by_property = {}
+
+return {
+  {
+    Cite = extract_cito(citations_by_property)
+  },
+  {
+    Meta = function (meta)
+      meta.cito_cites = citations_by_property
+      return meta
+    end
+  }
+}

+ 252 - 0
example/assets/pandoc-scholar/lua-filters/diagram-generator/README.md

@@ -0,0 +1,252 @@
+# Diagram Generator Lua Filter
+
+## Introduction
+This Lua filter is used to create images with or without captions from code
+blocks. Currently PlantUML, Graphviz, Ti*k*Z and Python can be processed.
+This document also serves as a test document, which is why the subsequent
+test diagrams are integrated in every supported language.
+
+## Prerequisites
+To be able to use this Lua filter, the respective external tools must be
+installed. However, it is sufficient if the tools to be used are installed.
+If you only want to use PlantUML, you don't need LaTeX or Python, etc.
+
+### PlantUML
+To use PlantUML, you must install PlantUML itself. See the
+[PlantUML website](http://plantuml.com/) for more details. It should be
+noted that PlantUML is a Java program and therefore Java must also
+be installed.
+
+By default, this filter expects the plantuml.jar file to be in the
+working directory. Alternatively, the environment variable
+`PLANTUML` can be set with a path. If, for example, a specific
+PlantUML version is to be used per pandoc document, the
+`plantumlPath` meta variable can be set.
+
+Furthermore, this filter assumes that Java is located in the
+system or user path. This means that from any place of the system
+the `java` command is understood. Alternatively, the `JAVA_HOME`
+environment variable gets used. To use a specific Java version per
+pandoc document, use the `javaPath` meta variable. Please notice
+that `JAVA_HOME` must be set to the java's home directory e.g.
+`c:\Program Files\Java\jre1.8.0_201\` whereas `javaPath` must be
+set to the absolute path of `java.exe` e.g.
+`c:\Program Files\Java\jre1.8.0_201\bin\java.exe`.
+
+Example usage:
+
+~~~~~~~~~~~~~~~~
+```{.plantuml caption="This is an image, created by **PlantUML**."}
+@startuml
+Alice -> Bob: Authentication Request Bob --> Alice: Authentication Response
+Alice -> Bob: Another authentication Request Alice <-- Bob: another Response
+@enduml
+```
+~~~~~~~~~~~~~~~~
+
+### Graphviz
+To use Graphviz you only need to install Graphviz, as you can read
+on its [website](http://www.graphviz.org/). There are no other
+dependencies.
+
+This filter assumes that the `dot` command is located in the path
+and therefore can be used from any location. Alternatively, you can
+set the environment variable `DOT` or use the pandoc's meta variable
+`dotPath`.
+
+Example usage from [the Graphviz
+gallery](https://graphviz.gitlab.io/_pages/Gallery/directed/fsm.html):
+
+~~~~~~~~~~~~~~~~
+```{.graphviz caption="This is an image, created by **Graphviz**'s dot."}
+digraph finite_state_machine {
+	rankdir=LR;
+	size="8,5"
+	node [shape = doublecircle]; LR_0 LR_3 LR_4 LR_8;
+	node [shape = circle];
+	LR_0 -> LR_2 [ label = "SS(B)" ];
+	LR_0 -> LR_1 [ label = "SS(S)" ];
+	LR_1 -> LR_3 [ label = "S($end)" ];
+	LR_2 -> LR_6 [ label = "SS(b)" ];
+	LR_2 -> LR_5 [ label = "SS(a)" ];
+	LR_2 -> LR_4 [ label = "S(A)" ];
+	LR_5 -> LR_7 [ label = "S(b)" ];
+	LR_5 -> LR_5 [ label = "S(a)" ];
+	LR_6 -> LR_6 [ label = "S(b)" ];
+	LR_6 -> LR_5 [ label = "S(a)" ];
+	LR_7 -> LR_8 [ label = "S(b)" ];
+	LR_7 -> LR_5 [ label = "S(a)" ];
+	LR_8 -> LR_6 [ label = "S(b)" ];
+	LR_8 -> LR_5 [ label = "S(a)" ];
+}
+```
+~~~~~~~~~~~~~~~~
+
+### Ti*k*Z
+Ti*k*Z (cf. [Wikipedia](https://en.wikipedia.org/wiki/PGF/TikZ)) is a
+description language for graphics of any kind that can be used within
+LaTeX (cf. [Wikipedia](https://en.wikipedia.org/wiki/LaTeX)).
+
+Therefore a LaTeX system must be installed on the system. The Ti*k*Z code is
+embedded into a dynamic LaTeX document. This temporary document gets
+translated into a PDF document using LaTeX (`pdflatex`). Finally,
+Inkscape is used to convert the PDF file to the desired format.
+
+Note: We are using Inkscape here to use a stable solution for the
+convertion. Formerly ImageMagick was used instead. ImageMagick is
+not able to convert PDF files. Hence, it uses Ghostscript to do
+so, cf. [1](https://stackoverflow.com/a/6599718/2258393).
+Unfortunately, Ghostscript behaves unpredictable during Windows and
+Linux tests cases, cf. [2](https://stackoverflow.com/questions/21774561/some-pdfs-are-converted-improperly-using-imagemagick),
+[3](https://stackoverflow.com/questions/9064706/imagemagic-convert-command-pdf-convertion-with-bad-size-orientation), [4](https://stackoverflow.com/questions/18837093/imagemagic-renders-image-with-black-background),
+[5](https://stackoverflow.com/questions/37392798/pdf-to-svg-is-not-perfect),
+[6](https://stackoverflow.com/q/10288065/2258393), etc. By using Inkscape,
+we need one dependency less and get rid of unexpected Ghostscript issues.
+
+Due to this more complicated process, the use of Ti*k*Z is also more
+complicated overall. The process is error-prone: An insufficiently
+configured LaTeX installation or an insufficiently configured
+Inkscape installation can lead to errors. Overall, this results in
+the following dependencies:
+
+- Any LaTeX installation. This should be configured so that
+missing packages are installed automatically. This filter uses the
+`pdflatex` command which is available by the system's path. Alternatively,
+you can set the `PDFLATEX` environment variable. In case you have to use
+a specific LaTeX version on a pandoc document basis, you might set the
+`pdflatexPath` meta variable.
+
+- An installation of [Inkscape](https://inkscape.org/).
+It is assumed that the `inkscape` command is in the path and can be
+executed from any location. Alternatively, the environment
+variable `INKSCAPE` can be set with a path. If a specific
+version per pandoc document is to be used, the `inkscapePath`
+meta-variable can be set.
+
+In order to use additional LaTeX packages, use the optional
+`additionalPackages` attribute in your document, as in the
+example below.
+
+Example usage from [TikZ
+examples](http://www.texample.net/tikz/examples/parallelepiped/) by
+[Kjell Magne Fauske](http://www.texample.net/tikz/examples/nav1d/):
+
+~~~~~~~~~~~~~~~~
+```{.tikz caption="This is an image, created by **TikZ i.e. LaTeX**."
+     additionalPackages="\usepackage{adjustbox}"}
+\usetikzlibrary{arrows}
+\tikzstyle{int}=[draw, fill=blue!20, minimum size=2em]
+\tikzstyle{init} = [pin edge={to-,thin,black}]
+
+\resizebox{16cm}{!}{%
+  \trimbox{3.5cm 0cm 0cm 0cm}{
+    \begin{tikzpicture}[node distance=2.5cm,auto,>=latex']
+      \node [int, pin={[init]above:$v_0$}] (a) {$\frac{1}{s}$};
+      \node (b) [left of=a,node distance=2cm, coordinate] {a};
+      \node [int, pin={[init]above:$p_0$}] at (0,0) (c)
+        [right of=a] {$\frac{1}{s}$};
+      \node [coordinate] (end) [right of=c, node distance=2cm]{};
+      \path[->] (b) edge node {$a$} (a);
+      \path[->] (a) edge node {$v$} (c);
+      \draw[->] (c) edge node {$p$} (end) ;
+    \end{tikzpicture}
+  }
+}
+```
+~~~~~~~~~~~~~~~~
+
+### Python
+In order to use Python to generate a diagram, your Python code must store the
+final image data in a temporary file with the correct format. In case you use
+matplotlib for a diagram, add the following line to do so:
+
+```python
+plt.savefig("$DESTINATION$", dpi=300, fomat="$FORMAT$")
+```
+
+The placeholder `$FORMAT$` gets replace by the necessary format. Most of the
+time, this will be `png` or `svg`. The second placeholder, `$DESTINATION$`
+gets replaced by the path and file name of the destination. Both placeholders
+can be used as many times as you want. Example usage from the [Matplotlib 
+examples](https://matplotlib.org/gallery/lines_bars_and_markers/cohere.html#sphx-glr-gallery-lines-bars-and-markers-cohere-py):
+
+~~~~~~~~~~~~~~~~
+```{.py2image caption="This is an image, created by **Python**."}
+import matplotlib
+matplotlib.use('Agg')
+
+import sys
+import numpy as np
+import matplotlib.pyplot as plt
+
+# Fixing random state for reproducibility
+np.random.seed(19680801)
+
+dt = 0.01
+t = np.arange(0, 30, dt)
+nse1 = np.random.randn(len(t))                 # white noise 1
+nse2 = np.random.randn(len(t))                 # white noise 2
+
+# Two signals with a coherent part at 10Hz and a random part
+s1 = np.sin(2 * np.pi * 10 * t) + nse1
+s2 = np.sin(2 * np.pi * 10 * t) + nse2
+
+fig, axs = plt.subplots(2, 1)
+axs[0].plot(t, s1, t, s2)
+axs[0].set_xlim(0, 2)
+axs[0].set_xlabel('time')
+axs[0].set_ylabel('s1 and s2')
+axs[0].grid(True)
+
+cxy, f = axs[1].cohere(s1, s2, 256, 1. / dt)
+axs[1].set_ylabel('coherence')
+
+fig.tight_layout()
+plt.savefig("$DESTINATION$", dpi=300, fomat="$FORMAT$")
+```
+~~~~~~~~~~~~~~~~
+
+Precondition to use Python is a Python environment which contains all
+necessary libraries you want to use. To use, for example, the standard
+[Anaconda Python](https://www.anaconda.com/distribution/) environment
+on a Microsoft Windows system ...
+
+- set the environment variable `PYTHON` or the meta key `pythonPath`
+to `c:\ProgramData\Anaconda3\python.exe`
+
+- set the environment variable `PYTHON_ACTIVATE` or the meta
+key `activatePythonPath` to `c:\ProgramData\Anaconda3\Scripts\activate.bat`.
+
+Pandoc will activate this Python environment and starts Python with your code.
+
+## How to run pandoc
+This section will show, how to call Pandoc in order to use this filter with
+meta keys. The following command assume, that the filters are stored in the
+subdirectory `filters`. Further, this is a example for a Microsoft Windows
+system.
+
+Command to use PlantUML (a single line):
+
+```
+pandoc.exe README.md -f markdown -t docx --self-contained --standalone --lua-filter=filters\diagram-generator.lua --metadata=plantumlPath:"c:\ProgramData\chocolatey\lib\plantuml\tools\plantuml.jar" --metadata=javaPath:"c:\Program Files\Java\jre1.8.0_201\bin\java.exe" -o README.docx
+```
+
+All available environment variables:
+
+- `PLANTUML` e.g. `c:\ProgramData\chocolatey\lib\plantuml\tools\plantuml.jar`; Default: `plantuml.jar`
+- `INKSCAPE` e.g. `c:\Program Files\Inkscape\inkscape.exe`; Default: `inkscape`
+- `PYTHON` e.g. `c:\ProgramData\Anaconda3\python.exe`; Default: n/a
+- `PYTHON_ACTIVATE` e.g. `c:\ProgramData\Anaconda3\Scripts\activate.bat`; Default: n/a
+- `JAVA_HOME` e.g. `c:\Program Files\Java\jre1.8.0_201`; Default: n/a
+- `DOT` e.g. `c:\ProgramData\chocolatey\bin\dot.exe`; Default: `dot`
+- `PDFLATEX` e.g. `c:\Program Files\MiKTeX 2.9\miktex\bin\x64\pdflatex.exe`; Default: `pdflatex`
+
+All available meta keys:
+
+- `plantumlPath`
+- `inkscapePath`
+- `pythonPath`
+- `activatePythonPath`
+- `javaPath`
+- `dotPath`
+- `pdflatexPath`

+ 316 - 0
example/assets/pandoc-scholar/lua-filters/diagram-generator/diagram-generator.lua

@@ -0,0 +1,316 @@
+--[[
+diagram-generator – create images and figures from code blocks.
+
+This Lua filter is used to create images with or without captions
+from code blocks. Currently PlantUML, GraphViz, Tikz, and Python
+can be processed. For further details, see README.md.
+
+Copyright: © 2018-2020 John MacFarlane <jgm@berkeley.edu>,
+             2018 Florian Schätzig <florian@schaetzig.de>,
+             2019 Thorsten Sommer <contact@sommer-engineering.com>,
+             2019-2020 Albert Krewinkel <albert+pandoc@zeitkraut.de>
+License:   MIT – see LICENSE file for details
+]]
+-- Module pandoc.system is required and was added in version 2.7.3
+PANDOC_VERSION:must_be_at_least '2.7.3'
+
+local system = require 'pandoc.system'
+local with_temporary_directory = system.with_temporary_directory
+local with_working_directory = system.with_working_directory
+
+-- The PlantUML path. If set, uses the environment variable PLANTUML or the
+-- value "plantuml.jar" (local PlantUML version). In order to define a
+-- PlantUML version per pandoc document, use the meta data to define the key
+-- "plantumlPath".
+local plantumlPath = os.getenv("PLANTUML") or "plantuml.jar"
+
+-- The Inkscape path. In order to define an Inkscape version per pandoc
+-- document, use the meta data to define the key "inkscapePath".
+local inkscapePath = os.getenv("INKSCAPE") or "inkscape"
+
+-- The Python path. In order to define a Python version per pandoc document,
+-- use the meta data to define the key "pythonPath".
+local pythonPath = os.getenv("PYTHON")
+
+-- The Python environment's activate script. Can be set on a per document
+-- basis by using the meta data key "activatePythonPath".
+local pythonActivatePath = os.getenv("PYTHON_ACTIVATE")
+
+-- The Java path. In order to define a Java version per pandoc document,
+-- use the meta data to define the key "javaPath".
+local javaPath = os.getenv("JAVA_HOME")
+if javaPath then
+    javaPath = javaPath .. package.config:sub(1,1) .. "bin"
+        .. package.config:sub(1,1) .. "java"
+else
+    javaPath = "java"
+end
+
+-- The dot (Graphviz) path. In order to define a dot version per pandoc
+-- document, use the meta data to define the key "dotPath".
+local dotPath = os.getenv("DOT") or "dot"
+
+-- The pdflatex path. In order to define a pdflatex version per pandoc
+-- document, use the meta data to define the key "pdflatexPath".
+local pdflatexPath = os.getenv("PDFLATEX") or "pdflatex"
+
+-- The default format is SVG i.e. vector graphics:
+local filetype = "svg"
+local mimetype = "image/svg+xml"
+
+-- Check for output formats that potentially cannot use SVG
+-- vector graphics. In these cases, we use a different format
+-- such as PNG:
+if FORMAT == "docx" then
+    filetype = "png"
+    mimetype = "image/png"
+elseif FORMAT == "pptx" then
+    filetype = "png"
+    mimetype = "image/png"
+elseif FORMAT == "rtf" then
+    filetype = "png"
+    mimetype = "image/png"
+end
+
+-- Execute the meta data table to determine the paths. This function
+-- must be called first to get the desired path. If one of these
+-- meta options was set, it gets used instead of the corresponding
+-- environment variable:
+function Meta(meta)
+    plantumlPath = meta.plantumlPath or plantumlPath
+    inkscapePath = meta.inkscapePath or inkscapePath
+    pythonPath = meta.pythonPath or pythonPath
+    pythonActivatePath = meta.activatePythonPath or pythonActivatePath
+    javaPath = meta.javaPath or javaPath
+    dotPath = meta.dotPath or dotPath
+    pdflatexPath = meta.pdflatexPath or pdflatexPath
+end
+
+-- Call plantuml.jar with some parameters (cf. PlantUML help):
+local function plantuml(puml, filetype)
+    local final = pandoc.pipe(javaPath, {"-jar", plantumlPath, "-t" .. filetype, "-pipe", "-charset", "UTF8"}, puml)
+    return final
+end
+
+-- Call dot (GraphViz) in order to generate the image
+-- (thanks @muxueqz for this code):
+local function graphviz(code, filetype)
+    local final = pandoc.pipe(dotPath, {"-T" .. filetype}, code)
+    return final
+end
+
+--
+-- TikZ
+--
+
+--- LaTeX template used to compile TikZ images. Takes additional
+--- packages as the first, and the actual TikZ code as the second
+--- argument.
+local tikz_template = [[
+\documentclass{standalone}
+\usepackage{tikz}
+%% begin: additional packages
+%s
+%% end: additional packages
+\begin{document}
+%s
+\end{document}
+]]
+
+--- Returns a function which takes the filename of a PDF and a
+-- target filename, and writes the input as the given format.
+-- Returns `nil` if conversion into the target format is not
+-- possible.
+local function convert_from_pdf(filetype)
+  -- Build the basic Inkscape command for the conversion
+  local inkscape_output_args
+  if filetype == 'png' then
+    inkscape_output_args = '--export-png="%s" --export-dpi=300'
+  elseif filetype == 'svg' then
+    inkscape_output_args = '--export-plain-svg="%s"'
+  else
+    return nil
+  end
+  return function (pdf_file, outfile)
+    local inkscape_command = string.format(
+      '"%s" --without-gui --file="%s" ' .. inkscape_output_args,
+      inkscapePath,
+      pdf_file,
+      outfile
+    )
+    io.stderr:write(inkscape_command .. '\n')
+    local command_output = io.popen(inkscape_command)
+    -- TODO: print output when debugging.
+    command_output:close()
+  end
+end
+
+--- Compile LaTeX with Tikz code to an image
+local function tikz2image(src, filetype, additional_packages)
+  local convert = convert_from_pdf(filetype)
+  -- Bail if there is now known way from PDF to the target format.
+  if not convert then
+    error(string.format("Don't know how to convert pdf to %s.", filetype))
+  end
+  return with_temporary_directory("tikz2image", function (tmpdir)
+    return with_working_directory(tmpdir, function ()
+      -- Define file names:
+      local file_template = "%s/tikz-image.%s"
+      local tikz_file = file_template:format(tmpdir, "tex")
+      local pdf_file = file_template:format(tmpdir, "pdf")
+      local outfile = file_template:format(tmpdir, filetype)
+
+      -- Build and write the LaTeX document:
+      local f = io.open(tikz_file, 'w')
+      f:write(tikz_template:format(additional_packages or '', src))
+      f:close()
+
+      -- Execute the LaTeX compiler:
+      pandoc.pipe(pdflatexPath, {'-output-directory', tmpdir, tikz_file}, '')
+
+      convert(pdf_file, outfile)
+
+      -- Try to open and read the image:
+      local img_data
+      local r = io.open(outfile, 'rb')
+      if r then
+        img_data = r:read("*all")
+        r:close()
+      else
+        -- TODO: print warning
+      end
+
+      return img_data
+    end)
+  end)
+end
+
+-- Run Python to generate an image:
+local function py2image(code, filetype)
+
+    -- Define the temp files:
+    local outfile = string.format('%s.%s', os.tmpname(), filetype)
+    local pyfile = os.tmpname()
+
+    -- Replace the desired destination's file type in the Python code:
+    local extendedCode = string.gsub(code, "%$FORMAT%$", filetype)
+
+    -- Replace the desired destination's path in the Python code:
+    extendedCode = string.gsub(extendedCode, "%$DESTINATION%$", outfile)
+
+    -- Write the Python code:
+    local f = io.open(pyfile, 'w')
+    f:write(extendedCode)
+    f:close()
+
+    -- Execute Python in the desired environment:
+    local pycmd = pythonPath .. ' ' .. pyfile
+    local command = pythonActivatePath
+      and pythonActivatePath .. ' && ' .. pycmd
+      or pycmd
+    os.execute(command)
+
+    -- Try to open the written image:
+    local r = io.open(outfile, 'rb')
+    local imgData = nil
+
+    -- When the image exist, read it:
+    if r then
+        imgData = r:read("*all")
+        r:close()
+    else
+        io.stderr:write(string.format("File '%s' could not be opened", outfile))
+        error 'Could not create image from python code.'
+    end
+
+    -- Delete the tmp files:
+    os.remove(pyfile)
+    os.remove(outfile)
+
+    return imgData
+end
+
+-- Executes each document's code block to find matching code blocks:
+function CodeBlock(block)
+
+    -- Predefine a potential image:
+    local fname = nil
+
+    -- Using a table with all known generators i.e. converters:
+    local converters = {
+        plantuml = plantuml,
+        graphviz = graphviz,
+        tikz = tikz2image,
+        py2image = py2image,
+    }
+
+    -- Check if a converter exists for this block. If not, return the block
+    -- unchanged.
+    local img_converter = converters[block.classes[1]]
+    if not img_converter then
+      return nil
+    end
+
+    -- Call the correct converter which belongs to the used class:
+    local success, img = pcall(img_converter, block.text,
+        filetype, block.attributes["additionalPackages"] or nil)
+
+    -- Was ok?
+    if success and img then
+        -- Hash the figure name and content:
+        fname = pandoc.sha1(img) .. "." .. filetype
+
+        -- Store the data in the media bag:
+        pandoc.mediabag.insert(fname, mimetype, img)
+
+    else
+
+        -- an error occured; img contains the error message
+        io.stderr:write(tostring(img))
+        io.stderr:write('\n')
+        error 'Image conversion failed. Aborting.'
+
+    end
+
+    -- Case: This code block was an image e.g. PlantUML or dot/Graphviz, etc.:
+    if fname then
+
+        -- Define the default caption:
+        local caption = {}
+        local enableCaption = nil
+
+        -- If the user defines a caption, use it:
+        if block.attributes["caption"] then
+            caption = pandoc.read(block.attributes.caption).blocks[1].content
+
+            -- This is pandoc's current hack to enforce a caption:
+            enableCaption = "fig:"
+        end
+
+        -- Create a new image for the document's structure. Attach the user's
+        -- caption. Also use a hack (fig:) to enforce pandoc to create a
+        -- figure i.e. attach a caption to the image.
+        local imgObj = pandoc.Image(caption, fname, enableCaption)
+
+        -- Now, transfer the attribute "name" from the code block to the new
+        -- image block. It might gets used by the figure numbering lua filter.
+        -- If the figure numbering gets not used, this additional attribute
+        -- gets ignored as well.
+        if block.attributes["name"] then
+            imgObj.attributes["name"] = block.attributes["name"]
+        end
+
+        -- Finally, put the image inside an empty paragraph. By returning the
+        -- resulting paragraph object, the source code block gets replaced by
+        -- the image:
+        return pandoc.Para{ imgObj }
+    end
+end
+
+-- Normally, pandoc will run the function in the built-in order Inlines ->
+-- Blocks -> Meta -> Pandoc. We instead want Meta -> Blocks. Thus, we must
+-- define our custom order:
+return {
+    {Meta = Meta},
+    {CodeBlock = CodeBlock},
+}

+ 70 - 0
example/assets/pandoc-scholar/lua-filters/include-files/README.md

@@ -0,0 +1,70 @@
+# include-files
+
+Filter to include other files in the document.
+
+## Usage
+
+Use a special code block with class `include` to include files of
+the same format as the input. Each code line is treated as the
+filename of a file, parsed, and the result is added to the
+document.
+
+Metadata from included files is discarded.
+
+### Shifting Headings
+
+The default is to include the subdocuments unchanged, but it can
+be convenient to modify the level of headers; a top-level header
+in an included file should be a second or third-level header in
+the final document. Use the `shift-heading-level-by` attribute to
+control header shifting.
+
+### Comments
+
+Comment lines can be added in the include block by beginning a
+line with two `//` characters.
+
+### Different formats
+
+Files are assumed to be written in Markdown, but sometimes one
+will want to include files written in a different format. An
+alternative format can be specified via the `format` attribute.
+Only plain-text formats are accepted.
+
+## Example
+
+Let's assume we are writing a longer document, like a thesis.
+Each chapter and appendix section resides in its own file, with
+some additional information in the main file `main.md`:
+
+    ---
+    author: me
+    title: Thesis
+    ---
+
+    # Frontmatter
+
+    Thanks everyone!
+
+    <!-- actual chapters start here -->
+
+    ``` {.include}
+    chapters/introduction.md
+    chapters/methods.md
+    chapters/results.md
+    chapters/discussion.md
+    ```
+
+    # Appendix
+
+    More info goes here.
+
+    ``` {.include shift-heading-level-by=1}
+    // headings in included documents are shifted down a level,
+    // a level 1 heading becomes level 2.
+    appendix/questionaire.md
+    ```
+
+An HTML can be produced with this command:
+
+    pandoc --lua-filter=include-files.lua main.md --output result.html

+ 48 - 0
example/assets/pandoc-scholar/lua-filters/include-files/include-files.lua

@@ -0,0 +1,48 @@
+--- include-files.lua – filter to include Markdown files
+---
+--- Copyright: © 2019–2020 Albert Krewinkel
+--- License:   MIT – see LICENSE file for details
+
+-- pandoc's List type
+local List = require 'pandoc.List'
+
+--- Shift headings in block list by given number
+function shift_headings(blocks, shift_by)
+  if not shift_by then
+    return blocks
+  end
+
+  local shift_headings_filter = {
+    Header = function (header)
+      header.level = header.level + shift_by
+      return header
+    end
+  }
+
+  return pandoc.walk_block(pandoc.Div(blocks), shift_headings_filter).content
+end
+
+--- Filter function for code blocks
+function CodeBlock(cb)
+  -- ignore code blocks which are not of class "include".
+  if not cb.classes:includes 'include' then
+    return
+  end
+
+  -- Markdown is used if this is nil.
+  local format = cb.attributes['format']
+  local shift_heading_level_by =
+    tonumber(cb.attributes['shift-heading-level-by'])
+
+
+  local blocks = List:new()
+  for line in cb.text:gmatch('[^\n]+') do
+    if line:sub(1,2) ~= '//' then
+      local fh = io.open(line)
+      local contents = pandoc.read(fh:read '*a', format).blocks
+      blocks:extend(shift_headings(contents, shift_heading_level_by))
+      fh:close()
+    end
+  end
+  return blocks
+end

+ 49 - 0
example/assets/pandoc-scholar/lua-filters/latex-hyphen/README.md

@@ -0,0 +1,49 @@
+# latex-hyphen.lua
+
+`latex-hyphen.lua` is a [pandoc](https://pandoc.org/) filter that replaces
+intra-word hyphens with the raw LaTeX expression `"=` for improved
+hyphenation.
+
+## Purpose
+
+The regular hyphen `-` prevents LaTeX from breaking a word at any other
+position than the explicit hyphen. With long, hyphenated words as they occur
+in languages like German, this can lead to undesirable visual results. The
+expression `"=` outputs a normal hyphen while still allowing LaTeX to break
+the word at any other position according to its regular hyphenation rules.
+
+Before:
+
+![](without-filter.png)
+
+After:
+
+![](with-filter.png)
+
+## Usage
+
+For this to work, babel shorthands have to be activated. With XeLaTeX or
+LuaTeX as PDF engine, this can be done using the YAML frontmatter:
+
+```yaml
+polyglossia-lang:
+    name: german
+    options:
+        - spelling=new,babelshorthands=true
+
+```
+
+For pdflatex, a custom template has to be used, as the built-in template
+explicitly deactivates babel’s shorthands.
+
+The filter can then be called like this:
+
+```sh
+pandoc -o mydoc.pdf --pdf-engine xelatex \
+    --lua-filter latex-hyphen.lua mydoc.md
+```
+
+## Caveat
+
+pandoc strips LaTeX expressions from PDF strings like bookmarks. Thus, the
+document outline in the resulting PDF file will lack any hyphens.

+ 81 - 0
example/assets/pandoc-scholar/lua-filters/latex-hyphen/latex-hyphen.lua

@@ -0,0 +1,81 @@
+--- Replace intra-word hyphens with LaTeX shorthand "= for better hyphenation.
+--
+-- PURPOSE
+--
+-- The regular hyphen - prevents LaTeX from breaking a word at any other
+-- position than the explicit hyphen. With long, hyphenated words as they occur
+-- in languages like German, this can lead to undesirable visual results. The
+-- expression "= outputs a normal hyphen while still allowing LaTeX to break
+-- the word at any other position according to its regular hyphenation rules.
+--
+-- USAGE
+--
+-- For this to work, babel shorthands have to be activated. With XeLaTeX or
+-- LuaTeX as PDF engine, this can be done using the YAML frontmatter:
+
+-- polyglossia-lang:
+--     name: german
+--     options:
+--         - spelling=new,babelshorthands=true
+--
+-- For pdflatex, a custom template has to be used, as the built-in template
+-- explicitly deactivates babel’s shorthands.
+--
+-- The filter can then be called like this:
+--
+-- pandoc -o doc.pdf --pdf-engine xelatex --lua-filter latex-hyphen.lua doc.md
+--
+-- AUTHOR
+--
+-- Copyright 2020 Frederik Elwert <frederik.elwert@rub.de>
+--
+-- LICENSE
+--
+-- 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.
+
+
+if FORMAT ~= 'latex' then
+  return {}
+end
+
+function split_hyphen(inputstr)
+  local sep = '-'
+  local t = {}
+  for str in string.gmatch(inputstr, '([^'..sep..']+)') do
+    table.insert(t, str)
+  end
+  return t
+end
+
+function Str(elem)
+  local parts = split_hyphen(elem.c)
+  -- if not more than one part, string contains no hyphen, return unchanged.
+  if #parts <= 1 then
+    return nil
+  end
+  -- otherwise, splice raw latex "= between parts
+  local o = {}
+  for index, part in ipairs(parts) do
+    table.insert(o, pandoc.Str(part))
+    if index < #parts then
+      table.insert(o, pandoc.RawInline('latex', '"='))
+    end
+  end
+  return o
+end

+ 81 - 0
example/assets/pandoc-scholar/lua-filters/lilypond/README.md

@@ -0,0 +1,81 @@
+# lilypond
+This filter renders [LilyPond](http://lilypond.org) inline code and
+code blocks into embedded images of musical notation. It's designed with
+(pandoc-flavored) Markdown input in mind.
+
+See the accompanying test files for some examples of how the filter works.
+
+## Rationale
+LilyPond is the tool of choice for generating musical notation from
+text input.  Integrating it with pandoc lets us write documents that include the
+code for musical examples alongside their main content and compile them with a
+single command. Because filters operate directly on pandoc's AST, support for
+any sufficiently rich output format is free.
+
+The LilyPond distribution includes a program called
+[`lilypond-book`](http://lilypond.org/doc/v2.19/Documentation/usage/lilypond_002dbook.en.html)
+that's intended to serve a similar purpose. Unfortunately, it has some
+significant limitations: only HTML and Texinfo are supported for input,
+compilation is messy, and the [source
+code](https://git.savannah.gnu.org/cgit/lilypond.git/tree/scripts/lilypond-book.py)
+is complex, running to over 700 lines of Python 2. This filter aims to be a
+superior alternative.
+
+## Usage
+The filter operates on inline code (type `Code`) and code block (type
+`CodeBlock`) elements that are marked with the `lilypond` class. Each such
+element is replaced by an image element, with the underlying PNG image generated
+by feeding the contents of the original element to LilyPond. (Eventually the
+filter will support SVG output as well.)
+
+You can configure the filter's behavior in two ways: by adding classes and
+attributes to individual code elements, and by adding metadata to the input
+document. Classes and attributes naturally only affect the element they're
+attached to, while metadata options affect all code elements in the document.
+
+The available classes are:
+
+* `ly-fragment`: the code in this element will be wrapped in some additional
+  boilerplate before compilation, meaning you can start writing notes
+  immediately without a bunch of setup. Inline code elements are always treated
+  as fragments.
+* `ly-norender`: this element will be ignored by the filter.
+
+The available (key-value) attributes are:
+
+* `ly-caption`: caption for the image generated from this element.  Default:
+  `"Musical notation"`.
+* `ly-name`: base filename (without path) for the image generated from this
+  element; an file extension will be appended. Default: the SHA1 digest of the
+  element's contents.
+* `ly-resolution`: resolution (in DPI) for the image generated from this
+  element. Default: set by LilyPond.
+* `ly-title`: title for the image generated from this element. Default: the
+  element's contents.
+
+The available metadata options are:
+
+* `lilypond.image_directory` (string): directory where generated images should
+  be saved. Will be resolved relative to the output file for this run of pandoc.
+  Default: `"."`.
+* `lilypond.relativize` (boolean): if enabled, use relative paths for the `src`
+  attributes of generated images.
+
+The classes and attributes listed above will *not* be copied to the generated
+image, but all other classes and attributes will be, and so will the identifier
+if one is present. The `lilypond` block (if present) will be stripped from the
+document metadata. Images generated from inline code will be tagged with the
+`lilypond-image-inline` class, and those generated from code blocks with the
+`lilypond-image-standalone` class.
+
+## Requirements
+The `lilypond` executable must be installed to a location on
+your `PATH`. You can obtain it [here](http://lilypond.org/download.html) or
+through your package manager.
+
+The filter uses some path-manipulation commands from the GNU coreutils,
+specifically `realpath` and `dirname`, so you'll also need those installed.
+
+Finally, because `lilypond.lua` uses functions from the `pandoc.system`
+submodule, it requires pandoc version 2.7.3 or later.
+

+ 189 - 0
example/assets/pandoc-scholar/lua-filters/lilypond/lilypond.lua

@@ -0,0 +1,189 @@
+if PANDOC_VERSION and PANDOC_VERSION.must_be_at_least then
+  -- Actually, this check is redundant since `Version' objects were
+  -- introduced in pandoc v2.7.3, but I've left it in for clarity.
+  PANDOC_VERSION:must_be_at_least("2.7.3")
+else
+  error("pandoc version >=2.7.3 is required")
+end
+
+local OPTIONS = {
+        image_directory = ".",
+        relativize = false
+      }
+
+local SPECIAL_CLASSES = {
+        ["lilypond"] = true,
+        ["ly-fragment"] = true,
+        ["ly-norender"] = true
+      }
+
+local SPECIAL_ATTRIBUTES = {
+        ["ly-caption"] = true,
+        ["ly-name"] = true,
+        ["ly-resolution"] = true,
+        ["ly-title"] = true
+      }
+
+-- pandoc.system.with_temporary_directory had a different (undocumented)
+-- name in the 2.7.3 release.
+local with_temporary_directory = tostring(PANDOC_VERSION) == "2.7.3"
+                                   and pandoc.system.with_temp_directory
+                                    or pandoc.system.with_temporary_directory
+
+-- This is the extra boilerplate that's added to code snippets when the
+-- `ly-fragment' class is present. It's adapted from what `lilypond-book'
+-- does. (The file `lilypond-book-preamble.ly' is placed on the include
+-- path as part of the default LilyPond installation.)
+local function wrap_fragment(src)
+  return table.concat(
+           {
+             [[\include "lilypond-book-preamble.ly"]],
+             [[\paper { indent = 0\mm }]],
+             src,
+           },
+           "\n"
+         )
+end
+
+local function get_output_directory()
+  return PANDOC_STATE.output_file
+           and pandoc.pipe(
+                 "dirname",
+                 {PANDOC_STATE.output_file},
+                 ""
+               ):gsub("\n", "")
+end
+
+local function resolve_relative_path(what, where)
+  return pandoc.system.with_working_directory(
+           where,
+           function ()
+             return pandoc.pipe("realpath", {what}, ""):gsub("\n", "")
+           end
+         )
+end
+
+local function generate_image(name, input, dpi, whither)
+  local fullname = name .. ".png"
+  with_temporary_directory(
+    "lilypond-lua-XXXXX",
+    function (tmp_dir)
+      pandoc.system.with_working_directory(
+        tmp_dir,
+        function ()
+          pandoc.pipe(
+            "lilypond",
+            {
+              "--silent",
+              "--png", dpi and "-dresolution=" .. dpi or "",
+              "--output=" .. name, "-"
+            },
+            input
+          )
+          pandoc.pipe("cp", {fullname, whither}, "")
+        end
+      )
+    end
+  )
+  return whither .. "/" .. fullname
+end
+
+local function make_relative_path(to, from)
+  return pandoc.pipe(
+           "realpath",
+           {"--relative-to=" .. from, to},
+           ""
+         ):gsub("\n", "")
+end
+
+local function process_lilypond(elem, inline)
+  local code = elem.text
+  local fragment = elem.classes:includes("ly-fragment") or inline
+  local input = fragment
+                  and wrap_fragment(code)
+                   or code
+  local dpi = elem.attributes["ly-resolution"]
+  local name = elem.attributes["ly-name"] or pandoc.sha1(code)
+
+  local out_dir = get_output_directory() or "."
+  local dest = resolve_relative_path(OPTIONS.image_directory, out_dir)
+
+  local path = generate_image(name, input, dpi, dest)
+  local img = io.open(path, "rb")
+  pandoc.mediabag.insert(path, "image/png", img:read("*a"))
+  img:close()
+
+  local caption = elem.attributes["ly-caption"] or "Musical notation"
+  local src = OPTIONS.relativize
+                and make_relative_path(path, out_dir)
+                 or path
+  -- The "fig:" prefix causes this image to be rendered as a proper figure
+  -- in HTML ouput (this is a rather ugly pandoc feature and may be replaced
+  -- by something more elegant in the future).
+  local fudge = inline and "" or "fig:"
+  -- Strip newlines, indendation, etc. from the code for a more readable title.
+  local title = fudge .. (elem.attributes["ly-title"]
+                            or code:gsub("%s+", " "))
+
+  -- Strip most of the LilyPond-related attributes from this code element, for
+  -- tidiness.
+  local classes = elem.classes:filter(
+    function (cls)
+      return not SPECIAL_CLASSES[cls]
+    end
+  )
+  table.insert(
+    classes,
+    -- Add one special class for styling/manipulation purposes.
+    inline and "lilypond-image-inline"
+            or "lilypond-image-standalone"
+  )
+  local attributes = elem.attributes
+  for a, t in pairs(SPECIAL_ATTRIBUTES) do
+    attributes[a] = nil
+  end
+  local attrs = pandoc.Attr(elem.identifier, classes, attributes)
+
+  return pandoc.Image(caption, src, title, attrs)
+end
+
+-- Update `OPTIONS' based on the document metadata.
+local function meta_transformer(md)
+  local ly_block = md.lilypond or {}
+  local dir_conf = ly_block.image_directory
+  OPTIONS.image_directory = dir_conf
+                              and pandoc.utils.stringify(dir_conf)
+                               or OPTIONS.image_directory
+  OPTIONS.relativize = ly_block.relativize
+                         or OPTIONS.relativize
+
+  md.lilypond = nil
+  return md
+end
+
+local function code_transformer(elem)
+  if elem.classes:includes("lilypond")
+       and not elem.classes:includes("ly-norender") then
+    return process_lilypond(elem, true)
+  else
+    return elem
+  end
+end
+
+local function code_block_transformer(elem)
+  if elem.classes:includes("lilypond")
+       and not elem.classes:includes("ly-norender") then
+    -- When replacing a block element we must wrap the generated image
+    -- in a `Para' since `Image' is an inline element.
+    return pandoc.Para({process_lilypond(elem, false)})
+  else
+    return elem
+  end
+end
+
+-- Make sure the metadata transformation runs first so that the code
+-- transformations operate with the correct options.
+return {
+         {Meta = meta_transformer},
+         {Code = code_transformer, CodeBlock = code_block_transformer},
+       }

+ 316 - 0
example/assets/pandoc-scholar/lua-filters/minted/README.md

@@ -0,0 +1,316 @@
+# minted
+
+This filter enables users to use the [`minted`][minted] package with the
+`beamer` and `latex` writers.  Users may attach any desired `minted` specific
+styling / attributes to their code-blocks (or via document metadata).  These
+`minted` specific attributes will be _removed_ for any writers that are not
+`beamer` or `latex`, since many of the `minted` options require using `latex`
+specific syntax that can cause problems in other output formats.  For example,
+if the `fontsize=\footnotesize` attribute were applied to a code block, an
+`html` export would include `data-fontsize="\footnotesize"`, which may produce
+errors or more commonly be entirely meaningless for non-latex writers.
+
+The `minted` package will be used as a _replacement_ for the existing `pandoc`
+inline code and code block elements.  Behind the scenes, `minted` builds on top
+of the `fancyvrb` latex package, using [pygments][pygments] to perform the
+highlighting.  The `minted` package contains _many_ options for customizing
+output, users are encouraged to read / review section 5.3 of the
+[minted documentation][minted_docs].  **This filter does not make any attempts
+to validate arguments supplied to the `minted` package**.  Invalid / conflicting
+arguments are a usage error.
+
+**Contents**
+
+- [Setup](#setup)
+    - [LaTeX Preamble Configuration](#latex-preamble-configuration)
+    - [PDF Compilation](#pdf-compilation)
+- [Minted Filter Settings](#minted-filter-settings)
+    - [Default Settings](#default-settings)
+    - [All Metadata Settings](#all-metadata-settings)
+        - [`no_default_autogobble`](#no_default_autogobble-boolean)
+        - [`no_mintinline`](#no_mintinline-boolean)
+        - [`default_block_language`](#default_block_language-string)
+        - [`default_inline_language`](#default_inline_language-string)
+        - [`block_attributes`](#block_attributes-list-of-strings)
+        - [`inline_attributes`](#inline_attributes-list-of-strings)
+- [Important Usage Notes](#important-usage-notes)
+- [Bonus](#bonus)
+
+# Setup
+
+## LaTeX Preamble Configuration
+
+Since this filter will emit `\mintline` commands for inline code, and
+`\begin{minted} ... \end{minted}` environments for code blocks, you must ensure
+that your document includes the `minted` package in the preamble of your
+`beamer` or `latex` document.  The filter cannot accomplish this for you.
+
+**Option 1**
+
+Use the `header-includes` feature of `pandoc` (`-H` / `--include-in-header`).
+This will be injected into the preamble section of your `beamer` or `latex`
+document.  The bare minimum you need in this file is
+
+```latex
+\usepackage{minted}
+```
+
+However, there are many other things you can set here (related or unrelated to
+this filter), and this is a good opportunity to perform some global setup on the
+`minted` package.  Some examples:
+
+```latex
+\usepackage{minted}
+
+% Set the `style=tango` attribute for all minted blocks.  Can still be overriden
+% per block (e.g., you want to change just one).  Run `pygmentize -L` to see
+% all available options.
+\usemintedstyle{tango}
+
+% Depending on which pygments style you choose, comments and preprocessor
+% directives may be italic.  The `tango` style is one of these.  This disables
+% all italics in the `minted` environment.
+\AtBeginEnvironment{minted}{\let\itshape\relax}
+
+% This disables italics for the `\mintinline` commands.
+% Credit: https://tex.stackexchange.com/a/469702/113687
+\usepackage{xpatch}
+\xpatchcmd{\mintinline}{\begingroup}{\begingroup\let\itshape\relax}{}{}
+```
+
+The `minted` package has many options, see the
+[minted documentation][minted_docs] for more information.  For example, see the
+`bgcolor` option for the `minted` package.  In this "header-include" file would
+be an excellent location to `\definecolor`s that you want to use with `bgcolor`.
+
+**Option 1.5**
+
+You can also set `header-includes` in the metadata of your document.  The above
+example could be set as (noting the escaped backslashes):
+
+```yaml
+colorlinks: true
+header-includes:
+  # Include the minted package, set global style, define colors, etc.
+  - "\\usepackage{minted}"
+  - "\\usemintedstyle{tango}"
+  # Prevent italics in the `minted` environment.
+  - "\\AtBeginEnvironment{minted}{\\let\\itshape\\relax}"
+  # Prevent italics in the `\mintinline` command.
+  - "\\usepackage{xpatch}"
+  - "`\\xpatchcmd{\\mintinline}{\\begingroup}{\\begingroup\\let\\itshape\\relax}{}{}`{=latex}"
+```
+
+Note on the last line calling `\xpatchcmd`, we escape the backslashes and
+additionally force `pandoc` to treat this as `latex` code by making it an inline
+`latex` code element.  See [pandoc issue 2139 (comment)][pandoc_issue_2139] for
+more information.
+
+Formally, you may want to apply the ``-"`\\raw_tex`{=latex}"`` trick to all
+metadata to indicate it is `latex` specific code.  However, since `pandoc`
+strips out any raw `latex` when converting to other writers, it isn't necessary.
+
+**Option 2**
+
+You can also create your own custom `beamer` or `latex` template to have much
+finer control over what is / is not included in your document.  You may obtain
+a copy of the template that `pandoc` uses by default by running
+`pandoc -D beamer` or `pandoc -D latex` depending on your document type.
+
+After you have modified the template to suit your needs (including at the very
+least a `\usepackage{minted}`), specify your template file to `pandoc` using
+the `--template <path/to/template/file>` command line argument.
+
+## PDF Compilation
+
+To compile a PDF, there are two things that the `minted` package requires be
+available: an escaped shell to be able to run external commands (the
+`-shell-escape` command line flag), and the ability to create and later read
+auxiliary files (`minted` runs `pygmentize` for the highlighting).
+
+At the time of writing this, only one of these is accessible using `pandoc`
+directly.  One may pass `--pdf-engine-opt=-shell-escape` to forward the
+`-shell-escape` flag to the latex engine being used.  Unfortunately, though,
+the second component (related to temporary files being created) is not supported
+by `pandoc`.  See [pandoc issue 4271][pandoc_issue_4271].
+
+**However**, in reality this is an minor issue that can easily be worked around.
+Instead of generating `md => pdf`, you just use `pandoc` to generate `md => tex`
+and then compile `tex => pdf` yourself.  See the [sample Makefile](Makefile) for
+examples of how to execute both stages.  **Furthermore**, you will notice a
+significant advantage of managing the `pdf` compilation yourself: the generated
+`minted` files are cached and unless you `make clean` (or remove them manually),
+unchanged code listings will be reused.  That is, you will have faster
+compilation times :slightly_smiling_face:
+
+# Minted Filter Settings
+
+Direct control over the settings of this filter are performed by setting
+sub-keys of a `minted` metadata key for your document.
+
+## Default Settings
+
+By default, this filter
+
+1. Transforms all inline `Code` elements to `\mintinline`.  This can be disabled
+   globally by setting `no_mintinline: true`.
+
+2. Transforms all `CodeBlock` elements to `\begin{minted} ... \end{minted}` raw
+   latex code.  This cannot be disabled.
+
+3. Both (1) and (2) default to the `"text"` pygments lexer, meaning that inline
+   code or code blocks without a specific code class applied will receive no
+   syntax highlighting.  This can be changed globally by setting
+   `default_block_language: "lexer"` or `default_inline_language: "lexer"`.
+
+4. All `CodeBlock` elements have the `autogobble` attribute applied to them,
+   which informs `minted` to trim all common preceding whitespace.  This can be
+   disabled globally by setting `no_default_autogobble: true`.  However, doing
+   this is **strongly discouraged**.  Consider a code block nested underneath
+   a list item.  Pandoc will (correctly) generate indented code, meaning you
+   will need to manually inform `minted` to `gobble=indent` where `indent` is
+   the number of spaces to trim.  Note that `pandoc` may not reproduce the same
+   indentation level of the original document.
+
+## All Metadata Settings
+
+Each of the following are nested under the `minted` metadata key.
+
+### `no_default_autogobble` (boolean)
+
+By default this filter will always use `autogobble` with minted, which will
+automatically trim common preceding whitespace.  This is important because
+code blocks nested under a list or other block elements _will_ have common
+preceding whitespace that you _will_ want trimmed.
+
+### `no_mintinline` (boolean)
+
+Globally prevent this filter from emitting `\mintinline` calls for inline
+Code elements, emitting `\texttt` instead.  Possibly useful in saving
+compile time for large documents that do not seek to have syntax
+highlighting on inline code elements.
+
+### `default_block_language` (string)
+
+The default pygments lexer class to use for code blocks.  By default this
+is `"text"`, meaning no syntax highlighting.  This is a fallback value, code
+blocks that explicitly specify a lexer will not use it.
+
+### `default_inline_language` (string)
+
+Same as `default_block_language`, only for inline code (typed in single
+backticks).  The default is also `"text"`, and changing is discouraged.
+
+### `block_attributes` (list of strings)
+
+Any default attributes to apply to _all_ code blocks.  These may be
+overriden on a per-code-block basis.  See section 5.3 of the
+[minted documentation][minted_docs] for available options.
+
+### `inline_attributes` (list of strings)
+
+Any default attributes to apply to _all_ inline code.  These may be
+overriden on a per-code basis.  See section 5.3 of the
+[minted documentation][minted_docs] for available options.
+
+[minted_docs]: http://mirrors.ctan.org/macros/latex/contrib/minted/minted.pdf
+[minted]: https://ctan.org/pkg/minted?lang=en
+[pygments]: http://pygments.org/
+[pandoc_issue_2139]: https://github.com/jgm/pandoc/issues/2139#issuecomment-310522113
+[pandoc_issue_4271]: https://github.com/jgm/pandoc/issues/4721
+
+# Important Usage Notes
+
+Refer to the [`sample.md`](sample.md) file for some live examples of how to use
+this filter.  If you execute `make` in this directory, `sample_beamer.pdf`,
+`sample_latex.pdf`, and `sample.html` will all be generated to demonstrate the
+filter in action.
+
+`pandoc` allows you to specify additional attributes on either the closing
+backtick of an inline code element, or after the third backtick of a fenced
+code block.  This is done using `{curly braces}`, an example:
+
+```md
+`#include <type_traits>`{.cpp .showspaces style=bw}
+```
+
+or
+
+    ```{.cpp .showspaces style=bw}
+    #include <type_traits>
+    ```
+
+In order, these are
+
+- `.cpp`: specify the language lexer class.
+- `.showspaces`: a `minted` boolean attribute.
+- `style=bw`: a `minted` attribute that takes an argument (`bw` is a pygments
+  style, black-white, just an example).
+
+There are two rules that must not be violated:
+
+1. Any time you want to supply extra arguments to `minted` to a specific inline
+   code or code block element, **the lexer class must always be first, and
+   always be present**.
+
+   This is a limitation of the implementation of this filter.
+
+2. Observe the difference between specifying boolean attributes vs attributes
+   that take an argument.  Boolean `minted` attributes **must** have a leading
+   `.`, and `minted` attributes that take an argument **may not** have a leading
+   `.`.
+
+    - **Yes**: `{.cpp .showspaces}`, **No**: `{.cpp showspaces}`
+    - **Yes**: `{.cpp style=bw}`, **No**: `{.cpp .style=bw}`
+
+   If you violate this, then `pandoc` will likely not produce an actual inline
+   `Code` or `CodeBlock` element, but instead something else (undefined).
+
+Last, but not least, you will see that the `--no-highlight` flag is used in the
+`Makefile` for the latex targets.  This is added in the spirit of the filter
+being a "full replacement" for `pandoc` highlighting with `minted`.  This only
+affects inline code elements that meet the following criteria:
+
+1. The inline code element has a lexer, e.g., `{.cpp}`.
+2. The inline code element can actually be parsed for that language by `pandoc`.
+
+If these two conditions are met, and you do **not** specify `--no-highlight`,
+the `pandoc` highlighting engine will take over.  Users are encouraged to build
+the samples (`make` in this directory) and look at the end of the
+`Special Characters are Supported` section.  If you remove `--no-highlight`,
+`make realclean`, and then `make` again, you will see that the pandoc
+highlighting engine will colorize the `auto foo = [](){};`.
+
+Simply put: if you do not want any pandoc highlighting in your LaTeX, **make
+sure you add `--no-highlight`** and it will not happen.
+
+It is advantageous for this filter to rely on this behavior, because it means
+that the filter does not need to worry about escaping special characters for
+LaTeX -- `pandoc` will do that for us.  Inspect the generated `sample_*.tex`
+files (near the end) to see the difference.  `--no-highlight` will produce
+`\texttt` commands, but omitting this flag will result in some `\VERB` commands
+from `pandoc`.
+
+# Bonus
+
+Included here is a simple python script to help you get the right color
+definitions for `bgcolor` with minted.  Just run
+[`background_color.py`](background_color.py) with a single argument that is the
+name of the pygments style you want the `latex` background color definition for:
+
+```console
+$ ./background_color.py monokai
+Options for monokai (choose *one*):
+
+  (*) \definecolor{monokai_bg}{HTML}{272822}
+  (*) \definecolor{monokai_bg}{RGB}{39,40,34}
+  (*) \definecolor{monokai_bg}{rgb}{0.1529,0.1569,0.1333}
+                   |--------/
+                   |
+                   +--> You can rename this too :)
+```
+
+See the contents of [`sample.md`](sample.md) (click on "View Raw" to see the
+comments in the metadata section).  Notably, in order to use `\definecolor` you
+should make sure that the `xcolor` package is actually included.  Comments in
+the file explain the options.

+ 456 - 0
example/assets/pandoc-scholar/lua-filters/minted/minted.lua

@@ -0,0 +1,456 @@
+--[[
+minted -- enable the minted environment for code listings in beamer and latex.
+
+MIT License
+
+Copyright (c) 2019 Stephen McDowell
+
+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.
+]]
+
+--------------------------------------------------------------------------------
+-- Quick documentation.  See full documentation here:                         --
+-- https://github.com/pandoc/lua-filters/blob/master/minted                   --
+--------------------------------------------------------------------------------
+--[[
+Brief overview of metadata keys that you can use in your document:
+
+minted:
+  no_default_autogobble:   <boolean>, *DISCOURAGED*
+  no_mintinline:           <boolean>
+  default_block_language:  <string>
+  default_inline_language: <string>
+  block_attributes:        <list of strings>
+    - attr_1
+    - attr_2
+    - ...
+  inline_attributes:       <list of strings>
+    - attr_1
+    - attr_2
+    - ...
+
+In words, underneath the `minted` metadata key, you have the following options:
+
+### `no_default_autogobble` (boolean)
+
+By default this filter will always use `autogobble` with minted, which will
+automatically trim common preceding whitespace.  This is important because
+code blocks nested under a list or other block elements _will_ have common
+preceding whitespace that you _will_ want trimmed.
+
+### `no_mintinline` (boolean)
+
+Globally prevent this filter from emitting `\mintinline` calls for inline
+Code elements, emitting `\texttt` instead.  Possibly useful in saving
+compile time for large documents that do not seek to have syntax
+highlighting on inline code elements.
+
+### `default_block_language` (string)
+
+The default pygments lexer class to use for code blocks.  By default this
+is `"text"`, meaning no syntax highlighting.  This is a fallback value, code
+blocks that explicitly specify a lexer will not use it.
+
+### `default_inline_language` (string)
+
+Same as `default_block_language`, only for inline code (typed in single
+backticks).  The default is also `"text"`, and changing is discouraged.
+
+### `block_attributes` (list of strings)
+
+Any default attributes to apply to _all_ code blocks.  These may be
+overriden on a per-code-block basis.  See section 5.3 of the
+[minted documentation][minted_docs] for available options.
+
+### `inline_attributes` (list of strings)
+
+Any default attributes to apply to _all_ inline code.  These may be
+overriden on a per-code basis.  See section 5.3 of the
+[minted documentation][minted_docs] for available options.
+
+[minted_docs]: http://mirrors.ctan.org/macros/latex/contrib/minted/minted.pdf
+]]
+
+local List = require('pandoc.List')
+
+--------------------------------------------------------------------------------
+-- Potential metadata elements to override.                                   --
+--------------------------------------------------------------------------------
+local minted_no_mintinline           = false
+local minted_default_block_language  = "text"
+local minted_default_inline_language = "text"
+local minted_block_attributes        = {}
+local minted_inline_attributes       = {}
+
+--------------------------------------------------------------------------------
+-- Constants used to differentiate Code and CodeBlock elements.               --
+--------------------------------------------------------------------------------
+local MintedInline = 0
+local MintedBlock  = 1
+
+--------------------------------------------------------------------------------
+-- Utility functions.                                                         --
+--------------------------------------------------------------------------------
+-- Return the string lexer class to be used with minted.  `elem` should be
+-- either a Code or CodeBlock element (whose `classes` list will be inspected
+-- first).  `kind` is assumed to be either `MintedInline` or `MintedBlock` in
+-- order to choose the appropriate fallback lexer when unspecified.
+local function minted_language(elem, kind)
+  -- If the code [block] attached classes, we assume the first one is the
+  -- lexer class to use.
+  if #elem.classes > 0 then
+    return elem.classes[1]
+  end
+  -- Allow user-level metadata to override the inline language.
+  if kind == MintedInline then
+    return minted_default_inline_language
+  end
+  -- Allow user-level metadata to override the block language.
+  if kind == MintedBlock then
+    return minted_default_block_language
+  end
+
+  -- Failsafe, should not hit here unless function called incorrectly.
+  return "text"
+end
+
+-- Returns a boolean specifying whether or not the specified string `cls` is an
+-- option that is supported by the minted package.
+local function is_minted_class(cls)
+  -- Section 5.3 Available Options of Minted documentation.  Note that many of
+  -- these do not apply to \mintinline (inline Code).  Users are responsible
+  -- for supplying valid arguments to minted.  For example, specifying
+  -- `autogobble` and `gobble` at the same time is a usage error.
+  --
+  -- http://mirrors.ctan.org/macros/latex/contrib/minted/minted.pdf
+  local all_minted_options = List:new{
+    "autogobble", "baselinestretch", "beameroverlays", "breakafter",
+    "breakaftergroup", "breakaftersymbolpre", "breakaftersymbolpost",
+    "breakanywhere", "breakanywheresymbolpre", "breakanywheresymbolpost",
+    "breakautoindent", "breakbefore", "breakbeforegroup",
+    "breakbeforesymbolpre", "breakbeforesymbolpost", "breakbytoken",
+    "breakbytokenanywhere", "breakindent", "breakindentnchars", "breaklines",
+    "breaksymbol", "breaksymbolleft", "breaksymbolright", "breaksymbolindent",
+    "breaksymbolindentnchars", "breaksymbolindentleft",
+    "breaksymbolindentleftnchars", "breaksymbolindentright",
+    "breaksymbolindentrightnchars", "breaksymbolsep", "breaksymbolsepnchars",
+    "breaksymbolsepleft", "breaksymbolsepleftnchars", "breaksymbolsepright",
+    "breaksymbolseprightnchars", "bgcolor", "codetagify", "curlyquotes",
+    "encoding", "escapeinside", "firstline", "firstnumber", "fontfamily",
+    "fontseries", "fontsize", "fontshape", "formatcom", "frame", "framerule",
+    "framesep", "funcnamehighlighting", "gobble", "highlightcolor",
+    "highlightlines", "keywordcase", "label", "labelposition", "lastline",
+    "linenos", "numberfirstline", "numbers", "mathescape", "numberblanklines",
+    "numbersep", "obeytabs", "outencoding", "python3", "resetmargins",
+    "rulecolor", "samepage", "showspaces", "showtabs", "space", "spacecolor",
+    "startinline", "style", "stepnumber", "stepnumberfromfirst",
+    "stepnumberoffsetvalues", "stripall", "stripnl", "tab", "tabcolor",
+    "tabsize", "texcl", "texcomments", "xleftmargin", "xrightmargin"
+  }
+  return all_minted_options:includes(cls, 0)
+end
+
+-- Return a string for the minted attributes `\begin{minted}[attributes]` or
+-- `\mintinline[attributes]`.  Attributes are acquired by inspecting the
+-- specified element's `classes` and `attr` fields.  Any global attributes
+-- provided in the document metadata will be included _only_ if they do not
+-- override the element-level attributes.
+--
+-- `elem` should either be a Code or CodeBlock element, and `kind` is assumed to
+-- be either `MintedInline` or `MintedBlock`.  The `kind` determines which
+-- global default attribute list to use.
+local function minted_attributes(elem, kind)
+  -- The full listing of attributes that will be joined and returned.
+  local minted_attributes = {}
+
+  -- Book-keeping, track xxx=yyy keys `xxx` that have been added to
+  -- `minted_attributes` to make checking optional global defaults via the
+  -- `block_attributes` or `inline_attributes` easier.
+  local minted_keys = {}
+
+  -- Boolean style options for minted (e.g., ```{.bash .autogobble}) will appear
+  -- in the list of classes.
+  for _, cls in ipairs(elem.classes) do
+    if is_minted_class(cls) then
+      table.insert(minted_attributes, cls)
+      table.insert(minted_keys, cls)
+    end
+  end
+
+  -- Value options using key=value (e.g., ```{.bash fontsize=\scriptsize}) show
+  -- up in the list of attributes.
+  for _, attr in ipairs(elem.attributes) do
+    cls, value = attr[1], attr[2]
+    if is_minted_class(cls) then
+      table.insert(minted_attributes, cls .. "=" .. value)
+      table.insert(minted_keys, cls)
+    end
+  end
+
+  -- Add any global defaults _only_ if they do not conflict.  Note that conflict
+  -- is only in the literal sense.  If a user has `autogobble` and `gobble=2`
+  -- specified, these do conflict in the minted sense, but this filter makes no
+  -- checks on validity ;)
+  local global_defaults = nil
+  if kind == MintedInline then
+    global_defaults = minted_inline_attributes
+  elseif kind == MintedBlock then
+    global_defaults = minted_block_attributes
+  end
+  for _, global_attr in ipairs(global_defaults) do
+    -- Either use the index of `=` minus one, or -1 if no `=` present.  Fallback
+    -- on -1 means that the substring is the original string.
+    local end_idx = (string.find(global_attr, "=") or 0) - 1
+    local global_key = string.sub(global_attr, 1, end_idx)
+    local can_insert_global = true
+    for _, existing_key in ipairs(minted_keys) do
+      if existing_key == global_key then
+        can_insert_global = false
+        break
+      end
+    end
+
+    if can_insert_global then
+      table.insert(minted_attributes, global_attr)
+    end
+  end
+
+  -- Return a comma delimited string for specifying the attributes to minted.
+  return table.concat(minted_attributes, ",")
+end
+
+-- Return the specified `elem` with any minted data removed from the `classes`
+-- and `attr`.  Otherwise writers such as the HTML writer might produce invalid
+-- code since latex makes heavy use of the \backslash.
+local function remove_minted_attibutes(elem)
+  -- Remove any minted items from the classes.
+  classes = {}
+  for _, cls in ipairs(elem.classes) do
+    if not is_minted_class(cls) and cls ~= "no_minted" then
+      table.insert(classes, cls)
+    end
+  end
+  elem.classes = classes
+
+  -- Remove any minted items from the attributes.
+  extra_attrs = {}
+  for _, attr in ipairs(elem.attributes) do
+    cls, value = attr[1], attr[2]
+    if not is_minted_class(cls) then
+      table.insert(extra_attrs, {cls, value})
+    end
+  end
+  elem.attributes = extra_attrs
+
+  -- Return the (potentially modified) element for pandoc to take over.
+  return elem
+end
+
+-- Return a `start_delim` and `end_delim` that can safely wrap around the
+-- specified `text` when used inline. If no special characters occur in `text`,
+-- then a pair of braces are returned. Otherwise, if any character of
+-- `possible_delims` are not in `text`, then it is returned. If no delimiter
+-- could be found, an error is raised.
+local function minted_inline_delims(text)
+  local start_delim, end_delim
+  if text:find('[{}]') then
+    -- Try some other delimiter (the alphanumeric digits are in Python's
+    -- string.digits + string.ascii_letters order)
+    possible_delims = ('|!@#^&*-=+' .. '0123456789' ..
+                       'abcdefghijklmnopqrstuvwxyz' ..
+                       'ABCDEFGHIJKLMNOPQRSTUVWXYZ')
+    for char in possible_delims:gmatch('.') do
+      if not text:find(char, 1, true) then
+        start_delim = char
+        end_delim = char
+        break
+      end
+    end
+    if not start_delim then
+      local msg = 'Unable to determine delimiter to use around inline code %q'
+      error(msg:format(text))
+    end
+  else
+    start_delim = '{'
+    end_delim = '}'
+  end
+
+  return start_delim, end_delim
+end
+
+--------------------------------------------------------------------------------
+-- Pandoc overrides.                                                          --
+--------------------------------------------------------------------------------
+-- Override the pandoc Meta function so that we can parse the metadata for the
+-- document and store the necessary variables locally to use in other functions
+-- such as Code and CodeBlock (helper methods).
+function Meta(m)
+  -- Grab the `minted` metadata, quit early if not present.
+  local minted = m["minted"]
+  local found_autogobble = false
+  local always_autogobble = true
+  if minted ~= nil then
+    -- Parse and set the global bypass to turn off all \mintinline calls.
+    local no_mintinline = minted["no_mintinline"]
+    if no_mintinline ~= nil then
+      minted_no_mintinline = no_mintinline
+    end
+
+    -- Parse and set the default block language.
+    local default_block_language = minted.default_block_language
+      and pandoc.utils.stringify(minted.default_block_language)
+    if default_block_language ~= nil then
+      minted_default_block_language = default_block_language
+    end
+
+    -- Parse and set the default inline language.
+    local default_inline_language = minted.default_inline_language
+      and pandoc.utils.stringify(minted.default_inline_language)
+    if default_inline_language ~= nil then
+      minted_default_inline_language = default_inline_language
+    end
+
+    -- Parse the global default minted attributes to use on every block.
+    local block_attributes = minted["block_attributes"]
+    if block_attributes ~= nil then
+      for _, attr in ipairs(block_attributes) do
+        if attr == "autogobble" then
+          found_autogobble = true
+        end
+        table.insert(minted_block_attributes, attr[1].text)
+      end
+    end
+
+    -- Allow users to turn off autogobble for blocks, but really they should not
+    -- ever seek to do this (indented code blocks under list for example).
+    local no_default_autogobble = minted["no_default_autogobble"]
+    if no_default_autogobble ~= nil then
+      always_autogobble = not no_default_autogobble
+    end
+
+    -- Parse the global default minted attributes to use on ever inline.
+    local inline_attributes = minted["inline_attributes"]
+    if inline_attributes ~= nil then
+      for _, attr in ipairs(inline_attributes) do
+        table.insert(minted_inline_attributes, attr[1].text)
+      end
+    end
+  end
+
+  -- Make sure autogobble is turned on by default if no `minted` meta key is
+  -- provided for the document.
+  if always_autogobble and not found_autogobble then
+    table.insert(minted_block_attributes, "autogobble")
+  end
+
+  -- Return the metadata to pandoc (unchanged).
+  return m
+end
+
+-- Override inline code elements to use \mintinline for beamer / latex writers.
+-- Other writers have all minted attributes removed.
+function Code(elem)
+  if FORMAT == "beamer" or FORMAT == "latex" then
+    -- Allow a bypass to turn off \mintinline via adding .no_minted class.
+    local found_no_minted_class = false
+    for _, cls in ipairs(elem.classes) do
+      if cls == "no_minted" then
+        found_no_minted_class = true
+        break
+      end
+    end
+
+    -- Check for local or global bypass to turn off \mintinline
+    if minted_no_mintinline or found_no_minted_class then
+      return nil -- Return `nil` signals to `pandoc` that elem is not changed.
+    end
+
+    local start_delim, end_delim = minted_inline_delims(elem.text)
+    local language   = minted_language(elem, MintedInline)
+    local attributes = minted_attributes(elem, MintedInline)
+    local raw_minted = string.format(
+      "\\mintinline[%s]{%s}%s%s%s",
+      attributes,
+      language,
+      start_delim,
+      elem.text,
+      end_delim
+    )
+    -- NOTE: prior to pandoc commit 24a0d61, `beamer` cannot be used as the
+    -- RawBlock format.  Using `latex` should not cause any problems.
+    return pandoc.RawInline("latex", raw_minted)
+  else
+    return remove_minted_attibutes(elem)
+  end
+end
+
+-- Override code blocks to use \begin{minted}...\end{minted} for beamer / latex
+-- writers.  Other writers have all minted attributes removed.
+function CodeBlock(block)
+  if FORMAT == "beamer" or FORMAT == "latex" then
+    local language   = minted_language(block, MintedBlock)
+    local attributes = minted_attributes(block, MintedBlock)
+    local raw_minted = string.format(
+      "\\begin{minted}[%s]{%s}\n%s\n\\end{minted}",
+      attributes,
+      language,
+      block.text
+    )
+    -- NOTE: prior to pandoc commit 24a0d61, `beamer` cannot be used as the
+    -- RawBlock format.  Using `latex` should not cause any problems.
+    return pandoc.RawBlock("latex", raw_minted)
+  else
+    return remove_minted_attibutes(block)
+  end
+end
+
+-- Override headers to make all beamer frames fragile, since any minted
+-- environments or \mintinline invocations will halt compilation if the frame
+-- is not marked as fragile.
+function Header(elem)
+  if FORMAT == 'beamer' then
+    -- Check first that 'fragile' is not already present.
+    local has_fragile = false
+    for _, val in ipairs(elem.classes) do
+      if val == 'fragile' then
+        has_fragile = true
+        break
+      end
+    end
+
+    -- If not found, add fragile to the list of classes.
+    if not has_fragile then
+      table.insert(elem.classes, 'fragile')
+    end
+
+    -- NOTE: pass the remaining work to pandoc, noting that 2.5 and below
+    -- may duplicate the 'fragile' specifier.  Duplicated fragile does *not*
+    -- cause compile errors.
+    return elem
+  end
+end
+
+-- NOTE: order of return matters, Meta needs to be first otherwise the metadata
+-- from the document will not be loaded _first_.
+return {
+  {Meta = Meta},
+  {Code = Code},
+  {CodeBlock = CodeBlock},
+  {Header = Header}
+}

+ 33 - 0
example/assets/pandoc-scholar/lua-filters/multiple-bibliographies/README.md

@@ -0,0 +1,33 @@
+# multiple-bibliographies
+
+This filter allows to create multiple bibliographies using
+`pandoc-citeproc`. The content of each bibliography is controlled
+via YAML values and the file in which a bibliographic entry is
+specified.
+
+## Usage
+
+Instead of using the usual *bibliography* metadata field, all
+bibliographies must be defined via a separate field of the scheme
+*bibliographyX*, e.g.
+
+    ---
+    bibliography_main: main-bibliography.bib
+    bibliography_software: software.bib
+    ---
+
+The placement of bibliographies is controlled via special divs.
+
+    # References
+    
+    ::: {#refs_main}
+    :::
+    
+    # Software
+    
+    ::: {#refs_software}
+    :::
+
+Each refsX div should have a matching bibliographyX entry in the
+header. These divs are filled with citations from the respective
+bib-file.

+ 110 - 0
example/assets/pandoc-scholar/lua-filters/multiple-bibliographies/multiple-bibliographies.lua

@@ -0,0 +1,110 @@
+--[[
+multiple-bibliographies – create multiple bibliographies
+
+Copyright © 2018-2020 Albert Krewinkel
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+]]
+local List = require 'pandoc.List'
+local utils = require 'pandoc.utils'
+local stringify = utils.stringify
+local run_json_filter = utils.run_json_filter
+
+--- Collection of all cites in the document
+local all_cites = {}
+--- Document meta value
+local doc_meta = pandoc.Meta{}
+
+--- Div used by pandoc-citeproc to insert the bibliography.
+local refs_div = pandoc.Div({}, pandoc.Attr('refs'))
+
+local supports_quiet_flag = (function ()
+  local version = pandoc.pipe('pandoc-citeproc', {'--version'}, '')
+  local major, minor, patch = version:match 'pandoc%-citeproc (%d+)%.(%d+)%.?(%d*)'
+  major, minor, patch = tonumber(major), tonumber(minor), tonumber(patch)
+  return major > 0
+    or minor > 14
+    or (minor == 14 and patch >= 5)
+end)()
+
+--- Resolve citations in the document by combining all bibliographies
+-- before running pandoc-citeproc on the full document.
+local function resolve_doc_citations (doc)
+  -- combine all bibliographies
+  local meta = doc.meta
+  local orig_bib = meta.bibliography
+  meta.bibliography = pandoc.MetaList{orig_bib}
+  for name, value in pairs(meta) do
+    if name:match('^bibliography_') then
+      table.insert(meta.bibliography, value)
+    end
+  end
+  -- add dummy div to catch the created bibliography
+  table.insert(doc.blocks, refs_div)
+  -- resolve all citations
+  doc = run_json_filter(doc, 'pandoc-citeproc')
+  -- remove catch-all bibliography
+  table.remove(doc.blocks)
+  -- restore bibliography to original value
+  doc.meta.bibliography = orig_bib
+  return doc
+end
+
+--- Explicitly create a new meta object with all fields relevant for
+--- pandoc-citeproc.
+local function meta_for_pandoc_citeproc (bibliography)
+  -- We could just indiscriminately copy all meta fields, but let's be
+  -- explicit about what's important.
+  local fields = {
+    'bibliography', 'references', 'csl', 'citation-style',
+    'link-citations', 'citation-abbreviations', 'lang',
+    'suppress-bibliography', 'reference-section-title',
+    'notes-after-punctuation', 'nocite'
+  }
+  local new_meta = pandoc.Meta{}
+  for _, field in ipairs(fields) do
+    new_meta[field] = doc_meta[field]
+  end
+  new_meta.bibliography = bibliography
+  return new_meta
+end
+
+--- Create a bibliography for a given topic. This acts on all divs whose
+-- ID starts with "refs", followed by nothing but underscores and
+-- alphanumeric characters.
+local function create_topic_bibliography (div)
+  local name = div.identifier:match('^refs([_%w]*)$')
+  local bibfile = name and doc_meta['bibliography' .. name]
+  if not bibfile then
+    return nil
+  end
+  local tmp_blocks = {pandoc.Para(all_cites), refs_div}
+  local tmp_meta = meta_for_pandoc_citeproc(bibfile)
+  local tmp_doc = pandoc.Pandoc(tmp_blocks, tmp_meta)
+  local filter_args = {FORMAT, supports_quiet_flag and '-q' or nil}
+  local res = run_json_filter(tmp_doc, 'pandoc-citeproc', filter_args)
+  -- First block of the result contains the dummy paragraph, second is
+  -- the refs Div filled by pandoc-citeproc.
+  div.content = res.blocks[2].content
+  return div
+end
+
+return {
+  {
+    -- Collect all citations and the doc's Meta value for other filters.
+    Cite = function (c) all_cites[#all_cites + 1] = c end,
+    Meta = function (m) doc_meta = m end,
+  },
+  { Pandoc = resolve_doc_citations },
+  { Div = create_topic_bibliography },
+}

+ 68 - 0
example/assets/pandoc-scholar/lua-filters/pagebreak/README.md

@@ -0,0 +1,68 @@
+pagebreak
+=========
+
+This filter converts paragraps containing only the LaTeX
+`\newpage` or `\pagebreak` command into appropriate pagebreak
+markup for other formats. The command must be the only contents
+of a raw TeX block in order to be recognized. I.e., for Markdown
+the following is sufficient:
+
+    Paragraph before page break
+
+    \newpage
+
+    Paragraph after page break
+
+
+Usage
+-----
+
+Fully supported output formats are:
+
+- Docx,
+- LaTeX,
+- HTML, and
+- EPUB.
+
+ODT is supported, but requires additional settings in the
+reference document (see below).
+
+In all other formats, the page break is represented using the
+form feed character.
+
+
+### Usage with HTML
+If you want to use an HTML class rather than an inline style set
+the value of the metadata key `newpage_html_class` or the
+environment variable `PANDOC_NEWPAGE_HTML_CLASS` (the metadata
+'wins' if both are defined) to the name of the class and use CSS
+like this:
+
+    @media all {
+        .page-break	{ display: none; }
+    }
+    @media print {
+        .page-break	{ display: block; page-break-after: always; }
+    }
+
+
+### Usage with ODT
+
+To use with ODT you must create a reference ODT with a named
+paragraph style called `Pagebreak` (or whatever you set the
+metadata field `newpage_odt_style` or the environment variable
+`PANDOC_NEWPAGE_ODT_STYLE` to) and define it as having no extra
+space before or after but set it to have a pagebreak after it
+<https://help.libreoffice.org/Writer/Text_Flow>.
+
+(There will be an empty dummy paragraph, which means some extra
+vertical space, and you probably want that space to go at the
+bottom of the page before the break rather than at the top of
+the page after the break!)
+
+
+Alternative syntax
+------------------
+
+The form feed character as the only element in a paragraph is
+supported as an alternative to the LaTeX syntax described above.

+ 100 - 0
example/assets/pandoc-scholar/lua-filters/pagebreak/pagebreak.lua

@@ -0,0 +1,100 @@
+--[[
+pagebreak – convert raw LaTeX page breaks to other formats
+
+Copyright © 2017-2020 Benct Philip Jonsson, Albert Krewinkel
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+]]
+local stringify_orig = (require 'pandoc.utils').stringify
+
+local function stringify(x)
+  return type(x) == 'string' and x or stringify_orig(x)
+end
+
+--- configs – these are populated in the Meta filter.
+local pagebreak = {
+  epub = '<p style="page-break-after: always;"> </p>',
+  html = '<div style="page-break-after: always;"></div>',
+  latex = '\\newpage{}',
+  ooxml = '<w:p><w:r><w:br w:type="page"/></w:r></w:p>',
+  odt = '<text:p text:style-name="Pagebreak"/>'
+}
+
+local function pagebreaks_from_config (meta)
+  local html_class =
+    (meta.newpage_html_class and stringify(meta.newpage_html_class))
+    or os.getenv 'PANDOC_NEWPAGE_HTML_CLASS'
+  if html_class and html_class ~= '' then
+    pagebreak.html = string.format('<div class="%s"></div>', html_class)
+  end
+
+  local odt_style =
+    (meta.newpage_odt_style and stringify(meta.newpage_odt_style))
+    or os.getenv 'PANDOC_NEWPAGE_ODT_STYLE'
+  if odt_style and odt_style ~= '' then
+    pagebreak.odt = string.format('<text:p text:style-name="%s"/>', odt_style)
+  end
+end
+
+--- Return a block element causing a page break in the given format.
+local function newpage(format)
+  if format == 'docx' then
+    return pandoc.RawBlock('openxml', pagebreak.ooxml)
+  elseif format:match 'latex' then
+    return pandoc.RawBlock('tex', pagebreak.latex)
+  elseif format:match 'odt' then
+    return pandoc.RawBlock('opendocument', pagebreak.odt)
+  elseif format:match 'html.*' then
+    return pandoc.RawBlock('html', pagebreak.html)
+  elseif format:match 'epub' then
+    return pandoc.RawBlock('html', pagebreak.epub)
+  else
+    -- fall back to insert a form feed character
+    return pandoc.Para{pandoc.Str '\f'}
+  end
+end
+
+local function is_newpage_command(command)
+  return command:match '^\\newpage%{?%}?$'
+    or command:match '^\\pagebreak%{?%}?$'
+end
+
+-- Filter function called on each RawBlock element.
+function RawBlock (el)
+  -- Don't do anything if the output is TeX
+  if FORMAT:match 'tex$' then
+    return nil
+  end
+  -- check that the block is TeX or LaTeX and contains only
+  -- \newpage or \pagebreak.
+  if el.format:match 'tex' and is_newpage_command(el.text) then
+    -- use format-specific pagebreak marker. FORMAT is set by pandoc to
+    -- the targeted output format.
+    return newpage(FORMAT)
+  end
+  -- otherwise, leave the block unchanged
+  return nil
+end
+
+-- Turning paragraphs which contain nothing but a form feed
+-- characters into line breaks.
+function Para (el)
+  if #el.content == 1 and el.content[1].text == '\f' then
+    return newpage(FORMAT)
+  end
+end
+
+return {
+  {Meta = pagebreaks_from_config},
+  {RawBlock = RawBlock, Para = Para}
+}

+ 19 - 0
example/assets/pandoc-scholar/lua-filters/pandoc-quotes.lua/LICENSE.txt

@@ -0,0 +1,19 @@
+Copyright (c) 2018 Odin Kroeger
+
+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.

+ 110 - 0
example/assets/pandoc-scholar/lua-filters/pandoc-quotes.lua/README.md

@@ -0,0 +1,110 @@
+# pandoc-quotes.lua
+
+`pandoc-quotes.lua` is a filter for [Pandoc](https://www.pandoc.org/) that
+replaces non-typographic quotation marks with typographic ones for languages
+other than American English.
+
+You can define which typographic quotation marks to replace plain ones with by
+setting either a document's `quot-marks`, `quot-lang`, or `lang` metadata
+field. Typically, it should 'just work'.
+
+See the [manual page](man/pandoc-quotes.lua.md) for details.
+
+
+## Installing `pandoc-quotes.lua`
+
+You use `pandoc-quotes.lua` **at your own risk**. You have been warned.
+
+### Requirements
+
+You need [Pandoc](https://www.pandoc.org/) 2.0 or later.
+
+
+### Installation
+
+1. Download the
+   [latest release](https://github.com/odkr/pandoc-quotes.lua/releases/latest).
+2. Unpack it.
+3. Move `pandoc-quotes.lua` from the repository directory to the
+   `filters` sub-directory of your Pandoc data directory
+   (`pandoc --version` will tell you where that is).
+
+### POSIX-compliant systems
+
+If you have [curl](https://curl.haxx.se/) or
+[wget](https://www.gnu.org/software/wget/), you can (probably)
+install `pandoc-quotes.lua` by copy-pasting the
+following commands into a bourne shell:
+
+```sh
+(
+    set -Cefu
+    NAME=pandoc-quotes.lua VERS=0.1.10
+    URL="https://github.com/odkr/${NAME:?}/archive/v${VERS:?}.tar.gz"
+    FILTERS="${HOME:?}/.pandoc/filters"
+    mkdir -p "${FILTERS:?}"
+    {
+        curl -L "$URL" || ERR=$?
+        [ "${ERR-0}" -eq 127 ] && wget -q -O - "$URL"
+    } | tar xz
+    mv "$NAME-$VERS/pandoc-quotes.lua" "$FILTERS"
+)
+```
+
+You may also want to copy the manual page from the `man` directory in the
+repository to wherever your operating system searches for manual pages.
+
+
+## Test suite
+
+For the test suite to work, you need a POSIX-compliant operating system,
+[make](https://en.wikipedia.org/wiki/Make_(software)), and
+[Pandoc](https://www.pandoc.org/) 2.7.2. The test suite may or may not
+work with other versions of Pandoc.
+
+To run the test suite, just say:
+
+```sh
+    make test
+```
+
+## Documentation
+
+See the [manual page](man/pandoc-quotes.lua.md)
+and the source for details.
+
+
+## Contact
+
+If there's something wrong with `pandoc-quotes.lua`,
+[open an issue](https://github.com/odkr/pandoc-quotes.lua/issues).
+
+
+## License
+
+Copyright 2018, 2019 Odin Kroeger
+
+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.
+
+
+## Further Information
+
+
+GitHub:
+    <https://github.com/odkr/pandoc-quotes.lua>

+ 474 - 0
example/assets/pandoc-scholar/lua-filters/pandoc-quotes.lua/pandoc-quotes.lua

@@ -0,0 +1,474 @@
+--- Replaces plain quotation marks with typographic ones.
+-- 
+-- # SYNOPSIS
+-- 
+--      pandoc --lua-filter pandoc-quotes.lua
+-- 
+-- 
+-- # DESCRIPTION
+-- 
+-- pandoc-quotes.lua is a filter for pandoc that replaces non-typographic
+-- quotation marks with typographic ones for languages other than American
+-- English.
+-- 
+-- You can define which typographic quotation marks to replace plain ones with
+-- by setting either a document's quot-marks, quot-lang, or lang
+-- metadata field. If none of these is set, pandoc-quotes.lua does nothing.
+-- 
+-- You can add your own mapping of a language to quotation marks or override
+-- the default ones by setting quot-marks-by-lang.
+-- 
+-- ## quot-marks
+-- 
+-- A list of four strings, where the first item lists the primary left
+-- quotation mark, the second the primary right quotation mark, the third
+-- the secondary left quotation mark, and the fourth the secondary right
+-- quotation mark.
+-- 
+-- For example:
+-- 
+-- ```yaml
+-- ---
+-- quot-marks:
+--     - ''
+--     - ''
+--     - '
+--     - '
+-- ...
+-- ```
+-- 
+-- You always have to set all four.
+-- 
+-- If each quotation mark consists of one character only,
+-- you can write the whole list as a simple string.
+-- 
+-- For example:
+-- 
+-- ```yaml
+-- ---
+-- quot-marks: ""''
+-- ...
+-- ```
+-- 
+-- If quot-marks is set, the other fields are ignored.
+-- 
+-- 
+-- # quotation-lang
+-- 
+-- An RFC 5646-like code for the language the quotation marks of
+-- which shall be used (e.g., "pt-BR", "es").
+-- 
+-- For example:
+-- 
+-- ```yaml
+-- ---
+-- quot-lang: de-AT
+-- ...
+-- ```
+-- 
+-- Note: Only the language and the country tags of RFC 5646 are supported.
+-- For example, "it-CH" (i.e., Italian as spoken in Switzerland) is fine, 
+-- but "it-756" (also Italian as spoken in Switzerland) will return the 
+-- quotation marks for "it" (i.e., Italian as spoken in general).
+-- 
+-- If quot-marks is set, quot-lang is ignored.
+-- 
+-- 
+-- # lang
+-- 
+-- The format of lang is the same as for quot-lang. If quot-marks
+-- or quot-lang is set, lang is ignored. 
+-- 
+-- For example:
+-- 
+-- ```yaml
+-- ---
+-- lang: de-AT
+-- ...
+-- ```
+-- 
+-- 
+-- # ADDING LANGUAGES
+-- 
+-- You can add quotation marks for unsupported languages, or override the
+-- defaults, by setting the metadata field quot-marks-by-lang to a maping
+-- of RFC 5646-like language codes (e.g., "pt-BR", "es") to lists of quotation
+-- marks, which are given in the same format as for the quot-marks
+-- metadata field.
+-- 
+-- For example:
+-- 
+-- ```yaml
+-- ---
+-- quot-marks-by-lang:
+--     abc-XYZ: ""''
+-- lang: abc-XYZ
+-- ...
+-- ```
+-- 
+-- 
+-- # CAVEATS
+-- 
+-- pandoc represents documents as abstract syntax trees internally, and
+-- quotations are nodes in that tree. However, pandoc-quotes.lua replaces
+-- those nodes with their content, adding proper quotation marks. That is,
+-- pandoc-quotes.lua pushes quotations from the syntax of a document's
+-- representation into its semantics. That being so, you should not 
+-- use pandoc-quotes.lua with output formats that represent quotes
+-- syntactically (e.g., HTML, LaTeX, ConTexT). Moroever, filters running after
+-- pandoc-quotes won't recognise quotes. So, it should be the last or
+-- one of the last filters you apply.
+-- 
+-- Support for quotation marks of different languages is certainly incomplete
+-- and likely erroneous. See <https://github.com/odkr/pandoc-quotes.lua> if
+-- you'd like to help with this.
+-- 
+-- pandoc-quotes.lua is Unicode-agnostic.
+-- 
+-- 
+-- # SEE ALSO
+-- 
+-- pandoc(1)
+--
+--
+-- # AUTHOR
+--
+-- Copyright 2019 Odin Kroeger
+--
+--
+-- # LICENSE
+--
+-- 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.
+--
+--
+-- @script pandoc-quotes.lua
+-- @release 0.1.10
+-- @author Odin Kroeger
+-- @copyright 2018, 2020 Odin Kroeger
+-- @license MIT
+
+
+-- # INITIALISATION
+
+local M = {}
+
+local pairs = pairs
+local require = require
+
+local io = io
+local table = table
+local package = package
+
+local pandoc = pandoc
+if not pandoc.utils then pandoc.utils = require 'pandoc.utils' end
+
+local _ENV = M
+
+local text = require 'text'
+
+
+-- # CONSTANTS
+
+--- The name of this script.
+SCRIPT_NAME = 'pandoc-quotes.lua'
+
+--- The path seperator of the operating system.
+PATH_SEP = package.config:sub(1, 1)
+
+--- The character sequence to end a line.
+if PATH_SEP == '\\' then EOL = '\r\n'
+                    else EOL = '\n'   end
+
+
+--- A list of mappings from RFC 5646-ish language codes to quotation marks.
+-- 
+-- I have adopted the list below from:
+-- <https://en.wikipedia.org/w/index.php?title=Quotation_mark&oldid=836731669>
+-- 
+-- I tried to come up with reasonable defaults for secondary quotes for
+-- language that, according to the Wikipedia, don't have any.
+--
+-- Adding languages:
+--
+-- Add an ordered pair, where the first item is an RFC 5646 language
+-- code (though only the language and country tags are supported) and the
+-- second item is a list of quotation marks, in the following order:
+-- primary left, primary right, secondary left, secondary right.
+--
+-- You have to list four quotation marks, even if the langauge you add does
+-- not use secondary quotation marks. Just come up with something that makes
+-- sense. This is because a user may, rightly, find that just because their
+-- language does not 'officially' have secondary quotation marks, they
+-- are going to use them anyway. And they should get a reasonable result,
+-- not a runtime error.
+--
+-- The order in which languages are listed is meaningless. If you define 
+-- variants for a language that is spoken in different countries, also
+-- define a 'default' for the language alone, without the country tag.
+QUOT_MARKS_BY_LANG = {
+    bo          = {'「', '」',    '『', '』'     },
+    bs          = {'”',  '”',     '’',  '’'    },
+    cn          = {'「', '」',    '『', '』'     },
+    cs          = {'„',  '“',     '‚',  '‘'    },
+    cy          = {'‘',  '’',     '“',  '”'    },
+    da          = {'»',  '«',     '›',  '‹'    },
+    de          = {'„',  '“',     '‚',  '‘'    },
+    ['de-CH']   = {'«',  '»',     '‹',  '›'    },
+    el          = {'«',  '»',     '“',  '”'    },
+    en          = {'“',  '”',     '‘',  '’'    },
+    ['en-US']   = {'“',  '”',     '‘',  '’'    },
+    ['en-GB']   = {'‘',  '’',     '“',  '”'    },
+    ['en-UK']   = {'‘',  '’',     '“',  '”'    },
+    ['en-CA']   = {'“',  '”',     '‘',  '’'    },
+    eo          = {'“',  '”',     '‘',  '’'    },
+    es          = {'«',  '»',     '“',  '”'    },
+    et          = {'„',  '“',     '‚',  '‘'    },
+    fi          = {'”',  '”',     '’',  '’'    },
+    fil         = {'“',  '”',     '‘',  '’'    },
+    fa          = {'«',  '»',     '‹',  '›'    },
+    fr          = {'«',  '»',     '‹',  '›'    },
+    ga          = {'“',  '”',     '‘',  '’'    },
+    gd          = {'‘',  '’',     '“',  '”'    },
+    gl          = {'«',  '»',     '‹',  '›'    },
+    he          = {'“',  '”',     '‘',  '’'    },
+    hi          = {'“',  '”',     '‘',  '’'    },
+    hu          = {'„',  '”',     '»',  '«'    },
+    hr          = {'„',  '“',     '‚',  '‘'    },
+    ia          = {'“',  '”',     '‘',  '’'    },
+    id          = {'“',  '”',     '‘',  '’'    },
+    is          = {'„',  '“',     '‚',  '‘'    },
+    it          = {'«',  '»',     '“',  '”'    },
+    ['it-CH']   = {'«',  '»',     '‹',  '›'    },
+    ja          = {'「', '」',    '『',  '』'    },
+    jbo         = {'lu', 'li\'u', 'lu', 'li\'u'},
+    ka          = {'„',  '“',     '‚',  '‘'    },
+    khb         = {'《', '》',    '〈',  '〉'    },
+    kk          = {'«',  '»',     '‹',  '›'    },
+    km          = {'«',  '»',     '‹',  '›'    },
+    ko          = {'《', '》',    '〈',  '〉'    },
+    ['ko-KR']   = {'“',  '”',     '‘',  '’'    },
+    lt          = {'„',  '“',     '‚',  '‘'    },
+    lv          = {'„',  '“',     '‚',  '‘'    },
+    lo          = {'«',  '»',     '‹',  '›'    },
+    nl          = {'„',  '”',     '‚',  '’'    },
+    mk          = {'„',  '“',     '’',  '‘'    },
+    mn          = {'«',  '»',     '‹',  '›'    },
+    mt          = {'“',  '”',     '‘',  '’'    },
+    no          = {'«',  '»',     '«',  '»'    },
+    pl          = {'„',  '”',     '»',  '«'    },
+    ps          = {'«',  '»',     '‹',  '›'    },
+    pt          = {'«',  '»',     '“',  '”'    },
+    ['pt-BR']   = {'“',  '”',     '‘',  '’'    },
+    rm          = {'«',  '»',     '‹',  '›'    },
+    ro          = {'„',  '”',     '«',  '»'    },
+    ru          = {'«',  '»',     '“',  '”'    },
+    sk          = {'„',  '“',     '‚',  '‘'    },
+    sl          = {'„',  '“',     '‚',  '‘'    },
+    sq          = {'„',  '“',     '‚',  '‘'    },
+    sr          = {'„',  '“',     '’',  '’'    },
+    sv          = {'”',  '”',     '’',  '’'    },
+    tdd         = {'「', '」',    '『',  '』'    },
+    ti          = {'«',  '»',     '‹',  '›'    },
+    th          = {'“',  '”',     '‘',  '’'    },
+    thi         = {'「', '」',    '『',  '』'    },
+    tr          = {'«',  '»',     '‹',  '›'    },
+    ug          = {'«',  '»',     '‹',  '›'    },
+    uk          = {'«',  '»',     '„',  '“'    },
+    uz          = {'«',  '»',     '„',  '“'    },
+    vi          = {'“',  '”',     '‘',  '’'    },
+    wen         = {'„',  '“',     '‚',  '‘'    },
+    ka          = {'„',  '“',     '‚',  '‘'    },
+    khb         = {'《', '》',     '〈', '〉'    },
+    kk          = {'«',  '»',     '‹',  '›'    },
+    km          = {'«',  '»',     '‹',  '›'    },
+    ko          = {'《', '》',     '〈', '〉'    },
+    ['ko-KR']   = {'“',  '”',     '‘',  '’'    },
+    lt          = {'„',  '“',     '‚',  '‘'    },
+    lv          = {'„',  '“',     '‚',  '‘'    },
+    lo          = {'«',  '»',     '‹',  '›'    },
+    nl          = {'„',  '”',     '‚',  '’'    },
+    mk          = {'„',  '“',     '’',  '‘'    },
+    mn          = {'«',  '»',     '‹',  '›'    },
+    mt          = {'“',  '”',     '‘',  '’'    },
+    no          = {'«',  '»',     '«',  '»'    },
+    pl          = {'„',  '”',     '»',  '«'    },
+    ps          = {'«',  '»',     '‹',  '›'    },
+    pt          = {'«',  '»',     '“',  '”'    },
+    ['pt-BR']   = {'“',  '”',     '‘',  '’'    },
+    rm          = {'«',  '»',     '‹',  '›'    },
+    ro          = {'„',  '”',     '«',  '»'    },
+    ru          = {'«',  '»',     '“',  '”'    },
+    sk          = {'„',  '“',     '‚',  '‘'    },
+    sl          = {'„',  '“',     '‚',  '‘'    },
+    sq          = {'„',  '“',     '‚',  '‘'    },
+    sr          = {'„',  '“',     '’',  '’'    },
+    sv          = {'”',  '”',     '’',  '’'    },
+    tdd         = {'「', '」',     '『', '』'    },
+    ti          = {'«',  '»',     '‹',  '›'    },
+    th          = {'“',  '”',     '‘',  '’'    },
+    thi         = {'「', '」',     '『', '』'    },
+    tr          = {'«',  '»',     '‹',  '›'    },
+    ug          = {'«',  '»',     '‹',  '›'    },
+    uk          = {'«',  '»',     '„',  '“'    },
+    uz          = {'«',  '»',     '„',  '“'    },
+    vi          = {'“',  '”',     '‘',  '’'    },
+    wen         = {'„',  '“',     '‚',  '‘'    }
+}
+
+
+-- # FUNCTIONS
+
+--- Prints warnings to STDERR.
+--
+-- Prefixes messages with `SCRIPT_NAME` and ": ".
+-- Also appends an end of line sequence.
+--
+-- @tparam string str A string format to be written to STDERR.
+-- @tparam string ... Arguments to that format.
+function warn (str, ...)
+    io.stderr:write(SCRIPT_NAME, ': ', string.format(str, ...), EOL)
+end
+
+
+--- Applies a function to every element of a list.
+--
+-- @tparam func f The function.
+-- @tparam tab list The list.
+-- @treturn tab The return values of `f`.
+function map (f, list)
+    local ret = {}
+    for k, v in pairs(list) do ret[k] = f(v) end
+    return ret
+end
+
+do
+    local stringify = pandoc.utils.stringify
+
+    --- Reads quotation marks from a `quot-marks` metadata field.
+    --
+    -- @tparam pandoc.MetaValue The content of a metadata field.
+    --  Must be either of type pandoc.MetaInlines or pandoc.MetaList.
+    -- @treturn[1] {pandoc.Str,pandoc.Str,pandoc.Str,pandoc.Str} 
+    --  A table of quotation marks 
+    -- @treturn[2] `nil` if an error occurred.
+    -- @treturn[2] string An error message.
+    function get_quotation_marks (meta)
+        if meta.t == 'MetaInlines' then
+            local marks = stringify(meta)
+            if text.len(marks) ~= 4 then
+                return nil, 'not four quotation marks'
+            end
+            local ret = {}
+            for i = 1, 4 do ret[i] = text.sub(marks, i, i) end
+            return ret
+        elseif meta.t == 'MetaList' then
+            local marks = map(stringify, meta)
+            if #marks ~= 4 then
+                return nil, 'not four quotation marks'
+            end
+            return marks
+        end
+        return nil, 'neither a string nor a list'
+    end
+end
+
+
+do
+    local stringify = pandoc.utils.stringify
+    
+    -- Holds the quotation marks for the language of the document.
+    -- Common to `configure` and `insert_quot_marks`.
+    local QUOT_MARKS = nil
+
+    --- Determines the quotation marks for the document.
+    --
+    -- Stores them in `QUOT_MARKS`, which it shares with `insert_quot_marks`.
+    -- Prints errors to STDERR.
+    --
+    -- @tparam pandoc.Meta The document's metadata.
+    function configure (meta)
+        local quot_marks, lang
+        if meta['quot-marks-by-lang'] then
+            for k, v in pairs(meta['quot-marks-by-lang']) do
+                local quot_marks, err = get_quotation_marks(v)
+                if not quot_marks then 
+                    warn('metadata field "quot-marks-by-lang": lang "%s": %s.',
+                         k, err) 
+                    return
+                end
+                QUOT_MARKS_BY_LANG[k] = quot_marks
+            end
+        end
+        if meta['quot-marks'] then
+            local err
+            quot_marks, err = get_quotation_marks(meta['quot-marks'])
+            if not quot_marks then 
+                warn('metadata field "quot-marks": %s.', err)
+                return
+            end
+        elseif meta['quot-lang'] then
+            lang = stringify(meta['quot-lang'])
+        elseif meta['lang'] then
+            lang = stringify(meta['lang'])
+        end
+        if lang then
+            for i = 1, 3 do
+                if     i == 2 then lang = lang:match '^(%a+)'
+                elseif i == 3 then
+                    local expr = '^' .. lang .. '-'
+                    for k, v in pairs(QUOT_MARKS_BY_LANG) do
+                        if k:match(expr) then quot_marks = v break end
+                    end
+                end
+                if     i  < 3 then quot_marks = QUOT_MARKS_BY_LANG[lang] end
+                if quot_marks then break end
+            end
+        end
+        if quot_marks then QUOT_MARKS = map(pandoc.Str, quot_marks) 
+        elseif lang then warn('%s: unknown language.', lang) end
+    end
+
+
+    do
+        local insert = table.insert
+        --- Replaces quoted elements with quoted text.
+        --
+        -- Uses the quotation marks stored in `QUOT_MARKS`, 
+        -- which it shares with `configure`.
+        --
+        -- @tparam pandoc.Quoted quoted A quoted element.
+        -- @treturn {pandoc.Str,pandoc.Inline,...,pandoc.Str}
+        --  A list with the opening quote (as `pandoc.Str`),
+        --  the content of `quoted`, and the closing quote (as `pandoc.Str`).
+        function insert_quot_marks (quoted)
+            if not QUOT_MARKS then return end
+            local quote_type = quoted.c[1]
+            local inlines    = quoted.c[2]
+            local left, right
+            if     quote_type == 'DoubleQuote' then left, right = 1, 2
+            elseif quote_type == 'SingleQuote' then left, right = 3, 4
+            else   error('unknown quote type') end
+            insert(inlines, 1, QUOT_MARKS[left])
+            insert(inlines,    QUOT_MARKS[right])
+            return inlines
+        end
+    end
+end
+
+return {{Meta = configure}, {Quoted = insert_quot_marks}}

+ 56 - 0
example/assets/pandoc-scholar/lua-filters/plantuml/plantuml.lua

@@ -0,0 +1,56 @@
+--[[
+# PlantUML Pandoc filter
+PlantUML Pandoc filter to process code blocks with class "plantuml" containing PlantUML notation into images.
+
+* For textual output formats, use --extract-media=DIR
+* For HTML formats, you may alternatively use --self-contained
+
+## Example in markdown-file
+```plantuml
+@startuml
+Alice -> Bob: Authentication Request Bob --> Alice: Authentication Response
+Alice -> Bob: Another authentication Request Alice <-- Bob: another authentication Response @enduml
+```
+## Run pandoc
+```
+pandoc --self-contained --lua-filter=plantuml.lua readme.md -o output.htm
+```
+
+## Prerequisites
+* download PlantUML from http://plantuml.com (needs JAVA)
+* 3 ways to set the environment
+    1. plantuml.lua and plantuml.jar in the same folder and start pandoc always from this folder
+    2. set a Environment Variable PLANTUML with the path to plantuml.jar
+        * Windows - with powershell: Set-Item env:PLANTUML "c:\bin\plantuml.jar"
+    3. change path to plantuml.jar in plantuml.lua
+
+This script based on the example "Converting ABC code to music notation" from https://pandoc.org/lua-filters.html
+**This script was only tested with markdown to html on a windows environment!**
+]]
+
+-- Path to PlantUML.jar
+-- if you use opinion 3 change the path to plantuml.jar like this:
+-- local plantumlPath = os.getenv("PLANTUML") or "c:\\bin\\plantuml.jar"
+local plantumlPath = os.getenv("PLANTUML") or "plantuml.jar"
+
+-- SVG has a much better quality
+-- local filetype = "png"
+-- local mimetype = "image/png"
+local filetype = "svg"
+local mimetype = "image/svg+xml"
+
+-- call plantuml.jar wit some parameters (see plantuml help)
+local function plantuml(puml, filetype, plantumlPath)
+    local final = pandoc.pipe("java", {"-jar", plantumlPath, "-t" .. filetype, "-pipe", "-charset", "UTF8"}, puml)
+    return final
+end
+
+-- search for class "plantuml" and replace with image
+function CodeBlock(block)
+    if block.classes[1] == "plantuml" then
+        local img = plantuml(block.text, filetype, plantumlPath)
+        local fname = pandoc.sha1(img) .. "." .. filetype
+        pandoc.mediabag.insert(fname, mimetype, img)
+        return pandoc.Para{ pandoc.Image({pandoc.Str("PlantUML Diagramm")}, fname) }
+    end
+end

+ 30 - 0
example/assets/pandoc-scholar/lua-filters/plantuml/readme.md

@@ -0,0 +1,30 @@
+# PlantUML Pandoc filter
+PlantUML Pandoc filter to process code blocks with class "plantuml" containing PlantUML notation into images.
+
+* For textual output formats, use --extract-media=DIR
+* For HTML formats, you may alternatively use --self-contained
+
+## Example in markdown-file
+```plantuml
+@startuml
+Alice -> Bob: Authentication Request Bob --> Alice: Authentication Response
+Alice -> Bob: Another authentication Request Alice <-- Bob: another authentication Response
+@enduml
+```
+## Run pandoc
+```
+pandoc --self-contained --lua-filter=plantuml.lua readme.md -o output.htm
+```
+
+## Prerequisites
+* download PlantUML from http://plantuml.com (needs JAVA)
+* 3 ways to set the environment
+    1. plantuml.lua and plantuml.jar in the same folder and start pandoc always from this folder
+    2. set a Environment Variable PLANTUML with the path to plantuml.jar
+        * Windows - with powershell: Set-Item env:PLANTUML "c:\bin\plantuml.jar"
+    3. change path to plantuml.jar in plantuml.lua
+
+
+This script based on the example "Converting ABC code to music notation" from https://pandoc.org/lua-filters.html
+
+This script was only tested with markdown to html on a windows environment!

+ 91 - 0
example/assets/pandoc-scholar/lua-filters/scholarly-metadata/README.md

@@ -0,0 +1,91 @@
+# scholarly-metadata
+
+The filter turns metadata entries for authors and their
+affiliations into a canonical form. This allows users to
+conveniently declare document authors and their affiliations,
+while making it possible to rely on default object metadata
+structures when using the data in other filters or when accessing
+the data from custom templates.
+
+
+## Canonical format for authors and affiliations
+
+Authors and affiliations entries are treated as *named objects*.
+All named objects will have an ID and a name, i.e. they are
+metadata objects with *at least* those two keys:
+
+    - id: namedObjectExample
+      name: Example for a named object.
+
+The filter converts the *author* and *institute* metadata fields
+into lists of named objects.
+
+E.g., the following YAML data
+
+    author:
+      - Jane Doe:
+          email: 'jane.doe@example.edu'
+      - John Q. Doe
+
+
+will be transformed into
+
+    author:
+    - email: 'jane.doe\@example.edu'
+      id: Jane Doe
+      name: Jane Doe
+    - id: 'John Q. Doe'
+      name: 'John Q. Doe'
+      
+Internally, `id` will be a simple string, while `name` is of type
+`MetaInlines`.
+      
+
+## Referencing affiliations
+
+Author affiliations are a common feature of scholarly
+publications. It is possible to add institutes to each author
+object. Three methods of doing this are supported.
+
+1.  **Referencing institutes by list index**: affiliations can be
+    listed in the *institute* metadata field and then referenced
+    by using the numerical index:
+    
+        institute:
+          - Acme Corporation
+          - Federation of Planets
+        author:
+          - Jane Doe:
+              institute: [1, 2]
+          - John Q. Doe:
+              institute: [2]
+        
+    This is also the canonical representation used to keep track
+    of author affiliations.
+
+2.  **Referencing institutes by ID**: using numerical indices is
+    error prone and difficult to maintain when adding or removing
+    authors or affilications. It is hence possible to use IDs
+    instead:
+
+        institute:
+          - acme: Acme Corporation
+          - federation: Federation of Planets
+        author:
+          - Jane Doe:
+              institute: [acme, federation]
+          - John Q. Doe:
+              institute: [federation]
+
+3.  **Adding institute as an attribute**: sometimes it might be
+    more convenient to give an affiliation directly in the
+    author's YAML object. Those objects can still be referenced
+    by ID from authors listed below such entry.
+    
+        author:
+          - Jane Doe:
+              institute:
+               - Acme Cooproration
+               - federation: Federation of Planets
+          - John Q. Doe:
+              institute: [federation]

+ 185 - 0
example/assets/pandoc-scholar/lua-filters/scholarly-metadata/scholarly-metadata.lua

@@ -0,0 +1,185 @@
+--[[
+ScholarlyMeta – normalize author/affiliation meta variables
+
+Copyright (c) 2017-2020 Albert Krewinkel, Robert Winkler
+
+Permission to use, copy, modify, and/or distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright notice
+and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+]]
+local List = require 'pandoc.List'
+
+-- Split a string at commas.
+local function comma_separated_values(str)
+  local acc = List:new{}
+  for substr in str:gmatch('([^,]*)') do
+    acc[#acc + 1] = substr:gsub('^%s*', ''):gsub('%s*$', '') -- trim
+  end
+  return acc
+end
+
+--- Ensure the return value is a list.
+local function ensure_list (val)
+  if type(val) ~= 'table' then
+    -- create singleton list (or empty list if val == nil).
+    return List:new{val}
+  elseif val.t == 'MetaInlines' then
+    -- check if this is really a comma-separated list
+    local csv = comma_separated_values(pandoc.utils.stringify(val))
+    if #csv >= 2 then
+      return csv
+    end
+    return List:new{val}
+  elseif val.t == 'MetaList' then
+    return List:new(val)
+  else
+    -- MetaBlocks or MetaMap, use as a singleton
+    return List:new{val}
+  end
+end
+
+--- Returns a function which checks whether an object has the given ID.
+local function has_id (id)
+  return function(x) return x.id == id end
+end
+
+--- Copy all key-value pairs of the first table into the second iff there is no
+-- such key yet in the second table.
+-- @returns the second argument
+function add_missing_entries(a, b)
+  for k, v in pairs(a) do
+    b[k] = b[k] or v
+  end
+  return b
+end
+
+--- Create an object with a name. The name is either taken directly from the
+-- `name` field, or from the *only* field name (i.e., key) if the object is a
+-- dictionary with just one entry. If neither exists, the name is left unset
+-- (`nil`).
+function to_named_object (obj)
+  local named = {}
+  if type(obj) ~= 'table' then
+    -- if the object isn't a table, just use its value as a name.
+    named.name = pandoc.MetaInlines{pandoc.Str(tostring(obj))}
+    named.id = tostring(obj)
+  elseif obj.t == 'MetaInlines' then
+      -- Treat inlines as the name
+      named.name = obj
+      named.id = pandoc.utils.stringify(obj)
+  elseif obj.name ~= nil then
+    -- object has name attribute → just create a copy of the object
+    add_missing_entries(obj, named)
+    named.id = pandoc.utils.stringify(named.id or named.name)
+  elseif next(obj) and next(obj, next(obj)) == nil then
+    -- the entry's key is taken as the name, the value contains the
+    -- attributes.
+    key, attribs = next(obj)
+    if type(attribs) == "string" or attribs.t == 'MetaInlines' then
+      named.name = attribs
+    else
+      add_missing_entries(attribs, named)
+      named.name = named.name or pandoc.MetaInlines{pandoc.Str(tostring(key))}
+    end
+    named.id = named.id and pandoc.utils.stringify(named.id) or key
+  else
+    -- this is not a named object adhering to the usual conventions.
+    error('not a named object: ' .. tostring(obj))
+  end
+  return named
+end
+
+--- Resolve institute placeholders to full named objects
+local function resolve_institutes (institute, known_institutes)
+  local unresolved_institutes
+  if institute == nil then
+    unresolved_institutes = {}
+  elseif type(institute) == "string" or type(institute) == "number" then
+    unresolved_institutes = {institute}
+  else
+    unresolved_institutes = institute
+  end
+
+  local result = List:new{}
+  for i, inst in ipairs(unresolved_institutes) do
+    result[i] =
+      known_institutes[tonumber(inst)] or
+      known_institutes:find_if(has_id(pandoc.utils.stringify(inst))) or
+      to_named_object(inst)
+  end
+  return result
+end
+
+--- Insert a named object into a list; if an object of the same name exists
+-- already, add all properties only present in the new object to the existing
+-- item.
+function merge_on_id (list, namedObj)
+  local elem, idx = list:find_if(has_id(namedObj.id))
+  local res = elem and add_missing_entries(namedObj, elem) or namedObj
+  local obj_idx = idx or (#list + 1)
+  -- return res, obj_idx
+  list[obj_idx] = res
+  return res, #list
+end
+
+--- Flatten a list of lists.
+local function flatten (lists)
+  local result = List:new{}
+  for _, lst in ipairs(lists) do
+    result:extend(lst)
+  end
+  return result
+end
+
+--- Canonicalize authors and institutes
+local function canonicalize(raw_author, raw_institute)
+  local institutes = ensure_list(raw_institute):map(to_named_object)
+  local authors = ensure_list(raw_author):map(to_named_object)
+
+  for _, author in ipairs(authors) do
+    author.institute = resolve_institutes(
+      ensure_list(author.institute),
+      institutes
+    )
+  end
+
+  -- Merge institutes defined in author objects with those defined in the
+  -- top-level list.
+  local author_insts = flatten(authors:map(function(x) return x.institute end))
+  for _, inst in ipairs(author_insts) do
+    merge_on_id(institutes, inst)
+  end
+
+  -- Add list indices to institutes for numbering and reference purposes
+  for idx, inst in ipairs(institutes) do
+    inst.index = pandoc.MetaInlines{pandoc.Str(tostring(idx))}
+  end
+
+  -- replace institutes with their indices
+  local to_index = function (inst)
+    return tostring(select(2, institutes:find_if(has_id(inst.id))))
+  end
+  for _, author in ipairs(authors) do
+    author.institute = pandoc.MetaList(author.institute:map(to_index))
+  end
+
+  return authors, institutes
+end
+
+
+return {
+  {
+    Meta = function(meta)
+      meta.author, meta.institute = canonicalize(meta.author, meta.institute)
+      return meta
+    end
+  }
+}

+ 60 - 0
example/assets/pandoc-scholar/lua-filters/scrlttr2/README.md

@@ -0,0 +1,60 @@
+# scrlttr2
+
+This filter allows to write DIN 5008 letter using the [scrlttr2]
+LaTeX document class from KOMA script. It converts metadata to
+the appropriate KOMA variables and allows using the default LaTeX
+template shipped with pandoc.
+
+[scrlttr2]: https://www.ctan.org/pkg/scrlttr2
+
+## Base variables
+
+  - `opening`: phrase used as an opening;
+    defaults to "Dear Sir/Madam,"
+  - `closing`: closing phrase; defaults to "Sincerely,"
+  - `address`: recipient's street address;
+    defaults to "no address given"
+  - `date`: the date of the letter; defaults to the current day.
+
+## KOMA Variables
+
+Currently, the following metadata fields are translated to KOMA
+variables:
+
+- `fromaddress` (alias: `return-address`): address of the sender
+- `fromfax` (alias: `fax`): sender's fax number
+- `fromemail` (alias: `email`): sender's email
+- `fromlogo` (alias: `logo`): value to be used as the sender's logo
+- `fromname` (alias: `author`): sender name
+- `fromphone` (alias: `phone`): sender's phone number
+- `fromurl` (alias: `url`): sender's URL
+- `customer`: customer number
+- `invoice`: invoice number
+- `myref`: sender's reference
+- `place`: sender's place used near date
+- `signature`: sender's signature
+- `subject`: letter's subject
+- `title`: letter title
+- `yourref`: addressee's reference
+
+The values of these variables are converted to MetaInlines. If a
+list is given, then each list item is used as a line, e.g.,
+
+    fromaddress:
+      - 35 Industry Way
+      - Springfield
+      
+The `KOMAoptions` value is inferred from the given variables, but
+can be overwritten by specifying it explicitly.
+
+See the scrlttr2 documentation for details.
+
+## Intended Usage
+
+Many sender variables don't change, so it is sensible to provide
+default values for these. Authors using Markdown to draft letters
+can use a separate YAML file for this. E.g., if there is a file
+`default.yml` which contains the sender's details, then only the
+addressee's data must be specified.
+
+    pandoc --lua-filter=scrlttr2 letter.md default.yml -o out.pdf

+ 161 - 0
example/assets/pandoc-scholar/lua-filters/scrlttr2/scrlttr2.lua

@@ -0,0 +1,161 @@
+-- Ensure unpack also works if pandoc was compiled against Lua 5.1
+local unpack = unpack or table.unpack
+local List = require 'pandoc.List'
+local stringify = (require 'pandoc.utils')['stringify']
+
+--- Set some default options
+local default = {
+  opening = 'Dear Sir/Madam,',
+  closing = 'Sincerely,',
+  address = 'no address given'
+}
+
+--- Return a list of inlines representing a call to a latex command.
+local function latex_command (command, ...)
+  local entry = {
+    pandoc.RawInline('latex', '\\' .. command),
+  }
+  for _, arg in ipairs{...} do
+    entry[#entry + 1] = pandoc.RawInline('latex', '{')
+    if type(arg) ~= 'table' then
+      entry[#entry + 1] = pandoc.RawInline('latex', tostring(arg))
+    else
+      List.extend(entry, arg)
+    end
+    entry[#entry + 1] = pandoc.RawInline('latex', '}')
+  end
+  return entry
+end
+
+--- Convert the given meta-value to a list of inlines
+local function ensure_inlines (val)
+  if not val or type(val) == 'string' or type(val) == 'boolean' then
+    return pandoc.MetaInlines{pandoc.Str(tostring(val))}
+  elseif type(val) == 'table' and val.t == 'MetaInlines' then
+      return val
+  elseif type(val) == 'table' then
+    local res = List:new{}
+    for i = 1, #val do
+      res:extend(val[i])
+      res[#res + 1] = pandoc.RawInline('latex', '\\\\ ')
+    end
+    res[#res] = nil -- drop last linebreak
+    return pandoc.MetaInlines(res)
+  else
+    return pandoc.MetaInlines{pandoc.Str(pandoc.utils.stringify(val))}
+  end
+end
+
+--- Convert the given value to a MetaList
+local function ensure_meta_list (val)
+  if not val or val.t ~= 'MetaList'  then
+    return pandoc.MetaList{}
+  else
+    return val
+  end
+end
+
+--- Set supported variables as KOMA variables.
+function setkomavar_commands (meta)
+  local set_vars = {}
+  local res = {}
+  local function set_koma_var (name, value, enable)
+    if value ~= nil then
+      res[#res + 1] = latex_command('setkomavar', name, ensure_inlines(value))
+      if enable then
+        set_vars[#set_vars + 1] = name
+      end
+    end
+  end
+
+  set_koma_var('fromname', meta.fromname or meta.author)
+  set_koma_var('fromaddress', meta.fromaddress or meta['return-address'])
+  set_koma_var('subject', meta.subject)
+  set_koma_var('title', meta.title)
+  set_koma_var('signature', meta.signature)
+  set_koma_var('customer', meta.customer)
+  set_koma_var('yourref', meta.yourref)
+  set_koma_var('myref', meta.myref)
+  set_koma_var('invoice', meta.invoice)
+  set_koma_var('place', meta.place)
+
+  set_koma_var('fromfax', meta.fromfax or meta.fax, true)
+  set_koma_var('fromurl', meta.fromurl or meta.url, true)
+  set_koma_var('fromlogo', meta.fromlogo or meta.logo, true)
+  set_koma_var('fromemail', meta.fromemail or meta.email, true)
+  set_koma_var('fromphone', meta.fromphone or meta.phone, true)
+
+  -- don't set date if date is set to `false`
+  if meta.date == nil or meta.date == true then
+    if meta['date-format'] then
+      set_koma_var('date', os.date(stringify(date_format)))
+    else
+      set_koma_var('date', pandoc.MetaInlines{pandoc.RawInline('latex', '\\today')})
+    end
+  elseif meta.date then
+    set_koma_var('date', meta.date)
+  end
+
+  if meta['KOMAoptions'] or #set_vars >= 1 then
+    res[#res + 1] = latex_command(
+      'KOMAoptions',
+      meta['KOMAoptions']
+        or table.concat(set_vars, '=true,') .. '=true'
+    )
+  end
+
+  return res
+end
+
+--- Bring Metadata in a form suitable for the scrlttr KOMA class
+local function make_koma_metadata(meta)
+  local header_includes = ensure_meta_list(meta['header-includes'])
+  List.extend(header_includes, setkomavar_commands(meta))
+
+  local include_before = ensure_meta_list(meta['include-before'])
+  List.extend(
+    include_before,
+    {
+      pandoc.MetaInlines(
+        latex_command(
+          'begin',
+          'letter',
+          ensure_inlines(meta.address or default.address)
+        )
+      ),
+
+      pandoc.MetaInlines(
+        latex_command('opening', meta.opening or default.opening)
+      ),
+    }
+  )
+
+  local include_after = ensure_meta_list(meta['include-after'])
+  List.extend(
+    include_after,
+    {
+      pandoc.MetaInlines(
+        latex_command('closing', meta.closing or default.closing)
+      ),
+      pandoc.MetaInlines(latex_command('end', 'letter')),
+    }
+  )
+
+  -- unset or reset some unwanted vars
+  meta.data   = nil  -- set via komavar 'date'
+  meta.title  = nil  -- set via komavar 'subject'
+  meta.indent = true -- disable parskib
+  -- set documentclass to scrlttr2 if it's unset
+  meta.documentclass = meta.documentclass or pandoc.MetaString'scrlttr2'
+
+
+  meta['header-includes'] = header_includes
+  meta['include-before'] = include_before
+  meta['include-after'] = include_after
+
+  return meta
+end
+
+return {
+  {Meta = make_koma_metadata}
+}

+ 47 - 0
example/assets/pandoc-scholar/lua-filters/section-refs/README.md

@@ -0,0 +1,47 @@
+# section-refs
+
+This filter allows the user to put bibliographies at the end of
+each section, containing only those references in the section. It
+works by splitting the document up into sections, and then
+treating each section as a separate document for pandoc-citeproc
+to process.
+
+## Usage
+
+This filter interferes with the default operation of
+pandoc-citeproc. The `pandoc-citeproc` filter must either be run
+*before* this filter, or not at all. The `section-refs.lua`
+filter calls `pandoc-citeproc` as necessary. For example:
+
+    pandoc input.md -F pandoc-citeproc --lua-filter section-refs.lua
+
+or
+
+    pandoc input.md --lua-filter section-refs.lua
+
+### Configuration
+
+The filter allows customization through these metadata fields:
+
+`section-refs-level`
+:   This variable controls what level the biblography will occur
+    at the end of. The header of the generated references section
+    will be one level lower than the section that it appears on
+    (so if it occurs at the end of a level-1 section, it will
+    receive a level-2 header, and so on).
+
+`section-refs-bibliography`
+:   Behaves like `bibliography` in the context of this filter.
+    This variable exists because pandoc automatically invokes
+    `pandoc-citeproc` as the final filter if it is called with
+    either `--bibliography`, or if the `bibliography` metadata is
+    given via a command line option. Using
+    `section-refs-bibliography` on the command line avoids this
+    unwanted invocation.
+
+## Dependencies
+
+This filter requires
+
+  * pandoc version 2.8 or later, and
+  * pandoc-citeproc version 0.14.5 or later.

+ 137 - 0
example/assets/pandoc-scholar/lua-filters/section-refs/section-refs.lua

@@ -0,0 +1,137 @@
+-- pandoc.utils.make_sections exists since pandoc 2.8
+if PANDOC_VERSION == nil then -- if pandoc_version < 2.1
+  error("ERROR: pandoc >= 2.1 required for section-refs filter")
+else
+  PANDOC_VERSION:must_be_at_least {2,8}
+end
+
+local utils = require 'pandoc.utils'
+local run_json_filter = utils.run_json_filter
+
+--- The document's metadata
+local meta
+-- Lowest level at which bibliographies should be generated.
+local section_refs_level
+-- original bibliography value
+local orig_bibliography
+
+-- Returns true iff a div is a section div.
+local function is_section_div (div)
+  return div.t == 'Div'
+    and div.classes[1] == 'section'
+    and div.attributes.number
+end
+
+local function section_header (div)
+  local header = div.content and div.content[1]
+  local is_header = is_section_div(div)
+    and header
+    and header.t == 'Header'
+  return is_header and header or nil
+end
+
+local function adjust_refs_components (div)
+  local header = section_header(div)
+  if not header then
+    return div
+  end
+  local blocks = div.content
+  local bib_header = blocks:find_if(function (b)
+      return b.identifier == 'bibliography'
+  end)
+  local refs = blocks:find_if(function (b)
+      return b.identifier == 'refs'
+  end)
+  if bib_header then
+    bib_header.identifier = 'bibliography-' .. header.attributes.number
+    bib_header.level = header.level + 1
+  end
+  if refs and refs.identifier == 'refs' then
+    refs.identifier = 'refs-' .. header.attributes.number
+  end
+  return div
+end
+
+--- Create a bibliography for a given topic. This acts on all
+-- section divs at or above `section_refs_level`
+local function create_section_bibliography (div)
+  -- don't do anything if there is no bibliography
+  if not meta.bibliography and not meta.references then
+    return nil
+  end
+  local header = section_header(div)
+  -- Blocks for which a bibliography will be generated
+  local subsections
+  local blocks
+  if not header or section_refs_level < header.level then
+    -- Don't do anything for lower level sections.
+    return nil
+  elseif section_refs_level == header.level then
+    blocks = div.content
+    subsections = pandoc.List:new{}
+  else
+    blocks = div.content:filter(function (b)
+        return not is_section_div(b)
+    end)
+    subsections = div.content:filter(is_section_div)
+  end
+  local tmp_doc = pandoc.Pandoc(blocks, meta)
+  local filter_args = {FORMAT, '-q'} -- keep pandoc-citeproc quiet
+  local new_doc = run_json_filter(tmp_doc, 'pandoc-citeproc', filter_args)
+  div.content = new_doc.blocks .. subsections
+  return adjust_refs_components(div)
+end
+
+--- Remove remaining section divs
+local function flatten_sections (div)
+  local header = section_header(div)
+  if not header then
+    return nil
+  else
+    header.identifier = div.identifier
+    header.attributes.number = nil
+    div.content[1] = header
+    return div.content
+  end
+end
+
+--- Filter to the references div and bibliography header added by
+--- pandoc-citeproc.
+local remove_pandoc_citeproc_results = {
+  Header = function (header)
+    return header.identifier == 'bibliography'
+      and {}
+      or nil
+  end,
+  Div = function (div)
+    return div.identifier == 'refs'
+      and {}
+      or nil
+  end
+}
+
+local function restore_bibliography (meta)
+  meta.bibliography = orig_bibliography
+  return meta
+end
+
+--- Setup the document for further processing by wrapping all
+--- sections in Div elements.
+function setup_document (doc)
+  -- save meta for other filter functions
+  meta = doc.meta
+  section_refs_level = tonumber(meta["section-refs-level"]) or 1
+  orig_bibliography = meta.bibliography
+  meta.bibliography = meta['section-refs-bibliography'] or meta.bibliography
+  local sections = utils.make_sections(true, nil, doc.blocks)
+  return pandoc.Pandoc(sections, doc.meta)
+end
+
+return {
+  -- remove result of previous pandoc-citeproc run (for backwards
+  -- compatibility)
+  remove_pandoc_citeproc_results,
+  {Pandoc = setup_document},
+  {Div = create_section_bibliography},
+  {Div = flatten_sections, Meta = restore_bibliography}
+}

+ 52 - 0
example/assets/pandoc-scholar/lua-filters/short-captions/README.md

@@ -0,0 +1,52 @@
+---
+title: "short-captions.lua"
+lof: true
+---
+
+# Short captions in \LaTeX\ output
+
+For latex output, this filter uses the attribute `short-caption` for
+figures so that the attribute value appears in the List of Figures, if
+one is desired.
+
+# Usage
+
+Where you would have a figure in, say, markdown as 
+
+    ![The caption](foo.png ) 
+
+You can now specify the figure as 
+
+    ![The long caption](foo.png){short-caption="a short caption"} 
+
+If the document metadata includes `lof:true`, then the List of Figures
+will use the short caption. This is particularly useful for students
+writing dissertations, who often have to include a List of Figures in
+the front matter, but where figure captions themselves can be quite
+lengthy.
+
+    pandoc --lua-filter=short-captions.lua article.md -o article.tex
+
+    pandoc --lua-filter=short-captions.lua article.md -o article.pdf
+    
+
+
+# Example
+
+@Fig:shortcap is an interesting figure with a long caption, but a short
+caption in the List of Figures.
+
+![This is an *extremely* interesting figure that has a lot of detail I
+will need to describe in a few sentences. This figure has a short
+caption that will appear in the list of figures. Other attributes are
+preserved](fig.pdf){#fig:shortcap short-caption="A short caption with
+math $x^n + y^n = z^n$" width="50%"}
+
+
+# Limitations
+
+- The filter will process the `short-caption` attribute value as pandoc
+  markdown, regardless of the input format.
+- It does not work for tables and listings yet.
+- But it works with pandoc-crossref, regardless of the order of
+  application.

+ 37 - 0
example/assets/pandoc-scholar/lua-filters/short-captions/short-captions.lua

@@ -0,0 +1,37 @@
+if FORMAT ~= "latex" then
+  return
+end
+
+local function latex(str)
+  return pandoc.RawInline('latex', str)
+end
+
+function figure_image (elem)
+  local image = elem.content and elem.content[1]
+  return (image.t == 'Image' and image.title == 'fig:')
+    and image
+    or nil
+end
+
+function Para (para)
+  local img = figure_image(para)
+  if not img or not img.caption or not img.attributes['short-caption'] then
+    return nil
+  end
+
+  local short_caption = pandoc.Span(
+    pandoc.read(img.attributes['short-caption']).blocks[1].c
+  )
+  local hypertarget = "{%%\n"
+  local label = "\n"
+  if img.identifier ~= img.title then
+    hypertarget = string.format("\\hypertarget{%s}{%%\n",img.identifier)
+    label = string.format("\n\\label{%s}",img.identifier)
+  end
+  return pandoc.Para {
+    latex(hypertarget .. "\\begin{figure}\n\\centering\n"),
+    img,
+    latex("\n\\caption["), short_caption, latex("]"), pandoc.Span(img.caption),
+    latex(label .."\n\\end{figure}\n}\n")
+  }
+end

+ 42 - 0
example/assets/pandoc-scholar/lua-filters/spellcheck/README.md

@@ -0,0 +1,42 @@
+# spellcheck
+
+This filter checks the spelling of words in the body of the
+document (omitting metadata).  The external program `aspell` is
+used for the checking, and must be present in the path.
+
+Why use this instead of just running `aspell` on the
+document's source?  Because this filter is sensitive to
+the semantics of the document in ways that `aspell` is
+not:
+
+- Material in code spans, raw HTML, URLs in links,
+  and math is not spell-checked, eliminating a big
+  class of false positives.
+
+- The filter is sensitive to the `lang` specified in
+  the document's metadata; this will be treated as the
+  default language for the document.
+
+- It is also sensitive to `lang` attributes on native
+  divs and spans. Thus, for example, in an English
+  document, `[chevaux]{lang=fr}` will not be registered
+  as a spelling error.
+
+To run it,
+
+    pandoc --lua-filter spellcheck.lua sample.md
+
+A list of misspelled words (or at any rate, words not
+in the appropriate dictionary) will be printed to stdout.
+If the word is in a div or span with a non-default `lang`
+attribute, the relevant language will be indicated in
+brackets after the word, separated by a tab.
+
+To add words to the list for a language, you can add files
+with names `.aspell.LANG.pws` in your home directory.  Example:
+
+```
+% cat ~/.aspell.en.pws
+personal_ws-1.1 en 0
+goopy
+```

+ 70 - 0
example/assets/pandoc-scholar/lua-filters/spellcheck/spellcheck.lua

@@ -0,0 +1,70 @@
+-- lua filter for spell checking: requires 'aspell'.
+-- Copyright (C) 2017-2020 John MacFarlane, released under MIT license
+
+local text = require('text')
+local words = {}
+local deflang
+
+local function add_to_dict(lang, t)
+  if not words[lang] then
+    words[lang] = {}
+  end
+  if not words[lang][t] then
+    words[lang][t] = (words[lang][t] or 0) + 1
+  end
+end
+
+local function get_deflang(meta)
+  deflang = (meta.lang and meta.lang[1] and meta.lang[1].c) or 'en'
+  -- the following is better but won't work in pandoc 2.0.6.
+  -- it requires pandoc commit ecc46e229fde934f163d1f646383d24bfe2039e1:
+  -- deflang = (meta.lang and pandoc.utils.stringify(meta.lang)) or 'en'
+  return {} -- eliminate meta so it doesn't get spellchecked
+end
+
+local function run_spellcheck(lang)
+  local keys = {}
+  local wordlist = words[lang]
+  for k,_ in pairs(wordlist) do
+    keys[#keys + 1] = k
+  end
+  local inp = table.concat(keys, '\n')
+  local outp = pandoc.pipe('aspell', {'list','-l',lang}, inp)
+  for w in string.gmatch(outp, "([%S]+)\n") do
+    io.write(w)
+    if lang ~= deflang then
+      io.write("\t[" .. lang .. "]")
+    end
+    io.write("\n")
+  end
+end
+
+local function results(el)
+    pandoc.walk_block(pandoc.Div(el.blocks), {Str = function(e) add_to_dict(deflang, e.text) end})
+    for lang,v in pairs(words) do
+        run_spellcheck(lang)
+    end
+    os.exit(0)
+end
+
+local function checkstr(el)
+  add_to_dict(deflang, el.text)
+end
+
+local function checkspan(el)
+  local lang = el.attributes.lang
+  if not lang then return nil end
+  pandoc.walk_inline(el, {Str = function(e) add_to_dict(lang, e.text) end})
+  return {} -- remove span, so it doesn't get checked again
+end
+
+local function checkdiv(el)
+  local lang = el.attributes.lang
+  if not lang then return nil end
+  pandoc.walk_block(el, {Str = function(e) add_to_dict(lang, e.text) end})
+  return {} -- remove div, so it doesn't get checked again
+end
+
+return {{Meta = get_deflang},
+        {Div = checkdiv, Span = checkspan},
+        {Str = function(e) add_to_dict(deflang, e.text) end, Pandoc = results}}

+ 66 - 0
example/assets/pandoc-scholar/lua-filters/table-short-captions/README.md

@@ -0,0 +1,66 @@
+---
+title: "table-short-captions.lua"
+---
+
+# Short captions in \LaTeX\ tables output
+
+For LaTeX output, this filter enables use of the attribute
+`short-caption` for tables. The attribute value will appear in the List
+of Tables.
+
+This filter also enables the class `.unlisted` for tables. This will
+prevent the table caption from appearing in the List of Tables.
+
+# Usage
+
+In Pandoc Markdown, you can add a caption to a table with
+
+    Table: This is the *italicised long caption* of my table, which has
+    a very long caption.
+
+If the document metadata includes `lot:true`, then the List of Tables
+will be inserted at the beginning of the document.
+
+The [pandoc-crossref](http://lierdakil.github.io/pandoc-crossref/)
+filter extends this, and enables you to specify a custom label for the
+table.
+
+    Table: This is the *italicised long caption* of my table, which has
+    a very long caption.  {#tbl:full-of-juicy-data}
+
+This filter, when run _before_ pandoc-crossref, allows you to add short
+captions to the table as a `short-caption` attribute. What is between
+the quotes will be parsed as Markdown.
+
+**Important!:** You _must_ use empty square brackets before the
+attributes tag.
+
+    Table: This is the *italicised long caption* of my table, which has
+    a very long caption.
+    []{#tbl:full-of-juicy-data short-caption="Short caption for *juicy* data table."}
+
+Alternatively, if you wish to create a table which is unlisted in the
+List of Tables, you can use the `.unlisted` class in the attributes tag.
+
+    Table: This is the *italicised long caption* of my table, which will
+    not appear in the List of Tables. []{#tbl:full-of-juicy-data .unlisted}
+
+This filter should prove useful for students writing dissertations, who
+often have to include a List of Tables in the front matter, but where
+table captions themselves can be quite lengthy.
+
+    pandoc --lua-filter=table-short-captions.lua \
+           --filter pandoc-crossref \
+           article.md -o article.tex
+
+    pandoc --lua-filter=table-short-captions.lua \
+           --filter pandoc-crossref \
+           article.md -o article.pdf
+
+
+# Limitations
+
+- The filter will process the `short-caption` attribute value as pandoc
+  markdown, regardless of the input format.
+- pandoc-crossref should be run after it.
+- I have only tested this from a Markdown source.

+ 160 - 0
example/assets/pandoc-scholar/lua-filters/table-short-captions/table-short-captions.lua

@@ -0,0 +1,160 @@
+---LaTeXTableShortCapts – enable `.unlisted` and `short-caption=""` properties
+--                        for Pandoc conversion to LaTeX
+
+--[[
+Copyright (c) 2019 Blake Riley
+
+Permission to use, copy, modify, and/or distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright notice
+and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+]]
+local List = require 'pandoc.List'
+
+-- don't do anything unless we target latex
+if FORMAT ~= "latex" then
+  return {}
+end
+
+--- Code for injection into the LaTeX header,
+--  to overwrite a macro in longtable captions.
+longtable_caption_mod = [[
+% -- begin:latex-table-short-captions --
+\makeatletter\AtBeginDocument{%
+\def\LT@c@ption#1[#2]#3{%                 % Overwrite the workhorse macro used in formatting a longtable caption.
+  \LT@makecaption#1\fnum@table{#3}%
+  \@ifundefined{pandoctableshortcapt}
+     {\def\@tempa{#2}}                    % Use default behaviour: argument in square brackets
+     {\let\@tempa\pandoctableshortcapt}   % If defined (even if blank), use to override
+  \ifx\@tempa\@empty\else                 % If @tempa is blank, no lot entry! Otherwise, @tempa becomes the lot title.
+     {\let\\\space
+     \addcontentsline{lot}{table}{\protect\numberline{\thetable}{\@tempa}}}%
+  \fi}
+}\makeatother
+% -- end:latex-table-short-captions --
+]]
+
+--- Creates a def shortcaption block to be placed before the table
+-- @tparam ?string sc : The short-caption property value
+-- @treturn Plain : The def shortcaption block
+local function defshortcapt(sc)
+  local scblock = List:new{}
+  scblock:extend {pandoc.RawInline('tex', "\\def\\pandoctableshortcapt{")}
+  if sc then
+    scblock:extend (pandoc.read(sc).blocks[1].c)
+  end
+  scblock:extend {pandoc.RawInline('tex', "}")}
+  if not sc then
+    scblock:extend {pandoc.RawInline('tex', "  % .unlisted")}
+  end
+  return pandoc.Plain(scblock)
+end
+
+--- The undef shortcaption block to be placed after the table
+local undefshortcapt = pandoc.RawBlock('tex', "\\let\\pandoctableshortcapt\\relax")
+
+--- Parses a mock "Table Attr".
+-- We use the Attr of an empty Span as if it were Table Attr.
+-- This function extracts what is needed to build a short-caption.
+-- @tparam Attr attr : The Attr of the property Span in the table caption
+-- @treturn ?string : The identifier
+-- @treturn ?string : The "short-caption" property, if present.
+-- @treturn bool : Whether ".unlisted" appeared in the classes
+local function parse_table_attrs(attr)
+  -- Find label
+  local label = nil
+  if attr.identifier and (#attr.identifier > 0) then
+    label = attr.identifier
+  end
+
+  -- Look for ".unlisted" in classes
+  local unlisted = false
+  if attr.classes:includes("unlisted") then
+    unlisted = true
+  end
+
+  -- If not unlisted, then find the property short-caption.
+  local short_caption = nil
+  if not unlisted then
+    if (attr.attributes["short-caption"]) and
+       (#attr.attributes["short-caption"] > 0) then
+      short_caption = attr.attributes['short-caption']
+    end
+  end
+
+  return label, short_caption, unlisted
+end
+
+--- Wraps a table with shortcaption code
+-- @tparam Table tbl : The table with {}-wrapped properties in the caption
+-- @treturn List[Blocks] : The table with {label} in the caption,
+--                         optionally wrapped in shortcaption code
+function rewrite_longtable_caption(tbl)
+  -- Escape if there is no caption present.
+  if not tbl.caption then
+    return nil
+  end
+
+  -- Try find the properties block
+  local is_properties_span = function (inl)
+    return (inl.t) and (inl.t == "Span")                      -- is span
+                   and (inl.content) and (#inl.content == 0)  -- is empty span
+  end
+  local propspan, idx = tbl.caption:find_if(is_properties_span)
+
+  -- If we couldn't find properties, escape.
+  if not propspan then
+    return nil
+  end
+
+  -- Otherwise, parse it all
+  local label, short_caption, unlisted = parse_table_attrs(propspan.attr)
+
+  -- Excise the span from the caption
+  tbl.caption[idx] = nil
+
+  -- Put label back into caption for pandoc-crossref
+  if label then
+    tbl.caption:extend {pandoc.Str("{#"..label.."}")}
+  end
+
+  -- Place new table
+  local result = List:new{}
+  if short_caption or unlisted then
+    result:extend {defshortcapt(short_caption)}
+  end
+  result:extend {tbl}
+  if short_caption or unlisted then
+    result:extend {undefshortcapt}
+  end
+  return result
+end
+
+--- Inserts longtable_caption_mod into the header_includes
+-- @tparam Meta meta : The document metadata
+-- @treturn Meta : The document metadata, with replacement LaTeX macro
+--                 in header_includes
+function add_longtable_caption_mod(meta)
+  local header_includes = -- test ? a : b
+    (meta['header-includes'] and meta['header-includes'].t == 'MetaList')
+    and meta['header-includes']
+    or pandoc.MetaList{meta['header-includes']}
+  header_includes[#header_includes + 1] =
+    pandoc.MetaBlocks{pandoc.RawBlock('tex', longtable_caption_mod)}
+  meta['header-includes'] = header_includes
+  return meta
+end
+
+return {
+  {
+    Meta = add_longtable_caption_mod,
+    Table = rewrite_longtable_caption,
+  }
+}

+ 18 - 0
example/assets/pandoc-scholar/lua-filters/track-changes/README.md

@@ -0,0 +1,18 @@
+# Tracks changes in LaTeX and HTML or removes them in other output formats
+
+The Pandoc Docx reader and writer supports track changes of MS Word
+(command line parameter `--track-changes=accept|reject|all`).
+
+If `--track-changes=all` was used to read a docx file, track changes
+and/or comments are included in the AST as spans and are written to any
+other output formats than docx and clutters the output.
+
+This Lua filter addresses this problem by interpreting the parameter
+`--track-changes` (pandoc version >= 2.1.1) or the metadata variable
+`trackChanges: accept|reject|all` (set either in a YAML block or with
+`-M`) and accepts/rejects changes and removes comments for all output
+formats including docx. In case of `--track-changes=all` and for html
+and latex, it converts track changings and comments to appropriate
+commands (for LaTex provided by the [changes
+package](https://ctan.org/pkg/changes)) and tries to mimic the
+visualization as in MS Word.

+ 247 - 0
example/assets/pandoc-scholar/lua-filters/track-changes/track-changes.lua

@@ -0,0 +1,247 @@
+local authors = {}
+
+local function is_tex(format)
+    return format == 'latex' or format == 'tex' or format == 'context'
+end
+
+local function is_html (format)
+    return format == 'html' or format == 'html4' or format == 'html5'
+end
+
+local function is_wordprocessing (format)
+    return format == 'docx' or format == 'odt'
+end
+
+header_track_changes = [[
+
+\makeatletter
+\PassOptionsToPackage{textsize=scriptsize}{todonotes}
+\PassOptionsToPackage{markup=underlined,authormarkup=none,commentmarkup=todo}{changes}
+\usepackage{changes}
+\@ifpackagelater{changes}{2018/11/03}{%
+}{%
+  \usepackage{todonotes}
+  \setremarkmarkup{\todo[color=Changes@Color#1!20]{\sffamily\textbf{#1:}~#2}}
+}%
+\makeatother
+\definecolor{auth1}{HTML}{4477AA}
+\definecolor{auth2}{HTML}{117733}
+\definecolor{auth3}{HTML}{999933}
+\definecolor{auth4}{HTML}{CC6677}
+\definecolor{auth5}{HTML}{AA4499}
+\definecolor{auth6}{HTML}{332288}
+\setlength{\marginparwidth}{3cm}
+\newcommand{\note}[2][]{\added[#1,remark={#2}]{}}
+\newcommand\hlnotesingle{%
+  \bgroup
+  \expandafter\def\csname sout\space\endcsname{\bgroup \ULdepth =-.8ex \ULset}%
+  \markoverwith{\textcolor{yellow}{\rule[-.5ex]{.1pt}{2.5ex}}}%
+  \ULon}
+\newcommand\hlnote[1]{\let\helpcmd\hlnotesingle\parhelp#1\par\relax\relax}
+\long\def\parhelp#1\par#2\relax{%
+  \helpcmd{#1}\ifx\relax#2\else\par\parhelp#2\relax\fi%
+}
+
+\makeatletter
+\newcommand\ifmoving{%
+  \ifx\protect\@unexpandable@protect
+      \expandafter\@firstoftwo
+  \else
+      \expandafter\@secondoftwo
+  \fi
+}
+
+\newcommand{\gobbletwo}[2][]{\@bsphack\@esphack}
+\newcommand{\gobbleone}[1][]{\@bsphack\@esphack}
+
+\let\oldadded\added
+\let\olddeleted\deleted
+\let\oldhlnote\hlnote
+\let\oldnote\note
+\renewcommand{\added}{\ifmoving{\gobbleone}{\oldadded}}
+\renewcommand{\deleted}{\ifmoving{\gobbletwo}{\olddeleted}}
+\renewcommand{\hlnote}{\ifmoving{}{\oldhlnote}}
+\renewcommand{\note}{\ifmoving{\gobbletwo}{\oldnote}}
+\makeatother
+]]
+
+local function initials(s)
+    local ignore = { -- list of words to ignore
+        ['dr'] = true, ['mr'] = true, ['ms'] = true, ['mrs'] = true, ['prof'] = true,
+        ['mx'] = true, ['sir'] = true,
+    }
+
+    local ans = {}
+    for w in s:gmatch '[%w\']+' do
+        if not ignore[w:lower()] then ans[#ans+1] = w:sub(1,1):upper() end
+    end
+    return table.concat(ans)
+end
+
+relinerHtml = {
+    Str = function (s)
+        if s.text == "¶" then
+            return pandoc.Str('&#10;')
+        end
+    end
+}
+
+relinerTex = {
+    Str = function (s)
+        if s.text == "¶" then
+            return pandoc.Str('\\newline')
+        end
+    end
+}
+
+reliner = {
+    Str = function (s)
+        if s.text == "¶" then
+           return pandoc.LineBreak()
+        end
+    end
+}
+
+function SpanReliner(elem)
+    local classes = elem.classes or elem.attr.classes
+    if classes:includes("comment-start") then
+        return pandoc.walk_inline(elem, reliner)
+    end
+end
+
+local toTex = {["comment-start"] = "\\note", insertion = "\\added", deletion = "\\deleted"}
+
+local function TrackingSpanToTex(elem)
+    if toTex[elem.classes[1]] ~= nil then
+        local author = elem.attributes.author
+        local inits = author:find' ' and initials(author) or author
+        authors[inits] = author
+        local s = toTex[elem.classes[1]] .. '[id=' .. inits .. ']{'
+        if elem.classes:includes("comment-start") then
+            s = s .. pandoc.utils.stringify(pandoc.walk_inline(elem, relinerTex)) .. '}\\hlnote{'
+        else
+            s = s .. pandoc.utils.stringify(elem.content) .. '}'
+        end
+        return pandoc.RawInline('latex', s)
+    elseif elem.classes:includes("comment-end") then
+        return pandoc.RawInline('latex', '}')
+    end
+end
+
+local function pairsByKeys(t, f)
+    local a = {}
+    for n in pairs(t) do table.insert(a, n) end
+    table.sort(a, f)
+    local i = 0
+    local iter = function ()
+      i = i + 1
+      return a[i], t[a[i]]
+    end
+    return iter
+end
+
+--- Add packages to the header includes.
+local function add_track_changes(meta)
+    local header_includes
+    if meta['header-includes'] and meta['header-includes'].t == 'MetaList' then
+        header_includes = meta['header-includes']
+    else
+        header_includes = pandoc.MetaList{meta['header-includes']}
+    end
+    header_includes[#header_includes + 1] =
+        pandoc.MetaBlocks{pandoc.RawBlock('latex', header_track_changes)}
+    local a = 1
+    for key,value in pairsByKeys(authors) do -- sorted author list; otherwise make test may fail
+        header_includes[#header_includes + 1] =
+            pandoc.MetaBlocks{pandoc.RawBlock('latex', '\\definechangesauthor[name={' .. value .. '}, color=auth' .. a .. ']{' .. key .. '}')}
+        a = a + 1
+    end
+    meta['header-includes'] = header_includes
+    return meta
+end
+
+local toHtml = {["comment-start"] = "mark", insertion = "ins", deletion = "del"}
+
+local function TrackingSpanToHtml(elem)
+    if toHtml[elem.classes[1]] ~= nil then
+        local author = elem.attributes.author
+        local inits = author:find' ' and initials(author) or author
+        authors[inits] = author
+        local s = '<' .. toHtml[elem.classes[1]]
+        for k,v in pairs(elem.attributes) do
+            local hattr = k
+            if hattr ~= 'date' then hattr = 'data-' .. hattr end
+            s = s .. ' ' .. hattr .. '="' .. v .. '"'
+        end
+        if elem.classes:includes("comment-start") then
+            if elem.identifier then
+                s = s .. ' data-id="' .. elem.identifier .. '"'
+            end
+            s = s .. ' title="' .. pandoc.utils.stringify(pandoc.walk_inline(elem, relinerHtml)) .. '">'
+        else
+            s = s .. '>' .. pandoc.utils.stringify(elem.content) .. '</' .. toHtml[elem.classes[1]] .. '>'
+        end
+        return pandoc.RawInline('html', s)
+    elseif elem.classes:includes("comment-end") then
+        return pandoc.RawInline('html', '</mark>')
+    end
+end
+
+local function SpanAcceptChanges(elem)
+    if elem.classes:includes("comment-start") or elem.classes:includes("comment-end") then
+        return {}
+    elseif elem.classes:includes("insertion") then
+        return elem.content
+    elseif elem.classes:includes("deletion") then
+        return {}
+    end
+end
+
+local function SpanRejectChanges(elem)
+    if elem.classes:includes("comment-start") or elem.classes:includes("comment-end") then
+        return {}
+    elseif elem.classes:includes("insertion") then
+        return {}
+    elseif elem.classes:includes("deletion") then
+        return elem.content
+    end
+end
+
+function Pandoc(doc)
+    local meta = doc.meta
+    local trackChangesOptions = {all = 'AllChanges', accept = 'AcceptChanges', reject = 'RejectChanges' }
+    local tc = meta and meta['trackChanges']
+    tc = type(meta['trackChanges']) == 'table' and pandoc.utils.stringify(meta['trackChanges']) or meta['trackChanges'] or 'accept'
+    local trackChanges = PANDOC_READER_OPTIONS and PANDOC_READER_OPTIONS.trackChanges or trackChangesOptions[tc]
+    meta.trackChanges = nil -- remove it from the matadata
+    
+    local M = {}
+    if trackChanges == 'AllChanges' then
+        if is_html(FORMAT) then
+            M[#M + 1] = {
+                Span = TrackingSpanToHtml
+            }
+        elseif is_tex(FORMAT) then
+            M[#M + 1] = {
+                Span = TrackingSpanToTex,
+            }
+        elseif is_wordprocessing(FORMAT) then
+            M[#M + 1] = { Span = SpanReliner }
+        end
+    elseif trackChanges == 'RejectChanges' then
+        M[#M + 1] = { Span = SpanRejectChanges }
+    else -- otherwise assumes AcceptChanges
+        M[#M + 1] = { Span = SpanAcceptChanges }
+    end
+
+    if #M then
+        local blocks = doc.blocks
+        for i = 1, #M do
+            blocks = pandoc.walk_block(pandoc.Div(blocks), M[i]).content
+        end
+        if trackChanges == 'AllChanges' and is_tex(FORMAT) then
+            meta = add_track_changes(meta)
+        end
+        return pandoc.Pandoc(blocks, meta)
+    end
+end

+ 11 - 0
example/assets/pandoc-scholar/lua-filters/wordcount/README.md

@@ -0,0 +1,11 @@
+# wordcount
+
+This filter counts the words in the body of a document (omitting
+metadata like titles and abstracts), including words in code.
+It should be more accurate than `wc -w` run directly on a
+Markdown document, since the latter will count markup
+characters, like the `#` in front of an ATX header, or
+tags in HTML documents, as words.
+
+To run it, `pandoc --lua-filter wordcount.lua myfile.md`.
+The word count will be printed to stdout.

+ 29 - 0
example/assets/pandoc-scholar/lua-filters/wordcount/wordcount.lua

@@ -0,0 +1,29 @@
+-- counts words in a document 
+
+words = 0 
+
+wordcount = { 
+  Str = function(el) 
+    -- we don't count a word if it's entirely punctuation: 
+    if el.text:match("%P") then 
+        words = words + 1 
+    end 
+  end, 
+
+  Code = function(el) 
+    _,n = el.text:gsub("%S+","") 
+    words = words + n 
+  end, 
+
+  CodeBlock = function(el) 
+    _,n = el.text:gsub("%S+","") 
+    words = words + n 
+  end 
+} 
+
+function Pandoc(el) 
+    -- skip metadata, just count body: 
+    pandoc.walk_block(pandoc.Div(el.blocks), wordcount) 
+    print(words .. " words in body") 
+    os.exit(0) 
+end

+ 50 - 0
example/assets/pandoc-scholar/pandoc-options.inc.mk

@@ -0,0 +1,50 @@
+# Settings for Pandoc
+# ===================
+
+TEMPLATE_FILE_LATEX   ?= $(PANDOC_SCHOLAR_PATH)/templates/pandoc-scholar.latex
+TEMPLATE_FILE_HTML    ?= $(PANDOC_SCHOLAR_PATH)/templates/pandoc-scholar.html
+TEMPLATE_FILE_JATS    ?= $(PANDOC_SCHOLAR_PATH)/templates/pandoc-scholar.jats
+
+TEMPLATE_STYLE_HTML   ?= $(PANDOC_SCHOLAR_PATH)/templates/styles/pandoc-scholar.css
+
+## Pandoc options
+PANDOC_READER_OPTIONS ?=
+ifdef BIBLIOGRAPHY_FILE
+PANDOC_READER_OPTIONS += --metadata "bibliography:$(BIBLIOGRAPHY_FILE)"
+endif
+
+ifndef PANDOC_WRITER_OPTIONS
+PANDOC_WRITER_OPTIONS  = --standalone
+PANDOC_WRITER_OPTIONS += --citeproc
+ifdef BIBLIOGRAPHY_FILE
+PANDOC_WRITER_OPTIONS += --metadata "bibliography:$(BIBLIOGRAPHY_FILE)"
+PANDOC_WRITER_OPTIONS += --bibliography=$(BIBLIOGRAPHY_FILE)
+endif
+endif
+
+PANDOC_ODT_OPTIONS    ?=
+PANDOC_DOCX_OPTIONS   ?=
+PANDOC_HTML_OPTIONS   ?=
+PANDOC_EPUB_OPTIONS   ?=
+ifndef PANDOC_LATEX_OPTIONS
+PANDOC_LATEX_OPTIONS   = --pdf-engine=xelatex
+endif
+
+ifdef ODT_REFERENCE_FILE
+PANDOC_ODT_OPTIONS    += --reference-doc=$(ODT_REFERENCE_FILE)
+endif
+ifdef DOCX_REFERENCE_FILE
+PANDOC_DOCX_OPTIONS   += --reference-doc=$(DOCX_REFERENCE_FILE)
+endif
+ifdef TEMPLATE_FILE_LATEX
+PANDOC_LATEX_OPTIONS  += --template=$(TEMPLATE_FILE_LATEX)
+endif
+ifdef TEMPLATE_FILE_HTML
+PANDOC_HTML_OPTIONS   += --template=$(TEMPLATE_FILE_HTML)
+endif
+ifdef TEMPLATE_FILE_EPUB
+PANDOC_EPUB_OPTIONS   += --template=$(TEMPLATE_FILE_EPUB)
+endif
+ifdef TEMPLATE_FILE_JATS
+PANDOC_JATS_OPTIONS   += --template=$(TEMPLATE_FILE_JATS)
+endif

+ 714 - 0
example/assets/pandoc-scholar/scholar-filters/dkjson.lua

@@ -0,0 +1,714 @@
+-- Module options:
+local always_try_using_lpeg = true
+local register_global_module_table = false
+local global_module_name = 'json'
+
+--[==[
+
+David Kolf's JSON module for Lua 5.1/5.2
+
+Version 2.5
+
+
+For the documentation see the corresponding readme.txt or visit
+<http://dkolf.de/src/dkjson-lua.fsl/>.
+
+You can contact the author by sending an e-mail to 'david' at the
+domain 'dkolf.de'.
+
+
+Copyright (C) 2010-2013 David Heiko Kolf
+
+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.
+
+--]==]
+
+-- global dependencies:
+local pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset =
+      pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset
+local error, require, pcall, select = error, require, pcall, select
+local floor, huge = math.floor, math.huge
+local strrep, gsub, strsub, strbyte, strchar, strfind, strlen, strformat =
+      string.rep, string.gsub, string.sub, string.byte, string.char,
+      string.find, string.len, string.format
+local strmatch = string.match
+local concat = table.concat
+
+local json = { version = "dkjson 2.5" }
+
+if register_global_module_table then
+  _G[global_module_name] = json
+end
+
+local _ENV = nil -- blocking globals in Lua 5.2
+
+pcall (function()
+  -- Enable access to blocked metatables.
+  -- Don't worry, this module doesn't change anything in them.
+  local debmeta = require "debug".getmetatable
+  if debmeta then getmetatable = debmeta end
+end)
+
+json.null = setmetatable ({}, {
+  __tojson = function () return "null" end
+})
+
+local function isarray (tbl)
+  local max, n, arraylen = 0, 0, 0
+  for k,v in pairs (tbl) do
+    if k == 'n' and type(v) == 'number' then
+      arraylen = v
+      if v > max then
+        max = v
+      end
+    else
+      if type(k) ~= 'number' or k < 1 or floor(k) ~= k then
+        return false
+      end
+      if k > max then
+        max = k
+      end
+      n = n + 1
+    end
+  end
+  if max > 10 and max > arraylen and max > n * 2 then
+    return false -- don't create an array with too many holes
+  end
+  return true, max
+end
+
+local escapecodes = {
+  ["\""] = "\\\"", ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f",
+  ["\n"] = "\\n",  ["\r"] = "\\r",  ["\t"] = "\\t"
+}
+
+local function escapeutf8 (uchar)
+  local value = escapecodes[uchar]
+  if value then
+    return value
+  end
+  local a, b, c, d = strbyte (uchar, 1, 4)
+  a, b, c, d = a or 0, b or 0, c or 0, d or 0
+  if a <= 0x7f then
+    value = a
+  elseif 0xc0 <= a and a <= 0xdf and b >= 0x80 then
+    value = (a - 0xc0) * 0x40 + b - 0x80
+  elseif 0xe0 <= a and a <= 0xef and b >= 0x80 and c >= 0x80 then
+    value = ((a - 0xe0) * 0x40 + b - 0x80) * 0x40 + c - 0x80
+  elseif 0xf0 <= a and a <= 0xf7 and b >= 0x80 and c >= 0x80 and d >= 0x80 then
+    value = (((a - 0xf0) * 0x40 + b - 0x80) * 0x40 + c - 0x80) * 0x40 + d - 0x80
+  else
+    return ""
+  end
+  if value <= 0xffff then
+    return strformat ("\\u%.4x", value)
+  elseif value <= 0x10ffff then
+    -- encode as UTF-16 surrogate pair
+    value = value - 0x10000
+    local highsur, lowsur = 0xD800 + floor (value/0x400), 0xDC00 + (value % 0x400)
+    return strformat ("\\u%.4x\\u%.4x", highsur, lowsur)
+  else
+    return ""
+  end
+end
+
+local function fsub (str, pattern, repl)
+  -- gsub always builds a new string in a buffer, even when no match
+  -- exists. First using find should be more efficient when most strings
+  -- don't contain the pattern.
+  if strfind (str, pattern) then
+    return gsub (str, pattern, repl)
+  else
+    return str
+  end
+end
+
+local function quotestring (value)
+  -- based on the regexp "escapable" in https://github.com/douglascrockford/JSON-js
+  value = fsub (value, "[%z\1-\31\"\\\127]", escapeutf8)
+  if strfind (value, "[\194\216\220\225\226\239]") then
+    value = fsub (value, "\194[\128-\159\173]", escapeutf8)
+    value = fsub (value, "\216[\128-\132]", escapeutf8)
+    value = fsub (value, "\220\143", escapeutf8)
+    value = fsub (value, "\225\158[\180\181]", escapeutf8)
+    value = fsub (value, "\226\128[\140-\143\168-\175]", escapeutf8)
+    value = fsub (value, "\226\129[\160-\175]", escapeutf8)
+    value = fsub (value, "\239\187\191", escapeutf8)
+    value = fsub (value, "\239\191[\176-\191]", escapeutf8)
+  end
+  return "\"" .. value .. "\""
+end
+json.quotestring = quotestring
+
+local function replace(str, o, n)
+  local i, j = strfind (str, o, 1, true)
+  if i then
+    return strsub(str, 1, i-1) .. n .. strsub(str, j+1, -1)
+  else
+    return str
+  end
+end
+
+-- locale independent num2str and str2num functions
+local decpoint, numfilter
+
+local function updatedecpoint ()
+  decpoint = strmatch(tostring(0.5), "([^05+])")
+  -- build a filter that can be used to remove group separators
+  numfilter = "[^0-9%-%+eE" .. gsub(decpoint, "[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0") .. "]+"
+end
+
+updatedecpoint()
+
+local function num2str (num)
+  return replace(fsub(tostring(num), numfilter, ""), decpoint, ".")
+end
+
+local function str2num (str)
+  local num = tonumber(replace(str, ".", decpoint))
+  if not num then
+    updatedecpoint()
+    num = tonumber(replace(str, ".", decpoint))
+  end
+  return num
+end
+
+local function addnewline2 (level, buffer, buflen)
+  buffer[buflen+1] = "\n"
+  buffer[buflen+2] = strrep ("  ", level)
+  buflen = buflen + 2
+  return buflen
+end
+
+function json.addnewline (state)
+  if state.indent then
+    state.bufferlen = addnewline2 (state.level or 0,
+                           state.buffer, state.bufferlen or #(state.buffer))
+  end
+end
+
+local encode2 -- forward declaration
+
+local function addpair (key, value, prev, indent, level, buffer, buflen, tables, globalorder, state)
+  local kt = type (key)
+  if kt ~= 'string' and kt ~= 'number' then
+    return nil, "type '" .. kt .. "' is not supported as a key by JSON."
+  end
+  if prev then
+    buflen = buflen + 1
+    buffer[buflen] = ","
+  end
+  if indent then
+    buflen = addnewline2 (level, buffer, buflen)
+  end
+  buffer[buflen+1] = quotestring (key)
+  buffer[buflen+2] = ":"
+  return encode2 (value, indent, level, buffer, buflen + 2, tables, globalorder, state)
+end
+
+local function appendcustom(res, buffer, state)
+  local buflen = state.bufferlen
+  if type (res) == 'string' then
+    buflen = buflen + 1
+    buffer[buflen] = res
+  end
+  return buflen
+end
+
+local function exception(reason, value, state, buffer, buflen, defaultmessage)
+  defaultmessage = defaultmessage or reason
+  local handler = state.exception
+  if not handler then
+    return nil, defaultmessage
+  else
+    state.bufferlen = buflen
+    local ret, msg = handler (reason, value, state, defaultmessage)
+    if not ret then return nil, msg or defaultmessage end
+    return appendcustom(ret, buffer, state)
+  end
+end
+
+function json.encodeexception(reason, value, state, defaultmessage)
+  return quotestring("<" .. defaultmessage .. ">")
+end
+
+encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, state)
+  local valtype = type (value)
+  local valmeta = getmetatable (value)
+  valmeta = type (valmeta) == 'table' and valmeta -- only tables
+  local valtojson = valmeta and valmeta.__tojson
+  if valtojson then
+    if tables[value] then
+      return exception('reference cycle', value, state, buffer, buflen)
+    end
+    tables[value] = true
+    state.bufferlen = buflen
+    local ret, msg = valtojson (value, state)
+    if not ret then return exception('custom encoder failed', value, state, buffer, buflen, msg) end
+    tables[value] = nil
+    buflen = appendcustom(ret, buffer, state)
+  elseif value == nil then
+    buflen = buflen + 1
+    buffer[buflen] = "null"
+  elseif valtype == 'number' then
+    local s
+    if value ~= value or value >= huge or -value >= huge then
+      -- This is the behaviour of the original JSON implementation.
+      s = "null"
+    else
+      s = num2str (value)
+    end
+    buflen = buflen + 1
+    buffer[buflen] = s
+  elseif valtype == 'boolean' then
+    buflen = buflen + 1
+    buffer[buflen] = value and "true" or "false"
+  elseif valtype == 'string' then
+    buflen = buflen + 1
+    buffer[buflen] = quotestring (value)
+  elseif valtype == 'table' then
+    if tables[value] then
+      return exception('reference cycle', value, state, buffer, buflen)
+    end
+    tables[value] = true
+    level = level + 1
+    local isa, n = isarray (value)
+    if n == 0 and valmeta and valmeta.__jsontype == 'object' then
+      isa = false
+    end
+    local msg
+    if isa then -- JSON array
+      buflen = buflen + 1
+      buffer[buflen] = "["
+      for i = 1, n do
+        buflen, msg = encode2 (value[i], indent, level, buffer, buflen, tables, globalorder, state)
+        if not buflen then return nil, msg end
+        if i < n then
+          buflen = buflen + 1
+          buffer[buflen] = ","
+        end
+      end
+      buflen = buflen + 1
+      buffer[buflen] = "]"
+    else -- JSON object
+      local prev = false
+      buflen = buflen + 1
+      buffer[buflen] = "{"
+      local order = valmeta and valmeta.__jsonorder or globalorder
+      if order then
+        local used = {}
+        n = #order
+        for i = 1, n do
+          local k = order[i]
+          local v = value[k]
+          if v then
+            used[k] = true
+            buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
+            prev = true -- add a seperator before the next element
+          end
+        end
+        for k,v in pairs (value) do
+          if not used[k] then
+            buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
+            if not buflen then return nil, msg end
+            prev = true -- add a seperator before the next element
+          end
+        end
+      else -- unordered
+        for k,v in pairs (value) do
+          buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
+          if not buflen then return nil, msg end
+          prev = true -- add a seperator before the next element
+        end
+      end
+      if indent then
+        buflen = addnewline2 (level - 1, buffer, buflen)
+      end
+      buflen = buflen + 1
+      buffer[buflen] = "}"
+    end
+    tables[value] = nil
+  else
+    return exception ('unsupported type', value, state, buffer, buflen,
+      "type '" .. valtype .. "' is not supported by JSON.")
+  end
+  return buflen
+end
+
+function json.encode (value, state)
+  state = state or {}
+  local oldbuffer = state.buffer
+  local buffer = oldbuffer or {}
+  state.buffer = buffer
+  updatedecpoint()
+  local ret, msg = encode2 (value, state.indent, state.level or 0,
+                   buffer, state.bufferlen or 0, state.tables or {}, state.keyorder, state)
+  if not ret then
+    error (msg, 2)
+  elseif oldbuffer == buffer then
+    state.bufferlen = ret
+    return true
+  else
+    state.bufferlen = nil
+    state.buffer = nil
+    return concat (buffer)
+  end
+end
+
+local function loc (str, where)
+  local line, pos, linepos = 1, 1, 0
+  while true do
+    pos = strfind (str, "\n", pos, true)
+    if pos and pos < where then
+      line = line + 1
+      linepos = pos
+      pos = pos + 1
+    else
+      break
+    end
+  end
+  return "line " .. line .. ", column " .. (where - linepos)
+end
+
+local function unterminated (str, what, where)
+  return nil, strlen (str) + 1, "unterminated " .. what .. " at " .. loc (str, where)
+end
+
+local function scanwhite (str, pos)
+  while true do
+    pos = strfind (str, "%S", pos)
+    if not pos then return nil end
+    local sub2 = strsub (str, pos, pos + 1)
+    if sub2 == "\239\187" and strsub (str, pos + 2, pos + 2) == "\191" then
+      -- UTF-8 Byte Order Mark
+      pos = pos + 3
+    elseif sub2 == "//" then
+      pos = strfind (str, "[\n\r]", pos + 2)
+      if not pos then return nil end
+    elseif sub2 == "/*" then
+      pos = strfind (str, "*/", pos + 2)
+      if not pos then return nil end
+      pos = pos + 2
+    else
+      return pos
+    end
+  end
+end
+
+local escapechars = {
+  ["\""] = "\"", ["\\"] = "\\", ["/"] = "/", ["b"] = "\b", ["f"] = "\f",
+  ["n"] = "\n", ["r"] = "\r", ["t"] = "\t"
+}
+
+local function unichar (value)
+  if value < 0 then
+    return nil
+  elseif value <= 0x007f then
+    return strchar (value)
+  elseif value <= 0x07ff then
+    return strchar (0xc0 + floor(value/0x40),
+                    0x80 + (floor(value) % 0x40))
+  elseif value <= 0xffff then
+    return strchar (0xe0 + floor(value/0x1000),
+                    0x80 + (floor(value/0x40) % 0x40),
+                    0x80 + (floor(value) % 0x40))
+  elseif value <= 0x10ffff then
+    return strchar (0xf0 + floor(value/0x40000),
+                    0x80 + (floor(value/0x1000) % 0x40),
+                    0x80 + (floor(value/0x40) % 0x40),
+                    0x80 + (floor(value) % 0x40))
+  else
+    return nil
+  end
+end
+
+local function scanstring (str, pos)
+  local lastpos = pos + 1
+  local buffer, n = {}, 0
+  while true do
+    local nextpos = strfind (str, "[\"\\]", lastpos)
+    if not nextpos then
+      return unterminated (str, "string", pos)
+    end
+    if nextpos > lastpos then
+      n = n + 1
+      buffer[n] = strsub (str, lastpos, nextpos - 1)
+    end
+    if strsub (str, nextpos, nextpos) == "\"" then
+      lastpos = nextpos + 1
+      break
+    else
+      local escchar = strsub (str, nextpos + 1, nextpos + 1)
+      local value
+      if escchar == "u" then
+        value = tonumber (strsub (str, nextpos + 2, nextpos + 5), 16)
+        if value then
+          local value2
+          if 0xD800 <= value and value <= 0xDBff then
+            -- we have the high surrogate of UTF-16. Check if there is a
+            -- low surrogate escaped nearby to combine them.
+            if strsub (str, nextpos + 6, nextpos + 7) == "\\u" then
+              value2 = tonumber (strsub (str, nextpos + 8, nextpos + 11), 16)
+              if value2 and 0xDC00 <= value2 and value2 <= 0xDFFF then
+                value = (value - 0xD800)  * 0x400 + (value2 - 0xDC00) + 0x10000
+              else
+                value2 = nil -- in case it was out of range for a low surrogate
+              end
+            end
+          end
+          value = value and unichar (value)
+          if value then
+            if value2 then
+              lastpos = nextpos + 12
+            else
+              lastpos = nextpos + 6
+            end
+          end
+        end
+      end
+      if not value then
+        value = escapechars[escchar] or escchar
+        lastpos = nextpos + 2
+      end
+      n = n + 1
+      buffer[n] = value
+    end
+  end
+  if n == 1 then
+    return buffer[1], lastpos
+  elseif n > 1 then
+    return concat (buffer), lastpos
+  else
+    return "", lastpos
+  end
+end
+
+local scanvalue -- forward declaration
+
+local function scantable (what, closechar, str, startpos, nullval, objectmeta, arraymeta)
+  local len = strlen (str)
+  local tbl, n = {}, 0
+  local pos = startpos + 1
+  if what == 'object' then
+    setmetatable (tbl, objectmeta)
+  else
+    setmetatable (tbl, arraymeta)
+  end
+  while true do
+    pos = scanwhite (str, pos)
+    if not pos then return unterminated (str, what, startpos) end
+    local char = strsub (str, pos, pos)
+    if char == closechar then
+      return tbl, pos + 1
+    end
+    local val1, err
+    val1, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
+    if err then return nil, pos, err end
+    pos = scanwhite (str, pos)
+    if not pos then return unterminated (str, what, startpos) end
+    char = strsub (str, pos, pos)
+    if char == ":" then
+      if val1 == nil then
+        return nil, pos, "cannot use nil as table index (at " .. loc (str, pos) .. ")"
+      end
+      pos = scanwhite (str, pos + 1)
+      if not pos then return unterminated (str, what, startpos) end
+      local val2
+      val2, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
+      if err then return nil, pos, err end
+      tbl[val1] = val2
+      pos = scanwhite (str, pos)
+      if not pos then return unterminated (str, what, startpos) end
+      char = strsub (str, pos, pos)
+    else
+      n = n + 1
+      tbl[n] = val1
+    end
+    if char == "," then
+      pos = pos + 1
+    end
+  end
+end
+
+scanvalue = function (str, pos, nullval, objectmeta, arraymeta)
+  pos = pos or 1
+  pos = scanwhite (str, pos)
+  if not pos then
+    return nil, strlen (str) + 1, "no valid JSON value (reached the end)"
+  end
+  local char = strsub (str, pos, pos)
+  if char == "{" then
+    return scantable ('object', "}", str, pos, nullval, objectmeta, arraymeta)
+  elseif char == "[" then
+    return scantable ('array', "]", str, pos, nullval, objectmeta, arraymeta)
+  elseif char == "\"" then
+    return scanstring (str, pos)
+  else
+    local pstart, pend = strfind (str, "^%-?[%d%.]+[eE]?[%+%-]?%d*", pos)
+    if pstart then
+      local number = str2num (strsub (str, pstart, pend))
+      if number then
+        return number, pend + 1
+      end
+    end
+    pstart, pend = strfind (str, "^%a%w*", pos)
+    if pstart then
+      local name = strsub (str, pstart, pend)
+      if name == "true" then
+        return true, pend + 1
+      elseif name == "false" then
+        return false, pend + 1
+      elseif name == "null" then
+        return nullval, pend + 1
+      end
+    end
+    return nil, pos, "no valid JSON value at " .. loc (str, pos)
+  end
+end
+
+local function optionalmetatables(...)
+  if select("#", ...) > 0 then
+    return ...
+  else
+    return {__jsontype = 'object'}, {__jsontype = 'array'}
+  end
+end
+
+function json.decode (str, pos, nullval, ...)
+  local objectmeta, arraymeta = optionalmetatables(...)
+  return scanvalue (str, pos, nullval, objectmeta, arraymeta)
+end
+
+function json.use_lpeg ()
+  local g = require ("lpeg")
+
+  if g.version() == "0.11" then
+    error "due to a bug in LPeg 0.11, it cannot be used for JSON matching"
+  end
+
+  local pegmatch = g.match
+  local P, S, R = g.P, g.S, g.R
+
+  local function ErrorCall (str, pos, msg, state)
+    if not state.msg then
+      state.msg = msg .. " at " .. loc (str, pos)
+      state.pos = pos
+    end
+    return false
+  end
+
+  local function Err (msg)
+    return g.Cmt (g.Cc (msg) * g.Carg (2), ErrorCall)
+  end
+
+  local SingleLineComment = P"//" * (1 - S"\n\r")^0
+  local MultiLineComment = P"/*" * (1 - P"*/")^0 * P"*/"
+  local Space = (S" \n\r\t" + P"\239\187\191" + SingleLineComment + MultiLineComment)^0
+
+  local PlainChar = 1 - S"\"\\\n\r"
+  local EscapeSequence = (P"\\" * g.C (S"\"\\/bfnrt" + Err "unsupported escape sequence")) / escapechars
+  local HexDigit = R("09", "af", "AF")
+  local function UTF16Surrogate (match, pos, high, low)
+    high, low = tonumber (high, 16), tonumber (low, 16)
+    if 0xD800 <= high and high <= 0xDBff and 0xDC00 <= low and low <= 0xDFFF then
+      return true, unichar ((high - 0xD800)  * 0x400 + (low - 0xDC00) + 0x10000)
+    else
+      return false
+    end
+  end
+  local function UTF16BMP (hex)
+    return unichar (tonumber (hex, 16))
+  end
+  local U16Sequence = (P"\\u" * g.C (HexDigit * HexDigit * HexDigit * HexDigit))
+  local UnicodeEscape = g.Cmt (U16Sequence * U16Sequence, UTF16Surrogate) + U16Sequence/UTF16BMP
+  local Char = UnicodeEscape + EscapeSequence + PlainChar
+  local String = P"\"" * g.Cs (Char ^ 0) * (P"\"" + Err "unterminated string")
+  local Integer = P"-"^(-1) * (P"0" + (R"19" * R"09"^0))
+  local Fractal = P"." * R"09"^0
+  local Exponent = (S"eE") * (S"+-")^(-1) * R"09"^1
+  local Number = (Integer * Fractal^(-1) * Exponent^(-1))/str2num
+  local Constant = P"true" * g.Cc (true) + P"false" * g.Cc (false) + P"null" * g.Carg (1)
+  local SimpleValue = Number + String + Constant
+  local ArrayContent, ObjectContent
+
+  -- The functions parsearray and parseobject parse only a single value/pair
+  -- at a time and store them directly to avoid hitting the LPeg limits.
+  local function parsearray (str, pos, nullval, state)
+    local obj, cont
+    local npos
+    local t, nt = {}, 0
+    repeat
+      obj, cont, npos = pegmatch (ArrayContent, str, pos, nullval, state)
+      if not npos then break end
+      pos = npos
+      nt = nt + 1
+      t[nt] = obj
+    until cont == 'last'
+    return pos, setmetatable (t, state.arraymeta)
+  end
+
+  local function parseobject (str, pos, nullval, state)
+    local obj, key, cont
+    local npos
+    local t = {}
+    repeat
+      key, obj, cont, npos = pegmatch (ObjectContent, str, pos, nullval, state)
+      if not npos then break end
+      pos = npos
+      t[key] = obj
+    until cont == 'last'
+    return pos, setmetatable (t, state.objectmeta)
+  end
+
+  local Array = P"[" * g.Cmt (g.Carg(1) * g.Carg(2), parsearray) * Space * (P"]" + Err "']' expected")
+  local Object = P"{" * g.Cmt (g.Carg(1) * g.Carg(2), parseobject) * Space * (P"}" + Err "'}' expected")
+  local Value = Space * (Array + Object + SimpleValue)
+  local ExpectedValue = Value + Space * Err "value expected"
+  ArrayContent = Value * Space * (P"," * g.Cc'cont' + g.Cc'last') * g.Cp()
+  local Pair = g.Cg (Space * String * Space * (P":" + Err "colon expected") * ExpectedValue)
+  ObjectContent = Pair * Space * (P"," * g.Cc'cont' + g.Cc'last') * g.Cp()
+  local DecodeValue = ExpectedValue * g.Cp ()
+
+  function json.decode (str, pos, nullval, ...)
+    local state = {}
+    state.objectmeta, state.arraymeta = optionalmetatables(...)
+    local obj, retpos = pegmatch (DecodeValue, str, pos, nullval, state)
+    if state.msg then
+      return nil, state.pos, state.msg
+    else
+      return obj, retpos
+    end
+  end
+
+  -- use this function only once:
+  json.use_lpeg = function () return json end
+
+  json.using_lpeg = true
+
+  return json -- so you can get the module using json = require "dkjson".use_lpeg()
+end
+
+if always_try_using_lpeg then
+  pcall (json.use_lpeg)
+end
+
+return json
+

+ 234 - 0
example/assets/pandoc-scholar/scholar-filters/json-ld.lua

@@ -0,0 +1,234 @@
+-- json-ld.lua: add a JSON-LD metadata field describing the document.
+--
+-- Copyright (c) 2017-2021 Albert Krewinkel
+--
+-- This program is free software; you can redistribute it and/or modify it
+-- under the terms of the GNU public license version 2 or later.
+-- See the LICENSE file for details.
+local SCRIPT_DIR = PANDOC_SCRIPT_FILE:gsub('/[^/]*$', '')
+
+package.path =  SCRIPT_DIR .. '/?.lua;' .. package.path
+
+local json = require "dkjson"
+local List = require 'pandoc.List'
+
+local function stringify(x)
+  if x == nil then
+    return nil
+  elseif type(x) == 'string' then
+    return x
+  end
+  return pandoc.utils.stringify(x)
+end
+
+local function Organizations(orgs)
+  local orgs_json = {}
+  for i, org in ipairs(orgs) do
+    orgs_json[i] = {
+      ["@type"] = "Organization",
+      ["name"]  = org.name and stringify(org.name),
+      ['url']   = org.url and stringify(org.url),
+    }
+  end
+  return orgs_json
+end
+
+local function Authors(authors)
+  local authors_json = pandoc.MetaList{}
+  for i, author in ipairs(authors) do
+    authors_json[i] = {
+      ['@type']       = "Person",
+      ['@id']         = authors[i].orcid and
+                          ("https://orcid.org/" .. stringify(authors[i].orcid)),
+      ["name"]        = author.name and stringify(author.name),
+      ["affiliation"] = author.institute and Organizations(author.institute),
+      ['email']       = author.email and stringify(author.email),
+      ['url']         = author.url and stringify(author.url),
+    }
+  end
+  return authors_json
+end
+
+local function Cito (bibjson, cites_by_cito_property)
+  function find_citation(id)
+    -- sloooow
+    for i = 1, #bibjson do
+      if bibjson[i].id == id then
+        return bibjson[i]
+      end
+    end
+  end
+
+  local result = {}
+  local bibentry, citation_ld
+  for citation_type, typed_citation_ids in pairs(cites_by_cito_property) do
+    for i = 1, #typed_citation_ids do
+      bibentry = find_citation(typed_citation_ids[i])
+      if bibentry and bibentry.DOI then
+        citation_ld = {
+          ["@id"] = "http://dx.doi.org/" .. bibentry.DOI
+        }
+        cito_type_str = "cito:" .. citation_type
+        if not result[cito_type_str] then
+          result[cito_type_str] = {}
+        end
+        table.insert(result[cito_type_str], citation_ld)
+      end
+    end
+  end
+  return result
+end
+
+local function Citations (bibjson, citation_ids)
+  function find_citation(id)
+    -- sloooow
+    for i = 1, #bibjson do
+      if bibjson[i].id == id then
+        return bibjson[i]
+      end
+    end
+  end
+
+  function CitationSchema(record)
+    local type
+    if record.type == "report" then
+      type = "Report"
+    elseif record.type == "article-journal" then
+      type = "ScholarlyArticle"
+    else
+      type = "Article"
+    end
+
+    local authors = {}
+    if record.author then
+      for i = 1, #record.author do
+        local name = {
+          record.author[i].family,
+          record.author[i].given
+        }
+        authors[i] = {
+          name = table.concat(name, ", ")
+        }
+      end
+    end
+
+    return {
+      ["@context"] = {
+        ["@vocab"]    = "http://schema.org/",
+        ["title"]     = "headline",
+        ["page"]      = "pagination",
+        ["date"]      = "datePublished",
+        ["publisher"] = "publisher",
+        ["author"]    = "author",
+      },
+      ["@type"]     = type,
+      ["@id"]       = record.DOI and ("http://dx.doi.org/" .. record.DOI),
+      ["title"]     = record.title,
+      ["author"]    = Authors(authors),
+      ["date"]      = record.issued and
+        record.issued["date-parts"] and
+        table.concat(record.issued["date-parts"][1], "-"),
+      ["publisher"] = record.publisher and
+        { ["@type"] = "Organization", ["name"] = record.publisher },
+      ["page"]      = record.page,
+    }
+  end
+
+  local res = {}
+  for cit_id, _ in pairs(citation_ids) do
+    local citation_record = find_citation(cit_id)
+    if citation_record then
+      res[#res + 1] = CitationSchema(citation_record)
+    end
+  end
+  return res
+end
+
+function json_ld (meta)
+  local default_image = "https://upload.wikimedia.org/wikipedia/commons/f/fa/Globe.svg"
+  local accessible_for_free
+  if meta.accessible_for_free ~= nil then
+    accessible_for_free = meta.accessible_for_free
+  else
+    accessible_for_free = true
+  end
+  local context = {
+    ["@vocab"]    = "http://schema.org/",
+    ["cito"]      = "http://purl.org/spar/cito/",
+    ["author"]    = "author",
+    ["name"]      = "name",
+    ["title"]     = "headline",
+    ["subtitle"]  = "alternativeTitle",
+    ["publisher"] = "publisher",
+    ["date"]      = "datePublished",
+    ["isFree"]    = accessible_for_free and "isAccessibleForFree" or nil,
+    ["image"]     = "image",
+    ["citation"]  = "citation",
+  }
+
+  local citation_ids = {}
+  for _, ids in pairs(meta.cito_cites) do
+    for _, id in ipairs(ids) do citation_ids[id] = true end
+  end
+  local result = {
+    ["@context"]  = context,
+    ["@type"]     = "ScholarlyArticle",
+    ["author"]    = Authors(meta.author),
+    ["name"]      = stringify(meta.title),
+    ["title"]     = stringify(meta.title),
+    ["subtitle"]  = meta.subtitle and stringify(meta.subtitle),
+    ["date"]      = meta.date and stringify(meta.date) or os.date("%Y-%m-%d"),
+    -- -- ["image"]     = meta.image or default_image,
+    ["isFree"]    = accessible_for_free,
+    ["citation"]  = Citations(meta.bibliography_records, citation_ids),
+  }
+  for k, v in pairs(Cito(meta.bibliography_records, meta.cito_cites)) do
+    result[k] = v
+  end
+  return result
+end
+
+local function bibliography(bibfilename)
+  if not bibfilename or bibfilename == '' then
+    return {}
+  end
+  local bibfile = io.popen("pandoc-citeproc --bib2json " .. bibfilename, "r")
+  local jsonstr = bibfile:read("*a")
+  bibfile:close()
+  return json.decode(jsonstr)
+end
+
+local function institute_resolver (institutes)
+  return function (inst_idx)
+    return institutes[tonumber(stringify(inst_idx))]
+  end
+end
+
+function Meta (meta)
+  local function clone (obj)
+    local result = {}
+    for k, v in pairs(obj) do result[k] = v end
+    return result
+  end
+  local metadata = clone(meta)
+
+  local resolve_institute = function (idx)
+    return meta.institute[tonumber(idx)]
+  end
+  local tmp_authors = {}
+  for i, author_orig in ipairs(meta.author) do
+    local author = clone(author_orig)
+    if author.institute then
+      author.institute = List.map(author.institute, resolve_institute)
+    end
+    tmp_authors[i] = author
+  end
+  metadata.author = tmp_authors
+
+  local bib = pandoc.utils.stringify(meta.bibliography)
+  metadata.bibliography_records = bibliography(bib)
+  local jsonld_object = json_ld(metadata)
+  meta.jsonld = json.encode(jsonld_object)
+
+  return meta
+end

+ 48 - 0
example/assets/pandoc-scholar/scholar-filters/template-helper.lua

@@ -0,0 +1,48 @@
+--[[
+template-helper: generate meta fields to be used in templates.
+
+Copyright © 2017–2021 Albert Krewinkel
+
+Permission to use, copy, modify, and/or distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright notice
+and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+]]
+
+local List = require 'pandoc.List'
+
+function Meta (meta)
+  local function resolve_institute (idx)
+    return meta.institute[tonumber(idx)]
+  end
+
+  for i, author in ipairs(meta.author) do
+    local institute_indices = List:new(author.institute)
+    local institutes = institute_indices:map(resolve_institute)
+    author.institute_indices = institute_indices
+    author.institute = institutes
+    meta.has_equal_contributors = meta.has_equal_contributors
+      or author.equal_contributor
+    meta.has_correspondence = meta.has_correspondence
+      or author.correspondence and author.email
+  end
+  -- helper attributes
+  if #meta.author > 0 then
+    meta.author[1].first = true
+    meta.author[#meta.author].last = true
+  end
+
+  for i, institute in ipairs(meta.institute) do
+    institute.index = tostring(i)
+  end
+
+  return meta
+end
+

BIN
example/assets/pandoc-scholar/templates/images/arrow-down.png


BIN
example/assets/pandoc-scholar/templates/images/octocat-small.png


BIN
example/assets/pandoc-scholar/templates/images/pdf.png


+ 119 - 0
example/assets/pandoc-scholar/templates/pandoc-scholar.html

@@ -0,0 +1,119 @@
+<!doctype html>
+<!--
+Template created by Andrew G. York, based on this theme by Diana Mounter:
+https://github.com/broccolini/dinky, which mentioned that
+attribution is appreciated. Thanks, broccolini! -->
+<html lang="en">
+<head>
+  <base target="_blank"/>
+  <meta charset="utf-8"/>
+  <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
+  <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
+$for(author-meta)$
+  <meta name="author" content="$author-meta$"/>
+$endfor$
+$if(date-meta)$
+  <meta name="dcterms.date" content="$date-meta$"/>
+$endif$
+$if(keywords)$
+  <meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$"/>
+$endif$
+  <title>$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$</title>
+  <style type="text/css">code{white-space: pre;}</style>
+$if(quotes)$
+  <style type="text/css">q { quotes: "“" "”" "‘" "’"; }</style>
+$endif$
+$if(highlighting-css)$
+  <style type="text/css">
+$highlighting-css$
+  </style>
+$endif$
+$for(css)$
+  <link rel="stylesheet" href="$css$">
+$endfor$
+$if(math)$
+$if(mathjax)$
+$-- MathJax is handled specially.  We need to add the data-external attribute
+$-- so it doesn't get inlined (and thus broken) by the --self-contained option.
+$-- (2.7.2 is the default MathJax version as of Pandoc 2.2.1.)
+  <script data-external="1" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-AMS_CHTML-full"></script>
+$else$
+  $math$
+$endif$
+$endif$
+  <!--[if lt IE 9]>
+    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
+  <![endif]-->
+$for(header-includes)$
+  $header-includes$
+$endfor$
+</head>
+<body>
+<div class="wrapper">
+$if(project)$
+<header class="page-header">
+  <h1 class="header">$project.title$</h1>
+  <ul>
+$if(project.zip-url)$
+    <li class="download"><a class="buttons" href="$project.zip-url$">Download ZIP</a></li>
+$endif$
+$if(project.github-url)$
+    <li><a class="buttons github" href="$project.github-url$">View On GitHub</a></li>
+$endif$
+$if(project.pdf-url)$
+    <li><a class="buttons pdf" href="$project.pdf-url$">Download PDF</a></li>
+$endif$
+  </ul>
+  <p class="header">This project is maintained by $project.maintainer$</p>
+</header>
+$endif$
+<article typeof="ScholarlyArticle" vocab="http://schema.org/">
+    <!-- <header class="article-header"> -->
+<h1 property="headline">$title$</h1>
+$if(subtitle)$
+<p property="alternativeHeadline" class="subtitle">$subtitle$</p>
+$endif$
+<!-- </header> -->
+<p class="author-list">
+$for(author)$
+  $if(author.last)$and $endif$<span property="author" typeof="Person">
+    $author.name$</span><sup>$if(author.correspondence)$$if(author.email)$<a href="mailto:$author.email$">✉</a> $endif$$endif$$for(author.institute_indices)$$author.institute_indices$$sep$,$endfor$$if(author.equal_contributor)$,$if(equal_contributor_symbol)$$equal_contributor_symbol$$else$*$endif$$endif$</sup>$sep$,
+$endfor$
+</p>
+<div class="author-affiliations">
+$for(institute)$
+  <div class="affiliation"><sup>$institute.index$</sup>$institute.name$$if(institute.address)$, $institute.address$$endif$
+  </div>
+$endfor$
+</div>
+<div class="author-info">
+    $if(has_equal_contributors)$
+    <div class="author-contrib">
+        <sup>$if(equal_contributor_symbol)$$equal_contributor_symbol$$else$*$endif$</sup>These authors contributed equally to this work
+    </div>
+    $endif$
+    $if(has_correspondence)$
+    <div class="author-correspondence">
+        Correspondence: $for(author)$$if(author.correspondence)$$if(author.email)$$author.name$ <a href="mailto:$author.email$">&lt;$author.email$&gt;</a> $endif$$endif$$endfor$
+    </div>
+    $endif$
+</div>
+$if(abstract)$<p class="abstract" property="description">$abstract$</p>$endif$
+$if(doi)$<p><a href="https://doi.org/$doi$">doi: $doi$</a></p>$endif$
+
+$for(include-before)$
+$include-before$
+
+$endfor$
+
+<div property="articleBody" class="article-body">
+$body$
+</div>
+</article>
+<footer>
+  <p><small>Generated using <a href="https://github.com/pandoc-scholar/pandoc-scholar">pandoc scholar</a></small></p>
+</footer>
+</div>
+ <!--[if !IE]><script>fixScale(document);</script><![endif]-->
+</body>
+</html>

+ 118 - 0
example/assets/pandoc-scholar/templates/pandoc-scholar.jats

@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="utf-8" ?>
+$if(xml-stylesheet)$
+<?xml-stylesheet type="text/xsl" href="$xml-stylesheet$"?>
+$endif$
+<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Article Authoring DTD v1.2 20190208//EN"
+          "JATS-articleauthoring1.dtd">
+<article xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink" dtd-version="1.2" article-type="research-article">
+<front>
+<article-meta>
+$if(title)$
+<title-group>
+<article-title>$title$</article-title>
+</title-group>
+$endif$
+$if(author)$
+<contrib-group>
+$for(author)$
+<contrib contrib-type="author" corresp="$if(author.correspondence)$yes$else$no$endif$">
+$if(author.orcid)$
+<contrib-id contrib-id-type="orcid">$author.orcid$</contrib-id>
+$endif$
+<name-alternatives>
+<string-name>$author.name$</string-name>
+</name-alternatives>
+$for(author.institute)$
+<aff>
+$author.institute.name$
+$if(author.institute.phone)$
+<phone>$author.institute.phone$</phone>
+$endif$
+</aff>
+$endfor$
+$if(author.email)$
+<email>$author.email$</email>
+$endif$
+</contrib>
+$endfor$
+</contrib-group>
+$endif$
+$if(date)$
+<pub-date pub-type="epub"$if(date.iso-8601)$ iso-8601-date="$date.iso-8601$"$endif$>
+$if(date.day)$
+<day>$date.day$</day>
+$endif$
+$if(date.month)$
+<month>$date.month$</month>
+$endif$
+<year>$date.year$</year>
+</pub-date>
+$endif$
+$if(article.volume)$
+<volume>$article.volume$</volume>
+$endif$
+$if(article.issue)$
+<issue>$article.issue$</issue>
+$endif$
+$if(article.fpage)$
+<fpage>$article.fpage$</fpage>
+$endif$
+$if(article.lpage)$
+<lpage>$article.lpage$</lpage>
+$endif$
+$if(article.elocation-id)$
+<elocation-id>$article.elocation-id$</elocation-id>
+$endif$
+$if(history)$
+<history>
+</history>
+$endif$
+$if(copyright)$
+<permissions>
+$if(copyright.statement)$
+<copyright-statement>$copyright.statement$</copyright-statement>
+$endif$
+$if(copyright.year)$
+<copyright-year>$copyright.year$</copyright-year>
+$endif$
+$if(copyright.holder)$
+<copyright-holder>$copyright.holder$</copyright-holder>
+$endif$
+$if(copyright.text)$
+<license license-type="$copyright.type$" xlink:href="$copyright.link$">
+<license-p>$copyright.text$</license-p>
+</license>
+</permissions>
+$endif$
+$endif$
+$if(abstract)$
+<abstract>
+$abstract$
+</abstract>
+$endif$
+$if(tags)$
+<kwd-group kwd-group-type="author">
+$for(tags)$
+<kwd>$tags$</kwd>
+$endfor$
+</kwd-group>
+$endif$
+$if(article.funding-statement)$
+<funding-group>
+<funding-statement>$article.funding-statement$</funding-statement>
+</funding-group>
+$endif$
+</article-meta>
+$if(notes)$
+<notes>$notes$</notes>
+$endif$
+</front>
+<body>
+$body$
+</body>
+<back>
+$if(back)$
+$back$
+$endif$
+</back>
+</article>

+ 399 - 0
example/assets/pandoc-scholar/templates/pandoc-scholar.latex

@@ -0,0 +1,399 @@
+% Options for packages loaded elsewhere
+\PassOptionsToPackage{unicode$for(hyperrefoptions)$,$hyperrefoptions$$endfor$}{hyperref}
+\PassOptionsToPackage{hyphens}{url}
+$if(colorlinks)$
+\PassOptionsToPackage{dvipsnames,svgnames*,x11names*}{xcolor}
+$endif$
+$if(dir)$
+$if(latex-dir-rtl)$
+\PassOptionsToPackage{RTLdocument}{bidi}
+$endif$
+$endif$
+$if(CJKmainfont)$
+\PassOptionsToPackage{space}{xeCJK}
+$endif$
+%
+\documentclass[
+$if(fontsize)$
+  $fontsize$,
+$endif$
+$if(lang)$
+  $babel-lang$,
+$endif$
+$if(papersize)$
+  $papersize$paper,
+$endif$
+$for(classoption)$
+  $classoption$$sep$,
+$endfor$
+]{$documentclass$}
+\usepackage{amsmath,amssymb}
+$if(fontfamily)$
+\usepackage[$for(fontfamilyoptions)$$fontfamilyoptions$$sep$,$endfor$]{$fontfamily$}
+$else$
+\usepackage{lmodern}
+$endif$
+$if(linestretch)$
+\usepackage{setspace}
+$endif$
+\usepackage{ifxetex,ifluatex}
+\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
+  \usepackage[$if(fontenc)$$fontenc$$else$T1$endif$]{fontenc}
+  \usepackage[utf8]{inputenc}
+  \usepackage{textcomp} % provide euro and other symbols
+\else % if luatex or xetex
+$if(mathspec)$
+  \ifxetex
+    \usepackage{mathspec}
+  \else
+    \usepackage{unicode-math}
+  \fi
+$else$
+  \usepackage{unicode-math}
+$endif$
+  \defaultfontfeatures{Scale=MatchLowercase}
+  \defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1}
+$if(mainfont)$
+  \setmainfont[$for(mainfontoptions)$$mainfontoptions$$sep$,$endfor$]{$mainfont$}
+$endif$
+$if(sansfont)$
+  \setsansfont[$for(sansfontoptions)$$sansfontoptions$$sep$,$endfor$]{$sansfont$}
+$endif$
+$if(monofont)$
+  \setmonofont[$for(monofontoptions)$$monofontoptions$$sep$,$endfor$]{$monofont$}
+$endif$
+$for(fontfamilies)$
+  \newfontfamily{$fontfamilies.name$}[$for(fontfamilies.options)$$fontfamilies.options$$sep$,$endfor$]{$fontfamilies.font$}
+$endfor$
+$if(mathfont)$
+$if(mathspec)$
+  \ifxetex
+    \setmathfont(Digits,Latin,Greek)[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
+  \else
+    \setmathfont[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
+  \fi
+$else$
+  \setmathfont[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
+$endif$
+$endif$
+$if(CJKmainfont)$
+  \ifxetex
+    \usepackage{xeCJK}
+    \setCJKmainfont[$for(CJKoptions)$$CJKoptions$$sep$,$endfor$]{$CJKmainfont$}
+  \fi
+$endif$
+$if(luatexjapresetoptions)$
+  \ifluatex
+    \usepackage[$for(luatexjapresetoptions)$$luatexjapresetoptions$$sep$,$endfor$]{luatexja-preset}
+  \fi
+$endif$
+$if(CJKmainfont)$
+  \ifluatex
+    \usepackage[$for(luatexjafontspecoptions)$$luatexjafontspecoptions$$sep$,$endfor$]{luatexja-fontspec}
+    \setmainjfont[$for(CJKoptions)$$CJKoptions$$sep$,$endfor$]{$CJKmainfont$}
+  \fi
+$endif$
+\fi
+% Use upquote if available, for straight quotes in verbatim environments
+\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
+\IfFileExists{microtype.sty}{% use microtype if available
+  \usepackage[$for(microtypeoptions)$$microtypeoptions$$sep$,$endfor$]{microtype}
+  \UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
+}{}
+$if(indent)$
+$else$
+\makeatletter
+\@ifundefined{KOMAClassName}{% if non-KOMA class
+  \IfFileExists{parskip.sty}{%
+    \usepackage{parskip}
+  }{% else
+    \setlength{\parindent}{0pt}
+    \setlength{\parskip}{6pt plus 2pt minus 1pt}}
+}{% if KOMA class
+  \KOMAoptions{parskip=half}}
+\makeatother
+$endif$
+$if(verbatim-in-note)$
+\usepackage{fancyvrb}
+$endif$
+\usepackage{xcolor}
+\IfFileExists{xurl.sty}{\usepackage{xurl}}{} % add URL line breaks if available
+\IfFileExists{bookmark.sty}{\usepackage{bookmark}}{\usepackage{hyperref}}
+\hypersetup{
+$if(title-meta)$
+  pdftitle={$title-meta$},
+$endif$
+$if(author-meta)$
+  pdfauthor={$author-meta$},
+$endif$
+$if(lang)$
+  pdflang={$lang$},
+$endif$
+$if(subject)$
+  pdfsubject={$subject$},
+$endif$
+$if(keywords)$
+  pdfkeywords={$for(keywords)$$keywords$$sep$, $endfor$},
+$endif$
+$if(colorlinks)$
+  colorlinks=true,
+  linkcolor=$if(linkcolor)$$linkcolor$$else$Maroon$endif$,
+  filecolor=$if(filecolor)$$filecolor$$else$Maroon$endif$,
+  citecolor=$if(citecolor)$$citecolor$$else$Blue$endif$,
+  urlcolor=$if(urlcolor)$$urlcolor$$else$Blue$endif$,
+$else$
+  hidelinks,
+$endif$
+  pdfcreator={LaTeX via pandoc}}
+\urlstyle{same} % disable monospaced font for URLs
+$if(verbatim-in-note)$
+\VerbatimFootnotes % allow verbatim text in footnotes
+$endif$
+$if(geometry)$
+\usepackage[$for(geometry)$$geometry$$sep$,$endfor$]{geometry}
+$endif$
+$if(listings)$
+\usepackage{listings}
+\newcommand{\passthrough}[1]{#1}
+\lstset{defaultdialect=[5.3]Lua}
+\lstset{defaultdialect=[x86masm]Assembler}
+$endif$
+$if(lhs)$
+\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
+$endif$
+$if(highlighting-macros)$
+$highlighting-macros$
+$endif$
+$if(tables)$
+\usepackage{longtable,booktabs,array}
+\usepackage{calc} % for calculating minipage widths
+% Correct order of tables after \paragraph or \subparagraph
+\usepackage{etoolbox}
+\makeatletter
+\patchcmd\longtable{\par}{\if@noskipsec\mbox{}\fi\par}{}{}
+\makeatother
+% Allow footnotes in longtable head/foot
+\IfFileExists{footnotehyper.sty}{\usepackage{footnotehyper}}{\usepackage{footnote}}
+\makesavenoteenv{longtable}
+$endif$
+$if(graphics)$
+\usepackage{graphicx}
+\makeatletter
+\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
+\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
+\makeatother
+% Scale images if necessary, so that they will not overflow the page
+% margins by default, and it is still possible to overwrite the defaults
+% using explicit options in \includegraphics[width, height, ...]{}
+\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
+% Set default figure placement to htbp
+\makeatletter
+\def\fps@figure{htbp}
+\makeatother
+$endif$
+$if(links-as-notes)$
+% Make links footnotes instead of hotlinks:
+\DeclareRobustCommand{\href}[2]{#2\footnote{\url{#1}}}
+$endif$
+$if(strikeout)$
+\usepackage[normalem]{ulem}
+% Avoid problems with \sout in headers with hyperref
+\pdfstringdefDisableCommands{\renewcommand{\sout}{}}
+$endif$
+\setlength{\emergencystretch}{3em} % prevent overfull lines
+\providecommand{\tightlist}{%
+  \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
+$if(numbersections)$
+\setcounter{secnumdepth}{$if(secnumdepth)$$secnumdepth$$else$5$endif$}
+$else$
+\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
+$endif$
+$if(block-headings)$
+% Make \paragraph and \subparagraph free-standing
+\ifx\paragraph\undefined\else
+  \let\oldparagraph\paragraph
+  \renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
+\fi
+\ifx\subparagraph\undefined\else
+  \let\oldsubparagraph\subparagraph
+  \renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
+\fi
+$endif$
+$if(pagestyle)$
+\pagestyle{$pagestyle$}
+$endif$
+$for(header-includes)$
+$header-includes$
+$endfor$
+$if(lang)$
+\ifxetex
+  % Load polyglossia as late as possible: uses bidi with RTL langages (e.g. Hebrew, Arabic)
+  \usepackage{polyglossia}
+  \setmainlanguage[$for(polyglossia-lang.options)$$polyglossia-lang.options$$sep$,$endfor$]{$polyglossia-lang.name$}
+$for(polyglossia-otherlangs)$
+  \setotherlanguage[$for(polyglossia-otherlangs.options)$$polyglossia-otherlangs.options$$sep$,$endfor$]{$polyglossia-otherlangs.name$}
+$endfor$
+\else
+  \usepackage[$for(babel-otherlangs)$$babel-otherlangs$,$endfor$main=$babel-lang$]{babel}
+% get rid of language-specific shorthands (see #6817):
+\let\LanguageShortHands\languageshorthands
+\def\languageshorthands#1{}
+$if(babel-newcommands)$
+  $babel-newcommands$
+$endif$
+\fi
+$endif$
+\ifluatex
+  \usepackage{selnolig}  % disable illegal ligatures
+\fi
+$if(dir)$
+\ifxetex
+  % Load bidi as late as possible as it modifies e.g. graphicx
+  \usepackage{bidi}
+\fi
+\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
+  \TeXXeTstate=1
+  \newcommand{\RL}[1]{\beginR #1\endR}
+  \newcommand{\LR}[1]{\beginL #1\endL}
+  \newenvironment{RTL}{\beginR}{\endR}
+  \newenvironment{LTR}{\beginL}{\endL}
+\fi
+$endif$
+$if(csl-refs)$
+\newlength{\cslhangindent}
+\setlength{\cslhangindent}{1.5em}
+\newlength{\csllabelwidth}
+\setlength{\csllabelwidth}{3em}
+\newenvironment{CSLReferences}[2] % #1 hanging-ident, #2 entry spacing
+ {% don't indent paragraphs
+  \setlength{\parindent}{0pt}
+  % turn on hanging indent if param 1 is 1
+  \ifodd #1 \everypar{\setlength{\hangindent}{\cslhangindent}}\ignorespaces\fi
+  % set entry spacing
+  \ifnum #2 > 0
+  \setlength{\parskip}{#2\baselineskip}
+  \fi
+ }%
+ {}
+\usepackage{calc}
+\newcommand{\CSLBlock}[1]{#1\hfill\break}
+\newcommand{\CSLLeftMargin}[1]{\parbox[t]{\csllabelwidth}{#1}}
+\newcommand{\CSLRightInline}[1]{\parbox[t]{\linewidth - \csllabelwidth}{#1}\break}
+\newcommand{\CSLIndent}[1]{\hspace{\cslhangindent}#1}
+% for compatibility with pandoc 2.10
+\newenvironment{cslreferences}%
+  {$if(csl-hanging-indent)$\setlength{\parindent}{0pt}%
+  \everypar{\setlength{\hangindent}{\cslhangindent}}\ignorespaces$endif$}%
+  {\par}
+$endif$
+
+$if(title)$
+\title{$title$$if(thanks)$\thanks{$thanks$}$endif$}
+$endif$
+$if(subtitle)$
+\usepackage{etoolbox}
+\makeatletter
+\providecommand{\subtitle}[1]{% add subtitle to \maketitle
+  \apptocmd{\@title}{\par {\large #1 \par}}{}{}
+}
+\makeatother
+\subtitle{$subtitle$}
+$endif$
+\usepackage{authblk}
+$for(author)$
+\author[$for(author.institute_indices)$%
+  $author.institute_indices$%
+  $sep$,$endfor$]{%
+  $author.name$%
+  $if(author.correspondence)$$if(author.email)$%
+  \textsuperscript{*\,}%
+  %$endif$$endif$%
+  $if(author.equal_contributor)$
+  \textsuperscript{$if(equal_contributor_symbol)$$equal_contributor_symbol$$else$\textdagger$endif$\,}%
+  $endif$%
+}
+$endfor$
+$for(institute)$
+\affil[$institute.index$]{$institute.name$}
+$endfor$
+\date{$date$}
+
+\makeatletter
+\def\@maketitle{%
+  \newpage \null \vskip 2em
+  \begin {center}%
+    \let \footnote \thanks
+         {\LARGE \@title \par}%
+         \vskip 1.5em%
+                {\large \lineskip .5em%
+                  \begin {tabular}[t]{c}%
+                    \@author
+                  \end {tabular}\par}%
+                $if(has_equal_contributors)$
+                \vskip 0.5em{\textsuperscript{$if(equal_contributor_symbol)$$equal_contributor_symbol$$else$\textdagger$endif$}\,%
+                  These authors contributed equally to this work.}
+                $endif$
+                $if(has_correspondence)$
+                \vskip 0.2em{\textsuperscript{*}\,Correspondence:
+                  $for(author)$$if(author.correspondence)$$if(author.email)$
+                  $author.name$ <$author.email$>\\
+                  $endif$$endif$$endfor$}%
+                %$endif$
+                \vskip 1em{\large \@date}%
+  \end {center}%
+  \par
+  \vskip 1.5em}
+\makeatother
+
+\begin{document}
+$if(has-frontmatter)$
+\frontmatter
+$endif$
+$if(title)$
+\maketitle
+$if(abstract)$
+\begin{abstract}
+$abstract$
+\end{abstract}
+$endif$
+$endif$
+
+$for(include-before)$
+$include-before$
+
+$endfor$
+$if(toc)$
+$if(toc-title)$
+\renewcommand*\contentsname{$toc-title$}
+$endif$
+{
+$if(colorlinks)$
+\hypersetup{linkcolor=$if(toccolor)$$toccolor$$else$$endif$}
+$endif$
+\setcounter{tocdepth}{$toc-depth$}
+\tableofcontents
+}
+$endif$
+$if(lot)$
+\listoftables
+$endif$
+$if(lof)$
+\listoffigures
+$endif$
+$if(linestretch)$
+\setstretch{$linestretch$}
+$endif$
+$if(has-frontmatter)$
+\mainmatter
+$endif$
+$body$
+
+$if(has-frontmatter)$
+\backmatter
+$endif$
+
+$for(include-after)$
+$include-after$
+
+$endfor$
+\end{document}

+ 478 - 0
example/assets/pandoc-scholar/templates/styles/pandoc-scholar.css

@@ -0,0 +1,478 @@
+@import url(https://fonts.googleapis.com/css?family=Arvo:400,700,400italic);
+
+/* MeyerWeb Reset */
+
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, embed,
+figure, figcaption, footer, header, hgroup,
+article, menu, nav, output, ruby, section, summary,
+time, mark, audio, video {
+  margin: 0;
+  padding: 0;
+  border: 0;
+  font: inherit;
+  vertical-align: baseline;
+}
+
+
+/* Base text styles */
+
+body {
+  padding: 10px 50px 0 0;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 15px;
+  color: #030303;
+  background-color: #FCFBF8;
+  margin: 0;
+  line-height: 1.8em;
+  -webkit-font-smoothing: antialiased;
+}
+
+h1, h2, h3, h4, h5, h6 {
+  color: #232323;
+  margin: 36px 0 10px;
+}
+
+p, ul, ol, table, dl {
+  margin: 0 0 22px;
+}
+
+sub, sup {
+  font-size: 80%;
+}
+
+sub {
+  vertical-align: sub;
+}
+
+sup {
+  vertical-align: sup;
+}
+
+.author-list {
+  margin:0 0 0px;
+  font-weight: 700;
+}
+
+.author-affiliations {
+  margin:0 0 0px;
+  font-style: italic;
+}
+
+.contact_email {
+  font-style: italic;
+}
+
+.abstract {
+  margin: 0% 1% 2%;
+  font-weight: 700;
+}
+
+h1, h2, h3 {
+  border-bottom: 1px solid #ccc;
+  font-family: Arvo, Monaco, serif;
+  font-weight: normal;
+  line-height: 1.3;
+  padding-bottom: 5px;
+}
+
+h1 {
+  font-size: 30px;
+}
+
+h2 {
+  font-size: 24px;
+}
+
+h3 {
+  font-size: 18px;
+}
+
+h4, h5 {
+  font-family: Arvo, Monaco, serif;
+  font-weight: 700;
+}
+
+h6 {
+  font-family: Arvo, Monaco, serif;
+  font-weight: 200;
+}
+
+a {
+  font-weight:200;
+  text-decoration:none;
+}
+
+a:hover {
+  text-decoration: underline;
+}
+
+a small {
+  font-size: 12px;
+}
+
+em {
+  font-style: italic;
+}
+
+strong {
+  font-weight:700;
+}
+
+sup {
+  vertical-align: super;
+  font-size: smaller;
+}
+
+ul {
+  list-style-position: inside;
+  list-style: disc;
+  padding-left: 25px;
+}
+
+ol {
+  list-style-position: inside;
+  list-style: decimal;
+  padding-left: 25px;
+}
+
+blockquote {
+  margin: 0;
+  padding: 0 0 0 20px;
+  font-style: italic;
+}
+
+dl, dt, dd, dl p {
+  font-color: #444;
+}
+
+dl dt {
+  font-weight: bold;
+}
+
+dl dd {
+  padding-left: 20px;
+  font-style: italic;
+}
+
+dl p {
+  padding-left: 20px;
+  font-style: italic;
+}
+
+hr {
+  border: 0;
+  background: #ccc;
+  height: 1px;
+  margin: 0 0 24px;
+}
+
+/* Images */
+
+img {
+  position: relative;
+  margin: 0 auto;
+  height: auto;
+  max-width: 100%;
+  padding: 0px;
+  margin: 0px 0 0px 0;
+  border: 0px solid #ccc;
+}
+
+p img {
+  display: inline;
+  margin: 0;
+  padding: 0;
+  vertical-align: middle;
+  text-align: center;
+  border: none;
+}
+
+figure {
+  border: 1px solid #ccc;
+  background: #FFFFFF;
+}
+
+figcaption {
+  font-size: 12px;
+  background: #FFFFFF;
+  line-height: 150%;
+  margin-right: 1%;
+  margin-left: 1%;
+}
+
+/* Code blocks */
+
+code, pre {
+  font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
+  color: #000;
+  background: #e7e7e7;
+  font-size: 12px;
+}
+
+pre {
+  padding: 4px 12px;
+  border-radius:4px;
+  border:1px solid #D7D8C8;
+  overflow: auto;
+  overflow-y: hidden;
+  margin-bottom: 32px;
+}
+
+
+/* Tables */
+
+table {
+  width: 100%;
+  border: 1px solid #ccc;
+  margin-bottom: 32px;
+  text-align: left;
+ }
+
+table.figure_controls {
+  font-size: 12px;
+  line-height: 100%;
+  margin-bottom: 0px;
+}
+
+th {
+  background: #232323;
+  color: #FDFEFB;
+  font-family: 'Arvo', Helvetica, Arial, sans-serif;
+  font-size: 18px;
+  font-weight: normal;
+  padding: 10px;
+}
+
+td {
+  background: #eee;
+  padding: 0px;
+}
+
+
+/* Wrapper */
+.wrapper {
+  width:960px;
+}
+
+
+/* Header */
+
+.page-header {
+  background-color: #474747;
+  border-bottom-right-radius: 4px;
+  border-top-right-radius: 4px;
+  border: 1px solid #000;
+  color: #FDFDFB;
+  float: left;
+  margin: 30px 25px 0 0;
+  padding: 34px 25px 22px 50px;
+  position: fixed;
+  width: 170px;
+  -webkit-font-smoothing: antialiased;
+}
+
+.subtitle {
+  font-size: 16px;
+}
+
+.page-header h1 {
+  font-family: Arvo, sans-serif;
+  font-size: 30px;
+  font-weight: 300;
+  line-height: 1.3em;
+  border-bottom: none;
+  margin-top: 0;
+}
+
+
+.page-header h1,
+.page-header a {
+  color: #fff;
+}
+
+.page-header a {
+  text-decoration: underline;
+}
+
+a.name {
+  white-space: nowrap;
+}
+
+.page-header ul {
+  list-style:none;
+  padding:0;
+}
+
+.page-header li {
+  list-style-type: none;
+  width: 135px;
+  height: 15px;
+  margin-bottom: 12px;
+  line-height: 1em;
+  padding: 6px 6px 6px 7px;
+  background: #1100AF;
+  background: -moz-linear-gradient(top, #1100AF 0%, #110082 100%);
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%, #dddddd));
+  background: -webkit-linear-gradient(top, #1100AF 0%,#110082 100%);
+  background: -o-linear-gradient(top, #1100AF 0%,#110082 100%);
+  background: -ms-linear-gradient(top, #1100AF 0%,#110082 100%);
+  background: linear-gradient(top, #1100AF 0%,#110082 100%);
+  border-radius:4px;
+  border:1px solid #0D0D0D;
+  -webkit-box-shadow: inset 0px 1px 1px 0 rgba(38,2,233, 1);
+  box-shadow: inset 0px 1px 1px 0 rgba(38,2,233, 1);
+}
+
+.page-header li:hover {
+  background: #1D00C3;
+  background: -moz-linear-gradient(top, #1D00C3 0%, #190195 100%);
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#dddddd));
+  background: -webkit-linear-gradient(top, #1D00C3 0%,#190195 100%);
+  background: -o-linear-gradient(top, #1D00C3 0%,#190195 100%);
+  background: -ms-linear-gradient(top, #1D00C3 0%,#190195 100%);
+  background: linear-gradient(top, #1D00C3 0%,#190195 100%);
+}
+
+.buttons {
+  -webkit-font-smoothing: antialiased;
+  background: url(../images/arrow-down.png) no-repeat;
+  font-weight: normal;
+  height: 30px;
+  padding: 2px 2px 2px 22px;
+  text-shadow: rgba(0, 0, 0, 0.4) 0 -1px 0;
+}
+
+a.buttons {
+  text-decoration: none;
+}
+
+.buttons.github {
+  background: url(../images/octocat-small.png) no-repeat 1px;
+}
+
+.buttons.pdf {
+  background: url(../images/pdf.png) no-repeat 1px;
+}
+
+.buttons:hover {
+  color: #fff;
+  text-decoration: none;
+}
+
+
+/* Article - for main page content */
+
+article {
+  width: 650px;
+  float: right;
+  padding-bottom: 50px;
+}
+
+
+/* Footer */
+
+footer {
+  width: 170px;
+  float: left;
+  position: fixed;
+  bottom: 10px;
+  padding-left: 50px;
+}
+
+@media print, screen and (max-width: 960px) {
+  div.wrapper {
+    width: auto;
+    margin: 0;
+  }
+
+  .page-header, article, footer {
+    float: none;
+    position: static;
+    width: auto;
+  }
+
+  footer {
+    border-top: 1px solid #ccc;
+    margin: 0 84px 0 50px;
+    padding: 0;
+  }
+
+  .page-header {
+    padding-right: 320px;
+  }
+
+  article {
+    padding: 20px 84px 20px 50px;
+    margin: 0 0 20px;
+  }
+
+  .page-header a small {
+    display: inline;
+  }
+
+  .page-header ul {
+    position: absolute;
+    right: 130px;
+    top: 84px;
+  }
+}
+
+@media print, screen and (max-width: 720px) {
+  body {
+    word-wrap:break-word;
+  }
+
+  .page-header {
+    padding: 10px 20px 0;
+    margin-right: 0;
+  }
+
+  article {
+    margin: 0 0 30px;
+    padding: 10px 0 10px 20px;
+  }
+
+  footer {
+    margin: 0 0 0 30px;
+  }
+
+  .page-header ul, .page-header p.view {
+    position: static;
+  }
+}
+
+@media print, screen and (max-width: 480px) {
+  .page-header ul li.download {
+    display: none;
+  }
+
+  footer {
+    margin: 0 0 0 20px;
+  }
+
+  footer a {
+    display:block;
+  }
+}
+
+@media print {
+  body {
+    padding:0.4in;
+    font-size:12pt;
+    color:#444;
+  }
+}
+
+.onlyprint {display: none;}
+@media print {
+  .onlyprint {display: block;}
+}

BIN
example/assets/pandoc-scholar/templates/template.docx


+ 14 - 0
example/assets/pandoc-scholar/writers/jsonld.lua

@@ -0,0 +1,14 @@
+--
+-- jsonld.lua
+--
+-- Copyright (c) 2017 Albert Krewinkel, Robert Winkler
+--
+-- This program is free software; you can redistribute it and/or modify it
+-- under the terms of the GNU public license version 2 or later.
+-- See the LICENSE file for details.
+
+function Doc (body, meta, variables)
+  return meta.jsonld
+end
+
+setmetatable(_G, {__index = function () return function () return '' end end})

+ 19 - 0
example/assets/pd-chem-filter.lua

@@ -0,0 +1,19 @@
+-- This pandoc lua filter helps with latex chemical formulas with \ce
+--      In the case of markdown, it is re-escaped for math mode
+--      In the case of docx, the \ce is fully removed
+
+if FORMAT:match 'markdown' then
+
+    function Math(elem)
+        elem.text = elem.text:gsub("%\\\\ce", "\\ce")
+        return elem
+    end
+
+elseif FORMAT:match 'docx' then
+
+    function Math(elem)
+        elem.text = elem.text:gsub("%\\ce", "")
+        return elem
+    end
+
+end

+ 21 - 0
example/assets/pd-image-filter.lua

@@ -0,0 +1,21 @@
+if FORMAT:match 'markdown' then
+
+  function Image(elem)
+    -- Make sure extension is .png
+    elem.src = elem.src:gsub("%.pdf", ".png")
+
+    -- Prepend figure directory
+    elem.src = "figs/" .. elem.src
+    return elem
+  end
+
+end
+
+-- Filter images with this function if the target format is HTML
+if FORMAT:match 'html' then
+  function Image(elem)
+    elem.attributes.style = 'cursor:pointer'
+    elem.attributes.onclick = 'onClickImage(this)'
+    return elem
+  end
+end

+ 109 - 0
example/assets/pd-meta.py

@@ -0,0 +1,109 @@
+import argparse
+import pathlib
+import re
+
+NEWCOMAND_RE = re.compile(r"\\newcommand{[^}]*}{[^}]*}")  # a user new command
+ARGUMENT_RE = re.compile(r"(?<={)[^}]*(?=})")  # latex arguments
+
+meta_types = {
+    r"\pubtitle": "title",
+    r"\pubauth": "author",
+    r"\eqcontrib": "contribution",
+    r"\pubaffil": "affil",
+    r"\authemail": "email",
+    r"\orcid": "orcid",
+    r"\pubaddr": "institute",
+    r"\pubemail": "contact",
+}
+
+
+def repl_input(inp_section):
+
+    input_text = inp_section.group()
+    filename = ARGUMENT_RE.search(input_text)
+    print(filename)
+
+
+def read_meta(metafile):
+
+    metadata = {t: {} for t in meta_types.values()}
+    metadata['contact'] = []
+
+    with open(metafile, encoding="utf8") as f:
+        lines = f.readlines()
+
+    lines = [l.strip() for l in lines]
+    lines = [l for l in lines if l and not l.startswith("%")]
+    text = "".join(lines).replace("%", "")
+
+    for meta in NEWCOMAND_RE.findall(text):
+
+        m_typeno, m_val = ARGUMENT_RE.findall(meta)
+        m_type = next(
+            iter(t for t in meta_types if m_typeno.startswith(t)), None
+        )
+        if not m_type:
+            continue
+        elif m_type in [r"\pubemail", r"\contribution"]:
+            metadata[meta_types[m_type]].append(m_val[-1].lower())
+        elif m_type == r"\pubtitle":
+            metadata[meta_types[m_type]] = m_val
+        elif m_type == r"\pubaffil":
+            metadata[meta_types[m_type]][m_no] = m_val.replace(" ",
+                                                               "").split(",")
+        else:
+            m_no = m_typeno[-1].lower()
+            metadata[meta_types[m_type]][m_no] = m_val
+
+    return metadata
+
+
+def write_meta(meta, metafile):
+
+    with open("templates/pandoc/meta-base.yaml", encoding="utf8") as f:
+        base = f.read()
+
+    with open(metafile, 'w', encoding='utf8') as f:
+        f.write("---\n")
+        f.write(f"title: \"{meta['title']}\"\n")
+        f.write("author:\n")
+        for a in meta['author']:
+            f.write(f"  - {meta['author'][a]}:\n")
+            f.write("      institute:\n")
+            for aff in meta['affil'][a]:
+                f.write(f"        - {aff}\n")
+            if meta['orcid'].get(a, None):
+                f.write(f"      orcid: {meta['orcid'][a]}\n")
+            if meta['email'].get(a, None):
+                f.write(f"      email: {meta['email'][a]}\n")
+            if a in meta['contact']:
+                f.write("      correspondence: \"yes\"\n")
+            if a in meta['contribution']:
+                f.write("      equal_contributor: \"yes\"\n")
+
+        f.write("institute:\n")
+        for i in meta['institute']:
+            f.write(f"  - {i}:\n")
+            f.write(f"      name: {meta['institute'][i]}\n")
+        f.write(base)
+        f.write("\n---\n")
+
+
+if __name__ == "__main__":
+
+    parser = argparse.ArgumentParser(description='Write metadata files.')
+    parser.add_argument(
+        '--tex',
+        type=str,
+        default=pathlib.Path(__file__).parent.parent / 'templates' /
+        'metadata.tex'
+    )
+    parser.add_argument(
+        '--yaml',
+        type=str,
+        default=pathlib.Path(__file__).parent.parent / 'templates' /
+        'metadata-pd.yaml'
+    )
+    args = parser.parse_args()
+    meta = read_meta(args.tex)
+    write_meta(meta, args.yaml)

+ 54 - 0
example/assets/pd-ref-filter.lua

@@ -0,0 +1,54 @@
+-- Generate string
+local function split_prepend_ref(inputstr)
+  local t = '['
+  for str in inputstr:gmatch('([^,]+)') do
+    if t ~= '[' then
+      t = t..';'
+    end
+    t = t..'@'..str:gsub('^%s*', ''):gsub('%s*$', '')
+  end
+  t = t..']'
+  return t
+end
+
+if FORMAT:match 'markdown' then
+  function Link(elem)
+    if elem.attributes.reference then
+        return pandoc.RawInline('markdown', split_prepend_ref(elem.attributes.reference))
+        -- return pandoc.RawInline('markdown', '{+@' ..elem.attributes.reference .. '}')
+    else
+        return elem
+    end
+  end
+end
+
+if FORMAT:match 'markdown' then
+  function Math(elem)
+    if elem.mathtype == "DisplayMath" then
+      if elem.text:find("\\label") then
+        for label in elem.text:gmatch("\\label{(.-)}") do
+          elem.text = elem.text:gsub("\\label{"..label.."}", "")
+          return pandoc.RawInline('markdown', "$$"..elem.text.."$$".." {#"..label.."}")
+        end
+      end
+    end
+    -- tprint(elem, 4)
+  end
+end
+
+-- Print contents of `tbl`, with indentation.
+-- `indent` sets the initial level of indentation.
+function tprint(tbl, indent)
+  if not indent then indent = 0 end
+  for k, v in pairs(tbl) do
+    formatting = string.rep("  ", indent) .. k .. ": "
+    if type(v) == "table" then
+      print(formatting)
+      tprint(v, indent+1)
+    elseif type(v) == 'boolean' then
+      print(formatting .. tostring(v))      
+    else
+      print(formatting .. v)
+    end
+  end
+end

+ 28 - 0
example/assets/submit-clean.py

@@ -0,0 +1,28 @@
+"""Clean processed folder.
+
+Usage: clean [--output_dir=<output_dir>] [<directory>]
+"""
+
+import argparse
+import pathlib
+import shutil
+import os
+
+
+def main(source_dir):
+    if source_dir.exists():
+        shutil.rmtree(source_dir)
+    zip_path = source_dir.parent / "manuscript.zip"
+    if zip_path.exists():
+        os.remove(zip_path)
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(description='Clean processed folder.')
+    parser.add_argument(
+        '--dir',
+        type=str,
+        default=pathlib.Path(__file__).parent.parent / 'condensed'
+    )
+    args = parser.parse_args()
+    main(args.dir)

+ 311 - 0
example/assets/submit-condense.py

@@ -0,0 +1,311 @@
+"""Condense manuscript into single files, often preferred by journals.
+
+Usage: condense [--output_dir=<output_dir>] [<directory>]
+"""
+
+import argparse
+import pathlib
+import shutil
+import re
+
+STYLE_RE = re.compile(r"\\def\\style{\d}\s")  # style statement + newline
+INPUT_RE = re.compile(r"\\input{.*}")  # an input statement
+ARGUMENT_RE = re.compile(r"(?<={)[\s\S]*(?=})")  # any latex argument
+IF_RE = re.compile(r"\\if[^def][\s\S]*?\\fi")  # any if/fi section not ifdef
+ELSE_RE = re.compile(r"\\else[\s\S]*?\\fi")  # any else/fi section
+IF_ARG_RE = re.compile(r"(?<=\\if\\style)\d")  # the style if comparator
+IF_ARG_STRIP = re.compile(r"\\if\\\w*\s*|\\fi")  # the if/fi edges
+ELSE_ARG_STRIP = re.compile(r"\\else|\\fi")  # the else/fi edges
+META_RE = re.compile(r"% !TEX .*")  # tex meta commands
+
+IFDEF_RE = re.compile(r"\\ifdef")  # any ifdefined/fi section
+NEWCOMM_RE = re.compile(r"\\newcommand")  # any ifdefined/fi section
+
+style_d = {
+    '0': 'pi',
+    '1': 'els',
+    '2': 'rsc',
+    '3': 'acs',
+}
+
+
+def check(directory, filename):
+    for path in directory.iterdir():
+        if path.name == filename:
+            return True
+    return False
+
+
+def get_style(text):
+    """Figure out style, then remove from file."""
+    style_match = STYLE_RE.search(text)
+    if not style_match:
+        return None, text
+    style = ARGUMENT_RE.search(style_match.group()).group()
+    text = STYLE_RE.sub("", text)
+
+    return style, text
+
+
+def find_close_bracket(string):
+    """finds the closing of a scope, taking into account nesting"""
+    nest = 1
+    for ind, char in enumerate(string):
+        if char == '{':
+            nest += 1
+        elif char == '}':
+            nest -= 1
+        if nest == 0:
+            return ind
+
+
+def sort_style_ifs(text, style):
+    r"""
+    Deal with any if/else/fi flags.
+    The if/else types to replace are only '\if\style'
+    """
+    def repl_ifs(if_section):
+        if_text = if_section.group()
+        if_style = IF_ARG_RE.search(if_text)  # find if in group
+        if not if_style:
+            raise Exception(if_text)
+        else_match = ELSE_RE.search(if_text)
+        if else_match:
+            if_text = if_text[0:else_match.start()]
+            else_text = else_match.group()
+        if style == if_style.group():
+            return IF_ARG_STRIP.sub("", if_text)
+        else:
+            if else_match:
+                return ELSE_ARG_STRIP.sub("", else_text)
+            return ""
+
+    return IF_RE.sub(repl_ifs, text)
+
+
+def sort_other_ifs(text):
+    r"""
+    Deal with other if flags.
+    # The types to replace are either \ifdef or \if@switch
+    """
+    def repl_ifswitch(if_section):
+        if_text = if_section.group()
+        if if_text.startswith("\\if@switch"):
+            if text.startswith("% Master SI"):
+                return ""
+            else_match = ELSE_RE.search(if_text)
+            if_text = if_text[0:else_match.start()]
+            else_text = else_match.group()
+            return ELSE_ARG_STRIP.sub("", else_text)
+        else:
+            raise Exception
+
+    text = IF_RE.sub(repl_ifswitch, text)
+
+    hit = IFDEF_RE.search(text)
+    while hit:
+        arg1_o = hit.end() + 1
+        arg1_e = arg1_o + find_close_bracket(text[arg1_o:])
+        arg2_o = arg1_e + 2
+        arg2_e = arg2_o + find_close_bracket(text[arg2_o:])
+        arg3_o = arg2_e + 2
+        arg3_e = arg3_o + find_close_bracket(text[arg3_o:])
+
+        if text.find(f"\\newcommand{{{text[arg1_o:arg1_e]}}}") != -1:
+            text = text[:hit.start()] + text[arg2_o:arg2_e] + text[arg3_e + 1:]
+        else:
+            text = text[:hit.start()] + text[arg3_o:arg3_e] + text[arg3_e + 1:]
+        hit = IFDEF_RE.search(text)
+
+    return text
+
+
+def expand(text):
+    def repl_input(inp_section):
+
+        input_text = inp_section.group()
+        filename = ARGUMENT_RE.search(input_text)
+        if not filename:
+            raise Exception
+        filepath = pathlib.Path("./" + filename.group() + '.tex')
+        with open(filepath, 'r', encoding="utf-8") as file:
+            return file.read()
+
+    return INPUT_RE.subn(repl_input, text)
+
+
+def expand_meta(text):
+
+    replaced = [
+        r'\pubauth',
+        r'\pubaffil',
+        r'\pubaddr',
+        r'\orcid',
+        r'\pubkeywords',
+        r'\pubSI',
+        r'\pubtitle',
+        r'\dg',
+        r'\eqcontrib',
+        r'\authemail',
+        r'\pubemail',
+    ]
+
+    for r in replaced:
+        replaced_vals = []
+        for hit in NEWCOMM_RE.finditer(text):
+            arg1_o = hit.end() + 1
+            arg1_e = arg1_o + find_close_bracket(text[arg1_o:])
+            if text[arg1_e + 1] == "{":
+                arg2_o = arg1_e + 2
+                arg2_e = arg2_o + find_close_bracket(text[arg2_o:])
+
+            command = text[arg1_o:arg1_e]
+            value = text[arg2_o:arg2_e]
+
+            if command.startswith(r):
+                replaced_vals.append([command, value, hit.start(), arg2_e + 1])
+
+        text = ''.join([
+            chr for idx, chr in enumerate(text, 1) if not any(
+                strt_idx <= idx <= end_idx
+                for _, _, strt_idx, end_idx in replaced_vals
+            )
+        ])
+        for val in replaced_vals:
+            text = text.replace(val[0], val[1])
+
+    return text
+
+
+def clean(text, style):
+
+    # remove meta commands
+    text = META_RE.sub("", text)
+
+    # remove advanced tex lines
+    text = re.sub(r"\\makeatletter", r'', text)
+    text = re.sub(r"\\makeatother", r'', text)
+
+    # pandoc unnecessary commands
+    text = text.replace(
+        r"\newenvironment{widefigure}{\begin{figure*}}{\end{figure*}}", ""
+    )
+    text = text.replace("widefigure", "figure*")
+    text = text.replace(
+        r"\newenvironment{widetable}{\begin{table*}}{\end{table*}}", ""
+    )
+    text = text.replace("widetable", "table*")
+
+    # remove comment lines
+    text = re.sub(r'(?<!\\)%.*', r'', text)
+
+    # remove superfluous newlines
+    text = re.sub(r'\n\s*\n', r'\n\n', text)
+
+    # update references
+    text = re.sub(r"(?<=\\bibliography{)refs/biblio(?=})", r'biblio', text)
+
+    if style == '0' or style is None:
+        text = re.sub(r"templates/pi/", r'', text)
+    elif style == '2':
+        text = re.sub(r"templates/rsc/", r'', text)
+
+    return text
+
+
+def process_tex(target):
+    """Process a tex file to return it to a simple 'one file' format."""
+    with target.open() as file:
+
+        # get file contents
+        filetext = file.read()
+
+        # get style
+        style, filetext = get_style(filetext)
+
+        # style if/else processing
+        if style:
+            filetext = sort_style_ifs(filetext, style)
+
+        # input expansion
+        expansions = 1
+        while expansions > 0:
+            filetext, expansions = expand(filetext)
+
+        # second if/else processing
+        filetext = sort_other_ifs(filetext)
+
+        # replace metadata commands
+        filetext = expand_meta(filetext)
+
+        # cleaning
+        filetext = clean(filetext, style)
+
+        return filetext, style
+
+
+def copy_files(source, target, style):
+    shutil.copy((source / 'refs' / 'biblio.bib'), (target / 'biblio.bib'))
+    shutil.copy((source / 'manuscript-SI.aux'), (target / 'manuscript-SI.aux'))
+    shutil.copy((source / 'manuscript-SI.pdf'), (target / 'manuscript-SI.pdf'))
+    shutil.copytree((source / 'figs'), (target / 'figs'),
+                    ignore=shutil.ignore_patterns('*.md', '*.txt'))
+    if style == '0':
+        shutil.copy((source / 'templates' / 'pi' / 'pi-article.cls'),
+                    (target / 'pi-article.cls'))
+        shutil.copy((source / 'templates' / 'pi' / 'pi-bib.bst'),
+                    (target / 'pi-bib.bst'))
+    elif style == '2':
+        shutil.copy((source / 'templates' / 'rsc' / 'rsc.bst'),
+                    (target / 'rsc.bst'))
+        shutil.copytree((source / 'templates' / 'rsc' / 'head_foot'),
+                        (target / 'head_foot'))
+
+
+def main(source_dir, output_dir='./condensed/'):
+
+    # define source and output dirs
+    source_dir = pathlib.Path(source_dir)
+    output_dir = pathlib.Path(output_dir)
+
+    # create and clean output dir
+    if output_dir.exists():
+        shutil.rmtree(output_dir)
+    output_dir.mkdir(parents=True, exist_ok=True)
+
+    # the manuscript style (own, RCS, etc)
+    man_style = None
+
+    # condense the manuscript files
+    files = [
+        'manuscript.tex',
+        'manuscript-SI.tex',
+    ]
+    for filename in files:
+        if check(source_dir, filename):
+            target_in = source_dir / filename
+            target_out = output_dir / filename
+            processed, style = process_tex(target_in)
+            if style:
+                man_style = style
+            with open(target_out, "w", encoding="utf-8") as file:
+                file.write(processed)
+
+    # copy over other required data
+    copy_files(source_dir, output_dir, man_style)
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(
+        description='Condense manuscript to a single file.'
+    )
+    parser.add_argument(
+        '--source', type=str, default=pathlib.Path(__file__).parent.parent
+    )
+    parser.add_argument(
+        '--dest',
+        type=str,
+        default=pathlib.Path(__file__).parent.parent / 'condensed'
+    )
+    args = parser.parse_args()
+    main(args.source, args.dest)

+ 68 - 0
example/assets/submit-zip.py

@@ -0,0 +1,68 @@
+"""Zip manuscript folder.
+
+Usage: zip [--source=<output_dir>] [--dest=<destination_dir>]
+"""
+
+import argparse
+import pathlib
+import shutil
+
+EXCLUDE_EXTS = (
+    '*.pdf',
+    '*.gz',
+    '*.aux',
+    '*.bbl',
+    '*.blg',
+    '*.fdb_latexmk',
+    '*.fls',
+    '*.log',
+    '*.out',
+)
+
+
+def clean(source_dir):
+
+    source_temp = source_dir.parent / 'condensed_temp'
+    if source_temp.exists():
+        shutil.rmtree(source_temp)
+
+    # create temp files
+    shutil.copytree(
+        source_dir, source_temp, ignore=shutil.ignore_patterns(*EXCLUDE_EXTS)
+    )
+    shutil.copy(
+        source_dir / "manuscript-SI.aux", source_temp / "manuscript-SI.aux"
+    )
+
+    return source_temp
+
+
+def main(source_dir, output_file='./manuscript'):
+
+    source_dir = pathlib.Path(source_dir)
+
+    # clean from source dir
+    cleaned_source_dir = clean(source_dir)
+
+    # archive source dir
+    shutil.make_archive(output_file, format='zip', root_dir=cleaned_source_dir)
+
+    # delete temp files
+    shutil.rmtree(cleaned_source_dir)
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(description='Zip submission files.')
+    parser.add_argument(
+        '--source',
+        type=str,
+        default=pathlib.Path(__file__).parent.parent / 'condensed'
+    )
+    parser.add_argument(
+        '--dest',
+        type=str,
+        default=pathlib.Path(__file__).parent.parent / 'condensed' /
+        'manuscript'
+    )
+    args = parser.parse_args()
+    main(args.source, args.dest)

BIN
example/docx_templates/template.docx


+ 684 - 0
example/html_templates/template.css

@@ -0,0 +1,684 @@
+/*
+   Modified by: Paul Iacomi
+   Originally based on a marked2app template
+*/
+
+/* Colors */
+
+:root {
+    --color-highlight-1: #2f80a5;
+    --color-highlight-2: #0f5271;
+    --color-highlight-3: #3a3a4f;
+    --color-complementary-1: #b54b3a;
+    --color-complementary-2: #a73f2d;
+    --color-white: #FFFFFF;
+    --color-off-white: #F8F5F0;
+    --color-off-white-2: #ECE6DA;
+    --color-grey-1: #ddd;
+    --color-grey-2: #68645d;
+    --color-grey-3: #57534A;
+    --color-grey-4: #423F37;
+    --color-black: rgb(0, 0, 0);
+    --color-transparent: rgba(0, 0, 0, 0.4);
+}
+
+@font-face {
+    font-family: "Ubuntu";
+    font-style: normal;
+    font-weight: 300;
+    src: local("Ubuntu Light"), local("Ubuntu-Light"), url("http://themes.googleusercontent.com/static/fonts/ubuntu/v4/WtcvfJHWXKxx4x0kuS1kobO3LdcAZYWl9Si6vvxL-qU.woff") format("woff");
+}
+
+@font-face {
+    font-family: "Ubuntu";
+    font-style: normal;
+    font-weight: 400;
+    src: local("Ubuntu"), url("http://themes.googleusercontent.com/static/fonts/ubuntu/v4/CGXpU_uR_FUfdeyCjAWgZ-vvDin1pK8aKteLpeZ5c0A.woff") format("woff");
+}
+
+@font-face {
+    font-family: "Ubuntu";
+    font-style: normal;
+    font-weight: 500;
+    src: local("Ubuntu Medium"), local("Ubuntu-Medium"), url("http://themes.googleusercontent.com/static/fonts/ubuntu/v4/gMhvhm-nVj1086DvGgmzB7O3LdcAZYWl9Si6vvxL-qU.woff") format("woff");
+}
+
+@font-face {
+    font-family: "Ubuntu";
+    font-style: normal;
+    font-weight: 700;
+    src: local("Ubuntu Bold"), local("Ubuntu-Bold"), url("http://themes.googleusercontent.com/static/fonts/ubuntu/v4/nsLtvfQoT-rVwGTHHnkeJrO3LdcAZYWl9Si6vvxL-qU.woff") format("woff");
+}
+
+@font-face {
+    font-family: "Ubuntu";
+    font-style: italic;
+    font-weight: 300;
+    src: local("Ubuntu Light Italic"), local("Ubuntu-LightItalic"), url("http://themes.googleusercontent.com/static/fonts/ubuntu/v4/DZ_YjBPqZ88vcZCcIXm6VqfTCPadK0KLfdEfFtGWCYw.woff") format("woff");
+}
+
+/* General settings */
+
+html {
+    font-size: 100%;
+    scroll-behavior: smooth;
+}
+
+html, button, input, select, textarea {
+    font-family: sans-serif;
+}
+
+html, body, button, input, select, textarea {
+    color: var(--color-grey-3);
+    font-family: "Ubuntu Medium", "Myriad Pro", "Myriad", sans-serif;
+    font-size: 18px;
+    font-weight: 300;
+}
+
+body {
+    margin: 0 auto;
+    background-color: var(--color-white);
+    height: 100%;
+    min-height: 100%;
+    overflow: hidden;
+}
+
+body, textarea {
+    line-height: 1.4;
+}
+
+body:after {
+    clear: both;
+    content: "";
+    display: table;
+}
+
+h1, h2, h3, dt {
+    color: var(--color-grey-4);
+    font-weight: 700;
+}
+
+h1 {
+    font-size: 2em;
+    margin: 0.67em 0;
+}
+
+h2, .article-list .article-title {
+    font-size: 1.5em;
+    margin: 0.83em 0;
+}
+
+h3, dt {
+    font-size: 1.17em;
+    margin: 1em 0;
+}
+
+h4 {
+    font-size: 1em;
+    margin: 1.33em 0;
+}
+
+h5 {
+    font-size: 0.83em;
+    margin: 1.67em 0;
+}
+
+h6 {
+    font-size: 0.75em;
+    margin: 2.33em 0;
+}
+
+a {
+    color: var(--color-highlight-1);
+    cursor: pointer;
+    outline: 0 none;
+    text-decoration: underline;
+}
+
+a:hover {
+    outline: 0 none;
+    color: var(--color-highlight-2);
+}
+
+p, pre {
+    margin: 1em 0;
+}
+
+.article-body p {
+    text-align: justify;
+}
+
+code, kbd, pre, samp {
+    font-family: monospace, serif;
+    font-size: 1em;
+    margin: 0;
+    padding: 0;
+}
+
+pre {
+    white-space: pre-wrap;
+    word-wrap: break-word;
+}
+
+pre {
+    background-color: var(--color-off-white);
+    font-size: 0.7rem;
+    overflow-x: auto;
+    padding: 1.3rem;
+    position: relative;
+    white-space: pre;
+    word-wrap: normal;
+}
+
+pre, code, kbd, samp {
+    margin: 0;
+}
+
+code, kbd, pre, samp {
+    font-family: monospace, serif;
+}
+
+code {
+    color: var(--color-grey-4);
+}
+
+aside {
+    display: block;
+    float: right;
+    width: 390px;
+}
+
+b, strong {
+    font-weight: bold;
+    color: var(--color-grey-4);
+    font-weight: 700;
+}
+
+blockquote {
+    color: var(--color-grey-4);
+    font-size: 1.25em;
+    font-weight: 700;
+    margin: 1em 40px;
+}
+
+blockquote {
+    margin-bottom: 2em;
+    margin-top: 2em;
+}
+
+hr {
+    -moz-border-bottom-colors: none;
+    -moz-border-left-colors: none;
+    -moz-border-right-colors: none;
+    -moz-border-top-colors: none;
+    border-color: -moz-use-text-color -moz-use-text-color var(--color-off-white-2);
+    border-image: none;
+    border-style: none none solid;
+    border-width: medium medium 1px;
+    margin: 3em 6em;
+}
+
+/* buttons */
+
+.button {
+    box-shadow: inset 0px 34px 0px -15px var(--color-complementary-1);
+    background-color: var(--color-complementary-2);
+    border: 1px solid var(--color-grey-4);
+    display: inline-block;
+    cursor: pointer;
+    color: var(--color-white);
+    font-size: 15px;
+    font-weight: bold;
+    padding: 9px 23px;
+    text-decoration: none;
+    text-shadow: 0px -1px 0px var(--color-grey-4);
+}
+
+.button:hover {
+    background-color: var(--color-complementary-1);
+}
+
+.button:active {
+    position: relative;
+    top: 1px;
+}
+
+
+/* Wrapper and Header */
+
+.wrapper {
+    flex: 1;
+    display: flex;
+}
+
+.container {
+    flex: 1;
+    order: 1;
+    height: 100vh;
+    overflow-y: auto;
+}
+
+article {
+    padding-left: 6rem;
+    padding-right: 6rem;
+    margin-left: auto;
+    margin-right: auto;
+    max-width: 42rem;
+    display: block;
+}
+
+/* header/navbar */
+
+header {
+    flex: 0 0 25%;
+    order: 0;
+    background-color: var(--color-highlight-3);
+    border-left: 1px solid var(--color-black);
+    color: var(--color-off-white);
+    -webkit-font-smoothing: antialiased;
+    height: 100vh;
+    overflow-y: auto;
+    padding: 20px;
+}
+
+header h1 {
+    font-family: Arvo, sans-serif;
+    font-size: 1.3em;
+    font-weight: 300;
+    color: var(--color-white);
+    line-height: 1.3em;
+    border-bottom: none;
+    margin-top: 0;
+    margin-left: 10px;
+}
+
+header ul>li:before {
+    background-color: var(--color-white);
+}
+
+header a {
+    text-decoration: none;
+    font-size: 0.9em;
+    color: var(--color-off-white);
+}
+
+header a:hover {
+    outline: 0 none;
+    color: var(--color-highlight-1);
+}
+
+header ul {
+    list-style: none;
+    padding: 0;
+}
+
+.navbar-hamburger {
+    display: none;
+}
+
+#navbar-check {
+    display: none;
+}
+
+@media print, screen and (max-width: 960px) {
+    body {
+        overflow: auto;
+    }
+    .wrapper {
+        flex-direction: column;
+    }
+    /* header, article, footer {
+        float: none;
+        position: static;
+        width: auto;
+    } */
+    article, footer {
+        float: none;
+        position: static;
+        width: auto;
+    }
+    header {
+        position: static;
+        flex: 0 0 0;
+        padding: 20px;
+    }
+    article {
+        padding-left: 3.5rem;
+        padding-right: 3.5rem;
+    }
+    .navbar-items {
+        background-color: var(--color-highlight-3);
+        position: fixed;
+        top: 0;
+        bottom: 0;
+        width: 70%;
+        padding: 10px;
+        overflow-y: auto;
+        -webkit-box-orient: vertical;
+        -webkit-box-direction: normal;
+        -ms-flex-flow: column nowrap;
+        flex-flow: column nowrap;
+        -webkit-box-pack: center;
+        -ms-flex-pack: center;
+        justify-content: center;
+    }
+    .navbar-hamburger {
+        display: block !important;
+        float: left;
+        position: fixed;
+        z-index: 6;
+        top: 5%;
+        color: var(--color-off-white);
+        background-color: var(--color-complementary-2);
+        -webkit-transform: translateY(-50%);
+        transform: translateY(-50%);
+        transform: scale(2);
+    }
+    .navbar-left .navbar-items {
+        left: 0;
+        margin-left: -100%;
+        -webkit-transition: margin-left 0.2s ease;
+        transition: margin-left 0.2s ease;
+    }
+    .navbar-left #navbar-check:checked~.navbar-items {
+        margin-left: 0;
+    }
+    .navbar-left #navbar-check:checked~.navbar-hamburger {
+        margin-left: 72%;
+    }
+    div.navbar-item:not(:last-of-type) {
+        margin-bottom: 8px;
+    }
+}
+
+/* images and figures */
+
+figure {
+    margin-bottom: 2em;
+    margin-top: 2em;
+}
+
+figure>figcaption {
+    margin-top: 0.5em;
+}
+
+img {
+    max-width: 100%;
+    max-height: 100vh;
+    display: block;
+    border: 0 none;
+    margin: auto;
+}
+
+.img-modal {
+    z-index: 3;
+    display: none;
+    position: fixed;
+    left: 0;
+    top: 0;
+    width: 100%;
+    height: 100%;
+    overflow: auto;
+    background-color: var(--color-black);
+    background-color: var(--color-transparent);
+}
+
+.img-modal-content {
+    margin: auto;
+    background-color: var(--color-white);
+    position: relative;
+    padding: 0;
+    outline: 0;
+    max-width: 60%;
+    animation: animatezoom 0.6s;
+}
+
+.img-modal-content img {
+    max-width: 100%;
+    max-height: 100%;
+}
+
+@keyframes animatezoom {
+    from {
+        transform: scale(0)
+    }
+    to {
+        transform: scale(1)
+    }
+}
+
+/* Lists and tables */
+
+ol>li:before {
+    color: var(--color-grey-4);
+    content: counter(ol, decimal) ".";
+    counter-increment: ol;
+    font-weight: 700;
+    margin-right: 0.333em;
+    position: absolute;
+    right: 100%;
+}
+
+ul>li:before {
+    background-color: var(--color-grey-4);
+    border-radius: 14px 14px 14px 14px;
+    content: "";
+    height: 6px;
+    margin-right: 0.333em;
+    margin-top: 0.55em;
+    position: absolute;
+    right: 100%;
+    width: 6px;
+}
+
+ol, ul, dl {
+    margin-left: 2rem;
+    padding: 0;
+}
+
+ol {
+    counter-reset: ol;
+}
+
+li+li, dd+dt {
+    margin-top: 0.5em;
+}
+
+ul>li {
+    position: relative;
+}
+
+ol>li {
+    position: relative;
+}
+
+li {
+    list-style: none outside none;
+}
+
+small, dd, figcaption {
+    color: var(--color-grey-2);
+    display: block;
+    font-size: 0.8rem;
+    font-style: italic;
+    line-height: 1.2;
+}
+
+/* Tables */
+
+tbody {
+    display: table-row-group
+}
+
+tfoot {
+    display: table-footer-group
+}
+
+table {
+    margin-bottom: 2em;
+    font-size: 0.8em;
+    padding: 0;
+    border-collapse: collapse;
+    box-shadow: 1px 1px 2px var(--color-transparent);
+    -webkit-box-shadow: 1px 1px 2px var(--color-transparent);
+    width: 80%;
+    margin: 0 auto 2em auto
+}
+
+table th, table td {
+    padding: 10px 10px 9px;
+    line-height: 18px;
+    text-align: left
+}
+
+table th {
+    padding-top: 9px;
+    vertical-align: middle
+}
+
+table td {
+    vertical-align: top;
+    border-top: 1px solid var(--color-grey-1);
+}
+
+table tbody th {
+    border-top: 1px solid var(--color-grey-1);
+    vertical-align: top
+}
+
+table {
+    border: 1px solid var(--color-grey-1);
+    border-collapse: separate;
+    *border-collapse: collapse;
+    -webkit-border-radius: 4px;
+    -moz-border-radius: 4px;
+    border-radius: 4px
+}
+
+table th+th, table td+td, table th+td {
+    border-left: 1px solid var(--color-grey-1)
+}
+
+table thead tr:first-child th:first-child, table tbody tr:first-child td:first-child {
+    -webkit-border-radius: 4px 0 0 0;
+    -moz-border-radius: 4px 0 0 0;
+    border-radius: 4px 0 0 0
+}
+
+table thead tr:first-child th:last-child, table tbody tr:first-child td:last-child {
+    -webkit-border-radius: 0 4px 0 0;
+    -moz-border-radius: 0 4px 0 0;
+    border-radius: 0 4px 0 0
+}
+
+table tbody tr:last-child td:first-child {
+    -webkit-border-radius: 0 0 0 4px;
+    -moz-border-radius: 0 0 0 4px;
+    border-radius: 0 0 0 4px
+}
+
+table tbody tr:last-child td:last-child {
+    -webkit-border-radius: 0 0 4px 0;
+    -moz-border-radius: 0 0 4px 0;
+    border-radius: 0 0 4px 0
+}
+
+tbody tr:nth-child(odd) {
+    background-color: rgba(0, 0, 0, 0.03)
+}
+
+caption {
+    display: table-caption;
+    font-weight: 300;
+    font-size: 1.1em;
+    background: var(--color-transparent);
+    padding: 5px;
+    border-radius: 4px;
+    -webkit-border-radius: 4px;
+    margin: 4px 0;
+    box-shadow: 2px 2px 2px var(--color-transparent);
+    -webkit-box-shadow: 2px 2px 2px var(--color-transparent);
+}
+
+/* grey out placeholders */
+
+:-moz-placeholder {
+    color: var(--color-off-white-2);
+}
+
+::-webkit-input-placeholder {
+    color: var(--color-off-white-2);
+}
+
+.article-date {
+    color: var(--color-off-white-2);
+    display: block;
+    font-size: 0.8rem;
+}
+
+/* Title, author, institution, abstract */
+
+.author-list {
+    margin: 0 0 0px;
+    font-weight: 700;
+}
+
+.author-affiliations {
+    margin: 0 0 0px;
+    font-style: italic;
+    font-size: smaller;
+}
+
+.author-correspondence {
+    line-height: 2rem;
+    font-weight: 700;
+    font-size: smaller;
+}
+
+.abstract {
+    margin: 0% 1% 2%;
+    font-weight: 700;
+}
+
+/* References */
+
+.references {
+    line-height: 1.1;
+    font-size: 15px;
+}
+
+div.csl-entry {
+    clear: both;
+    margin-bottom: 0.5em;
+}
+
+.hanging div.csl-entry {
+    margin-left: 2em;
+    text-indent: -2em;
+}
+
+div.csl-left-margin {
+    min-width: 2em;
+    float: left;
+}
+
+div.csl-right-inline {
+    margin-left: 2em;
+    padding-left: 1em;
+}
+
+div.csl-indent {
+    margin-left: 2em;
+}
+
+/* Other pandoc settings */
+
+q {
+    quotes: "ÔÇ£" "ÔÇØ" "ÔÇÿ" "ÔÇÖ";
+}
+
+.display.math {
+    display: block;
+    text-align: center;
+    margin: 0.5rem auto;
+}

+ 207 - 0
example/html_templates/template.html

@@ -0,0 +1,207 @@
+<!DOCTYPE html>
+<html$if(lang)$ lang="$lang$" $endif$>
+
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
+    <meta name="generator" content="pandoc">
+
+    $for(author-meta)$
+    <meta name="author" content="$author-meta$">
+    $endfor$
+
+    $if(date-meta)$
+    <meta name="dcterms.date" content="$date-meta$">
+    $endif$
+
+    $if(keywords)$
+    <meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" />
+    $endif$
+
+    <title>$if(title-prefix)$$title-prefix$ - $endif$$pagetitle$</title>
+    <style type="text/css">
+      code {
+        white-space: pre;
+      }
+    </style>
+
+    $if(quotes)$
+    <style type="text/css">
+      q {
+        quotes: "“""”""‘""’";
+      }
+    </style>
+    $endif$
+
+    $if(highlighting-css)$
+    <style type="text/css">
+      $highlighting-css$
+    </style>
+    $endif$
+
+    $for(css)$
+    <link rel="stylesheet" href="$css$">
+    $endfor$
+
+    $if(math)$
+    $if(mathjax)$
+    $-- MathJax is handled specially. We need to add the data-external attribute
+    $-- so it doesn't get inlined (and thus broken) by the --self-contained option.
+    <script type="text/javascript" id="MathJax-script" async
+      src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js">
+      </script>
+    <script type="text/x-mathjax-config">
+      MathJax.Ajax.config.path["mhchem"] = "https://cdnjs.cloudflare.com/ajax/libs/mathjax-mhchem/3.3.2";
+      MathJax.Hub.Config({
+        TeX: {
+          extensions: ["[mhchem]/mhchem.js"]
+        }
+      });
+    </script>
+    $else$
+    $math$
+    $endif$
+    $endif$
+
+    $for(header-includes)$
+    $header-includes$
+    $endfor$
+
+  </head>
+
+  <body>
+    <div class="wrapper">
+
+      $if(project)$
+      <header>
+        <div class="navbar-left">
+          <input type="checkbox" id="navbar-check">
+          <label for="navbar-check" class="navbar-hamburger">☰</label>
+          <div class="navbar-items">
+            <h1 class="header">$title$</h1>
+            <a class="button" href="manuscript.pdf">Download PDF</a>
+            <a class="button" href="manuscript-SI.pdf">Download SI PDF</a>
+
+            $if(toc)$
+            <nav id="$idprefix$TOC">
+              $toc$
+            </nav>
+            $endif$
+
+          </div>
+        </div>
+      </header>
+      $endif$
+
+      <div class="container">
+        <article typeof="ScholarlyArticle" vocab="http://schema.org/">
+
+          <h1 property="headline">$title$</h1>
+          $if(subtitle)$
+          <p property="alternativeHeadline" class="subtitle">$subtitle$</p>
+          $endif$
+          <p class="author-list">
+            $for(author)$
+            $if(author.last)$ $-- not working!
+            and
+            $endif$
+            <span property="author" typeof="Person">$author.name$</span>
+            <sup>
+              $if(author.correspondence)$
+              $if(author.email)$<a href="mailto:$author.email$">✉</a> $endif$
+              $endif$
+              $for(author.institute_indices)$
+              $author.institute_indices$
+              $sep$,
+              $endfor$
+              $if(author.equal_contributor)$,
+              $if(equal_contributor_symbol)$
+              $equal_contributor_symbol$
+              $else$*
+              $endif$
+              $endif$
+            </sup>$sep$,
+            $endfor$
+          </p>
+          <div class="author-affiliations">
+            $for(institute)$
+            <div class="affiliation"><sup>$institute.index$</sup>$institute.name$$if(institute.address)$,
+              $institute.address$$endif$
+            </div>
+            $endfor$
+          </div>
+          <div class="author-info">
+            $if(has_equal_contributors)$
+            <div class="author-contrib">
+              <sup>$if(equal_contributor_symbol)$$equal_contributor_symbol$$else$*$endif$</sup>These authors contributed
+              equally to this work
+            </div>
+            $endif$
+            $if(has_correspondence)$
+            <div class="author-correspondence">
+              Correspondence: $for(author)$$if(author.correspondence)$$if(author.email)$$author.name$ <a
+                href="mailto:$author.email$">&lt;$author.email$&gt;</a> $endif$$endif$$endfor$
+            </div>
+            $endif$
+          </div>
+
+          $if(abstract)$
+          <span class="abstract" property="description">$abstract$</span>
+          $endif$
+          $if(doi)$<p><a href="https://doi.org/$doi$">doi: $doi$</a></p>$endif$
+
+          $for(include-before)$
+          $include-before$
+          $endfor$
+
+          <div property="articleBody" class="article-body">
+            $body$
+          </div>
+        </article>
+      </div>
+    </div>
+
+  <!--  Image display zoom modal  -->
+    <div id="img-modal" class="img-modal" onclick="this.style.display='none'">
+      <span class="button">&times;</span>
+      <div class="img-modal-content animate-zoom">
+        <img id="img-modal-inner" style="width:100%">
+      </div>
+    </div>
+
+  </body>
+
+  <!--  Small navigation script  -->
+  <script>
+    window.onhashchange = function () {
+      hash = window.location.hash
+      let target = document.querySelector(hash)
+      target.scrollIntoView({
+        behavior: 'smooth',
+        block: 'start'
+      })
+    }
+    document.querySelectorAll('a[href^="#"]').forEach(anchor => {
+      anchor.addEventListener('click', function (e) {
+        let hashval = anchor.getAttribute('href')
+        let target = document.querySelector(hashval)
+        target.scrollIntoView({
+          behavior: 'smooth',
+          block: 'start'
+        })
+        history.pushState(null, null, hashval)
+        e.preventDefault()
+      });
+    });
+  </script>
+
+  <!--  Image highlight script  -->
+  <script>
+    function onClickImage(element) {
+      document.getElementById("img-modal-inner").src = element.src;
+      document.getElementById("img-modal").style.display = "block";
+    }
+  </script>
+
+  </html>

+ 91 - 0
example/manuscript.md

@@ -0,0 +1,91 @@
+---
+author:
+- Paul Iacomi:
+    correspondence: yes
+    email: mail\@pauliacomi.com
+    equal_contributor: yes
+    institute:
+    - a
+    - b
+    orcid: 0000-0001-5477-1503
+- Someone Else:
+    equal_contributor: yes
+    institute:
+    - a
+    orcid: 0000-0001-5124-7052
+autoEqnLabels: true
+bibliography:
+- refs/biblio.bib
+cref: false
+institute:
+- a:
+    name: My current affiliation, with address and everything.
+- b:
+    name: Long address from someone else or other affiliation
+link-citations: true
+linkReferences: true
+number-sections: true
+project:
+  title: project
+title: This is the paper title
+xnos-capitalise: true
+xnos-number-by-section: false
+---
+
+# Abstract
+
+# Introduction
+
+Herein we refer to a table ([@tbl:example-table]), but also to a figure ([@fig:caption-1]) or a
+latter equation ([@eq:example]). Finally, figures ([@fig:caption-si]) from the SI can also be
+referenced. We can add citations as well [@example]. Units are inserted with the help of `siunitx`.
+We can have some standard data 40 kJ/mol or ranges such as 20 Å--30 Å. Finally simple unit
+typesetting is also possible MHz/kPa.
+
+Chemistry is included by referring to the `mhchem` package. Simple molecules like $\ce{N2}$ and
+$\ce{C2H4}$ should be easy to include. More complex formula typesetting is possible too:
+$\ce{^{13}C}$ NMR, $\ce{CaCl2 * 12H2O}$ and $\ce{Fe^{II}Fe^{III}2O4}$.
+
+Equations are in a standard Latex `equation` environment.
+
+$$
+    e^{i\pi} + 1 = 0$$ {#eq:example}
+
+# Materials and methods
+
+::: {#tbl:example-table}
+                Head 1                 Head 2            Head 3
+  ---------------------------------- ----------- -----------------------
+              Content 1               Content 2      Long Content 2
+              Content 4               Content 5   Even Longer Content 6
+   \* Multicolmns are also possible              
+
+  :  An example table, with caption on top.
+:::
+
+# Results and discussion
+
+![ Example small figure and its caption. ](figs/example-image.png){#fig:caption-1
+width="0.9\\linewidth"}
+
+![ Example twocolumn large figure. ](figs/example-image.png){#fig:caption-2 width="0.9\\linewidth"}
+
+# Conclusions
+
+# Acknowledgements {#acknowledgements .unnumbered}
+
+# Author contributions {#author-contributions .unnumbered}
+
+# Supplementary Information
+
+## SI section 1
+
+Here is a citation. [@example]
+
+![ Example caption. ](figs/example-image.png){#fig:caption-si width="0.9\\linewidth"}
+
+## SI section 2
+
+We are referring to previous [@fig:caption-si].
+
+# References {#references .unnumbered}

+ 0 - 0
example/makefile → example/old_makefile


+ 0 - 2
example/slides.md

@@ -3,8 +3,6 @@ title: Marp slide deck
 description: An example slide deck created by Marp CLI
 author: Yuki Hattori
 keywords: marp,marp-cli,slide
-#backgroundImage: url('0.png')
-#_backgroundImage: url('4.png')
 footer: 25/04/2022
 _footer: ""
 

+ 386 - 0
example/tex_templates/ieee.csl

@@ -0,0 +1,386 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="sort-only">
+  <info>
+    <title>IEEE</title>
+    <id>http://www.zotero.org/styles/ieee</id>
+    <link href="http://www.zotero.org/styles/ieee" rel="self"/>
+    <link href="https://ieeeauthorcenter.ieee.org/wp-content/uploads/IEEE-Reference-Guide.pdf" rel="documentation"/>
+    <link href="https://journals.ieeeauthorcenter.ieee.org/your-role-in-article-production/ieee-editorial-style-manual/" rel="documentation"/>
+    <author>
+      <name>Michael Berkowitz</name>
+      <email>mberkowi@gmu.edu</email>
+    </author>
+    <contributor>
+      <name>Julian Onions</name>
+      <email>julian.onions@gmail.com</email>
+    </contributor>
+    <contributor>
+      <name>Rintze Zelle</name>
+      <uri>http://twitter.com/rintzezelle</uri>
+    </contributor>
+    <contributor>
+      <name>Stephen Frank</name>
+      <uri>http://www.zotero.org/sfrank</uri>
+    </contributor>
+    <contributor>
+      <name>Sebastian Karcher</name>
+    </contributor>
+    <contributor>
+      <name>Giuseppe Silano</name>
+      <email>g.silano89@gmail.com</email>
+      <uri>http://giuseppesilano.net</uri>
+    </contributor>
+    <contributor>
+      <name>Patrick O'Brien</name>
+    </contributor>
+    <category citation-format="numeric"/>
+    <category field="engineering"/>
+    <category field="generic-base"/>
+    <summary>IEEE style as per the 2018 guidelines, V 11.12.2018.</summary>
+    <updated>2020-03-28T21:02:10+00:00</updated>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
+  </info>
+  <locale xml:lang="en">
+    <terms>
+      <term name="chapter" form="short">ch.</term>
+      <term name="presented at">presented at the</term>
+      <term name="available at">available</term>
+    </terms>
+  </locale>
+  <!-- Macros -->
+  <macro name="status">
+    <choose>
+      <if variable="page issue volume" match="none">
+        <text variable="status" text-case="capitalize-first" suffix="" font-weight="bold"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="edition">
+    <choose>
+      <if type="bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="any">
+        <choose>
+          <if is-numeric="edition">
+            <group delimiter=" ">
+              <number variable="edition" form="ordinal"/>
+              <text term="edition" form="short"/>
+            </group>
+          </if>
+          <else>
+            <text variable="edition" text-case="capitalize-first" suffix="."/>
+          </else>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="issued">
+    <choose>
+      <if type="article-journal report" match="any">
+        <date variable="issued">
+          <date-part name="month" form="short" suffix=" "/>
+          <date-part name="year" form="long"/>
+        </date>
+      </if>
+      <else-if type="bill book chapter graphic legal_case legislation motion_picture song thesis" match="any">
+        <date variable="issued">
+          <date-part name="year" form="long"/>
+        </date>
+      </else-if>
+      <else-if type="paper-conference" match="any">
+        <date variable="issued">
+          <date-part name="month" form="short"/>
+          <date-part name="year" prefix=" "/>
+        </date>
+      </else-if>
+      <else>
+        <date variable="issued">
+          <date-part name="month" form="short" suffix=" "/>
+          <date-part name="day" form="numeric-leading-zeros" suffix=", "/>
+          <date-part name="year"/>
+        </date>
+      </else>
+    </choose>
+  </macro>
+  <macro name="author">
+    <names variable="author">
+      <name and="text" et-al-min="7" et-al-use-first="1" initialize-with=". "/>
+      <label form="short" prefix=", " text-case="capitalize-first"/>
+      <et-al font-style="italic"/>
+      <substitute>
+        <names variable="editor"/>
+        <names variable="translator"/>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="editor">
+    <names variable="editor">
+      <name initialize-with=". " delimiter=", " and="text"/>
+      <label form="short" prefix=", " text-case="capitalize-first"/>
+    </names>
+  </macro>
+  <macro name="locators">
+    <group delimiter=", ">
+      <text macro="edition"/>
+      <group delimiter=" ">
+        <text term="volume" form="short"/>
+        <number variable="volume" form="numeric"/>
+      </group>
+      <group delimiter=" ">
+        <number variable="number-of-volumes" form="numeric"/>
+        <text term="volume" form="short" plural="true"/>
+      </group>
+      <group delimiter=" ">
+        <text term="issue" form="short"/>
+        <number variable="issue" form="numeric"/>
+      </group>
+    </group>
+  </macro>
+  <macro name="title">
+    <choose>
+      <if type="bill book graphic legal_case legislation motion_picture song" match="any">
+        <text variable="title" font-style="italic"/>
+      </if>
+      <else>
+        <text variable="title" quotes="true"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="publisher">
+    <choose>
+      <if type="bill book chapter graphic legal_case legislation motion_picture paper-conference song" match="any">
+        <group delimiter=": ">
+          <text variable="publisher-place"/>
+          <text variable="publisher"/>
+        </group>
+      </if>
+      <else>
+        <group delimiter=", ">
+          <text variable="publisher"/>
+          <text variable="publisher-place"/>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="event">
+    <choose>
+      <if type="paper-conference speech" match="any">
+        <choose>
+          <!-- Published Conference Paper -->
+          <if variable="container-title">
+            <group delimiter=", ">
+              <group delimiter=" ">
+                <text term="in"/>
+                <text variable="container-title" font-style="italic"/>
+              </group>
+              <text variable="event-place"/>
+            </group>
+          </if>
+          <!-- Unpublished Conference Paper -->
+          <else>
+            <group delimiter=", ">
+              <group delimiter=" ">
+                <text term="presented at"/>
+                <text variable="event"/>
+              </group>
+              <text variable="event-place"/>
+            </group>
+          </else>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="access">
+    <choose>
+      <if type="webpage post post-weblog" match="any">
+        <choose>
+          <if variable="URL">
+            <group delimiter=" ">
+              <text variable="URL"/>
+              <group delimiter=" " prefix="(" suffix=")">
+                <text term="accessed"/>
+                <date variable="accessed">
+                  <date-part name="month" form="short" strip-periods="false"/>
+                  <date-part name="day" form="numeric-leading-zeros" prefix=" " suffix=", "/>
+                  <date-part name="year" form="long"/>
+                </date>
+              </group>
+            </group>
+          </if>
+        </choose>
+      </if>
+      <else-if match="any" variable="DOI">
+        <text variable="DOI" prefix="doi: "/>
+      </else-if>
+      <else>
+        <group delimiter=". ">
+          <group delimiter=": ">
+            <text term="accessed" text-case="capitalize-first"/>
+            <date variable="accessed">
+              <date-part name="month" form="short" suffix=" "/>
+              <date-part name="day" form="numeric-leading-zeros" suffix=", "/>
+              <date-part name="year"/>
+            </date>
+          </group>
+          <text term="online" prefix="[" suffix="]" text-case="capitalize-first"/>
+          <group delimiter=": ">
+            <text term="available at" text-case="capitalize-first"/>
+            <text variable="URL"/>
+          </group>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="page">
+    <group>
+      <label variable="page" form="short" suffix=" "/>
+      <text variable="page"/>
+    </group>
+  </macro>
+  <macro name="citation-locator">
+    <group delimiter=" ">
+      <choose>
+        <if locator="page">
+          <label variable="locator" form="short"/>
+        </if>
+        <else>
+          <label variable="locator" form="short" text-case="capitalize-first"/>
+        </else>
+      </choose>
+      <text variable="locator"/>
+    </group>
+  </macro>
+  <!-- Citation -->
+  <citation collapse="citation-number">
+    <sort>
+      <key variable="citation-number"/>
+    </sort>
+    <layout delimiter=", ">
+      <group prefix="[" suffix="]" delimiter=", ">
+        <text variable="citation-number"/>
+        <text macro="citation-locator"/>
+      </group>
+    </layout>
+  </citation>
+  <!-- Bibliography -->
+  <bibliography entry-spacing="0" second-field-align="flush">
+    <layout suffix=".">
+      <!-- Citation Number -->
+      <text variable="citation-number" prefix="[" suffix="]"/>
+      <!-- Author(s) -->
+      <text macro="author" suffix=", "/>
+      <!-- Rest of Citation -->
+      <choose>
+        <!-- Specific Formats -->
+        <if type="article-journal">
+          <group delimiter=", ">
+            <text macro="title"/>
+            <text variable="container-title" font-style="italic" form="short"/>
+            <text macro="locators"/>
+            <text macro="page"/>
+            <text macro="issued"/>
+            <text macro="status"/>
+            <text macro="access"/>
+          </group>
+        </if>
+        <else-if type="paper-conference speech" match="any">
+          <group delimiter=", ">
+            <text macro="title"/>
+            <text macro="event"/>
+            <text macro="issued"/>
+            <text macro="locators"/>
+            <text macro="page"/>
+            <text macro="status"/>
+            <text macro="access"/>
+          </group>
+        </else-if>
+        <else-if type="report">
+          <group delimiter=". ">
+            <group delimiter=", ">
+              <text macro="title"/>
+              <text macro="publisher"/>
+              <group delimiter=" ">
+                <text variable="genre"/>
+                <text variable="number"/>
+              </group>
+              <text macro="issued"/>
+            </group>
+            <text macro="access"/>
+          </group>
+        </else-if>
+        <else-if type="thesis">
+          <group delimiter=", ">
+            <text macro="title"/>
+            <text variable="genre"/>
+            <text macro="publisher"/>
+            <text macro="issued"/>
+          </group>
+        </else-if>
+        <else-if type="webpage post-weblog post" match="any">
+          <group delimiter=", " suffix=". ">
+            <text macro="title"/>
+            <text variable="container-title" font-style="italic"/>
+            <text macro="issued"/>
+          </group>
+          <text macro="access"/>
+        </else-if>
+        <else-if type="patent">
+          <group delimiter=", ">
+            <text macro="title"/>
+            <text variable="number"/>
+            <text macro="issued"/>
+          </group>
+        </else-if>
+        <!-- Generic/Fallback Formats -->
+        <else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+          <group delimiter=", " suffix=". ">
+            <text macro="title"/>
+            <text macro="locators"/>
+          </group>
+          <group delimiter=", ">
+            <text macro="publisher"/>
+            <text macro="issued"/>
+            <text macro="page"/>
+          </group>
+        </else-if>
+        <else-if type="article-magazine article-newspaper broadcast interview manuscript map patent personal_communication song speech thesis webpage" match="any">
+          <group delimiter=", ">
+            <text macro="title"/>
+            <text variable="container-title" font-style="italic"/>
+            <text macro="locators"/>
+            <text macro="publisher"/>
+            <text macro="page"/>
+            <text macro="issued"/>
+          </group>
+        </else-if>
+        <else-if type="chapter paper-conference" match="any">
+          <group delimiter=", " suffix=", ">
+            <text macro="title"/>
+            <group delimiter=" ">
+              <text term="in"/>
+              <text variable="container-title" font-style="italic"/>
+            </group>
+            <text macro="locators"/>
+          </group>
+          <text macro="editor" suffix=" "/>
+          <group delimiter=", ">
+            <text macro="publisher"/>
+            <text macro="issued"/>
+            <text macro="page"/>
+          </group>
+        </else-if>
+        <else>
+          <group delimiter=", " suffix=". ">
+            <text macro="title"/>
+            <text variable="container-title" font-style="italic"/>
+            <text macro="locators"/>
+          </group>
+          <group delimiter=", ">
+            <text macro="publisher"/>
+            <text macro="page"/>
+            <text macro="issued"/>
+            <text macro="access"/>
+          </group>
+        </else>
+      </choose>
+    </layout>
+  </bibliography>
+</style>

+ 33 - 0
example/tex_templates/manuscript-SI.tex

@@ -0,0 +1,33 @@
+% Master SI file
+
+% Documentclass
+\documentclass[11pt, SI]{templates/pi/pi-article}
+
+% Graphics
+\graphicspath{ {figs/} }
+
+% Metadata
+\input{templates/metadata}
+
+% Preamble
+\input{templates/pi/pi-preamble}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\begin{document}
+
+% Doc input
+\input{templates/pi/pi-doc}
+
+\pagebreak
+\tableofcontents
+
+\pagebreak
+\input{docs/SI/.si-content}
+
+\pagebreak
+\bibliography{refs/biblio}
+
+% End doc
+\end{document}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Деякі файли не було показано, через те що забагато файлів було змінено