git.iko.soy/typeable/pandoc
on master help sign in
.circleci/config.yml+1−1
since splitsnapshots
unifiedsplit
@@ -2,7 +2,7 @@ version: "2.1"
2jobs:
2jobs:
3 build:
3 build:
4 macos:
4 macos:
5− xcode: 9.4.1
5+ xcode: 11.1.0
6 environment:
6 environment:
7 HOMEBREW_NO_AUTO_UPDATE: 1
7 HOMEBREW_NO_AUTO_UPDATE: 1
8 steps:
8 steps:
.editorconfig+8
@@ -8,6 +8,14 @@ indent_size = 2
8insert_final_newline = true
8insert_final_newline = true
9trim_trailing_whitespace = true
9trim_trailing_whitespace = true
10
10
11+[*.{zip,docx}]
12+charset =
13+end_of_line =
14+indent_style =
15+indent_size =
16+insert_final_newline =
17+trim_trailing_whitespace =
18+
11[*.{markdown,md}]
19[*.{markdown,md}]
12trim_trailing_whitespace = false
20trim_trailing_whitespace = false
13
21
.github/ISSUE_TEMPLATEdeleted−11
@@ -1,11 +0,0 @@
1−Asking a question?
2−Please use the pandoc-discuss mailing list instead:
3−https://groups.google.com/forum/#!forum/pandoc-discuss
4−This tracker is for bug reports and enhancement requests.
5−
6−Reporting a bug?
7−Please include your pandoc version and an example that allows us
8−to reproduce the problem (complete input, exact command line
9−used, expected and actual output). The smaller the example, the
10−better.
11−
.github/ISSUE_TEMPLATE/bug_report.mdnew file+25
@@ -0,0 +1,25 @@
1+---
2+name: Bug report
3+about: Create a report to help us improve
4+title: ''
5+labels: 'bug'
6+assignees: ''
7+
8+---
9+
10+<!--
11+Thank you for reporting an issue! Before you continue, please make sure that you have
12+
13+- searched the issue tracker for similar issues (including closed issues): https://github.com/jgm/pandoc/issues
14+- searched the pandoc-discuss mailing list for solutions: https://groups.google.com/forum/#!forum/pandoc-discuss
15+- reproduced your issue on the latest release of pandoc, or on https://pandoc.org/try
16+
17+Note that this bug tracker is for reporting bugs, not asking questions. For questions, use the pandoc-discuss mailing list.
18+-->
19+
20+**Explain the problem.**
21+Include the exact command line you used and all inputs necessary to reproduce the issue. Please create as minimal an example as possible, to help the maintainers isolate the problem. Explain the output you received and how it differs from what you expected.
22+
23+**Pandoc version?**
24+What version of pandoc are you using, on what OS?
25+
.github/ISSUE_TEMPLATE/config.ymlnew file+9
@@ -0,0 +1,9 @@
1+blank_issues_enabled: false
2+contact_links:
3+ - name: Ask a question
4+ url: https://groups.google.com/forum/#!forum/pandoc-discuss
5+ about: "Discussion forum for pandoc (may be used as an email list)"
6+ - name: Contributing Guidelines
7+ url: https://pandoc.org/CONTRIBUTING.html
8+ about: "Guidelines for submitting bug reports and code improvements"
9+
.github/ISSUE_TEMPLATE/feature_request.mdnew file+21
@@ -0,0 +1,21 @@
1+---
2+name: Feature request
3+about: Suggest an idea for this project
4+title: ''
5+labels: 'enhancement'
6+assignees: ''
7+
8+---
9+
10+<!--
11+Thank you for suggesting a feature! Before you continue, please make sure that you have
12+
13+- read the contributing guidelines: https://pandoc.org/CONTRIBUTING.html
14+- searched the issue tracker for similar issues (including closed issues): https://github.com/jgm/pandoc/issues
15+- searched the pandoc-discuss mailing list for relevant discussions: https://groups.google.com/forum/#!forum/pandoc-discuss
16+-->
17+
18+**Describe your proposed improvement and the problem it solves.**
19+
20+**Describe alternatives you've considered.**
21+
.github/workflows/ci.yml+21−6
@@ -44,32 +44,47 @@ jobs:
44 matrix:
44 matrix:
45 versions:
45 versions:
46 - ghc: '8.0.2'
46 - ghc: '8.0.2'
47− cabal: '2.2'
47+ cabal: '2.4'
48− prefix: 'new-'
48+ prefix: 'v2-'
49+ cabalopts: ''
49 testopts: ''
50 testopts: ''
50 - ghc: '8.2.2'
51 - ghc: '8.2.2'
51 cabal: '2.4'
52 cabal: '2.4'
52 prefix: 'v2-'
53 prefix: 'v2-'
54+ cabalopts: ''
53 testopts: ''
55 testopts: ''
54 - ghc: '8.4.4'
56 - ghc: '8.4.4'
55 cabal: '2.4'
57 cabal: '2.4'
56 prefix: 'v2-'
58 prefix: 'v2-'
59+ cabalopts: '-f-embed_data_files'
57 testopts: ''
60 testopts: ''
58 - ghc: '8.6.5'
61 - ghc: '8.6.5'
59 cabal: '3.2'
62 cabal: '3.2'
60 prefix: ''
63 prefix: ''
64+ cabalopts: ''
61 testopts: '--test-option=--hide-successes'
65 testopts: '--test-option=--hide-successes'
62 - ghc: '8.8.4'
66 - ghc: '8.8.4'
63 cabal: '3.2'
67 cabal: '3.2'
64 prefix: ''
68 prefix: ''
69+ cabalopts: ''
65 testopts: '--test-option=--hide-successes'
70 testopts: '--test-option=--hide-successes'
66− - ghc: '8.10.2'
71+ - ghc: '8.10.4'
67 cabal: '3.2'
72 cabal: '3.2'
68 prefix: ''
73 prefix: ''
74+ cabalopts: '-ftrypandoc'
75+ testopts: '--test-option=--hide-successes'
76+ - ghc: '9.0.1'
77+ cabal: '3.4'
78+ prefix: ''
79+ cabalopts: ''
69 testopts: '--test-option=--hide-successes'
80 testopts: '--test-option=--hide-successes'
70 steps:
81 steps:
71 - uses: actions/checkout@v2
82 - uses: actions/checkout@v2
72
83
84+ # needed by memory
85+ - name: Install numa
86+ run: sudo apt-get install libnuma-dev
87+
73 # need to install older cabal/ghc versions from ppa repository
88 # need to install older cabal/ghc versions from ppa repository
74
89
75 - name: Install recent cabal/ghc
90 - name: Install recent cabal/ghc
@@ -101,14 +116,14 @@ jobs:
101 - name: Install dependencies
116 - name: Install dependencies
102 run: |
117 run: |
103 cabal ${{ matrix.versions.prefix }}update
118 cabal ${{ matrix.versions.prefix }}update
104− cabal ${{ matrix.versions.prefix }}build --dependencies-only --enable-tests --disable-optimization
119+ cabal ${{ matrix.versions.prefix }}build ${{ matrix.versions.cabalopts }} --dependencies-only --enable-tests --disable-optimization
105
120
106 - name: Build and test
121 - name: Build and test
107 run: |
122 run: |
108− cabal ${{ matrix.versions.prefix }}build --enable-tests --disable-optimization 2>&1 | tee build.log
123+ cabal ${{ matrix.versions.prefix }}build ${{ matrix.versions.cabalopts }} --enable-tests --disable-optimization 2>&1 | tee build.log
109 # fail if warnings in local build
124 # fail if warnings in local build
110 ! grep -q ": *[Ww]arning:" build.log || exit 1
125 ! grep -q ": *[Ww]arning:" build.log || exit 1
111− cabal ${{ matrix.versions.prefix }}test --disable-optimization ${{ matrix.versions.testopts }}
126+ cabal ${{ matrix.versions.prefix }}test ${{ matrix.versions.cabalopts }} --disable-optimization ${{ matrix.versions.testopts }}
112
127
113 windows:
128 windows:
114
129
.github/workflows/nightly.yml+2−2
@@ -22,10 +22,10 @@ jobs:
22 ghc --version
22 ghc --version
23 cabal --version
23 cabal --version
24 cabal v2-update
24 cabal v2-update
25− cabal v2-build --dependencies-only all
25+ cabal v2-build --dependencies-only
26 - name: Build
26 - name: Build
27 run: |
27 run: |
28− cabal v2-install all
28+ cabal v2-install
29 strip $HOME/.cabal/bin/pandoc
29 strip $HOME/.cabal/bin/pandoc
30 - name: Install artifact
30 - name: Install artifact
31 run: |
31 run: |
.hlint.yaml+1
@@ -9,6 +9,7 @@
9# Ignore some builtin hints
9# Ignore some builtin hints
10#
10#
11- ignore: {name: "Avoid lambda"}
11- ignore: {name: "Avoid lambda"}
12+- ignore: {name: "Use bimap"}
12- ignore: {name: "Eta reduce"}
13- ignore: {name: "Eta reduce"}
13- ignore: {name: "Evaluate"}
14- ignore: {name: "Evaluate"}
14- ignore: {name: "Reduce duplication"} # TODO: could be more fine-grained
15- ignore: {name: "Reduce duplication"} # TODO: could be more fine-grained
AUTHORS.md+14
@@ -20,6 +20,7 @@
20- Andreas Lööw
20- Andreas Lööw
21- Andrew Dunning
21- Andrew Dunning
22- Andy Morris
22- Andy Morris
23+- Anti-Distinctlyminty
23- Antoine Latter
24- Antoine Latter
24- Antonio Terceiro
25- Antonio Terceiro
25- Arata Mizuki
26- Arata Mizuki
@@ -35,6 +36,7 @@
35- Benoit Schweblin
36- Benoit Schweblin
36- Bjorn Buckwalter
37- Bjorn Buckwalter
37- Blake Eryx
38- Blake Eryx
39+- Bodigrim
38- Bradley Kuhn
40- Bradley Kuhn
39- Brent Yorgey
41- Brent Yorgey
40- Brian Leung
42- Brian Leung
@@ -45,6 +47,7 @@
45- Carlos Sosa
47- Carlos Sosa
46- Cécile Chemin
48- Cécile Chemin
47- Cédric Couralet
49- Cédric Couralet
50+- Charanjit Singh
48- Chris Black
51- Chris Black
49- Christian Conkle
52- Christian Conkle
50- Christian Despres
53- Christian Despres
@@ -75,8 +78,10 @@
75- Eigil Rischel
78- Eigil Rischel
76- Emanuel Evans
79- Emanuel Evans
77- Emerson Harkin
80- Emerson Harkin
81+- Emily Bourke
78- Emily Eisenberg
82- Emily Eisenberg
79- Eric Kow
83- Eric Kow
84+- Erik Rask
80- Eric Seidel
85- Eric Seidel
81- Eric Schrijver
86- Eric Schrijver
82- Ethan Riley
87- Ethan Riley
@@ -86,6 +91,7 @@
86- Florian Beeres
91- Florian Beeres
87- Florian Eitel
92- Florian Eitel
88- Florian Klink
93- Florian Klink
94+- Florian Kohrt
89- Francesco Occhipinti
95- Francesco Occhipinti
90- François Gannaz
96- François Gannaz
91- Frederik Elwert
97- Frederik Elwert
@@ -146,6 +152,7 @@
146- Josef Svenningsson
152- Josef Svenningsson
147- Joseph C. Sible
153- Joseph C. Sible
148- Julien Cretel
154- Julien Cretel
155+- Julien Dutant
149- Juliette Fourcot
156- Juliette Fourcot
150- Juliusz Gonera
157- Juliusz Gonera
151- Justin Bogner
158- Justin Bogner
@@ -228,6 +235,7 @@
228- Raymond Ehlers
235- Raymond Ehlers
229- Recai Oktaş
236- Recai Oktaş
230- Roland Hieber
237- Roland Hieber
238+- Roman Beránek
231- RyanGlScott
239- RyanGlScott
232- Salim B
240- Salim B
233- Sascha Wilde
241- Sascha Wilde
@@ -245,6 +253,7 @@
245- Stefan Dresselhaus
253- Stefan Dresselhaus
246- Sumit Sahrawat
254- Sumit Sahrawat
247- Tarik Graba
255- Tarik Graba
256+- Tatiana Porras
248- Thenaesh Elango
257- Thenaesh Elango
249- Thomas Hodgson
258- Thomas Hodgson
250- Thomas Weißschuh
259- Thomas Weißschuh
@@ -278,6 +287,7 @@
278- a-vrma
287- a-vrma
279- andrebauer
288- andrebauer
280- argent0
289- argent0
290+- badumont
281- blmage
291- blmage
282- bucklereed
292- bucklereed
283- bumper314
293- bumper314
@@ -293,8 +303,11 @@
293- kaizshang91
303- kaizshang91
294- lux-lth
304- lux-lth
295- lwolfsonkin
305- lwolfsonkin
306+- mbrackeantidot
296- nkalvi
307- nkalvi
297- niszet
308- niszet
309+- nuew
310+- obcat
298- oltolm
311- oltolm
299- oquechy
312- oquechy
300- quasicomputational
313- quasicomputational
@@ -306,6 +319,7 @@
306- shreevatsa.public
319- shreevatsa.public
307- takahashim
320- takahashim
308- taotieren
321- taotieren
322+- tecosaur
309- TEC
323- TEC
310- tgkokk
324- tgkokk
311- the-solipsist
325- the-solipsist
CONTRIBUTING.md+6−5
@@ -406,11 +406,11 @@ The library is structured as follows:
406 tree automatically.
406 tree automatically.
407 - `Text.Pandoc.Readers.*` are the readers, and `Text.Pandoc.Writers.*`
407 - `Text.Pandoc.Readers.*` are the readers, and `Text.Pandoc.Writers.*`
408 are the writers.
408 are the writers.
409− - `Text.Pandoc.Biblio` is a utility module for formatting citations
409+ - `Text.Pandoc.Citeproc.*` contain the code for citation handling,
410− using citeproc-hs.
410+ including an interface to the [citeproc] library.
411 - `Text.Pandoc.Data` is used to embed data files when the `embed_data_files`
411 - `Text.Pandoc.Data` is used to embed data files when the `embed_data_files`
412− cabal flag is used. It is generated from `src/Text/Pandoc/Data.hsb` using
412+ cabal flag is used.
413− the preprocessor [hsb2hs].
413+ - `Text.Pandoc.Emoji` is a thin wrapper around [emojis].
414 - `Text.Pandoc.Highlighting` contains the interface to the
414 - `Text.Pandoc.Highlighting` contains the interface to the
415 skylighting library, which is used for code syntax highlighting.
415 skylighting library, which is used for code syntax highlighting.
416 - `Text.Pandoc.ImageSize` is a utility module containing functions for
416 - `Text.Pandoc.ImageSize` is a utility module containing functions for
@@ -421,7 +421,6 @@ The library is structured as follows:
421 - `Text.Pandoc.PDF` contains functions for producing a PDF from a
421 - `Text.Pandoc.PDF` contains functions for producing a PDF from a
422 LaTeX source.
422 LaTeX source.
423 - `Text.Pandoc.Parsing` contains parsing functions used in multiple readers.
423 - `Text.Pandoc.Parsing` contains parsing functions used in multiple readers.
424− - `Text.Pandoc.Pretty` is a pretty-printing library specialized to
425 the needs of pandoc.
424 the needs of pandoc.
426 - `Text.Pandoc.SelfContained` contains functions for making an HTML
425 - `Text.Pandoc.SelfContained` contains functions for making an HTML
427 file "self-contained," by importing remotely linked images, CSS,
426 file "self-contained," by importing remotely linked images, CSS,
@@ -456,6 +455,8 @@ you may want to consider submitting a pull request to the
456[EditorConfig]: https://editorconfig.org/
455[EditorConfig]: https://editorconfig.org/
457[Haskell platform]: https://www.haskell.org/platform/
456[Haskell platform]: https://www.haskell.org/platform/
458[hlint]: https://hackage.haskell.org/package/hlint
457[hlint]: https://hackage.haskell.org/package/hlint
458+[citeproc]: https://hackage.haskell.org/package/citeproc
459+[emojis]: https://hackage.haskell.org/package/emojis
459[hsb2hs]: https://hackage.haskell.org/package/hsb2hs
460[hsb2hs]: https://hackage.haskell.org/package/hsb2hs
460[pre-commit hook]: https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
461[pre-commit hook]: https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
461[GitHub labels]: https://github.com/jgm/pandoc/labels
462[GitHub labels]: https://github.com/jgm/pandoc/labels
INSTALL.md+4
@@ -34,6 +34,10 @@ without SVG support), [Python] (to use Pandoc filters), and
34
34
35 choco install rsvg-convert python miktex
35 choco install rsvg-convert python miktex
36
36
37+Using multiple installation methods can result in two separate
38+installations of pandoc; it is recommended to properly uninstall
39+pandoc before switching to an alternative installation method.
40+
37By default, Pandoc creates PDFs using LaTeX.
41By default, Pandoc creates PDFs using LaTeX.
38We recommend installing it via [MiKTeX].
42We recommend installing it via [MiKTeX].
39
43
MANUAL.txt+176−62
@@ -1,7 +1,7 @@
1---
1---
2title: Pandoc User's Guide
2title: Pandoc User's Guide
3author: John MacFarlane
3author: John MacFarlane
4−date: March 8, 2021
4+date: June 20, 2021
5---
5---
6
6
7# Synopsis
7# Synopsis
@@ -675,12 +675,12 @@ header when requesting a document from a URL:
675: Extract images and other media contained in or linked from
675: Extract images and other media contained in or linked from
676 the source document to the path *DIR*, creating it if
676 the source document to the path *DIR*, creating it if
677 necessary, and adjust the images references in the document
677 necessary, and adjust the images references in the document
678− so they point to the extracted files. If the source format is
678+ so they point to the extracted files. Media are downloaded,
679− a binary container (docx, epub, or odt), the media is
679+ read from the file system, or extracted from a binary
680− extracted from the container and the original
680+ container (e.g. docx), as needed. The original file paths
681− filenames are used. Otherwise the media is read from the
681+ are used if they are relative paths not containing `..`.
682− file system or downloaded, and new filenames are constructed
682+ Otherwise filenames are constructed from the SHA1 hash of
683− based on SHA1 hashes of the contents.
683+ the contents.
684
684
685`--abbreviations=`*FILE*
685`--abbreviations=`*FILE*
686
686
@@ -1415,13 +1415,12 @@ results only for basic math, usually you will want to use
1415`--gladtex`
1415`--gladtex`
1416
1416
1417: Enclose TeX math in `<eq>` tags in HTML output. The resulting HTML
1417: Enclose TeX math in `<eq>` tags in HTML output. The resulting HTML
1418− can then be processed by [GladTeX] to produce images of the typeset
1418+ can then be processed by [GladTeX] to produce SVG images of the typeset
1419− formulas and an HTML file with links to these images.
1419+ formulas and an HTML file with these images embedded.
1420− So, the procedure is:
1421
1420
1422 pandoc -s --gladtex input.md -o myfile.htex
1421 pandoc -s --gladtex input.md -o myfile.htex
1423− gladtex -d myfile-images myfile.htex
1422+ gladtex -d image_dir myfile.htex
1424− # produces myfile.html and images in myfile-images
1423+ # produces myfile.html and images in image_dir
1425
1424
1426[MathML]: https://www.w3.org/Math/
1425[MathML]: https://www.w3.org/Math/
1427[MathJax]: https://www.mathjax.org
1426[MathJax]: https://www.mathjax.org
@@ -2315,8 +2314,8 @@ math equations flush left using [YAML metadata](#layout) or with
2315
2314
2316These affect HTML output when [producing slide shows with pandoc].
2315These affect HTML output when [producing slide shows with pandoc].
2317
2316
2318−All [reveal.js configuration options] are available as variables.
2317+`institute`
2319−To turn off boolean flags that default to true in reveal.js, use `0`.
2318+: author affiliations: can be a list when there are multiple authors
2320
2319
2321`revealjs-url`
2320`revealjs-url`
2322: base URL for reveal.js documents (defaults to
2321: base URL for reveal.js documents (defaults to
@@ -2336,6 +2335,9 @@ To turn off boolean flags that default to true in reveal.js, use `0`.
2336: additional attributes for the title slide of reveal.js slide shows.
2335: additional attributes for the title slide of reveal.js slide shows.
2337 See [background in reveal.js and beamer] for an example.
2336 See [background in reveal.js and beamer] for an example.
2338
2337
2338+All [reveal.js configuration options] are available as variables.
2339+To turn off boolean flags that default to true in reveal.js, use `0`.
2340+
2339[reveal.js configuration options]: https://revealjs.com/config/
2341[reveal.js configuration options]: https://revealjs.com/config/
2340
2342
2341### Variables for Beamer slides
2343### Variables for Beamer slides
@@ -3752,7 +3754,7 @@ definition:
3752Note that space between items in a definition list is required.
3754Note that space between items in a definition list is required.
3753(A variant that loosens this requirement, but disallows "lazy"
3755(A variant that loosens this requirement, but disallows "lazy"
3754hard wrapping, can be activated with `compact_definition_lists`: see
3756hard wrapping, can be activated with `compact_definition_lists`: see
3755−[Non-pandoc extensions], below.)
3757+[Non-default extensions], below.)
3756
3758
3757[^3]: I have been influenced by the suggestions of [David
3759[^3]: I have been influenced by the suggestions of [David
3758 Wheeler](https://justatheory.com/2009/02/modest-markdown-proposal/).
3760 Wheeler](https://justatheory.com/2009/02/modest-markdown-proposal/).
@@ -4177,10 +4179,12 @@ option is used. All of the metadata will appear in a single block
4177at the beginning of the document.
4179at the beginning of the document.
4178
4180
4179Note that [YAML] escaping rules must be followed. Thus, for example,
4181Note that [YAML] escaping rules must be followed. Thus, for example,
4180−if a title contains a colon, it must be quoted. The pipe character
4182+if a title contains a colon, it must be quoted, and if it contains a
4183+backslash escape, then it must be ensured that it is not treated as a
4184+[YAML escape sequence]. The pipe character (`|`) can be used to begin
4181−(`|`) can be used to begin an indented block that will be interpreted
4185+an indented block that will be interpreted literally, without need for
4182−literally, without need for escaping. This form is necessary
4186+escaping. This form is necessary when the field contains blank lines
4183−when the field contains blank lines or block-level formatting:
4187+or block-level formatting:
4184
4188
4185 ---
4189 ---
4186 title: 'This is the title: it contains a colon'
4190 title: 'This is the title: it contains a colon'
@@ -4194,6 +4198,12 @@ when the field contains blank lines or block-level formatting:
4194 It consists of two paragraphs.
4198 It consists of two paragraphs.
4195 ...
4199 ...
4196
4200
4201+The literal block after the `|` must be indented relative to the
4202+line containing the `|`. If it is not, the YAML will be invalid
4203+and pandoc will not interpret it as metadata. For an overview
4204+of the complex rules governing YAML, see the [Wikipedia entry on
4205+YAML syntax].
4206+
4197Template variables will be set automatically from the metadata. Thus, for
4207Template variables will be set automatically from the metadata. Thus, for
4198example, in writing HTML, the variable `abstract` will be set to the HTML
4208example, in writing HTML, the variable `abstract` will be set to the HTML
4199equivalent of the Markdown in the `abstract` field:
4209equivalent of the Markdown in the `abstract` field:
@@ -4240,6 +4250,24 @@ will be interpreted as markdown. For example:
4240 \renewcommand{\section}[1]{\clearpage\oldsection{#1}}
4250 \renewcommand{\section}[1]{\clearpage\oldsection{#1}}
4241 ```
4251 ```
4242
4252
4253+Note: the `yaml_metadata_block` extension works with
4254+`commonmark` as well as `markdown` (and it is enabled by default
4255+in `gfm` and `commonmark_x`). However, in these formats the
4256+following restrictions apply:
4257+
4258+- The YAML metadata block must occur at the beginning of the
4259+ document (and there can be only one). If multiple files are
4260+ given as arguments to pandoc, only the first can be a YAML
4261+ metadata block.
4262+
4263+- The leaf nodes of the YAML structure are parsed in isolation from
4264+ each other and from the rest of the document. So, for
4265+ example, you can't use a reference link in these contexts
4266+ if the link definition is somewhere else in the document.
4267+
4268+[YAML escape sequence]: https://yaml.org/spec/1.2/spec.html#id2776092
4269+[Wikipedia entry on YAML syntax]: https://en.m.wikipedia.org/wiki/YAML#Syntax
4270+
4243## Backslash escapes
4271## Backslash escapes
4244
4272
4245#### Extension: `all_symbols_escapable` ####
4273#### Extension: `all_symbols_escapable` ####
@@ -4932,37 +4960,68 @@ Inline and regular footnotes may be mixed freely.
4932
4960
4933#### Extension: `citations` ####
4961#### Extension: `citations` ####
4934
4962
4935−Markdown citations go inside square brackets and are separated
4963+To cite a bibliographic item with an identifier foo, use the
4936−by semicolons. Each citation must have a key, composed of '@' +
4964+syntax `@foo`. Normal citations should be included in square
4937−the citation identifier from the database, and may optionally
4965+brackets, with semicolons separating distinct items:
4938−have a prefix, a locator, and a suffix. The citation key must
4966+
4967+ Blah blah [@doe99; @smith2000; @smith2004].
4968+
4969+How this is rendered depends on the citation style. In an
4970+author-date style, it might render as
4971+
4972+ Blah blah (Doe 1999, Smith 2000, 2004).
4973+
4974+In a footnote style, it might render as
4975+
4976+ Blah blah.[^1]
4977+
4978+ [^1]: John Doe, "Frogs," *Journal of Amphibians* 44 (1999);
4979+ Susan Smith, "Flies," *Journal of Insects* (2000);
4980+ Susan Smith, "Bees," *Journal of Insects* (2004).
4981+
4982+See the [CSL user documentation] for more information about CSL
4983+styles and how they affect rendering.
4984+
4939−begin with a letter, digit, or `_`, and may contain
4985+Unless a citation key start with a letter, digit, or `_`,
4940−alphanumerics, `_`, and internal punctuation characters
4986+and contains only alphanumerics and internal punctuation
4941−(`:.#$%&-+?<>~/`). Here are some examples:
4987+characters (`:.#$%&-+?<>~/`), it must be surrounded
4942−
4988+by curly braces, which are not considered part of the key.
4943− Blah blah [see @doe99, pp. 33-35; also @smith04, chap. 1].
4989+In `@Foo_bar.baz.`, the key is `Foo_bar.baz`. The final
4944−
4990+period is not *internal* punctuation, so it is not included in
4945− Blah blah [@doe99, pp. 33-35, 38-39 and *passim*].
4991+the key. In `@{Foo_bar.baz.}`, the key is `Foo_bar.baz.`, including
4946−
4992+the final period. The curly braces are recommended if you use URLs as
4947− Blah blah [@smith04; @doe99].
4993+keys: `[@{https://example.com/bib?name=foobar&date=2000}, p. 33]`.
4948−
4994+
4995+Citation items may optionally include a prefix, a locator, and
4996+a suffix. In
4997+
4998+ Blah blah [see @doe99, pp. 33-35 and *passim*; @smith04, chap. 1].
4999+
5000+The first item (`doe99`) has prefix `see `, locator `pp. 33-35`,
5001+and suffix `and *passim*`. The second item (`smith04`) has
5002+locator `chap. 1` and no prefix or suffix.
5003+
5004+Pandoc uses some heuristics to separate the locator from the
5005+rest of the subject. It is sensitive to the locator terms
4949−`pandoc` detects locator terms in the [CSL locale files].
5006+defined in the [CSL locale files]. Either abbreviated or
4950−Either abbreviated or unabbreviated forms are accepted. In the `en-US`
5007+unabbreviated forms are accepted. In the `en-US` locale, locator
4951−locale, locator terms can be written in either singular or plural forms,
5008+terms can be written in either singular or plural forms, as
4952−as `book`, `bk.`/`bks.`; `chapter`, `chap.`/`chaps.`; `column`,
5009+`book`, `bk.`/`bks.`; `chapter`, `chap.`/`chaps.`; `column`,
4953−`col.`/`cols.`; `figure`, `fig.`/`figs.`; `folio`, `fol.`/`fols.`;
5010+`col.`/`cols.`; `figure`, `fig.`/`figs.`; `folio`,
4954−`number`, `no.`/`nos.`; `line`, `l.`/`ll.`; `note`, `n.`/`nn.`; `opus`,
5011+`fol.`/`fols.`; `number`, `no.`/`nos.`; `line`, `l.`/`ll.`;
5012+`note`, `n.`/`nn.`; `opus`, `op.`/`opp.`; `page`, `p.`/`pp.`;
4955−`op.`/`opp.`; `page`, `p.`/`pp.`; `paragraph`, `para.`/`paras.`; `part`,
5013+`paragraph`, `para.`/`paras.`; `part`, `pt.`/`pts.`; `section`,
4956−`pt.`/`pts.`; `section`, `sec.`/`secs.`; `sub verbo`, `s.v.`/`s.vv.`;
5014+`sec.`/`secs.`; `sub verbo`, `s.v.`/`s.vv.`; `verse`,
4957−`verse`, `v.`/`vv.`; `volume`, `vol.`/`vols.`; `¶`/`¶¶`; `§`/`§§`. If no
5015+`v.`/`vv.`; `volume`, `vol.`/`vols.`; `¶`/`¶¶`; `§`/`§§`. If no
4958locator term is used, "page" is assumed.
5016locator term is used, "page" is assumed.
4959
5017
4960−`pandoc` will use heuristics to distinguish the locator
5018+In complex cases, you can force something to be treated as
4961−from the suffix. In complex cases, the locator can be enclosed
4962−in curly braces:
5019+a locator by enclosing it in curly braces or prevent parsing
5020+the suffix as locator by prepending curly braces:
4963
5021
4964 [@smith{ii, A, D-Z}, with a suffix]
5022 [@smith{ii, A, D-Z}, with a suffix]
4965 [@smith, {pp. iv, vi-xi, (xv)-(xvii)} with suffix here]
5023 [@smith, {pp. iv, vi-xi, (xv)-(xvii)} with suffix here]
5024+ [@smith{}, 99 years later]
4966
5025
4967A minus sign (`-`) before the `@` will suppress mention of
5026A minus sign (`-`) before the `@` will suppress mention of
4968the author in the citation. This can be useful when the
5027the author in the citation. This can be useful when the
@@ -4970,13 +5029,26 @@ author is already mentioned in the text:
4970
5029
4971 Smith says blah [-@smith04].
5030 Smith says blah [-@smith04].
4972
5031
4973−You can also write an in-text citation, as follows:
5032+You can also write an author-in-text citation, by omitting the
5033+square brackets:
4974
5034
4975 @smith04 says blah.
5035 @smith04 says blah.
4976
5036
4977 @smith04 [p. 33] says blah.
5037 @smith04 [p. 33] says blah.
4978
5038
5039+This will cause the author's name to be rendered, followed by
5040+the bibliographical details. Use this form when you want to
5041+make the citation the subject of a sentence.
4979
5042
5043+When you are using a note style, it is usually better to let
5044+citeproc create the footnotes from citations rather than writing
5045+an explicit note. If you do write an explicit note that
5046+contains a citation, note that normal citations will be put in
5047+parentheses, while author-in-text citations will not. For
5048+this reason, it is sometimes preferable to use the
5049+author-in-text style inside notes when using a note style.
5050+
5051+[CSL user documentation]: https://citationstyles.org/authors/
4980[CSL]: https://docs.citationstyles.org/en/stable/specification.html
5052[CSL]: https://docs.citationstyles.org/en/stable/specification.html
4981[CSL markup specs]: https://docs.citationstyles.org/en/1.0/release-notes.html#rich-text-markup-within-fields
5053[CSL markup specs]: https://docs.citationstyles.org/en/1.0/release-notes.html#rich-text-markup-within-fields
4982[Chicago Manual of Style]: https://chicagomanualofstyle.org
5054[Chicago Manual of Style]: https://chicagomanualofstyle.org
@@ -4985,13 +5057,44 @@ You can also write an in-text citation, as follows:
4985[finding and editing styles]: https://citationstyles.org/authors/
5057[finding and editing styles]: https://citationstyles.org/authors/
4986[CSL locale files]: https://github.com/citation-style-language/locales
5058[CSL locale files]: https://github.com/citation-style-language/locales
4987
5059
4988−## Non-pandoc extensions
5060+## Non-default extensions
4989
5061
4990The following Markdown syntax extensions are not enabled by default
5062The following Markdown syntax extensions are not enabled by default
4991in pandoc, but may be enabled by adding `+EXTENSION` to the format
5063in pandoc, but may be enabled by adding `+EXTENSION` to the format
4992name, where `EXTENSION` is the name of the extension. Thus, for
5064name, where `EXTENSION` is the name of the extension. Thus, for
4993example, `markdown+hard_line_breaks` is Markdown with hard line breaks.
5065example, `markdown+hard_line_breaks` is Markdown with hard line breaks.
4994
5066
5067+#### Extension: `rebase_relative_paths` ####
5068+
5069+Rewrite relative paths for Markdown links and images, depending
5070+on the path of the file containing the link or image link. For
5071+each link or image, pandoc will compute the directory of the
5072+containing file, relative to the working directory, and prepend
5073+the resulting path to the link or image path.
5074+
5075+The use of this extension is best understood by example.
5076+Suppose you have a a subdirectory for each chapter of a book,
5077+`chap1`, `chap2`, `chap3`. Each contains a file `text.md` and a
5078+number of images used in the chapter. You would like to have
5079+`![image](spider.jpg)` in `chap1/text.md` refer to
5080+`chap1/spider.jpg` and `![image](spider.jpg)` in `chap2/text.md`
5081+refer to `chap2/spider.jpg`. To do this, use
5082+
5083+ pandoc chap*/*.md -f markdown+rebase_relative_paths
5084+
5085+Without this extension, you would have to use
5086+`![image](chap1/spider.jpg)` in `chap1/text.md` and
5087+`![image](chap2/spider.jpg)` in `chap2/text.md`. Links with
5088+relative paths will be rewritten in the same way as images.
5089+
5090+Absolute paths and URLs are not changed. Neither are empty
5091+paths or paths consisting entirely of a fragment, e.g., `#foo`.
5092+
5093+Note that relative paths in reference links and images will
5094+be rewritten relative to the file containing the link
5095+reference definition, not the file containing the reference link
5096+or image itself, if these differ.
5097+
4995#### Extension: `attributes` ####
5098#### Extension: `attributes` ####
4996
5099
4997Allows attributes to be attached to any inline or block-level
5100Allows attributes to be attached to any inline or block-level
@@ -5525,10 +5628,23 @@ A few other metadata fields affect bibliography formatting:
5525
5628
5526`lang`
5629`lang`
5527: The `lang` field will affect how the style is localized,
5630: The `lang` field will affect how the style is localized,
5528− for example in the translation of labels and the use
5631+ for example in the translation of labels, the use
5632+ of quotation marks, and the way items are sorted.
5529− of quotation marks. (For backwards compatibility,
5633+ (For backwards compatibility, `locale` may be used instead
5530− `locale` may be used instead of `lang`, but this use
5531− is deprecated.)
5634+ of `lang`, but this use is deprecated.)
5635+
5636+ A BCP 47 language tag is expected: for example, `en`,
5637+ `de`, `en-US`, `fr-CA`, `ug-Cyrl`. The unicode extension
5638+ syntax (after `-u-`) may be used to specify options for
5639+ collation (sorting) more precisely. Here are some examples:
5640+
5641+ - `zh-u-co-pinyin` -- Chinese with the Pinyin collation.
5642+ - `es-u-co-trad` -- Spanish with the traditional collation
5643+ (with `Ch` sorting after `C`).
5644+ - `fr-u-kb` -- French with "backwards" accent sorting
5645+ (with `coté` sorting after `côte`).
5646+ - `en-US-u-kf-upper` -- English with uppercase letters sorting
5647+ before lower (default is lower before upper).
5532
5648
5533`notes-after-punctuation`
5649`notes-after-punctuation`
5534: If true (the default), pandoc will put footnote citations
5650: If true (the default), pandoc will put footnote citations
@@ -5540,12 +5656,6 @@ A few other metadata fields affect bibliography formatting:
5540 punctuation.
5656 punctuation.
5541
5657
5542
5658
5543−
5544−
5545−
5546−
5547−
5548−
5549# Slide shows
5659# Slide shows
5550
5660
5551You can use pandoc to produce an HTML + JavaScript slide presentation
5661You can use pandoc to produce an HTML + JavaScript slide presentation
@@ -5638,7 +5748,11 @@ rules:
5638 * A heading at the slide level always starts a new slide.
5748 * A heading at the slide level always starts a new slide.
5639
5749
5640 * Headings *below* the slide level in the hierarchy create
5750 * Headings *below* the slide level in the hierarchy create
5641− headings *within* a slide.
5751+ headings *within* a slide. (In beamer, a "block" will be
5752+ created. If the heading has the class `example`, an
5753+ `exampleblock` environment will be used; if it has the class
5754+ `alert`, an `alertblock` will be used; otherwise a regular
5755+ `block` will be used.)
5642
5756
5643 * Headings *above* the slide level in the hierarchy create
5757 * Headings *above* the slide level in the hierarchy create
5644 "title slides," which just contain the section title
5758 "title slides," which just contain the section title
@@ -6216,7 +6330,7 @@ Then edit `my.theme` and use it like this:
6216If you are not satisfied with the built-in highlighting, or you
6330If you are not satisfied with the built-in highlighting, or you
6217want highlight a language that isn't supported, you can use the
6331want highlight a language that isn't supported, you can use the
6218`--syntax-definition` option to load a [KDE-style XML syntax definition
6332`--syntax-definition` option to load a [KDE-style XML syntax definition
6219−file](https://docs.kde.org/stable5/en/applications/katepart/highlight.html).
6333+file](https://docs.kde.org/stable5/en/kate/katepart/highlight.html).
6220Before writing your own, have a look at KDE's [repository of syntax
6334Before writing your own, have a look at KDE's [repository of syntax
6221definitions](https://github.com/KDE/syntax-highlighting/tree/master/data/syntax).
6335definitions](https://github.com/KDE/syntax-highlighting/tree/master/data/syntax).
6222
6336
@@ -6390,9 +6504,9 @@ application, here are some things to keep in mind:
63904. The HTML generated by pandoc is not guaranteed to be safe.
65044. The HTML generated by pandoc is not guaranteed to be safe.
6391 If `raw_html` is enabled for the Markdown input, users can
6505 If `raw_html` is enabled for the Markdown input, users can
6392 inject arbitrary HTML. Even if `raw_html` is disabled,
6506 inject arbitrary HTML. Even if `raw_html` is disabled,
6393− users can include dangerous content in attributes for
6507+ users can include dangerous content in URLs and attributes.
6394− headings, spans, and code blocks. To be safe, you should
6395− run all the generated HTML through an HTML sanitizer.
6508+ To be safe, you should run all the generated HTML through
6509+ an HTML sanitizer.
6396
6510
6397# Authors
6511# Authors
6398
6512
SECURITY.mdnew file+12
@@ -0,0 +1,12 @@
1+# Security Policy
2+
3+## Supported Versions
4+
5+Only the most recent version of pandoc is supported with security updates.
6+
7+## Reporting a Vulnerability
8+
9+To report a vulnerability, email the maintainer, jgm@berkeley.edu.
10+But first please read the section of the manual entitled
11+[A note on security](https://pandoc.org/MANUAL.html#a-note-on-security),
12+which describes some security guarantees pandoc does NOT make.
cabal.project+9−8
@@ -1,12 +1,13 @@
1packages: pandoc.cabal
1packages: pandoc.cabal
2−
3tests: True
2tests: True
3+flags: +embed_data_files
4
4
5−package pandoc
5+source-repository-package
6− flags: +embed_data_files
6+ type: git
7− ghc-options: +RTS -A256m -RTS
7+ location: https://github.com/jgm/doctemplates
8+ tag: 428c26d5303cf7a2b1051fe1ffd9aafe9ba71c81
8
9
9−-- source-repository-package
10+source-repository-package
10−-- type: git
11+ type: git
11−-- location: https://github.com/jgm/citeproc
12+ location: https://github.com/jgm/citeproc
12−-- tag: d44e24696ab444090d0e63e321c3a573f68b2e74
13+ tag: 4ce0501cd6f9c86eee087afcf878c256e49b9615
changelog.md+659−10
@@ -1,6 +1,608 @@
1# Revision history for pandoc
1# Revision history for pandoc
2
2
3−## pandoc 2.12.1 (PROVISIONAL)
3+## pandoc 2.14.0.3 (2021-06-22)
4+
5+ * Text.Pandoc.MediaBag `insertMediaBag`: ensure we get a sane mediaPath
6+ for URLs (#7391). In earlier 2.14.x versions, we'd get
7+ incorrect paths for resources downloaded from URLs when the
8+ media are extracted (including in PDF production).
9+ * Text.Pandoc.Parsing: improve `emailAddress` (#7398).
10+ Previously the parser would accept characters in domains
11+ that are illegal in domains, and this sometimes caused it
12+ to gobble bits of the following text.
13+ * txt2tags reader: modify the email address parser so
14+ it still includes form parameters, even after the change to
15+ `emailAddress` in Text.Pandoc.Parsing.
16+ * Text.Pandoc.Readers.Metadata: Fix regression with comment-only YAML
17+ metadata blocks (#7400).
18+ * reveal.js writer and template: better handling of options. Previously
19+ it was impossible to specify false values for options that default to
20+ true (e.g. `center`); setting the option to false just caused the portion
21+ of the template setting the option to be omitted. Now we prepopulate
22+ all the variables with their default values, including them all
23+ unconditionally and allowing them to be overridden.
24+ * Markdown writer: Fix regression in code blocks with attributes (#7397).
25+ Code blocks with a single class but nonempty attributes
26+ were having attributes drop as a result of #7242.
27+ * LaTeX writer:
28+ + Add strut at end of minipage if it contains line breaks.
29+ Without them, the last line is not as tall as it should be in
30+ some cases.
31+ + Always use a minipage for cells with line breaks, when
32+ width information is available (#7393). Otherwise the way we treat them
33+ can lead to content that overflows a cell.
34+ + Use `\strut` instead of `~` before `\\` in empty line.
35+ * Use lts-18.0 stack resolver.
36+ * Require skylighting 0.10.5.2 (adding support for Swift).
37+ * Require commonmark 0.2.1.
38+ * Rephrase section on unsafe HTML in manual.
39+ * Create SECURITY.md
40+
41+## pandoc 2.14.0.2 (2021-06-13)
42+
43+ * Fix MediaBag regressions (#7345). iIn the 2.14 release `--extract-media`
44+ stopped working as before; there could be mismatches between the
45+ paths in the rendered document and the extracted media.
46+ This patch makes several changes that restore the earlier behavior
47+ (while keeping the same API). The `mediaPath` in 2.14 was always
48+ constructed from the SHA1 hash of the media contents. Now, we
49+ preserve the original path unless it's an absolute path or contains
50+ `..` segments (in that case we use a path based on the SHA1 hash of
51+ the contents).
52+
53+ In Text.Pandoc.MediaBag, `mediaDirectory` and `mediaItems` now use the
54+ `mediaPath`, rather than the mediabag key, for the first component of the
55+ tuple. This makes more sense, I think, and fits with the documentation of
56+ these functions; eventually, though, we should rework the API so that
57+ `mediaItems` returns both the keys and the MediaItems.
58+
59+ In Text.Pandoc.Class.IO, rewriting of source paths in `extractMedia` has
60+ been fixed.
61+
62+ In Text.Pandoc.Class.PandocMonad, `fillMediaBag` has been modified so that
63+ it doesn't modify image paths (that was part of the problem in #7345).
64+
65+ We now do path normalization (e.g. `\` separators on Windows) in
66+ writing the media.
67+
68+ * Text.Pandoc.PDF:
69+
70+ + Text.Pandoc.PDF: Fix regression in 2.14 for generation of PDFs with
71+ SVGs (#7344).
72+ + Only print relevant part of environment on `--verbose`. Since
73+ `--verbose` output might be put in an issue, we want to avoid
74+ spilling out secrets in environment variables.
75+
76+ * Markdown reader: fix pipe table regression in 2.11.4 (#7343).
77+ Previously pipe tables with empty headers (that is, a header
78+ line with all empty cells) would be rendered as headerless
79+ tables. This broke in 2.11.4. The fix here is to produce an
80+ AST with an empty table head when a pipe table has all empty
81+ header cells.
82+
83+ * LaTeX reader: don't allow optional `*` on symbol control sequences
84+ (#7340). Generally we allow optional starred variants of LaTeX commands
85+ (since many allow them, and if we don't accept these explicitly,
86+ ignoring the star usually gives acceptable results). But we
87+ don't want to do this for `\(*\)` and similar cases.
88+
89+ * Docx reader: handle absolute URIs in Relationship Target (#7374).
90+
91+ * Docx writer: fix handling of empty table headers (Albert Krewinkel,
92+ #7369). A table header which does not contain any cells is now treated as
93+ an empty header.
94+
95+ * LaTeX writer: Fix regression in table header position (#7347).
96+ In recent versions the table headers were no longer bottom-aligned
97+ (if more than one line). This patch fixes that by using minipages
98+ for table headers in non-simple tables.
99+
100+ * CommonMark writer:
101+
102+ + Do not use simple class for fenced-divs (Jan Tojnar, amends #7242.)
103+ + Do not throw away attributes when `Ext_attributes` is enabled.
104+ `Ext_attributes` covers at least the following:
105+ `Ext_fenced_code_attributes`, `Ext_header_attributes`,
106+ `Ext_inline_code_attributes`, `Ext_link_attributes`.
107+
108+ * Markdown writer:
109+
110+ + Allow `pipe_tables` to be disabled for commonmark formats
111+ (`commonmark_x`, `gfm`) (#7375).
112+ + Re-use functions from Text.Pandoc.Markdown.Inline (Jan Tojnar).
113+
114+ * DocBook writer: Remove non-existent admonitions (Jan Tojnar).
115+ `attention`, `error` and `hint` are reStructuredText specific.
116+
117+ * HTML writer: Don't omit width attribute on div (#7342).
118+
119+ * Text.Pandoc.MIME, `extensionFromMimeType`: add a few special cases.
120+ When we do a reverse lookup in the MIME table, we just get the
121+ last match, so when the same mime type is associated with several
122+ different extensions, we sometimes got weird results, e.g. `.vs`
123+ for `text/plain`. These special cases help us get the most standard
124+ extensions for mime types like `text/plain`.
125+
126+ * Lua utils: fix handling of table headers in `from_simple_table` (Albert
127+ Krewinkel, #7369). Passing an empty list of header cells now results
128+ in an empty table header.
129+
130+ * Text.Pandoc.Citeproc:
131+
132+ + Avoid duplicate classes and attributes on references div.
133+ + Fix regression in citeproc processing (#7376). If inline
134+ references are used (in the metadata `references` field), we
135+ should still only include in the bibliography items that are
136+ actually cited (unless `nocite` is used).
137+
138+ * Require citeproc 0.4.0.1. This fixes a bug which led to doubled
139+ "et al." in some (rare) circumstances.
140+
141+ * MANUAL.txt:
142+
143+ + Mention GladTeX for EPUB export (Sebastian Humenda).
144+ This updates the manual and the web site about the GladTeX usage.
145+ + More details and a useful link for YAML syntax.
146+
147+ * CONTRIBUTING.md: update modules overview (Albert Krewinkel).
148+
149+ * using-the-pandoc-api.md: switch from String to Text (Albert Krewinkel).
150+
151+
152+## pandoc 2.14.0.1 (2021-06-01)
153+
154+ * Commonmark reader: Fix regression in 2.14 with YAML metdata block parsing,
155+ which could cause the document body to be omitted after metadata (#7339).
156+
157+ * HTML reader: fix column width regression in 2.14 (#7334).
158+ Column widths specified with a style attribute were off by a factor of 100.
159+
160+ * Markdown reader: in `rebasePaths`, check for both Windows and Posix
161+ absolute paths. Previously Windows pandoc was treating
162+ `/foo/bar.jpg` as non-absolute.
163+
164+ * Text.Pandoc.Logging: In rendering `LoadedResource`, use relative paths.
165+
166+ * Docx writer: fix regression on captions (#7328). The "Table Caption"
167+ style was no longer getting applied. (It was overwritten by "Compact.")
168+
169+ * Use commonmark-extensions 0.2.1.2
170+
171+## pandoc 2.14 (2021-05-28)
172+
173+ * Change reader types, allowing better tracking of source positions
174+ [API change]. Previously, when multiple file arguments were provided,
175+ pandoc simply concatenated them and passed the contents to the readers,
176+ which took a Text argument. As a result, the readers had no way of knowing
177+ which file was the source of any particular bit of text. This meant that
178+ we couldn't report accurate source positions on errors or include accurate
179+ source positions as attributes in the AST. More seriously, it meant that
180+ we couldn't resolve resource paths relative to the files containing them
181+ (see e.g. #5501, #6632, #6384, #3752).
182+
183+ * Add `rebase_relative_paths` extension (#3752). When enabled, this
184+ extension rewrites relative image and link paths by prepending
185+ the (relative) directory of the containing file. This
186+ behavior is useful when your input sources are split
187+ into multiple files, across several directories, with files
188+ referring to images stored in the same directory. The
189+ extension can be enabled for all markdown and commonmark-based formats.
190+
191+ * Add Text.Pandoc.Sources (exported module), with a `Sources` type and a
192+ `ToSources` class. A `Sources` wraps a list of `(SourcePos, Text)` pairs
193+ [API change]. A parsec `Stream` instance is provided for `Sources`. The
194+ module also exports versions of parsec's `satisfy` and other Char parsers
195+ that track source positions accurately from a `Sources` stream (or any
196+ instance of the new `UpdateSourcePos` class).
197+
198+ * Text.Pandoc.Parsing
199+
200+ + Export the modified Char parsers defined in Text.Pandoc.Sources
201+ instead of the ones parsec provides. Modified parsers to use a
202+ `Sources` as stream [API change].
203+ + Improve include file functions [API change]. Remove old
204+ `insertIncludedFileF`. Give `insertIncludedFile` a more general type,
205+ allowing it to be used where `insertIncludedFileF` was.
206+ + Add parameter to the `citeKey` parser from
207+ Text.Pandoc.Parsing, which controls whether the `@{..}`
208+ syntax is allowed [API change].
209+
210+ * Text.Pandoc.Error: Modified the constructor `PandocParsecError` to take a
211+ `Sources` rather than a `Text` as first argument, so parse error locations
212+ can be accurately reported.
213+
214+ * Fix source position reporting for YAML bibliographies (#7273).
215+
216+ * Issue error message when reader or writer format is malformed
217+ (#7231). Previously we exited with an error status but (due to a bug)
218+ no message.
219+
220+ * Smarter smart quotes (#7216, #2103). Treat a leading `"` with no
221+ closing `"` as a left curly quote. This supports the practice, in
222+ fiction, of continuing paragraphs quoting the same speaker without an
223+ end quote. It also helps with quotes that break over lines in line blocks.
224+
225+ * Markdown reader:
226+
227+ + Use MetaInlines not MetaBlocks for multimarkdown metadata fields.
228+ This gives better results in converting to e.g. pandoc markdown.
229+ + Implement curly-brace syntax for Markdown citation keys (#6026).
230+ The change provides a way to use citation keys that contain
231+ special characters not usable with the standard citation key syntax.
232+ Example: `@{foo_bar{x}'}` for the key `foo_bar{x}`. It also allows
233+ separating citation keys from immediately following text, e.g. `@{foo}A`.
234+
235+ * RST reader:
236+
237+ + Seek include files in the directory of the file
238+ containing the include directive, as RST requires (#6632).
239+ + Use `insertIncludedFile` from Text.Pandoc.Parsing
240+ instead of reproducing much of its code.
241+
242+ * Org reader: Resolve org includes relative to the directory containing the
243+ file containing the INCLUDE directive (#5501).
244+
245+ * ODT reader: Treat tabs as spaces (#7185, niszet).
246+
247+ * Docx reader:
248+
249+ + Add handling of vml image objects (#7257, mbrackeantidot).
250+ + Support new table features (Emily Bourke, #6316): column
251+ spans, row spans, multiple header rows, table description
252+ (parsed as a simple caption), captions, column widths.
253+
254+ * LaTeX reader:
255+
256+ + Improved siunitx support (#6658, #6620).
257+ + Better support for `\xspace` (#7299).
258+ + Improve parsing of `\def` macros. We previously set "verbatim mode"
259+ even for parsing the initial `\def`; this caused problems
260+ for `\def` nested inside another `\def`.
261+ + Implement `\newif`.
262+
263+ * ConTeXt writer: improve ordered lists (#5016, Denis Maier).
264+ Change ordered list from itemize to enumerate. Add new
265+ itemgroup for ordered lists. Remove manual insertion of
266+ width attributes. Use tabular figures in ordered list
267+ enumerators.
268+
269+ * HTML reader:
270+
271+ + Don't fail on unmatched closing "script" tag (Albert Krenkel, #7282).
272+ + Keep h1 tags as normal headers (#2293, Albert Krewinkel).
273+ The tags `<title>` and `<h1 class="title">` often contain the same
274+ information, so the latter was dropped from the document. However, as
275+ this can lead to loss of information, the heading is now always
276+ retained. Use `--shift-heading-level-by=-1` to turn the `<h1>`
277+ into the document title, or a filter to restore the previous behavior.
278+ + Handle relative lengths (e.g. `2*`) in HTML column widths (#4063).
279+ See <https://www.w3.org/TR/html4/types.html#h-6.6>.
280+
281+ * DocBook/JATS readers:
282+
283+ + Fix mathml regression caused by the switch in XML libraries (#7173).
284+ + Fix "phrase" in DocBook: take classes from "role" not "class" (#7195).
285+
286+ * DocBook reader: ensure that first and last names are separated (#6541).
287+
288+ * Jira reader (Albert Krewinkel, #7218):
289+
290+ + Support "smart" links: `[alias|https://example.com|smart-card]` syntax.
291+ + Allow spaces and most unicode characters in attachment links.
292+ + No longer require a newline character after `{noformat}`.
293+ + Only allow URI path segment characters in bare links.
294+ + The `file:` schema is no longer allowed in bare links; these
295+ rarely make sense.
296+
297+ * Plain writer: handle superscript unicode minus (#7276).
298+
299+ * LaTeX writer:
300+
301+ + Better handling of line breaks in simple tables (#7272).
302+ Now we also handle the case where they're embedded in other elements,
303+ e.g. spans.
304+ + For beamer output, support `exampleblock` and `alertblock` (#7278).
305+ A block will be rendered as an `exampleblock` if the heading
306+ has class `example` and an `alertblock` if it has class `alert`.
307+ + Separate successive quote chars with thin space (#6958,
308+ Albert Krewinkel). Successive quote characters are separated with
309+ a thin space to improve readability and to prevent unwanted ligatures.
310+ Detection of these quotes sometimes had failed if the second quote
311+ was nested in a span element.
312+ + Separate successive quote chars with thin space (#6958, Albert
313+ Krewinkel).
314+
315+ * EPUB Writer: Fix belongs-to-collection XML id choice (#7267, nuew).
316+ The epub writer previously used the same XML id for both the book
317+ identifier and the epub collection. This causes an error on epubcheck.
318+
319+ * BibTeX/BibLaTeX writer: Handle `annote` field (#7266).
320+
321+ * ZimWiki writer: allow links and emphasis in headers (#6605,
322+ Albert Krewinkel).
323+
324+ * ConTeXt writer:
325+
326+ + Support blank lines in line blocks (#6564, Albert Krewinkel,
327+ thanks to @denismaier).
328+ + Use span identifiers as reference anchors (#7246, Albert Krewinkel).
329+
330+ * HTML writer:
331+
332+ + Keep attributes from code nested below `pre` tag (#7221,
333+ Albert Krewinkel). If a code block is defined with `<pre><code
334+ class="language-x">…</code></pre>`, where the `<pre>` element has no
335+ attributes, then the attributes from the `<code>` element are used
336+ instead. Any leading `language-` prefix is dropped in the code's
337+ `class` attribute are dropped to improve syntax highlighting.
338+ + Ensure headings only have valid attribs in HTML4 (#5944, Albert
339+ Krewinkel).
340+ + Parse `<header>` as a Div (Albert Krewinkel).
341+
342+ * Org writer:
343+
344+ + Inline latex envs need newlines (#7252, tecosaur).
345+ As specified in https://orgmode.org/manual/LaTeX-fragments.html, an
346+ inline \begin{}...\end{} LaTeX block must start on a new line.
347+ + Use LaTeX style maths deliminators (#7196, tecosaur).
348+
349+ * JATS writer (Albert Krewinkel):
350+
351+ + Use either styled-content or named-content for spans (#7211).
352+ If the element has a content-type attribute, or at least one class,
353+ then that value is used as `content-type` and the span is put inside
354+ a `<named-content>` element. Otherwise a `<styled-content>` element
355+ is used instead.
356+ + Reduce unnecessary use of `<p>` elements for wrapping (#7227).
357+ The `<p>` element is used for wrapping in cases were the contents
358+ would otherwise not be allowed in a certain context. Unnecessary
359+ wrapping is avoided, especially around quotes (`<disp-quote>` elements).
360+ + Convert spans to `<named-content>` elements (#7211). Spans with
361+ attributes are converted to `<named-content>` elements instead of
362+ being wrapped with `<milestone-start/>` and `<milestone-end>`
363+ elements. Milestone elements are not allowed in documents using the
364+ articleauthoring tag set, so this change ensures the creation of valid
365+ documents.
366+ + Add footnote number as label in backmatter (#7210). Footnotes in the
367+ backmatter are given the footnote's number as a label. The
368+ articleauthoring output is unaffected from this change, as footnotes
369+ are placed inline there.
370+ + Escape disallows chars in identifiers. XML identifiers must start
371+ with an underscore or letter, and can contain only a limited set
372+ of punctuation characters. Any IDs not adhering to these rules are
373+ rewritten by writing the offending characters as `Uxxxx`,
374+ where `xxxx` is the character's hex code.
375+
376+ * Jira writer: use `{color}` when span has a color attribute
377+ (Albert Krewinkel, tarleb/jira-wiki-markup#10).
378+
379+ * Docx writer:
380+
381+ + Autoset table width if no column has an explicit width (Albert
382+ Krewinkel).
383+ + Extract Table handling into separate module (Albert Krewinkel).
384+ + Support colspans and rowspans in tables (Albert Krewinkel, #6315).
385+ + Support multirow table headers (Albert Krewinkel).
386+ + Improve integration of settings from reference.docx (#1209).
387+ This change allows users to create a reference.docx that
388+ sets `w:proofState` for spelling or grammar to `dirty`,
389+ so that spell/grammar checking will be triggered on the
390+ generated docx.
391+ + Copy over more settings from reference.docx (#7240). From settings.xml
392+ in the reference-doc, we now include: `zoom`, `embedSystemFonts`,
393+ `doNotTrackMoves`, `defaultTabStop`, `drawingGridHorizontalSpacing`,
394+ `drawingGridVerticalSpacing`, `displayHorizontalDrawingGridEvery`,
395+ `displayVerticalDrawingGridEvery`, `characterSpacingControl`,
396+ `savePreviewPicture`, `mathPr`, `themeFontLang`, `decimalSymbol`,
397+ `listSeparator`, `autoHyphenation`, `compat`.
398+ + Set zoom to 100% by default in settings.xml.
399+ + Align math options more with current Word defaults (e.g. Cambria Math
400+ font).
401+ + Remove `rsid`s from default settings.xml. Word will add these
402+ when revisions are made.
403+
404+ * Ms writer: Handle tables with multiple paragraphs (#7288).
405+ Previously they overflowed the table cell width. We now set line lengths
406+ per-cell and restore them after the table has been written.
407+
408+ * Markdown writer:
409+
410+ + Use cleaner braceless syntax for code blocks with a
411+ single class (#7242, Jan Tojnar).
412+ + Add quotes properly in markdown YAML metadata fields (#7245).
413+ This fixes a bug, which caused the writer to look at the *last*
414+ rather than the *first* character in determining whether quotes
415+ were needed. So we got spurious quotes in some cases and
416+ didn't get necessary quotes in others.
417+ + Use `@{..}` syntax for citations when needed.
418+ + Use fewer unneeded escapes for `#` (see #6259).
419+ + Improve escaping of `@`. We need to escape literal `@` before
420+ `{` because of the new citation syntax.
421+
422+ * Commonmark writer: Use backslash escapes for `<` and `|`...
423+ instead of entities (#7208).
424+
425+ * Powerpoint writer: allow `monofont` to be specified in metadata
426+ (#7187).
427+
428+ * LaTeX template:
429+
430+ + Use non-starred names for xcolor color names (#6109).
431+ This should make svgnames and x11names work properly.
432+ + Fix bad vertical spacing after bibliography (#7234, badumont).
433+ + List of figures before list of tables (#7235, Julien Dutant).
434+ + Move CSL macro definitions before header-includes so they can be
435+ overridden (#7286).
436+ + Improve treatment of CSL `entry-spacing` (#7296).
437+ Previously with the default template settings (`indent` variable
438+ not set), we would get interparagraph spaces separating bib
439+ entries even with `entry-spacing="0"`. On the other hand,
440+ setting `entry-spacing="2"` gave ridiculously large spacing.
441+ This change makes the spacing caused by `entry-spacing` a multiple
442+ of `\parskip` by default, which gives aesthetically reasonable
443+ output. Those who want a larger or smaller unit (e.g. because
444+ they use `indent` which sets `\parskip` to 0) may
445+ `\setlength{\cslentryspacingunit}{10pt}` in header-includes
446+ to override the defaults.
447+ + Move title, author, date up to top of preamble (#7295).
448+ This allows header-includes to use them, and puts them
449+ in a position where you can see them immediately.
450+ + Define commands for zero width non-joiner character
451+ (#6639, Albert Krewinkel). The zero-width non-joiner character
452+ is used to avoid ligatures (e.g. in German).
453+
454+ * ConTeXt template:
455+
456+ + Define `enumerate` itemgroup (#5016, Denis Maier).
457+ + List of figures before list of tables (#7235, Julien Dutant).
458+
459+ * reveal.js template:
460+
461+ + Support `toc-title` (#7171, Florian Kohrt).
462+ + Use `hash: true` by default rather than `history: true` (#6968).
463+
464+ * HTML-based slide shows: add support for `institute` (#7289, Thomas
465+ Hodgson).
466+
467+ * Text.Pandoc.Extensions: Add constructor `Ext_rebase_relative_paths` to
468+ `Extensions` [API change].
469+
470+ * Text.Pandoc.XML.Light: add Eq, Ord instances for Content,
471+ Element, Attr, CDataKind [API change].
472+
473+ * Text.Pandoc.MediaBag:
474+
475+ + Change type to use a `Text` key instead of `[FilePath]`.
476+ We normalize the path and use `/` separators for consistency.
477+ + Export `MediaItem` type [API change].
478+ + Change `MediaBag` type to a map from Text to MediaItem [API change].
479+ + `lookupMedia` now returns a `MediaItem` [API change].
480+ + Change `insertMedia` so it sets the `mediaPath` to a filename based on
481+ the SHA1 hash of the contents. This will be used when contents
482+ are extracted.
483+
484+ * Text.Pandoc.Class.PandocMonad:
485+
486+ + Remove `fetchMediaResource` [API change]. Use `fetchItem` to get
487+ resources in `fillMediaBag`.
488+ + Add informational message in `downloadOrRead` indicating what path
489+ local resources have been loaded from.
490+
491+ * Text.Pandoc.Logging:
492+
493+ + Remove single quotes around paths in messages.
494+ + Add LoadedResource constructor to LogMessage [API change].
495+ This is for INFO-level messages telling where image data has been
496+ loaded from. (This can vary because of the resource path.)
497+
498+ * Text.Pandoc.Asciify: simplify code and export `toAsciiText` [API change].
499+ Instead of encoding a giant (and incomplete) map, we now
500+ just use unicode-transforms to normalize the text to
501+ a canonical decomposition, and manipulate the result.
502+
503+ * App: allow tabs expansion even if file-scope is used (Albert Krewinkel,
504+ #6709). Tabs in plain-text inputs are now handled correctly, even if
505+ the `--file-scope` flag is used.
506+
507+ * Add new internal module Text.Pandoc.Writers.GridTable (Albert Krewinkel).
508+
509+ * Text.Pandoc.Highlighting: Change type of `languagesByExtension`, adding
510+ a parameter for a `SyntaxMap` [API change] (Jan Tojnar, #7241).
511+ Languages defined using `--syntax-definition` were not recognized by
512+ `languagesByExtension`. This patch corrects that, allowing the writers
513+ to see all custom definitions. The LaTeX writer still uses the default
514+ syntax map, but that's okay in that context, since
515+ `--syntax-definition` won't create new listings styles.
516+
517+ * Text.Pandoc.Citeproc:
518+
519+ + Ensure that CSL-related attributes are passed on to a Div with id
520+ 'refs'. Otherwise things like `entry-spacing` won't work when
521+ such Divs are used.
522+ + Use metadata's `lang` for the lang parameter of citeproc, overriding
523+ `localeLanguage`.
524+ + Recognize locators spelled with a capital letter (#7323).
525+ + Add a comma and a space in front of the suffix if it doesn't start
526+ with space or punctuation (#7324).
527+ + Don't detect math elements as locators (#7321).
528+
529+ * Remove Text.Pandoc.BCP47 module [API change]. Use types and functions
530+ from UnicodeCollation.Lang instead. This is a richer implementation
531+ of BCP 47.
532+
533+ * Text.Pandoc.Shared:
534+
535+ + Fix regression in grid tables for wide characters (#7214).
536+ In the translation from String to Text, a char-width-sensitive
537+ `splitAt'` was dropped. This commit reinstates it and uses it to make
538+ `splitTextByInstances` char-width sensitive.
539+ + Add `getLang` (formerly in the now-removed BCP47) [API change].
540+
541+ * Text.Pandoc.SelfContained: use `application/octet-stream`
542+ for unknown mime types instead of halting with an error (#7202).
543+
544+ * Lua filters: respect Inlines/Blocks filter functions in `pandoc.walk_*`
545+ (Albert Krewinkel).
546+
547+ * Add text as build-depend for trypandoc (#7193, Roman Beránek).
548+
549+ * Bump upper-bounds for network-uri, time, attoparsec.
550+
551+ * Use citeproc 0.4.
552+
553+ * Use texmath 0.12.3.
554+
555+ * Use jira-wiki-markup 1.3.5 (Albert Krewinkel).
556+
557+ * Require latest skylighting (fixes a bug in XML syntax highlighting).
558+
559+ * Use latest xml-conduit.
560+
561+ * Use latest commonmark, commonmark-extensions, commonmark-pandoc.
562+
563+ * Use haddock-library-1.10.0 (Albert Krewinkel).
564+
565+ * Allow compilation with base 4.15 (Albert Krewinkel).
566+
567+ * MANUAL:
568+
569+ + Add information about `lang` and bibliography sorting.
570+ + Add info about YAML escape sequences, link to spec (#7152,
571+ Albert Krewinkel).
572+ + Note that `institute` variable works for HTML-based slides.
573+ + Update documentation on citation syntax.
574+ + Add citation example for locators and suffixes (Tristan Stenner)
575+
576+ * Updated and fixed typos in documentation (Charanjit Singh,
577+ Anti-Distinctlyminty, Tatiana Porras, obcat).
578+
579+ * Add instructions for installing pandoc-types before compiling filter.
580+
581+ * INSTALL: add note that parallel installations should be avoided
582+ (#6865).
583+
584+ * Remove `biblatex-nussbaum.md` test. It is basically the same
585+ as `biblaetx-quotes.md`.
586+
587+ * Command tests: fail if a file contains no tests---and fix a
588+ test that failed in that way!
589+
590+ * Use smaller images in tests, reducing the size of the source tarball by 8 MB.
591+
592+
593+## pandoc 2.13 (2021-03-21)
594+
595+ * Support `yaml_metadata_block` extension for `commonmark`, `gfm` (#6537).
596+ This supported is a bit more limited than with pandoc's
597+ `markdown`. The YAML block must be the first thing in the input,
598+ and the leaf notes are parsed in isolation from the rest of
599+ the document. So, for example, you can't use reference
600+ links if the references are defined later in the document.
601+
602+ * Fix fallback to default partials when custom templates are used.
603+ If the directory containing a template does not contain the partial,
604+ it should be sought in the default templates, but this was not
605+ working properly (#7164).
4
606
5 * Handle `nocite` better with `--biblatex` and `--natbib` (#4585).
607 * Handle `nocite` better with `--biblatex` and `--natbib` (#4585).
6 Previously the nocite metadata field was ignored with these formats.
608 Previously the nocite metadata field was ignored with these formats.
@@ -11,6 +613,32 @@
11 that incorporates a prefix like `https://doi.org/` into a following link
613 that incorporates a prefix like `https://doi.org/` into a following link
12 when appropriate.
614 when appropriate.
13
615
616+ * Text.Pandoc.Shared:
617+
618+ + Remove `backslashEscapes`, `escapeStringUsing` [API change]. Replace
619+ these inefficient association list lookups with more efficient escaping
620+ functions in the writers that used them (for a 10-25% performance boost
621+ in org, haddock, rtf, texinfo writers).
622+ + Remove `ToString`, `ToText` typeclasses [API change]. These were needed
623+ for the transition from String to Text, but they are no longer used and
624+ may clash with other things.
625+ + Simplify `compactDL`.
626+
627+ * Text.Pandoc.Parsing:
628+
629+ + Change type of `readWithM` so that it is no longer polymorphic
630+ [API change]. The `ToText` class has been removed, and now that we've
631+ completed the transition to Text we no longer need this to operate
632+ on Strings.
633+ + Remove `F` type synonym [API change]. Muse and Org were defining their
634+ own `F` anyway.
635+
636+ * Text.Pandoc.Readers.Metadata:
637+
638+ + Export `yamlMetaBlock` [API change].
639+ + Make `yamlBsToMeta`, `yamlBsToRefs` polymorphic on the parser state
640+ [API change].
641+
14 * Markdown reader: Fix regression with `tex_math_backslash` (#7155).
642 * Markdown reader: Fix regression with `tex_math_backslash` (#7155).
15
643
16 * MediaWiki reader: Allow block-level content in notes (ref) (#7145).
644 * MediaWiki reader: Allow block-level content in notes (ref) (#7145).
@@ -27,6 +655,11 @@
27 * RST reader: fix logic for ending comments (#7134). Previously comments
655 * RST reader: fix logic for ending comments (#7134). Previously comments
28 sometimes got extended too far.
656 sometimes got extended too far.
29
657
658+ * DocBook writer: include Header attributes as XML attributes on
659+ section (Erik Rask). Attributes with key names that are not allowed
660+ as XML attributes are dropped, as are attributes with invalid values
661+ and `xml:id` (DocBook 5) and `id` (DocBook 4).
662+
30 * Docx writer:
663 * Docx writer:
31
664
32 + Make `nsid` in `abstractNum` deterministic. Previously we assigned
665 + Make `nsid` in `abstractNum` deterministic. Previously we assigned
@@ -56,17 +689,19 @@
56
689
57 * reveal.js template: replace JS comment with HTML (#7154, Florian Kohrt).
690 * reveal.js template: replace JS comment with HTML (#7154, Florian Kohrt).
58
691
59− * Text.Pandoc.Shared: Simplify `compactDL`.
60−
61 * Text.Pandoc.Logging: Add `DuplicateAttribute` constructor to `LogMessage`.
692 * Text.Pandoc.Logging: Add `DuplicateAttribute` constructor to `LogMessage`.
62 [API change]
693 [API change]
63
694
64− * Use `-j4` for linux release build. This speeds up the build
695+ * Use `-j4` for linux release build. This speeds up the build dramatically
65− dramatically on arm.
696+ on arm.
66
697
67− * cabal.project: remove `-j`.
698+ * cabal.project: remove ghcoptions. Move flags to top level, so they can
699+ be set differently on the command line.
68
700
69 * Require latest texmath, skylighting, citeproc, jira-wiki-markup.
701 * Require latest texmath, skylighting, citeproc, jira-wiki-markup.
702+ (The latest skylighting fixes a bad bug with Haskell syntax highlighting.)
703+ Narrow version bounds for texmath, skylighting, and citeproc, since
704+ the test output depend on them.
70
705
71 * Use doclayout 0.3.0.2. This significantly reduces the time and memory
706 * Use doclayout 0.3.0.2. This significantly reduces the time and memory
72 needed to compile pandoc.
707 needed to compile pandoc.
@@ -75,12 +710,26 @@
75
710
76 * Update bounds for random (#7156, Alexey Kuleshevich).
711 * Update bounds for random (#7156, Alexey Kuleshevich).
77
712
713+ * Remove uses of some partial functions.
714+
715+ * Don't bake in a larger stack size for the executable.
716+
717+ * Test improvements:
718+
719+ + Use `getExecutablePath` from base, avoiding the dependency on
720+ `executable-path`.
721+ + Factor out `setupEnvironment` in Helpers, to avoid code duplication.
722+ + Fix finding of data files by setting teh `pandoc_datadir` environment
723+ variable when we shell out to pandoc. This avoids the need to use
724+ `--data-dir` for the tests, which caused problems finding `pandoc.lua`
725+ when compiling without the `embed_data_files` flag (#7163).
726+
78− * Benchmark improvements.
727+ * Benchmark improvements:
79
728
80 + Build `+RTS -A8m -RTS` into default ghc-options for benchmark.
729 + Build `+RTS -A8m -RTS` into default ghc-options for benchmark.
81− This is necessary to get accurate benchmark results; otherwise
730+ This is necessary to get accurate benchmark results; otherwise we
82− we are largely measuring garbage collecting, some not related
731+ are largely measuring garbage collecting, some not related to the
83− to the current benchmark.
732+ current benchmark.
84 + Allow specifying BASELINE file in 'make bench' for comparison
733 + Allow specifying BASELINE file in 'make bench' for comparison
85 (otherwise the latest benchmark is chosen by default).
734 (otherwise the latest benchmark is chosen by default).
86 + Force `readFile` in benchmarks early (Bodigrim).
735 + Force `readFile` in benchmarks early (Bodigrim).
data/docx/word/settings.xml+6−16
@@ -1,6 +1,6 @@
1<?xml version="1.0" encoding="UTF-8"?>
1<?xml version="1.0" encoding="UTF-8"?>
2<w:settings xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:sl="http://schemas.openxmlformats.org/schemaLibrary/2006/main">
2<w:settings xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:sl="http://schemas.openxmlformats.org/schemaLibrary/2006/main">
3− <w:zoom w:percent="90" />
3+ <w:zoom w:percent="100" />
4 <w:embedSystemFonts />
4 <w:embedSystemFonts />
5 <w:proofState w:spelling="clean" w:grammar="clean" />
5 <w:proofState w:spelling="clean" w:grammar="clean" />
6 <w:stylePaneFormatFilter w:val="0004" />
6 <w:stylePaneFormatFilter w:val="0004" />
@@ -17,31 +17,21 @@
17 <w:characterSpacingControl w:val="doNotCompress" />
17 <w:characterSpacingControl w:val="doNotCompress" />
18 <w:savePreviewPicture />
18 <w:savePreviewPicture />
19 <w:rsids>
19 <w:rsids>
20− <w:rsidRoot w:val="00590D07" />
21− <w:rsid w:val="00011C8B" />
22− <w:rsid w:val="004E29B3" />
23− <w:rsid w:val="00590D07" />
24− <w:rsid w:val="00784D58" />
25− <w:rsid w:val="008D6863" />
26− <w:rsid w:val="00B86B75" />
27− <w:rsid w:val="00BC48D5" />
28− <w:rsid w:val="00C36279" />
29− <w:rsid w:val="00E315A3" />
30 </w:rsids>
20 </w:rsids>
31 <m:mathPr>
21 <m:mathPr>
32− <m:mathFont m:val="Lucida Grande" />
22+ <m:mathFont m:val="Cambria Math" />
33 <m:brkBin m:val="before" />
23 <m:brkBin m:val="before" />
34 <m:brkBinSub m:val="--" />
24 <m:brkBinSub m:val="--" />
35− <m:smallFrac m:val="false" />
25+ <m:smallFrac m:val="0" />
36− <m:dispDef m:val="false" />
26+ <m:dispDef />
37 <m:lMargin m:val="0" />
27 <m:lMargin m:val="0" />
38 <m:rMargin m:val="0" />
28 <m:rMargin m:val="0" />
39 <m:wrapRight />
29 <m:wrapRight />
40 <m:intLim m:val="subSup" />
30 <m:intLim m:val="subSup" />
41− <m:naryLim m:val="subSup" />
31+ <m:naryLim m:val="undOvr" />
42 </m:mathPr>
32 </m:mathPr>
43 <w:themeFontLang w:val="en-US" />
33 <w:themeFontLang w:val="en-US" />
44 <w:clrSchemeMapping w:bg1="light1" w:t1="dark1" w:bg2="light2" w:t2="dark2" w:accent1="accent1" w:accent2="accent2" w:accent3="accent3" w:accent4="accent4" w:accent5="accent5" w:accent6="accent6" w:hyperlink="hyperlink" w:followedHyperlink="followedHyperlink" />
34 <w:clrSchemeMapping w:bg1="light1" w:t1="dark1" w:bg2="light2" w:t2="dark2" w:accent1="accent1" w:accent2="accent2" w:accent3="accent3" w:accent4="accent4" w:accent5="accent5" w:accent6="accent6" w:hyperlink="hyperlink" w:followedHyperlink="followedHyperlink" />
45 <w:decimalSymbol w:val="." />
35 <w:decimalSymbol w:val="." />
46 <w:listSeparator w:val="," />
36 <w:listSeparator w:val="," />
47−</w:settings>
37+</w:settings>
data/templates/default.context+7−3
@@ -51,6 +51,7 @@ $endif$
51
51
52% use microtypography
52% use microtypography
53\definefontfeature[default][default][script=latn, protrusion=quality, expansion=quality, itlc=yes, textitalics=yes, onum=yes, pnum=yes]
53\definefontfeature[default][default][script=latn, protrusion=quality, expansion=quality, itlc=yes, textitalics=yes, onum=yes, pnum=yes]
54+\definefontfeature[default:tnum][default][tnum=yes, pnum=no]
54\definefontfeature[smallcaps][script=latn, protrusion=quality, expansion=quality, smcp=yes, onum=yes, pnum=yes]
55\definefontfeature[smallcaps][script=latn, protrusion=quality, expansion=quality, smcp=yes, onum=yes, pnum=yes]
55\setupalign[hz,hanging]
56\setupalign[hz,hanging]
56\setupitaliccorrection[global, always]
57\setupitaliccorrection[global, always]
@@ -97,6 +98,9 @@ $endif$
97\setupitemize[autointro] % prevent orphan list intro
98\setupitemize[autointro] % prevent orphan list intro
98\setupitemize[indentnext=no]
99\setupitemize[indentnext=no]
99
100
101+\defineitemgroup[enumerate]
102+\setupenumerate[each][fit][itemalign=left,distance=.5em,style={\feature[+][default:tnum]}]
103+
100\setupfloat[figure][default={here,nonumber}]
104\setupfloat[figure][default={here,nonumber}]
101\setupfloat[table][default={here,nonumber}]
105\setupfloat[table][default={here,nonumber}]
102
106
@@ -160,12 +164,12 @@ $endfor$
160$if(toc)$
164$if(toc)$
161\completecontent
165\completecontent
162$endif$
166$endif$
163−$if(lot)$
164−\completelistoftables
165−$endif$
166$if(lof)$
167$if(lof)$
167\completelistoffigures
168\completelistoffigures
168$endif$
169$endif$
170+$if(lot)$
171+\completelistoftables
172+$endif$
169
173
170$body$
174$body$
171
175
data/templates/default.dzslides+1−1
@@ -171,7 +171,7 @@ $if(subtitle)$
171 <h1 class="subtitle">$subtitle$</h1>
171 <h1 class="subtitle">$subtitle$</h1>
172$endif$
172$endif$
173 <footer>
173 <footer>
174− $if(author)$<span class="author">$for(author)$$author$$sep$, $endfor$</span>$endif$ · $if(date)$<span class="date">$date$</span>$endif$
174+ $if(author)$<span class="author">$for(author)$$author$$sep$, $endfor$</span> · $endif$$if(institute)$<span class="institute">$for(institute)$$institute$$sep$, $endfor$</span> · $endif$$if(date)$<span class="date">$date$</span>$endif$
175 </footer>
175 </footer>
176</section>
176</section>
177$endif$
177$endif$
data/templates/default.latex+48−26
@@ -2,7 +2,7 @@
2\PassOptionsToPackage{unicode$for(hyperrefoptions)$,$hyperrefoptions$$endfor$}{hyperref}
2\PassOptionsToPackage{unicode$for(hyperrefoptions)$,$hyperrefoptions$$endfor$}{hyperref}
3\PassOptionsToPackage{hyphens}{url}
3\PassOptionsToPackage{hyphens}{url}
4$if(colorlinks)$
4$if(colorlinks)$
5−\PassOptionsToPackage{dvipsnames,svgnames*,x11names*}{xcolor}
5+\PassOptionsToPackage{dvipsnames,svgnames,x11names}{xcolor}
6$endif$
6$endif$
7$if(dir)$
7$if(dir)$
8$if(latex-dir-rtl)$
8$if(latex-dir-rtl)$
@@ -156,6 +156,25 @@ $if(CJKmainfont)$
156 \fi
156 \fi
157$endif$
157$endif$
158\fi
158\fi
159+$if(zero-width-non-joiner)$
160+%% Support for zero-width non-joiner characters.
161+\makeatletter
162+\def\zerowidthnonjoiner{%
163+ % Prevent ligatures and adjust kerning, but still support hyphenating.
164+ \texorpdfstring{%
165+ \textormath{\nobreak\discretionary{-}{}{\kern.03em}%
166+ \ifvmode\else\nobreak\hskip\z@skip\fi}{}%
167+ }{}%
168+}
169+\makeatother
170+\ifPDFTeX
171+ \DeclareUnicodeCharacter{200C}{\zerowidthnonjoiner}
172+\else
173+ \catcode`^^^^200c=\active
174+ \protected\def ^^^^200c{\zerowidthnonjoiner}
175+\fi
176+%% End of ZWNJ support
177+$endif$
159$if(beamer)$
178$if(beamer)$
160$if(theme)$
179$if(theme)$
161\usetheme[$for(themeoptions)$$themeoptions$$sep$,$endfor$]{$theme$}
180\usetheme[$for(themeoptions)$$themeoptions$$sep$,$endfor$]{$theme$}
@@ -325,6 +344,31 @@ $endif$
325$if(pagestyle)$
344$if(pagestyle)$
326\pagestyle{$pagestyle$}
345\pagestyle{$pagestyle$}
327$endif$
346$endif$
347+$if(csl-refs)$
348+\newlength{\cslhangindent}
349+\setlength{\cslhangindent}{1.5em}
350+\newlength{\csllabelwidth}
351+\setlength{\csllabelwidth}{3em}
352+\newlength{\cslentryspacingunit} % times entry-spacing
353+\setlength{\cslentryspacingunit}{\parskip}
354+\newenvironment{CSLReferences}[2] % #1 hanging-ident, #2 entry spacing
355+ {% don't indent paragraphs
356+ \setlength{\parindent}{0pt}
357+ % turn on hanging indent if param 1 is 1
358+ \ifodd #1
359+ \let\oldpar\par
360+ \def\par{\hangindent=\cslhangindent\oldpar}
361+ \fi
362+ % set entry spacing
363+ \setlength{\parskip}{#2\cslentryspacingunit}
364+ }%
365+ {}
366+\usepackage{calc}
367+\newcommand{\CSLBlock}[1]{#1\hfill\break}
368+\newcommand{\CSLLeftMargin}[1]{\parbox[t]{\csllabelwidth}{#1}}
369+\newcommand{\CSLRightInline}[1]{\parbox[t]{\linewidth - \csllabelwidth}{#1}\break}
370+\newcommand{\CSLIndent}[1]{\hspace{\cslhangindent}#1}
371+$endif$
328$for(header-includes)$
372$for(header-includes)$
329$header-includes$
373$header-includes$
330$endfor$
374$endfor$
@@ -375,28 +419,6 @@ $endif$
375$if(nocite-ids)$
419$if(nocite-ids)$
376\nocite{$for(nocite-ids)$$it$$sep$, $endfor$}
420\nocite{$for(nocite-ids)$$it$$sep$, $endfor$}
377$endif$
421$endif$
378−$if(csl-refs)$
379−\newlength{\cslhangindent}
380−\setlength{\cslhangindent}{1.5em}
381−\newlength{\csllabelwidth}
382−\setlength{\csllabelwidth}{3em}
383−\newenvironment{CSLReferences}[2] % #1 hanging-ident, #2 entry spacing
384− {% don't indent paragraphs
385− \setlength{\parindent}{0pt}
386− % turn on hanging indent if param 1 is 1
387− \ifodd #1 \everypar{\setlength{\hangindent}{\cslhangindent}}\ignorespaces\fi
388− % set entry spacing
389− \ifnum #2 > 0
390− \setlength{\parskip}{#2\baselineskip}
391− \fi
392− }%
393− {}
394−\usepackage{calc}
395−\newcommand{\CSLBlock}[1]{#1\hfill\break}
396−\newcommand{\CSLLeftMargin}[1]{\parbox[t]{\csllabelwidth}{#1}}
397−\newcommand{\CSLRightInline}[1]{\parbox[t]{\linewidth - \csllabelwidth}{#1}\break}
398−\newcommand{\CSLIndent}[1]{\hspace{\cslhangindent}#1}
399−$endif$
400$if(csquotes)$
422$if(csquotes)$
401\usepackage{csquotes}
423\usepackage{csquotes}
402$endif$
424$endif$
@@ -472,12 +494,12 @@ $endif$
472}
494}
473$endif$
495$endif$
474$endif$
496$endif$
475−$if(lot)$
476−\listoftables
477−$endif$
478$if(lof)$
497$if(lof)$
479\listoffigures
498\listoffigures
480$endif$
499$endif$
500+$if(lot)$
501+\listoftables
502+$endif$
481$if(linestretch)$
503$if(linestretch)$
482\setstretch{$linestretch$}
504\setstretch{$linestretch$}
483$endif$
505$endif$
data/templates/default.revealjs+78−128
@@ -52,6 +52,9 @@ $endif$
52$for(author)$
52$for(author)$
53 <p class="author">$author$</p>
53 <p class="author">$author$</p>
54$endfor$
54$endfor$
55+$for(institute)$
56+ <p class="institute">$institute$</p>
57+$endfor$
55$if(date)$
58$if(date)$
56 <p class="date">$date$</p>
59 <p class="date">$date$</p>
57$endif$
60$endif$
@@ -59,7 +62,12 @@ $endif$
59$endif$
62$endif$
60$if(toc)$
63$if(toc)$
61<section id="$idprefix$TOC">
64<section id="$idprefix$TOC">
65+<nav role="doc-toc">
66+$if(toc-title)$
67+<h2 id="$idprefix$toc-title">$toc-title$</h2>
68+$endif$
62$table-of-contents$
69$table-of-contents$
70+</nav>
63</section>
71</section>
64$endif$
72$endif$
65
73
@@ -82,256 +90,198 @@ $endif$
82 // Full list of configuration options available at:
90 // Full list of configuration options available at:
83 // https://revealjs.com/config/
91 // https://revealjs.com/config/
84 Reveal.initialize({
92 Reveal.initialize({
85−$if(center)$
86− // Determines whether slide content should be vertically centered
87− center: $center$,
88−$endif$
89−$if(controls)$
90 // Display controls in the bottom right corner
93 // Display controls in the bottom right corner
91 controls: $controls$,
94 controls: $controls$,
92−$endif$
95+
93−$if(controlsTutorial)$
94 // Help the user learn the controls by providing hints, for example by
96 // Help the user learn the controls by providing hints, for example by
95 // bouncing the down arrow when they first encounter a vertical slide
97 // bouncing the down arrow when they first encounter a vertical slide
96 controlsTutorial: $controlsTutorial$,
98 controlsTutorial: $controlsTutorial$,
97−$endif$
99+
98−$if(controlsLayout)$
99 // Determines where controls appear, "edges" or "bottom-right"
100 // Determines where controls appear, "edges" or "bottom-right"
100 controlsLayout: '$controlsLayout$',
101 controlsLayout: '$controlsLayout$',
101−$endif$
102+
102−$if(controlsBackArrows)$
103 // Visibility rule for backwards navigation arrows; "faded", "hidden"
103 // Visibility rule for backwards navigation arrows; "faded", "hidden"
104 // or "visible"
104 // or "visible"
105 controlsBackArrows: '$controlsBackArrows$',
105 controlsBackArrows: '$controlsBackArrows$',
106−$endif$
106+
107−$if(progress)$
108 // Display a presentation progress bar
107 // Display a presentation progress bar
109 progress: $progress$,
108 progress: $progress$,
110−$endif$
109+
111−$if(slideNumber)$
112 // Display the page number of the current slide
110 // Display the page number of the current slide
113 slideNumber: $slideNumber$,
111 slideNumber: $slideNumber$,
114−$endif$
112+
115−$if(showSlideNumber)$
116 // 'all', 'print', or 'speaker'
113 // 'all', 'print', or 'speaker'
117 showSlideNumber: '$showSlideNumber$',
114 showSlideNumber: '$showSlideNumber$',
118−$endif$
115+
119−$if(hash)$
120 // Add the current slide number to the URL hash so that reloading the
116 // Add the current slide number to the URL hash so that reloading the
121 // page/copying the URL will return you to the same slide
117 // page/copying the URL will return you to the same slide
122 hash: $hash$,
118 hash: $hash$,
123−$endif$
119+
124−$if(hashOneBasedIndex)$
125 // Start with 1 for the hash rather than 0
120 // Start with 1 for the hash rather than 0
126 hashOneBasedIndex: $hashOneBasedIndex$,
121 hashOneBasedIndex: $hashOneBasedIndex$,
127−$endif$
122+
123+ // Flags if we should monitor the hash and change slides accordingly
124+ respondToHashChanges: $respondToHashChanges$,
125+
128 // Push each slide change to the browser history
126 // Push each slide change to the browser history
129− history: $if(history)$$history$$else$true$endif$,
127+ history: $history$,
130−$if(keyboard)$
128+
131 // Enable keyboard shortcuts for navigation
129 // Enable keyboard shortcuts for navigation
132 keyboard: $keyboard$,
130 keyboard: $keyboard$,
133−$endif$
131+
134−$if(overview)$
135 // Enable the slide overview mode
132 // Enable the slide overview mode
136 overview: $overview$,
133 overview: $overview$,
137−$endif$
134+
138−$if(center)$
135+ // Disables the default reveal.js slide layout (scaling and centering)
136+ // so that you can use custom CSS layout
137+ disableLayout: false,
138+
139 // Vertical centering of slides
139 // Vertical centering of slides
140 center: $center$,
140 center: $center$,
141−$endif$
141+
142−$if(touch)$
143 // Enables touch navigation on devices with touch input
142 // Enables touch navigation on devices with touch input
144 touch: $touch$,
143 touch: $touch$,
145−$endif$
144+
146−$if(loop)$
147 // Loop the presentation
145 // Loop the presentation
148 loop: $loop$,
146 loop: $loop$,
149−$endif$
147+
150−$if(rtl)$
151 // Change the presentation direction to be RTL
148 // Change the presentation direction to be RTL
152 rtl: $rtl$,
149 rtl: $rtl$,
153−$endif$
150+
154−$if(navigationMode)$
155 // see https://revealjs.com/vertical-slides/#navigation-mode
151 // see https://revealjs.com/vertical-slides/#navigation-mode
156 navigationMode: '$navigationMode$',
152 navigationMode: '$navigationMode$',
157−$endif$
153+
158−$if(shuffle)$
159 // Randomizes the order of slides each time the presentation loads
154 // Randomizes the order of slides each time the presentation loads
160 shuffle: $shuffle$,
155 shuffle: $shuffle$,
161−$endif$
156+
162−$if(fragments)$
163 // Turns fragments on and off globally
157 // Turns fragments on and off globally
164 fragments: $fragments$,
158 fragments: $fragments$,
165−$endif$
159+
166−$if(fragmentInURL)$
167 // Flags whether to include the current fragment in the URL,
160 // Flags whether to include the current fragment in the URL,
168 // so that reloading brings you to the same fragment position
161 // so that reloading brings you to the same fragment position
169 fragmentInURL: $fragmentInURL$,
162 fragmentInURL: $fragmentInURL$,
170−$endif$
163+
171−$if(embedded)$
172 // Flags if the presentation is running in an embedded mode,
164 // Flags if the presentation is running in an embedded mode,
173 // i.e. contained within a limited portion of the screen
165 // i.e. contained within a limited portion of the screen
174 embedded: $embedded$,
166 embedded: $embedded$,
175−$endif$
167+
176−$if(help)$
177 // Flags if we should show a help overlay when the questionmark
168 // Flags if we should show a help overlay when the questionmark
178 // key is pressed
169 // key is pressed
179 help: $help$,
170 help: $help$,
180−$endif$
171+
181−$if(pause)$
182− // Flags if it should be possible to pause the presentation (blackout)
172+ // Flags if it should be possible to pause the presentation (blackout)
183− pause: $pause$,
173+ pause: $pause$,
184−$endif$
174+
185−$if(showNotes)$
186 // Flags if speaker notes should be visible to all viewers
175 // Flags if speaker notes should be visible to all viewers
187 showNotes: $showNotes$,
176 showNotes: $showNotes$,
188−$endif$
177+
189−$if(autoPlayMedia)$
190− // Global override for autoplaying embedded media (video/audio/iframe)
178+ // Global override for autoplaying embedded media (null/true/false)
191− // - null: Media will only autoplay if data-autoplay is present
192− // - true: All media will autoplay, regardless of individual setting
193− // - false: No media will autoplay, regardless of individual setting
194 autoPlayMedia: $autoPlayMedia$,
179 autoPlayMedia: $autoPlayMedia$,
195−$endif$
180+
196−$if(preloadIframes)$
197− // Global override for preloading lazy-loaded iframes
181+ // Global override for preloading lazy-loaded iframes (null/true/false)
198− // - null: Iframes with data-src AND data-preload will be loaded when within
199− // the viewDistance, iframes with only data-src will be loaded when visible
200− // - true: All iframes with data-src will be loaded when within the viewDistance
201− // - false: All iframes with data-src will be loaded only when visible
202 preloadIframes: $preloadIframes$,
182 preloadIframes: $preloadIframes$,
203−$endif$
183+
204−$if(autoSlide)$
205 // Number of milliseconds between automatically proceeding to the
184 // Number of milliseconds between automatically proceeding to the
206 // next slide, disabled when set to 0, this value can be overwritten
185 // next slide, disabled when set to 0, this value can be overwritten
207 // by using a data-autoslide attribute on your slides
186 // by using a data-autoslide attribute on your slides
208 autoSlide: $autoSlide$,
187 autoSlide: $autoSlide$,
209−$endif$
188+
210−$if(autoSlideStoppable)$
211 // Stop auto-sliding after user input
189 // Stop auto-sliding after user input
212 autoSlideStoppable: $autoSlideStoppable$,
190 autoSlideStoppable: $autoSlideStoppable$,
213−$endif$
191+
214−$if(autoSlideMethod)$
215 // Use this method for navigation when auto-sliding
192 // Use this method for navigation when auto-sliding
216 autoSlideMethod: $autoSlideMethod$,
193 autoSlideMethod: $autoSlideMethod$,
217−$endif$
194+
218−$if(defaultTiming)$
219 // Specify the average time in seconds that you think you will spend
195 // Specify the average time in seconds that you think you will spend
220 // presenting each slide. This is used to show a pacing timer in the
196 // presenting each slide. This is used to show a pacing timer in the
221 // speaker view
197 // speaker view
222 defaultTiming: $defaultTiming$,
198 defaultTiming: $defaultTiming$,
223−$endif$
199+
224−$if(totalTime)$
225− // Specify the total time in seconds that is available to
226− // present. If this is set to a nonzero value, the pacing
227− // timer will work out the time available for each slide,
228− // instead of using the defaultTiming value
229− totalTime: $totalTime$,
230−$endif$
231−$if(minimumTimePerSlide)$
232− // Specify the minimum amount of time you want to allot to
233− // each slide, if using the totalTime calculation method. If
234− // the automated time allocation causes slide pacing to fall
235− // below this threshold, then you will see an alert in the
236− // speaker notes window
237− minimumTimePerSlide: $minimumTimePerSlide$,
238−$endif$
239−$if(mouseWheel)$
240 // Enable slide navigation via mouse wheel
200 // Enable slide navigation via mouse wheel
241 mouseWheel: $mouseWheel$,
201 mouseWheel: $mouseWheel$,
242−$endif$
202+
243−$if(rollingLinks)$
203+ // The display mode that will be used to show slides
244− // Apply a 3D roll to links on hover
204+ display: '$display$',
245− rollingLinks: $rollingLinks$,
205+
246−$endif$
247−$if(hideInactiveCursor)$
248 // Hide cursor if inactive
206 // Hide cursor if inactive
249 hideInactiveCursor: $hideInactiveCursor$,
207 hideInactiveCursor: $hideInactiveCursor$,
250−$endif$
208+
251−$if(hideCursorTime)$
252 // Time before the cursor is hidden (in ms)
209 // Time before the cursor is hidden (in ms)
253 hideCursorTime: $hideCursorTime$,
210 hideCursorTime: $hideCursorTime$,
254−$endif$
211+
255−$if(hideAddressBar)$
256− // Hides the address bar on mobile devices
257− hideAddressBar: $hideAddressBar$,
258−$endif$
259−$if(previewLinks)$
260 // Opens links in an iframe preview overlay
212 // Opens links in an iframe preview overlay
261 previewLinks: $previewLinks$,
213 previewLinks: $previewLinks$,
262−$endif$
214+
263−$if(transition)$
264− // Transition style
265− transition: '$transition$', // none/fade/slide/convex/concave/zoom
215+ // Transition style (none/fade/slide/convex/concave/zoom)
266−$endif$
216+ transition: '$transition$',
267−$if(transitionSpeed)$
217+
268− // Transition speed
218+ // Transition speed (default/fast/slow)
269− transitionSpeed: '$transitionSpeed$', // default/fast/slow
219+ transitionSpeed: '$transitionSpeed$',
270−$endif$
220+
271−$if(backgroundTransition)$
272 // Transition style for full page slide backgrounds
221 // Transition style for full page slide backgrounds
273− backgroundTransition: '$backgroundTransition$', // none/fade/slide/convex/concave/zoom
222+ // (none/fade/slide/convex/concave/zoom)
274−$endif$
223+ backgroundTransition: '$backgroundTransition$',
275−$if(viewDistance)$
224+
276 // Number of slides away from the current that are visible
225 // Number of slides away from the current that are visible
277 viewDistance: $viewDistance$,
226 viewDistance: $viewDistance$,
278−$endif$
227+
279−$if(mobileViewDistance)$
280 // Number of slides away from the current that are visible on mobile
228 // Number of slides away from the current that are visible on mobile
281 // devices. It is advisable to set this to a lower number than
229 // devices. It is advisable to set this to a lower number than
282 // viewDistance in order to save resources.
230 // viewDistance in order to save resources.
283 mobileViewDistance: $mobileViewDistance$,
231 mobileViewDistance: $mobileViewDistance$,
284−$endif$
285$if(parallaxBackgroundImage)$
232$if(parallaxBackgroundImage)$
233+
286 // Parallax background image
234 // Parallax background image
287 parallaxBackgroundImage: '$parallaxBackgroundImage$', // e.g. "'https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg'"
235 parallaxBackgroundImage: '$parallaxBackgroundImage$', // e.g. "'https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg'"
288$else$
236$else$
289$if(background-image)$
237$if(background-image)$
238+
290 // Parallax background image
239 // Parallax background image
291 parallaxBackgroundImage: '$background-image$', // e.g. "'https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg'"
240 parallaxBackgroundImage: '$background-image$', // e.g. "'https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg'"
292$endif$
241$endif$
293$endif$
242$endif$
294$if(parallaxBackgroundSize)$
243$if(parallaxBackgroundSize)$
244+
295 // Parallax background size
245 // Parallax background size
296 parallaxBackgroundSize: '$parallaxBackgroundSize$', // CSS syntax, e.g. "2100px 900px"
246 parallaxBackgroundSize: '$parallaxBackgroundSize$', // CSS syntax, e.g. "2100px 900px"
297$endif$
247$endif$
298$if(parallaxBackgroundHorizontal)$
248$if(parallaxBackgroundHorizontal)$
249+
299 // Amount to move parallax background (horizontal and vertical) on slide change
250 // Amount to move parallax background (horizontal and vertical) on slide change
300 // Number, e.g. 100
251 // Number, e.g. 100
301 parallaxBackgroundHorizontal: $parallaxBackgroundHorizontal$,
252 parallaxBackgroundHorizontal: $parallaxBackgroundHorizontal$,
302$endif$
253$endif$
303$if(parallaxBackgroundVertical)$
254$if(parallaxBackgroundVertical)$
255+
304 parallaxBackgroundVertical: $parallaxBackgroundVertical$,
256 parallaxBackgroundVertical: $parallaxBackgroundVertical$,
305$endif$
257$endif$
306$if(width)$
258$if(width)$
259+
307 // The "normal" size of the presentation, aspect ratio will be preserved
260 // The "normal" size of the presentation, aspect ratio will be preserved
308 // when the presentation is scaled to fit different resolutions. Can be
261 // when the presentation is scaled to fit different resolutions. Can be
309 // specified using percentage units.
262 // specified using percentage units.
310 width: $width$,
263 width: $width$,
311$endif$
264$endif$
312$if(height)$
265$if(height)$
266+
313 height: $height$,
267 height: $height$,
314$endif$
268$endif$
315$if(margin)$
269$if(margin)$
270+
316 // Factor of the display size that should remain empty around the content
271 // Factor of the display size that should remain empty around the content
317 margin: $margin$,
272 margin: $margin$,
318$endif$
273$endif$
319$if(minScale)$
274$if(minScale)$
275+
320 // Bounds for smallest/largest possible scale to apply to content
276 // Bounds for smallest/largest possible scale to apply to content
321 minScale: $minScale$,
277 minScale: $minScale$,
322$endif$
278$endif$
323$if(maxScale)$
279$if(maxScale)$
280+
324 maxScale: $maxScale$,
281 maxScale: $maxScale$,
325$endif$
282$endif$
326−$if(zoomKey)$
327− // Modifier key used to click-zoom to part of the slide
328− zoomKey: '$zoomKey$',
329−$endif$
330−$if(display)$
331− // The display mode that will be used to show slides
332− display: '$display$',
333−$endif$
334$if(mathjax)$
283$if(mathjax)$
284+
335 math: {
285 math: {
336 mathjax: '$mathjaxurl$',
286 mathjax: '$mathjaxurl$',
337 config: 'TeX-AMS_HTML-full',
287 config: 'TeX-AMS_HTML-full',
data/templates/default.s5+3
@@ -61,6 +61,9 @@ $endif$
61$if(author)$
61$if(author)$
62 <h3 class="author">$for(author)$$author$$sep$<br/>$endfor$</h3>
62 <h3 class="author">$for(author)$$author$$sep$<br/>$endfor$</h3>
63$endif$
63$endif$
64+$if(institute)$
65+ <h3 class="institute">$for(institute)$$institute$$sep$<br/>$endfor$</h3>
66+$endif$
64$if(date)$
67$if(date)$
65 <h4 class="date">$date$</h4>
68 <h4 class="date">$date$</h4>
66$endif$
69$endif$
data/templates/default.slideous+7
@@ -63,9 +63,16 @@ $if(title)$
63$if(subtitle)$
63$if(subtitle)$
64 <h1 class="subtitle">$subtitle$</h1>
64 <h1 class="subtitle">$subtitle$</h1>
65$endif$
65$endif$
66+$if(author)$
66 <p class="author">
67 <p class="author">
67$for(author)$$author$$sep$<br/>$endfor$
68$for(author)$$author$$sep$<br/>$endfor$
68 </p>
69 </p>
70+$endif$
71+$if(institute)$
72+ <p class="institute">
73+$for(institute)$$institute$$sep$<br/>$endfor$
74+ </p>
75+$endif$
69$if(date)$
76$if(date)$
70 <p class="date">$date$</p>
77 <p class="date">$date$</p>
71$endif$
78$endif$
data/templates/default.slidy+5
@@ -52,6 +52,11 @@ $if(author)$
52$for(author)$$author$$sep$<br/>$endfor$
52$for(author)$$author$$sep$<br/>$endfor$
53 </p>
53 </p>
54$endif$
54$endif$
55+$if(institute)$
56+ <p class="institute">
57+$for(institute)$$institute$$sep$<br/>$endfor$
58+ </p>
59+$endif$
55$if(date)$
60$if(date)$
56 <p class="date">$date$</p>
61 <p class="date">$date$</p>
57$endif$
62$endif$
data/templates/styles.html+2−1
@@ -14,7 +14,7 @@ body {
14 padding-top: $if(margin-top)$$margin-top$$else$50px$endif$;
14 padding-top: $if(margin-top)$$margin-top$$else$50px$endif$;
15 padding-bottom: $if(margin-bottom)$$margin-bottom$$else$50px$endif$;
15 padding-bottom: $if(margin-bottom)$$margin-bottom$$else$50px$endif$;
16 hyphens: auto;
16 hyphens: auto;
17− word-wrap: break-word;
17+ overflow-wrap: break-word;
18 text-rendering: optimizeLegibility;
18 text-rendering: optimizeLegibility;
19 font-kerning: normal;
19 font-kerning: normal;
20}
20}
@@ -93,6 +93,7 @@ $endif$
93pre code {
93pre code {
94 padding: 0;
94 padding: 0;
95 overflow: visible;
95 overflow: visible;
96+ overflow-wrap: normal;
96}
97}
97.sourceCode {
98.sourceCode {
98 background-color: transparent;
99 background-color: transparent;
doc/epub.md+9−2
@@ -141,8 +141,15 @@ Pandoc has an EPUB3 writer. It renders LaTeX math into MathML, which
141EPUB3 readers are supposed to support (but unfortunately few do).
141EPUB3 readers are supposed to support (but unfortunately few do).
142
142
143Of course, this isn't much help if you want EPUB2 output (`pandoc -t epub2`)
143Of course, this isn't much help if you want EPUB2 output (`pandoc -t epub2`)
144−or target readers that don't support MathML. Then you should try using the
144+or target readers that don't support MathML. Then you have two options:
145+
146+1. Use the [`--webtex`](https://pandoc.org/MANUAL.html#option--webtex) option,
145−`--webtex` option, which will use a web service to convert the TeX to an image.
147+ which will use a web service to convert the TeX to an image.
148+2. Use the [`--gladtex`](https://pandoc.org/MANUAL.html#option--gladtex) option
149+ to convert maths into SVG images on your local machine.
150+
151+Both GladTeX and WebTeX add the LaTeX source of the formula as alternative text
152+of the image, increasing accessibility for blind users.
146
153
147[KindleGen]: https://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211
154[KindleGen]: https://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211
148[EPUB]: https://en.wikipedia.org/wiki/EPUB
155[EPUB]: https://en.wikipedia.org/wiki/EPUB
doc/faqs.mdnew file+128
@@ -0,0 +1,128 @@
1+% FAQs
2+
3+::: faqs
4+
5+## How can I convert a whole directory of files from Markdown to RTF?
6+
7+On linux or OSX:
8+
9+ for f in *.txt; do pandoc "$f" -s -o "${f%.txt}.rtf"; done
10+
11+
12+In Windows Powershell:
13+
14+ gci -r -i *.txt |foreach{$rtf=$_.directoryname+"\"+$_.basename+".rtf";pandoc -f markdown -s $_.name -o $rtf}
15+
16+## I used pandoc to convert a document to ICML (or OPML or RTF), and when I try to open it I'm told it's invalid. What have I done wrong?
17+
18+Be sure to use the `-s` or `--standalone` flag, or you just get a
19+fragment, not a full document with the required header:
20+
21+ pandoc -s -f markdown -t icml -o my.icml my.md
22+
23+## I get a blank document when I try to convert a markdown document in Chinese to PDF.
24+
25+By default, pandoc uses pdflatex to generate the PDF, and pdflatex
26+doesn't handle Chinese characters. But you can change the default to
27+use xelatex instead. You should also make sure you're using a font
28+with Chinese glyphs. For example:
29+
30+ pandoc -o c.pdf --pdf-engine=xelatex -V mainfont='Adobe Ming Std'
31+
32+## The Windows installer does a single user install, rather than installing pandoc for all users. How can I install pandoc for all users?
33+
34+Run the following command as admin:
35+
36+ msiexec /i pandoc-VERSION.msi ALLUSERS=1
37+
38+This will put pandoc in `C:\Program Files\Pandoc`.
39+You can install Pandoc to a different directory by setting APPLICATIONFOLDER parameter,
40+for example:
41+
42+ msiexec /i pandoc-1.11.1.msi ALLUSERS=1 APPLICATIONFOLDER="C:\Pandoc"
43+
44+## How do I change the margins in PDF output?
45+
46+The option
47+
48+ -V geometry:margin=1in
49+
50+will set the margins to one inch on each side. If you don't want uniform
51+margins, you can do something like
52+
53+ -V geometry:"top=2cm, bottom=1.5cm, left=1cm, right=1cm"
54+
55+Or
56+
57+ -V geometry:"left=3cm, width=10cm"
58+
59+For more options, see the documentation for the LaTeX [geometry
60+package](https://www.ctan.org/pkg/geometry).
61+
62+## How does pandoc compare to multimarkdown?
63+
64+Here is a [wiki
65+page](https://github.com/jgm/pandoc/wiki/Pandoc-vs-Multimarkdown)
66+comparing the two.
67+
68+## When I specify an image width of 50% and convert to LaTeX, pandoc sets the height to textheight and the aspect ratio isn't preserved. How can I prevent this?
69+
70+For example, if you convert an image with `{width="50%"}`, the LaTeX produced
71+will be `\includegraphics[width=0.5\textwidth,height=\textheight]`.
72+
73+This output presupposes the following code in pandoc's default latex
74+template:
75+
76+```
77+% Scale images if necessary, so that they will not overflow the page
78+% margins by default, and it is still possible to overwrite the defaults
79+% using explicit options in \includegraphics[width, height, ...]{}
80+\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
81+```
82+
83+If you don't have this in your custom template, you should
84+add it. If we didn't set the `height` explicitly in this way,
85+the image would not be resized correctly unless it was
86+being resized to smaller than its original size.
87+
88+## Pandoc sometimes uses too much memory. How can I limit the memory used by pandoc?
89+
90+`pandoc +RTS -M30m -RTS` will limit heap memory to 30MB.
91+When converting a document requires more than this, an out of
92+memory error will be issued.
93+
94+## When using `--include-in-header` with PDF or LaTeX output, how do I reference tex declarations coming after `$header-includes$` in the default template?
95+
96+For various reasons, the `$header-includes$` are not at the very
97+end of the LaTeX preamble. This poses a problem when the code
98+you are inserting depends on declarations in the preamble coming
99+after the `$header-includes$` location. For example, you might
100+want to reference the `\author` and `\title` metadata values
101+(set at the very bottom of the preamble) and present them in
102+margins. In that case you can wrap your code in `etoolbox`'s
103+`\AtEndPreamble`. The technique is demonstrated in [this
104+gist](https://gist.github.com/JohnLukeBentley/9dda6166b9ee5c4127afd2b8cd16b70a).
105+When using `\AtEndPreamble`, keep any `makeatletter` or
106+`makeatother` outside of the `\AtEndPreamble`, as shown in the
107+example.
108+
109+## How can I convert PDFs to other formats using pandoc?
110+
111+You can't. You can try opening the PDF in Word or Google Docs
112+and saving in a format from which pandoc can convert directly.
113+
114+## Do I really need to install a 1 GB TeX installation to produce a PDF using pandoc?
115+
116+No. You can get by with a relatively small TeX installation,
117+for example, by starting with MacTeX's Basic TeX distribution
118+and using the `tlmgr` tool to install a few packages required by pandoc
119+(see https://pandoc.org/MANUAL.html#creating-a-pdf).
120+
121+Or, you can produce PDFs via HTML and `wkhtmltopdf`,
122+or via groff ms and `pdfroff`. (These don't produce as nice
123+topography as TeX, particularly when it comes to math, but they
124+may be fine for many purposes.)
125+
126+
127+:::
128+
doc/filters.md+2
@@ -394,6 +394,8 @@ automatically assign it `Just` the target format or `Nothing`.
394
394
395We compile our script:
395We compile our script:
396
396
397+ # first, make sure pandoc-types is installed:
398+ cabal install --lib pandoc-types --package-env .
397 ghc --make handleRuby
399 ghc --make handleRuby
398
400
399Then run it:
401Then run it:
doc/libraries.md+4
@@ -15,6 +15,9 @@ pandoc:
15[texmath]
15[texmath]
16: Conversion of math between tex, Word equation, MathML, and GNU eqn.
16: Conversion of math between tex, Word equation, MathML, and GNU eqn.
17
17
18+[unicode-collation]
19+: Proper Unicode collation (sorting).
20+
18[doclayout]
21[doclayout]
19: Combinators for laying out a textual document, with support
22: Combinators for laying out a textual document, with support
20 for line wrapping, tabular layout, and more.
23 for line wrapping, tabular layout, and more.
@@ -56,4 +59,5 @@ pandoc:
56[rfc5051]: https://hackage.haskell.org/package/rfc5051
59[rfc5051]: https://hackage.haskell.org/package/rfc5051
57[emojis]: https://hackage.haskell.org/package/emojis
60[emojis]: https://hackage.haskell.org/package/emojis
58[jira-wiki-markup]: https://hackage.haskell.org/package/jira-wiki-markup
61[jira-wiki-markup]: https://hackage.haskell.org/package/jira-wiki-markup
62+[unicode-collation]: https://hackage.haskell.org/package/unicode-collation
59
63
doc/lua-filters.md+2−2
@@ -109,7 +109,7 @@ element filtering function. In other words, filter entries will
109be called for each corresponding element in the document,
109be called for each corresponding element in the document,
110getting the respective element as input.
110getting the respective element as input.
111
111
112−The return of a filter function must one of the following:
112+The return of a filter function must be one of the following:
113
113
114- nil: this means that the object should remain unchanged.
114- nil: this means that the object should remain unchanged.
115- a pandoc object: this must be of the same type as the input
115- a pandoc object: this must be of the same type as the input
@@ -3205,7 +3205,7 @@ Usage:
3205
3205
3206# Module pandoc.List
3206# Module pandoc.List
3207
3207
3208−The this module defines pandoc's list type. It comes with useful
3208+This module defines pandoc's list type. It comes with useful
3209methods and convenience functions.
3209methods and convenience functions.
3210
3210
3211## Constructor
3211## Constructor
doc/org.md+16−2
@@ -25,8 +25,7 @@ The following export keywords are supported:
25- LANGUAGE: document language; included as plain-text metadata
25- LANGUAGE: document language; included as plain-text metadata
26 field `lang`. The value should be a [BCP47 language tag].
26 field `lang`. The value should be a [BCP47 language tag].
27
27
28−- SELECT_TAGS: tags which select a tree for export. Currently
28+- SELECT_TAGS: tags which select a tree for export.
29− *unsupported*.
30
29
31- EXCLUDE\_TAGS: tags which prevent a subtree from being
30- EXCLUDE\_TAGS: tags which prevent a subtree from being
32 exported. Fully supported.
31 exported. Fully supported.
@@ -37,6 +36,21 @@ The following export keywords are supported:
37 defaults to stdout unless a target has to be given as a command
36 defaults to stdout unless a target has to be given as a command
38 line option.
37 line option.
39
38
39+::: {.alert .alert-info}
40+Pandoc tries to be compatible with org-mode when exporting an org document. If
41+you find some behavior confusing, please do refer to org-mode
42+[Export-Settings](https://orgmode.org/manual/Export-Settings.html)
43+documentation. For example, a common confusion
44+([#3214](https://github.com/jgm/pandoc/issues/3214 "Problem with headers lower
45+then 3 in org-mode reader"), [#5169](https://github.com/jgm/pandoc/issues/5169
46+"org mode headings past level three converted to numbered outline list"),
47+[#6145](https://github.com/jgm/pandoc/issues/6145 "Headers 4 levels deep render
48+differently"), [#7236](https://github.com/jgm/pandoc/issues/7236 "In Org mode,
49+Header with level > 3 are not recognized as headers")) is treatment of headers
50+with level > 3 differently because org-mode sets `org-export-headline-levels`
51+(configurable with `#+OPTIONS: H:3`) to 3 by default.
52+:::
53+
40[BCP47 language tag]: https://tools.ietf.org/html/bcp47
54[BCP47 language tag]: https://tools.ietf.org/html/bcp47
41
55
42Format-specific options
56Format-specific options
doc/using-the-pandoc-api.md+25−12
@@ -14,7 +14,7 @@ and types is available at
14Pandoc is structured as a set of *readers*, which translate
14Pandoc is structured as a set of *readers*, which translate
15various input formats into an abstract syntax tree (the
15various input formats into an abstract syntax tree (the
16Pandoc AST) representing a structured document, and a set of
16Pandoc AST) representing a structured document, and a set of
17−*writers*, which render this AST into various input formats.
17+*writers*, which render this AST into various output formats.
18Pictorially:
18Pictorially:
19
19
20```
20```
@@ -90,8 +90,14 @@ Some notes:
90Let's look at the types of `readMarkdown` and `writeRST`:
90Let's look at the types of `readMarkdown` and `writeRST`:
91
91
92```haskell
92```haskell
93−readMarkdown :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
93+readMarkdown :: (PandocMonad m, ToSources a)
94+ => ReaderOptions
95+ -> a
96+ -> m Pandoc
94−writeRST :: PandocMonad m => WriterOptions -> Pandoc -> m Text
97+writeRST :: PandocMonad m
98+ => WriterOptions
99+ -> Pandoc
100+ -> m Text
95```
101```
96
102
97The `PandocMonad m =>` part is a typeclass constraint.
103The `PandocMonad m =>` part is a typeclass constraint.
@@ -133,7 +139,7 @@ report :: PandocMonad m => LogMessage -> m ()
133-- | Fetch an image or other item from the local filesystem or the net.
139-- | Fetch an image or other item from the local filesystem or the net.
134-- Returns raw content and maybe mime type.
140-- Returns raw content and maybe mime type.
135fetchItem :: PandocMonad m
141fetchItem :: PandocMonad m
136− => String
142+ => Text
137 -> m (B.ByteString, Maybe MimeType)
143 -> m (B.ByteString, Maybe MimeType)
138
144
139-- Set the resource path searched by 'fetchItem'.
145-- Set the resource path searched by 'fetchItem'.
@@ -155,6 +161,13 @@ Note that `PandocIO` is an instance of `MonadIO`, so you can
155use `liftIO` to perform arbitrary IO operations inside a pandoc
161use `liftIO` to perform arbitrary IO operations inside a pandoc
156conversion chain.
162conversion chain.
157
163
164+`readMarkdown` is polymorphic in its second argument, which
165+can be any type that is an instance of the `ToSources`
166+typeclass. You can use `Text`, as in the example above.
167+But you can also use `[(FilePath, Text)]`, if the input comes
168+from multiple files and you want to track source positions
169+accurately.
170+
158# Options
171# Options
159
172
160The first argument of each reader or writer is for
173The first argument of each reader or writer is for
@@ -200,8 +213,8 @@ of the Monoid typeclass and can easily be concatenated:
200import Text.Pandoc.Builder
213import Text.Pandoc.Builder
201
214
202mydoc :: Pandoc
215mydoc :: Pandoc
203−mydoc = doc $ header 1 (text "Hello!")
216+mydoc = doc $ header 1 (text (T.pack "Hello!"))
204− <> para (emph (text "hello world") <> text ".")
217+ <> para (emph (text (T.pack "hello world")) <> text (T.pack "."))
205
218
206main :: IO ()
219main :: IO ()
207main = print mydoc
220main = print mydoc
@@ -248,16 +261,16 @@ import qualified Data.Text as T
248import Data.List (intersperse)
261import Data.List (intersperse)
249
262
250data Station = Station{
263data Station = Station{
251− address :: String
264+ address :: T.Text
252− , name :: String
265+ , name :: T.Text
253− , cardsAccepted :: [String]
266+ , cardsAccepted :: [T.Text]
254 } deriving Show
267 } deriving Show
255
268
256instance FromJSON Station where
269instance FromJSON Station where
257 parseJSON (Object v) = Station <$>
270 parseJSON (Object v) = Station <$>
258 v .: "street_address" <*>
271 v .: "street_address" <*>
259 v .: "station_name" <*>
272 v .: "station_name" <*>
260− (words <$> (v .:? "cards_accepted" .!= ""))
273+ (T.words <$> (v .:? "cards_accepted" .!= ""))
261 parseJSON _ = mzero
274 parseJSON _ = mzero
262
275
263createLetter :: [Station] -> Pandoc
276createLetter :: [Station] -> Pandoc
@@ -315,7 +328,7 @@ users to override the system defaults. If you want to disable
315this behavior, use `setUserDataDir Nothing`.
328this behavior, use `setUserDataDir Nothing`.
316
329
317To render a template, use `renderTemplate'`, which takes two
330To render a template, use `renderTemplate'`, which takes two
318−arguments, a template (String) and a context (any instance
331+arguments, a template (Text) and a context (any instance
319of ToJSON). If you want to create a context from the metadata
332of ToJSON). If you want to create a context from the metadata
320part of a Pandoc document, use `metaToJSON'` from
333part of a Pandoc document, use `metaToJSON'` from
321[Text.Pandoc.Writers.Shared]. If you also want to incorporate
334[Text.Pandoc.Writers.Shared]. If you also want to incorporate
@@ -413,7 +426,7 @@ concatenated together. Here's an example that returns a
413list of the URLs linked to in a document:
426list of the URLs linked to in a document:
414
427
415```haskell
428```haskell
416−listURLs :: Pandoc -> [String]
429+listURLs :: Pandoc -> [Text]
417listURLs = query urls
430listURLs = query urls
418 where urls (Link _ _ (src, _)) = [src]
431 where urls (Link _ _ (src, _)) = [src]
419 urls _ = []
432 urls _ = []
man/pandoc.1+187−39
@@ -1,7 +1,7 @@
1'\" t
1'\" t
2−.\" Automatically generated by Pandoc 2.12
2+.\" Automatically generated by Pandoc 2.14.0.1
3.\"
3.\"
4−.TH "Pandoc User\[cq]s Guide" "" "March 8, 2021" "pandoc 2.12" ""
4+.TH "Pandoc User\[cq]s Guide" "" "June 20, 2021" "pandoc 2.14.0.3" ""
5.hy
5.hy
6.SH NAME
6.SH NAME
7pandoc - general markup converter
7pandoc - general markup converter
@@ -716,11 +716,11 @@ Extract images and other media contained in or linked from the source
716document to the path \f[I]DIR\f[R], creating it if necessary, and adjust
716document to the path \f[I]DIR\f[R], creating it if necessary, and adjust
717the images references in the document so they point to the extracted
717the images references in the document so they point to the extracted
718files.
718files.
719+Media are downloaded, read from the file system, or extracted from a
719−If the source format is a binary container (docx, epub, or odt), the
720+binary container (e.g.\ docx), as needed.
720−media is extracted from the container and the original filenames are
721+The original file paths are used if they are relative paths not
721−used.
722+containing \f[C]..\f[R].
722−Otherwise the media is read from the file system or downloaded, and new
723−filenames are constructed based on SHA1 hashes of the contents.
723+Otherwise filenames are constructed from the SHA1 hash of the contents.
724.TP
724.TP
725\f[B]\f[CB]--abbreviations=\f[B]\f[R]\f[I]FILE\f[R]
725\f[B]\f[CB]--abbreviations=\f[B]\f[R]\f[I]FILE\f[R]
726Specifies a custom abbreviations file, with abbreviations one to a line.
726Specifies a custom abbreviations file, with abbreviations one to a line.
@@ -1504,16 +1504,16 @@ inserted.
1504.TP
1504.TP
1505\f[B]\f[CB]--gladtex\f[B]\f[R]
1505\f[B]\f[CB]--gladtex\f[B]\f[R]
1506Enclose TeX math in \f[C]<eq>\f[R] tags in HTML output.
1506Enclose TeX math in \f[C]<eq>\f[R] tags in HTML output.
1507−The resulting HTML can then be processed by GladTeX to produce images of
1507+The resulting HTML can then be processed by GladTeX to produce SVG
1508−the typeset formulas and an HTML file with links to these images.
1508+images of the typeset formulas and an HTML file with these images
1509−So, the procedure is:
1509+embedded.
1510.RS
1510.RS
1511.IP
1511.IP
1512.nf
1512.nf
1513\f[C]
1513\f[C]
1514pandoc -s --gladtex input.md -o myfile.htex
1514pandoc -s --gladtex input.md -o myfile.htex
1515−gladtex -d myfile-images myfile.htex
1515+gladtex -d image_dir myfile.htex
1516−# produces myfile.html and images in myfile-images
1516+# produces myfile.html and images in image_dir
1517\f[R]
1517\f[R]
1518.fi
1518.fi
1519.RE
1519.RE
@@ -2591,10 +2591,9 @@ YAML metadata or with \f[C]-M classoption=fleqn\f[R].
2591.SS Variables for HTML slides
2591.SS Variables for HTML slides
2592.PP
2592.PP
2593These affect HTML output when [producing slide shows with pandoc].
2593These affect HTML output when [producing slide shows with pandoc].
2594−.PP
2594+.TP
2595−All reveal.js configuration options are available as variables.
2595+\f[B]\f[CB]institute\f[B]\f[R]
2596−To turn off boolean flags that default to true in reveal.js, use
2596+author affiliations: can be a list when there are multiple authors
2597−\f[C]0\f[R].
2598.TP
2597.TP
2599\f[B]\f[CB]revealjs-url\f[B]\f[R]
2598\f[B]\f[CB]revealjs-url\f[B]\f[R]
2600base URL for reveal.js documents (defaults to
2599base URL for reveal.js documents (defaults to
@@ -2613,6 +2612,10 @@ base URL for Slideous documents (defaults to \f[C]slideous\f[R])
2613\f[B]\f[CB]title-slide-attributes\f[B]\f[R]
2612\f[B]\f[CB]title-slide-attributes\f[B]\f[R]
2614additional attributes for the title slide of reveal.js slide shows.
2613additional attributes for the title slide of reveal.js slide shows.
2615See background in reveal.js and beamer for an example.
2614See background in reveal.js and beamer for an example.
2615+.PP
2616+All reveal.js configuration options are available as variables.
2617+To turn off boolean flags that default to true in reveal.js, use
2618+\f[C]0\f[R].
2616.SS Variables for Beamer slides
2619.SS Variables for Beamer slides
2617.PP
2620.PP
2618These variables change the appearance of PDF slides using
2621These variables change the appearance of PDF slides using
@@ -4272,7 +4275,7 @@ Term 2
4272Note that space between items in a definition list is required.
4275Note that space between items in a definition list is required.
4273(A variant that loosens this requirement, but disallows \[lq]lazy\[rq]
4276(A variant that loosens this requirement, but disallows \[lq]lazy\[rq]
4274hard wrapping, can be activated with \f[C]compact_definition_lists\f[R]:
4277hard wrapping, can be activated with \f[C]compact_definition_lists\f[R]:
4275−see Non-pandoc extensions, below.)
4278+see Non-default extensions, below.)
4276.SS Numbered example lists
4279.SS Numbered example lists
4277.SS Extension: \f[C]example_lists\f[R]
4280.SS Extension: \f[C]example_lists\f[R]
4278.PP
4281.PP
@@ -4793,7 +4796,9 @@ All of the metadata will appear in a single block at the beginning of
4793the document.
4796the document.
4794.PP
4797.PP
4795Note that YAML escaping rules must be followed.
4798Note that YAML escaping rules must be followed.
4796−Thus, for example, if a title contains a colon, it must be quoted.
4799+Thus, for example, if a title contains a colon, it must be quoted, and
4800+if it contains a backslash escape, then it must be ensured that it is
4801+not treated as a YAML escape sequence.
4797The pipe character (\f[C]|\f[R]) can be used to begin an indented block
4802The pipe character (\f[C]|\f[R]) can be used to begin an indented block
4798that will be interpreted literally, without need for escaping.
4803that will be interpreted literally, without need for escaping.
4799This form is necessary when the field contains blank lines or
4804This form is necessary when the field contains blank lines or
@@ -4815,6 +4820,13 @@ abstract: |
4815\f[R]
4820\f[R]
4816.fi
4821.fi
4817.PP
4822.PP
4823+The literal block after the \f[C]|\f[R] must be indented relative to the
4824+line containing the \f[C]|\f[R].
4825+If it is not, the YAML will be invalid and pandoc will not interpret it
4826+as metadata.
4827+For an overview of the complex rules governing YAML, see the Wikipedia
4828+entry on YAML syntax.
4829+.PP
4818Template variables will be set automatically from the metadata.
4830Template variables will be set automatically from the metadata.
4819Thus, for example, in writing HTML, the variable \f[C]abstract\f[R] will
4831Thus, for example, in writing HTML, the variable \f[C]abstract\f[R] will
4820be set to the HTML equivalent of the Markdown in the \f[C]abstract\f[R]
4832be set to the HTML equivalent of the Markdown in the \f[C]abstract\f[R]
@@ -4880,6 +4892,21 @@ header-includes:
4880 \[ga]\[ga]\[ga]
4892 \[ga]\[ga]\[ga]
4881\f[R]
4893\f[R]
4882.fi
4894.fi
4895+.PP
4896+Note: the \f[C]yaml_metadata_block\f[R] extension works with
4897+\f[C]commonmark\f[R] as well as \f[C]markdown\f[R] (and it is enabled by
4898+default in \f[C]gfm\f[R] and \f[C]commonmark_x\f[R]).
4899+However, in these formats the following restrictions apply:
4900+.IP \[bu] 2
4901+The YAML metadata block must occur at the beginning of the document (and
4902+there can be only one).
4903+If multiple files are given as arguments to pandoc, only the first can
4904+be a YAML metadata block.
4905+.IP \[bu] 2
4906+The leaf nodes of the YAML structure are parsed in isolation from each
4907+other and from the rest of the document.
4908+So, for example, you can\[cq]t use a reference link in these contexts if
4909+the link definition is somewhere else in the document.
4883.SS Backslash escapes
4910.SS Backslash escapes
4884.SS Extension: \f[C]all_symbols_escapable\f[R]
4911.SS Extension: \f[C]all_symbols_escapable\f[R]
4885.PP
4912.PP
@@ -5760,27 +5787,70 @@ Inline and regular footnotes may be mixed freely.
5760.SS Citation syntax
5787.SS Citation syntax
5761.SS Extension: \f[C]citations\f[R]
5788.SS Extension: \f[C]citations\f[R]
5762.PP
5789.PP
5763−Markdown citations go inside square brackets and are separated by
5790+To cite a bibliographic item with an identifier foo, use the syntax
5764−semicolons.
5791+\f[C]\[at]foo\f[R].
5765−Each citation must have a key, composed of `\[at]' + the citation
5792+Normal citations should be included in square brackets, with semicolons
5766−identifier from the database, and may optionally have a prefix, a
5793+separating distinct items:
5767−locator, and a suffix.
5768−The citation key must begin with a letter, digit, or \f[C]_\f[R], and
5769−may contain alphanumerics, \f[C]_\f[R], and internal punctuation
5770−characters (\f[C]:.#$%&-+?<>\[ti]/\f[R]).
5771−Here are some examples:
5772.IP
5794.IP
5773.nf
5795.nf
5774\f[C]
5796\f[C]
5775−Blah blah [see \[at]doe99, pp. 33-35; also \[at]smith04, chap. 1].
5797+Blah blah [\[at]doe99; \[at]smith2000; \[at]smith2004].
5776−
5798+\f[R]
5777−Blah blah [\[at]doe99, pp. 33-35, 38-39 and *passim*].
5799+.fi
5800+.PP
5801+How this is rendered depends on the citation style.
5802+In an author-date style, it might render as
5803+.IP
5804+.nf
5805+\f[C]
5806+Blah blah (Doe 1999, Smith 2000, 2004).
5807+\f[R]
5808+.fi
5809+.PP
5810+In a footnote style, it might render as
5811+.IP
5812+.nf
5813+\f[C]
5814+Blah blah.[\[ha]1]
5778
5815
5779−Blah blah [\[at]smith04; \[at]doe99].
5816+[\[ha]1]: John Doe, \[dq]Frogs,\[dq] *Journal of Amphibians* 44 (1999);
5817+Susan Smith, \[dq]Flies,\[dq] *Journal of Insects* (2000);
5818+Susan Smith, \[dq]Bees,\[dq] *Journal of Insects* (2004).
5780\f[R]
5819\f[R]
5781.fi
5820.fi
5782.PP
5821.PP
5822+See the CSL user documentation for more information about CSL styles and
5823+how they affect rendering.
5824+.PP
5825+Unless a citation key start with a letter, digit, or \f[C]_\f[R], and
5826+contains only alphanumerics and internal punctuation characters
5827+(\f[C]:.#$%&-+?<>\[ti]/\f[R]), it must be surrounded by curly braces,
5828+which are not considered part of the key.
5829+In \f[C]\[at]Foo_bar.baz.\f[R], the key is \f[C]Foo_bar.baz\f[R].
5830+The final period is not \f[I]internal\f[R] punctuation, so it is not
5831+included in the key.
5832+In \f[C]\[at]{Foo_bar.baz.}\f[R], the key is \f[C]Foo_bar.baz.\f[R],
5833+including the final period.
5834+The curly braces are recommended if you use URLs as keys:
5835+\f[C][\[at]{https://example.com/bib?name=foobar&date=2000}, p. 33]\f[R].
5836+.PP
5837+Citation items may optionally include a prefix, a locator, and a suffix.
5838+In
5839+.IP
5840+.nf
5841+\f[C]
5842+Blah blah [see \[at]doe99, pp. 33-35 and *passim*; \[at]smith04, chap. 1].
5843+\f[R]
5844+.fi
5845+.PP
5846+The first item (\f[C]doe99\f[R]) has prefix \f[C]see\f[R], locator
5847+\f[C]pp. 33-35\f[R], and suffix \f[C]and *passim*\f[R].
5848+The second item (\f[C]smith04\f[R]) has locator \f[C]chap. 1\f[R] and no
5849+prefix or suffix.
5850+.PP
5851+Pandoc uses some heuristics to separate the locator from the rest of the
5852+subject.
5783−\f[C]pandoc\f[R] detects locator terms in the CSL locale files.
5853+It is sensitive to the locator terms defined in the CSL locale files.
5784Either abbreviated or unabbreviated forms are accepted.
5854Either abbreviated or unabbreviated forms are accepted.
5785In the \f[C]en-US\f[R] locale, locator terms can be written in either
5855In the \f[C]en-US\f[R] locale, locator terms can be written in either
5786singular or plural forms, as \f[C]book\f[R],
5856singular or plural forms, as \f[C]book\f[R],
@@ -5802,14 +5872,15 @@ singular or plural forms, as \f[C]book\f[R],
5802\f[C]\[sc]\f[R]/\f[C]\[sc]\[sc]\f[R].
5872\f[C]\[sc]\f[R]/\f[C]\[sc]\[sc]\f[R].
5803If no locator term is used, \[lq]page\[rq] is assumed.
5873If no locator term is used, \[lq]page\[rq] is assumed.
5804.PP
5874.PP
5805−\f[C]pandoc\f[R] will use heuristics to distinguish the locator from the
5875+In complex cases, you can force something to be treated as a locator by
5806−suffix.
5876+enclosing it in curly braces or prevent parsing the suffix as locator by
5807−In complex cases, the locator can be enclosed in curly braces:
5877+prepending curly braces:
5808.IP
5878.IP
5809.nf
5879.nf
5810\f[C]
5880\f[C]
5811[\[at]smith{ii, A, D-Z}, with a suffix]
5881[\[at]smith{ii, A, D-Z}, with a suffix]
5812[\[at]smith, {pp. iv, vi-xi, (xv)-(xvii)} with suffix here]
5882[\[at]smith, {pp. iv, vi-xi, (xv)-(xvii)} with suffix here]
5883+[\[at]smith{}, 99 years later]
5813\f[R]
5884\f[R]
5814.fi
5885.fi
5815.PP
5886.PP
@@ -5823,7 +5894,8 @@ Smith says blah [-\[at]smith04].
5823\f[R]
5894\f[R]
5824.fi
5895.fi
5825.PP
5896.PP
5826−You can also write an in-text citation, as follows:
5897+You can also write an author-in-text citation, by omitting the square
5898+brackets:
5827.IP
5899.IP
5828.nf
5900.nf
5829\f[C]
5901\f[C]
@@ -5832,13 +5904,64 @@ You can also write an in-text citation, as follows:
5832\[at]smith04 [p. 33] says blah.
5904\[at]smith04 [p. 33] says blah.
5833\f[R]
5905\f[R]
5834.fi
5906.fi
5907+.PP
5908+This will cause the author\[cq]s name to be rendered, followed by the
5909+bibliographical details.
5910+Use this form when you want to make the citation the subject of a
5911+sentence.
5912+.PP
5913+When you are using a note style, it is usually better to let citeproc
5914+create the footnotes from citations rather than writing an explicit
5915+note.
5916+If you do write an explicit note that contains a citation, note that
5917+normal citations will be put in parentheses, while author-in-text
5918+citations will not.
5919+For this reason, it is sometimes preferable to use the author-in-text
5920+style inside notes when using a note style.
5835−.SS Non-pandoc extensions
5921+.SS Non-default extensions
5836.PP
5922.PP
5837The following Markdown syntax extensions are not enabled by default in
5923The following Markdown syntax extensions are not enabled by default in
5838pandoc, but may be enabled by adding \f[C]+EXTENSION\f[R] to the format
5924pandoc, but may be enabled by adding \f[C]+EXTENSION\f[R] to the format
5839name, where \f[C]EXTENSION\f[R] is the name of the extension.
5925name, where \f[C]EXTENSION\f[R] is the name of the extension.
5840Thus, for example, \f[C]markdown+hard_line_breaks\f[R] is Markdown with
5926Thus, for example, \f[C]markdown+hard_line_breaks\f[R] is Markdown with
5841hard line breaks.
5927hard line breaks.
5928+.SS Extension: \f[C]rebase_relative_paths\f[R]
5929+.PP
5930+Rewrite relative paths for Markdown links and images, depending on the
5931+path of the file containing the link or image link.
5932+For each link or image, pandoc will compute the directory of the
5933+containing file, relative to the working directory, and prepend the
5934+resulting path to the link or image path.
5935+.PP
5936+The use of this extension is best understood by example.
5937+Suppose you have a a subdirectory for each chapter of a book,
5938+\f[C]chap1\f[R], \f[C]chap2\f[R], \f[C]chap3\f[R].
5939+Each contains a file \f[C]text.md\f[R] and a number of images used in
5940+the chapter.
5941+You would like to have \f[C]![image](spider.jpg)\f[R] in
5942+\f[C]chap1/text.md\f[R] refer to \f[C]chap1/spider.jpg\f[R] and
5943+\f[C]![image](spider.jpg)\f[R] in \f[C]chap2/text.md\f[R] refer to
5944+\f[C]chap2/spider.jpg\f[R].
5945+To do this, use
5946+.IP
5947+.nf
5948+\f[C]
5949+pandoc chap*/*.md -f markdown+rebase_relative_paths
5950+\f[R]
5951+.fi
5952+.PP
5953+Without this extension, you would have to use
5954+\f[C]![image](chap1/spider.jpg)\f[R] in \f[C]chap1/text.md\f[R] and
5955+\f[C]![image](chap2/spider.jpg)\f[R] in \f[C]chap2/text.md\f[R].
5956+Links with relative paths will be rewritten in the same way as images.
5957+.PP
5958+Absolute paths and URLs are not changed.
5959+Neither are empty paths or paths consisting entirely of a fragment,
5960+e.g., \f[C]#foo\f[R].
5961+.PP
5962+Note that relative paths in reference links and images will be rewritten
5963+relative to the file containing the link reference definition, not the
5964+file containing the reference link or image itself, if these differ.
5842.SS Extension: \f[C]attributes\f[R]
5965.SS Extension: \f[C]attributes\f[R]
5843.PP
5966.PP
5844Allows attributes to be attached to any inline or block-level element.
5967Allows attributes to be attached to any inline or block-level element.
@@ -6468,9 +6591,29 @@ entries (for author-date and numerical styles only).
6468.TP
6591.TP
6469\f[B]\f[CB]lang\f[B]\f[R]
6592\f[B]\f[CB]lang\f[B]\f[R]
6470The \f[C]lang\f[R] field will affect how the style is localized, for
6593The \f[C]lang\f[R] field will affect how the style is localized, for
6471−example in the translation of labels and the use of quotation marks.
6594+example in the translation of labels, the use of quotation marks, and
6595+the way items are sorted.
6472(For backwards compatibility, \f[C]locale\f[R] may be used instead of
6596(For backwards compatibility, \f[C]locale\f[R] may be used instead of
6473\f[C]lang\f[R], but this use is deprecated.)
6597\f[C]lang\f[R], but this use is deprecated.)
6598+.RS
6599+.PP
6600+A BCP 47 language tag is expected: for example, \f[C]en\f[R],
6601+\f[C]de\f[R], \f[C]en-US\f[R], \f[C]fr-CA\f[R], \f[C]ug-Cyrl\f[R].
6602+The unicode extension syntax (after \f[C]-u-\f[R]) may be used to
6603+specify options for collation (sorting) more precisely.
6604+Here are some examples:
6605+.IP \[bu] 2
6606+\f[C]zh-u-co-pinyin\f[R] \[en] Chinese with the Pinyin collation.
6607+.IP \[bu] 2
6608+\f[C]es-u-co-trad\f[R] \[en] Spanish with the traditional collation
6609+(with \f[C]Ch\f[R] sorting after \f[C]C\f[R]).
6610+.IP \[bu] 2
6611+\f[C]fr-u-kb\f[R] \[en] French with \[lq]backwards\[rq] accent sorting
6612+(with \f[C]cot\['e]\f[R] sorting after \f[C]c\[^o]te\f[R]).
6613+.IP \[bu] 2
6614+\f[C]en-US-u-kf-upper\f[R] \[en] English with uppercase letters sorting
6615+before lower (default is lower before upper).
6616+.RE
6474.TP
6617.TP
6475\f[B]\f[CB]notes-after-punctuation\f[B]\f[R]
6618\f[B]\f[CB]notes-after-punctuation\f[B]\f[R]
6476If true (the default), pandoc will put footnote citations after
6619If true (the default), pandoc will put footnote citations after
@@ -6591,6 +6734,11 @@ A heading at the slide level always starts a new slide.
6591.IP \[bu] 2
6734.IP \[bu] 2
6592Headings \f[I]below\f[R] the slide level in the hierarchy create
6735Headings \f[I]below\f[R] the slide level in the hierarchy create
6593headings \f[I]within\f[R] a slide.
6736headings \f[I]within\f[R] a slide.
6737+(In beamer, a \[lq]block\[rq] will be created.
6738+If the heading has the class \f[C]example\f[R], an
6739+\f[C]exampleblock\f[R] environment will be used; if it has the class
6740+\f[C]alert\f[R], an \f[C]alertblock\f[R] will be used; otherwise a
6741+regular \f[C]block\f[R] will be used.)
6594.IP \[bu] 2
6742.IP \[bu] 2
6595Headings \f[I]above\f[R] the slide level in the hierarchy create
6743Headings \f[I]above\f[R] the slide level in the hierarchy create
6596\[lq]title slides,\[rq] which just contain the section title and help to
6744\[lq]title slides,\[rq] which just contain the section title and help to
@@ -7560,7 +7708,7 @@ The HTML generated by pandoc is not guaranteed to be safe.
7560If \f[C]raw_html\f[R] is enabled for the Markdown input, users can
7708If \f[C]raw_html\f[R] is enabled for the Markdown input, users can
7561inject arbitrary HTML.
7709inject arbitrary HTML.
7562Even if \f[C]raw_html\f[R] is disabled, users can include dangerous
7710Even if \f[C]raw_html\f[R] is disabled, users can include dangerous
7563−content in attributes for headings, spans, and code blocks.
7711+content in URLs and attributes.
7564To be safe, you should run all the generated HTML through an HTML
7712To be safe, you should run all the generated HTML through an HTML
7565sanitizer.
7713sanitizer.
7566.SH AUTHORS
7714.SH AUTHORS
pandoc.cabal+29−21
@@ -1,6 +1,6 @@
1cabal-version: 2.2
1cabal-version: 2.2
2name: pandoc
2name: pandoc
3−version: 2.12.1
3+version: 2.14.0.3
4build-type: Simple
4build-type: Simple
5license: GPL-2.0-or-later
5license: GPL-2.0-or-later
6license-file: COPYING.md
6license-file: COPYING.md
@@ -12,7 +12,7 @@ stability: alpha
12homepage: https://pandoc.org
12homepage: https://pandoc.org
13category: Text
13category: Text
14tested-with: GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5,
14tested-with: GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5,
15− GHC == 8.8.4, GHC == 8.10.2
15+ GHC == 8.8.4, GHC == 8.10.2, GHC == 9.0.1
16synopsis: Conversion between markup formats
16synopsis: Conversion between markup formats
17description: Pandoc is a Haskell library for converting from one markup
17description: Pandoc is a Haskell library for converting from one markup
18 format to another, and a command-line tool that uses
18 format to another, and a command-line tool that uses
@@ -208,12 +208,16 @@ extra-source-files:
208 test/command/*.md
208 test/command/*.md
209 test/command/*.csl
209 test/command/*.csl
210 test/command/biblio.bib
210 test/command/biblio.bib
211− test/command/biblatex-examples.bib
211+ test/command/averroes.bib
212 test/command/A.txt
212 test/command/A.txt
213 test/command/B.txt
213 test/command/B.txt
214 test/command/C.txt
214 test/command/C.txt
215 test/command/D.txt
215 test/command/D.txt
216 test/command/01.csv
216 test/command/01.csv
217+ test/command/chap1/spider.png
218+ test/command/chap2/spider.png
219+ test/command/chap1/text.md
220+ test/command/chap2/text.md
217 test/command/defaults1.yaml
221 test/command/defaults1.yaml
218 test/command/defaults2.yaml
222 test/command/defaults2.yaml
219 test/command/defaults3.yaml
223 test/command/defaults3.yaml
@@ -438,17 +442,18 @@ library
438 SHA >= 1.6 && < 1.7,
442 SHA >= 1.6 && < 1.7,
439 aeson >= 0.7 && < 1.6,
443 aeson >= 0.7 && < 1.6,
440 aeson-pretty >= 0.8.5 && < 0.9,
444 aeson-pretty >= 0.8.5 && < 0.9,
445+ array >= 0.5 && < 0.6,
441− attoparsec >= 0.12 && < 0.14,
446+ attoparsec >= 0.12 && < 0.15,
442 base64-bytestring >= 0.1 && < 1.3,
447 base64-bytestring >= 0.1 && < 1.3,
443 binary >= 0.7 && < 0.11,
448 binary >= 0.7 && < 0.11,
444 blaze-html >= 0.9 && < 0.10,
449 blaze-html >= 0.9 && < 0.10,
445 blaze-markup >= 0.8 && < 0.9,
450 blaze-markup >= 0.8 && < 0.9,
446 bytestring >= 0.9 && < 0.12,
451 bytestring >= 0.9 && < 0.12,
447 case-insensitive >= 1.2 && < 1.3,
452 case-insensitive >= 1.2 && < 1.3,
448− citeproc >= 0.3.0.9 && < 0.4,
453+ citeproc >= 0.4.0.1 && < 0.4.1,
449− commonmark >= 0.1.1.3 && < 0.2,
454+ commonmark >= 0.2.1 && < 0.3,
450− commonmark-extensions >= 0.2.0.4 && < 0.3,
455+ commonmark-extensions >= 0.2.1.2 && < 0.3,
451− commonmark-pandoc >= 0.2 && < 0.3,
456+ commonmark-pandoc >= 0.2.1.1 && < 0.3,
452 connection >= 0.3.1,
457 connection >= 0.3.1,
453 containers >= 0.4.2.1 && < 0.7,
458 containers >= 0.4.2.1 && < 0.7,
454 data-default >= 0.4 && < 0.8,
459 data-default >= 0.4 && < 0.8,
@@ -460,7 +465,7 @@ library
460 exceptions >= 0.8 && < 0.11,
465 exceptions >= 0.8 && < 0.11,
461 file-embed >= 0.0 && < 0.1,
466 file-embed >= 0.0 && < 0.1,
462 filepath >= 1.1 && < 1.5,
467 filepath >= 1.1 && < 1.5,
463− haddock-library >= 1.8 && < 1.10,
468+ haddock-library >= 1.10 && < 1.11,
464 hslua >= 1.1 && < 1.4,
469 hslua >= 1.1 && < 1.4,
465 hslua-module-path >= 0.1.0 && < 0.2.0,
470 hslua-module-path >= 0.1.0 && < 0.2.0,
466 hslua-module-system >= 0.2 && < 0.3,
471 hslua-module-system >= 0.2 && < 0.3,
@@ -469,30 +474,31 @@ library
469 http-client-tls >= 0.2.4 && < 0.4,
474 http-client-tls >= 0.2.4 && < 0.4,
470 http-types >= 0.8 && < 0.13,
475 http-types >= 0.8 && < 0.13,
471 ipynb >= 0.1 && < 0.2,
476 ipynb >= 0.1 && < 0.2,
472− jira-wiki-markup >= 1.3.4 && < 1.4,
477+ jira-wiki-markup >= 1.4 && < 1.5,
473 mtl >= 2.2 && < 2.3,
478 mtl >= 2.2 && < 2.3,
474 network >= 2.6,
479 network >= 2.6,
475− network-uri >= 2.6 && < 2.7,
480+ network-uri >= 2.6 && < 2.8,
476 pandoc-types >= 1.22 && < 1.23,
481 pandoc-types >= 1.22 && < 1.23,
477 parsec >= 3.1 && < 3.2,
482 parsec >= 3.1 && < 3.2,
478 process >= 1.2.3 && < 1.7,
483 process >= 1.2.3 && < 1.7,
479 random >= 1 && < 1.3,
484 random >= 1 && < 1.3,
480− safe >= 0.3 && < 0.4,
485+ safe >= 0.3.18 && < 0.4,
481 scientific >= 0.3 && < 0.4,
486 scientific >= 0.3 && < 0.4,
482− skylighting >= 0.10.4.1 && < 0.11,
487+ skylighting >= 0.10.5.2 && < 0.10.6,
483− skylighting-core >= 0.10.4.1 && < 0.11,
488+ skylighting-core >= 0.10.5.2 && < 0.10.6,
484 split >= 0.2 && < 0.3,
489 split >= 0.2 && < 0.3,
485 syb >= 0.1 && < 0.8,
490 syb >= 0.1 && < 0.8,
486 tagsoup >= 0.14.6 && < 0.15,
491 tagsoup >= 0.14.6 && < 0.15,
487 temporary >= 1.1 && < 1.4,
492 temporary >= 1.1 && < 1.4,
488− texmath >= 0.12.2 && < 0.13,
493+ texmath >= 0.12.3 && < 0.12.4,
489 text >= 1.1.1.0 && < 1.3,
494 text >= 1.1.1.0 && < 1.3,
490 text-conversions >= 0.3 && < 0.4,
495 text-conversions >= 0.3 && < 0.4,
491− time >= 1.5 && < 1.10,
496+ time >= 1.5 && < 1.12,
492 unicode-transforms >= 0.3 && < 0.4,
497 unicode-transforms >= 0.3 && < 0.4,
493 unordered-containers >= 0.2 && < 0.3,
498 unordered-containers >= 0.2 && < 0.3,
494 xml >= 1.3.12 && < 1.4,
499 xml >= 1.3.12 && < 1.4,
495− xml-conduit >= 1.7 && < 1.10,
500+ xml-conduit >= 1.9.1.1 && < 1.10,
501+ unicode-collation >= 0.1.1 && < 0.2,
496 zip-archive >= 0.2.3.4 && < 0.5,
502 zip-archive >= 0.2.3.4 && < 0.5,
497 zlib >= 0.5 && < 0.7
503 zlib >= 0.5 && < 0.7
498 if os(windows) && arch(i386)
504 if os(windows) && arch(i386)
@@ -511,6 +517,7 @@ library
511 Text.Pandoc.Options,
517 Text.Pandoc.Options,
512 Text.Pandoc.Extensions,
518 Text.Pandoc.Extensions,
513 Text.Pandoc.Shared,
519 Text.Pandoc.Shared,
520+ Text.Pandoc.Sources,
514 Text.Pandoc.MediaBag,
521 Text.Pandoc.MediaBag,
515 Text.Pandoc.Error,
522 Text.Pandoc.Error,
516 Text.Pandoc.Filter,
523 Text.Pandoc.Filter,
@@ -600,7 +607,6 @@ library
600 Text.Pandoc.Asciify,
607 Text.Pandoc.Asciify,
601 Text.Pandoc.Emoji,
608 Text.Pandoc.Emoji,
602 Text.Pandoc.ImageSize,
609 Text.Pandoc.ImageSize,
603− Text.Pandoc.BCP47,
604 Text.Pandoc.Class,
610 Text.Pandoc.Class,
605 Text.Pandoc.Citeproc
611 Text.Pandoc.Citeproc
606 other-modules: Text.Pandoc.App.CommandLineOptions,
612 other-modules: Text.Pandoc.App.CommandLineOptions,
@@ -657,6 +663,9 @@ library
657 Text.Pandoc.Readers.Metadata,
663 Text.Pandoc.Readers.Metadata,
658 Text.Pandoc.Readers.Roff,
664 Text.Pandoc.Readers.Roff,
659 Text.Pandoc.Writers.Docx.StyleMap,
665 Text.Pandoc.Writers.Docx.StyleMap,
666+ Text.Pandoc.Writers.Docx.Table,
667+ Text.Pandoc.Writers.Docx.Types,
668+ Text.Pandoc.Writers.GridTable
660 Text.Pandoc.Writers.JATS.References,
669 Text.Pandoc.Writers.JATS.References,
661 Text.Pandoc.Writers.JATS.Table,
670 Text.Pandoc.Writers.JATS.Table,
662 Text.Pandoc.Writers.JATS.Types,
671 Text.Pandoc.Writers.JATS.Types,
@@ -729,7 +738,7 @@ executable trypandoc
729 main-is: trypandoc.hs
738 main-is: trypandoc.hs
730 hs-source-dirs: trypandoc
739 hs-source-dirs: trypandoc
731 if flag(trypandoc)
740 if flag(trypandoc)
732− build-depends: aeson, http-types, wai >= 0.3, wai-extra >= 3.0.24
741+ build-depends: aeson, http-types, text, wai >= 0.3, wai-extra >= 3.0.24
733 buildable: True
742 buildable: True
734 else
743 else
735 buildable: False
744 buildable: False
@@ -748,7 +757,6 @@ test-suite test-pandoc
748 directory >= 1.2.3 && < 1.4,
757 directory >= 1.2.3 && < 1.4,
749 doctemplates >= 0.9 && < 0.10,
758 doctemplates >= 0.9 && < 0.10,
750 exceptions >= 0.8 && < 0.11,
759 exceptions >= 0.8 && < 0.11,
751− executable-path >= 0.0 && < 0.1,
752 filepath >= 1.1 && < 1.5,
760 filepath >= 1.1 && < 1.5,
753 hslua >= 1.1 && < 1.4,
761 hslua >= 1.1 && < 1.4,
754 mtl >= 2.2 && < 2.3,
762 mtl >= 2.2 && < 2.3,
@@ -760,7 +768,7 @@ test-suite test-pandoc
760 tasty-lua >= 0.2 && < 0.3,
768 tasty-lua >= 0.2 && < 0.3,
761 tasty-quickcheck >= 0.8 && < 0.11,
769 tasty-quickcheck >= 0.8 && < 0.11,
762 text >= 1.1.1.0 && < 1.3,
770 text >= 1.1.1.0 && < 1.3,
763− time >= 1.5 && < 1.10,
771+ time >= 1.5 && < 1.12,
764 xml >= 1.3.12 && < 1.4,
772 xml >= 1.3.12 && < 1.4,
765 zip-archive >= 0.2.3.4 && < 0.5
773 zip-archive >= 0.2.3.4 && < 0.5
766 other-modules: Tests.Old
774 other-modules: Tests.Old
src/Text/Pandoc/App.hs+19−13
@@ -55,7 +55,7 @@ import Text.Pandoc.App.Opt (Opt (..), LineEnding (..), defaultOpts,
55import Text.Pandoc.App.CommandLineOptions (parseOptions, parseOptionsFromArgs,
55import Text.Pandoc.App.CommandLineOptions (parseOptions, parseOptionsFromArgs,
56 options)
56 options)
57import Text.Pandoc.App.OutputSettings (OutputSettings (..), optToOutputSettings)
57import Text.Pandoc.App.OutputSettings (OutputSettings (..), optToOutputSettings)
58−import Text.Pandoc.BCP47 (Lang (..), parseBCP47)
58+import Text.Collate.Lang (Lang (..), parseLang)
59import Text.Pandoc.Filter (Filter (JSONFilter, LuaFilter), applyFilters)
59import Text.Pandoc.Filter (Filter (JSONFilter, LuaFilter), applyFilters)
60import Text.Pandoc.PDF (makePDF)
60import Text.Pandoc.PDF (makePDF)
61import Text.Pandoc.SelfContained (makeSelfContained)
61import Text.Pandoc.SelfContained (makeSelfContained)
@@ -160,9 +160,11 @@ convertWithOpts opts = do
160 else optTabStop opts)
160 else optTabStop opts)
161
161
162
162
163− let readSources :: [FilePath] -> PandocIO Text
163+ let readSources :: [FilePath] -> PandocIO [(FilePath, Text)]
164− readSources srcs = convertTabs . T.intercalate (T.pack "\n") <$>
164+ readSources srcs =
165+ mapM (\fp -> do
165− mapM readSource srcs
166+ t <- readSource fp
167+ return (if fp == "-" then "" else fp, convertTabs t)) srcs
166
168
167
169
168 outputSettings <- optToOutputSettings opts
170 outputSettings <- optToOutputSettings opts
@@ -200,8 +202,8 @@ convertWithOpts opts = do
200 Just f -> readFileStrict f
202 Just f -> readFileStrict f
201
203
202 case lookupMetaString "lang" (optMetadata opts) of
204 case lookupMetaString "lang" (optMetadata opts) of
203− "" -> setTranslations $ Lang "en" "" "US" []
205+ "" -> setTranslations $ Lang "en" Nothing (Just "US") [] [] []
204− l -> case parseBCP47 l of
206+ l -> case parseLang l of
205 Left _ -> report $ InvalidLang l
207 Left _ -> report $ InvalidLang l
206 Right l' -> setTranslations l'
208 Right l' -> setTranslations l'
207
209
@@ -255,13 +257,17 @@ convertWithOpts opts = do
255 let sourceToDoc :: [FilePath] -> PandocIO Pandoc
257 let sourceToDoc :: [FilePath] -> PandocIO Pandoc
256 sourceToDoc sources' =
258 sourceToDoc sources' =
257 case reader of
259 case reader of
258− TextReader r
260+ TextReader r
259− | optFileScope opts || readerNameBase == "json" ->
261+ | readerNameBase == "json" ->
262+ mconcat <$> mapM (readSource >=> r readerOpts) sources'
263+ | optFileScope opts ->
264+ -- Read source and convert tabs (see #6709)
265+ let readSource' = fmap convertTabs . readSource
260− mconcat <$> mapM (readSource >=> r readerOpts) sources'
266+ in mconcat <$> mapM (readSource' >=> r readerOpts) sources'
261− | otherwise ->
267+ | otherwise ->
262− readSources sources' >>= r readerOpts
268+ readSources sources' >>= r readerOpts
263− ByteStringReader r ->
269+ ByteStringReader r ->
264− mconcat <$> mapM (readFile' >=> r readerOpts) sources'
270+ mconcat <$> mapM (readFile' >=> r readerOpts) sources'
265
271
266
272
267 when (readerNameBase == "markdown_github" ||
273 when (readerNameBase == "markdown_github" ||
src/Text/Pandoc/App/Opt.hs+2−1
@@ -686,7 +686,8 @@ yamlToMeta (Mapping _ _ m) =
686 either (fail . show) return $ runEverything (yamlMap pMetaString m)
686 either (fail . show) return $ runEverything (yamlMap pMetaString m)
687 where
687 where
688 pMetaString = pure . MetaString <$> P.manyChar P.anyChar
688 pMetaString = pure . MetaString <$> P.manyChar P.anyChar
689+ runEverything p =
689− runEverything p = runPure (P.readWithM p def "")
690+ runPure (P.readWithM p (def :: P.ParserState) ("" :: Text))
690 >>= fmap (Meta . flip P.runF def)
691 >>= fmap (Meta . flip P.runF def)
691yamlToMeta _ = return mempty
692yamlToMeta _ = return mempty
692
693
src/Text/Pandoc/Asciify.hs+13−390
@@ -10,396 +10,19 @@
10Function to convert accented latin letters to their unaccented
10Function to convert accented latin letters to their unaccented
11ascii equivalents (used in constructing HTML identifiers).
11ascii equivalents (used in constructing HTML identifiers).
12-}
12-}
13−module Text.Pandoc.Asciify (toAsciiChar)
13+module Text.Pandoc.Asciify (toAsciiChar, toAsciiText)
14where
14where
15−import Data.Char (isAscii)
15+import Data.Char (isAscii, isMark)
16−import qualified Data.Map as M
16+import qualified Data.Text.Normalize as TN
17+import Data.Text (Text)
18+import qualified Data.Text as T
17
19
18−toAsciiChar :: Char -> Maybe Char
20+toAsciiText :: Text -> Text
19−toAsciiChar c | isAscii c = Just c
21+toAsciiText = T.filter isAscii . TN.normalize (TN.NFD)
20− | otherwise = M.lookup c asciiMap
21
22
22−asciiMap :: M.Map Char Char
23+toAsciiChar :: Char -> Maybe Char
23−asciiMap = M.fromList
24+toAsciiChar c = case T.unpack (TN.normalize TN.NFD (T.singleton c)) of
24− [('\192','A')
25+ (x:xs) | isAscii x
25− ,('\193','A')
26+ , all isMark xs
26− ,('\194','A')
27+ -> Just x
27− ,('\195','A')
28+ _ -> Nothing
28− ,('\196','A')
29− ,('\197','A')
30− ,('\199','C')
31− ,('\200','E')
32− ,('\201','E')
33− ,('\202','E')
34− ,('\203','E')
35− ,('\204','I')
36− ,('\205','I')
37− ,('\206','I')
38− ,('\207','I')
39− ,('\209','N')
40− ,('\210','O')
41− ,('\211','O')
42− ,('\212','O')
43− ,('\213','O')
44− ,('\214','O')
45− ,('\217','U')
46− ,('\218','U')
47− ,('\219','U')
48− ,('\220','U')
49− ,('\221','Y')
50− ,('\224','a')
51− ,('\225','a')
52− ,('\226','a')
53− ,('\227','a')
54− ,('\228','a')
55− ,('\229','a')
56− ,('\231','c')
57− ,('\232','e')
58− ,('\233','e')
59− ,('\234','e')
60− ,('\235','e')
61− ,('\236','i')
62− ,('\237','i')
63− ,('\238','i')
64− ,('\239','i')
65− ,('\241','n')
66− ,('\242','o')
67− ,('\243','o')
68− ,('\244','o')
69− ,('\245','o')
70− ,('\246','o')
71− ,('\249','u')
72− ,('\250','u')
73− ,('\251','u')
74− ,('\252','u')
75− ,('\253','y')
76− ,('\255','y')
77− ,('\256','A')
78− ,('\257','a')
79− ,('\258','A')
80− ,('\259','a')
81− ,('\260','A')
82− ,('\261','a')
83− ,('\262','C')
84− ,('\263','c')
85− ,('\264','C')
86− ,('\265','c')
87− ,('\266','C')
88− ,('\267','c')
89− ,('\268','C')
90− ,('\269','c')
91− ,('\270','D')
92− ,('\271','d')
93− ,('\274','E')
94− ,('\275','e')
95− ,('\276','E')
96− ,('\277','e')
97− ,('\278','E')
98− ,('\279','e')
99− ,('\280','E')
100− ,('\281','e')
101− ,('\282','E')
102− ,('\283','e')
103− ,('\284','G')
104− ,('\285','g')
105− ,('\286','G')
106− ,('\287','g')
107− ,('\288','G')
108− ,('\289','g')
109− ,('\290','G')
110− ,('\291','g')
111− ,('\292','H')
112− ,('\293','h')
113− ,('\296','I')
114− ,('\297','i')
115− ,('\298','I')
116− ,('\299','i')
117− ,('\300','I')
118− ,('\301','i')
119− ,('\302','I')
120− ,('\303','i')
121− ,('\304','I')
122− ,('\305','i')
123− ,('\308','J')
124− ,('\309','j')
125− ,('\310','K')
126− ,('\311','k')
127− ,('\313','L')
128− ,('\314','l')
129− ,('\315','L')
130− ,('\316','l')
131− ,('\317','L')
132− ,('\318','l')
133− ,('\323','N')
134− ,('\324','n')
135− ,('\325','N')
136− ,('\326','n')
137− ,('\327','N')
138− ,('\328','n')
139− ,('\332','O')
140− ,('\333','o')
141− ,('\334','O')
142− ,('\335','o')
143− ,('\336','O')
144− ,('\337','o')
145− ,('\340','R')
146− ,('\341','r')
147− ,('\342','R')
148− ,('\343','r')
149− ,('\344','R')
150− ,('\345','r')
151− ,('\346','S')
152− ,('\347','s')
153− ,('\348','S')
154− ,('\349','s')
155− ,('\350','S')
156− ,('\351','s')
157− ,('\352','S')
158− ,('\353','s')
159− ,('\354','T')
160− ,('\355','t')
161− ,('\356','T')
162− ,('\357','t')
163− ,('\360','U')
164− ,('\361','u')
165− ,('\362','U')
166− ,('\363','u')
167− ,('\364','U')
168− ,('\365','u')
169− ,('\366','U')
170− ,('\367','u')
171− ,('\368','U')
172− ,('\369','u')
173− ,('\370','U')
174− ,('\371','u')
175− ,('\372','W')
176− ,('\373','w')
177− ,('\374','Y')
178− ,('\375','y')
179− ,('\376','Y')
180− ,('\377','Z')
181− ,('\378','z')
182− ,('\379','Z')
183− ,('\380','z')
184− ,('\381','Z')
185− ,('\382','z')
186− ,('\416','O')
187− ,('\417','o')
188− ,('\431','U')
189− ,('\432','u')
190− ,('\461','A')
191− ,('\462','a')
192− ,('\463','I')
193− ,('\464','i')
194− ,('\465','O')
195− ,('\466','o')
196− ,('\467','U')
197− ,('\468','u')
198− ,('\486','G')
199− ,('\487','g')
200− ,('\488','K')
201− ,('\489','k')
202− ,('\490','O')
203− ,('\491','o')
204− ,('\496','j')
205− ,('\500','G')
206− ,('\501','g')
207− ,('\504','N')
208− ,('\505','n')
209− ,('\512','A')
210− ,('\513','a')
211− ,('\514','A')
212− ,('\515','a')
213− ,('\516','E')
214− ,('\517','e')
215− ,('\518','E')
216− ,('\519','e')
217− ,('\520','I')
218− ,('\521','i')
219− ,('\522','I')
220− ,('\523','i')
221− ,('\524','O')
222− ,('\525','o')
223− ,('\526','O')
224− ,('\527','o')
225− ,('\528','R')
226− ,('\529','r')
227− ,('\530','R')
228− ,('\531','r')
229− ,('\532','U')
230− ,('\533','u')
231− ,('\534','U')
232− ,('\535','u')
233− ,('\536','S')
234− ,('\537','s')
235− ,('\538','T')
236− ,('\539','t')
237− ,('\542','H')
238− ,('\543','h')
239− ,('\550','A')
240− ,('\551','a')
241− ,('\552','E')
242− ,('\553','e')
243− ,('\558','O')
244− ,('\559','o')
245− ,('\562','Y')
246− ,('\563','y')
247− ,('\894',';')
248− ,('\7680','A')
249− ,('\7681','a')
250− ,('\7682','B')
251− ,('\7683','b')
252− ,('\7684','B')
253− ,('\7685','b')
254− ,('\7686','B')
255− ,('\7687','b')
256− ,('\7690','D')
257− ,('\7691','d')
258− ,('\7692','D')
259− ,('\7693','d')
260− ,('\7694','D')
261− ,('\7695','d')
262− ,('\7696','D')
263− ,('\7697','d')
264− ,('\7698','D')
265− ,('\7699','d')
266− ,('\7704','E')
267− ,('\7705','e')
268− ,('\7706','E')
269− ,('\7707','e')
270− ,('\7710','F')
271− ,('\7711','f')
272− ,('\7712','G')
273− ,('\7713','g')
274− ,('\7714','H')
275− ,('\7715','h')
276− ,('\7716','H')
277− ,('\7717','h')
278− ,('\7718','H')
279− ,('\7719','h')
280− ,('\7720','H')
281− ,('\7721','h')
282− ,('\7722','H')
283− ,('\7723','h')
284− ,('\7724','I')
285− ,('\7725','i')
286− ,('\7728','K')
287− ,('\7729','k')
288− ,('\7730','K')
289− ,('\7731','k')
290− ,('\7732','K')
291− ,('\7733','k')
292− ,('\7734','L')
293− ,('\7735','l')
294− ,('\7738','L')
295− ,('\7739','l')
296− ,('\7740','L')
297− ,('\7741','l')
298− ,('\7742','M')
299− ,('\7743','m')
300− ,('\7744','M')
301− ,('\7745','m')
302− ,('\7746','M')
303− ,('\7747','m')
304− ,('\7748','N')
305− ,('\7749','n')
306− ,('\7750','N')
307− ,('\7751','n')
308− ,('\7752','N')
309− ,('\7753','n')
310− ,('\7754','N')
311− ,('\7755','n')
312− ,('\7764','P')
313− ,('\7765','p')
314− ,('\7766','P')
315− ,('\7767','p')
316− ,('\7768','R')
317− ,('\7769','r')
318− ,('\7770','R')
319− ,('\7771','r')
320− ,('\7774','R')
321− ,('\7775','r')
322− ,('\7776','S')
323− ,('\7777','s')
324− ,('\7778','S')
325− ,('\7779','s')
326− ,('\7786','T')
327− ,('\7787','t')
328− ,('\7788','T')
329− ,('\7789','t')
330− ,('\7790','T')
331− ,('\7791','t')
332− ,('\7792','T')
333− ,('\7793','t')
334− ,('\7794','U')
335− ,('\7795','u')
336− ,('\7796','U')
337− ,('\7797','u')
338− ,('\7798','U')
339− ,('\7799','u')
340− ,('\7804','V')
341− ,('\7805','v')
342− ,('\7806','V')
343− ,('\7807','v')
344− ,('\7808','W')
345− ,('\7809','w')
346− ,('\7810','W')
347− ,('\7811','w')
348− ,('\7812','W')
349− ,('\7813','w')
350− ,('\7814','W')
351− ,('\7815','w')
352− ,('\7816','W')
353− ,('\7817','w')
354− ,('\7818','X')
355− ,('\7819','x')
356− ,('\7820','X')
357− ,('\7821','x')
358− ,('\7822','Y')
359− ,('\7823','y')
360− ,('\7824','Z')
361− ,('\7825','z')
362− ,('\7826','Z')
363− ,('\7827','z')
364− ,('\7828','Z')
365− ,('\7829','z')
366− ,('\7830','h')
367− ,('\7831','t')
368− ,('\7832','w')
369− ,('\7833','y')
370− ,('\7840','A')
371− ,('\7841','a')
372− ,('\7842','A')
373− ,('\7843','a')
374− ,('\7864','E')
375− ,('\7865','e')
376− ,('\7866','E')
377− ,('\7867','e')
378− ,('\7868','E')
379− ,('\7869','e')
380− ,('\7880','I')
381− ,('\7881','i')
382− ,('\7882','I')
383− ,('\7883','i')
384− ,('\7884','O')
385− ,('\7885','o')
386− ,('\7886','O')
387− ,('\7887','o')
388− ,('\7908','U')
389− ,('\7909','u')
390− ,('\7910','U')
391− ,('\7911','u')
392− ,('\7922','Y')
393− ,('\7923','y')
394− ,('\7924','Y')
395− ,('\7925','y')
396− ,('\7926','Y')
397− ,('\7927','y')
398− ,('\7928','Y')
399− ,('\7929','y')
400− ,('\8175','`')
401− ,('\8490','K')
402− ,('\8800','=')
403− ,('\8814','<')
404− ,('\8815','>')
405− ]
src/Text/Pandoc/BCP47.hsdeleted−112
@@ -1,112 +0,0 @@
1−{-# LANGUAGE OverloadedStrings #-}
2−{- |
3− Module : Text.Pandoc.BCP47
4− Copyright : Copyright (C) 2017-2021 John MacFarlane
5− License : GNU GPL, version 2 or above
6−
7− Maintainer : John MacFarlane <jgm@berkeley.edu>
8− Stability : alpha
9− Portability : portable
10−
11−Functions for parsing and rendering BCP47 language identifiers.
12−-}
13−module Text.Pandoc.BCP47 (
14− getLang
15− , parseBCP47
16− , Lang(..)
17− , renderLang
18− )
19−where
20−import Control.Monad (guard)
21−import Data.Char (isAlphaNum, isAscii, isLetter, isLower, isUpper)
22−import Text.Pandoc.Definition
23−import Text.Pandoc.Options
24−import Text.DocTemplates (FromContext(..))
25−import qualified Data.Text as T
26−import qualified Text.Parsec as P
27−
28−-- | Represents BCP 47 language/country code.
29−data Lang = Lang{ langLanguage :: T.Text
30− , langScript :: T.Text
31− , langRegion :: T.Text
32− , langVariants :: [T.Text] }
33− deriving (Eq, Ord, Show)
34−
35−-- | Render a Lang as BCP 47.
36−renderLang :: Lang -> T.Text
37−renderLang lang = T.intercalate "-" (langLanguage lang : filter (not . T.null)
38− ([langScript lang, langRegion lang] ++ langVariants lang))
39−
40−-- | Get the contents of the `lang` metadata field or variable.
41−getLang :: WriterOptions -> Meta -> Maybe T.Text
42−getLang opts meta =
43− case lookupContext "lang" (writerVariables opts) of
44− Just s -> Just s
45− _ ->
46− case lookupMeta "lang" meta of
47− Just (MetaBlocks [Para [Str s]]) -> Just s
48− Just (MetaBlocks [Plain [Str s]]) -> Just s
49− Just (MetaInlines [Str s]) -> Just s
50− Just (MetaString s) -> Just s
51− _ -> Nothing
52−
53−-- | Parse a BCP 47 string as a Lang. Currently we parse
54−-- extensions and private-use fields as "variants," even
55−-- though officially they aren't.
56−parseBCP47 :: T.Text -> Either T.Text Lang
57−parseBCP47 lang =
58− case P.parse bcp47 "lang" lang of
59− Right r -> Right r
60− Left e -> Left $ T.pack $ show e
61− where bcp47 = do
62− language <- pLanguage
63− script <- P.option "" pScript
64− region <- P.option "" pRegion
65− variants <- P.many (pVariant P.<|> pExtension P.<|> pPrivateUse)
66− P.eof
67− return Lang{ langLanguage = language
68− , langScript = script
69− , langRegion = region
70− , langVariants = variants }
71− asciiLetter = P.satisfy (\c -> isAscii c && isLetter c)
72− pLanguage = do
73− cs <- P.many1 asciiLetter
74− let lcs = length cs
75− guard $ lcs == 2 || lcs == 3
76− return $ T.toLower $ T.pack cs
77− pScript = P.try $ do
78− P.char '-'
79− x <- P.satisfy (\c -> isAscii c && isLetter c && isUpper c)
80− xs <- P.count 3
81− (P.satisfy (\c -> isAscii c && isLetter c && isLower c))
82− return $ T.toLower $ T.pack (x:xs)
83− pRegion = P.try $ do
84− P.char '-'
85− cs <- P.many1 asciiLetter
86− let lcs = length cs
87− guard $ lcs == 2 || lcs == 3
88− return $ T.toUpper $ T.pack cs
89− pVariant = P.try $ do
90− P.char '-'
91− ds <- P.option "" (P.count 1 P.digit)
92− cs <- P.many1 asciiLetter
93− let var = ds ++ cs
94− lv = length var
95− guard $ if null ds
96− then lv >= 5 && lv <= 8
97− else lv == 4
98− return $ T.toLower $ T.pack var
99− pExtension = P.try $ do
100− P.char '-'
101− cs <- P.many1 $ P.satisfy (\c -> isAscii c && isAlphaNum c)
102− let lcs = length cs
103− guard $ lcs >= 2 && lcs <= 8
104− return $ T.toLower $ T.pack cs
105− pPrivateUse = P.try $ do
106− P.char '-'
107− P.char 'x'
108− P.char '-'
109− cs <- P.many1 $ P.satisfy (\c -> isAscii c && isAlphaNum c)
110− guard $ not (null cs) && length cs <= 8
111− let var = "x-" ++ cs
112− return $ T.toLower $ T.pack var
src/Text/Pandoc/Citeproc.hs+70−51
@@ -18,7 +18,6 @@ import Text.Pandoc.Citeproc.CslJson (cslJsonToReferences)
18import Text.Pandoc.Citeproc.BibTeX (readBibtexString, Variant(..))
18import Text.Pandoc.Citeproc.BibTeX (readBibtexString, Variant(..))
19import Text.Pandoc.Citeproc.MetaValue (metaValueToReference, metaValueToText)
19import Text.Pandoc.Citeproc.MetaValue (metaValueToReference, metaValueToText)
20import Text.Pandoc.Readers.Markdown (yamlToRefs)
20import Text.Pandoc.Readers.Markdown (yamlToRefs)
21−import qualified Text.Pandoc.BCP47 as BCP47
22import Text.Pandoc.Builder (Inlines, Many(..), deleteMeta, setMeta)
21import Text.Pandoc.Builder (Inlines, Many(..), deleteMeta, setMeta)
23import qualified Text.Pandoc.Builder as B
22import qualified Text.Pandoc.Builder as B
24import Text.Pandoc.Definition as Pandoc
23import Text.Pandoc.Definition as Pandoc
@@ -28,7 +27,7 @@ import Text.Pandoc.Error (PandocError(..))
28import Text.Pandoc.Extensions (pandocExtensions)
27import Text.Pandoc.Extensions (pandocExtensions)
29import Text.Pandoc.Logging (LogMessage(..))
28import Text.Pandoc.Logging (LogMessage(..))
30import Text.Pandoc.Options (ReaderOptions(..))
29import Text.Pandoc.Options (ReaderOptions(..))
31−import Text.Pandoc.Shared (stringify, ordNub, blocksToInlines, tshow)
30+import Text.Pandoc.Shared (stringify, ordNub, tshow)
32import qualified Text.Pandoc.UTF8 as UTF8
31import qualified Text.Pandoc.UTF8 as UTF8
33import Text.Pandoc.Walk (query, walk, walkM)
32import Text.Pandoc.Walk (query, walk, walkM)
34import Control.Applicative ((<|>))
33import Control.Applicative ((<|>))
@@ -75,8 +74,7 @@ processCitations (Pandoc meta bs) = do
75
74
76 let linkCites = maybe False truish $ lookupMeta "link-citations" meta
75 let linkCites = maybe False truish $ lookupMeta "link-citations" meta
77 let opts = defaultCiteprocOptions{ linkCitations = linkCites }
76 let opts = defaultCiteprocOptions{ linkCitations = linkCites }
78− let result = Citeproc.citeproc opts style (localeLanguage locale)
77+ let result = Citeproc.citeproc opts style mblang refs citations
79− refs citations
80 mapM_ (report . CiteprocWarning) (resultWarnings result)
78 mapM_ (report . CiteprocWarning) (resultWarnings result)
81 let sopts = styleOptions style
79 let sopts = styleOptions style
82 let classes = "references" : -- TODO remove this or keep for compatibility?
80 let classes = "references" : -- TODO remove this or keep for compatibility?
@@ -93,22 +91,18 @@ processCitations (Pandoc meta bs) = do
93 walk (convertQuotes locale) .
91 walk (convertQuotes locale) .
94 insertSpace $ out)
92 insertSpace $ out)
95 (resultBibliography result)
93 (resultBibliography result)
96− let moveNotes = maybe True truish $
94+ let moveNotes = styleIsNoteStyle sopts &&
97− lookupMeta "notes-after-punctuation" meta
95+ maybe True truish (lookupMeta "notes-after-punctuation" meta)
98 let cits = map (walk (convertQuotes locale)) $
96 let cits = map (walk (convertQuotes locale)) $
99 resultCitations result
97 resultCitations result
100
98
101− let fixQuotes = case localePunctuationInQuote locale of
102− Just True ->
103− B.toList . movePunctuationInsideQuotes . B.fromList
104− _ -> id
105−
106 let metanocites = lookupMeta "nocite" meta
99 let metanocites = lookupMeta "nocite" meta
107 let Pandoc meta'' bs' =
100 let Pandoc meta'' bs' =
108 maybe id (setMeta "nocite") metanocites .
101 maybe id (setMeta "nocite") metanocites .
109− walk (map capitalizeNoteCitation .
110− fixQuotes . mvPunct moveNotes locale) .
102+ walk (mvPunct moveNotes locale) .
103+ (if styleIsNoteStyle sopts
111− walk deNote .
104+ then walk addNote . walk deNote
105+ else id) .
112 evalState (walkM insertResolvedCitations $ Pandoc meta' bs)
106 evalState (walkM insertResolvedCitations $ Pandoc meta' bs)
113 $ cits
107 $ cits
114 return $ Pandoc meta''
108 return $ Pandoc meta''
@@ -197,7 +191,9 @@ getReferences mblocale (Pandoc meta bs) = do
197 then const True
191 then const True
198 else (`Set.member` citeIds)
192 else (`Set.member` citeIds)
199 let inlineRefs = case lookupMeta "references" meta of
193 let inlineRefs = case lookupMeta "references" meta of
194+ Just (MetaList rs) ->
195+ filter (idpred . unItemId . referenceId)
200− Just (MetaList rs) -> mapMaybe metaValueToReference rs
196+ $ mapMaybe metaValueToReference rs
201 _ -> []
197 _ -> []
202 externalRefs <- case lookupMeta "bibliography" meta of
198 externalRefs <- case lookupMeta "bibliography" meta of
203 Just (MetaList xs) ->
199 Just (MetaList xs) ->
@@ -376,7 +372,6 @@ formatFromExtension fp = case dropWhile (== '.') $ takeExtension fp of
376
372
377
373
378isNote :: Inline -> Bool
374isNote :: Inline -> Bool
379−isNote (Note _) = True
380isNote (Cite _ [Note _]) = True
375isNote (Cite _ [Note _]) = True
381 -- the following allows citation styles that are "in-text" but use superscript
376 -- the following allows citation styles that are "in-text" but use superscript
382 -- references to be treated as if they are "notes" for the purposes of moving
377 -- references to be treated as if they are "notes" for the purposes of moving
@@ -389,6 +384,12 @@ isSpacy Space = True
389isSpacy SoftBreak = True
384isSpacy SoftBreak = True
390isSpacy _ = False
385isSpacy _ = False
391
386
387+movePunctInsideQuotes :: Locale -> [Inline] -> [Inline]
388+movePunctInsideQuotes locale
389+ | localePunctuationInQuote locale == Just True
390+ = B.toList . movePunctuationInsideQuotes . B.fromList
391+ | otherwise
392+ = id
392
393
393mvPunct :: Bool -> Locale -> [Inline] -> [Inline]
394mvPunct :: Bool -> Locale -> [Inline] -> [Inline]
394mvPunct moveNotes locale (x : xs)
395mvPunct moveNotes locale (x : xs)
@@ -401,7 +402,8 @@ mvPunct moveNotes locale (q : s : x : ys)
401 in if moveNotes
402 in if moveNotes
402 then if T.null spunct
403 then if T.null spunct
403 then q : x : mvPunct moveNotes locale ys
404 then q : x : mvPunct moveNotes locale ys
405+ else movePunctInsideQuotes locale
404− else q : Str spunct : x : mvPunct moveNotes locale
406+ [q , Str spunct , x] ++ mvPunct moveNotes locale
405 (B.toList
407 (B.toList
406 (dropTextWhile isPunctuation (B.fromList ys)))
408 (dropTextWhile isPunctuation (B.fromList ys)))
407 else q : x : mvPunct moveNotes locale ys
409 else q : x : mvPunct moveNotes locale ys
@@ -413,9 +415,10 @@ mvPunct moveNotes locale (Cite cs ils : ys)
413 , moveNotes
415 , moveNotes
414 = let s = stringify ys
416 = let s = stringify ys
415 spunct = T.takeWhile isPunctuation s
417 spunct = T.takeWhile isPunctuation s
418+ in Cite cs (movePunctInsideQuotes locale $
416− in Cite cs (init ils
419+ init ils
417− ++ [Str spunct | not (endWithPunct False (init ils))]
420+ ++ [Str spunct | not (endWithPunct False (init ils))]
418− ++ [last ils]) :
421+ ++ [last ils]) :
419 mvPunct moveNotes locale
422 mvPunct moveNotes locale
420 (B.toList (dropTextWhile isPunctuation (B.fromList ys)))
423 (B.toList (dropTextWhile isPunctuation (B.fromList ys)))
421mvPunct moveNotes locale (s : x : ys) | isSpacy s, isNote x =
424mvPunct moveNotes locale (s : x : ys) | isSpacy s, isNote x =
@@ -501,7 +504,8 @@ insertRefs refkvs refclasses meta refs bs =
501 put True
504 put True
502 -- refHeader isn't used if you have an explicit references div
505 -- refHeader isn't used if you have an explicit references div
503 let cs' = ordNub $ cs ++ refclasses
506 let cs' = ordNub $ cs ++ refclasses
507+ let kvs' = ordNub $ kvs ++ refkvs
504− return $ Div ("refs",cs',kvs) (xs ++ refs)
508+ return $ Div ("refs",cs',kvs') (xs ++ refs)
505 go x = return x
509 go x = return x
506
510
507refTitle :: Meta -> Maybe [Inline]
511refTitle :: Meta -> Maybe [Inline]
@@ -560,42 +564,62 @@ extractText (FancyVal x) = toText x
560extractText (NumVal n) = T.pack (show n)
564extractText (NumVal n) = T.pack (show n)
561extractText _ = mempty
565extractText _ = mempty
562
566
567+-- Here we take the Spans with class csl-note that are left
568+-- after deNote has removed nested ones, and convert them
569+-- into real notes.
563−capitalizeNoteCitation :: Inline -> Inline
570+addNote :: Inline -> Inline
564−capitalizeNoteCitation (Cite cs [Note [Para ils]]) =
571+addNote (Span ("",["csl-note"],[]) ils) =
565− Cite cs
572+ Note [Para $
566− [Note [Para $ B.toList $ addTextCase Nothing CapitalizeFirst
573+ B.toList . addTextCase Nothing CapitalizeFirst . B.fromList $ ils]
567− $ B.fromList ils]]
574+addNote x = x
568−capitalizeNoteCitation x = x
575+
569−
576+-- Here we handle citation notes that occur inside footnotes
577+-- or other citation notes, in a note style. We don't want
578+-- notes inside notes, so we convert these to parenthesized
579+-- or comma-separated citations.
570−deNote :: [Inline] -> [Inline]
580+deNote :: Inline -> Inline
571−deNote [] = []
581+deNote (Note bs) =
572−deNote (Note bs:rest) =
582+ case bs of
573− Note (walk go bs) : deNote rest
583+ [Para (cit@(Cite (c:_) _) : ils)]
584+ | citationMode c /= AuthorInText ->
585+ -- if citation is first in note, no need to parenthesize.
586+ Note [Para (walk removeNotes $ cit : walk addParens ils)]
587+ _ -> Note (walk removeNotes . walk addParens $ bs)
588+
574 where
589 where
575− go [] = []
590+ addParens [] = []
576− go (Cite (c:cs) ils : zs)
591+ addParens (Cite (c:cs) ils : zs)
577 | citationMode c == AuthorInText
592 | citationMode c == AuthorInText
578− = Cite (c:cs) (concatMap (noteAfterComma (needsPeriod zs)) ils) : go zs
593+ = Cite (c:cs) (concatMap (noteAfterComma (needsPeriod zs)) ils) :
594+ addParens zs
579 | otherwise
595 | otherwise
580− = Cite (c:cs) (concatMap noteInParens ils) : go zs
596+ = Cite (c:cs) (concatMap noteInParens ils) : addParens zs
581− go (x:xs) = x : go xs
597+ addParens (x:xs) = x : addParens xs
598+
599+ removeNotes (Span ("",["csl-note"],[]) ils) = Span ("",[],[]) ils
600+ removeNotes x = x
601+
582 needsPeriod [] = True
602 needsPeriod [] = True
583 needsPeriod (Str t:_) = case T.uncons t of
603 needsPeriod (Str t:_) = case T.uncons t of
584 Nothing -> False
604 Nothing -> False
585 Just (c,_) -> isUpper c
605 Just (c,_) -> isUpper c
586 needsPeriod (Space:zs) = needsPeriod zs
606 needsPeriod (Space:zs) = needsPeriod zs
587 needsPeriod _ = False
607 needsPeriod _ = False
608+
588− noteInParens (Note bs')
609+ noteInParens (Span ("",["csl-note"],[]) ils)
589 = Space : Str "(" :
610 = Space : Str "(" :
590− removeFinalPeriod (blocksToInlines bs') ++ [Str ")"]
611+ removeFinalPeriod ils ++ [Str ")"]
591 noteInParens x = [x]
612 noteInParens x = [x]
613+
592− noteAfterComma needsPer (Note bs')
614+ noteAfterComma needsPer (Span ("",["csl-note"],[]) ils)
615+ | not (null ils)
593 = Str "," : Space :
616 = Str "," : Space :
594− (if needsPer
617+ if needsPer
595− then id
618+ then ils
596− else removeFinalPeriod) (blocksToInlines bs')
619+ else removeFinalPeriod ils
597 noteAfterComma _ x = [x]
620 noteAfterComma _ x = [x]
621+
598−deNote (x:xs) = x : deNote xs
622+deNote x = x
599
623
600-- Note: we can't use dropTextWhileEnd indiscriminately,
624-- Note: we can't use dropTextWhileEnd indiscriminately,
601-- because this would remove the final period on abbreviations like Ibid.
625-- because this would remove the final period on abbreviations like Ibid.
@@ -630,13 +654,8 @@ removeFinalPeriod ils =
630
654
631bcp47LangToIETF :: PandocMonad m => Text -> m (Maybe Lang)
655bcp47LangToIETF :: PandocMonad m => Text -> m (Maybe Lang)
632bcp47LangToIETF bcplang =
656bcp47LangToIETF bcplang =
633− case BCP47.parseBCP47 bcplang of
657+ case parseLang bcplang of
634 Left _ -> do
658 Left _ -> do
635 report $ InvalidLang bcplang
659 report $ InvalidLang bcplang
636 return Nothing
660 return Nothing
637− Right lang ->
638− return $ Just
661+ Right lang -> return $ Just lang
639− $ Lang (BCP47.langLanguage lang)
640− (if T.null (BCP47.langRegion lang)
641− then Nothing
642− else Just (BCP47.langRegion lang))
src/Text/Pandoc/Citeproc/BibTeX.hs+25−15
@@ -59,10 +59,11 @@ data Variant = Bibtex | Biblatex
59 deriving (Show, Eq, Ord)
59 deriving (Show, Eq, Ord)
60
60
61-- | Parse BibTeX or BibLaTeX into a list of 'Reference's.
61-- | Parse BibTeX or BibLaTeX into a list of 'Reference's.
62+readBibtexString :: ToSources a
62−readBibtexString :: Variant -- ^ bibtex or biblatex
63+ => Variant -- ^ bibtex or biblatex
63 -> Locale -- ^ Locale
64 -> Locale -- ^ Locale
64 -> (Text -> Bool) -- ^ Filter on citation ids
65 -> (Text -> Bool) -- ^ Filter on citation ids
65− -> Text -- ^ bibtex/biblatex text
66+ -> a -- ^ bibtex/biblatex text
66 -> Either ParseError [Reference Inlines]
67 -> Either ParseError [Reference Inlines]
67readBibtexString variant locale idpred contents = do
68readBibtexString variant locale idpred contents = do
68 case runParser (((resolveCrossRefs variant <$> bibEntries) <* eof) >>=
69 case runParser (((resolveCrossRefs variant <$> bibEntries) <* eof) >>=
@@ -70,9 +71,11 @@ readBibtexString variant locale idpred contents = do
70 filter (\item -> idpred (identifier item) &&
71 filter (\item -> idpred (identifier item) &&
71 entryType item /= "xdata"))
72 entryType item /= "xdata"))
72 (fromMaybe defaultLang $ localeLanguage locale, Map.empty)
73 (fromMaybe defaultLang $ localeLanguage locale, Map.empty)
73− "" contents of
74+ (initialSourceName sources) sources of
74 Left err -> Left err
75 Left err -> Left err
75 Right xs -> return xs
76 Right xs -> return xs
77+ where
78+ sources = toSources contents
76
79
77-- | Write BibTeX or BibLaTeX given given a 'Reference'.
80-- | Write BibTeX or BibLaTeX given given a 'Reference'.
78writeBibtexString :: WriterOptions -- ^ options (for writing LaTex)
81writeBibtexString :: WriterOptions -- ^ options (for writing LaTex)
@@ -155,6 +158,7 @@ writeBibtexString opts variant mblang ref =
155 , "langid"
158 , "langid"
156 , "abstract"
159 , "abstract"
157 , "keywords"
160 , "keywords"
161+ , "annote"
158 ]
162 ]
159 Bibtex ->
163 Bibtex ->
160 [ "author"
164 [ "author"
@@ -174,6 +178,7 @@ writeBibtexString opts variant mblang ref =
174 , "address"
178 , "address"
175 , "type"
179 , "type"
176 , "note"
180 , "note"
181+ , "annote"
177 ]
182 ]
178
183
179 valToInlines (TextVal t) = B.text t
184 valToInlines (TextVal t) = B.text t
@@ -205,10 +210,13 @@ writeBibtexString opts variant mblang ref =
205 [ (", " <>) <$> nameGiven name,
210 [ (", " <>) <$> nameGiven name,
206 nameDroppingParticle name ]
211 nameDroppingParticle name ]
207
212
208− mblang' = (parseLang <$> getVariableAsText "language") <|> mblang
213+ mblang' = case getVariableAsText "language" of
214+ Just l -> either (const Nothing) Just $ parseLang l
215+ Nothing -> mblang
209
216
210 titlecase = case mblang' of
217 titlecase = case mblang' of
218+ Just lang | langLanguage lang == "en"
211− Just (Lang "en" _) -> titlecase'
219+ -> titlecase'
212 Nothing -> titlecase'
220 Nothing -> titlecase'
213 _ ->
221 _ ->
214 case variant of
222 case variant of
@@ -331,12 +339,12 @@ writeBibtexString opts variant mblang ref =
331 renderFields = mconcat . intersperse ("," <> cr) . mapMaybe renderField
339 renderFields = mconcat . intersperse ("," <> cr) . mapMaybe renderField
332
340
333defaultLang :: Lang
341defaultLang :: Lang
334−defaultLang = Lang "en" (Just "US")
342+defaultLang = Lang "en" Nothing (Just "US") [] [] []
335
343
336-- a map of bibtex "string" macros
344-- a map of bibtex "string" macros
337type StringMap = Map.Map Text Text
345type StringMap = Map.Map Text Text
338
346
339−type BibParser = Parser Text (Lang, StringMap)
347+type BibParser = Parser Sources (Lang, StringMap)
340
348
341data Item = Item{ identifier :: Text
349data Item = Item{ identifier :: Text
342 , sourcePos :: SourcePos
350 , sourcePos :: SourcePos
@@ -351,9 +359,7 @@ itemToReference locale variant item = do
351 bib item $ do
359 bib item $ do
352 let lang = fromMaybe defaultLang $ localeLanguage locale
360 let lang = fromMaybe defaultLang $ localeLanguage locale
353 modify $ \st -> st{ localeLang = lang,
361 modify $ \st -> st{ localeLang = lang,
354− untitlecase = case lang of
362+ untitlecase = langLanguage lang == "en" }
355− (Lang "en" _) -> True
356− _ -> False }
357
363
358 id' <- asks identifier
364 id' <- asks identifier
359 otherIds <- (Just <$> getRawField "ids")
365 otherIds <- (Just <$> getRawField "ids")
@@ -711,7 +717,7 @@ itemToReference locale variant item = do
711
717
712
718
713bib :: Item -> Bib a -> BibParser a
719bib :: Item -> Bib a -> BibParser a
714−bib entry m = fst <$> evalRWST m entry (BibState True (Lang "en" (Just "US")))
720+bib entry m = fst <$> evalRWST m entry (BibState True defaultLang)
715
721
716resolveCrossRefs :: Variant -> [Item] -> [Item]
722resolveCrossRefs :: Variant -> [Item] -> [Item]
717resolveCrossRefs variant entries =
723resolveCrossRefs variant entries =
@@ -803,7 +809,7 @@ bibEntries = do
803 (bibComment <|> bibPreamble <|> bibString))
809 (bibComment <|> bibPreamble <|> bibString))
804
810
805bibSkip :: BibParser ()
811bibSkip :: BibParser ()
806−bibSkip = () <$ take1WhileP (/='@')
812+bibSkip = skipMany1 (satisfy (/='@'))
807
813
808bibComment :: BibParser ()
814bibComment :: BibParser ()
809bibComment = do
815bibComment = do
@@ -828,6 +834,9 @@ bibString = do
828 updateState (\(l,m) -> (l, Map.insert k v m))
834 updateState (\(l,m) -> (l, Map.insert k v m))
829 return ()
835 return ()
830
836
837+take1WhileP :: Monad m => (Char -> Bool) -> ParserT Sources u m Text
838+take1WhileP f = T.pack <$> many1 (satisfy f)
839+
831inBraces :: BibParser Text
840inBraces :: BibParser Text
832inBraces = do
841inBraces = do
833 char '{'
842 char '{'
@@ -859,7 +868,7 @@ fieldName = resolveAlias . T.toLower
859
868
860isBibtexKeyChar :: Char -> Bool
869isBibtexKeyChar :: Char -> Bool
861isBibtexKeyChar c =
870isBibtexKeyChar c =
862− isAlphaNum c || c `elem` (".:;?!`'()/*@_+=-[]*&" :: [Char])
871+ isAlphaNum c || c `elem` (".:;?!`'()$/*@_+=-[]*&" :: [Char])
863
872
864bibItem :: BibParser Item
873bibItem :: BibParser Item
865bibItem = do
874bibItem = do
@@ -1456,8 +1465,9 @@ resolveKey lang ils = Walk.walk go ils
1456 go x = x
1465 go x = x
1457
1466
1458resolveKey' :: Lang -> Text -> Text
1467resolveKey' :: Lang -> Text -> Text
1459−resolveKey' lang@(Lang l _) k =
1468+resolveKey' lang k =
1460− case Map.lookup l biblatexStringMap >>= Map.lookup (T.toLower k) of
1469+ case Map.lookup (langLanguage lang) biblatexStringMap >>=
1470+ Map.lookup (T.toLower k) of
1461 Nothing -> k
1471 Nothing -> k
1462 Just (x, _) -> either (const k) stringify $ parseLaTeX lang x
1472 Just (x, _) -> either (const k) stringify $ parseLaTeX lang x
1463
1473
src/Text/Pandoc/Citeproc/Data.hs+7−6
@@ -10,7 +10,7 @@ import qualified Data.Text.Encoding as TE
10import qualified Data.Text as T
10import qualified Data.Text as T
11import Data.Text (Text)
11import Data.Text (Text)
12import Text.Pandoc.Citeproc.Util (toIETF)
12import Text.Pandoc.Citeproc.Util (toIETF)
13−import Citeproc (Lang(..), parseLang)
13+import Text.Collate.Lang (Lang(..), parseLang)
14
14
15biblatexLocalizations :: [(FilePath, ByteString)]
15biblatexLocalizations :: [(FilePath, ByteString)]
16biblatexLocalizations = $(embedDir "citeproc/biblatex-localization")
16biblatexLocalizations = $(embedDir "citeproc/biblatex-localization")
@@ -21,11 +21,12 @@ biblatexStringMap :: M.Map Text (M.Map Text (Text, Text))
21biblatexStringMap = foldr go mempty biblatexLocalizations
21biblatexStringMap = foldr go mempty biblatexLocalizations
22 where
22 where
23 go (fp, bs) =
23 go (fp, bs) =
24− let Lang lang _ = parseLang (toIETF $ T.takeWhile (/= '.') $ T.pack fp)
25− ls = T.lines $ TE.decodeUtf8 bs
24+ let ls = T.lines $ TE.decodeUtf8 bs
25+ in case parseLang (toIETF $ T.takeWhile (/= '.') $ T.pack fp) of
26− in if length ls > 4
26+ Right lang | length ls > 4
27+ -> M.insert (langLanguage lang)
27− then M.insert lang (toStringMap $ map (T.splitOn "|") ls)
28+ (toStringMap $ map (T.splitOn "|") ls)
28− else id
29+ _ -> id
29 toStringMap = foldr go' mempty
30 toStringMap = foldr go' mempty
30 go' [term, x, y] = M.insert term (x, y)
31 go' [term, x, y] = M.insert term (x, y)
31 go' _ = id
32 go' _ = id
src/Text/Pandoc/Citeproc/Locator.hs+18−3
@@ -20,7 +20,7 @@ parseLocator :: Locale -> [Inline] -> (Maybe (Text, Text), [Inline])
20parseLocator locale inp =
20parseLocator locale inp =
21 case parse (pLocatorWords (toLocatorMap locale)) "suffix" $ splitInp inp of
21 case parse (pLocatorWords (toLocatorMap locale)) "suffix" $ splitInp inp of
22 Right r -> r
22 Right r -> r
23− Left _ -> (Nothing, inp)
23+ Left _ -> (Nothing, maybeAddComma inp)
24
24
25splitInp :: [Inline] -> [Inline]
25splitInp :: [Inline] -> [Inline]
26splitInp = splitStrWhen (\c -> isSpace c || (isPunctuation c && c /= ':'))
26splitInp = splitStrWhen (\c -> isSpace c || (isPunctuation c && c /= ':'))
@@ -42,9 +42,17 @@ pLocatorWords locMap = do
42 -- i.e. the first one will be " 9"
42 -- i.e. the first one will be " 9"
43 return $
43 return $
44 if T.null la && T.null lo
44 if T.null la && T.null lo
45− then (Nothing, s)
45+ then (Nothing, maybeAddComma s)
46 else (Just (la, T.strip lo), s)
46 else (Just (la, T.strip lo), s)
47
47
48+maybeAddComma :: [Inline] -> [Inline]
49+maybeAddComma [] = []
50+maybeAddComma ils@(Space : _) = ils
51+maybeAddComma ils@(Str t : _)
52+ | Just (c, _) <- T.uncons t
53+ , isPunctuation c = ils
54+maybeAddComma ils = Str "," : Space : ils
55+
48pLocatorDelimited :: LocatorMap -> LocatorParser (Text, Text)
56pLocatorDelimited :: LocatorMap -> LocatorParser (Text, Text)
49pLocatorDelimited locMap = try $ do
57pLocatorDelimited locMap = try $ do
50 _ <- pMatchChar "{" (== '{')
58 _ <- pMatchChar "{" (== '{')
@@ -97,7 +105,7 @@ pLocatorLabel' locMap lim = go ""
97 t <- anyToken
105 t <- anyToken
98 ts <- manyTill anyToken (try $ lookAhead lim)
106 ts <- manyTill anyToken (try $ lookAhead lim)
99 let s = acc <> stringify (t:ts)
107 let s = acc <> stringify (t:ts)
100− case M.lookup (T.strip s) locMap of
108+ case M.lookup (T.toCaseFold $ T.strip s) locMap of
101 -- try to find a longer one, or return this one
109 -- try to find a longer one, or return this one
102 Just l -> go s <|> return (l, False)
110 Just l -> go s <|> return (l, False)
103 Nothing -> go s
111 Nothing -> go s
@@ -181,6 +189,7 @@ pPageUnit = roman <|> plainUnit
181 plainUnit = do
189 plainUnit = do
182 ts <- many1 (notFollowedBy pSpace >>
190 ts <- many1 (notFollowedBy pSpace >>
183 notFollowedBy pLocatorPunct >>
191 notFollowedBy pLocatorPunct >>
192+ notFollowedBy pMath >>
184 anyToken)
193 anyToken)
185 let s = stringify ts
194 let s = stringify ts
186 -- otherwise look for actual digits or -s
195 -- otherwise look for actual digits or -s
@@ -211,6 +220,12 @@ pMatchChar msg f = satisfyTok f' <?> msg
211pSpace :: LocatorParser Inline
220pSpace :: LocatorParser Inline
212pSpace = satisfyTok (\t -> isSpacey t || t == Str "\160") <?> "space"
221pSpace = satisfyTok (\t -> isSpacey t || t == Str "\160") <?> "space"
213
222
223+pMath :: LocatorParser Inline
224+pMath = satisfyTok isMath
225+ where
226+ isMath (Math{}) = True
227+ isMath _ = False
228+
214satisfyTok :: (Inline -> Bool) -> LocatorParser Inline
229satisfyTok :: (Inline -> Bool) -> LocatorParser Inline
215satisfyTok f = tokenPrim show (\sp _ _ -> sp) (\tok -> if f tok
230satisfyTok f = tokenPrim show (\sp _ _ -> sp) (\tok -> if f tok
216 then Just tok
231 then Just tok
src/Text/Pandoc/Class/CommonState.hs+1−1
@@ -19,7 +19,7 @@ where
19
19
20import Data.Default (Default (def))
20import Data.Default (Default (def))
21import Data.Text (Text)
21import Data.Text (Text)
22−import Text.Pandoc.BCP47 (Lang)
22+import Text.Collate.Lang (Lang)
23import Text.Pandoc.MediaBag (MediaBag)
23import Text.Pandoc.MediaBag (MediaBag)
24import Text.Pandoc.Logging (LogMessage, Verbosity (WARNING))
24import Text.Pandoc.Logging (LogMessage, Verbosity (WARNING))
25import Text.Pandoc.Translations (Translations)
25import Text.Pandoc.Translations (Translations)
src/Text/Pandoc/Class/IO.hs+21−22
@@ -62,7 +62,7 @@ import Text.Pandoc.Definition (Pandoc, Inline (Image))
62import Text.Pandoc.Error (PandocError (..))
62import Text.Pandoc.Error (PandocError (..))
63import Text.Pandoc.Logging (LogMessage (..), messageVerbosity, showLogMessage)
63import Text.Pandoc.Logging (LogMessage (..), messageVerbosity, showLogMessage)
64import Text.Pandoc.MIME (MimeType)
64import Text.Pandoc.MIME (MimeType)
65−import Text.Pandoc.MediaBag (MediaBag, lookupMedia, mediaDirectory)
65+import Text.Pandoc.MediaBag (MediaBag, MediaItem(..), lookupMedia, mediaItems)
66import Text.Pandoc.Walk (walk)
66import Text.Pandoc.Walk (walk)
67import qualified Control.Exception as E
67import qualified Control.Exception as E
68import qualified Data.ByteString as B
68import qualified Data.ByteString as B
@@ -200,33 +200,32 @@ alertIndent (l:ls) = do
200extractMedia :: (PandocMonad m, MonadIO m) => FilePath -> Pandoc -> m Pandoc
200extractMedia :: (PandocMonad m, MonadIO m) => FilePath -> Pandoc -> m Pandoc
201extractMedia dir d = do
201extractMedia dir d = do
202 media <- getMediaBag
202 media <- getMediaBag
203− case [fp | (fp, _, _) <- mediaDirectory media] of
203+ let items = mediaItems media
204+ if null items
204− [] -> return d
205+ then return d
205− fps -> do
206+ else do
206− mapM_ (writeMedia dir media) fps
207+ mapM_ (writeMedia dir) items
207− return $ walk (adjustImagePath dir fps) d
208+ return $ walk (adjustImagePath dir media) d
208
209
209-- | Write the contents of a media bag to a path.
210-- | Write the contents of a media bag to a path.
210writeMedia :: (PandocMonad m, MonadIO m)
211writeMedia :: (PandocMonad m, MonadIO m)
211− => FilePath -> MediaBag -> FilePath
212+ => FilePath
213+ -> (FilePath, MimeType, BL.ByteString)
212 -> m ()
214 -> m ()
213−writeMedia dir mediabag subpath = do
215+writeMedia dir (fp, _mt, bs) = do
214− -- we join and split to convert a/b/c to a\b\c on Windows;
216+ -- we normalize to get proper path separators for the platform
215− -- in zip containers all paths use /
216− let fullpath = dir </> unEscapeString (normalise subpath)
217+ let fullpath = normalise $ dir </> fp
217− let mbcontents = lookupMedia subpath mediabag
218− case mbcontents of
219− Nothing -> throwError $ PandocResourceNotFound $ pack subpath
220− Just (_, bs) -> do
221− report $ Extracting $ pack fullpath
222− liftIOError (createDirectoryIfMissing True) (takeDirectory fullpath)
218+ liftIOError (createDirectoryIfMissing True) (takeDirectory fullpath)
223− logIOError $ BL.writeFile fullpath bs
219+ logIOError $ BL.writeFile fullpath bs
224
220
225-- | If the given Inline element is an image with a @src@ path equal to
221-- | If the given Inline element is an image with a @src@ path equal to
226-- one in the list of @paths@, then prepends @dir@ to the image source;
222-- one in the list of @paths@, then prepends @dir@ to the image source;
227-- returns the element unchanged otherwise.
223-- returns the element unchanged otherwise.
228−adjustImagePath :: FilePath -> [FilePath] -> Inline -> Inline
224+adjustImagePath :: FilePath -> MediaBag -> Inline -> Inline
229−adjustImagePath dir paths (Image attr lab (src, tit))
225+adjustImagePath dir mediabag (Image attr lab (src, tit)) =
230− | unpack src `elem` paths
226+ case lookupMedia (T.unpack src) mediabag of
227+ Nothing -> Image attr lab (src, tit)
228+ Just item ->
229+ let fullpath = dir </> mediaPath item
231− = Image attr lab (pack (normalise $ dir </> unpack src), tit)
230+ in Image attr lab (T.pack fullpath, tit)
232adjustImagePath _ _ x = x
231adjustImagePath _ _ x = x
src/Text/Pandoc/Class/PandocMonad.hs+22−33
@@ -1,4 +1,5 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2+{-# LANGUAGE TupleSections #-}
2{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE MultiParamTypeClasses #-}
5{-# LANGUAGE MultiParamTypeClasses #-}
@@ -37,7 +38,6 @@ module Text.Pandoc.Class.PandocMonad
37 , setUserDataDir
38 , setUserDataDir
38 , getUserDataDir
39 , getUserDataDir
39 , fetchItem
40 , fetchItem
40− , fetchMediaResource
41 , getInputFiles
41 , getInputFiles
42 , setInputFiles
42 , setInputFiles
43 , getOutputFile
43 , getOutputFile
@@ -57,8 +57,6 @@ module Text.Pandoc.Class.PandocMonad
57import Codec.Archive.Zip
57import Codec.Archive.Zip
58import Control.Monad.Except (MonadError (catchError, throwError),
58import Control.Monad.Except (MonadError (catchError, throwError),
59 MonadTrans, lift, when)
59 MonadTrans, lift, when)
60−import Data.Digest.Pure.SHA (sha1, showDigest)
61−import Data.Maybe (fromMaybe)
62import Data.List (foldl')
60import Data.List (foldl')
63import Data.Time (UTCTime)
61import Data.Time (UTCTime)
64import Data.Time.Clock.POSIX (POSIXTime, utcTimeToPOSIXSeconds,
62import Data.Time.Clock.POSIX (POSIXTime, utcTimeToPOSIXSeconds,
@@ -67,16 +65,16 @@ import Data.Time.LocalTime (TimeZone, ZonedTime, utcToZonedTime)
67import Network.URI ( escapeURIString, nonStrictRelativeTo,
65import Network.URI ( escapeURIString, nonStrictRelativeTo,
68 unEscapeString, parseURIReference, isAllowedInURI,
66 unEscapeString, parseURIReference, isAllowedInURI,
69 parseURI, URI(..) )
67 parseURI, URI(..) )
70−import System.FilePath ((</>), (<.>), takeExtension, dropExtension,
68+import System.FilePath ((</>), takeExtension, dropExtension,
71− isRelative, splitDirectories)
69+ isRelative, splitDirectories, makeRelative)
72import System.Random (StdGen)
70import System.Random (StdGen)
73−import Text.Pandoc.BCP47 (Lang(..), parseBCP47, renderLang)
71+import Text.Collate.Lang (Lang(..), parseLang, renderLang)
74import Text.Pandoc.Class.CommonState (CommonState (..))
72import Text.Pandoc.Class.CommonState (CommonState (..))
75import Text.Pandoc.Definition
73import Text.Pandoc.Definition
76import Text.Pandoc.Error
74import Text.Pandoc.Error
77import Text.Pandoc.Logging
75import Text.Pandoc.Logging
78−import Text.Pandoc.MIME (MimeType, getMimeType, extensionFromMimeType)
76+import Text.Pandoc.MIME (MimeType, getMimeType)
79−import Text.Pandoc.MediaBag (MediaBag, lookupMedia)
77+import Text.Pandoc.MediaBag (MediaBag, lookupMedia, MediaItem(..))
80import Text.Pandoc.Shared (uriPathToPath, safeRead)
78import Text.Pandoc.Shared (uriPathToPath, safeRead)
81import Text.Pandoc.Translations (Term(..), Translations, lookupTerm,
79import Text.Pandoc.Translations (Term(..), Translations, lookupTerm,
82 readTranslations)
80 readTranslations)
@@ -285,7 +283,7 @@ readFileFromDirs (d:ds) f = catchError
285toLang :: PandocMonad m => Maybe T.Text -> m (Maybe Lang)
283toLang :: PandocMonad m => Maybe T.Text -> m (Maybe Lang)
286toLang Nothing = return Nothing
284toLang Nothing = return Nothing
287toLang (Just s) =
285toLang (Just s) =
288− case parseBCP47 s of
286+ case parseLang s of
289 Left _ -> do
287 Left _ -> do
290 report $ InvalidLang s
288 report $ InvalidLang s
291 return Nothing
289 return Nothing
@@ -376,7 +374,8 @@ fetchItem :: PandocMonad m
376fetchItem s = do
374fetchItem s = do
377 mediabag <- getMediaBag
375 mediabag <- getMediaBag
378 case lookupMedia (T.unpack s) mediabag of
376 case lookupMedia (T.unpack s) mediabag of
379− Just (mime, bs) -> return (BL.toStrict bs, Just mime)
377+ Just item -> return (BL.toStrict (mediaContents item),
378+ Just (mediaMimeType item))
380 Nothing -> downloadOrRead s
379 Nothing -> downloadOrRead s
381
380
382-- | Returns the content and, if available, the MIME type of a resource.
381-- | Returns the content and, if available, the MIME type of a resource.
@@ -411,9 +410,10 @@ downloadOrRead s = do
411 _ -> readLocalFile fp -- get from local file system
410 _ -> readLocalFile fp -- get from local file system
412 where readLocalFile f = do
411 where readLocalFile f = do
413 resourcePath <- getResourcePath
412 resourcePath <- getResourcePath
414− cont <- if isRelative f
413+ (fp', cont) <- if isRelative f
415− then withPaths resourcePath readFileStrict f
414+ then withPaths resourcePath readFileStrict f
416− else readFileStrict f
415+ else (f,) <$> readFileStrict f
416+ report $ LoadedResource f (makeRelative "." fp')
417 return (cont, mime)
417 return (cont, mime)
418 httpcolon = URI{ uriScheme = "http:",
418 httpcolon = URI{ uriScheme = "http:",
419 uriAuthority = Nothing,
419 uriAuthority = Nothing,
@@ -623,25 +623,13 @@ makeCanonical = Posix.joinPath . transformPathParts . splitDirectories
623-- that filepath. Returns the result of the first successful execution
623-- that filepath. Returns the result of the first successful execution
624-- of the action, or throws a @PandocResourceNotFound@ exception if the
624-- of the action, or throws a @PandocResourceNotFound@ exception if the
625-- action errors for all filepaths.
625-- action errors for all filepaths.
626+withPaths :: PandocMonad m
626−withPaths :: PandocMonad m => [FilePath] -> (FilePath -> m a) -> FilePath -> m a
627+ => [FilePath] -> (FilePath -> m a) -> FilePath -> m (FilePath, a)
627withPaths [] _ fp = throwError $ PandocResourceNotFound $ T.pack fp
628withPaths [] _ fp = throwError $ PandocResourceNotFound $ T.pack fp
628withPaths (p:ps) action fp =
629withPaths (p:ps) action fp =
629− catchError (action (p </> fp))
630+ catchError ((p </> fp,) <$> action (p </> fp))
630 (\_ -> withPaths ps action fp)
631 (\_ -> withPaths ps action fp)
631
632
632−-- | Fetch local or remote resource (like an image) and provide data suitable
633−-- for adding it to the MediaBag.
634−fetchMediaResource :: PandocMonad m
635− => T.Text -> m (FilePath, Maybe MimeType, BL.ByteString)
636−fetchMediaResource src = do
637− (bs, mt) <- downloadOrRead src
638− let ext = fromMaybe (T.pack $ takeExtension $ T.unpack src)
639− (mt >>= extensionFromMimeType)
640− let bs' = BL.fromChunks [bs]
641− let basename = showDigest $ sha1 bs'
642− let fname = basename <.> T.unpack ext
643− return (fname, mt, bs')
644−
645-- | Traverse tree, filling media bag for any images that
633-- | Traverse tree, filling media bag for any images that
646-- aren't already in the media bag.
634-- aren't already in the media bag.
647fillMediaBag :: PandocMonad m => Pandoc -> m Pandoc
635fillMediaBag :: PandocMonad m => Pandoc -> m Pandoc
@@ -649,12 +637,13 @@ fillMediaBag d = walkM handleImage d
649 where handleImage :: PandocMonad m => Inline -> m Inline
637 where handleImage :: PandocMonad m => Inline -> m Inline
650 handleImage (Image attr lab (src, tit)) = catchError
638 handleImage (Image attr lab (src, tit)) = catchError
651 (do mediabag <- getMediaBag
639 (do mediabag <- getMediaBag
652− case lookupMedia (T.unpack src) mediabag of
640+ let fp = T.unpack src
641+ case lookupMedia fp mediabag of
653− Just (_, _) -> return $ Image attr lab (src, tit)
642+ Just _ -> return ()
654 Nothing -> do
643 Nothing -> do
655− (fname, mt, bs) <- fetchMediaResource src
644+ (bs, mt) <- fetchItem src
656− insertMedia fname mt bs
645+ insertMedia fp mt (BL.fromStrict bs)
657− return $ Image attr lab (T.pack fname, tit))
646+ return $ Image attr lab (src, tit))
658 (\e ->
647 (\e ->
659 case e of
648 case e of
660 PandocResourceNotFound _ -> do
649 PandocResourceNotFound _ -> do
src/Text/Pandoc/Error.hs+23−16
@@ -23,26 +23,27 @@ import Control.Exception (Exception, displayException)
23import Data.Typeable (Typeable)
23import Data.Typeable (Typeable)
24import Data.Word (Word8)
24import Data.Word (Word8)
25import Data.Text (Text)
25import Data.Text (Text)
26+import Data.List (sortOn)
26import qualified Data.Text as T
27import qualified Data.Text as T
28+import Data.Ord (Down(..))
27import GHC.Generics (Generic)
29import GHC.Generics (Generic)
28import Network.HTTP.Client (HttpException)
30import Network.HTTP.Client (HttpException)
29import System.Exit (ExitCode (..), exitWith)
31import System.Exit (ExitCode (..), exitWith)
30import System.IO (stderr)
32import System.IO (stderr)
31import qualified Text.Pandoc.UTF8 as UTF8
33import qualified Text.Pandoc.UTF8 as UTF8
34+import Text.Pandoc.Sources (Sources(..))
32import Text.Printf (printf)
35import Text.Printf (printf)
33import Text.Parsec.Error
36import Text.Parsec.Error
34import Text.Parsec.Pos hiding (Line)
37import Text.Parsec.Pos hiding (Line)
35import Text.Pandoc.Shared (tshow)
38import Text.Pandoc.Shared (tshow)
36import Citeproc (CiteprocError, prettyCiteprocError)
39import Citeproc (CiteprocError, prettyCiteprocError)
37
40
38−type Input = Text
39−
40data PandocError = PandocIOError Text IOError
41data PandocError = PandocIOError Text IOError
41 | PandocHttpError Text HttpException
42 | PandocHttpError Text HttpException
42 | PandocShouldNeverHappenError Text
43 | PandocShouldNeverHappenError Text
43 | PandocSomeError Text
44 | PandocSomeError Text
44 | PandocParseError Text
45 | PandocParseError Text
45− | PandocParsecError Input ParseError
46+ | PandocParsecError Sources ParseError
46 | PandocMakePDFError Text
47 | PandocMakePDFError Text
47 | PandocOptionError Text
48 | PandocOptionError Text
48 | PandocSyntaxMapError Text
49 | PandocSyntaxMapError Text
@@ -81,22 +82,28 @@ renderError e =
81 "Please report this to pandoc's developers: " <> s
82 "Please report this to pandoc's developers: " <> s
82 PandocSomeError s -> s
83 PandocSomeError s -> s
83 PandocParseError s -> s
84 PandocParseError s -> s
84− PandocParsecError input err' ->
85+ PandocParsecError (Sources inputs) err' ->
85 let errPos = errorPos err'
86 let errPos = errorPos err'
86 errLine = sourceLine errPos
87 errLine = sourceLine errPos
87 errColumn = sourceColumn errPos
88 errColumn = sourceColumn errPos
89+ errFile = sourceName errPos
90+ errorInFile =
91+ case sortOn (Down . sourceLine . fst)
92+ [ (pos,t)
93+ | (pos,t) <- inputs
94+ , sourceName pos == errFile
95+ , sourceLine pos <= errLine
96+ ] of
97+ [] -> ""
98+ ((pos,txt):_) ->
88− ls = T.lines input <> [""]
99+ let ls = T.lines txt <> [""]
100+ ln = (errLine - sourceLine pos) + 1
89− errorInFile = if length ls > errLine - 1
101+ in if length ls > ln && ln >= 1
90− then T.concat ["\n", ls !! (errLine - 1)
102+ then T.concat ["\n", ls !! (ln - 1)
91− ,"\n", T.replicate (errColumn - 1) " "
103+ ,"\n", T.replicate (errColumn - 1) " "
92− ,"^"]
104+ ,"^"]
93− else ""
105+ else ""
94− in "\nError at " <> tshow err' <>
106+ in "Error at " <> tshow err' <> errorInFile
95− -- if error comes from a chunk or included file,
96− -- then we won't get the right text this way:
97− if sourceName errPos == "source"
98− then errorInFile
99− else ""
100 PandocMakePDFError s -> s
107 PandocMakePDFError s -> s
101 PandocOptionError s -> s
108 PandocOptionError s -> s
102 PandocSyntaxMapError s -> s
109 PandocSyntaxMapError s -> s
src/Text/Pandoc/Extensions.hs+7
@@ -136,6 +136,8 @@ data Extension =
136 | Ext_raw_html -- ^ Allow raw HTML
136 | Ext_raw_html -- ^ Allow raw HTML
137 | Ext_raw_tex -- ^ Allow raw TeX (other than math)
137 | Ext_raw_tex -- ^ Allow raw TeX (other than math)
138 | Ext_raw_markdown -- ^ Parse markdown in ipynb as raw markdown
138 | Ext_raw_markdown -- ^ Parse markdown in ipynb as raw markdown
139+ | Ext_rebase_relative_paths -- ^ Rebase relative image and link paths,
140+ -- relative to directory of containing file
139 | Ext_shortcut_reference_links -- ^ Shortcut reference links
141 | Ext_shortcut_reference_links -- ^ Shortcut reference links
140 | Ext_simple_tables -- ^ Pandoc-style simple tables
142 | Ext_simple_tables -- ^ Pandoc-style simple tables
141 | Ext_smart -- ^ "Smart" quotes, apostrophes, ellipses, dashes
143 | Ext_smart -- ^ "Smart" quotes, apostrophes, ellipses, dashes
@@ -354,6 +356,7 @@ getDefaultExtensions "gfm" = extensionsFromList
354 , Ext_strikeout
356 , Ext_strikeout
355 , Ext_task_lists
357 , Ext_task_lists
356 , Ext_emoji
358 , Ext_emoji
359+ , Ext_yaml_metadata_block
357 ]
360 ]
358getDefaultExtensions "commonmark" = extensionsFromList
361getDefaultExtensions "commonmark" = extensionsFromList
359 [Ext_raw_html]
362 [Ext_raw_html]
@@ -379,6 +382,7 @@ getDefaultExtensions "commonmark_x" = extensionsFromList
379 , Ext_raw_attribute
382 , Ext_raw_attribute
380 , Ext_implicit_header_references
383 , Ext_implicit_header_references
381 , Ext_attributes
384 , Ext_attributes
385+ , Ext_yaml_metadata_block
382 ]
386 ]
383getDefaultExtensions "org" = extensionsFromList
387getDefaultExtensions "org" = extensionsFromList
384 [Ext_citations,
388 [Ext_citations,
@@ -460,6 +464,7 @@ getAllExtensions f = universalExtensions <> getAll f
460 , Ext_gutenberg
464 , Ext_gutenberg
461 , Ext_smart
465 , Ext_smart
462 , Ext_literate_haskell
466 , Ext_literate_haskell
467+ , Ext_rebase_relative_paths
463 ]
468 ]
464 getAll "markdown_strict" = allMarkdownExtensions
469 getAll "markdown_strict" = allMarkdownExtensions
465 getAll "markdown_phpextra" = allMarkdownExtensions
470 getAll "markdown_phpextra" = allMarkdownExtensions
@@ -511,6 +516,8 @@ getAllExtensions f = universalExtensions <> getAll f
511 , Ext_implicit_header_references
516 , Ext_implicit_header_references
512 , Ext_attributes
517 , Ext_attributes
513 , Ext_sourcepos
518 , Ext_sourcepos
519+ , Ext_yaml_metadata_block
520+ , Ext_rebase_relative_paths
514 ]
521 ]
515 getAll "commonmark_x" = getAll "commonmark"
522 getAll "commonmark_x" = getAll "commonmark"
516 getAll "org" = autoIdExtensions <>
523 getAll "org" = autoIdExtensions <>
src/Text/Pandoc/Highlighting.hs+5−5
@@ -52,12 +52,12 @@ highlightingStyles =
52 ("breezedark", breezeDark),
52 ("breezedark", breezeDark),
53 ("haddock", haddock)]
53 ("haddock", haddock)]
54
54
55−languages :: [T.Text]
55+languages :: SyntaxMap -> [T.Text]
56−languages = [T.toLower (sName s) | s <- M.elems defaultSyntaxMap]
56+languages syntaxmap = [T.toLower (sName s) | s <- M.elems syntaxmap]
57
57
58−languagesByExtension :: T.Text -> [T.Text]
58+languagesByExtension :: SyntaxMap -> T.Text -> [T.Text]
59−languagesByExtension ext =
59+languagesByExtension syntaxmap ext =
60− [T.toLower (sName s) | s <- syntaxesByExtension defaultSyntaxMap (T.unpack ext)]
60+ [T.toLower (sName s) | s <- syntaxesByExtension syntaxmap (T.unpack ext)]
61
61
62highlight :: SyntaxMap
62highlight :: SyntaxMap
63 -> (FormatOptions -> [SourceLine] -> a) -- ^ Formatter
63 -> (FormatOptions -> [SourceLine] -> a) -- ^ Formatter
src/Text/Pandoc/ImageSize.hs+5−1
@@ -57,7 +57,8 @@ import Codec.Picture (decodeImageWithMetadata)
57-- quick and dirty functions to get image sizes
57-- quick and dirty functions to get image sizes
58-- algorithms borrowed from wwwis.pl
58-- algorithms borrowed from wwwis.pl
59
59
60−data ImageType = Png | Gif | Jpeg | Svg | Pdf | Eps | Emf deriving Show
60+data ImageType = Png | Gif | Jpeg | Svg | Pdf | Eps | Emf | Tiff
61+ deriving Show
61data Direction = Width | Height
62data Direction = Width | Height
62instance Show Direction where
63instance Show Direction where
63 show Width = "width"
64 show Width = "width"
@@ -100,6 +101,8 @@ imageType :: ByteString -> Maybe ImageType
100imageType img = case B.take 4 img of
101imageType img = case B.take 4 img of
101 "\x89\x50\x4e\x47" -> return Png
102 "\x89\x50\x4e\x47" -> return Png
102 "\x47\x49\x46\x38" -> return Gif
103 "\x47\x49\x46\x38" -> return Gif
104+ "\x49\x49\x2a\x00" -> return Tiff
105+ "\x4D\x4D\x00\x2a" -> return Tiff
103 "\xff\xd8\xff\xe0" -> return Jpeg -- JFIF
106 "\xff\xd8\xff\xe0" -> return Jpeg -- JFIF
104 "\xff\xd8\xff\xe1" -> return Jpeg -- Exif
107 "\xff\xd8\xff\xe1" -> return Jpeg -- Exif
105 "%PDF" -> return Pdf
108 "%PDF" -> return Pdf
@@ -124,6 +127,7 @@ imageSize opts img = checkDpi <$>
124 Just Png -> getSize img
127 Just Png -> getSize img
125 Just Gif -> getSize img
128 Just Gif -> getSize img
126 Just Jpeg -> getSize img
129 Just Jpeg -> getSize img
130+ Just Tiff -> getSize img
127 Just Svg -> mbToEither "could not determine SVG size" $ svgSize opts img
131 Just Svg -> mbToEither "could not determine SVG size" $ svgSize opts img
128 Just Eps -> mbToEither "could not determine EPS size" $ epsSize img
132 Just Eps -> mbToEither "could not determine EPS size" $ epsSize img
129 Just Pdf -> mbToEither "could not determine PDF size" $ pdfSize img
133 Just Pdf -> mbToEither "could not determine PDF size" $ pdfSize img
src/Text/Pandoc/Logging.hs+18−9
@@ -85,6 +85,7 @@ data LogMessage =
85 | CouldNotParseCSS Text
85 | CouldNotParseCSS Text
86 | Fetching Text
86 | Fetching Text
87 | Extracting Text
87 | Extracting Text
88+ | LoadedResource FilePath FilePath
88 | NoTitleElement Text
89 | NoTitleElement Text
89 | NoLangSpecified
90 | NoLangSpecified
90 | InvalidLang Text
91 | InvalidLang Text
@@ -195,6 +196,9 @@ instance ToJSON LogMessage where
195 ["path" .= fp]
196 ["path" .= fp]
196 Extracting fp ->
197 Extracting fp ->
197 ["path" .= fp]
198 ["path" .= fp]
199+ LoadedResource orig found ->
200+ ["for" .= orig
201+ ,"from" .= found]
198 NoTitleElement fallback ->
202 NoTitleElement fallback ->
199 ["fallback" .= fallback]
203 ["fallback" .= fallback]
200 NoLangSpecified -> []
204 NoLangSpecified -> []
@@ -241,9 +245,11 @@ instance ToJSON LogMessage where
241showPos :: SourcePos -> Text
245showPos :: SourcePos -> Text
242showPos pos = Text.pack $ sn ++ "line " ++
246showPos pos = Text.pack $ sn ++ "line " ++
243 show (sourceLine pos) ++ " column " ++ show (sourceColumn pos)
247 show (sourceLine pos) ++ " column " ++ show (sourceColumn pos)
244− where sn = if sourceName pos == "source" || sourceName pos == ""
248+ where
249+ sn' = sourceName pos
250+ sn = if sn' == "source" || sn' == "" || sn' == "-"
245− then ""
251+ then ""
246− else sourceName pos ++ " "
252+ else sn' ++ " "
247
253
248encodeLogMessages :: [LogMessage] -> BL.ByteString
254encodeLogMessages :: [LogMessage] -> BL.ByteString
249encodeLogMessages ms =
255encodeLogMessages ms =
@@ -276,7 +282,7 @@ showLogMessage msg =
276 ParsingUnescaped s pos ->
282 ParsingUnescaped s pos ->
277 "Parsing unescaped '" <> s <> "' at " <> showPos pos
283 "Parsing unescaped '" <> s <> "' at " <> showPos pos
278 CouldNotLoadIncludeFile fp pos ->
284 CouldNotLoadIncludeFile fp pos ->
279− "Could not load include file '" <> fp <> "' at " <> showPos pos
285+ "Could not load include file " <> fp <> " at " <> showPos pos
280 MacroAlreadyDefined name pos ->
286 MacroAlreadyDefined name pos ->
281 "Macro '" <> name <> "' already defined, ignoring at " <> showPos pos
287 "Macro '" <> name <> "' already defined, ignoring at " <> showPos pos
282 InlineNotRendered il ->
288 InlineNotRendered il ->
@@ -288,18 +294,18 @@ showLogMessage msg =
288 IgnoredIOError s ->
294 IgnoredIOError s ->
289 "IO Error (ignored): " <> s
295 "IO Error (ignored): " <> s
290 CouldNotFetchResource fp s ->
296 CouldNotFetchResource fp s ->
291− "Could not fetch resource '" <> fp <> "'" <>
297+ "Could not fetch resource " <> fp <>
292 if Text.null s then "" else ": " <> s
298 if Text.null s then "" else ": " <> s
293 CouldNotDetermineImageSize fp s ->
299 CouldNotDetermineImageSize fp s ->
294− "Could not determine image size for '" <> fp <> "'" <>
300+ "Could not determine image size for " <> fp <>
295 if Text.null s then "" else ": " <> s
301 if Text.null s then "" else ": " <> s
296 CouldNotConvertImage fp s ->
302 CouldNotConvertImage fp s ->
297− "Could not convert image '" <> fp <> "'" <>
303+ "Could not convert image " <> fp <>
298 if Text.null s then "" else ": " <> s
304 if Text.null s then "" else ": " <> s
299 CouldNotDetermineMimeType fp ->
305 CouldNotDetermineMimeType fp ->
300− "Could not determine mime type for '" <> fp <> "'"
306+ "Could not determine mime type for " <> fp
301 CouldNotConvertTeXMath s m ->
307 CouldNotConvertTeXMath s m ->
302− "Could not convert TeX math '" <> s <> "', rendering as TeX" <>
308+ "Could not convert TeX math " <> s <> ", rendering as TeX" <>
303 if Text.null m then "" else ":\n" <> m
309 if Text.null m then "" else ":\n" <> m
304 CouldNotParseCSS m ->
310 CouldNotParseCSS m ->
305 "Could not parse CSS" <> if Text.null m then "" else ":\n" <> m
311 "Could not parse CSS" <> if Text.null m then "" else ":\n" <> m
@@ -307,6 +313,8 @@ showLogMessage msg =
307 "Fetching " <> fp <> "..."
313 "Fetching " <> fp <> "..."
308 Extracting fp ->
314 Extracting fp ->
309 "Extracting " <> fp <> "..."
315 "Extracting " <> fp <> "..."
316+ LoadedResource orig found ->
317+ "Loaded " <> Text.pack orig <> " from " <> Text.pack found
310 NoTitleElement fallback ->
318 NoTitleElement fallback ->
311 "This document format requires a nonempty <title> element.\n" <>
319 "This document format requires a nonempty <title> element.\n" <>
312 "Defaulting to '" <> fallback <> "' as the title.\n" <>
320 "Defaulting to '" <> fallback <> "' as the title.\n" <>
@@ -387,6 +395,7 @@ messageVerbosity msg =
387 CouldNotParseCSS{} -> WARNING
395 CouldNotParseCSS{} -> WARNING
388 Fetching{} -> INFO
396 Fetching{} -> INFO
389 Extracting{} -> INFO
397 Extracting{} -> INFO
398+ LoadedResource{} -> INFO
390 NoTitleElement{} -> WARNING
399 NoTitleElement{} -> WARNING
391 NoLangSpecified -> INFO
400 NoLangSpecified -> INFO
392 InvalidLang{} -> WARNING
401 InvalidLang{} -> WARNING
src/Text/Pandoc/Lua/Filter.hs+2
@@ -13,7 +13,9 @@ module Text.Pandoc.Lua.Filter ( LuaFilterFunction
13 , LuaFilter
13 , LuaFilter
14 , runFilterFile
14 , runFilterFile
15 , walkInlines
15 , walkInlines
16+ , walkInlineLists
16 , walkBlocks
17 , walkBlocks
18+ , walkBlockLists
17 , module Text.Pandoc.Lua.Walk
19 , module Text.Pandoc.Lua.Walk
18 ) where
20 ) where
19import Control.Applicative ((<|>))
21import Control.Applicative ((<|>))
src/Text/Pandoc/Lua/Module/MediaBag.hs+3−3
@@ -73,9 +73,9 @@ lookup fp = do
73 res <- MB.lookupMedia fp <$> getMediaBag
73 res <- MB.lookupMedia fp <$> getMediaBag
74 liftPandocLua $ case res of
74 liftPandocLua $ case res of
75 Nothing -> 1 <$ Lua.pushnil
75 Nothing -> 1 <$ Lua.pushnil
76− Just (mimeType, contents) -> do
76+ Just item -> do
77− Lua.push mimeType
77+ Lua.push $ MB.mediaMimeType item
78− Lua.push contents
78+ Lua.push $ MB.mediaContents item
79 return 2
79 return 2
80
80
81list :: PandocLua NumResults
81list :: PandocLua NumResults
src/Text/Pandoc/Lua/Module/Pandoc.hs+8−3
@@ -23,8 +23,10 @@ import Foreign.Lua (Lua, NumResults, Optional, Peekable, Pushable)
23import System.Exit (ExitCode (..))
23import System.Exit (ExitCode (..))
24import Text.Pandoc.Class.PandocIO (runIO)
24import Text.Pandoc.Class.PandocIO (runIO)
25import Text.Pandoc.Definition (Block, Inline)
25import Text.Pandoc.Definition (Block, Inline)
26−import Text.Pandoc.Lua.Filter (walkInlines, walkBlocks, LuaFilter, SingletonsList (..))
26+import Text.Pandoc.Lua.Filter (LuaFilter, SingletonsList (..), walkInlines,
27+ walkInlineLists, walkBlocks, walkBlockLists)
27import Text.Pandoc.Lua.Marshaling ()
28import Text.Pandoc.Lua.Marshaling ()
29+import Text.Pandoc.Lua.Marshaling.List (List (..))
28import Text.Pandoc.Lua.PandocLua (PandocLua, addFunction, liftPandocLua,
30import Text.Pandoc.Lua.PandocLua (PandocLua, addFunction, liftPandocLua,
29 loadDefaultModule)
31 loadDefaultModule)
30import Text.Pandoc.Walk (Walkable)
32import Text.Pandoc.Walk (Walkable)
@@ -51,9 +53,12 @@ pushModule = do
51 return 1
53 return 1
52
54
53walkElement :: (Walkable (SingletonsList Inline) a,
55walkElement :: (Walkable (SingletonsList Inline) a,
54− Walkable (SingletonsList Block) a)
56+ Walkable (SingletonsList Block) a,
57+ Walkable (List Inline) a,
58+ Walkable (List Block) a)
55 => a -> LuaFilter -> PandocLua a
59 => a -> LuaFilter -> PandocLua a
56−walkElement x f = liftPandocLua $ walkInlines f x >>= walkBlocks f
60+walkElement x f = liftPandocLua $
61+ walkInlines f x >>= walkInlineLists f >>= walkBlocks f >>= walkBlockLists f
57
62
58walk_inline :: Inline -> LuaFilter -> PandocLua Inline
63walk_inline :: Inline -> LuaFilter -> PandocLua Inline
59walk_inline = walkElement
64walk_inline = walkElement
src/Text/Pandoc/Lua/Module/Utils.hs+1−1
@@ -146,7 +146,7 @@ from_simple_table (SimpleTable capt aligns widths head' body) = do
146 nullAttr
146 nullAttr
147 (Caption Nothing [Plain capt])
147 (Caption Nothing [Plain capt])
148 (zipWith (\a w -> (a, toColWidth w)) aligns widths)
148 (zipWith (\a w -> (a, toColWidth w)) aligns widths)
149− (TableHead nullAttr [blockListToRow head'])
149+ (TableHead nullAttr [blockListToRow head' | not (null head') ])
150 [TableBody nullAttr 0 [] $ map blockListToRow body]
150 [TableBody nullAttr 0 [] $ map blockListToRow body]
151 (TableFoot nullAttr [])
151 (TableFoot nullAttr [])
152 return (NumResults 1)
152 return (NumResults 1)
src/Text/Pandoc/MIME.hs+10
@@ -43,6 +43,16 @@ getMimeTypeDef :: FilePath -> MimeType
43getMimeTypeDef = fromMaybe "application/octet-stream" . getMimeType
43getMimeTypeDef = fromMaybe "application/octet-stream" . getMimeType
44
44
45extensionFromMimeType :: MimeType -> Maybe T.Text
45extensionFromMimeType :: MimeType -> Maybe T.Text
46+-- few special cases, where there are multiple options:
47+extensionFromMimeType "text/plain" = Just "txt"
48+extensionFromMimeType "video/quicktime" = Just "mov"
49+extensionFromMimeType "video/mpeg" = Just "mpeg"
50+extensionFromMimeType "video/dv" = Just "dv"
51+extensionFromMimeType "image/vnd.djvu" = Just "djvu"
52+extensionFromMimeType "image/tiff" = Just "tiff"
53+extensionFromMimeType "image/jpeg" = Just "jpg"
54+extensionFromMimeType "application/xml" = Just "xml"
55+extensionFromMimeType "application/ogg" = Just "ogg"
46extensionFromMimeType mimetype =
56extensionFromMimeType mimetype =
47 M.lookup (T.takeWhile (/=';') mimetype) reverseMimeTypes
57 M.lookup (T.takeWhile (/=';') mimetype) reverseMimeTypes
48 -- note: we just look up the basic mime type, dropping the content-encoding etc.
58 -- note: we just look up the basic mime type, dropping the content-encoding etc.
src/Text/Pandoc/MediaBag.hs+45−14
@@ -1,4 +1,5 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2+{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE DeriveDataTypeable #-}
3{-# LANGUAGE DeriveDataTypeable #-}
3{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4{- |
5{- |
@@ -14,6 +15,7 @@ Definition of a MediaBag object to hold binary resources, and an
14interface for interacting with it.
15interface for interacting with it.
15-}
16-}
16module Text.Pandoc.MediaBag (
17module Text.Pandoc.MediaBag (
18+ MediaItem(..),
17 MediaBag,
19 MediaBag,
18 deleteMedia,
20 deleteMedia,
19 lookupMedia,
21 lookupMedia,
@@ -24,29 +26,43 @@ module Text.Pandoc.MediaBag (
24import qualified Data.ByteString.Lazy as BL
26import qualified Data.ByteString.Lazy as BL
25import Data.Data (Data)
27import Data.Data (Data)
26import qualified Data.Map as M
28import qualified Data.Map as M
27−import Data.Maybe (fromMaybe)
29+import Data.Maybe (fromMaybe, isNothing)
28import Data.Typeable (Typeable)
30import Data.Typeable (Typeable)
29import System.FilePath
31import System.FilePath
30−import qualified System.FilePath.Posix as Posix
31−import Text.Pandoc.MIME (MimeType, getMimeTypeDef)
32+import Text.Pandoc.MIME (MimeType, getMimeTypeDef, extensionFromMimeType)
33+import Data.Text (Text)
34+import qualified Data.Text as T
35+import Data.Digest.Pure.SHA (sha1, showDigest)
36+import Network.URI (URI (..), parseURI)
37+
38+data MediaItem =
39+ MediaItem
40+ { mediaMimeType :: MimeType
41+ , mediaPath :: FilePath
42+ , mediaContents :: BL.ByteString
43+ } deriving (Eq, Ord, Show, Data, Typeable)
32
44
33-- | A container for a collection of binary resources, with names and
45-- | A container for a collection of binary resources, with names and
34-- mime types. Note that a 'MediaBag' is a Monoid, so 'mempty'
46-- mime types. Note that a 'MediaBag' is a Monoid, so 'mempty'
35-- can be used for an empty 'MediaBag', and '<>' can be used to append
47-- can be used for an empty 'MediaBag', and '<>' can be used to append
36-- two 'MediaBag's.
48-- two 'MediaBag's.
37−newtype MediaBag = MediaBag (M.Map [FilePath] (MimeType, BL.ByteString))
49+newtype MediaBag = MediaBag (M.Map Text MediaItem)
38 deriving (Semigroup, Monoid, Data, Typeable)
50 deriving (Semigroup, Monoid, Data, Typeable)
39
51
40instance Show MediaBag where
52instance Show MediaBag where
41 show bag = "MediaBag " ++ show (mediaDirectory bag)
53 show bag = "MediaBag " ++ show (mediaDirectory bag)
42
54
55+-- | We represent paths with /, in normalized form.
56+canonicalize :: FilePath -> Text
57+canonicalize = T.replace "\\" "/" . T.pack . normalise
58+
43-- | Delete a media item from a 'MediaBag', or do nothing if no item corresponds
59-- | Delete a media item from a 'MediaBag', or do nothing if no item corresponds
44-- to the given path.
60-- to the given path.
45deleteMedia :: FilePath -- ^ relative path and canonical name of resource
61deleteMedia :: FilePath -- ^ relative path and canonical name of resource
46 -> MediaBag
62 -> MediaBag
47 -> MediaBag
63 -> MediaBag
48deleteMedia fp (MediaBag mediamap) =
64deleteMedia fp (MediaBag mediamap) =
49− MediaBag $ M.delete (splitDirectories fp) mediamap
65+ MediaBag $ M.delete (canonicalize fp) mediamap
50
66
51-- | Insert a media item into a 'MediaBag', replacing any existing
67-- | Insert a media item into a 'MediaBag', replacing any existing
52-- value with the same name.
68-- value with the same name.
@@ -56,26 +72,41 @@ insertMedia :: FilePath -- ^ relative path and canonical name of resource
56 -> MediaBag
72 -> MediaBag
57 -> MediaBag
73 -> MediaBag
58insertMedia fp mbMime contents (MediaBag mediamap) =
74insertMedia fp mbMime contents (MediaBag mediamap) =
59− MediaBag (M.insert (splitDirectories fp) (mime, contents) mediamap)
75+ MediaBag (M.insert fp' mediaItem mediamap)
60− where mime = fromMaybe fallback mbMime
76+ where mediaItem = MediaItem{ mediaPath = newpath
77+ , mediaContents = contents
78+ , mediaMimeType = mt }
79+ fp' = canonicalize fp
80+ uri = parseURI fp
81+ newpath = if isRelative fp
82+ && isNothing uri
83+ && ".." `notElem` splitPath fp
84+ then T.unpack fp'
85+ else showDigest (sha1 contents) <> "." <> ext
61 fallback = case takeExtension fp of
86 fallback = case takeExtension fp of
62 ".gz" -> getMimeTypeDef $ dropExtension fp
87 ".gz" -> getMimeTypeDef $ dropExtension fp
63 _ -> getMimeTypeDef fp
88 _ -> getMimeTypeDef fp
89+ mt = fromMaybe fallback mbMime
90+ path = maybe fp uriPath uri
91+ ext = case takeExtension path of
92+ '.':e -> e
93+ _ -> maybe "" T.unpack $ extensionFromMimeType mt
94+
64
95
65-- | Lookup a media item in a 'MediaBag', returning mime type and contents.
96-- | Lookup a media item in a 'MediaBag', returning mime type and contents.
66lookupMedia :: FilePath
97lookupMedia :: FilePath
67 -> MediaBag
98 -> MediaBag
68− -> Maybe (MimeType, BL.ByteString)
99+ -> Maybe MediaItem
69−lookupMedia fp (MediaBag mediamap) = M.lookup (splitDirectories fp) mediamap
100+lookupMedia fp (MediaBag mediamap) = M.lookup (canonicalize fp) mediamap
70
101
71-- | Get a list of the file paths stored in a 'MediaBag', with
102-- | Get a list of the file paths stored in a 'MediaBag', with
72-- their corresponding mime types and the lengths in bytes of the contents.
103-- their corresponding mime types and the lengths in bytes of the contents.
73mediaDirectory :: MediaBag -> [(FilePath, MimeType, Int)]
104mediaDirectory :: MediaBag -> [(FilePath, MimeType, Int)]
74−mediaDirectory (MediaBag mediamap) =
105+mediaDirectory mediabag =
75− M.foldrWithKey (\fp (mime,contents) ->
76− ((Posix.joinPath fp, mime, fromIntegral $ BL.length contents):)) [] mediamap
106+ map (\(fp, mt, bs) -> (fp, mt, fromIntegral (BL.length bs)))
107+ (mediaItems mediabag)
77
108
78mediaItems :: MediaBag -> [(FilePath, MimeType, BL.ByteString)]
109mediaItems :: MediaBag -> [(FilePath, MimeType, BL.ByteString)]
79mediaItems (MediaBag mediamap) =
110mediaItems (MediaBag mediamap) =
80− M.foldrWithKey (\fp (mime,contents) ->
111+ map (\item -> (mediaPath item, mediaMimeType item, mediaContents item))
81− ((Posix.joinPath fp, mime, contents):)) [] mediamap
112+ (M.elems mediamap)
src/Text/Pandoc/Options.hs+17−17
@@ -315,6 +315,23 @@ defaultMathJaxURL = "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.j
315defaultKaTeXURL :: Text
315defaultKaTeXURL :: Text
316defaultKaTeXURL = "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.11.1/"
316defaultKaTeXURL = "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.11.1/"
317
317
318+-- Update documentation in doc/filters.md if this is changed.
319+$(deriveJSON defaultOptions{ constructorTagModifier =
320+ camelCaseStrToHyphenated
321+ } ''TrackChanges)
322+
323+$(deriveJSON defaultOptions{ constructorTagModifier =
324+ camelCaseStrToHyphenated
325+ } ''WrapOption)
326+
327+$(deriveJSON defaultOptions{ constructorTagModifier =
328+ camelCaseStrToHyphenated . drop 8
329+ } ''TopLevelDivision)
330+
331+$(deriveJSON defaultOptions{ constructorTagModifier =
332+ camelCaseStrToHyphenated
333+ } ''ReferenceLocation)
334+
318-- Update documentation in doc/filters.md if this is changed.
335-- Update documentation in doc/filters.md if this is changed.
319$(deriveJSON defaultOptions ''ReaderOptions)
336$(deriveJSON defaultOptions ''ReaderOptions)
320
337
@@ -338,20 +355,3 @@ $(deriveJSON defaultOptions{ constructorTagModifier =
338 } ''ObfuscationMethod)
355 } ''ObfuscationMethod)
339
356
340$(deriveJSON defaultOptions ''HTMLSlideVariant)
357$(deriveJSON defaultOptions ''HTMLSlideVariant)
341−
342−-- Update documentation in doc/filters.md if this is changed.
343−$(deriveJSON defaultOptions{ constructorTagModifier =
344− camelCaseStrToHyphenated
345− } ''TrackChanges)
346−
347−$(deriveJSON defaultOptions{ constructorTagModifier =
348− camelCaseStrToHyphenated
349− } ''WrapOption)
350−
351−$(deriveJSON defaultOptions{ constructorTagModifier =
352− camelCaseStrToHyphenated . drop 8
353− } ''TopLevelDivision)
354−
355−$(deriveJSON defaultOptions{ constructorTagModifier =
356− camelCaseStrToHyphenated
357− } ''ReferenceLocation)
src/Text/Pandoc/PDF.hs+16−3
@@ -202,7 +202,7 @@ convertImage opts tmpdir fname = do
202 Just "image/svg+xml" -> E.catch (do
202 Just "image/svg+xml" -> E.catch (do
203 (exit, _) <- pipeProcess Nothing "rsvg-convert"
203 (exit, _) <- pipeProcess Nothing "rsvg-convert"
204 ["-f","pdf","-a","--dpi-x",dpi,"--dpi-y",dpi,
204 ["-f","pdf","-a","--dpi-x",dpi,"--dpi-y",dpi,
205− "-o",pdfOut,fname] BL.empty
205+ "-o",pdfOut,svgIn] BL.empty
206 if exit == ExitSuccess
206 if exit == ExitSuccess
207 then return $ Right pdfOut
207 then return $ Right pdfOut
208 else return $ Left "conversion from SVG failed")
208 else return $ Left "conversion from SVG failed")
@@ -217,6 +217,7 @@ convertImage opts tmpdir fname = do
217 where
217 where
218 pngOut = replaceDirectory (replaceExtension fname ".png") tmpdir
218 pngOut = replaceDirectory (replaceExtension fname ".png") tmpdir
219 pdfOut = replaceDirectory (replaceExtension fname ".pdf") tmpdir
219 pdfOut = replaceDirectory (replaceExtension fname ".pdf") tmpdir
220+ svgIn = tmpdir </> fname
220 mime = getMimeType fname
221 mime = getMimeType fname
221 doNothing = return (Right fname)
222 doNothing = return (Right fname)
222
223
@@ -506,8 +507,20 @@ showVerboseInfo mbTmpDir program programArgs env source = do
506 UTF8.hPutStrLn stderr $
507 UTF8.hPutStrLn stderr $
507 T.pack program <> " " <> T.pack (unwords (map show programArgs))
508 T.pack program <> " " <> T.pack (unwords (map show programArgs))
508 UTF8.hPutStr stderr "\n"
509 UTF8.hPutStr stderr "\n"
509− UTF8.hPutStrLn stderr "[makePDF] Environment:"
510+ UTF8.hPutStrLn stderr "[makePDF] Relevant environment variables:"
511+ -- we filter out irrelevant stuff to avoid leaking passwords and keys!
512+ let isRelevant ("PATH",_) = True
513+ isRelevant ("TMPDIR",_) = True
514+ isRelevant ("PWD",_) = True
515+ isRelevant ("LANG",_) = True
516+ isRelevant ("HOME",_) = True
517+ isRelevant ("LUA_PATH",_) = True
518+ isRelevant ("LUA_CPATH",_) = True
519+ isRelevant ("SHELL",_) = True
520+ isRelevant ("TEXINPUTS",_) = True
521+ isRelevant ("TEXMFOUTPUT",_) = True
522+ isRelevant _ = False
510− mapM_ (UTF8.hPutStrLn stderr . tshow) env
523+ mapM_ (UTF8.hPutStrLn stderr . tshow) (filter isRelevant env)
511 UTF8.hPutStr stderr "\n"
524 UTF8.hPutStr stderr "\n"
512 UTF8.hPutStrLn stderr "[makePDF] Source:"
525 UTF8.hPutStrLn stderr "[makePDF] Source:"
513 UTF8.hPutStrLn stderr source
526 UTF8.hPutStrLn stderr source
src/Text/Pandoc/Parsing.hs+360−242
@@ -5,7 +5,6 @@
5{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6{-# LANGUAGE IncoherentInstances #-}
6{-# LANGUAGE IncoherentInstances #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
8−{-# LANGUAGE ViewPatterns #-}
9{-# LANGUAGE OverloadedStrings #-}
8{-# LANGUAGE OverloadedStrings #-}
10{- |
9{- |
11 Module : Text.Pandoc.Parsing
10 Module : Text.Pandoc.Parsing
@@ -19,8 +18,7 @@
19A utility library with parsers used in pandoc readers.
18A utility library with parsers used in pandoc readers.
20-}
19-}
21
20
22−module Text.Pandoc.Parsing ( take1WhileP,
21+module Text.Pandoc.Parsing ( module Text.Pandoc.Sources,
23− takeP,
24 countChar,
22 countChar,
25 textStr,
23 textStr,
26 anyLine,
24 anyLine,
@@ -105,14 +103,14 @@ module Text.Pandoc.Parsing ( take1WhileP,
105 singleQuoteEnd,
103 singleQuoteEnd,
106 doubleQuoteStart,
104 doubleQuoteStart,
107 doubleQuoteEnd,
105 doubleQuoteEnd,
108− ellipses,
109 apostrophe,
106 apostrophe,
107+ doubleCloseQuote,
108+ ellipses,
110 dash,
109 dash,
111 nested,
110 nested,
112 citeKey,
111 citeKey,
113 Parser,
112 Parser,
114 ParserT,
113 ParserT,
115− F,
116 Future(..),
114 Future(..),
117 runF,
115 runF,
118 askF,
116 askF,
@@ -123,7 +121,6 @@ module Text.Pandoc.Parsing ( take1WhileP,
123 (<+?>),
121 (<+?>),
124 extractIdClass,
122 extractIdClass,
125 insertIncludedFile,
123 insertIncludedFile,
126− insertIncludedFileF,
127 -- * Re-exports from Text.Parsec
124 -- * Re-exports from Text.Parsec
128 Stream,
125 Stream,
129 runParser,
126 runParser,
@@ -134,22 +131,10 @@ module Text.Pandoc.Parsing ( take1WhileP,
134 getInput,
131 getInput,
135 setInput,
132 setInput,
136 unexpected,
133 unexpected,
137− char,
138− letter,
139− digit,
140− alphaNum,
141 skipMany,
134 skipMany,
142 skipMany1,
135 skipMany1,
143− spaces,
144− space,
145− anyChar,
146− satisfy,
147− newline,
148− string,
149 count,
136 count,
150 eof,
137 eof,
151− noneOf,
152− oneOf,
153 lookAhead,
138 lookAhead,
154 notFollowedBy,
139 notFollowedBy,
155 many,
140 many,
@@ -174,6 +159,8 @@ module Text.Pandoc.Parsing ( take1WhileP,
174 SourcePos,
159 SourcePos,
175 getPosition,
160 getPosition,
176 setPosition,
161 setPosition,
162+ sourceName,
163+ setSourceName,
177 sourceColumn,
164 sourceColumn,
178 sourceLine,
165 sourceLine,
179 setSourceColumn,
166 setSourceColumn,
@@ -189,48 +176,141 @@ module Text.Pandoc.Parsing ( take1WhileP,
189where
176where
190
177
191import Control.Monad.Identity
178import Control.Monad.Identity
179+ ( guard,
180+ join,
181+ unless,
182+ when,
183+ void,
184+ liftM2,
185+ liftM,
186+ Identity(..),
187+ MonadPlus(mzero) )
192import Control.Monad.Reader
188import Control.Monad.Reader
189+ ( asks, runReader, MonadReader(ask), Reader, ReaderT(ReaderT) )
193import Data.Char (chr, isAlphaNum, isAscii, isAsciiUpper, isAsciiLower,
190import Data.Char (chr, isAlphaNum, isAscii, isAsciiUpper, isAsciiLower,
194− isPunctuation, isSpace, ord, toLower, toUpper)
191+ isSpace, ord, toLower, toUpper)
195−import Data.Default
192+import Data.Default ( Default(..) )
196import Data.Functor (($>))
193import Data.Functor (($>))
197import Data.List (intercalate, transpose)
194import Data.List (intercalate, transpose)
198import qualified Data.Map as M
195import qualified Data.Map as M
199−import Data.Maybe (mapMaybe, fromMaybe)
196+import Data.Maybe (fromMaybe)
200import qualified Data.Set as Set
197import qualified Data.Set as Set
201−import Data.String
202import Data.Text (Text)
198import Data.Text (Text)
203import qualified Data.Text as T
199import qualified Data.Text as T
204import Text.HTML.TagSoup.Entity (lookupEntity)
200import Text.HTML.TagSoup.Entity (lookupEntity)
205−import Text.Pandoc.Asciify (toAsciiChar)
201+import Text.Pandoc.Asciify (toAsciiText)
206import Text.Pandoc.Builder (Blocks, HasMeta (..), Inlines, trimInlines)
202import Text.Pandoc.Builder (Blocks, HasMeta (..), Inlines, trimInlines)
207import qualified Text.Pandoc.Builder as B
203import qualified Text.Pandoc.Builder as B
208import Text.Pandoc.Class.PandocMonad (PandocMonad, readFileFromDirs, report)
204import Text.Pandoc.Class.PandocMonad (PandocMonad, readFileFromDirs, report)
209import Text.Pandoc.Definition
205import Text.Pandoc.Definition
206+ ( Target,
207+ nullMeta,
208+ nullAttr,
209+ Meta,
210+ ColWidth(ColWidthDefault, ColWidth),
211+ TableFoot(TableFoot),
212+ TableBody(TableBody),
213+ Attr,
214+ TableHead(TableHead),
215+ Row(..),
216+ Alignment(..),
217+ Inline(Str),
218+ ListNumberDelim(..),
219+ ListAttributes,
220+ ListNumberStyle(..) )
210import Text.Pandoc.Logging
221import Text.Pandoc.Logging
222+ ( LogMessage(CouldNotLoadIncludeFile, DuplicateIdentifier) )
211import Text.Pandoc.Options
223import Text.Pandoc.Options
224+ ( extensionEnabled,
225+ Extension(Ext_old_dashes, Ext_tex_math_dollars,
226+ Ext_tex_math_single_backslash, Ext_tex_math_double_backslash,
227+ Ext_auto_identifiers, Ext_ascii_identifiers, Ext_smart),
228+ ReaderOptions(readerTabStop, readerColumns, readerExtensions) )
212import Text.Pandoc.Readers.LaTeX.Types (Macro)
229import Text.Pandoc.Readers.LaTeX.Types (Macro)
213import Text.Pandoc.Shared
230import Text.Pandoc.Shared
231+ ( uniqueIdent,
232+ tshow,
233+ mapLeft,
234+ compactify,
235+ trim,
236+ trimr,
237+ splitTextByIndices,
238+ safeRead,
239+ trimMath,
240+ schemes,
241+ escapeURI )
242+import Text.Pandoc.Sources
214import qualified Text.Pandoc.UTF8 as UTF8 (putStrLn)
243import qualified Text.Pandoc.UTF8 as UTF8 (putStrLn)
215import Text.Pandoc.XML (fromEntities)
244import Text.Pandoc.XML (fromEntities)
216−import Text.Parsec hiding (token)
245+import Text.Parsec
246+ ( between,
247+ setSourceName,
248+ Parsec,
249+ Column,
250+ Line,
251+ incSourceLine,
252+ incSourceColumn,
253+ setSourceLine,
254+ setSourceColumn,
255+ sourceLine,
256+ sourceColumn,
257+ sourceName,
258+ setSourceName,
259+ setPosition,
260+ getPosition,
261+ updateState,
262+ setState,
263+ getState,
264+ optionMaybe,
265+ optional,
266+ option,
267+ endBy1,
268+ endBy,
269+ sepEndBy1,
270+ sepEndBy,
271+ sepBy1,
272+ sepBy,
273+ try,
274+ choice,
275+ (<?>),
276+ (<|>),
277+ manyTill,
278+ many1,
279+ many,
280+ notFollowedBy,
281+ lookAhead,
282+ eof,
283+ count,
284+ skipMany1,
285+ skipMany,
286+ unexpected,
287+ setInput,
288+ getInput,
289+ anyToken,
290+ tokenPrim,
291+ parse,
292+ runParserT,
293+ runParser,
294+ ParseError,
295+ ParsecT,
296+ SourcePos,
297+ Stream(..) )
217−import Text.Parsec.Pos (initialPos, newPos, updatePosString)
298+import Text.Parsec.Pos (initialPos, newPos)
218−
219−import Control.Monad.Except
299+import Control.Monad.Except ( MonadError(throwError) )
220import Text.Pandoc.Error
300import Text.Pandoc.Error
301+ ( PandocError(PandocParseError, PandocParsecError) )
221
302
222type Parser t s = Parsec t s
303type Parser t s = Parsec t s
223
304
224type ParserT = ParsecT
305type ParserT = ParsecT
225
306
307+
226-- | Reader monad wrapping the parser state. This is used to possibly delay
308-- | Reader monad wrapping the parser state. This is used to possibly delay
227-- evaluation until all relevant information has been parsed and made available
309-- evaluation until all relevant information has been parsed and made available
228-- in the parser state.
310-- in the parser state.
229newtype Future s a = Future { runDelayed :: Reader s a }
311newtype Future s a = Future { runDelayed :: Reader s a }
230 deriving (Monad, Applicative, Functor)
312 deriving (Monad, Applicative, Functor)
231
313
232−type F = Future ParserState
233−
234runF :: Future s a -> s -> a
314runF :: Future s a -> s -> a
235runF = runReader . runDelayed
315runF = runReader . runDelayed
236
316
@@ -253,70 +333,48 @@ instance (Semigroup a, Monoid a) => Monoid (Future s a) where
253 mappend = (<>)
333 mappend = (<>)
254
334
255-- | Like @count@, but packs its result
335-- | Like @count@, but packs its result
256−countChar :: (Stream s m Char, Monad m)
336+countChar :: (Stream s m Char, UpdateSourcePos s Char, Monad m)
257 => Int
337 => Int
258 -> ParsecT s st m Char
338 -> ParsecT s st m Char
259 -> ParsecT s st m Text
339 -> ParsecT s st m Text
260countChar n = fmap T.pack . count n
340countChar n = fmap T.pack . count n
261
341
262-- | Like @string@, but uses @Text@.
342-- | Like @string@, but uses @Text@.
343+textStr :: (Stream s m Char, UpdateSourcePos s Char)
263−textStr :: Stream s m Char => Text -> ParsecT s u m Text
344+ => Text -> ParsecT s u m Text
264textStr t = string (T.unpack t) $> t
345textStr t = string (T.unpack t) $> t
265
346
266−-- | Parse characters while a predicate is true.
347+
267−take1WhileP :: Monad m
268− => (Char -> Bool)
269− -> ParserT Text st m Text
270−take1WhileP f = do
271− -- needed to persuade parsec that this won't match an empty string:
272− c <- satisfy f
273− inp <- getInput
274− pos <- getPosition
275− let (t, rest) = T.span f inp
276− setInput rest
277− setPosition $
278− if f '\t' || f '\n'
279− then updatePosString pos $ T.unpack t
280− else incSourceColumn pos (T.length t)
281− return $ T.singleton c <> t
282−
283−-- Parse n characters of input (or the rest of the input if
284−-- there aren't n characters).
285−takeP :: Monad m => Int -> ParserT Text st m Text
286−takeP n = do
287− guard (n > 0)
288− -- faster than 'count n anyChar'
289− inp <- getInput
290− pos <- getPosition
291− let (xs, rest) = T.splitAt n inp
292− -- needed to persuade parsec that this won't match an empty string:
293− anyChar
294− setInput rest
295− setPosition $ updatePosString pos $ T.unpack xs
296− return xs
297−
298−-- | Parse any line of text
348+-- | Parse any line of text, returning the contents without the
349+-- final newline.
299−anyLine :: Monad m => ParserT Text st m Text
350+anyLine :: Monad m => ParserT Sources st m Text
300anyLine = do
351anyLine = do
301 -- This is much faster than:
352 -- This is much faster than:
302 -- manyTill anyChar newline
353 -- manyTill anyChar newline
303 inp <- getInput
354 inp <- getInput
304− pos <- getPosition
355+ case inp of
356+ Sources [] -> mzero
357+ Sources ((fp,t):inps) ->
358+ -- we assume that lines don't span different input files
305− case T.break (=='\n') inp of
359+ case T.break (=='\n') t of
306− (this, T.uncons -> Just ('\n', rest)) -> do
360+ (this, rest)
361+ | T.null rest
362+ , not (null inps) ->
363+ -- line may span different input files, so do it
364+ -- character by character
365+ T.pack <$> manyTill anyChar newline
366+ | otherwise -> do -- either end of inputs or newline in rest
367+ setInput $ Sources ((fp, rest):inps)
307− -- needed to persuade parsec that this won't match an empty string:
368+ char '\n' -- needed so parsec knows we won't match empty string
308− anyChar
369+ -- and so source pos is updated
309− setInput rest
310− setPosition $ incSourceLine (setSourceColumn pos 1) 1
311− return this
370+ return this
312− _ -> mzero
313
371
314-- | Parse any line, include the final newline in the output
372-- | Parse any line, include the final newline in the output
315−anyLineNewline :: Monad m => ParserT Text st m Text
373+anyLineNewline :: Monad m => ParserT Sources st m Text
316anyLineNewline = (<> "\n") <$> anyLine
374anyLineNewline = (<> "\n") <$> anyLine
317
375
318-- | Parse indent by specified number of spaces (or equiv. tabs)
376-- | Parse indent by specified number of spaces (or equiv. tabs)
319−indentWith :: Stream s m Char
377+indentWith :: (Stream s m Char, UpdateSourcePos s Char)
320 => HasReaderOptions st
378 => HasReaderOptions st
321 => Int -> ParserT s st m Text
379 => Int -> ParserT s st m Text
322indentWith num = do
380indentWith num = do
@@ -401,11 +459,13 @@ notFollowedBy' p = try $ join $ do a <- try p
401 return (return ())
459 return (return ())
402-- (This version due to Andrew Pimlott on the Haskell mailing list.)
460-- (This version due to Andrew Pimlott on the Haskell mailing list.)
403
461
462+oneOfStrings' :: (Stream s m Char, UpdateSourcePos s Char)
404−oneOfStrings' :: Stream s m Char => (Char -> Char -> Bool) -> [Text] -> ParserT s st m Text
463+ => (Char -> Char -> Bool) -> [Text] -> ParserT s st m Text
405oneOfStrings' f = fmap T.pack . oneOfStrings'' f . fmap T.unpack
464oneOfStrings' f = fmap T.pack . oneOfStrings'' f . fmap T.unpack
406
465
407-- TODO: This should be re-implemented in a Text-aware way
466-- TODO: This should be re-implemented in a Text-aware way
467+oneOfStrings'' :: (Stream s m Char, UpdateSourcePos s Char)
408−oneOfStrings'' :: Stream s m Char => (Char -> Char -> Bool) -> [String] -> ParserT s st m String
468+ => (Char -> Char -> Bool) -> [String] -> ParserT s st m String
409oneOfStrings'' _ [] = Prelude.fail "no strings"
469oneOfStrings'' _ [] = Prelude.fail "no strings"
410oneOfStrings'' matches strs = try $ do
470oneOfStrings'' matches strs = try $ do
411 c <- anyChar
471 c <- anyChar
@@ -420,14 +480,16 @@ oneOfStrings'' matches strs = try $ do
420-- | Parses one of a list of strings. If the list contains
480-- | Parses one of a list of strings. If the list contains
421-- two strings one of which is a prefix of the other, the longer
481-- two strings one of which is a prefix of the other, the longer
422-- string will be matched if possible.
482-- string will be matched if possible.
483+oneOfStrings :: (Stream s m Char, UpdateSourcePos s Char)
423−oneOfStrings :: Stream s m Char => [Text] -> ParserT s st m Text
484+ => [Text] -> ParserT s st m Text
424oneOfStrings = oneOfStrings' (==)
485oneOfStrings = oneOfStrings' (==)
425
486
426-- | Parses one of a list of strings (tried in order), case insensitive.
487-- | Parses one of a list of strings (tried in order), case insensitive.
427
488
428-- TODO: This will not be accurate with general Unicode (neither
489-- TODO: This will not be accurate with general Unicode (neither
429-- Text.toLower nor Text.toCaseFold can be implemented with a map)
490-- Text.toLower nor Text.toCaseFold can be implemented with a map)
491+oneOfStringsCI :: (Stream s m Char, UpdateSourcePos s Char)
430−oneOfStringsCI :: Stream s m Char => [Text] -> ParserT s st m Text
492+ => [Text] -> ParserT s st m Text
431oneOfStringsCI = oneOfStrings' ciMatch
493oneOfStringsCI = oneOfStrings' ciMatch
432 where ciMatch x y = toLower' x == toLower' y
494 where ciMatch x y = toLower' x == toLower' y
433 -- this optimizes toLower by checking common ASCII case
495 -- this optimizes toLower by checking common ASCII case
@@ -438,11 +500,13 @@ oneOfStringsCI = oneOfStrings' ciMatch
438 | otherwise = toLower c
500 | otherwise = toLower c
439
501
440-- | Parses a space or tab.
502-- | Parses a space or tab.
503+spaceChar :: (Stream s m Char, UpdateSourcePos s Char)
441−spaceChar :: Stream s m Char => ParserT s st m Char
504+ => ParserT s st m Char
442spaceChar = satisfy $ \c -> c == ' ' || c == '\t'
505spaceChar = satisfy $ \c -> c == ' ' || c == '\t'
443
506
444-- | Parses a nonspace, nonnewline character.
507-- | Parses a nonspace, nonnewline character.
445−nonspaceChar :: Stream s m Char => ParserT s st m Char
508+nonspaceChar :: (Stream s m Char, UpdateSourcePos s Char)
509+ => ParserT s st m Char
446nonspaceChar = satisfy (not . isSpaceChar)
510nonspaceChar = satisfy (not . isSpaceChar)
447
511
448isSpaceChar :: Char -> Bool
512isSpaceChar :: Char -> Bool
@@ -453,21 +517,24 @@ isSpaceChar '\r' = True
453isSpaceChar _ = False
517isSpaceChar _ = False
454
518
455-- | Skips zero or more spaces or tabs.
519-- | Skips zero or more spaces or tabs.
456−skipSpaces :: Stream s m Char => ParserT s st m ()
520+skipSpaces :: (Stream s m Char, UpdateSourcePos s Char)
521+ => ParserT s st m ()
457skipSpaces = skipMany spaceChar
522skipSpaces = skipMany spaceChar
458
523
459-- | Skips zero or more spaces or tabs, then reads a newline.
524-- | Skips zero or more spaces or tabs, then reads a newline.
525+blankline :: (Stream s m Char, UpdateSourcePos s Char)
460−blankline :: Stream s m Char => ParserT s st m Char
526+ => ParserT s st m Char
461blankline = try $ skipSpaces >> newline
527blankline = try $ skipSpaces >> newline
462
528
463-- | Parses one or more blank lines and returns a string of newlines.
529-- | Parses one or more blank lines and returns a string of newlines.
530+blanklines :: (Stream s m Char, UpdateSourcePos s Char)
464−blanklines :: Stream s m Char => ParserT s st m Text
531+ => ParserT s st m Text
465blanklines = T.pack <$> many1 blankline
532blanklines = T.pack <$> many1 blankline
466
533
467-- | Gobble n spaces; if tabs are encountered, expand them
534-- | Gobble n spaces; if tabs are encountered, expand them
468-- and gobble some or all of their spaces, leaving the rest.
535-- and gobble some or all of their spaces, leaving the rest.
469gobbleSpaces :: (HasReaderOptions st, Monad m)
536gobbleSpaces :: (HasReaderOptions st, Monad m)
470− => Int -> ParserT Text st m ()
537+ => Int -> ParserT Sources st m ()
471gobbleSpaces 0 = return ()
538gobbleSpaces 0 = return ()
472gobbleSpaces n
539gobbleSpaces n
473 | n < 0 = error "gobbleSpaces called with negative number"
540 | n < 0 = error "gobbleSpaces called with negative number"
@@ -475,18 +542,26 @@ gobbleSpaces n
475 char ' ' <|> eatOneSpaceOfTab
542 char ' ' <|> eatOneSpaceOfTab
476 gobbleSpaces (n - 1)
543 gobbleSpaces (n - 1)
477
544
478−eatOneSpaceOfTab :: (HasReaderOptions st, Monad m) => ParserT Text st m Char
545+eatOneSpaceOfTab :: (HasReaderOptions st, Monad m) => ParserT Sources st m Char
479eatOneSpaceOfTab = do
546eatOneSpaceOfTab = do
480− char '\t'
547+ lookAhead (char '\t')
548+ pos <- getPosition
481 tabstop <- getOption readerTabStop
549 tabstop <- getOption readerTabStop
550+ -- replace the tab on the input stream with spaces
551+ let numSpaces = tabstop - ((sourceColumn pos - 1) `mod` tabstop)
482 inp <- getInput
552 inp <- getInput
483− setInput $ T.replicate (tabstop - 1) " " <> inp
553+ setInput $
484− return ' '
554+ case inp of
555+ Sources [] -> error "eatOneSpaceOfTab - empty Sources list"
556+ Sources ((fp,t):rest) ->
557+ -- drop the tab and add spaces
558+ Sources ((fp, T.replicate numSpaces " " <> T.drop 1 t):rest)
559+ char ' '
485
560
486-- | Gobble up to n spaces; if tabs are encountered, expand them
561-- | Gobble up to n spaces; if tabs are encountered, expand them
487-- and gobble some or all of their spaces, leaving the rest.
562-- and gobble some or all of their spaces, leaving the rest.
488gobbleAtMostSpaces :: (HasReaderOptions st, Monad m)
563gobbleAtMostSpaces :: (HasReaderOptions st, Monad m)
489− => Int -> ParserT Text st m Int
564+ => Int -> ParserT Sources st m Int
490gobbleAtMostSpaces 0 = return 0
565gobbleAtMostSpaces 0 = return 0
491gobbleAtMostSpaces n
566gobbleAtMostSpaces n
492 | n < 0 = error "gobbleAtMostSpaces called with negative number"
567 | n < 0 = error "gobbleAtMostSpaces called with negative number"
@@ -495,7 +570,8 @@ gobbleAtMostSpaces n
495 (+ 1) <$> gobbleAtMostSpaces (n - 1)
570 (+ 1) <$> gobbleAtMostSpaces (n - 1)
496
571
497-- | Parses material enclosed between start and end parsers.
572-- | Parses material enclosed between start and end parsers.
573+enclosed :: (Show end, Stream s m Char, UpdateSourcePos s Char)
498−enclosed :: (Show end, Stream s m Char) => ParserT s st m t -- ^ start parser
574+ => ParserT s st m t -- ^ start parser
499 -> ParserT s st m end -- ^ end parser
575 -> ParserT s st m end -- ^ end parser
500 -> ParserT s st m a -- ^ content parser (to be used repeatedly)
576 -> ParserT s st m a -- ^ content parser (to be used repeatedly)
501 -> ParserT s st m [a]
577 -> ParserT s st m [a]
@@ -503,39 +579,41 @@ enclosed start end parser = try $
503 start >> notFollowedBy space >> many1Till parser end
579 start >> notFollowedBy space >> many1Till parser end
504
580
505-- | Parse string, case insensitive.
581-- | Parse string, case insensitive.
582+stringAnyCase :: (Stream s m Char, UpdateSourcePos s Char)
506−stringAnyCase :: Stream s m Char => Text -> ParserT s st m Text
583+ => Text -> ParserT s st m Text
507stringAnyCase = fmap T.pack . stringAnyCase' . T.unpack
584stringAnyCase = fmap T.pack . stringAnyCase' . T.unpack
508
585
586+stringAnyCase' :: (Stream s m Char, UpdateSourcePos s Char)
509−stringAnyCase' :: Stream s m Char => String -> ParserT s st m String
587+ => String -> ParserT s st m String
510stringAnyCase' [] = string ""
588stringAnyCase' [] = string ""
511stringAnyCase' (x:xs) = do
589stringAnyCase' (x:xs) = do
512 firstChar <- char (toUpper x) <|> char (toLower x)
590 firstChar <- char (toUpper x) <|> char (toLower x)
513 rest <- stringAnyCase' xs
591 rest <- stringAnyCase' xs
514 return (firstChar:rest)
592 return (firstChar:rest)
515
593
594+-- TODO rewrite by just adding to Sources stream?
516-- | Parse contents of 'str' using 'parser' and return result.
595-- | Parse contents of 'str' using 'parser' and return result.
517−parseFromString :: (Stream s m Char, IsString s)
596+parseFromString :: Monad m
518− => ParserT s st m r
597+ => ParserT Sources st m r
519 -> Text
598 -> Text
520− -> ParserT s st m r
599+ -> ParserT Sources st m r
521parseFromString parser str = do
600parseFromString parser str = do
522 oldPos <- getPosition
601 oldPos <- getPosition
523 setPosition $ initialPos "chunk"
602 setPosition $ initialPos "chunk"
524 oldInput <- getInput
603 oldInput <- getInput
525− setInput $ fromString $ T.unpack str
604+ setInput $ toSources str
526 result <- parser
605 result <- parser
527 spaces
606 spaces
528− eof
529 setInput oldInput
607 setInput oldInput
530 setPosition oldPos
608 setPosition oldPos
531 return result
609 return result
532
610
533-- | Like 'parseFromString' but specialized for 'ParserState'.
611-- | Like 'parseFromString' but specialized for 'ParserState'.
534-- This resets 'stateLastStrPos', which is almost always what we want.
612-- This resets 'stateLastStrPos', which is almost always what we want.
535−parseFromString' :: (Stream s m Char, IsString s, HasLastStrPosition u)
613+parseFromString' :: (Monad m, HasLastStrPosition u)
536− => ParserT s u m a
614+ => ParserT Sources u m a
537 -> Text
615 -> Text
538− -> ParserT s u m a
616+ -> ParserT Sources u m a
539parseFromString' parser str = do
617parseFromString' parser str = do
540 oldLastStrPos <- getLastStrPos <$> getState
618 oldLastStrPos <- getLastStrPos <$> getState
541 updateState $ setLastStrPos Nothing
619 updateState $ setLastStrPos Nothing
@@ -544,7 +622,7 @@ parseFromString' parser str = do
544 return res
622 return res
545
623
546-- | Parse raw line block up to and including blank lines.
624-- | Parse raw line block up to and including blank lines.
547−lineClump :: Monad m => ParserT Text st m Text
625+lineClump :: Monad m => ParserT Sources st m Text
548lineClump = blanklines
626lineClump = blanklines
549 <|> (T.unlines <$> many1 (notFollowedBy blankline >> anyLine))
627 <|> (T.unlines <$> many1 (notFollowedBy blankline >> anyLine))
550
628
@@ -553,7 +631,7 @@ lineClump = blanklines
553-- pairs of open and close, which must be different. For example,
631-- pairs of open and close, which must be different. For example,
554-- @charsInBalanced '(' ')' anyChar@ will parse "(hello (there))"
632-- @charsInBalanced '(' ')' anyChar@ will parse "(hello (there))"
555-- and return "hello (there)".
633-- and return "hello (there)".
556−charsInBalanced :: Stream s m Char => Char -> Char -> ParserT s st m Char
634+charsInBalanced :: (Stream s m Char, UpdateSourcePos s Char) => Char -> Char -> ParserT s st m Char
557 -> ParserT s st m Text
635 -> ParserT s st m Text
558charsInBalanced open close parser = try $ do
636charsInBalanced open close parser = try $ do
559 char open
637 char open
@@ -572,7 +650,7 @@ charsInBalanced open close parser = try $ do
572-- Auxiliary functions for romanNumeral:
650-- Auxiliary functions for romanNumeral:
573
651
574-- | Parses a roman numeral (uppercase or lowercase), returns number.
652-- | Parses a roman numeral (uppercase or lowercase), returns number.
575−romanNumeral :: Stream s m Char => Bool -- ^ Uppercase if true
653+romanNumeral :: (Stream s m Char, UpdateSourcePos s Char) => Bool -- ^ Uppercase if true
576 -> ParserT s st m Int
654 -> ParserT s st m Int
577romanNumeral upperCase = do
655romanNumeral upperCase = do
578 let rchar uc = char $ if upperCase then uc else toLower uc
656 let rchar uc = char $ if upperCase then uc else toLower uc
@@ -608,20 +686,19 @@ romanNumeral upperCase = do
608
686
609-- | Parses an email address; returns original and corresponding
687-- | Parses an email address; returns original and corresponding
610-- escaped mailto: URI.
688-- escaped mailto: URI.
611−emailAddress :: Stream s m Char => ParserT s st m (Text, Text)
689+emailAddress :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (Text, Text)
612emailAddress = try $ toResult <$> mailbox <*> (char '@' *> domain)
690emailAddress = try $ toResult <$> mailbox <*> (char '@' *> domain)
613 where toResult mbox dom = let full = fromEntities $ T.pack $ mbox ++ '@':dom
691 where toResult mbox dom = let full = fromEntities $ T.pack $ mbox ++ '@':dom
614 in (full, escapeURI $ "mailto:" <> full)
692 in (full, escapeURI $ "mailto:" <> full)
615 mailbox = intercalate "." <$> (emailWord `sepBy1'` dot)
693 mailbox = intercalate "." <$> (emailWord `sepBy1'` dot)
616 domain = intercalate "." <$> (subdomain `sepBy1'` dot)
694 domain = intercalate "." <$> (subdomain `sepBy1'` dot)
617 dot = char '.'
695 dot = char '.'
618− subdomain = many1 $ alphaNum <|> innerPunct
696+ subdomain = many1 $ alphaNum <|> innerPunct (=='-')
619 -- this excludes some valid email addresses, since an
697 -- this excludes some valid email addresses, since an
620 -- email could contain e.g. '__', but gives better results
698 -- email could contain e.g. '__', but gives better results
621 -- for our purposes, when combined with markdown parsing:
699 -- for our purposes, when combined with markdown parsing:
622− innerPunct = try (satisfy (\c -> isEmailPunct c || c == '@')
700+ innerPunct f = try (satisfy f
623− <* notFollowedBy space
701+ <* notFollowedBy (satisfy (not . isAlphaNum)))
624− <* notFollowedBy (satisfy isPunctuation))
625 -- technically an email address could begin with a symbol,
702 -- technically an email address could begin with a symbol,
626 -- but allowing this creates too many problems.
703 -- but allowing this creates too many problems.
627 -- See e.g. https://github.com/jgm/pandoc/issues/2940
704 -- See e.g. https://github.com/jgm/pandoc/issues/2940
@@ -632,11 +709,11 @@ emailAddress = try $ toResult <$> mailbox <*> (char '@' *> domain)
632 isEmailPunct c = T.any (== c) "!\"#$%&'*+-/=?^_{|}~;"
709 isEmailPunct c = T.any (== c) "!\"#$%&'*+-/=?^_{|}~;"
633
710
634
711
635−uriScheme :: Stream s m Char => ParserT s st m Text
712+uriScheme :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m Text
636uriScheme = oneOfStringsCI (Set.toList schemes)
713uriScheme = oneOfStringsCI (Set.toList schemes)
637
714
638-- | Parses a URI. Returns pair of original and URI-escaped version.
715-- | Parses a URI. Returns pair of original and URI-escaped version.
639−uri :: Stream s m Char => ParserT s st m (Text, Text)
716+uri :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (Text, Text)
640uri = try $ do
717uri = try $ do
641 scheme <- uriScheme
718 scheme <- uriScheme
642 char ':'
719 char ':'
@@ -679,7 +756,7 @@ uri = try $ do
679 uriChunkBetween l r = try $ do chunk <- between (char l) (char r) uriChunk
756 uriChunkBetween l r = try $ do chunk <- between (char l) (char r) uriChunk
680 return (T.pack $ [l] ++ chunk ++ [r])
757 return (T.pack $ [l] ++ chunk ++ [r])
681
758
682−mathInlineWith :: Stream s m Char => Text -> Text -> ParserT s st m Text
759+mathInlineWith :: (Stream s m Char, UpdateSourcePos s Char) => Text -> Text -> ParserT s st m Text
683mathInlineWith op cl = try $ do
760mathInlineWith op cl = try $ do
684 textStr op
761 textStr op
685 when (op == "$") $ notFollowedBy space
762 when (op == "$") $ notFollowedBy space
@@ -700,10 +777,10 @@ mathInlineWith op cl = try $ do
700 notFollowedBy digit -- to prevent capture of $5
777 notFollowedBy digit -- to prevent capture of $5
701 return $ trimMath $ T.concat words'
778 return $ trimMath $ T.concat words'
702 where
779 where
703− inBalancedBraces :: Stream s m Char => Int -> Text -> ParserT s st m Text
780+ inBalancedBraces :: (Stream s m Char, UpdateSourcePos s Char) => Int -> Text -> ParserT s st m Text
704 inBalancedBraces n = fmap T.pack . inBalancedBraces' n . T.unpack
781 inBalancedBraces n = fmap T.pack . inBalancedBraces' n . T.unpack
705
782
706− inBalancedBraces' :: Stream s m Char => Int -> String -> ParserT s st m String
783+ inBalancedBraces' :: (Stream s m Char, UpdateSourcePos s Char) => Int -> String -> ParserT s st m String
707 inBalancedBraces' 0 "" = do
784 inBalancedBraces' 0 "" = do
708 c <- anyChar
785 c <- anyChar
709 if c == '{'
786 if c == '{'
@@ -720,13 +797,13 @@ mathInlineWith op cl = try $ do
720 '{' -> inBalancedBraces' (numOpen + 1) (c:xs)
797 '{' -> inBalancedBraces' (numOpen + 1) (c:xs)
721 _ -> inBalancedBraces' numOpen (c:xs)
798 _ -> inBalancedBraces' numOpen (c:xs)
722
799
723−mathDisplayWith :: Stream s m Char => Text -> Text -> ParserT s st m Text
800+mathDisplayWith :: (Stream s m Char, UpdateSourcePos s Char) => Text -> Text -> ParserT s st m Text
724mathDisplayWith op cl = try $ fmap T.pack $ do
801mathDisplayWith op cl = try $ fmap T.pack $ do
725 textStr op
802 textStr op
726 many1Till (satisfy (/= '\n') <|> (newline <* notFollowedBy' blankline))
803 many1Till (satisfy (/= '\n') <|> (newline <* notFollowedBy' blankline))
727 (try $ textStr cl)
804 (try $ textStr cl)
728
805
729−mathDisplay :: (HasReaderOptions st, Stream s m Char)
806+mathDisplay :: (HasReaderOptions st, Stream s m Char, UpdateSourcePos s Char)
730 => ParserT s st m Text
807 => ParserT s st m Text
731mathDisplay =
808mathDisplay =
732 (guardEnabled Ext_tex_math_dollars >> mathDisplayWith "$$" "$$")
809 (guardEnabled Ext_tex_math_dollars >> mathDisplayWith "$$" "$$")
@@ -735,7 +812,7 @@ mathDisplay =
735 <|> (guardEnabled Ext_tex_math_double_backslash >>
812 <|> (guardEnabled Ext_tex_math_double_backslash >>
736 mathDisplayWith "\\\\[" "\\\\]")
813 mathDisplayWith "\\\\[" "\\\\]")
737
814
738−mathInline :: (HasReaderOptions st , Stream s m Char)
815+mathInline :: (HasReaderOptions st, Stream s m Char, UpdateSourcePos s Char)
739 => ParserT s st m Text
816 => ParserT s st m Text
740mathInline =
817mathInline =
741 (guardEnabled Ext_tex_math_dollars >> mathInlineWith "$" "$")
818 (guardEnabled Ext_tex_math_dollars >> mathInlineWith "$" "$")
@@ -748,7 +825,7 @@ mathInline =
748-- displacement (the difference between the source column at the end
825-- displacement (the difference between the source column at the end
749-- and the source column at the beginning). Vertical displacement
826-- and the source column at the beginning). Vertical displacement
750-- (source row) is ignored.
827-- (source row) is ignored.
751−withHorizDisplacement :: Stream s m Char
828+withHorizDisplacement :: (Stream s m Char, UpdateSourcePos s Char)
752 => ParserT s st m a -- ^ Parser to apply
829 => ParserT s st m a -- ^ Parser to apply
753 -> ParserT s st m (a, Int) -- ^ (result, displacement)
830 -> ParserT s st m (a, Int) -- ^ (result, displacement)
754withHorizDisplacement parser = do
831withHorizDisplacement parser = do
@@ -760,30 +837,37 @@ withHorizDisplacement parser = do
760-- | Applies a parser and returns the raw string that was parsed,
837-- | Applies a parser and returns the raw string that was parsed,
761-- along with the value produced by the parser.
838-- along with the value produced by the parser.
762withRaw :: Monad m
839withRaw :: Monad m
763− => ParsecT Text st m a
840+ => ParsecT Sources st m a
764− -> ParsecT Text st m (a, Text)
841+ -> ParsecT Sources st m (a, Text)
765withRaw parser = do
842withRaw parser = do
766− pos1 <- getPosition
767− inp <- getInput
843+ inps1 <- getInput
768 result <- parser
844 result <- parser
769− pos2 <- getPosition
845+ inps2 <- getInput
770− let (l1,c1) = (sourceLine pos1, sourceColumn pos1)
846+ -- 'raw' is the difference between inps1 and inps2
771− let (l2,c2) = (sourceLine pos2, sourceColumn pos2)
847+ return (result, sourcesDifference inps1 inps2)
772− let inplines = take ((l2 - l1) + 1) $ T.lines inp
848+
773− let raw = case inplines of
849+sourcesDifference :: Sources -> Sources -> Text
850+sourcesDifference (Sources is1) (Sources is2) = go is1 is2
851+ where
852+ go inps1 inps2 =
853+ case (inps1, inps2) of
774− [] -> ""
854+ ([], _) -> mempty
775− [l] -> T.take (c2 - c1) l
855+ (_, []) -> mconcat $ map snd inps1
776− ls -> T.unlines (init ls) <> T.take (c2 - 1) (last ls)
856+ ((p1,t1):rest1, (p2, t2):rest2)
777− return (result, raw)
857+ | p1 == p2
858+ , t1 == t2 -> go rest1 rest2
859+ | p1 == p2
860+ , t1 /= t2 -> fromMaybe mempty $ T.stripSuffix t2 t1
861+ | otherwise -> t1 <> go rest1 inps2
778
862
779-- | Parses backslash, then applies character parser.
863-- | Parses backslash, then applies character parser.
780−escaped :: Stream s m Char
864+escaped :: (Stream s m Char, UpdateSourcePos s Char)
781 => ParserT s st m Char -- ^ Parser for character to escape
865 => ParserT s st m Char -- ^ Parser for character to escape
782 -> ParserT s st m Char
866 -> ParserT s st m Char
783escaped parser = try $ char '\\' >> parser
867escaped parser = try $ char '\\' >> parser
784
868
785-- | Parse character entity.
869-- | Parse character entity.
786−characterReference :: Stream s m Char => ParserT s st m Char
870+characterReference :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m Char
787characterReference = try $ do
871characterReference = try $ do
788 char '&'
872 char '&'
789 ent <- many1Till nonspaceChar (char ';')
873 ent <- many1Till nonspaceChar (char ';')
@@ -796,19 +880,19 @@ characterReference = try $ do
796 _ -> Prelude.fail "entity not found"
880 _ -> Prelude.fail "entity not found"
797
881
798-- | Parses an uppercase roman numeral and returns (UpperRoman, number).
882-- | Parses an uppercase roman numeral and returns (UpperRoman, number).
799−upperRoman :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
883+upperRoman :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
800upperRoman = do
884upperRoman = do
801 num <- romanNumeral True
885 num <- romanNumeral True
802 return (UpperRoman, num)
886 return (UpperRoman, num)
803
887
804-- | Parses a lowercase roman numeral and returns (LowerRoman, number).
888-- | Parses a lowercase roman numeral and returns (LowerRoman, number).
805−lowerRoman :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
889+lowerRoman :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
806lowerRoman = do
890lowerRoman = do
807 num <- romanNumeral False
891 num <- romanNumeral False
808 return (LowerRoman, num)
892 return (LowerRoman, num)
809
893
810-- | Parses a decimal numeral and returns (Decimal, number).
894-- | Parses a decimal numeral and returns (Decimal, number).
811−decimal :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
895+decimal :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
812decimal = do
896decimal = do
813 num <- many1 digit
897 num <- many1 digit
814 return (Decimal, fromMaybe 1 $ safeRead $ T.pack num)
898 return (Decimal, fromMaybe 1 $ safeRead $ T.pack num)
@@ -817,7 +901,7 @@ decimal = do
817-- returns (DefaultStyle, [next example number]). The next
901-- returns (DefaultStyle, [next example number]). The next
818-- example number is incremented in parser state, and the label
902-- example number is incremented in parser state, and the label
819-- (if present) is added to the label table.
903-- (if present) is added to the label table.
820−exampleNum :: Stream s m Char
904+exampleNum :: (Stream s m Char, UpdateSourcePos s Char)
821 => ParserT s ParserState m (ListNumberStyle, Int)
905 => ParserT s ParserState m (ListNumberStyle, Int)
822exampleNum = do
906exampleNum = do
823 char '@'
907 char '@'
@@ -836,37 +920,37 @@ exampleNum = do
836 return (Example, num)
920 return (Example, num)
837
921
838-- | Parses a '#' returns (DefaultStyle, 1).
922-- | Parses a '#' returns (DefaultStyle, 1).
839−defaultNum :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
923+defaultNum :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
840defaultNum = do
924defaultNum = do
841 char '#'
925 char '#'
842 return (DefaultStyle, 1)
926 return (DefaultStyle, 1)
843
927
844-- | Parses a lowercase letter and returns (LowerAlpha, number).
928-- | Parses a lowercase letter and returns (LowerAlpha, number).
845−lowerAlpha :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
929+lowerAlpha :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
846lowerAlpha = do
930lowerAlpha = do
847 ch <- satisfy isAsciiLower
931 ch <- satisfy isAsciiLower
848 return (LowerAlpha, ord ch - ord 'a' + 1)
932 return (LowerAlpha, ord ch - ord 'a' + 1)
849
933
850-- | Parses an uppercase letter and returns (UpperAlpha, number).
934-- | Parses an uppercase letter and returns (UpperAlpha, number).
851−upperAlpha :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
935+upperAlpha :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
852upperAlpha = do
936upperAlpha = do
853 ch <- satisfy isAsciiUpper
937 ch <- satisfy isAsciiUpper
854 return (UpperAlpha, ord ch - ord 'A' + 1)
938 return (UpperAlpha, ord ch - ord 'A' + 1)
855
939
856-- | Parses a roman numeral i or I
940-- | Parses a roman numeral i or I
857−romanOne :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
941+romanOne :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
858romanOne = (char 'i' >> return (LowerRoman, 1)) <|>
942romanOne = (char 'i' >> return (LowerRoman, 1)) <|>
859 (char 'I' >> return (UpperRoman, 1))
943 (char 'I' >> return (UpperRoman, 1))
860
944
861-- | Parses an ordered list marker and returns list attributes.
945-- | Parses an ordered list marker and returns list attributes.
862−anyOrderedListMarker :: Stream s m Char => ParserT s ParserState m ListAttributes
946+anyOrderedListMarker :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s ParserState m ListAttributes
863anyOrderedListMarker = choice
947anyOrderedListMarker = choice
864 [delimParser numParser | delimParser <- [inPeriod, inOneParen, inTwoParens],
948 [delimParser numParser | delimParser <- [inPeriod, inOneParen, inTwoParens],
865 numParser <- [decimal, exampleNum, defaultNum, romanOne,
949 numParser <- [decimal, exampleNum, defaultNum, romanOne,
866 lowerAlpha, lowerRoman, upperAlpha, upperRoman]]
950 lowerAlpha, lowerRoman, upperAlpha, upperRoman]]
867
951
868-- | Parses a list number (num) followed by a period, returns list attributes.
952-- | Parses a list number (num) followed by a period, returns list attributes.
869−inPeriod :: Stream s m Char
953+inPeriod :: (Stream s m Char, UpdateSourcePos s Char)
870 => ParserT s st m (ListNumberStyle, Int)
954 => ParserT s st m (ListNumberStyle, Int)
871 -> ParserT s st m ListAttributes
955 -> ParserT s st m ListAttributes
872inPeriod num = try $ do
956inPeriod num = try $ do
@@ -878,7 +962,7 @@ inPeriod num = try $ do
878 return (start, style, delim)
962 return (start, style, delim)
879
963
880-- | Parses a list number (num) followed by a paren, returns list attributes.
964-- | Parses a list number (num) followed by a paren, returns list attributes.
881−inOneParen :: Stream s m Char
965+inOneParen :: (Stream s m Char, UpdateSourcePos s Char)
882 => ParserT s st m (ListNumberStyle, Int)
966 => ParserT s st m (ListNumberStyle, Int)
883 -> ParserT s st m ListAttributes
967 -> ParserT s st m ListAttributes
884inOneParen num = try $ do
968inOneParen num = try $ do
@@ -887,7 +971,7 @@ inOneParen num = try $ do
887 return (start, style, OneParen)
971 return (start, style, OneParen)
888
972
889-- | Parses a list number (num) enclosed in parens, returns list attributes.
973-- | Parses a list number (num) enclosed in parens, returns list attributes.
890−inTwoParens :: Stream s m Char
974+inTwoParens :: (Stream s m Char, UpdateSourcePos s Char)
891 => ParserT s st m (ListNumberStyle, Int)
975 => ParserT s st m (ListNumberStyle, Int)
892 -> ParserT s st m ListAttributes
976 -> ParserT s st m ListAttributes
893inTwoParens num = try $ do
977inTwoParens num = try $ do
@@ -898,7 +982,7 @@ inTwoParens num = try $ do
898
982
899-- | Parses an ordered list marker with a given style and delimiter,
983-- | Parses an ordered list marker with a given style and delimiter,
900-- returns number.
984-- returns number.
901−orderedListMarker :: Stream s m Char
985+orderedListMarker :: (Stream s m Char, UpdateSourcePos s Char)
902 => ListNumberStyle
986 => ListNumberStyle
903 -> ListNumberDelim
987 -> ListNumberDelim
904 -> ParserT s ParserState m Int
988 -> ParserT s ParserState m Int
@@ -921,10 +1005,10 @@ orderedListMarker style delim = do
921 return start
1005 return start
922
1006
923-- | Parses a character reference and returns a Str element.
1007-- | Parses a character reference and returns a Str element.
924−charRef :: Stream s m Char => ParserT s st m Inline
1008+charRef :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m Inline
925charRef = Str . T.singleton <$> characterReference
1009charRef = Str . T.singleton <$> characterReference
926
1010
927−lineBlockLine :: Monad m => ParserT Text st m Text
1011+lineBlockLine :: Monad m => ParserT Sources st m Text
928lineBlockLine = try $ do
1012lineBlockLine = try $ do
929 char '|'
1013 char '|'
930 char ' '
1014 char ' '
@@ -934,11 +1018,11 @@ lineBlockLine = try $ do
934 continuations <- many (try $ char ' ' >> anyLine)
1018 continuations <- many (try $ char ' ' >> anyLine)
935 return $ white <> T.unwords (line : continuations)
1019 return $ white <> T.unwords (line : continuations)
936
1020
937−blankLineBlockLine :: Stream s m Char => ParserT s st m Char
1021+blankLineBlockLine :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m Char
938blankLineBlockLine = try (char '|' >> blankline)
1022blankLineBlockLine = try (char '|' >> blankline)
939
1023
940-- | Parses an RST-style line block and returns a list of strings.
1024-- | Parses an RST-style line block and returns a list of strings.
941−lineBlockLines :: Monad m => ParserT Text st m [Text]
1025+lineBlockLines :: Monad m => ParserT Sources st m [Text]
942lineBlockLines = try $ do
1026lineBlockLines = try $ do
943 lines' <- many1 (lineBlockLine <|> (T.singleton <$> blankLineBlockLine))
1027 lines' <- many1 (lineBlockLine <|> (T.singleton <$> blankLineBlockLine))
944 skipMany blankline
1028 skipMany blankline
@@ -946,7 +1030,8 @@ lineBlockLines = try $ do
946
1030
947-- | Parse a table using 'headerParser', 'rowParser',
1031-- | Parse a table using 'headerParser', 'rowParser',
948-- 'lineParser', and 'footerParser'.
1032-- 'lineParser', and 'footerParser'.
1033+tableWith :: (Stream s m Char, UpdateSourcePos s Char,
949−tableWith :: (Stream s m Char, HasReaderOptions st, Monad mf)
1034+ HasReaderOptions st, Monad mf)
950 => ParserT s st m (mf [Blocks], [Alignment], [Int])
1035 => ParserT s st m (mf [Blocks], [Alignment], [Int])
951 -> ([Int] -> ParserT s st m (mf [Blocks]))
1036 -> ([Int] -> ParserT s st m (mf [Blocks]))
952 -> ParserT s st m sep
1037 -> ParserT s st m sep
@@ -966,7 +1051,8 @@ tableWith headerParser rowParser lineParser footerParser = try $ do
966
1051
967type TableComponents mf = ([Alignment], [Double], mf [Row], mf [Row])
1052type TableComponents mf = ([Alignment], [Double], mf [Row], mf [Row])
968
1053
1054+tableWith' :: (Stream s m Char, UpdateSourcePos s Char,
969−tableWith' :: (Stream s m Char, HasReaderOptions st, Monad mf)
1055+ HasReaderOptions st, Monad mf)
970 => ParserT s st m (mf [Blocks], [Alignment], [Int])
1056 => ParserT s st m (mf [Blocks], [Alignment], [Int])
971 -> ([Int] -> ParserT s st m (mf [Blocks]))
1057 -> ([Int] -> ParserT s st m (mf [Blocks]))
972 -> ParserT s st m sep
1058 -> ParserT s st m sep
@@ -1015,20 +1101,19 @@ widthsFromIndices numColumns' indices =
1015-- (which may be grid), then the rows,
1101-- (which may be grid), then the rows,
1016-- which may be grid, separated by blank lines, and
1102-- which may be grid, separated by blank lines, and
1017-- ending with a footer (dashed line followed by blank line).
1103-- ending with a footer (dashed line followed by blank line).
1018−gridTableWith :: (Stream s m Char, HasReaderOptions st, HasLastStrPosition st,
1104+gridTableWith :: (Monad m, HasReaderOptions st, HasLastStrPosition st, Monad mf)
1019− Monad mf, IsString s)
1020− => ParserT s st m (mf Blocks) -- ^ Block list parser
1105+ => ParserT Sources st m (mf Blocks) -- ^ Block list parser
1021 -> Bool -- ^ Headerless table
1106 -> Bool -- ^ Headerless table
1022− -> ParserT s st m (mf Blocks)
1107+ -> ParserT Sources st m (mf Blocks)
1023gridTableWith blocks headless =
1108gridTableWith blocks headless =
1024 tableWith (gridTableHeader headless blocks) (gridTableRow blocks)
1109 tableWith (gridTableHeader headless blocks) (gridTableRow blocks)
1025 (gridTableSep '-') gridTableFooter
1110 (gridTableSep '-') gridTableFooter
1026
1111
1027−gridTableWith' :: (Stream s m Char, HasReaderOptions st, HasLastStrPosition st,
1112+gridTableWith' :: (Monad m, HasReaderOptions st, HasLastStrPosition st,
1028− Monad mf, IsString s)
1113+ Monad mf)
1029− => ParserT s st m (mf Blocks) -- ^ Block list parser
1114+ => ParserT Sources st m (mf Blocks) -- ^ Block list parser
1030 -> Bool -- ^ Headerless table
1115 -> Bool -- ^ Headerless table
1031− -> ParserT s st m (TableComponents mf)
1116+ -> ParserT Sources st m (TableComponents mf)
1032gridTableWith' blocks headless =
1117gridTableWith' blocks headless =
1033 tableWith' (gridTableHeader headless blocks) (gridTableRow blocks)
1118 tableWith' (gridTableHeader headless blocks) (gridTableRow blocks)
1034 (gridTableSep '-') gridTableFooter
1119 (gridTableSep '-') gridTableFooter
@@ -1037,7 +1122,7 @@ gridTableSplitLine :: [Int] -> Text -> [Text]
1037gridTableSplitLine indices line = map removeFinalBar $ tail $
1122gridTableSplitLine indices line = map removeFinalBar $ tail $
1038 splitTextByIndices (init indices) $ trimr line
1123 splitTextByIndices (init indices) $ trimr line
1039
1124
1040−gridPart :: Stream s m Char => Char -> ParserT s st m ((Int, Int), Alignment)
1125+gridPart :: Monad m => Char -> ParserT Sources st m ((Int, Int), Alignment)
1041gridPart ch = do
1126gridPart ch = do
1042 leftColon <- option False (True <$ char ':')
1127 leftColon <- option False (True <$ char ':')
1043 dashes <- many1 (char ch)
1128 dashes <- many1 (char ch)
@@ -1052,7 +1137,7 @@ gridPart ch = do
1052 (False, False) -> AlignDefault
1137 (False, False) -> AlignDefault
1053 return ((lengthDashes, lengthDashes + 1), alignment)
1138 return ((lengthDashes, lengthDashes + 1), alignment)
1054
1139
1055−gridDashedLines :: Stream s m Char => Char -> ParserT s st m [((Int, Int), Alignment)]
1140+gridDashedLines :: Monad m => Char -> ParserT Sources st m [((Int, Int), Alignment)]
1056gridDashedLines ch = try $ char '+' >> many1 (gridPart ch) <* blankline
1141gridDashedLines ch = try $ char '+' >> many1 (gridPart ch) <* blankline
1057
1142
1058removeFinalBar :: Text -> Text
1143removeFinalBar :: Text -> Text
@@ -1061,14 +1146,14 @@ removeFinalBar = T.dropWhileEnd go . T.dropWhileEnd (=='|')
1061 go c = T.any (== c) " \t"
1146 go c = T.any (== c) " \t"
1062
1147
1063-- | Separator between rows of grid table.
1148-- | Separator between rows of grid table.
1064−gridTableSep :: Stream s m Char => Char -> ParserT s st m Char
1149+gridTableSep :: Monad m => Char -> ParserT Sources st m Char
1065gridTableSep ch = try $ gridDashedLines ch >> return '\n'
1150gridTableSep ch = try $ gridDashedLines ch >> return '\n'
1066
1151
1067-- | Parse header for a grid table.
1152-- | Parse header for a grid table.
1068−gridTableHeader :: (Stream s m Char, Monad mf, IsString s, HasLastStrPosition st)
1153+gridTableHeader :: (Monad m, Monad mf, HasLastStrPosition st)
1069 => Bool -- ^ Headerless table
1154 => Bool -- ^ Headerless table
1070− -> ParserT s st m (mf Blocks)
1155+ -> ParserT Sources st m (mf Blocks)
1071− -> ParserT s st m (mf [Blocks], [Alignment], [Int])
1156+ -> ParserT Sources st m (mf [Blocks], [Alignment], [Int])
1072gridTableHeader True _ = do
1157gridTableHeader True _ = do
1073 optional blanklines
1158 optional blanklines
1074 dashes <- gridDashedLines '-'
1159 dashes <- gridDashedLines '-'
@@ -1091,17 +1176,17 @@ gridTableHeader False blocks = try $ do
1091 heads <- sequence <$> mapM (parseFromString' blocks . trim) rawHeads
1176 heads <- sequence <$> mapM (parseFromString' blocks . trim) rawHeads
1092 return (heads, aligns, indices)
1177 return (heads, aligns, indices)
1093
1178
1094−gridTableRawLine :: Stream s m Char => [Int] -> ParserT s st m [Text]
1179+gridTableRawLine :: (Stream s m Char, UpdateSourcePos s Char) => [Int] -> ParserT s st m [Text]
1095gridTableRawLine indices = do
1180gridTableRawLine indices = do
1096 char '|'
1181 char '|'
1097 line <- many1Till anyChar newline
1182 line <- many1Till anyChar newline
1098 return (gridTableSplitLine indices $ T.pack line)
1183 return (gridTableSplitLine indices $ T.pack line)
1099
1184
1100-- | Parse row of grid table.
1185-- | Parse row of grid table.
1101−gridTableRow :: (Stream s m Char, Monad mf, IsString s, HasLastStrPosition st)
1186+gridTableRow :: (Monad m, Monad mf, HasLastStrPosition st)
1102− => ParserT s st m (mf Blocks)
1187+ => ParserT Sources st m (mf Blocks)
1103 -> [Int]
1188 -> [Int]
1104− -> ParserT s st m (mf [Blocks])
1189+ -> ParserT Sources st m (mf [Blocks])
1105gridTableRow blocks indices = do
1190gridTableRow blocks indices = do
1106 colLines <- many1 (gridTableRawLine indices)
1191 colLines <- many1 (gridTableRawLine indices)
1107 let cols = map ((<> "\n") . T.unlines . removeOneLeadingSpace) $
1192 let cols = map ((<> "\n") . T.unlines . removeOneLeadingSpace) $
@@ -1122,34 +1207,38 @@ removeOneLeadingSpace xs =
1122 Just (c, _) -> c == ' '
1207 Just (c, _) -> c == ' '
1123
1208
1124-- | Parse footer for a grid table.
1209-- | Parse footer for a grid table.
1125−gridTableFooter :: Stream s m Char => ParserT s st m ()
1210+gridTableFooter :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m ()
1126gridTableFooter = optional blanklines
1211gridTableFooter = optional blanklines
1127
1212
1128---
1213---
1129
1214
1130-- | Removes the ParsecT layer from the monad transformer stack
1215-- | Removes the ParsecT layer from the monad transformer stack
1131−readWithM :: (Stream s m Char, ToText s)
1216+readWithM :: (Monad m, ToSources t)
1132− => ParserT s st m a -- ^ parser
1217+ => ParserT Sources st m a -- ^ parser
1133− -> st -- ^ initial state
1218+ -> st -- ^ initial state
1134− -> s -- ^ input
1219+ -> t -- ^ input
1135 -> m (Either PandocError a)
1220 -> m (Either PandocError a)
1136readWithM parser state input =
1221readWithM parser state input =
1137− mapLeft (PandocParsecError $ toText input) `liftM` runParserT parser state "source" input
1222+ mapLeft (PandocParsecError sources)
1223+ <$> runParserT parser state (initialSourceName sources) sources
1224+ where
1225+ sources = toSources input
1138
1226
1139-- | Parse a string with a given parser and state
1227-- | Parse a string with a given parser and state
1228+readWith :: ToSources t
1140−readWith :: Parser Text st a
1229+ => Parser Sources st a
1141 -> st
1230 -> st
1142− -> Text
1231+ -> t
1143 -> Either PandocError a
1232 -> Either PandocError a
1144readWith p t inp = runIdentity $ readWithM p t inp
1233readWith p t inp = runIdentity $ readWithM p t inp
1145
1234
1146-- | Parse a string with @parser@ (for testing).
1235-- | Parse a string with @parser@ (for testing).
1147testStringWith :: Show a
1236testStringWith :: Show a
1148− => ParserT Text ParserState Identity a
1237+ => ParserT Sources ParserState Identity a
1149 -> Text
1238 -> Text
1150 -> IO ()
1239 -> IO ()
1151testStringWith parser str = UTF8.putStrLn $ tshow $
1240testStringWith parser str = UTF8.putStrLn $ tshow $
1152− readWith parser defaultParserState str
1241+ readWith parser defaultParserState (toSources str)
1153
1242
1154-- | Parsing options.
1243-- | Parsing options.
1155data ParserState = ParserState
1244data ParserState = ParserState
@@ -1169,7 +1258,7 @@ data ParserState = ParserState
1169 stateInNote :: Bool, -- ^ True if parsing note contents
1258 stateInNote :: Bool, -- ^ True if parsing note contents
1170 stateNoteNumber :: Int, -- ^ Last note number for citations
1259 stateNoteNumber :: Int, -- ^ Last note number for citations
1171 stateMeta :: Meta, -- ^ Document metadata
1260 stateMeta :: Meta, -- ^ Document metadata
1172− stateMeta' :: F Meta, -- ^ Document metadata
1261+ stateMeta' :: Future ParserState Meta, -- ^ Document metadata
1173 stateCitations :: M.Map Text Text, -- ^ RST-style citations
1262 stateCitations :: M.Map Text Text, -- ^ RST-style citations
1174 stateHeaderTable :: [HeaderType], -- ^ Ordered list of header types used
1263 stateHeaderTable :: [HeaderType], -- ^ Ordered list of header types used
1175 stateIdentifiers :: Set.Set Text, -- ^ Header identifiers used
1264 stateIdentifiers :: Set.Set Text, -- ^ Header identifiers used
@@ -1348,7 +1437,7 @@ data QuoteContext
1348
1437
1349type NoteTable = [(Text, Text)]
1438type NoteTable = [(Text, Text)]
1350
1439
1351−type NoteTable' = M.Map Text (SourcePos, F Blocks)
1440+type NoteTable' = M.Map Text (SourcePos, Future ParserState Blocks)
1352-- used in markdown reader
1441-- used in markdown reader
1353
1442
1354newtype Key = Key Text deriving (Show, Read, Eq, Ord)
1443newtype Key = Key Text deriving (Show, Read, Eq, Ord)
@@ -1383,7 +1472,7 @@ registerHeader (ident,classes,kvs) header' = do
1383 then do
1472 then do
1384 let id' = uniqueIdent exts (B.toList header') ids
1473 let id' = uniqueIdent exts (B.toList header') ids
1385 let id'' = if Ext_ascii_identifiers `extensionEnabled` exts
1474 let id'' = if Ext_ascii_identifiers `extensionEnabled` exts
1386− then T.pack $ mapMaybe toAsciiChar $ T.unpack id'
1475+ then toAsciiText id'
1387 else id'
1476 else id'
1388 updateState $ updateIdentifierList $ Set.insert id'
1477 updateState $ updateIdentifierList $ Set.insert id'
1389 updateState $ updateIdentifierList $ Set.insert id''
1478 updateState $ updateIdentifierList $ Set.insert id''
@@ -1396,34 +1485,42 @@ registerHeader (ident,classes,kvs) header' = do
1396 updateState $ updateIdentifierList $ Set.insert ident
1485 updateState $ updateIdentifierList $ Set.insert ident
1397 return (ident,classes,kvs)
1486 return (ident,classes,kvs)
1398
1487
1399−smartPunctuation :: (HasReaderOptions st, HasLastStrPosition st, HasQuoteContext st m, Stream s m Char)
1488+smartPunctuation :: (HasReaderOptions st, HasLastStrPosition st,
1489+ HasQuoteContext st m,
1490+ Stream s m Char, UpdateSourcePos s Char)
1400 => ParserT s st m Inlines
1491 => ParserT s st m Inlines
1401 -> ParserT s st m Inlines
1492 -> ParserT s st m Inlines
1402smartPunctuation inlineParser = do
1493smartPunctuation inlineParser = do
1403 guardEnabled Ext_smart
1494 guardEnabled Ext_smart
1404− choice [ quoted inlineParser, apostrophe, dash, ellipses ]
1495+ choice [ quoted inlineParser, apostrophe, doubleCloseQuote, dash, ellipses ]
1405
1496
1406−apostrophe :: Stream s m Char => ParserT s st m Inlines
1407−apostrophe = (char '\'' <|> char '\8217') >> return (B.str "\x2019")
1408−
1409−quoted :: (HasLastStrPosition st, HasQuoteContext st m, Stream s m Char)
1497+quoted :: (HasLastStrPosition st, HasQuoteContext st m,
1498+ Stream s m Char, UpdateSourcePos s Char)
1410 => ParserT s st m Inlines
1499 => ParserT s st m Inlines
1411 -> ParserT s st m Inlines
1500 -> ParserT s st m Inlines
1412quoted inlineParser = doubleQuoted inlineParser <|> singleQuoted inlineParser
1501quoted inlineParser = doubleQuoted inlineParser <|> singleQuoted inlineParser
1413
1502
1414−singleQuoted :: (HasLastStrPosition st, HasQuoteContext st m, Stream s m Char)
1503+singleQuoted :: (HasLastStrPosition st, HasQuoteContext st m,
1504+ Stream s m Char, UpdateSourcePos s Char)
1415 => ParserT s st m Inlines
1505 => ParserT s st m Inlines
1416 -> ParserT s st m Inlines
1506 -> ParserT s st m Inlines
1417−singleQuoted inlineParser = try $ B.singleQuoted . mconcat
1507+singleQuoted inlineParser = do
1418− <$ singleQuoteStart
1508+ singleQuoteStart
1509+ (B.singleQuoted . mconcat <$>
1510+ try
1419− <*> withQuoteContext InSingleQuote (many1Till inlineParser singleQuoteEnd)
1511+ (withQuoteContext InSingleQuote (many1Till inlineParser singleQuoteEnd)))
1420−
1512+ <|> pure "\8217"
1513+
1421−doubleQuoted :: (HasQuoteContext st m, Stream s m Char)
1514+doubleQuoted :: (HasQuoteContext st m, HasLastStrPosition st,
1515+ Stream s m Char, UpdateSourcePos s Char)
1422 => ParserT s st m Inlines
1516 => ParserT s st m Inlines
1423 -> ParserT s st m Inlines
1517 -> ParserT s st m Inlines
1424−doubleQuoted inlineParser = try $ B.doubleQuoted . mconcat
1518+doubleQuoted inlineParser = do
1425− <$ doubleQuoteStart
1519+ doubleQuoteStart
1520+ (B.doubleQuoted . mconcat <$>
1521+ try
1426− <*> withQuoteContext InDoubleQuote (manyTill inlineParser doubleQuoteEnd)
1522+ (withQuoteContext InDoubleQuote (manyTill inlineParser doubleQuoteEnd)))
1523+ <|> pure (B.str "\8220")
1427
1524
1428failIfInQuoteContext :: (HasQuoteContext st m, Stream s m t)
1525failIfInQuoteContext :: (HasQuoteContext st m, Stream s m t)
1429 => QuoteContext
1526 => QuoteContext
@@ -1432,13 +1529,14 @@ failIfInQuoteContext context = do
1432 context' <- getQuoteContext
1529 context' <- getQuoteContext
1433 when (context' == context) $ Prelude.fail "already inside quotes"
1530 when (context' == context) $ Prelude.fail "already inside quotes"
1434
1531
1435−charOrRef :: Stream s m Char => [Char] -> ParserT s st m Char
1532+charOrRef :: (Stream s m Char, UpdateSourcePos s Char) => [Char] -> ParserT s st m Char
1436charOrRef cs =
1533charOrRef cs =
1437 oneOf cs <|> try (do c <- characterReference
1534 oneOf cs <|> try (do c <- characterReference
1438 guard (c `elem` cs)
1535 guard (c `elem` cs)
1439 return c)
1536 return c)
1440
1537
1441−singleQuoteStart :: (HasLastStrPosition st, HasQuoteContext st m, Stream s m Char)
1538+singleQuoteStart :: (HasLastStrPosition st, HasQuoteContext st m,
1539+ Stream s m Char, UpdateSourcePos s Char)
1442 => ParserT s st m ()
1540 => ParserT s st m ()
1443singleQuoteStart = do
1541singleQuoteStart = do
1444 failIfInQuoteContext InSingleQuote
1542 failIfInQuoteContext InSingleQuote
@@ -1446,30 +1544,39 @@ singleQuoteStart = do
1446 guard =<< notAfterString
1544 guard =<< notAfterString
1447 try $ do
1545 try $ do
1448 charOrRef "'\8216\145"
1546 charOrRef "'\8216\145"
1449− notFollowedBy (oneOf [' ', '\t', '\n'])
1547+ void $ lookAhead (satisfy (not . isSpaceChar))
1450
1548
1451−singleQuoteEnd :: Stream s m Char
1549+singleQuoteEnd :: (Stream s m Char, UpdateSourcePos s Char)
1452 => ParserT s st m ()
1550 => ParserT s st m ()
1453singleQuoteEnd = try $ do
1551singleQuoteEnd = try $ do
1454 charOrRef "'\8217\146"
1552 charOrRef "'\8217\146"
1455 notFollowedBy alphaNum
1553 notFollowedBy alphaNum
1456
1554
1555+doubleQuoteStart :: (HasLastStrPosition st,
1457−doubleQuoteStart :: (HasQuoteContext st m, Stream s m Char)
1556+ HasQuoteContext st m,
1557+ Stream s m Char, UpdateSourcePos s Char)
1458 => ParserT s st m ()
1558 => ParserT s st m ()
1459doubleQuoteStart = do
1559doubleQuoteStart = do
1460 failIfInQuoteContext InDoubleQuote
1560 failIfInQuoteContext InDoubleQuote
1561+ guard =<< notAfterString
1461 try $ do charOrRef "\"\8220\147"
1562 try $ do charOrRef "\"\8220\147"
1462− notFollowedBy (oneOf [' ', '\t', '\n'])
1563+ void $ lookAhead (satisfy (not . isSpaceChar))
1463
1564
1464−doubleQuoteEnd :: Stream s m Char
1565+doubleQuoteEnd :: (Stream s m Char, UpdateSourcePos s Char)
1465 => ParserT s st m ()
1566 => ParserT s st m ()
1466doubleQuoteEnd = void (charOrRef "\"\8221\148")
1567doubleQuoteEnd = void (charOrRef "\"\8221\148")
1467
1568
1569+apostrophe :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m Inlines
1570+apostrophe = (char '\'' <|> char '\8217') >> return (B.str "\8217")
1571+
1572+doubleCloseQuote :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m Inlines
1573+doubleCloseQuote = B.str "\8221" <$ char '"'
1574+
1468−ellipses :: Stream s m Char
1575+ellipses :: (Stream s m Char, UpdateSourcePos s Char)
1469 => ParserT s st m Inlines
1576 => ParserT s st m Inlines
1470ellipses = try (string "..." >> return (B.str "\8230"))
1577ellipses = try (string "..." >> return (B.str "\8230"))
1471
1578
1472−dash :: (HasReaderOptions st, Stream s m Char)
1579+dash :: (HasReaderOptions st, Stream s m Char, UpdateSourcePos s Char)
1473 => ParserT s st m Inlines
1580 => ParserT s st m Inlines
1474dash = try $ do
1581dash = try $ do
1475 oldDashes <- extensionEnabled Ext_old_dashes <$> getOption readerExtensions
1582 oldDashes <- extensionEnabled Ext_old_dashes <$> getOption readerExtensions
@@ -1496,20 +1603,28 @@ nested p = do
1496 updateState $ \st -> st{ stateMaxNestingLevel = nestlevel }
1603 updateState $ \st -> st{ stateMaxNestingLevel = nestlevel }
1497 return res
1604 return res
1498
1605
1499−citeKey :: (Stream s m Char, HasLastStrPosition st)
1606+citeKey :: (Stream s m Char, UpdateSourcePos s Char, HasLastStrPosition st)
1607+ => Bool -- ^ If True, allow expanded @{..} syntax.
1500− => ParserT s st m (Bool, Text)
1608+ -> ParserT s st m (Bool, Text)
1501−citeKey = try $ do
1609+citeKey allowBraced = try $ do
1502 guard =<< notAfterString
1610 guard =<< notAfterString
1503 suppress_author <- option False (True <$ char '-')
1611 suppress_author <- option False (True <$ char '-')
1504 char '@'
1612 char '@'
1613+ key <- simpleCiteIdentifier
1614+ <|> if allowBraced
1615+ then charsInBalanced '{' '}' (satisfy (not . isSpace))
1616+ else mzero
1617+ return (suppress_author, key)
1618+
1619+simpleCiteIdentifier :: (Stream s m Char, UpdateSourcePos s Char)
1620+ => ParserT s st m Text
1621+simpleCiteIdentifier = do
1505 firstChar <- alphaNum <|> char '_' <|> char '*' -- @* for wildcard in nocite
1622 firstChar <- alphaNum <|> char '_' <|> char '*' -- @* for wildcard in nocite
1506 let regchar = satisfy (\c -> isAlphaNum c || c == '_')
1623 let regchar = satisfy (\c -> isAlphaNum c || c == '_')
1507 let internal p = try $ p <* lookAhead regchar
1624 let internal p = try $ p <* lookAhead regchar
1508 rest <- many $ regchar <|> internal (oneOf ":.#$%&-+?<>~/") <|>
1625 rest <- many $ regchar <|> internal (oneOf ":.#$%&-+?<>~/") <|>
1509 try (oneOf ":/" <* lookAhead (char '/'))
1626 try (oneOf ":/" <* lookAhead (char '/'))
1510− let key = firstChar:rest
1511− return (suppress_author, T.pack key)
1627+ return $ T.pack $ firstChar:rest
1512−
1513
1628
1514token :: (Stream s m t)
1629token :: (Stream s m t)
1515 => (t -> Text)
1630 => (t -> Text)
@@ -1529,12 +1644,15 @@ extractIdClass (ident, cls, kvs) = (ident', cls', kvs')
1529 cls' = maybe cls T.words $ lookup "class" kvs
1644 cls' = maybe cls T.words $ lookup "class" kvs
1530 kvs' = filter (\(k,_) -> k /= "id" || k /= "class") kvs
1645 kvs' = filter (\(k,_) -> k /= "id" || k /= "class") kvs
1531
1646
1532−insertIncludedFile' :: (PandocMonad m, HasIncludeFiles st)
1647+insertIncludedFile :: (PandocMonad m, HasIncludeFiles st)
1533− => ParserT a st m (mf Blocks)
1648+ => ParserT a st m b -- ^ parser to apply
1534− -> (Text -> a)
1649+ -> (Text -> a) -- ^ convert Text to stream type
1535− -> [FilePath] -> FilePath
1650+ -> [FilePath] -- ^ search path (directories)
1651+ -> FilePath -- ^ path of file to include
1652+ -> Maybe Int -- ^ start line (negative counts from end)
1653+ -> Maybe Int -- ^ end line (negative counts from end)
1536− -> ParserT a st m (mf Blocks)
1654+ -> ParserT a st m b
1537−insertIncludedFile' blocks totoks dirs f = do
1655+insertIncludedFile parser toStream dirs f mbstartline mbendline = do
1538 oldPos <- getPosition
1656 oldPos <- getPosition
1539 oldInput <- getInput
1657 oldInput <- getInput
1540 containers <- getIncludeFiles <$> getState
1658 containers <- getIncludeFiles <$> getState
@@ -1543,32 +1661,32 @@ insertIncludedFile' blocks totoks dirs f = do
1543 updateState $ addIncludeFile $ T.pack f
1661 updateState $ addIncludeFile $ T.pack f
1544 mbcontents <- readFileFromDirs dirs f
1662 mbcontents <- readFileFromDirs dirs f
1545 contents <- case mbcontents of
1663 contents <- case mbcontents of
1546− Just s -> return s
1664+ Just s -> return $ exciseLines mbstartline mbendline s
1547 Nothing -> do
1665 Nothing -> do
1548 report $ CouldNotLoadIncludeFile (T.pack f) oldPos
1666 report $ CouldNotLoadIncludeFile (T.pack f) oldPos
1549 return ""
1667 return ""
1668+ setInput $ toStream contents
1550− setPosition $ newPos f 1 1
1669+ setPosition $ newPos f (fromMaybe 1 mbstartline) 1
1551− setInput $ totoks contents
1670+ result <- parser
1552− bs <- blocks
1553 setInput oldInput
1671 setInput oldInput
1554 setPosition oldPos
1672 setPosition oldPos
1555 updateState dropLatestIncludeFile
1673 updateState dropLatestIncludeFile
1556− return bs
1674+ return result
1675+
1676+exciseLines :: Maybe Int -> Maybe Int -> Text -> Text
1677+exciseLines Nothing Nothing t = t
1678+exciseLines mbstartline mbendline t =
1679+ T.unlines $ take (endline' - (startline' - 1))
1680+ $ drop (startline' - 1) contentLines
1681+ where
1682+ contentLines = T.lines t
1683+ numLines = length contentLines
1684+ startline' = case mbstartline of
1685+ Nothing -> 1
1686+ Just x | x >= 0 -> x
1687+ | otherwise -> numLines + x -- negative from end
1688+ endline' = case mbendline of
1689+ Nothing -> numLines
1690+ Just x | x >= 0 -> x
1691+ | otherwise -> numLines + x -- negative from end
1557
1692
1558−-- | Parse content of include file as blocks. Circular includes result in an
1559−-- @PandocParseError@.
1560−insertIncludedFile :: (PandocMonad m, HasIncludeFiles st)
1561− => ParserT [a] st m Blocks
1562− -> (Text -> [a])
1563− -> [FilePath] -> FilePath
1564− -> ParserT [a] st m Blocks
1565−insertIncludedFile blocks totoks dirs f =
1566− runIdentity <$> insertIncludedFile' (Identity <$> blocks) totoks dirs f
1567−
1568−-- | Parse content of include file as future blocks. Circular includes result in
1569−-- an @PandocParseError@.
1570−insertIncludedFileF :: (PandocMonad m, HasIncludeFiles st)
1571− => ParserT Text st m (Future st Blocks)
1572− -> [FilePath] -> FilePath
1573− -> ParserT Text st m (Future st Blocks)
1574−insertIncludedFileF p = insertIncludedFile' p id
src/Text/Pandoc/Readers.hs+55−48
@@ -1,4 +1,5 @@
1{-# LANGUAGE MonoLocalBinds #-}
1{-# LANGUAGE MonoLocalBinds #-}
2+{-# LANGUAGE RankNTypes #-}
2{-# LANGUAGE ScopedTypeVariables #-}
3{-# LANGUAGE ScopedTypeVariables #-}
3{-# LANGUAGE OverloadedStrings #-}
4{-# LANGUAGE OverloadedStrings #-}
4{- |
5{- |
@@ -65,12 +66,14 @@ import Data.Aeson
65import qualified Data.ByteString.Lazy as BL
66import qualified Data.ByteString.Lazy as BL
66import Data.Text (Text)
67import Data.Text (Text)
67import qualified Data.Text as T
68import qualified Data.Text as T
69+import Text.Pandoc.Shared (tshow)
68import Text.Pandoc.Class
70import Text.Pandoc.Class
69import Text.Pandoc.Definition
71import Text.Pandoc.Definition
70import Text.Pandoc.Error
72import Text.Pandoc.Error
71import Text.Pandoc.Extensions
73import Text.Pandoc.Extensions
72import Text.Pandoc.Options
74import Text.Pandoc.Options
73import Text.Pandoc.Readers.CommonMark
75import Text.Pandoc.Readers.CommonMark
76+import Text.Pandoc.Readers.Markdown
74import Text.Pandoc.Readers.Creole
77import Text.Pandoc.Readers.Creole
75import Text.Pandoc.Readers.DocBook
78import Text.Pandoc.Readers.DocBook
76import Text.Pandoc.Readers.Docx
79import Text.Pandoc.Readers.Docx
@@ -83,7 +86,6 @@ import Text.Pandoc.Readers.HTML (readHtml)
83import Text.Pandoc.Readers.JATS (readJATS)
86import Text.Pandoc.Readers.JATS (readJATS)
84import Text.Pandoc.Readers.Jira (readJira)
87import Text.Pandoc.Readers.Jira (readJira)
85import Text.Pandoc.Readers.LaTeX
88import Text.Pandoc.Readers.LaTeX
86−import Text.Pandoc.Readers.Markdown
87import Text.Pandoc.Readers.MediaWiki
89import Text.Pandoc.Readers.MediaWiki
88import Text.Pandoc.Readers.Muse
90import Text.Pandoc.Readers.Muse
89import Text.Pandoc.Readers.Native
91import Text.Pandoc.Readers.Native
@@ -101,59 +103,60 @@ import Text.Pandoc.Readers.CSV
101import Text.Pandoc.Readers.CslJson
103import Text.Pandoc.Readers.CslJson
102import Text.Pandoc.Readers.BibTeX
104import Text.Pandoc.Readers.BibTeX
103import qualified Text.Pandoc.UTF8 as UTF8
105import qualified Text.Pandoc.UTF8 as UTF8
104−import Text.Parsec.Error
106+import Text.Pandoc.Sources (ToSources(..), sourcesToText)
105
107
108+data Reader m = TextReader (forall a . ToSources a =>
106−data Reader m = TextReader (ReaderOptions -> Text -> m Pandoc)
109+ ReaderOptions -> a -> m Pandoc)
107 | ByteStringReader (ReaderOptions -> BL.ByteString -> m Pandoc)
110 | ByteStringReader (ReaderOptions -> BL.ByteString -> m Pandoc)
108
111
109-- | Association list of formats and readers.
112-- | Association list of formats and readers.
110readers :: PandocMonad m => [(Text, Reader m)]
113readers :: PandocMonad m => [(Text, Reader m)]
111−readers = [ ("native" , TextReader readNative)
114+readers = [("native" , TextReader readNative)
112− ,("json" , TextReader readJSON)
115+ ,("json" , TextReader readJSON)
113− ,("markdown" , TextReader readMarkdown)
116+ ,("markdown" , TextReader readMarkdown)
114− ,("markdown_strict" , TextReader readMarkdown)
117+ ,("markdown_strict" , TextReader readMarkdown)
115− ,("markdown_phpextra" , TextReader readMarkdown)
118+ ,("markdown_phpextra" , TextReader readMarkdown)
116− ,("markdown_github" , TextReader readMarkdown)
119+ ,("markdown_github" , TextReader readMarkdown)
117− ,("markdown_mmd", TextReader readMarkdown)
120+ ,("markdown_mmd", TextReader readMarkdown)
118− ,("commonmark" , TextReader readCommonMark)
121+ ,("commonmark" , TextReader readCommonMark)
119− ,("commonmark_x" , TextReader readCommonMark)
122+ ,("commonmark_x" , TextReader readCommonMark)
120− ,("creole" , TextReader readCreole)
123+ ,("creole" , TextReader readCreole)
121− ,("dokuwiki" , TextReader readDokuWiki)
124+ ,("dokuwiki" , TextReader readDokuWiki)
122− ,("gfm" , TextReader readCommonMark)
125+ ,("gfm" , TextReader readCommonMark)
123− ,("rst" , TextReader readRST)
126+ ,("rst" , TextReader readRST)
124− ,("mediawiki" , TextReader readMediaWiki)
127+ ,("mediawiki" , TextReader readMediaWiki)
125− ,("vimwiki" , TextReader readVimwiki)
128+ ,("vimwiki" , TextReader readVimwiki)
126− ,("docbook" , TextReader readDocBook)
129+ ,("docbook" , TextReader readDocBook)
127− ,("opml" , TextReader readOPML)
130+ ,("opml" , TextReader readOPML)
128− ,("org" , TextReader readOrg)
131+ ,("org" , TextReader readOrg)
129− ,("textile" , TextReader readTextile) -- TODO : textile+lhs
132+ ,("textile" , TextReader readTextile) -- TODO : textile+lhs
130− ,("html" , TextReader readHtml)
133+ ,("html" , TextReader readHtml)
131− ,("jats" , TextReader readJATS)
134+ ,("jats" , TextReader readJATS)
132− ,("jira" , TextReader readJira)
135+ ,("jira" , TextReader readJira)
133− ,("latex" , TextReader readLaTeX)
136+ ,("latex" , TextReader readLaTeX)
134− ,("haddock" , TextReader readHaddock)
137+ ,("haddock" , TextReader readHaddock)
135− ,("twiki" , TextReader readTWiki)
138+ ,("twiki" , TextReader readTWiki)
136− ,("tikiwiki" , TextReader readTikiWiki)
139+ ,("tikiwiki" , TextReader readTikiWiki)
137− ,("docx" , ByteStringReader readDocx)
140+ ,("docx" , ByteStringReader readDocx)
138− ,("odt" , ByteStringReader readOdt)
141+ ,("odt" , ByteStringReader readOdt)
139− ,("t2t" , TextReader readTxt2Tags)
142+ ,("t2t" , TextReader readTxt2Tags)
140− ,("epub" , ByteStringReader readEPUB)
143+ ,("epub" , ByteStringReader readEPUB)
141− ,("muse" , TextReader readMuse)
144+ ,("muse" , TextReader readMuse)
142− ,("man" , TextReader readMan)
145+ ,("man" , TextReader readMan)
143− ,("fb2" , TextReader readFB2)
146+ ,("fb2" , TextReader readFB2)
144− ,("ipynb" , TextReader readIpynb)
147+ ,("ipynb" , TextReader readIpynb)
145− ,("csv" , TextReader readCSV)
148+ ,("csv" , TextReader readCSV)
146− ,("csljson" , TextReader readCslJson)
149+ ,("csljson" , TextReader readCslJson)
147− ,("bibtex" , TextReader readBibTeX)
150+ ,("bibtex" , TextReader readBibTeX)
148− ,("biblatex" , TextReader readBibLaTeX)
151+ ,("biblatex" , TextReader readBibLaTeX)
149 ]
152 ]
150
153
151-- | Retrieve reader, extensions based on formatSpec (format+extensions).
154-- | Retrieve reader, extensions based on formatSpec (format+extensions).
152getReader :: PandocMonad m => Text -> m (Reader m, Extensions)
155getReader :: PandocMonad m => Text -> m (Reader m, Extensions)
153getReader s =
156getReader s =
154 case parseFormatSpec s of
157 case parseFormatSpec s of
155− Left e -> throwError $ PandocAppError
158+ Left e -> throwError $ PandocAppError $
156− $ T.intercalate "\n" [T.pack m | Message m <- errorMessages e]
159+ "Error parsing reader format " <> tshow s <> ": " <> tshow e
157 Right (readerName, extsToEnable, extsToDisable) ->
160 Right (readerName, extsToEnable, extsToDisable) ->
158 case lookup readerName readers of
161 case lookup readerName readers of
159 Nothing -> throwError $ PandocUnknownReaderError
162 Nothing -> throwError $ PandocUnknownReaderError
@@ -173,9 +176,13 @@ getReader s =
173 return (r, exts)
176 return (r, exts)
174
177
175-- | Read pandoc document from JSON format.
178-- | Read pandoc document from JSON format.
176−readJSON :: PandocMonad m
179+readJSON :: (PandocMonad m, ToSources a)
177− => ReaderOptions -> Text -> m Pandoc
180+ => ReaderOptions
181+ -> a
182+ -> m Pandoc
178−readJSON _ t =
183+readJSON _ s =
179− case eitherDecode' . BL.fromStrict . UTF8.fromText $ t of
184+ case eitherDecode' . BL.fromStrict . UTF8.fromText
185+ . sourcesToText . toSources $ s of
180 Right doc -> return doc
186 Right doc -> return doc
181− Left e -> throwError $ PandocParseError ("JSON parse error: " <> T.pack e)
187+ Left e -> throwError $ PandocParseError ("JSON parse error: "
188+ <> T.pack e)
src/Text/Pandoc/Readers/BibTeX.hs+14−8
@@ -23,41 +23,47 @@ where
23import Text.Pandoc.Options
23import Text.Pandoc.Options
24import Text.Pandoc.Definition
24import Text.Pandoc.Definition
25import Text.Pandoc.Builder (setMeta, cite, str)
25import Text.Pandoc.Builder (setMeta, cite, str)
26−import Data.Text (Text)
27import Citeproc (Lang(..), parseLang)
26import Citeproc (Lang(..), parseLang)
28import Citeproc.Locale (getLocale)
27import Citeproc.Locale (getLocale)
29import Text.Pandoc.Error (PandocError(..))
28import Text.Pandoc.Error (PandocError(..))
30import Text.Pandoc.Class (PandocMonad, lookupEnv)
29import Text.Pandoc.Class (PandocMonad, lookupEnv)
31import Text.Pandoc.Citeproc.BibTeX as BibTeX
30import Text.Pandoc.Citeproc.BibTeX as BibTeX
32import Text.Pandoc.Citeproc.MetaValue (referenceToMetaValue)
31import Text.Pandoc.Citeproc.MetaValue (referenceToMetaValue)
32+import Text.Pandoc.Sources (ToSources(..))
33import Control.Monad.Except (throwError)
33import Control.Monad.Except (throwError)
34
34
35-- | Read BibTeX from an input string and return a Pandoc document.
35-- | Read BibTeX from an input string and return a Pandoc document.
36-- The document will have only metadata, with an empty body.
36-- The document will have only metadata, with an empty body.
37-- The metadata will contain a `references` field with the
37-- The metadata will contain a `references` field with the
38-- bibliography entries, and a `nocite` field with the wildcard `[@*]`.
38-- bibliography entries, and a `nocite` field with the wildcard `[@*]`.
39+readBibTeX :: (PandocMonad m, ToSources a)
39−readBibTeX :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
40+ => ReaderOptions -> a -> m Pandoc
40readBibTeX = readBibTeX' BibTeX.Bibtex
41readBibTeX = readBibTeX' BibTeX.Bibtex
41
42
42-- | Read BibLaTeX from an input string and return a Pandoc document.
43-- | Read BibLaTeX from an input string and return a Pandoc document.
43-- The document will have only metadata, with an empty body.
44-- The document will have only metadata, with an empty body.
44-- The metadata will contain a `references` field with the
45-- The metadata will contain a `references` field with the
45-- bibliography entries, and a `nocite` field with the wildcard `[@*]`.
46-- bibliography entries, and a `nocite` field with the wildcard `[@*]`.
46−readBibLaTeX :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
47+readBibLaTeX :: (PandocMonad m, ToSources a)
48+ => ReaderOptions -> a -> m Pandoc
47readBibLaTeX = readBibTeX' BibTeX.Biblatex
49readBibLaTeX = readBibTeX' BibTeX.Biblatex
48
50
51+readBibTeX' :: (PandocMonad m, ToSources a)
49−readBibTeX' :: PandocMonad m => Variant -> ReaderOptions -> Text -> m Pandoc
52+ => Variant -> ReaderOptions -> a -> m Pandoc
50readBibTeX' variant _opts t = do
53readBibTeX' variant _opts t = do
51− lang <- maybe (Lang "en" (Just "US")) parseLang
54+ mblangEnv <- lookupEnv "LANG"
52− <$> lookupEnv "LANG"
55+ let defaultLang = Lang "en" Nothing (Just "US") [] [] []
56+ let lang = case mblangEnv of
57+ Nothing -> defaultLang
58+ Just l -> either (const defaultLang) id $ parseLang l
53 locale <- case getLocale lang of
59 locale <- case getLocale lang of
54 Left e ->
60 Left e ->
55− case getLocale (Lang "en" (Just "US")) of
61+ case getLocale (Lang "en" Nothing (Just "US") [] [] []) of
56 Right l -> return l
62 Right l -> return l
57 Left _ -> throwError $ PandocCiteprocError e
63 Left _ -> throwError $ PandocCiteprocError e
58 Right l -> return l
64 Right l -> return l
59 case BibTeX.readBibtexString variant locale (const True) t of
65 case BibTeX.readBibtexString variant locale (const True) t of
60− Left e -> throwError $ PandocParsecError t e
66+ Left e -> throwError $ PandocParsecError (toSources t) e
61 Right refs -> return $ setMeta "references"
67 Right refs -> return $ setMeta "references"
62 (map referenceToMetaValue refs)
68 (map referenceToMetaValue refs)
63 . setMeta "nocite"
69 . setMeta "nocite"
src/Text/Pandoc/Readers/CSV.hs+7−7
@@ -13,23 +13,23 @@
13Conversion from CSV to a 'Pandoc' table.
13Conversion from CSV to a 'Pandoc' table.
14-}
14-}
15module Text.Pandoc.Readers.CSV ( readCSV ) where
15module Text.Pandoc.Readers.CSV ( readCSV ) where
16−import Data.Text (Text)
17import qualified Data.Text as T
16import qualified Data.Text as T
18import Text.Pandoc.CSV (parseCSV, defaultCSVOptions)
17import Text.Pandoc.CSV (parseCSV, defaultCSVOptions)
19import Text.Pandoc.Definition
18import Text.Pandoc.Definition
20import qualified Text.Pandoc.Builder as B
19import qualified Text.Pandoc.Builder as B
21import Text.Pandoc.Class (PandocMonad)
20import Text.Pandoc.Class (PandocMonad)
22−import Text.Pandoc.Shared (crFilter)
23import Text.Pandoc.Error
21import Text.Pandoc.Error
22+import Text.Pandoc.Sources (ToSources(..), sourcesToText)
24import Text.Pandoc.Options (ReaderOptions)
23import Text.Pandoc.Options (ReaderOptions)
25import Control.Monad.Except (throwError)
24import Control.Monad.Except (throwError)
26
25
27−readCSV :: PandocMonad m
26+readCSV :: (PandocMonad m, ToSources a)
28 => ReaderOptions -- ^ Reader options
27 => ReaderOptions -- ^ Reader options
29− -> Text -- ^ Text to parse (assuming @'\n'@ line endings)
28+ -> a
30 -> m Pandoc
29 -> m Pandoc
31−readCSV _opts s =
30+readCSV _opts s = do
31+ let txt = sourcesToText $ toSources s
32− case parseCSV defaultCSVOptions (crFilter s) of
32+ case parseCSV defaultCSVOptions txt of
33 Right (r:rs) -> return $ B.doc $ B.table capt
33 Right (r:rs) -> return $ B.doc $ B.table capt
34 (zip aligns widths)
34 (zip aligns widths)
35 (TableHead nullAttr hdrs)
35 (TableHead nullAttr hdrs)
@@ -45,4 +45,4 @@ readCSV _opts s =
45 aligns = replicate numcols AlignDefault
45 aligns = replicate numcols AlignDefault
46 widths = replicate numcols ColWidthDefault
46 widths = replicate numcols ColWidthDefault
47 Right [] -> return $ B.doc mempty
47 Right [] -> return $ B.doc mempty
48− Left e -> throwError $ PandocParsecError s e
48+ Left e -> throwError $ PandocParsecError (toSources [("",txt)]) e
src/Text/Pandoc/Readers/CommonMark.hs+46−4
@@ -26,19 +26,59 @@ import Text.Pandoc.Definition
26import Text.Pandoc.Builder as B
26import Text.Pandoc.Builder as B
27import Text.Pandoc.Options
27import Text.Pandoc.Options
28import Text.Pandoc.Error
28import Text.Pandoc.Error
29+import Text.Pandoc.Readers.Metadata (yamlMetaBlock)
29import Control.Monad.Except
30import Control.Monad.Except
30import Data.Functor.Identity (runIdentity)
31import Data.Functor.Identity (runIdentity)
31import Data.Typeable
32import Data.Typeable
33+import Text.Pandoc.Parsing (runParserT, getInput,
34+ runF, defaultParserState, option, many1, anyChar,
35+ Sources(..), ToSources(..), ParserT, Future,
36+ sourceName)
37+import qualified Data.Text as T
32
38
33-- | Parse a CommonMark formatted string into a 'Pandoc' structure.
39-- | Parse a CommonMark formatted string into a 'Pandoc' structure.
34−readCommonMark :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
40+readCommonMark :: (PandocMonad m, ToSources a)
41+ => ReaderOptions -> a -> m Pandoc
35readCommonMark opts s
42readCommonMark opts s
43+ | isEnabled Ext_yaml_metadata_block opts = do
44+ let sources = toSources s
45+ let toks = concatMap sourceToToks (unSources sources)
46+ res <- runParserT (do meta <- yamlMetaBlock (metaValueParser opts)
47+ rest <- getInput
48+ return (meta, rest))
49+ defaultParserState "YAML metadata" (toSources s)
50+ case res of
51+ Left _ -> readCommonMarkBody opts sources toks
52+ Right (meta, rest) -> do
53+ -- strip off metadata section and parse body
54+ let body = concatMap sourceToToks (unSources rest)
55+ Pandoc _ bs <- readCommonMarkBody opts sources body
56+ return $ Pandoc (runF meta defaultParserState) bs
57+ | otherwise = do
58+ let sources = toSources s
59+ let toks = concatMap sourceToToks (unSources sources)
60+ readCommonMarkBody opts sources toks
61+
62+sourceToToks :: (SourcePos, Text) -> [Tok]
63+sourceToToks (pos, s) = tokenize (sourceName pos) s
64+
65+metaValueParser :: Monad m
66+ => ReaderOptions -> ParserT Sources st m (Future st MetaValue)
67+metaValueParser opts = do
68+ inp <- option "" $ T.pack <$> many1 anyChar
69+ let toks = concatMap sourceToToks (unSources (toSources inp))
70+ case runIdentity (parseCommonmarkWith (specFor opts) toks) of
71+ Left _ -> mzero
72+ Right (Cm bls :: Cm () Blocks) -> return $ return $ B.toMetaValue bls
73+
74+readCommonMarkBody :: PandocMonad m => ReaderOptions -> Sources -> [Tok] -> m Pandoc
75+readCommonMarkBody opts s toks
36 | isEnabled Ext_sourcepos opts =
76 | isEnabled Ext_sourcepos opts =
37− case runIdentity (commonmarkWith (specFor opts) "" s) of
77+ case runIdentity (parseCommonmarkWith (specFor opts) toks) of
38 Left err -> throwError $ PandocParsecError s err
78 Left err -> throwError $ PandocParsecError s err
39 Right (Cm bls :: Cm SourceRange Blocks) -> return $ B.doc bls
79 Right (Cm bls :: Cm SourceRange Blocks) -> return $ B.doc bls
40 | otherwise =
80 | otherwise =
41− case runIdentity (commonmarkWith (specFor opts) "" s) of
81+ case runIdentity (parseCommonmarkWith (specFor opts) toks) of
42 Left err -> throwError $ PandocParsecError s err
82 Left err -> throwError $ PandocParsecError s err
43 Right (Cm bls :: Cm () Blocks) -> return $ B.doc bls
83 Right (Cm bls :: Cm () Blocks) -> return $ B.doc bls
44
84
@@ -72,5 +112,7 @@ specFor opts = foldr ($) defaultSyntaxSpec exts
72 | isEnabled Ext_implicit_header_references opts ] ++
112 | isEnabled Ext_implicit_header_references opts ] ++
73 [ (footnoteSpec <>) | isEnabled Ext_footnotes opts ] ++
113 [ (footnoteSpec <>) | isEnabled Ext_footnotes opts ] ++
74 [ (definitionListSpec <>) | isEnabled Ext_definition_lists opts ] ++
114 [ (definitionListSpec <>) | isEnabled Ext_definition_lists opts ] ++
75− [ (taskListSpec <>) | isEnabled Ext_task_lists opts ]
115+ [ (taskListSpec <>) | isEnabled Ext_task_lists opts ] ++
116+ [ (rebaseRelativePathsSpec <>)
117+ | isEnabled Ext_rebase_relative_paths opts ]
76
118
src/Text/Pandoc/Readers/Creole.hs+5−6
@@ -23,21 +23,20 @@ import Text.Pandoc.Class.PandocMonad (PandocMonad (..))
23import Text.Pandoc.Definition
23import Text.Pandoc.Definition
24import Text.Pandoc.Options
24import Text.Pandoc.Options
25import Text.Pandoc.Parsing hiding (enclosed)
25import Text.Pandoc.Parsing hiding (enclosed)
26−import Text.Pandoc.Shared (crFilter)
27−
28
26
29-- | Read creole from an input string and return a Pandoc document.
27-- | Read creole from an input string and return a Pandoc document.
30−readCreole :: PandocMonad m
28+readCreole :: (PandocMonad m, ToSources a)
31 => ReaderOptions
29 => ReaderOptions
32− -> Text
30+ -> a
33 -> m Pandoc
31 -> m Pandoc
34readCreole opts s = do
32readCreole opts s = do
33+ let sources = ensureFinalNewlines 2 (toSources s)
35− res <- readWithM parseCreole def{ stateOptions = opts } $ crFilter s <> "\n\n"
34+ res <- readWithM parseCreole def{ stateOptions = opts } sources
36 case res of
35 case res of
37 Left e -> throwError e
36 Left e -> throwError e
38 Right d -> return d
37 Right d -> return d
39
38
40−type CRLParser = ParserT Text ParserState
39+type CRLParser = ParserT Sources ParserState
41
40
42--
41--
43-- Utility functions
42-- Utility functions
src/Text/Pandoc/Readers/CslJson.hs+5−4
@@ -24,21 +24,22 @@ import Text.Pandoc.Options
24import Text.Pandoc.Definition
24import Text.Pandoc.Definition
25import Text.Pandoc.Builder (setMeta, cite, str)
25import Text.Pandoc.Builder (setMeta, cite, str)
26import qualified Text.Pandoc.UTF8 as UTF8
26import qualified Text.Pandoc.UTF8 as UTF8
27−import Data.Text (Text)
28import qualified Data.Text as T
27import qualified Data.Text as T
29import Text.Pandoc.Error (PandocError(..))
28import Text.Pandoc.Error (PandocError(..))
30import Text.Pandoc.Class (PandocMonad)
29import Text.Pandoc.Class (PandocMonad)
31import Text.Pandoc.Citeproc.CslJson (cslJsonToReferences)
30import Text.Pandoc.Citeproc.CslJson (cslJsonToReferences)
32import Text.Pandoc.Citeproc.MetaValue (referenceToMetaValue)
31import Text.Pandoc.Citeproc.MetaValue (referenceToMetaValue)
33import Control.Monad.Except (throwError)
32import Control.Monad.Except (throwError)
33+import Text.Pandoc.Sources (ToSources(..), sourcesToText)
34
34
35-- | Read CSL JSON from an input string and return a Pandoc document.
35-- | Read CSL JSON from an input string and return a Pandoc document.
36-- The document will have only metadata, with an empty body.
36-- The document will have only metadata, with an empty body.
37-- The metadata will contain a `references` field with the
37-- The metadata will contain a `references` field with the
38-- bibliography entries, and a `nocite` field with the wildcard `[@*]`.
38-- bibliography entries, and a `nocite` field with the wildcard `[@*]`.
39+readCslJson :: (PandocMonad m, ToSources a)
39−readCslJson :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
40+ => ReaderOptions -> a -> m Pandoc
40−readCslJson _opts t =
41+readCslJson _opts x =
41− case cslJsonToReferences (UTF8.fromText t) of
42+ case cslJsonToReferences (UTF8.fromText $ sourcesToText $ toSources x) of
42 Left e -> throwError $ PandocParseError $ T.pack e
43 Left e -> throwError $ PandocParseError $ T.pack e
43 Right refs -> return $ setMeta "references"
44 Right refs -> return $ setMeta "references"
44 (map referenceToMetaValue refs)
45 (map referenceToMetaValue refs)
src/Text/Pandoc/Readers/DocBook.hs+30−15
@@ -18,6 +18,7 @@ import Data.Either (rights)
18import Data.Foldable (asum)
18import Data.Foldable (asum)
19import Data.Generics
19import Data.Generics
20import Data.List (intersperse,elemIndex)
20import Data.List (intersperse,elemIndex)
21+import Data.List.NonEmpty (nonEmpty)
21import Data.Maybe (fromMaybe,mapMaybe)
22import Data.Maybe (fromMaybe,mapMaybe)
22import Data.Text (Text)
23import Data.Text (Text)
23import qualified Data.Text as T
24import qualified Data.Text as T
@@ -29,7 +30,8 @@ import Text.Pandoc.Builder
29import Text.Pandoc.Class.PandocMonad (PandocMonad, report)
30import Text.Pandoc.Class.PandocMonad (PandocMonad, report)
30import Text.Pandoc.Options
31import Text.Pandoc.Options
31import Text.Pandoc.Logging (LogMessage(..))
32import Text.Pandoc.Logging (LogMessage(..))
32−import Text.Pandoc.Shared (crFilter, safeRead, extractSpaces)
33+import Text.Pandoc.Shared (safeRead, extractSpaces)
34+import Text.Pandoc.Sources (ToSources(..), sourcesToText)
33import Text.TeXMath (readMathML, writeTeX)
35import Text.TeXMath (readMathML, writeTeX)
34import Text.Pandoc.XML.Light
36import Text.Pandoc.XML.Light
35
37
@@ -132,6 +134,7 @@ List of all DocBook tags, with [x] indicating implemented,
132[ ] corpcredit - A corporation or organization credited in a document
134[ ] corpcredit - A corporation or organization credited in a document
133[ ] corpname - The name of a corporation
135[ ] corpname - The name of a corporation
134[ ] country - The name of a country
136[ ] country - The name of a country
137+[x] danger - An admonition set off from the text indicating hazardous situation
135[ ] database - The name of a database, or part of a database
138[ ] database - The name of a database, or part of a database
136[x] date - The date of publication or revision of a document
139[x] date - The date of publication or revision of a document
137[ ] dedication - A wrapper for the dedication section of a book
140[ ] dedication - A wrapper for the dedication section of a book
@@ -538,11 +541,15 @@ instance Default DBState where
538 , dbContent = [] }
541 , dbContent = [] }
539
542
540
543
541−readDocBook :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
544+readDocBook :: (PandocMonad m, ToSources a)
545+ => ReaderOptions
546+ -> a
547+ -> m Pandoc
542readDocBook _ inp = do
548readDocBook _ inp = do
549+ let sources = toSources inp
543 tree <- either (throwError . PandocXMLError "") return $
550 tree <- either (throwError . PandocXMLError "") return $
544 parseXMLContents
551 parseXMLContents
545− (TL.fromStrict . handleInstructions $ crFilter inp)
552+ (TL.fromStrict . handleInstructions . sourcesToText $ sources)
546 (bs, st') <- flip runStateT (def{ dbContent = tree }) $ mapM parseBlock tree
553 (bs, st') <- flip runStateT (def{ dbContent = tree }) $ mapM parseBlock tree
547 return $ Pandoc (dbMeta st') (toList . mconcat $ bs)
554 return $ Pandoc (dbMeta st') (toList . mconcat $ bs)
548
555
@@ -594,16 +601,24 @@ addMetadataFromElement e = do
594 Nothing -> return ()
601 Nothing -> return ()
595 Just z -> addMetaField "author" z
602 Just z -> addMetaField "author" z
596 addMetaField "subtitle" e
603 addMetaField "subtitle" e
597− addMetaField "author" e
604+ addAuthor e
598 addMetaField "date" e
605 addMetaField "date" e
599 addMetaField "release" e
606 addMetaField "release" e
600 addMetaField "releaseinfo" e
607 addMetaField "releaseinfo" e
601 return mempty
608 return mempty
609+ where
610+ addAuthor elt =
611+ case filterChildren (named "author") elt of
612+ [] -> return ()
613+ [z] -> fromAuthor z >>= addMeta "author"
614+ zs -> mapM fromAuthor zs >>= addMeta "author"
615+ fromAuthor elt =
616+ mconcat . intersperse space <$> mapM getInlines (elChildren elt)
602− where addMetaField fieldname elt =
617+ addMetaField fieldname elt =
603− case filterChildren (named fieldname) elt of
618+ case filterChildren (named fieldname) elt of
604− [] -> return ()
619+ [] -> return ()
605− [z] -> getInlines z >>= addMeta fieldname
620+ [z] -> getInlines z >>= addMeta fieldname
606− zs -> mapM getInlines zs >>= addMeta fieldname
621+ zs -> mapM getInlines zs >>= addMeta fieldname
607
622
608addMeta :: PandocMonad m => ToMetaValue a => Text -> a -> DB m ()
623addMeta :: PandocMonad m => ToMetaValue a => Text -> a -> DB m ()
609addMeta field val = modify (setMeta field val)
624addMeta field val = modify (setMeta field val)
@@ -704,7 +719,7 @@ blockTags =
704 ] ++ admonitionTags
719 ] ++ admonitionTags
705
720
706admonitionTags :: [Text]
721admonitionTags :: [Text]
707−admonitionTags = ["important","caution","note","tip","warning"]
722+admonitionTags = ["caution","danger","important","note","tip","warning"]
708
723
709-- Trim leading and trailing newline characters
724-- Trim leading and trailing newline characters
710trimNl :: Text -> Text
725trimNl :: Text -> Text
@@ -949,9 +964,8 @@ parseBlock (Elem e) =
949 (x >= '0' && x <= '9')
964 (x >= '0' && x <= '9')
950 || x == '.') w
965 || x == '.') w
951 if n > 0 then Just n else Nothing
966 if n > 0 then Just n else Nothing
952− let numrows = case bodyrows of
967+ let numrows = maybe 0 maximum $ nonEmpty
953− [] -> 0
954− xs -> maximum $ map length xs
968+ $ map length bodyrows
955 let aligns = case colspecs of
969 let aligns = case colspecs of
956 [] -> replicate numrows AlignDefault
970 [] -> replicate numrows AlignDefault
957 cs -> map toAlignment cs
971 cs -> map toAlignment cs
@@ -1075,7 +1089,7 @@ parseInline (Elem e) =
1075 return $ spanWith (attrValue "id" e, [], []) mempty
1089 return $ spanWith (attrValue "id" e, [], []) mempty
1076 "phrase" -> do
1090 "phrase" -> do
1077 let ident = attrValue "id" e
1091 let ident = attrValue "id" e
1078− let classes = T.words $ attrValue "class" e
1092+ let classes = T.words $ attrValue "role" e
1079 if ident /= "" || classes /= []
1093 if ident /= "" || classes /= []
1080 then innerInlines (spanWith (ident,classes,[]))
1094 then innerInlines (spanWith (ident,classes,[]))
1081 else innerInlines id
1095 else innerInlines id
@@ -1239,7 +1253,8 @@ equation e constructor =
1239 where
1253 where
1240 mathMLEquations :: [Text]
1254 mathMLEquations :: [Text]
1241 mathMLEquations = map writeTeX $ rights $ readMath
1255 mathMLEquations = map writeTeX $ rights $ readMath
1242− (\x -> qName (elName x) == "math" && qPrefix (elName x) == Just "mml")
1256+ (\x -> qName (elName x) == "math" &&
1257+ qURI (elName x) == Just "http://www.w3.org/1998/Math/MathML")
1243 (readMathML . showElement)
1258 (readMathML . showElement)
1244
1259
1245 latexEquations :: [Text]
1260 latexEquations :: [Text]
src/Text/Pandoc/Readers/Docx.hs+59−42
@@ -61,13 +61,14 @@ module Text.Pandoc.Readers.Docx
61import Codec.Archive.Zip
61import Codec.Archive.Zip
62import Control.Monad.Reader
62import Control.Monad.Reader
63import Control.Monad.State.Strict
63import Control.Monad.State.Strict
64+import Data.Bifunctor (bimap, first)
64import qualified Data.ByteString.Lazy as B
65import qualified Data.ByteString.Lazy as B
65import Data.Default (Default)
66import Data.Default (Default)
66−import Data.List (delete, intersect)
67+import Data.List (delete, intersect, foldl')
67import Data.Char (isSpace)
68import Data.Char (isSpace)
68import qualified Data.Map as M
69import qualified Data.Map as M
69import qualified Data.Text as T
70import qualified Data.Text as T
70−import Data.Maybe (isJust, fromMaybe)
71+import Data.Maybe (catMaybes, isJust, fromMaybe)
71import Data.Sequence (ViewL (..), viewl)
72import Data.Sequence (ViewL (..), viewl)
72import qualified Data.Sequence as Seq
73import qualified Data.Sequence as Seq
73import qualified Data.Set as Set
74import qualified Data.Set as Set
@@ -85,6 +86,7 @@ import Text.Pandoc.Class.PandocMonad (PandocMonad)
85import qualified Text.Pandoc.Class.PandocMonad as P
86import qualified Text.Pandoc.Class.PandocMonad as P
86import Text.Pandoc.Error
87import Text.Pandoc.Error
87import Text.Pandoc.Logging
88import Text.Pandoc.Logging
89+import Data.List.NonEmpty (nonEmpty)
88
90
89readDocx :: PandocMonad m
91readDocx :: PandocMonad m
90 => ReaderOptions
92 => ReaderOptions
@@ -112,6 +114,7 @@ data DState = DState { docxAnchorMap :: M.Map T.Text T.Text
112 -- restarting
114 -- restarting
113 , docxListState :: M.Map (T.Text, T.Text) Integer
115 , docxListState :: M.Map (T.Text, T.Text) Integer
114 , docxPrevPara :: Inlines
116 , docxPrevPara :: Inlines
117+ , docxTableCaptions :: [Blocks]
115 }
118 }
116
119
117instance Default DState where
120instance Default DState where
@@ -122,6 +125,7 @@ instance Default DState where
122 , docxDropCap = mempty
125 , docxDropCap = mempty
123 , docxListState = M.empty
126 , docxListState = M.empty
124 , docxPrevPara = mempty
127 , docxPrevPara = mempty
128+ , docxTableCaptions = []
125 }
129 }
126
130
127data DEnv = DEnv { docxOptions :: ReaderOptions
131data DEnv = DEnv { docxOptions :: ReaderOptions
@@ -490,15 +494,32 @@ singleParaToPlain blks
490 singleton $ Plain ils
494 singleton $ Plain ils
491singleParaToPlain blks = blks
495singleParaToPlain blks = blks
492
496
493−cellToBlocks :: PandocMonad m => Docx.Cell -> DocxContext m Blocks
497+cellToCell :: PandocMonad m => RowSpan -> Docx.Cell -> DocxContext m Pandoc.Cell
494−cellToBlocks (Docx.Cell bps) = do
498+cellToCell rowSpan (Docx.Cell gridSpan _ bps) = do
495 blks <- smushBlocks <$> mapM bodyPartToBlocks bps
499 blks <- smushBlocks <$> mapM bodyPartToBlocks bps
496− return $ fromList $ blocksToDefinitions $ blocksToBullets $ toList blks
500+ let blks' = singleParaToPlain $ fromList $ blocksToDefinitions $ blocksToBullets $ toList blks
501+ return (cell AlignDefault rowSpan (ColSpan (fromIntegral gridSpan)) blks')
502+
503+rowsToRows :: PandocMonad m => [Docx.Row] -> DocxContext m [Pandoc.Row]
504+rowsToRows rows = do
505+ let rowspans = (fmap . fmap) (first RowSpan) (Docx.rowsToRowspans rows)
506+ cells <- traverse (traverse (uncurry cellToCell)) rowspans
507+ return (fmap (Pandoc.Row nullAttr) cells)
508+
509+splitHeaderRows :: Bool -> [Docx.Row] -> ([Docx.Row], [Docx.Row])
510+splitHeaderRows hasFirstRowFormatting rs = bimap reverse reverse $ fst
511+ $ if hasFirstRowFormatting
512+ then foldl' f ((take 1 rs, []), True) (drop 1 rs)
513+ else foldl' f (([], []), False) rs
514+ where
515+ f ((headerRows, bodyRows), previousRowWasHeader) r@(Docx.Row h cs)
516+ | h == HasTblHeader || (previousRowWasHeader && any isContinuationCell cs)
517+ = ((r : headerRows, bodyRows), True)
518+ | otherwise
519+ = ((headerRows, r : bodyRows), False)
520+
521+ isContinuationCell (Docx.Cell _ vm _) = vm == Docx.Continue
497
522
498−rowToBlocksList :: PandocMonad m => Docx.Row -> DocxContext m [Blocks]
499−rowToBlocksList (Docx.Row cells) = do
500− blksList <- mapM cellToBlocks cells
501− return $ map singleParaToPlain blksList
502
523
503-- like trimInlines, but also take out linebreaks
524-- like trimInlines, but also take out linebreaks
504trimSps :: Inlines -> Inlines
525trimSps :: Inlines -> Inlines
@@ -545,6 +566,11 @@ normalizeToClassName = T.map go . fromStyleName
545 where go c | isSpace c = '-'
566 where go c | isSpace c = '-'
546 | otherwise = c
567 | otherwise = c
547
568
569+bodyPartToTableCaption :: PandocMonad m => BodyPart -> DocxContext m (Maybe Blocks)
570+bodyPartToTableCaption (TblCaption pPr parparts) =
571+ Just <$> bodyPartToBlocks (Paragraph pPr parparts)
572+bodyPartToTableCaption _ = pure Nothing
573+
548bodyPartToBlocks :: PandocMonad m => BodyPart -> DocxContext m Blocks
574bodyPartToBlocks :: PandocMonad m => BodyPart -> DocxContext m Blocks
549bodyPartToBlocks (Paragraph pPr parparts)
575bodyPartToBlocks (Paragraph pPr parparts)
550 | Just True <- pBidi pPr = do
576 | Just True <- pBidi pPr = do
@@ -636,54 +662,43 @@ bodyPartToBlocks (ListItem pPr _ _ _ parparts) =
636 let pPr' = pPr {pStyle = constructBogusParStyleData "list-paragraph": pStyle pPr}
662 let pPr' = pPr {pStyle = constructBogusParStyleData "list-paragraph": pStyle pPr}
637 in
663 in
638 bodyPartToBlocks $ Paragraph pPr' parparts
664 bodyPartToBlocks $ Paragraph pPr' parparts
665+bodyPartToBlocks (TblCaption _ _) =
666+ return $ para mempty -- collected separately
639bodyPartToBlocks (Tbl _ _ _ []) =
667bodyPartToBlocks (Tbl _ _ _ []) =
640 return $ para mempty
668 return $ para mempty
641−bodyPartToBlocks (Tbl cap _ look parts@(r:rs)) = do
669+bodyPartToBlocks (Tbl cap grid look parts) = do
642− let cap' = simpleCaption $ plain $ text cap
670+ captions <- gets docxTableCaptions
643− (hdr, rows) = case firstRowFormatting look of
671+ fullCaption <- case captions of
644− True | null rs -> (Nothing, [r])
672+ c : cs -> do
645− | otherwise -> (Just r, rs)
673+ modify (\s -> s { docxTableCaptions = cs })
646− False -> (Nothing, r:rs)
674+ return c
647−
675+ [] -> return $ if T.null cap then mempty else plain (text cap)
648− cells <- mapM rowToBlocksList rows
676+ let shortCaption = if T.null cap then Nothing else Just (toList (text cap))
677+ cap' = caption shortCaption fullCaption
678+ (hdr, rows) = splitHeaderRows (firstRowFormatting look) parts
649
679
650 let width = maybe 0 maximum $ nonEmpty $ map rowLength parts
680 let width = maybe 0 maximum $ nonEmpty $ map rowLength parts
651− -- Data.List.NonEmpty is not available with ghc 7.10 so we roll out
652− -- our own, see
653− -- https://github.com/jgm/pandoc/pull/4361#issuecomment-365416155
654− nonEmpty [] = Nothing
655− nonEmpty l = Just l
656 rowLength :: Docx.Row -> Int
681 rowLength :: Docx.Row -> Int
657− rowLength (Docx.Row c) = length c
682+ rowLength (Docx.Row _ c) = sum (fmap (\(Docx.Cell gridSpan _ _) -> fromIntegral gridSpan) c)
658
683
659− let toRow = Pandoc.Row nullAttr . map simpleCell
684+ headerCells <- rowsToRows hdr
660− toHeaderRow l = [toRow l | not (null l)]
685+ bodyCells <- rowsToRows rows
661
686
662− -- pad cells. New Text.Pandoc.Builder will do that for us,
687+ -- Horizontal column alignment goes to the default at the moment. Getting
663− -- so this is for compatibility while we switch over.
664− let cells' = map (\row -> toRow $ take width (row ++ repeat mempty)) cells
665−
666− hdrCells <- case hdr of
667− Just r' -> toHeaderRow <$> rowToBlocksList r'
668− Nothing -> return []
669−
670− -- The two following variables (horizontal column alignment and
671− -- relative column widths) go to the default at the
672− -- moment. Width information is in the TblGrid field of the Tbl,
673− -- so should be possible. Alignment might be more difficult,
674− -- since there doesn't seem to be a column entity in docx.
688+ -- it might be difficult, since there doesn't seem to be a column entity
689+ -- in docx.
675 let alignments = replicate width AlignDefault
690 let alignments = replicate width AlignDefault
676− widths = replicate width ColWidthDefault
691+ totalWidth = sum grid
692+ widths = (\w -> ColWidth (fromInteger w / fromInteger totalWidth)) <$> grid
677
693
678 return $ table cap'
694 return $ table cap'
679 (zip alignments widths)
695 (zip alignments widths)
680− (TableHead nullAttr hdrCells)
696+ (TableHead nullAttr headerCells)
681− [TableBody nullAttr 0 [] cells']
697+ [TableBody nullAttr 0 [] bodyCells]
682 (TableFoot nullAttr [])
698 (TableFoot nullAttr [])
683bodyPartToBlocks (OMathPara e) =
699bodyPartToBlocks (OMathPara e) =
684 return $ para $ displayMath (writeTeX e)
700 return $ para $ displayMath (writeTeX e)
685
701
686−
687-- replace targets with generated anchors.
702-- replace targets with generated anchors.
688rewriteLink' :: PandocMonad m => Inline -> DocxContext m Inline
703rewriteLink' :: PandocMonad m => Inline -> DocxContext m Inline
689rewriteLink' l@(Link attr ils (T.uncons -> Just ('#',target), title)) = do
704rewriteLink' l@(Link attr ils (T.uncons -> Just ('#',target), title)) = do
@@ -719,6 +734,8 @@ bodyToOutput :: PandocMonad m => Body -> DocxContext m (Meta, [Block])
719bodyToOutput (Body bps) = do
734bodyToOutput (Body bps) = do
720 let (metabps, blkbps) = sepBodyParts bps
735 let (metabps, blkbps) = sepBodyParts bps
721 meta <- bodyPartsToMeta metabps
736 meta <- bodyPartsToMeta metabps
737+ captions <- catMaybes <$> mapM bodyPartToTableCaption blkbps
738+ modify (\s -> s { docxTableCaptions = captions })
722 blks <- smushBlocks <$> mapM bodyPartToBlocks blkbps
739 blks <- smushBlocks <$> mapM bodyPartToBlocks blkbps
723 blks' <- rewriteLinks $ blocksToDefinitions $ blocksToBullets $ toList blks
740 blks' <- rewriteLinks $ blocksToDefinitions $ blocksToBullets $ toList blks
724 blks'' <- removeOrphanAnchors blks'
741 blks'' <- removeOrphanAnchors blks'
src/Text/Pandoc/Readers/Docx/Combine.hs+3−3
@@ -61,7 +61,7 @@ import Data.List
61import Data.Bifunctor
61import Data.Bifunctor
62import Data.Sequence ( ViewL (..), ViewR (..), viewl, viewr, spanr, spanl
62import Data.Sequence ( ViewL (..), ViewR (..), viewl, viewr, spanr, spanl
63 , (><), (|>) )
63 , (><), (|>) )
64−import Text.Pandoc.Builder
64+import Text.Pandoc.Builder as B
65
65
66data Modifier a = Modifier (a -> a)
66data Modifier a = Modifier (a -> a)
67 | AttrModifier (Attr -> a -> a) Attr
67 | AttrModifier (Attr -> a -> a) Attr
@@ -116,12 +116,12 @@ ilModifierAndInnards ils = case viewl $ unMany ils of
116
116
117inlinesL :: Inlines -> (Inlines, Inlines)
117inlinesL :: Inlines -> (Inlines, Inlines)
118inlinesL ils = case viewl $ unMany ils of
118inlinesL ils = case viewl $ unMany ils of
119− (s :< sq) -> (singleton s, Many sq)
119+ (s :< sq) -> (B.singleton s, Many sq)
120 _ -> (mempty, ils)
120 _ -> (mempty, ils)
121
121
122inlinesR :: Inlines -> (Inlines, Inlines)
122inlinesR :: Inlines -> (Inlines, Inlines)
123inlinesR ils = case viewr $ unMany ils of
123inlinesR ils = case viewr $ unMany ils of
124− (sq :> s) -> (Many sq, singleton s)
124+ (sq :> s) -> (Many sq, B.singleton s)
125 _ -> (ils, mempty)
125 _ -> (ils, mempty)
126
126
127combineInlines :: Inlines -> Inlines -> Inlines
127combineInlines :: Inlines -> Inlines -> Inlines
src/Text/Pandoc/Readers/Docx/Parse.hs+121−21
@@ -33,7 +33,9 @@ module Text.Pandoc.Readers.Docx.Parse ( Docx(..)
33 , ParStyle
33 , ParStyle
34 , CharStyle(cStyleData)
34 , CharStyle(cStyleData)
35 , Row(..)
35 , Row(..)
36+ , TblHeader(..)
36 , Cell(..)
37 , Cell(..)
38+ , VMerge(..)
37 , TrackedChange(..)
39 , TrackedChange(..)
38 , ChangeType(..)
40 , ChangeType(..)
39 , ChangeInfo(..)
41 , ChangeInfo(..)
@@ -50,6 +52,7 @@ module Text.Pandoc.Readers.Docx.Parse ( Docx(..)
50 , pHeading
52 , pHeading
51 , constructBogusParStyleData
53 , constructBogusParStyleData
52 , leftBiasedMergeRunStyle
54 , leftBiasedMergeRunStyle
55+ , rowsToRowspans
53 ) where
56 ) where
54import Text.Pandoc.Readers.Docx.Parse.Styles
57import Text.Pandoc.Readers.Docx.Parse.Styles
55import Codec.Archive.Zip
58import Codec.Archive.Zip
@@ -225,6 +228,7 @@ defaultParagraphStyle = ParagraphStyle { pStyle = []
225data BodyPart = Paragraph ParagraphStyle [ParPart]
228data BodyPart = Paragraph ParagraphStyle [ParPart]
226 | ListItem ParagraphStyle T.Text T.Text (Maybe Level) [ParPart]
229 | ListItem ParagraphStyle T.Text T.Text (Maybe Level) [ParPart]
227 | Tbl T.Text TblGrid TblLook [Row]
230 | Tbl T.Text TblGrid TblLook [Row]
231+ | TblCaption ParagraphStyle [ParPart]
228 | OMathPara [Exp]
232 | OMathPara [Exp]
229 deriving Show
233 deriving Show
230
234
@@ -236,12 +240,61 @@ newtype TblLook = TblLook {firstRowFormatting::Bool}
236defaultTblLook :: TblLook
240defaultTblLook :: TblLook
237defaultTblLook = TblLook{firstRowFormatting = False}
241defaultTblLook = TblLook{firstRowFormatting = False}
238
242
239−newtype Row = Row [Cell]
243+data Row = Row TblHeader [Cell] deriving Show
240− deriving Show
244+
245+data TblHeader = HasTblHeader | NoTblHeader deriving (Show, Eq)
241
246
242−newtype Cell = Cell [BodyPart]
247+data Cell = Cell GridSpan VMerge [BodyPart]
243 deriving Show
248 deriving Show
244
249
250+type GridSpan = Integer
251+
252+data VMerge = Continue
253+ -- ^ This cell should be merged with the one above it
254+ | Restart
255+ -- ^ This cell should not be merged with the one above it
256+ deriving (Show, Eq)
257+
258+rowsToRowspans :: [Row] -> [[(Int, Cell)]]
259+rowsToRowspans rows = let
260+ removeMergedCells = fmap (filter (\(_, Cell _ vmerge _) -> vmerge == Restart))
261+ in removeMergedCells (foldr f [] rows)
262+ where
263+ f :: Row -> [[(Int, Cell)]] -> [[(Int, Cell)]]
264+ f (Row _ cells) acc = let
265+ spans = g cells Nothing (listToMaybe acc)
266+ in spans : acc
267+
268+ g ::
269+ -- | The current row
270+ [Cell] ->
271+ -- | Number of columns left below
272+ Maybe Integer ->
273+ -- | (rowspan so far, cell) for the row below this one
274+ Maybe [(Int, Cell)] ->
275+ -- | (rowspan so far, cell) for this row
276+ [(Int, Cell)]
277+ g cells _ Nothing = zip (repeat 1) cells
278+ g cells columnsLeftBelow (Just rowBelow) =
279+ case cells of
280+ [] -> []
281+ thisCell@(Cell thisGridSpan _ _) : restOfRow -> case rowBelow of
282+ [] -> zip (repeat 1) cells
283+ (spanSoFarBelow, Cell gridSpanBelow vmerge _) : _ ->
284+ let spanSoFar = case vmerge of
285+ Restart -> 1
286+ Continue -> 1 + spanSoFarBelow
287+ columnsToDrop = thisGridSpan + (gridSpanBelow - fromMaybe gridSpanBelow columnsLeftBelow)
288+ (newColumnsLeftBelow, restOfRowBelow) = dropColumns columnsToDrop rowBelow
289+ in (spanSoFar, thisCell) : g restOfRow (Just newColumnsLeftBelow) (Just restOfRowBelow)
290+
291+ dropColumns :: Integer -> [(a, Cell)] -> (Integer, [(a, Cell)])
292+ dropColumns n [] = (n, [])
293+ dropColumns n cells@((_, Cell gridSpan _ _) : otherCells) =
294+ if n < gridSpan
295+ then (gridSpan - n, cells)
296+ else dropColumns (n - gridSpan) otherCells
297+
245leftBiasedMergeRunStyle :: RunStyle -> RunStyle -> RunStyle
298leftBiasedMergeRunStyle :: RunStyle -> RunStyle -> RunStyle
246leftBiasedMergeRunStyle a b = RunStyle
299leftBiasedMergeRunStyle a b = RunStyle
247 { isBold = isBold a <|> isBold b
300 { isBold = isBold a <|> isBold b
@@ -426,20 +479,26 @@ filePathToRelType path docXmlPath =
426 then Just InDocument
479 then Just InDocument
427 else Nothing
480 else Nothing
428
481
429−relElemToRelationship :: DocumentLocation -> Element -> Maybe Relationship
482+relElemToRelationship :: FilePath -> DocumentLocation -> Element
483+ -> Maybe Relationship
430−relElemToRelationship relType element | qName (elName element) == "Relationship" =
484+relElemToRelationship fp relType element | qName (elName element) == "Relationship" =
431 do
485 do
432 relId <- findAttr (QName "Id" Nothing Nothing) element
486 relId <- findAttr (QName "Id" Nothing Nothing) element
433 target <- findAttr (QName "Target" Nothing Nothing) element
487 target <- findAttr (QName "Target" Nothing Nothing) element
488+ -- target may be relative (media/image1.jpeg) or absolute
489+ -- (/word/media/image1.jpeg); we need to relativize it (see #7374)
490+ let frontOfFp = T.pack $ takeWhile (/= '_') fp
491+ let target' = fromMaybe target $
492+ T.stripPrefix frontOfFp $ T.dropWhile (== '/') target
434− return $ Relationship relType relId target
493+ return $ Relationship relType relId target'
435−relElemToRelationship _ _ = Nothing
494+relElemToRelationship _ _ _ = Nothing
436
495
437filePathToRelationships :: Archive -> FilePath -> FilePath -> [Relationship]
496filePathToRelationships :: Archive -> FilePath -> FilePath -> [Relationship]
438filePathToRelationships ar docXmlPath fp
497filePathToRelationships ar docXmlPath fp
439 | Just relType <- filePathToRelType fp docXmlPath
498 | Just relType <- filePathToRelType fp docXmlPath
440 , Just entry <- findEntryByPath fp ar
499 , Just entry <- findEntryByPath fp ar
441 , Just relElems <- parseXMLFromEntry entry =
500 , Just relElems <- parseXMLFromEntry entry =
442− mapMaybe (relElemToRelationship relType) $ elChildren relElems
501+ mapMaybe (relElemToRelationship fp relType) $ elChildren relElems
443filePathToRelationships _ _ _ = []
502filePathToRelationships _ _ _ = []
444
503
445archiveToRelationships :: Archive -> FilePath -> [Relationship]
504archiveToRelationships :: Archive -> FilePath -> [Relationship]
@@ -563,7 +622,7 @@ elemToTblGrid :: NameSpaces -> Element -> D TblGrid
563elemToTblGrid ns element | isElem ns "w" "tblGrid" element =
622elemToTblGrid ns element | isElem ns "w" "tblGrid" element =
564 let cols = findChildrenByName ns "w" "gridCol" element
623 let cols = findChildrenByName ns "w" "gridCol" element
565 in
624 in
566− mapD (\e -> maybeToD (findAttrByName ns "w" "val" e >>= stringToInteger))
625+ mapD (\e -> maybeToD (findAttrByName ns "w" "w" e >>= stringToInteger))
567 cols
626 cols
568elemToTblGrid _ _ = throwError WrongElem
627elemToTblGrid _ _ = throwError WrongElem
569
628
@@ -587,14 +646,31 @@ elemToRow ns element | isElem ns "w" "tr" element =
587 do
646 do
588 let cellElems = findChildrenByName ns "w" "tc" element
647 let cellElems = findChildrenByName ns "w" "tc" element
589 cells <- mapD (elemToCell ns) cellElems
648 cells <- mapD (elemToCell ns) cellElems
649+ let hasTblHeader = maybe NoTblHeader (const HasTblHeader)
650+ (findChildByName ns "w" "trPr" element
651+ >>= findChildByName ns "w" "tblHeader")
590− return $ Row cells
652+ return $ Row hasTblHeader cells
591elemToRow _ _ = throwError WrongElem
653elemToRow _ _ = throwError WrongElem
592
654
593elemToCell :: NameSpaces -> Element -> D Cell
655elemToCell :: NameSpaces -> Element -> D Cell
594elemToCell ns element | isElem ns "w" "tc" element =
656elemToCell ns element | isElem ns "w" "tc" element =
595 do
657 do
658+ let properties = findChildByName ns "w" "tcPr" element
659+ let gridSpan = properties
660+ >>= findChildByName ns "w" "gridSpan"
661+ >>= findAttrByName ns "w" "val"
662+ >>= stringToInteger
663+ let vMerge = case properties >>= findChildByName ns "w" "vMerge" of
664+ Nothing -> Restart
665+ Just e ->
666+ fromMaybe Continue $ do
667+ s <- findAttrByName ns "w" "val" e
668+ case s of
669+ "continue" -> Just Continue
670+ "restart" -> Just Restart
671+ _ -> Nothing
596 cellContents <- mapD (elemToBodyPart ns) (elChildren element)
672 cellContents <- mapD (elemToBodyPart ns) (elChildren element)
597− return $ Cell cellContents
673+ return $ Cell (fromMaybe 1 gridSpan) vMerge cellContents
598elemToCell _ _ = throwError WrongElem
674elemToCell _ _ = throwError WrongElem
599
675
600elemToParIndentation :: NameSpaces -> Element -> Maybe ParIndentation
676elemToParIndentation :: NameSpaces -> Element -> Maybe ParIndentation
@@ -626,10 +702,9 @@ pNumInfo = getParStyleField numInfo . pStyle
626elemToBodyPart :: NameSpaces -> Element -> D BodyPart
702elemToBodyPart :: NameSpaces -> Element -> D BodyPart
627elemToBodyPart ns element
703elemToBodyPart ns element
628 | isElem ns "w" "p" element
704 | isElem ns "w" "p" element
629− , (c:_) <- findChildrenByName ns "m" "oMathPara" element =
705+ , (c:_) <- findChildrenByName ns "m" "oMathPara" element = do
630− do
631− expsLst <- eitherToD $ readOMML $ showElement c
706+ expsLst <- eitherToD $ readOMML $ showElement c
632− return $ OMathPara expsLst
707+ return $ OMathPara expsLst
633elemToBodyPart ns element
708elemToBodyPart ns element
634 | isElem ns "w" "p" element
709 | isElem ns "w" "p" element
635 , Just (numId, lvl) <- getNumInfo ns element = do
710 , Just (numId, lvl) <- getNumInfo ns element = do
@@ -647,13 +722,31 @@ elemToBodyPart ns element
647 Nothing | Just (numId, lvl) <- pNumInfo parstyle -> do
722 Nothing | Just (numId, lvl) <- pNumInfo parstyle -> do
648 levelInfo <- lookupLevel numId lvl <$> asks envNumbering
723 levelInfo <- lookupLevel numId lvl <$> asks envNumbering
649 return $ ListItem parstyle numId lvl levelInfo parparts
724 return $ ListItem parstyle numId lvl levelInfo parparts
725+ _ -> let
726+ hasCaptionStyle = elem "Caption" (pStyleId <$> pStyle parstyle)
727+
728+ hasSimpleTableField = fromMaybe False $ do
729+ fldSimple <- findChildByName ns "w" "fldSimple" element
730+ instr <- findAttrByName ns "w" "instr" fldSimple
731+ pure ("Table" `elem` T.words instr)
732+
733+ hasComplexTableField = fromMaybe False $ do
734+ instrText <- findElementByName ns "w" "instrText" element
735+ pure ("Table" `elem` T.words (strContent instrText))
736+
737+ in if hasCaptionStyle && (hasSimpleTableField || hasComplexTableField)
738+ then return $ TblCaption parstyle parparts
650− _ -> return $ Paragraph parstyle parparts
739+ else return $ Paragraph parstyle parparts
740+
651elemToBodyPart ns element
741elemToBodyPart ns element
652 | isElem ns "w" "tbl" element = do
742 | isElem ns "w" "tbl" element = do
653− let caption' = findChildByName ns "w" "tblPr" element
743+ let tblProperties = findChildByName ns "w" "tblPr" element
744+ caption = fromMaybe "" $ tblProperties
654 >>= findChildByName ns "w" "tblCaption"
745 >>= findChildByName ns "w" "tblCaption"
655 >>= findAttrByName ns "w" "val"
746 >>= findAttrByName ns "w" "val"
656− caption = fromMaybe "" caption'
747+ description = fromMaybe "" $ tblProperties
748+ >>= findChildByName ns "w" "tblDescription"
749+ >>= findAttrByName ns "w" "val"
657 grid' = case findChildByName ns "w" "tblGrid" element of
750 grid' = case findChildByName ns "w" "tblGrid" element of
658 Just g -> elemToTblGrid ns g
751 Just g -> elemToTblGrid ns g
659 Nothing -> return []
752 Nothing -> return []
@@ -666,7 +759,7 @@ elemToBodyPart ns element
666 grid <- grid'
759 grid <- grid'
667 tblLook <- tblLook'
760 tblLook <- tblLook'
668 rows <- mapD (elemToRow ns) (elChildren element)
761 rows <- mapD (elemToRow ns) (elChildren element)
669− return $ Tbl caption grid tblLook rows
762+ return $ Tbl (caption <> description) grid tblLook rows
670elemToBodyPart _ _ = throwError WrongElem
763elemToBodyPart _ _ = throwError WrongElem
671
764
672lookupRelationship :: DocumentLocation -> RelId -> [Relationship] -> Maybe Target
765lookupRelationship :: DocumentLocation -> RelId -> [Relationship] -> Maybe Target
@@ -709,7 +802,8 @@ elemToParPart ns element
709 case drawing of
802 case drawing of
710 Just s -> expandDrawingId s >>= (\(fp, bs) -> return $ Drawing fp title alt bs $ elemToExtent drawingElem)
803 Just s -> expandDrawingId s >>= (\(fp, bs) -> return $ Drawing fp title alt bs $ elemToExtent drawingElem)
711 Nothing -> throwError WrongElem
804 Nothing -> throwError WrongElem
712−-- The below is an attempt to deal with images in deprecated vml format.
805+-- The two cases below are an attempt to deal with images in deprecated vml format.
806+-- Todo: check out title and attr for deprecated format.
713elemToParPart ns element
807elemToParPart ns element
714 | isElem ns "w" "r" element
808 | isElem ns "w" "r" element
715 , Just _ <- findChildByName ns "w" "pict" element =
809 , Just _ <- findChildByName ns "w" "pict" element =
@@ -717,9 +811,15 @@ elemToParPart ns element
717 >>= findAttrByName ns "r" "id"
811 >>= findAttrByName ns "r" "id"
718 in
812 in
719 case drawing of
813 case drawing of
720− -- Todo: check out title and attr for deprecated format.
721 Just s -> expandDrawingId s >>= (\(fp, bs) -> return $ Drawing fp "" "" bs Nothing)
814 Just s -> expandDrawingId s >>= (\(fp, bs) -> return $ Drawing fp "" "" bs Nothing)
722 Nothing -> throwError WrongElem
815 Nothing -> throwError WrongElem
816+elemToParPart ns element
817+ | isElem ns "w" "r" element
818+ , Just objectElem <- findChildByName ns "w" "object" element
819+ , Just shapeElem <- findChildByName ns "v" "shape" objectElem
820+ , Just imagedataElem <- findChildByName ns "v" "imagedata" shapeElem
821+ , Just drawingId <- findAttrByName ns "r" "id" imagedataElem
822+ = expandDrawingId drawingId >>= (\(fp, bs) -> return $ Drawing fp "" "" bs Nothing)
723-- Chart
823-- Chart
724elemToParPart ns element
824elemToParPart ns element
725 | isElem ns "w" "r" element
825 | isElem ns "w" "r" element
src/Text/Pandoc/Readers/Docx/Util.hs+7
@@ -19,6 +19,7 @@ module Text.Pandoc.Readers.Docx.Util (
19 , elemToNameSpaces
19 , elemToNameSpaces
20 , findChildByName
20 , findChildByName
21 , findChildrenByName
21 , findChildrenByName
22+ , findElementByName
22 , findAttrByName
23 , findAttrByName
23 ) where
24 ) where
24
25
@@ -56,6 +57,12 @@ findChildrenByName ns pref name el =
56 let ns' = ns <> elemToNameSpaces el
57 let ns' = ns <> elemToNameSpaces el
57 in findChildren (elemName ns' pref name) el
58 in findChildren (elemName ns' pref name) el
58
59
60+-- | Like 'findChildrenByName', but searches descendants.
61+findElementByName :: NameSpaces -> Text -> Text -> Element -> Maybe Element
62+findElementByName ns pref name el =
63+ let ns' = ns <> elemToNameSpaces el
64+ in findElement (elemName ns' pref name) el
65+
59findAttrByName :: NameSpaces -> Text -> Text -> Element -> Maybe Text
66findAttrByName :: NameSpaces -> Text -> Text -> Element -> Maybe Text
60findAttrByName ns pref name el =
67findAttrByName ns pref name el =
61 let ns' = ns <> elemToNameSpaces el
68 let ns' = ns <> elemToNameSpaces el
src/Text/Pandoc/Readers/DokuWiki.hs+9−8
@@ -29,26 +29,27 @@ import Text.Pandoc.Definition
29import Text.Pandoc.Error (PandocError (PandocParsecError))
29import Text.Pandoc.Error (PandocError (PandocParsecError))
30import Text.Pandoc.Options
30import Text.Pandoc.Options
31import Text.Pandoc.Parsing hiding (enclosed, nested)
31import Text.Pandoc.Parsing hiding (enclosed, nested)
32−import Text.Pandoc.Shared (crFilter, trim, stringify, tshow)
32+import Text.Pandoc.Shared (trim, stringify, tshow)
33
33
34-- | Read DokuWiki from an input string and return a Pandoc document.
34-- | Read DokuWiki from an input string and return a Pandoc document.
35−readDokuWiki :: PandocMonad m
35+readDokuWiki :: (PandocMonad m, ToSources a)
36 => ReaderOptions
36 => ReaderOptions
37− -> Text
37+ -> a
38 -> m Pandoc
38 -> m Pandoc
39readDokuWiki opts s = do
39readDokuWiki opts s = do
40− let input = crFilter s
40+ let sources = toSources s
41− res <- runParserT parseDokuWiki def {stateOptions = opts } "source" input
41+ res <- runParserT parseDokuWiki def {stateOptions = opts }
42+ (initialSourceName sources) sources
42 case res of
43 case res of
43− Left e -> throwError $ PandocParsecError input e
44+ Left e -> throwError $ PandocParsecError sources e
44 Right d -> return d
45 Right d -> return d
45
46
46−type DWParser = ParserT Text ParserState
47+type DWParser = ParserT Sources ParserState
47
48
48-- * Utility functions
49-- * Utility functions
49
50
50-- | Parse end-of-line, which can be either a newline or end-of-file.
51-- | Parse end-of-line, which can be either a newline or end-of-file.
51−eol :: Stream s m Char => ParserT s st m ()
52+eol :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m ()
52eol = void newline <|> eof
53eol = void newline <|> eof
53
54
54nested :: PandocMonad m => DWParser m a -> DWParser m a
55nested :: PandocMonad m => DWParser m a -> DWParser m a
src/Text/Pandoc/Readers/FB2.hs+6−3
@@ -40,9 +40,9 @@ import Text.Pandoc.Class.PandocMonad (PandocMonad, insertMedia, report)
40import Text.Pandoc.Error
40import Text.Pandoc.Error
41import Text.Pandoc.Logging
41import Text.Pandoc.Logging
42import Text.Pandoc.Options
42import Text.Pandoc.Options
43−import Text.Pandoc.Shared (crFilter)
44import Text.Pandoc.XML.Light
43import Text.Pandoc.XML.Light
45import qualified Text.Pandoc.UTF8 as UTF8
44import qualified Text.Pandoc.UTF8 as UTF8
45+import Text.Pandoc.Sources (ToSources(..), sourcesToText)
46
46
47type FB2 m = StateT FB2State m
47type FB2 m = StateT FB2State m
48
48
@@ -63,9 +63,12 @@ instance HasMeta FB2State where
63 setMeta field v s = s {fb2Meta = setMeta field v (fb2Meta s)}
63 setMeta field v s = s {fb2Meta = setMeta field v (fb2Meta s)}
64 deleteMeta field s = s {fb2Meta = deleteMeta field (fb2Meta s)}
64 deleteMeta field s = s {fb2Meta = deleteMeta field (fb2Meta s)}
65
65
66−readFB2 :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
66+readFB2 :: (PandocMonad m, ToSources a)
67+ => ReaderOptions
68+ -> a
69+ -> m Pandoc
67readFB2 _ inp =
70readFB2 _ inp =
68− case parseXMLElement $ TL.fromStrict $ crFilter inp of
71+ case parseXMLElement $ TL.fromStrict $ sourcesToText $ toSources inp of
69 Left msg -> throwError $ PandocXMLError "" msg
72 Left msg -> throwError $ PandocXMLError "" msg
70 Right el -> do
73 Right el -> do
71 (bs, st) <- runStateT (parseRootElement el) def
74 (bs, st) <- runStateT (parseRootElement el) def
src/Text/Pandoc/Readers/HTML.hs+43−27
@@ -62,21 +62,21 @@ import Text.Pandoc.Options (
62 extensionEnabled)
62 extensionEnabled)
63import Text.Pandoc.Parsing hiding ((<|>))
63import Text.Pandoc.Parsing hiding ((<|>))
64import Text.Pandoc.Shared (
64import Text.Pandoc.Shared (
65− addMetaField, blocksToInlines', crFilter, escapeURI, extractSpaces,
65+ addMetaField, blocksToInlines', escapeURI, extractSpaces,
66 htmlSpanLikeElements, renderTags', safeRead, tshow)
66 htmlSpanLikeElements, renderTags', safeRead, tshow)
67import Text.Pandoc.Walk
67import Text.Pandoc.Walk
68import Text.Parsec.Error
68import Text.Parsec.Error
69import Text.TeXMath (readMathML, writeTeX)
69import Text.TeXMath (readMathML, writeTeX)
70
70
71-- | Convert HTML-formatted string to 'Pandoc' document.
71-- | Convert HTML-formatted string to 'Pandoc' document.
72−readHtml :: PandocMonad m
72+readHtml :: (PandocMonad m, ToSources a)
73 => ReaderOptions -- ^ Reader options
73 => ReaderOptions -- ^ Reader options
74− -> Text -- ^ String to parse (assumes @'\n'@ line endings)
74+ -> a -- ^ Input to parse
75 -> m Pandoc
75 -> m Pandoc
76readHtml opts inp = do
76readHtml opts inp = do
77 let tags = stripPrefixes $ canonicalizeTags $
77 let tags = stripPrefixes $ canonicalizeTags $
78 parseTagsOptions parseOptions{ optTagPosition = True }
78 parseTagsOptions parseOptions{ optTagPosition = True }
79− (crFilter inp)
79+ (sourcesToText $ toSources inp)
80 parseDoc = do
80 parseDoc = do
81 blocks <- fixPlains False . mconcat <$> manyTill block eof
81 blocks <- fixPlains False . mconcat <$> manyTill block eof
82 meta <- stateMeta . parserState <$> getState
82 meta <- stateMeta . parserState <$> getState
@@ -205,6 +205,7 @@ block = ((do
205 | otherwise
205 | otherwise
206 -> pDiv
206 -> pDiv
207 "section" -> pDiv
207 "section" -> pDiv
208+ "header" -> pDiv
208 "main" -> pDiv
209 "main" -> pDiv
209 "figure" -> pFigure
210 "figure" -> pFigure
210 "iframe" -> pIframe
211 "iframe" -> pIframe
@@ -404,6 +405,7 @@ pLineBlock = try $ do
404isDivLike :: Text -> Bool
405isDivLike :: Text -> Bool
405isDivLike "div" = True
406isDivLike "div" = True
406isDivLike "section" = True
407isDivLike "section" = True
408+isDivLike "header" = True
407isDivLike "main" = True
409isDivLike "main" = True
408isDivLike _ = False
410isDivLike _ = False
409
411
@@ -499,17 +501,13 @@ pHeader = try $ do
499 tagOpen (`elem` ["h1","h2","h3","h4","h5","h6"])
501 tagOpen (`elem` ["h1","h2","h3","h4","h5","h6"])
500 (const True)
502 (const True)
501 let attr = toStringAttr attr'
503 let attr = toStringAttr attr'
502− let bodyTitle = TagOpen tagtype attr' ~== TagOpen ("h1" :: Text)
503− [("class","title")]
504 level <- headerLevel tagtype
504 level <- headerLevel tagtype
505 contents <- trimInlines . mconcat <$> manyTill inline (pCloses tagtype <|> eof)
505 contents <- trimInlines . mconcat <$> manyTill inline (pCloses tagtype <|> eof)
506 let ident = fromMaybe "" $ lookup "id" attr
506 let ident = fromMaybe "" $ lookup "id" attr
507 let classes = maybe [] T.words $ lookup "class" attr
507 let classes = maybe [] T.words $ lookup "class" attr
508 let keyvals = [(k,v) | (k,v) <- attr, k /= "class", k /= "id"]
508 let keyvals = [(k,v) | (k,v) <- attr, k /= "class", k /= "id"]
509 attr'' <- registerHeader (ident, classes, keyvals) contents
509 attr'' <- registerHeader (ident, classes, keyvals) contents
510− return $ if bodyTitle
511− then mempty -- skip a representation of the title in the body
512− else B.headerWith attr'' level contents
510+ return $ B.headerWith attr'' level contents
513
511
514pHrule :: PandocMonad m => TagParser m Blocks
512pHrule :: PandocMonad m => TagParser m Blocks
515pHrule = do
513pHrule = do
@@ -559,7 +557,18 @@ pFigure = try $ do
559pCodeBlock :: PandocMonad m => TagParser m Blocks
557pCodeBlock :: PandocMonad m => TagParser m Blocks
560pCodeBlock = try $ do
558pCodeBlock = try $ do
561 TagOpen _ attr' <- pSatisfy (matchTagOpen "pre" [])
559 TagOpen _ attr' <- pSatisfy (matchTagOpen "pre" [])
562− let attr = toAttr attr'
560+ -- if the `pre` has no attributes, try if it is followed by a `code`
561+ -- element and use those attributes if possible.
562+ attr <- case attr' of
563+ _:_ -> pure (toAttr attr')
564+ [] -> option nullAttr $ do
565+ TagOpen _ codeAttr <- pSatisfy (matchTagOpen "code" [])
566+ pure $ toAttr
567+ [ (k, v') | (k, v) <- codeAttr
568+ -- strip language from class
569+ , let v' = if k == "class"
570+ then fromMaybe v (T.stripPrefix "language-" v)
571+ else v ]
563 contents <- manyTill pAny (pCloses "pre" <|> eof)
572 contents <- manyTill pAny (pCloses "pre" <|> eof)
564 let rawText = T.concat $ map tagToText contents
573 let rawText = T.concat $ map tagToText contents
565 -- drop leading newline if any
574 -- drop leading newline if any
@@ -830,17 +839,19 @@ pInlinesInTags tagtype f = extractSpaces f <$> pInTags tagtype inline
830
839
831pTagText :: PandocMonad m => TagParser m Inlines
840pTagText :: PandocMonad m => TagParser m Inlines
832pTagText = try $ do
841pTagText = try $ do
842+ pos <- getPosition
833 (TagText str) <- pSatisfy isTagText
843 (TagText str) <- pSatisfy isTagText
834 st <- getState
844 st <- getState
835 qu <- ask
845 qu <- ask
836 parsed <- lift $ lift $
846 parsed <- lift $ lift $
837− flip runReaderT qu $ runParserT (many pTagContents) st "text" str
847+ flip runReaderT qu $ runParserT (many pTagContents) st "text"
848+ (Sources [(pos, str)])
838 case parsed of
849 case parsed of
839 Left _ -> throwError $ PandocParseError $
850 Left _ -> throwError $ PandocParseError $
840 "Could not parse `" <> str <> "'"
851 "Could not parse `" <> str <> "'"
841 Right result -> return $ mconcat result
852 Right result -> return $ mconcat result
842
853
843−type InlinesParser m = HTMLParser m Text
854+type InlinesParser m = HTMLParser m Sources
844
855
845pTagContents :: PandocMonad m => InlinesParser m Inlines
856pTagContents :: PandocMonad m => InlinesParser m Inlines
846pTagContents =
857pTagContents =
@@ -940,13 +951,15 @@ getTagName (TagClose t) = Just t
940getTagName _ = Nothing
951getTagName _ = Nothing
941
952
942isInlineTag :: Tag Text -> Bool
953isInlineTag :: Tag Text -> Bool
943−isInlineTag t =
944− isCommentTag t ||
954+isInlineTag t = isCommentTag t || case t of
945− case getTagName t of
946− Nothing -> False
947− Just "script" -> "math/tex" `T.isPrefixOf` fromAttrib "type" t
955+ TagOpen "script" _ -> "math/tex" `T.isPrefixOf` fromAttrib "type" t
956+ TagClose "script" -> True
957+ TagOpen name _ -> isInlineTagName name
958+ TagClose name -> isInlineTagName name
959+ _ -> False
960+ where isInlineTagName x =
948− Just x -> x `Set.notMember` blockTags ||
961+ x `Set.notMember` blockTags ||
949− T.take 1 x == "?" -- processing instr.
962+ T.take 1 x == "?" -- processing instr.
950
963
951isBlockTag :: Tag Text -> Bool
964isBlockTag :: Tag Text -> Bool
952isBlockTag t = isBlockTagName || isTagComment t
965isBlockTag t = isBlockTagName || isTagComment t
@@ -970,13 +983,14 @@ isCommentTag = tagComment (const True)
970-- | Matches a stretch of HTML in balanced tags.
983-- | Matches a stretch of HTML in balanced tags.
971htmlInBalanced :: Monad m
984htmlInBalanced :: Monad m
972 => (Tag Text -> Bool)
985 => (Tag Text -> Bool)
973− -> ParserT Text st m Text
986+ -> ParserT Sources st m Text
974htmlInBalanced f = try $ do
987htmlInBalanced f = try $ do
975 lookAhead (char '<')
988 lookAhead (char '<')
976− inp <- getInput
989+ sources <- getInput
977− let ts = canonicalizeTags $
990+ let ts = canonicalizeTags
978− parseTagsOptions parseOptions{ optTagWarning = True,
991+ $ parseTagsOptions parseOptions{ optTagWarning = True,
979− optTagPosition = True } inp
992+ optTagPosition = True }
993+ $ sourcesToText sources
980 case ts of
994 case ts of
981 (TagPosition sr sc : t@(TagOpen tn _) : rest) -> do
995 (TagPosition sr sc : t@(TagOpen tn _) : rest) -> do
982 guard $ f t
996 guard $ f t
@@ -1018,15 +1032,17 @@ hasTagWarning _ = False
1018-- | Matches a tag meeting a certain condition.
1032-- | Matches a tag meeting a certain condition.
1019htmlTag :: (HasReaderOptions st, Monad m)
1033htmlTag :: (HasReaderOptions st, Monad m)
1020 => (Tag Text -> Bool)
1034 => (Tag Text -> Bool)
1021− -> ParserT Text st m (Tag Text, Text)
1035+ -> ParserT Sources st m (Tag Text, Text)
1022htmlTag f = try $ do
1036htmlTag f = try $ do
1023 lookAhead (char '<')
1037 lookAhead (char '<')
1024 startpos <- getPosition
1038 startpos <- getPosition
1025− inp <- getInput
1039+ sources <- getInput
1040+ let inp = sourcesToText sources
1026 let ts = canonicalizeTags $ parseTagsOptions
1041 let ts = canonicalizeTags $ parseTagsOptions
1027 parseOptions{ optTagWarning = False
1042 parseOptions{ optTagWarning = False
1028 , optTagPosition = True }
1043 , optTagPosition = True }
1044+ (inp <> " ")
1029− (inp <> " ") -- add space to ensure that
1045+ -- add space to ensure that
1030 -- we get a TagPosition after the tag
1046 -- we get a TagPosition after the tag
1031 (next, ln, col) <- case ts of
1047 (next, ln, col) <- case ts of
1032 (TagPosition{} : next : TagPosition ln col : _)
1048 (TagPosition{} : next : TagPosition ln col : _)
src/Text/Pandoc/Readers/HTML/Table.hs+35−15
@@ -17,6 +17,8 @@ module Text.Pandoc.Readers.HTML.Table (pTable) where
17
17
18import Control.Applicative ((<|>))
18import Control.Applicative ((<|>))
19import Data.Maybe (fromMaybe)
19import Data.Maybe (fromMaybe)
20+import Data.Either (lefts, rights)
21+import Data.List.NonEmpty (nonEmpty)
20import Data.Text (Text)
22import Data.Text (Text)
21import Text.HTML.TagSoup
23import Text.HTML.TagSoup
22import Text.Pandoc.Builder (Blocks)
24import Text.Pandoc.Builder (Blocks)
@@ -32,34 +34,51 @@ import Text.Pandoc.Shared (onlySimpleTableCells, safeRead)
32import qualified Data.Text as T
34import qualified Data.Text as T
33import qualified Text.Pandoc.Builder as B
35import qualified Text.Pandoc.Builder as B
34
36
35−-- | Parses a @<col>@ element, returning the column's width. Defaults to
37+-- | Parses a @<col>@ element, returning the column's width.
38+-- An Either value is used: Left i means a "relative length" with
39+-- integral value i (see https://www.w3.org/TR/html4/types.html#h-6.6);
40+-- Right w means a regular width. Defaults to @'Right ColWidthDefault'@
36−-- @'ColWidthDefault'@ if the width is not set or cannot be determined.
41+-- if the width is not set or cannot be determined.
37−pCol :: PandocMonad m => TagParser m ColWidth
42+pCol :: PandocMonad m => TagParser m (Either Int ColWidth)
38pCol = try $ do
43pCol = try $ do
39 TagOpen _ attribs' <- pSatisfy (matchTagOpen "col" [])
44 TagOpen _ attribs' <- pSatisfy (matchTagOpen "col" [])
40 let attribs = toStringAttr attribs'
45 let attribs = toStringAttr attribs'
41 skipMany pBlank
46 skipMany pBlank
42 optional $ pSatisfy (matchTagClose "col")
47 optional $ pSatisfy (matchTagClose "col")
43 skipMany pBlank
48 skipMany pBlank
44− let width = case lookup "width" attribs of
49+ return $ case lookup "width" attribs of
45 Nothing -> case lookup "style" attribs of
50 Nothing -> case lookup "style" attribs of
46 Just (T.stripPrefix "width:" -> Just xs) | T.any (== '%') xs ->
51 Just (T.stripPrefix "width:" -> Just xs) | T.any (== '%') xs ->
52+ maybe (Right ColWidthDefault) (Right . ColWidth . (/ 100.0))
47− fromMaybe 0.0 $ safeRead (T.filter
53+ $ safeRead (T.filter
48− (`notElem` (" \t\r\n%'\";" :: [Char])) xs)
54+ (`notElem` (" \t\r\n%'\";" :: [Char])) xs)
49− _ -> 0.0
55+ _ -> Right ColWidthDefault
56+ Just (T.unsnoc -> Just (xs, '*')) ->
57+ maybe (Left 1) Left $ safeRead xs
50 Just (T.unsnoc -> Just (xs, '%')) ->
58 Just (T.unsnoc -> Just (xs, '%')) ->
59+ maybe (Right ColWidthDefault)
51− fromMaybe 0.0 $ safeRead xs
60+ (Right . ColWidth . (/ 100.0)) $ safeRead xs
52− _ -> 0.0
53− if width > 0.0
54− then return $ ColWidth $ width / 100.0
55− else return ColWidthDefault
61+ _ -> Right ColWidthDefault
56
62
57−pColgroup :: PandocMonad m => TagParser m [ColWidth]
63+pColgroup :: PandocMonad m => TagParser m [Either Int ColWidth]
58pColgroup = try $ do
64pColgroup = try $ do
59 pSatisfy (matchTagOpen "colgroup" [])
65 pSatisfy (matchTagOpen "colgroup" [])
60 skipMany pBlank
66 skipMany pBlank
61 manyTill pCol (pCloses "colgroup" <|> eof) <* skipMany pBlank
67 manyTill pCol (pCloses "colgroup" <|> eof) <* skipMany pBlank
62
68
69+resolveRelativeLengths :: [Either Int ColWidth] -> [ColWidth]
70+resolveRelativeLengths ws =
71+ let remaining = 1 - sum (map getColWidth $ rights ws)
72+ relatives = sum $ lefts ws
73+ relUnit = remaining / fromIntegral relatives
74+ toColWidth (Right x) = x
75+ toColWidth (Left i) = ColWidth (fromIntegral i * relUnit)
76+ in map toColWidth ws
77+
78+getColWidth :: ColWidth -> Double
79+getColWidth ColWidthDefault = 0
80+getColWidth (ColWidth w) = w
81+
63data CellType
82data CellType
64 = HeaderCell
83 = HeaderCell
65 | BodyCell
84 | BodyCell
@@ -181,7 +200,8 @@ pTable :: PandocMonad m
181pTable block = try $ do
200pTable block = try $ do
182 TagOpen _ attribs <- pSatisfy (matchTagOpen "table" []) <* skipMany pBlank
201 TagOpen _ attribs <- pSatisfy (matchTagOpen "table" []) <* skipMany pBlank
183 caption <- option mempty $ pInTags "caption" block <* skipMany pBlank
202 caption <- option mempty $ pInTags "caption" block <* skipMany pBlank
203+ widths <- resolveRelativeLengths <$>
184− widths <- ((mconcat <$> many1 pColgroup) <|> many pCol) <* skipMany pBlank
204+ ((mconcat <$> many1 pColgroup) <|> many pCol) <* skipMany pBlank
185 thead <- pTableHead block <* skipMany pBlank
205 thead <- pTableHead block <* skipMany pBlank
186 topfoot <- optionMaybe (pTableFoot block) <* skipMany pBlank
206 topfoot <- optionMaybe (pTableFoot block) <* skipMany pBlank
187 tbodies <- many (pTableBody block) <* skipMany pBlank
207 tbodies <- many (pTableBody block) <* skipMany pBlank
@@ -216,7 +236,7 @@ normalize widths head' bodies foot = do
216 let rows = headRows head' <> concatMap bodyRows bodies <> footRows foot
236 let rows = headRows head' <> concatMap bodyRows bodies <> footRows foot
217 let cellWidth (Cell _ _ _ (ColSpan cs) _) = cs
237 let cellWidth (Cell _ _ _ (ColSpan cs) _) = cs
218 let rowLength = foldr (\cell acc -> cellWidth cell + acc) 0 . rowCells
238 let rowLength = foldr (\cell acc -> cellWidth cell + acc) 0 . rowCells
219− let ncols = maximum (map rowLength rows)
239+ let ncols = maybe 0 maximum $ nonEmpty $ map rowLength rows
220 let tblType = tableType (map rowCells rows)
240 let tblType = tableType (map rowCells rows)
221 -- fail on empty table
241 -- fail on empty table
222 if null rows
242 if null rows
src/Text/Pandoc/Readers/Haddock.hs+11−7
@@ -17,8 +17,9 @@ module Text.Pandoc.Readers.Haddock
17
17
18import Control.Monad.Except (throwError)
18import Control.Monad.Except (throwError)
19import Data.List (intersperse)
19import Data.List (intersperse)
20+import Data.List.NonEmpty (nonEmpty)
20import Data.Maybe (fromMaybe)
21import Data.Maybe (fromMaybe)
21−import Data.Text (Text, unpack)
22+import Data.Text (unpack)
22import qualified Data.Text as T
23import qualified Data.Text as T
23import Documentation.Haddock.Parser
24import Documentation.Haddock.Parser
24import Documentation.Haddock.Types as H
25import Documentation.Haddock.Types as H
@@ -28,15 +29,17 @@ import Text.Pandoc.Class.PandocMonad (PandocMonad)
28import Text.Pandoc.Definition
29import Text.Pandoc.Definition
29import Text.Pandoc.Error
30import Text.Pandoc.Error
30import Text.Pandoc.Options
31import Text.Pandoc.Options
32+import Text.Pandoc.Sources (ToSources(..), sourcesToText)
31−import Text.Pandoc.Shared (crFilter, splitTextBy, trim)
33+import Text.Pandoc.Shared (splitTextBy, trim)
32
34
33
35
34-- | Parse Haddock markup and return a 'Pandoc' document.
36-- | Parse Haddock markup and return a 'Pandoc' document.
35−readHaddock :: PandocMonad m
37+readHaddock :: (PandocMonad m, ToSources a)
36 => ReaderOptions
38 => ReaderOptions
37− -> Text
39+ -> a
38 -> m Pandoc
40 -> m Pandoc
39−readHaddock opts s = case readHaddockEither opts (unpack (crFilter s)) of
41+readHaddock opts s = case readHaddockEither opts
42+ (unpack . sourcesToText . toSources $ s) of
40 Right result -> return result
43 Right result -> return result
41 Left e -> throwError e
44 Left e -> throwError e
42
45
@@ -92,7 +95,7 @@ docHToBlocks d' =
92 then ([], map toCells bodyRows)
95 then ([], map toCells bodyRows)
93 else (toCells (head headerRows),
96 else (toCells (head headerRows),
94 map toCells (tail headerRows ++ bodyRows))
97 map toCells (tail headerRows ++ bodyRows))
95− colspecs = replicate (maximum (map length body))
98+ colspecs = replicate (maybe 0 maximum (nonEmpty (map length body)))
96 (AlignDefault, ColWidthDefault)
99 (AlignDefault, ColWidthDefault)
97 in B.table B.emptyCaption
100 in B.table B.emptyCaption
98 colspecs
101 colspecs
@@ -128,7 +131,8 @@ docHToInlines isCode d' =
128 DocIdentifier s -> B.codeWith ("",["haskell","identifier"],[]) $ T.pack s
131 DocIdentifier s -> B.codeWith ("",["haskell","identifier"],[]) $ T.pack s
129 _ -> mempty
132 _ -> mempty
130 DocIdentifierUnchecked s -> B.codeWith ("",["haskell","identifier"],[]) $ T.pack s
133 DocIdentifierUnchecked s -> B.codeWith ("",["haskell","identifier"],[]) $ T.pack s
131− DocModule s -> B.codeWith ("",["haskell","module"],[]) $ T.pack s
134+ DocModule s -> B.codeWith ("",["haskell","module"],[]) $
135+ T.pack (modLinkName s)
132 DocWarning _ -> mempty -- TODO
136 DocWarning _ -> mempty -- TODO
133 DocEmphasis d -> B.emph (docHToInlines isCode d)
137 DocEmphasis d -> B.emph (docHToInlines isCode d)
134 DocMonospaced (DocString s) -> B.code $ T.pack s
138 DocMonospaced (DocString s) -> B.code $ T.pack s
src/Text/Pandoc/Readers/Ipynb.hs+5−3
@@ -39,10 +39,12 @@ import Data.Aeson as Aeson
39import Control.Monad.Except (throwError)
39import Control.Monad.Except (throwError)
40import Text.Pandoc.Readers.Markdown (readMarkdown)
40import Text.Pandoc.Readers.Markdown (readMarkdown)
41import qualified Text.Pandoc.UTF8 as UTF8
41import qualified Text.Pandoc.UTF8 as UTF8
42+import Text.Pandoc.Sources (ToSources(..), sourcesToText)
42
43
44+readIpynb :: (PandocMonad m, ToSources a)
43−readIpynb :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
45+ => ReaderOptions -> a -> m Pandoc
44−readIpynb opts t = do
46+readIpynb opts x = do
45− let src = BL.fromStrict (TE.encodeUtf8 t)
47+ let src = BL.fromStrict . TE.encodeUtf8 . sourcesToText $ toSources x
46 case eitherDecode src of
48 case eitherDecode src of
47 Right (notebook4 :: Notebook NbV4) -> notebookToPandoc opts notebook4
49 Right (notebook4 :: Notebook NbV4) -> notebookToPandoc opts notebook4
48 Left _ ->
50 Left _ ->
src/Text/Pandoc/Readers/JATS.hs+13−6
@@ -29,11 +29,12 @@ import Text.HTML.TagSoup.Entity (lookupEntity)
29import Text.Pandoc.Builder
29import Text.Pandoc.Builder
30import Text.Pandoc.Class.PandocMonad (PandocMonad)
30import Text.Pandoc.Class.PandocMonad (PandocMonad)
31import Text.Pandoc.Options
31import Text.Pandoc.Options
32−import Text.Pandoc.Shared (crFilter, safeRead, extractSpaces)
32+import Text.Pandoc.Shared (safeRead, extractSpaces)
33import Text.TeXMath (readMathML, writeTeX)
33import Text.TeXMath (readMathML, writeTeX)
34import Text.Pandoc.XML.Light
34import Text.Pandoc.XML.Light
35import qualified Data.Set as S (fromList, member)
35import qualified Data.Set as S (fromList, member)
36import Data.Set ((\\))
36import Data.Set ((\\))
37+import Text.Pandoc.Sources (ToSources(..), sourcesToText)
37
38
38type JATS m = StateT JATSState m
39type JATS m = StateT JATSState m
39
40
@@ -52,10 +53,14 @@ instance Default JATSState where
52 , jatsContent = [] }
53 , jatsContent = [] }
53
54
54
55
55−readJATS :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
56+readJATS :: (PandocMonad m, ToSources a)
57+ => ReaderOptions
58+ -> a
59+ -> m Pandoc
56readJATS _ inp = do
60readJATS _ inp = do
61+ let sources = toSources inp
57 tree <- either (throwError . PandocXMLError "") return $
62 tree <- either (throwError . PandocXMLError "") return $
58− parseXMLContents (TL.fromStrict $ crFilter inp)
63+ parseXMLContents (TL.fromStrict . sourcesToText $ sources)
59 (bs, st') <- flip runStateT (def{ jatsContent = tree }) $ mapM parseBlock tree
64 (bs, st') <- flip runStateT (def{ jatsContent = tree }) $ mapM parseBlock tree
60 return $ Pandoc (jatsMeta st') (toList . mconcat $ bs)
65 return $ Pandoc (jatsMeta st') (toList . mconcat $ bs)
61
66
@@ -491,7 +496,8 @@ parseInline (Elem e) =
491
496
492 "disp-formula" -> formula displayMath
497 "disp-formula" -> formula displayMath
493 "inline-formula" -> formula math
498 "inline-formula" -> formula math
499+ "math" | qURI (elName e) == Just "http://www.w3.org/1998/Math/MathML"
494− "math" | qPrefix (elName e) == Just "mml" -> return . math $ mathML e
500+ -> return . math $ mathML e
495 "tex-math" -> return . math $ textContent e
501 "tex-math" -> return . math $ textContent e
496
502
497 "email" -> return $ link ("mailto:" <> textContent e) ""
503 "email" -> return $ link ("mailto:" <> textContent e) ""
@@ -514,8 +520,9 @@ parseInline (Elem e) =
514 filterChildren isMathML whereToLook
520 filterChildren isMathML whereToLook
515 return . mconcat . take 1 . map constructor $ texMaths ++ mathMLs
521 return . mconcat . take 1 . map constructor $ texMaths ++ mathMLs
516
522
517− isMathML x = qName (elName x) == "math" &&
523+ isMathML x = qName (elName x) == "math" &&
518− qPrefix (elName x) == Just "mml"
524+ qURI (elName x) ==
525+ Just "http://www.w3.org/1998/Math/MathML"
519 removePrefix elname = elname { qPrefix = Nothing }
526 removePrefix elname = elname { qPrefix = Nothing }
520 codeWithLang = do
527 codeWithLang = do
521 let classes' = case attrValue "language" e of
528 let classes' = case attrValue "language" e of
src/Text/Pandoc/Readers/Jira.hs+11−7
@@ -20,18 +20,20 @@ import Text.Pandoc.Builder hiding (cell)
20import Text.Pandoc.Error (PandocError (PandocParseError))
20import Text.Pandoc.Error (PandocError (PandocParseError))
21import Text.Pandoc.Options (ReaderOptions)
21import Text.Pandoc.Options (ReaderOptions)
22import Text.Pandoc.Shared (stringify)
22import Text.Pandoc.Shared (stringify)
23−
23+import Text.Pandoc.Sources (ToSources(..), sourcesToText)
24import qualified Text.Jira.Markup as Jira
24import qualified Text.Jira.Markup as Jira
25
25
26-- | Read Jira wiki markup.
26-- | Read Jira wiki markup.
27−readJira :: PandocMonad m
27+readJira :: (PandocMonad m, ToSources a)
28 => ReaderOptions
28 => ReaderOptions
29− -> Text
29+ -> a
30 -> m Pandoc
30 -> m Pandoc
31−readJira _opts s = case parse s of
31+readJira _opts inp = do
32+ let sources = toSources inp
33+ case parse (sourcesToText sources) of
32− Right d -> return $ jiraToPandoc d
34+ Right d -> return $ jiraToPandoc d
33− Left e -> throwError . PandocParseError $
35+ Left e -> throwError . PandocParseError $
34− "Jira parse error" `append` pack (show e)
36+ "Jira parse error" `append` pack (show e)
35
37
36jiraToPandoc :: Jira.Doc -> Pandoc
38jiraToPandoc :: Jira.Doc -> Pandoc
37jiraToPandoc (Jira.Doc blks) = doc $ foldMap jiraToPandocBlocks blks
39jiraToPandoc (Jira.Doc blks) = doc $ foldMap jiraToPandocBlocks blks
@@ -170,6 +172,8 @@ jiraLinkToPandoc linkType alias url =
170 Jira.Email -> link ("mailto:" <> url') "" alias'
172 Jira.Email -> link ("mailto:" <> url') "" alias'
171 Jira.Attachment -> linkWith ("", ["attachment"], []) url' "" alias'
173 Jira.Attachment -> linkWith ("", ["attachment"], []) url' "" alias'
172 Jira.User -> linkWith ("", ["user-account"], []) url' "" alias'
174 Jira.User -> linkWith ("", ["user-account"], []) url' "" alias'
175+ Jira.SmartCard -> linkWith ("", ["smart-card"], []) url' "" alias'
176+ Jira.SmartLink -> linkWith ("", ["smart-link"], []) url' "" alias'
173
177
174-- | Get unicode representation of a Jira icon.
178-- | Get unicode representation of a Jira icon.
175iconUnicode :: Jira.Icon -> Text
179iconUnicode :: Jira.Icon -> Text
src/Text/Pandoc/Readers/LaTeX.hs+22−34
@@ -1,4 +1,3 @@
1−{-# LANGUAGE CPP #-}
2{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE PatternGuards #-}
2{-# LANGUAGE PatternGuards #-}
4{-# LANGUAGE ScopedTypeVariables #-}
3{-# LANGUAGE ScopedTypeVariables #-}
@@ -25,7 +24,7 @@ module Text.Pandoc.Readers.LaTeX ( readLaTeX,
25import Control.Applicative (many, optional, (<|>))
24import Control.Applicative (many, optional, (<|>))
26import Control.Monad
25import Control.Monad
27import Control.Monad.Except (throwError)
26import Control.Monad.Except (throwError)
28−import Data.Char (isDigit, isLetter, toUpper, chr)
27+import Data.Char (isDigit, isLetter, isAlphaNum, toUpper, chr)
29import Data.Default
28import Data.Default
30import Data.List (intercalate)
29import Data.List (intercalate)
31import qualified Data.Map as M
30import qualified Data.Map as M
@@ -33,8 +32,9 @@ import Data.Maybe (fromMaybe, maybeToList)
33import qualified Data.Set as Set
32import qualified Data.Set as Set
34import Data.Text (Text)
33import Data.Text (Text)
35import qualified Data.Text as T
34import qualified Data.Text as T
35+import Skylighting (defaultSyntaxMap)
36import System.FilePath (addExtension, replaceExtension, takeExtension)
36import System.FilePath (addExtension, replaceExtension, takeExtension)
37−import Text.Pandoc.BCP47 (renderLang)
37+import Text.Collate.Lang (renderLang)
38import Text.Pandoc.Builder as B
38import Text.Pandoc.Builder as B
39import Text.Pandoc.Class.PandocPure (PandocPure)
39import Text.Pandoc.Class.PandocPure (PandocPure)
40import Text.Pandoc.Class.PandocMonad (PandocMonad (..), getResourcePath,
40import Text.Pandoc.Class.PandocMonad (PandocMonad (..), getResourcePath,
@@ -69,7 +69,7 @@ import Text.Pandoc.Readers.LaTeX.Inline (acronymCommands, refCommands,
69 listingsLanguage)
69 listingsLanguage)
70import Text.Pandoc.Shared
70import Text.Pandoc.Shared
71import Text.Pandoc.Walk
71import Text.Pandoc.Walk
72−import Safe
72+import Data.List.NonEmpty (nonEmpty)
73
73
74-- for debugging:
74-- for debugging:
75-- import Text.Pandoc.Extensions (getDefaultExtensions)
75-- import Text.Pandoc.Extensions (getDefaultExtensions)
@@ -77,16 +77,17 @@ import Safe
77-- import Debug.Trace (traceShowId)
77-- import Debug.Trace (traceShowId)
78
78
79-- | Parse LaTeX from string and return 'Pandoc' document.
79-- | Parse LaTeX from string and return 'Pandoc' document.
80−readLaTeX :: PandocMonad m
80+readLaTeX :: (PandocMonad m, ToSources a)
81 => ReaderOptions -- ^ Reader options
81 => ReaderOptions -- ^ Reader options
82− -> Text -- ^ String to parse (assumes @'\n'@ line endings)
82+ -> a -- ^ Input to parse
83 -> m Pandoc
83 -> m Pandoc
84readLaTeX opts ltx = do
84readLaTeX opts ltx = do
85+ let sources = toSources ltx
85 parsed <- runParserT parseLaTeX def{ sOptions = opts } "source"
86 parsed <- runParserT parseLaTeX def{ sOptions = opts } "source"
86− (tokenize "source" (crFilter ltx))
87+ (tokenizeSources sources)
87 case parsed of
88 case parsed of
88 Right result -> return result
89 Right result -> return result
89− Left e -> throwError $ PandocParsecError ltx e
90+ Left e -> throwError $ PandocParsecError sources e
90
91
91parseLaTeX :: PandocMonad m => LP m Pandoc
92parseLaTeX :: PandocMonad m => LP m Pandoc
92parseLaTeX = do
93parseLaTeX = do
@@ -97,11 +98,7 @@ parseLaTeX = do
97 let doc' = doc bs
98 let doc' = doc bs
98 let headerLevel (Header n _ _) = [n]
99 let headerLevel (Header n _ _) = [n]
99 headerLevel _ = []
100 headerLevel _ = []
100−#if MIN_VERSION_safe(0,3,18)
101+ let bottomLevel = maybe 1 minimum $ nonEmpty $ query headerLevel doc'
101− let bottomLevel = minimumBound 1 $ query headerLevel doc'
102−#else
103− let bottomLevel = minimumDef 1 $ query headerLevel doc'
104−#endif
105 let adjustHeaders m (Header n attr ils) = Header (n+m) attr ils
102 let adjustHeaders m (Header n attr ils) = Header (n+m) attr ils
106 adjustHeaders _ x = x
103 adjustHeaders _ x = x
107 let (Pandoc _ bs') =
104 let (Pandoc _ bs') =
@@ -136,11 +133,11 @@ resolveRefs _ x = x
136
133
137
134
138rawLaTeXBlock :: (PandocMonad m, HasMacros s, HasReaderOptions s)
135rawLaTeXBlock :: (PandocMonad m, HasMacros s, HasReaderOptions s)
139− => ParserT Text s m Text
136+ => ParserT Sources s m Text
140rawLaTeXBlock = do
137rawLaTeXBlock = do
141 lookAhead (try (char '\\' >> letter))
138 lookAhead (try (char '\\' >> letter))
142 inp <- getInput
139 inp <- getInput
143− let toks = tokenize "source" inp
140+ let toks = tokenizeSources inp
144 snd <$> (rawLaTeXParser toks False (macroDef (const mempty)) blocks
141 snd <$> (rawLaTeXParser toks False (macroDef (const mempty)) blocks
145 <|> rawLaTeXParser toks True
142 <|> rawLaTeXParser toks True
146 (do choice (map controlSeq
143 (do choice (map controlSeq
@@ -167,11 +164,11 @@ beginOrEndCommand = try $ do
167 (txt <> untokenize rawargs)
164 (txt <> untokenize rawargs)
168
165
169rawLaTeXInline :: (PandocMonad m, HasMacros s, HasReaderOptions s)
166rawLaTeXInline :: (PandocMonad m, HasMacros s, HasReaderOptions s)
170− => ParserT Text s m Text
167+ => ParserT Sources s m Text
171rawLaTeXInline = do
168rawLaTeXInline = do
172 lookAhead (try (char '\\' >> letter))
169 lookAhead (try (char '\\' >> letter))
173 inp <- getInput
170 inp <- getInput
174− let toks = tokenize "source" inp
171+ let toks = tokenizeSources inp
175 raw <- snd <$>
172 raw <- snd <$>
176 ( rawLaTeXParser toks True
173 ( rawLaTeXParser toks True
177 (mempty <$ (controlSeq "input" >> skipMany rawopt >> braced))
174 (mempty <$ (controlSeq "input" >> skipMany rawopt >> braced))
@@ -182,11 +179,11 @@ rawLaTeXInline = do
182 finalbraces <- mconcat <$> many (try (string "{}")) -- see #5439
179 finalbraces <- mconcat <$> many (try (string "{}")) -- see #5439
183 return $ raw <> T.pack finalbraces
180 return $ raw <> T.pack finalbraces
184
181
185−inlineCommand :: PandocMonad m => ParserT Text ParserState m Inlines
182+inlineCommand :: PandocMonad m => ParserT Sources ParserState m Inlines
186inlineCommand = do
183inlineCommand = do
187 lookAhead (try (char '\\' >> letter))
184 lookAhead (try (char '\\' >> letter))
188 inp <- getInput
185 inp <- getInput
189− let toks = tokenize "source" inp
186+ let toks = tokenizeSources inp
190 fst <$> rawLaTeXParser toks True (inlineEnvironment <|> inlineCommand')
187 fst <$> rawLaTeXParser toks True (inlineEnvironment <|> inlineCommand')
191 inlines
188 inlines
192
189
@@ -235,16 +232,6 @@ mkImage options (T.unpack -> src) = do
235 _ -> return src
232 _ -> return src
236 return $ imageWith attr (T.pack src') "" alt
233 return $ imageWith attr (T.pack src') "" alt
237
234
238−doxspace :: PandocMonad m => LP m Inlines
239−doxspace =
240− (space <$ lookAhead (satisfyTok startsWithLetter)) <|> return mempty
241− where startsWithLetter (Tok _ Word t) =
242− case T.uncons t of
243− Just (c, _) | isLetter c -> True
244− _ -> False
245− startsWithLetter _ = False
246−
247−
248removeDoubleQuotes :: Text -> Text
235removeDoubleQuotes :: Text -> Text
249removeDoubleQuotes t =
236removeDoubleQuotes t =
250 Data.Maybe.fromMaybe t $ T.stripPrefix "\"" t >>= T.stripSuffix "\""
237 Data.Maybe.fromMaybe t $ T.stripPrefix "\"" t >>= T.stripSuffix "\""
@@ -313,7 +300,9 @@ inlineCommand' :: PandocMonad m => LP m Inlines
313inlineCommand' = try $ do
300inlineCommand' = try $ do
314 Tok _ (CtrlSeq name) cmd <- anyControlSeq
301 Tok _ (CtrlSeq name) cmd <- anyControlSeq
315 guard $ name /= "begin" && name /= "end" && name /= "and"
302 guard $ name /= "begin" && name /= "end" && name /= "and"
303+ star <- if T.all isAlphaNum name
316− star <- option "" ("*" <$ symbol '*' <* sp)
304+ then option "" ("*" <$ symbol '*' <* sp)
305+ else pure ""
317 overlay <- option "" overlaySpecification
306 overlay <- option "" overlaySpecification
318 let name' = name <> star <> overlay
307 let name' = name <> star <> overlay
319 let names = ordNub [name', name] -- check non-starred as fallback
308 let names = ordNub [name', name] -- check non-starred as fallback
@@ -420,8 +409,6 @@ inlineCommands = M.unions
420 -- LaTeX colors
409 -- LaTeX colors
421 , ("textcolor", coloredInline "color")
410 , ("textcolor", coloredInline "color")
422 , ("colorbox", coloredInline "background-color")
411 , ("colorbox", coloredInline "background-color")
423− -- xspace
424− , ("xspace", doxspace)
425 -- etoolbox
412 -- etoolbox
426 , ("ifstrequal", ifstrequal)
413 , ("ifstrequal", ifstrequal)
427 , ("newtoggle", braced >>= newToggle)
414 , ("newtoggle", braced >>= newToggle)
@@ -645,7 +632,7 @@ opt = do
645 parsed <- runParserT (mconcat <$> many inline) st "bracketed option" toks
632 parsed <- runParserT (mconcat <$> many inline) st "bracketed option" toks
646 case parsed of
633 case parsed of
647 Right result -> return result
634 Right result -> return result
648− Left e -> throwError $ PandocParsecError (untokenize toks) e
635+ Left e -> throwError $ PandocParsecError (toSources toks) e
649
636
650-- block elements:
637-- block elements:
651
638
@@ -1175,7 +1162,8 @@ inputListing = do
1175 let (ident,classes,kvs) = parseListingsOptions options
1162 let (ident,classes,kvs) = parseListingsOptions options
1176 let classes' =
1163 let classes' =
1177 (case listingsLanguage options of
1164 (case listingsLanguage options of
1165+ Nothing -> (take 1 (languagesByExtension defaultSyntaxMap
1178− Nothing -> (take 1 (languagesByExtension (T.pack $ takeExtension $ T.unpack f)) <>)
1166+ (T.pack $ takeExtension $ T.unpack f)) <>)
1179 Just _ -> id) classes
1167 Just _ -> id) classes
1180 let firstline = fromMaybe 1 $ lookup "firstline" options >>= safeRead
1168 let firstline = fromMaybe 1 $ lookup "firstline" options >>= safeRead
1181 let lastline = fromMaybe (length codeLines) $
1169 let lastline = fromMaybe (length codeLines) $
src/Text/Pandoc/Readers/LaTeX/Citation.hs+1−1
@@ -120,7 +120,7 @@ simpleCiteArgs inline = try $ do
120 runParserT (mconcat <$> many inline) st "bracketed option" toks
120 runParserT (mconcat <$> many inline) st "bracketed option" toks
121 case parsed of
121 case parsed of
122 Right result -> return result
122 Right result -> return result
123− Left e -> throwError $ PandocParsecError (untokenize toks) e
123+ Left e -> throwError $ PandocParsecError (toSources toks) e
124
124
125
125
126
126
src/Text/Pandoc/Readers/LaTeX/Lang.hs+122−119
@@ -23,7 +23,7 @@ import qualified Data.Map as M
23import Data.Text (Text)
23import Data.Text (Text)
24import qualified Data.Text as T
24import qualified Data.Text as T
25import Text.Pandoc.Shared (extractSpaces)
25import Text.Pandoc.Shared (extractSpaces)
26−import Text.Pandoc.BCP47 (Lang(..), renderLang)
26+import Text.Collate.Lang (Lang(..), renderLang)
27import Text.Pandoc.Class (PandocMonad(..), setTranslations)
27import Text.Pandoc.Class (PandocMonad(..), setTranslations)
28import Text.Pandoc.Readers.LaTeX.Parsing
28import Text.Pandoc.Readers.LaTeX.Parsing
29import Text.Pandoc.Parsing (updateState, option, getState, QuoteContext(..),
29import Text.Pandoc.Parsing (updateState, option, getState, QuoteContext(..),
@@ -99,133 +99,136 @@ setDefaultLanguage = do
99polyglossiaLangToBCP47 :: M.Map T.Text (T.Text -> Lang)
99polyglossiaLangToBCP47 :: M.Map T.Text (T.Text -> Lang)
100polyglossiaLangToBCP47 = M.fromList
100polyglossiaLangToBCP47 = M.fromList
101 [ ("arabic", \o -> case T.filter (/=' ') o of
101 [ ("arabic", \o -> case T.filter (/=' ') o of
102− "locale=algeria" -> Lang "ar" "" "DZ" []
102+ "locale=algeria" -> Lang "ar" Nothing (Just "DZ") [] [] []
103− "locale=mashriq" -> Lang "ar" "" "SY" []
103+ "locale=mashriq" -> Lang "ar" Nothing (Just "SY") [] [] []
104− "locale=libya" -> Lang "ar" "" "LY" []
104+ "locale=libya" -> Lang "ar" Nothing (Just "LY") [] [] []
105− "locale=morocco" -> Lang "ar" "" "MA" []
105+ "locale=morocco" -> Lang "ar" Nothing (Just "MA") [] [] []
106− "locale=mauritania" -> Lang "ar" "" "MR" []
106+ "locale=mauritania" -> Lang "ar" Nothing (Just "MR") [] [] []
107− "locale=tunisia" -> Lang "ar" "" "TN" []
107+ "locale=tunisia" -> Lang "ar" Nothing (Just "TN") [] [] []
108− _ -> Lang "ar" "" "" [])
108+ _ -> Lang "ar" Nothing (Just "") [] [] [])
109 , ("german", \o -> case T.filter (/=' ') o of
109 , ("german", \o -> case T.filter (/=' ') o of
110− "spelling=old" -> Lang "de" "" "DE" ["1901"]
110+ "spelling=old" -> Lang "de" Nothing (Just "DE") ["1901"] [] []
111 "variant=austrian,spelling=old"
111 "variant=austrian,spelling=old"
112− -> Lang "de" "" "AT" ["1901"]
112+ -> Lang "de" Nothing (Just "AT") ["1901"] [] []
113− "variant=austrian" -> Lang "de" "" "AT" []
113+ "variant=austrian" -> Lang "de" Nothing (Just "AT") [] [] []
114 "variant=swiss,spelling=old"
114 "variant=swiss,spelling=old"
115− -> Lang "de" "" "CH" ["1901"]
115+ -> Lang "de" Nothing (Just "CH") ["1901"] [] []
116− "variant=swiss" -> Lang "de" "" "CH" []
116+ "variant=swiss" -> Lang "de" Nothing (Just "CH") [] [] []
117− _ -> Lang "de" "" "" [])
117+ _ -> Lang "de" Nothing Nothing [] [] [])
118− , ("lsorbian", \_ -> Lang "dsb" "" "" [])
118+ , ("lsorbian", \_ -> Lang "dsb" Nothing Nothing [] [] [])
119 , ("greek", \o -> case T.filter (/=' ') o of
119 , ("greek", \o -> case T.filter (/=' ') o of
120− "variant=poly" -> Lang "el" "" "polyton" []
120+ "variant=poly" -> Lang "el" Nothing (Just "polyton") [] [] []
121− "variant=ancient" -> Lang "grc" "" "" []
121+ "variant=ancient" -> Lang "grc" Nothing Nothing [] [] []
122− _ -> Lang "el" "" "" [])
122+ _ -> Lang "el" Nothing Nothing [] [] [])
123 , ("english", \o -> case T.filter (/=' ') o of
123 , ("english", \o -> case T.filter (/=' ') o of
124− "variant=australian" -> Lang "en" "" "AU" []
124+ "variant=australian" -> Lang "en" Nothing (Just "AU") [] [] []
125− "variant=canadian" -> Lang "en" "" "CA" []
125+ "variant=canadian" -> Lang "en" Nothing (Just "CA") [] [] []
126− "variant=british" -> Lang "en" "" "GB" []
126+ "variant=british" -> Lang "en" Nothing (Just "GB") [] [] []
127− "variant=newzealand" -> Lang "en" "" "NZ" []
127+ "variant=newzealand" -> Lang "en" Nothing (Just "NZ") [] [] []
128− "variant=american" -> Lang "en" "" "US" []
128+ "variant=american" -> Lang "en" Nothing (Just "US") [] [] []
129− _ -> Lang "en" "" "" [])
129+ _ -> Lang "en" Nothing (Just "") [] [] [])
130− , ("usorbian", \_ -> Lang "hsb" "" "" [])
130+ , ("usorbian", \_ -> Lang "hsb" Nothing Nothing [] [] [])
131 , ("latin", \o -> case T.filter (/=' ') o of
131 , ("latin", \o -> case T.filter (/=' ') o of
132− "variant=classic" -> Lang "la" "" "" ["x-classic"]
132+ "variant=classic" -> Lang "la" Nothing Nothing ["x-classic"] [] []
133− _ -> Lang "la" "" "" [])
133+ _ -> Lang "la" Nothing Nothing [] [] [])
134− , ("slovenian", \_ -> Lang "sl" "" "" [])
134+ , ("slovenian", \_ -> Lang "sl" Nothing Nothing [] [] [])
135− , ("serbianc", \_ -> Lang "sr" "cyrl" "" [])
135+ , ("serbianc", \_ -> Lang "sr" (Just "Cyrl") Nothing [] [] [])
136− , ("pinyin", \_ -> Lang "zh" "Latn" "" ["pinyin"])
136+ , ("pinyin", \_ -> Lang "zh" (Just "Latn") Nothing ["pinyin"] [] [])
137− , ("afrikaans", \_ -> Lang "af" "" "" [])
137+ , ("afrikaans", \_ -> simpleLang "af")
138− , ("amharic", \_ -> Lang "am" "" "" [])
138+ , ("amharic", \_ -> simpleLang "am")
139− , ("assamese", \_ -> Lang "as" "" "" [])
139+ , ("assamese", \_ -> simpleLang "as")
140− , ("asturian", \_ -> Lang "ast" "" "" [])
140+ , ("asturian", \_ -> simpleLang "ast")
141− , ("bulgarian", \_ -> Lang "bg" "" "" [])
141+ , ("bulgarian", \_ -> simpleLang "bg")
142− , ("bengali", \_ -> Lang "bn" "" "" [])
142+ , ("bengali", \_ -> simpleLang "bn")
143− , ("tibetan", \_ -> Lang "bo" "" "" [])
143+ , ("tibetan", \_ -> simpleLang "bo")
144− , ("breton", \_ -> Lang "br" "" "" [])
144+ , ("breton", \_ -> simpleLang "br")
145− , ("catalan", \_ -> Lang "ca" "" "" [])
145+ , ("catalan", \_ -> simpleLang "ca")
146− , ("welsh", \_ -> Lang "cy" "" "" [])
146+ , ("welsh", \_ -> simpleLang "cy")
147− , ("czech", \_ -> Lang "cs" "" "" [])
147+ , ("czech", \_ -> simpleLang "cs")
148− , ("coptic", \_ -> Lang "cop" "" "" [])
148+ , ("coptic", \_ -> simpleLang "cop")
149− , ("danish", \_ -> Lang "da" "" "" [])
149+ , ("danish", \_ -> simpleLang "da")
150− , ("divehi", \_ -> Lang "dv" "" "" [])
150+ , ("divehi", \_ -> simpleLang "dv")
151− , ("esperanto", \_ -> Lang "eo" "" "" [])
151+ , ("esperanto", \_ -> simpleLang "eo")
152− , ("spanish", \_ -> Lang "es" "" "" [])
152+ , ("spanish", \_ -> simpleLang "es")
153− , ("estonian", \_ -> Lang "et" "" "" [])
153+ , ("estonian", \_ -> simpleLang "et")
154− , ("basque", \_ -> Lang "eu" "" "" [])
154+ , ("basque", \_ -> simpleLang "eu")
155− , ("farsi", \_ -> Lang "fa" "" "" [])
155+ , ("farsi", \_ -> simpleLang "fa")
156− , ("finnish", \_ -> Lang "fi" "" "" [])
156+ , ("finnish", \_ -> simpleLang "fi")
157− , ("french", \_ -> Lang "fr" "" "" [])
157+ , ("french", \_ -> simpleLang "fr")
158− , ("friulan", \_ -> Lang "fur" "" "" [])
158+ , ("friulan", \_ -> simpleLang "fur")
159− , ("irish", \_ -> Lang "ga" "" "" [])
159+ , ("irish", \_ -> simpleLang "ga")
160− , ("scottish", \_ -> Lang "gd" "" "" [])
160+ , ("scottish", \_ -> simpleLang "gd")
161− , ("ethiopic", \_ -> Lang "gez" "" "" [])
161+ , ("ethiopic", \_ -> simpleLang "gez")
162− , ("galician", \_ -> Lang "gl" "" "" [])
162+ , ("galician", \_ -> simpleLang "gl")
163− , ("hebrew", \_ -> Lang "he" "" "" [])
163+ , ("hebrew", \_ -> simpleLang "he")
164− , ("hindi", \_ -> Lang "hi" "" "" [])
164+ , ("hindi", \_ -> simpleLang "hi")
165− , ("croatian", \_ -> Lang "hr" "" "" [])
165+ , ("croatian", \_ -> simpleLang "hr")
166− , ("magyar", \_ -> Lang "hu" "" "" [])
166+ , ("magyar", \_ -> simpleLang "hu")
167− , ("armenian", \_ -> Lang "hy" "" "" [])
167+ , ("armenian", \_ -> simpleLang "hy")
168− , ("interlingua", \_ -> Lang "ia" "" "" [])
168+ , ("interlingua", \_ -> simpleLang "ia")
169− , ("indonesian", \_ -> Lang "id" "" "" [])
169+ , ("indonesian", \_ -> simpleLang "id")
170− , ("icelandic", \_ -> Lang "is" "" "" [])
170+ , ("icelandic", \_ -> simpleLang "is")
171− , ("italian", \_ -> Lang "it" "" "" [])
171+ , ("italian", \_ -> simpleLang "it")
172− , ("japanese", \_ -> Lang "jp" "" "" [])
172+ , ("japanese", \_ -> simpleLang "jp")
173− , ("khmer", \_ -> Lang "km" "" "" [])
173+ , ("khmer", \_ -> simpleLang "km")
174− , ("kurmanji", \_ -> Lang "kmr" "" "" [])
174+ , ("kurmanji", \_ -> simpleLang "kmr")
175− , ("kannada", \_ -> Lang "kn" "" "" [])
175+ , ("kannada", \_ -> simpleLang "kn")
176− , ("korean", \_ -> Lang "ko" "" "" [])
176+ , ("korean", \_ -> simpleLang "ko")
177− , ("lao", \_ -> Lang "lo" "" "" [])
177+ , ("lao", \_ -> simpleLang "lo")
178− , ("lithuanian", \_ -> Lang "lt" "" "" [])
178+ , ("lithuanian", \_ -> simpleLang "lt")
179− , ("latvian", \_ -> Lang "lv" "" "" [])
179+ , ("latvian", \_ -> simpleLang "lv")
180− , ("malayalam", \_ -> Lang "ml" "" "" [])
180+ , ("malayalam", \_ -> simpleLang "ml")
181− , ("mongolian", \_ -> Lang "mn" "" "" [])
181+ , ("mongolian", \_ -> simpleLang "mn")
182− , ("marathi", \_ -> Lang "mr" "" "" [])
182+ , ("marathi", \_ -> simpleLang "mr")
183− , ("dutch", \_ -> Lang "nl" "" "" [])
183+ , ("dutch", \_ -> simpleLang "nl")
184− , ("nynorsk", \_ -> Lang "nn" "" "" [])
184+ , ("nynorsk", \_ -> simpleLang "nn")
185− , ("norsk", \_ -> Lang "no" "" "" [])
185+ , ("norsk", \_ -> simpleLang "no")
186− , ("nko", \_ -> Lang "nqo" "" "" [])
186+ , ("nko", \_ -> simpleLang "nqo")
187− , ("occitan", \_ -> Lang "oc" "" "" [])
187+ , ("occitan", \_ -> simpleLang "oc")
188− , ("panjabi", \_ -> Lang "pa" "" "" [])
188+ , ("panjabi", \_ -> simpleLang "pa")
189− , ("polish", \_ -> Lang "pl" "" "" [])
189+ , ("polish", \_ -> simpleLang "pl")
190− , ("piedmontese", \_ -> Lang "pms" "" "" [])
190+ , ("piedmontese", \_ -> simpleLang "pms")
191− , ("portuguese", \_ -> Lang "pt" "" "" [])
191+ , ("portuguese", \_ -> simpleLang "pt")
192− , ("romansh", \_ -> Lang "rm" "" "" [])
192+ , ("romansh", \_ -> simpleLang "rm")
193− , ("romanian", \_ -> Lang "ro" "" "" [])
193+ , ("romanian", \_ -> simpleLang "ro")
194− , ("russian", \_ -> Lang "ru" "" "" [])
194+ , ("russian", \_ -> simpleLang "ru")
195− , ("sanskrit", \_ -> Lang "sa" "" "" [])
195+ , ("sanskrit", \_ -> simpleLang "sa")
196− , ("samin", \_ -> Lang "se" "" "" [])
196+ , ("samin", \_ -> simpleLang "se")
197− , ("slovak", \_ -> Lang "sk" "" "" [])
197+ , ("slovak", \_ -> simpleLang "sk")
198− , ("albanian", \_ -> Lang "sq" "" "" [])
198+ , ("albanian", \_ -> simpleLang "sq")
199− , ("serbian", \_ -> Lang "sr" "" "" [])
199+ , ("serbian", \_ -> simpleLang "sr")
200− , ("swedish", \_ -> Lang "sv" "" "" [])
200+ , ("swedish", \_ -> simpleLang "sv")
201− , ("syriac", \_ -> Lang "syr" "" "" [])
201+ , ("syriac", \_ -> simpleLang "syr")
202− , ("tamil", \_ -> Lang "ta" "" "" [])
202+ , ("tamil", \_ -> simpleLang "ta")
203− , ("telugu", \_ -> Lang "te" "" "" [])
203+ , ("telugu", \_ -> simpleLang "te")
204− , ("thai", \_ -> Lang "th" "" "" [])
204+ , ("thai", \_ -> simpleLang "th")
205− , ("turkmen", \_ -> Lang "tk" "" "" [])
205+ , ("turkmen", \_ -> simpleLang "tk")
206− , ("turkish", \_ -> Lang "tr" "" "" [])
206+ , ("turkish", \_ -> simpleLang "tr")
207− , ("ukrainian", \_ -> Lang "uk" "" "" [])
207+ , ("ukrainian", \_ -> simpleLang "uk")
208− , ("urdu", \_ -> Lang "ur" "" "" [])
208+ , ("urdu", \_ -> simpleLang "ur")
209− , ("vietnamese", \_ -> Lang "vi" "" "" [])
209+ , ("vietnamese", \_ -> simpleLang "vi")
210 ]
210 ]
211
211
212+simpleLang :: Text -> Lang
213+simpleLang l = Lang l Nothing Nothing [] [] []
214+
212babelLangToBCP47 :: T.Text -> Maybe Lang
215babelLangToBCP47 :: T.Text -> Maybe Lang
213babelLangToBCP47 s =
216babelLangToBCP47 s =
214 case s of
217 case s of
215− "austrian" -> Just $ Lang "de" "" "AT" ["1901"]
218+ "austrian" -> Just $ Lang "de" Nothing (Just "AT") ["1901"] [] []
216− "naustrian" -> Just $ Lang "de" "" "AT" []
219+ "naustrian" -> Just $ Lang "de" Nothing (Just "AT") [] [] []
217− "swissgerman" -> Just $ Lang "de" "" "CH" ["1901"]
220+ "swissgerman" -> Just $ Lang "de" Nothing (Just "CH") ["1901"] [] []
218− "nswissgerman" -> Just $ Lang "de" "" "CH" []
221+ "nswissgerman" -> Just $ Lang "de" Nothing (Just "CH") [] [] []
219− "german" -> Just $ Lang "de" "" "DE" ["1901"]
222+ "german" -> Just $ Lang "de" Nothing (Just "DE") ["1901"] [] []
220− "ngerman" -> Just $ Lang "de" "" "DE" []
223+ "ngerman" -> Just $ Lang "de" Nothing (Just "DE") [] [] []
221− "lowersorbian" -> Just $ Lang "dsb" "" "" []
224+ "lowersorbian" -> Just $ Lang "dsb" Nothing Nothing [] [] []
222− "uppersorbian" -> Just $ Lang "hsb" "" "" []
225+ "uppersorbian" -> Just $ Lang "hsb" Nothing Nothing [] [] []
223− "polutonikogreek" -> Just $ Lang "el" "" "" ["polyton"]
226+ "polutonikogreek" -> Just $ Lang "el" Nothing Nothing ["polyton"] [] []
224− "slovene" -> Just $ Lang "sl" "" "" []
227+ "slovene" -> Just $ simpleLang "sl"
225− "australian" -> Just $ Lang "en" "" "AU" []
228+ "australian" -> Just $ Lang "en" Nothing (Just "AU") [] [] []
226− "canadian" -> Just $ Lang "en" "" "CA" []
229+ "canadian" -> Just $ Lang "en" Nothing (Just "CA") [] [] []
227− "british" -> Just $ Lang "en" "" "GB" []
230+ "british" -> Just $ Lang "en" Nothing (Just "GB") [] [] []
228− "newzealand" -> Just $ Lang "en" "" "NZ" []
231+ "newzealand" -> Just $ Lang "en" Nothing (Just "NZ") [] [] []
229− "american" -> Just $ Lang "en" "" "US" []
232+ "american" -> Just $ Lang "en" Nothing (Just "US") [] [] []
230− "classiclatin" -> Just $ Lang "la" "" "" ["x-classic"]
233+ "classiclatin" -> Just $ Lang "la" Nothing Nothing ["x-classic"] [] []
231 _ -> ($ "") <$> M.lookup s polyglossiaLangToBCP47
234 _ -> ($ "") <$> M.lookup s polyglossiaLangToBCP47
src/Text/Pandoc/Readers/LaTeX/Macro.hs+45−14
@@ -14,6 +14,7 @@ import Text.Pandoc.Parsing hiding (blankline, mathDisplay, mathInline,
14import Control.Applicative ((<|>), optional)
14import Control.Applicative ((<|>), optional)
15import qualified Data.Map as M
15import qualified Data.Map as M
16import Data.Text (Text)
16import Data.Text (Text)
17+import qualified Data.Text as T
17
18
18macroDef :: (PandocMonad m, Monoid a) => (Text -> a) -> LP m a
19macroDef :: (PandocMonad m, Monoid a) => (Text -> a) -> LP m a
19macroDef constructor = do
20macroDef constructor = do
@@ -22,9 +23,11 @@ macroDef constructor = do
22 guardDisabled Ext_latex_macros)
23 guardDisabled Ext_latex_macros)
23 <|> return mempty
24 <|> return mempty
24 where commandDef = do
25 where commandDef = do
25− (name, macro') <- newcommand <|> letmacro <|> defmacro
26+ nameMacroPairs <- newcommand <|> letmacro <|> defmacro <|> newif
26 guardDisabled Ext_latex_macros <|>
27 guardDisabled Ext_latex_macros <|>
28+ mapM_ (\(name, macro') ->
27− updateState (\s -> s{ sMacros = M.insert name macro' (sMacros s) })
29+ updateState (\s -> s{ sMacros = M.insert name macro'
30+ (sMacros s) })) nameMacroPairs
28 environmentDef = do
31 environmentDef = do
29 mbenv <- newenvironment
32 mbenv <- newenvironment
30 case mbenv of
33 case mbenv of
@@ -40,7 +43,7 @@ macroDef constructor = do
40 -- @\newcommand{\envname}[n-args][default]{begin}@
43 -- @\newcommand{\envname}[n-args][default]{begin}@
41 -- @\newcommand{\endenvname}@
44 -- @\newcommand{\endenvname}@
42
45
43−letmacro :: PandocMonad m => LP m (Text, Macro)
46+letmacro :: PandocMonad m => LP m [(Text, Macro)]
44letmacro = do
47letmacro = do
45 controlSeq "let"
48 controlSeq "let"
46 (name, contents) <- withVerbatimMode $ do
49 (name, contents) <- withVerbatimMode $ do
@@ -53,18 +56,47 @@ letmacro = do
53 contents <- bracedOrToken
56 contents <- bracedOrToken
54 return (name, contents)
57 return (name, contents)
55 contents' <- doMacros' 0 contents
58 contents' <- doMacros' 0 contents
56− return (name, Macro ExpandWhenDefined [] Nothing contents')
59+ return [(name, Macro ExpandWhenDefined [] Nothing contents')]
57
60
58−defmacro :: PandocMonad m => LP m (Text, Macro)
61+defmacro :: PandocMonad m => LP m [(Text, Macro)]
59−defmacro = try $
62+defmacro = do
60 -- we use withVerbatimMode, because macros are to be expanded
63 -- we use withVerbatimMode, because macros are to be expanded
61 -- at point of use, not point of definition
64 -- at point of use, not point of definition
65+ controlSeq "def"
62 withVerbatimMode $ do
66 withVerbatimMode $ do
63− controlSeq "def"
64 Tok _ (CtrlSeq name) _ <- anyControlSeq
67 Tok _ (CtrlSeq name) _ <- anyControlSeq
65 argspecs <- many (argspecArg <|> argspecPattern)
68 argspecs <- many (argspecArg <|> argspecPattern)
66 contents <- bracedOrToken
69 contents <- bracedOrToken
67− return (name, Macro ExpandWhenUsed argspecs Nothing contents)
70+ return [(name, Macro ExpandWhenUsed argspecs Nothing contents)]
71+
72+-- \newif\iffoo' defines:
73+-- \iffoo to be \iffalse
74+-- \footrue to be a command that defines \iffoo to be \iftrue
75+-- \foofalse to be a command that defines \iffoo to be \iffalse
76+newif :: PandocMonad m => LP m [(Text, Macro)]
77+newif = do
78+ controlSeq "newif"
79+ withVerbatimMode $ do
80+ Tok pos (CtrlSeq name) _ <- anyControlSeq
81+ -- \def\iffoo\iffalse
82+ -- \def\footrue{\def\iffoo\iftrue}
83+ -- \def\foofalse{\def\iffoo\iffalse}
84+ let base = T.drop 2 name
85+ return [ (name, Macro ExpandWhenUsed [] Nothing
86+ [Tok pos (CtrlSeq "iffalse") "\\iffalse"])
87+ , (base <> "true",
88+ Macro ExpandWhenUsed [] Nothing
89+ [ Tok pos (CtrlSeq "def") "\\def"
90+ , Tok pos (CtrlSeq name) ("\\" <> name)
91+ , Tok pos (CtrlSeq "iftrue") "\\iftrue"
92+ ])
93+ , (base <> "false",
94+ Macro ExpandWhenUsed [] Nothing
95+ [ Tok pos (CtrlSeq "def") "\\def"
96+ , Tok pos (CtrlSeq name) ("\\" <> name)
97+ , Tok pos (CtrlSeq "iffalse") "\\iffalse"
98+ ])
99+ ]
68
100
69argspecArg :: PandocMonad m => LP m ArgSpec
101argspecArg :: PandocMonad m => LP m ArgSpec
70argspecArg = do
102argspecArg = do
@@ -77,10 +109,9 @@ argspecPattern =
77 (toktype' == Symbol || toktype' == Word) &&
109 (toktype' == Symbol || toktype' == Word) &&
78 (txt /= "{" && txt /= "\\" && txt /= "}")))
110 (txt /= "{" && txt /= "\\" && txt /= "}")))
79
111
80−newcommand :: PandocMonad m => LP m (Text, Macro)
112+newcommand :: PandocMonad m => LP m [(Text, Macro)]
81newcommand = do
113newcommand = do
82− pos <- getPosition
83− Tok _ (CtrlSeq mtype) _ <- controlSeq "newcommand" <|>
114+ Tok pos (CtrlSeq mtype) _ <- controlSeq "newcommand" <|>
84 controlSeq "renewcommand" <|>
115 controlSeq "renewcommand" <|>
85 controlSeq "providecommand" <|>
116 controlSeq "providecommand" <|>
86 controlSeq "DeclareMathOperator" <|>
117 controlSeq "DeclareMathOperator" <|>
@@ -112,9 +143,9 @@ newcommand = do
112 Just macro
143 Just macro
113 | mtype == "newcommand" -> do
144 | mtype == "newcommand" -> do
114 report $ MacroAlreadyDefined txt pos
145 report $ MacroAlreadyDefined txt pos
115− return (name, macro)
146+ return [(name, macro)]
116− | mtype == "providecommand" -> return (name, macro)
147+ | mtype == "providecommand" -> return [(name, macro)]
117− _ -> return (name, Macro ExpandWhenUsed argspecs optarg contents)
148+ _ -> return [(name, Macro ExpandWhenUsed argspecs optarg contents)]
118
149
119newenvironment :: PandocMonad m => LP m (Maybe (Text, Macro, Macro))
150newenvironment :: PandocMonad m => LP m (Maybe (Text, Macro, Macro))
120newenvironment = do
151newenvironment = do
src/Text/Pandoc/Readers/LaTeX/Parsing.hs+48−7
@@ -27,6 +27,7 @@ module Text.Pandoc.Readers.LaTeX.Parsing
27 , rawLaTeXParser
27 , rawLaTeXParser
28 , applyMacros
28 , applyMacros
29 , tokenize
29 , tokenize
30+ , tokenizeSources
30 , untokenize
31 , untokenize
31 , untoken
32 , untoken
32 , totoks
33 , totoks
@@ -112,7 +113,6 @@ import Text.Pandoc.Readers.LaTeX.Types (ExpansionPoint (..), Macro (..),
112 ArgSpec (..), Tok (..), TokType (..))
113 ArgSpec (..), Tok (..), TokType (..))
113import Text.Pandoc.Shared
114import Text.Pandoc.Shared
114import Text.Parsec.Pos
115import Text.Parsec.Pos
115−-- import Debug.Trace
116
116
117newtype DottedNum = DottedNum [Int]
117newtype DottedNum = DottedNum [Int]
118 deriving (Show, Eq)
118 deriving (Show, Eq)
@@ -248,7 +248,7 @@ withVerbatimMode parser = do
248
248
249rawLaTeXParser :: (PandocMonad m, HasMacros s, HasReaderOptions s)
249rawLaTeXParser :: (PandocMonad m, HasMacros s, HasReaderOptions s)
250 => [Tok] -> Bool -> LP m a -> LP m a
250 => [Tok] -> Bool -> LP m a -> LP m a
251− -> ParserT Text s m (a, Text)
251+ -> ParserT Sources s m (a, Text)
252rawLaTeXParser toks retokenize parser valParser = do
252rawLaTeXParser toks retokenize parser valParser = do
253 pstate <- getState
253 pstate <- getState
254 let lstate = def{ sOptions = extractReaderOptions pstate }
254 let lstate = def{ sOptions = extractReaderOptions pstate }
@@ -268,7 +268,7 @@ rawLaTeXParser toks retokenize parser valParser = do
268 Left _ -> mzero
268 Left _ -> mzero
269 Right ((val, raw), st) -> do
269 Right ((val, raw), st) -> do
270 updateState (updateMacros (sMacros st <>))
270 updateState (updateMacros (sMacros st <>))
271− _ <- takeP (T.length (untokenize toks'))
271+ void $ count (T.length (untokenize toks')) anyChar
272 let result = untokenize raw
272 let result = untokenize raw
273 -- ensure we end with space if input did, see #4442
273 -- ensure we end with space if input did, see #4442
274 let result' =
274 let result' =
@@ -281,7 +281,7 @@ rawLaTeXParser toks retokenize parser valParser = do
281 return (val, result')
281 return (val, result')
282
282
283applyMacros :: (PandocMonad m, HasMacros s, HasReaderOptions s)
283applyMacros :: (PandocMonad m, HasMacros s, HasReaderOptions s)
284− => Text -> ParserT Text s m Text
284+ => Text -> ParserT Sources s m Text
285applyMacros s = (guardDisabled Ext_latex_macros >> return s) <|>
285applyMacros s = (guardDisabled Ext_latex_macros >> return s) <|>
286 do let retokenize = untokenize <$> many (satisfyTok (const True))
286 do let retokenize = untokenize <$> many (satisfyTok (const True))
287 pstate <- getState
287 pstate <- getState
@@ -301,6 +301,11 @@ QuickCheck property:
301> let t = T.pack s in untokenize (tokenize "random" t) == t
301> let t = T.pack s in untokenize (tokenize "random" t) == t
302-}
302-}
303
303
304+tokenizeSources :: Sources -> [Tok]
305+tokenizeSources = concatMap tokenizeSource . unSources
306+ where
307+ tokenizeSource (pos, t) = totoks pos t
308+
304tokenize :: SourceName -> Text -> [Tok]
309tokenize :: SourceName -> Text -> [Tok]
305tokenize sourcename = totoks (initialPos sourcename)
310tokenize sourcename = totoks (initialPos sourcename)
306
311
@@ -458,7 +463,7 @@ satisfyTok f = do
458doMacros :: PandocMonad m => LP m ()
463doMacros :: PandocMonad m => LP m ()
459doMacros = do
464doMacros = do
460 st <- getState
465 st <- getState
461− unless (sVerbatimMode st || M.null (sMacros st)) $ do
466+ unless (sVerbatimMode st) $
462 getInput >>= doMacros' 1 >>= setInput
467 getInput >>= doMacros' 1 >>= setInput
463
468
464doMacros' :: PandocMonad m => Int -> [Tok] -> LP m [Tok]
469doMacros' :: PandocMonad m => Int -> [Tok] -> LP m [Tok]
@@ -520,7 +525,7 @@ doMacros' n inp =
520 $ throwError $ PandocMacroLoop name
525 $ throwError $ PandocMacroLoop name
521 macros <- sMacros <$> getState
526 macros <- sMacros <$> getState
522 case M.lookup name macros of
527 case M.lookup name macros of
523− Nothing -> mzero
528+ Nothing -> trySpecialMacro name ts
524 Just (Macro expansionPoint argspecs optarg newtoks) -> do
529 Just (Macro expansionPoint argspecs optarg newtoks) -> do
525 let getargs' = do
530 let getargs' = do
526 args <-
531 args <-
@@ -548,6 +553,41 @@ doMacros' n inp =
548 ExpandWhenUsed -> doMacros' (n' + 1) result
553 ExpandWhenUsed -> doMacros' (n' + 1) result
549 ExpandWhenDefined -> return result
554 ExpandWhenDefined -> return result
550
555
556+-- | Certain macros do low-level tex manipulations that can't
557+-- be represented in our Macro type, so we handle them here.
558+trySpecialMacro :: PandocMonad m => Text -> [Tok] -> LP m [Tok]
559+trySpecialMacro "xspace" ts = do
560+ ts' <- doMacros' 1 ts
561+ case ts' of
562+ Tok pos Word t : _
563+ | startsWithAlphaNum t -> return $ Tok pos Spaces " " : ts'
564+ _ -> return ts'
565+trySpecialMacro "iftrue" ts = handleIf True ts
566+trySpecialMacro "iffalse" ts = handleIf False ts
567+trySpecialMacro _ _ = mzero
568+
569+handleIf :: PandocMonad m => Bool -> [Tok] -> LP m [Tok]
570+handleIf b ts = do
571+ res' <- lift $ runParserT (ifParser b) defaultLaTeXState "tokens" ts
572+ case res' of
573+ Left _ -> Prelude.fail "Could not parse conditional"
574+ Right ts' -> return ts'
575+
576+ifParser :: PandocMonad m => Bool -> LP m [Tok]
577+ifParser b = do
578+ ifToks <- many (notFollowedBy (controlSeq "else" <|> controlSeq "fi")
579+ *> anyTok)
580+ elseToks <- (controlSeq "else" >> manyTill anyTok (controlSeq "fi"))
581+ <|> ([] <$ controlSeq "fi")
582+ rest <- getInput
583+ return $ (if b then ifToks else elseToks) ++ rest
584+
585+startsWithAlphaNum :: Text -> Bool
586+startsWithAlphaNum t =
587+ case T.uncons t of
588+ Just (c, _) | isAlphaNum c -> True
589+ _ -> False
590+
551setpos :: SourcePos -> Tok -> Tok
591setpos :: SourcePos -> Tok -> Tok
552setpos spos (Tok _ tt txt) = Tok spos tt txt
592setpos spos (Tok _ tt txt) = Tok spos tt txt
553
593
@@ -783,7 +823,8 @@ withRaw parser = do
783
823
784keyval :: PandocMonad m => LP m (Text, Text)
824keyval :: PandocMonad m => LP m (Text, Text)
785keyval = try $ do
825keyval = try $ do
826+ key <- untokenize <$> many1 (notFollowedBy (symbol '=') >>
786− Tok _ Word key <- satisfyTok isWordTok
827+ (symbol '-' <|> symbol '_' <|> satisfyTok isWordTok))
787 sp
828 sp
788 val <- option mempty $ do
829 val <- option mempty $ do
789 symbol '='
830 symbol '='
src/Text/Pandoc/Readers/LaTeX/SIunitx.hs+140−66
@@ -1,3 +1,4 @@
1+{-# LANGUAGE ScopedTypeVariables #-}
1{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
2module Text.Pandoc.Readers.LaTeX.SIunitx
3module Text.Pandoc.Readers.LaTeX.SIunitx
3 ( siunitxCommands )
4 ( siunitxCommands )
@@ -9,27 +10,32 @@ import Text.Pandoc.Class
9import Text.Pandoc.Parsing hiding (blankline, mathDisplay, mathInline,
10import Text.Pandoc.Parsing hiding (blankline, mathDisplay, mathInline,
10 optional, space, spaces, withRaw, (<|>))
11 optional, space, spaces, withRaw, (<|>))
11import Control.Applicative ((<|>))
12import Control.Applicative ((<|>))
13+import Control.Monad (void)
12import qualified Data.Map as M
14import qualified Data.Map as M
13import Data.Char (isDigit)
15import Data.Char (isDigit)
14import Data.Text (Text)
16import Data.Text (Text)
15import qualified Data.Text as T
17import qualified Data.Text as T
16import Data.List (intersperse)
18import Data.List (intersperse)
17−
19+import qualified Data.Sequence as Seq
20+import Text.Pandoc.Walk (walk)
18
21
19siunitxCommands :: PandocMonad m
22siunitxCommands :: PandocMonad m
20 => LP m Inlines -> M.Map Text (LP m Inlines)
23 => LP m Inlines -> M.Map Text (LP m Inlines)
21siunitxCommands tok = M.fromList
24siunitxCommands tok = M.fromList
22− [ ("si", skipopts *> dosi tok)
25+ [ ("si", dosi tok)
23 , ("SI", doSI tok)
26 , ("SI", doSI tok)
24 , ("SIrange", doSIrange True tok)
27 , ("SIrange", doSIrange True tok)
25 , ("numrange", doSIrange False tok)
28 , ("numrange", doSIrange False tok)
26 , ("numlist", doSInumlist)
29 , ("numlist", doSInumlist)
30+ , ("SIlist", doSIlist tok)
27 , ("num", doSInum)
31 , ("num", doSInum)
28 , ("ang", doSIang)
32 , ("ang", doSIang)
29 ]
33 ]
30
34
31dosi :: PandocMonad m => LP m Inlines -> LP m Inlines
35dosi :: PandocMonad m => LP m Inlines -> LP m Inlines
36+dosi tok = do
37+ options <- option [] keyvals
32−dosi tok = grouped (siUnit tok) <|> siUnit tok
38+ grouped (siUnit options tok) <|> siUnit options tok
33
39
34-- converts e.g. \SI{1}[\$]{} to "$ 1" or \SI{1}{\euro} to "1 €"
40-- converts e.g. \SI{1}[\$]{} to "$ 1" or \SI{1}{\euro} to "1 €"
35doSI :: PandocMonad m => LP m Inlines -> LP m Inlines
41doSI :: PandocMonad m => LP m Inlines -> LP m Inlines
@@ -64,23 +70,50 @@ doSInumlist = do
64 mconcat (intersperse (str "," <> space) (init xs)) <>
70 mconcat (intersperse (str "," <> space) (init xs)) <>
65 text ", & " <> last xs
71 text ", & " <> last xs
66
72
73+doSIlist :: PandocMonad m => LP m Inlines -> LP m Inlines
74+doSIlist tok = do
75+ options <- option [] keyvals
76+ nums <- map tonum . T.splitOn ";" . untokenize <$> braced
77+ unit <- grouped (siUnit options tok) <|> siUnit options tok
78+ let xs = map (<> (str "\xa0" <> unit)) nums
79+ case xs of
80+ [] -> return mempty
81+ [x] -> return x
82+ _ -> return $
83+ mconcat (intersperse (str "," <> space) (init xs)) <>
84+ text ", & " <> last xs
85+
67parseNum :: Parser Text () Inlines
86parseNum :: Parser Text () Inlines
68parseNum = (mconcat <$> many parseNumPart) <* eof
87parseNum = (mconcat <$> many parseNumPart) <* eof
69
88
89+minus :: Text
90+minus = "\x2212"
91+
92+hyphenToMinus :: Inline -> Inline
93+hyphenToMinus (Str t) = Str (T.replace "-" minus t)
94+hyphenToMinus x = x
95+
70parseNumPart :: Parser Text () Inlines
96parseNumPart :: Parser Text () Inlines
71parseNumPart =
97parseNumPart =
72 parseDecimalNum <|>
98 parseDecimalNum <|>
73 parseComma <|>
99 parseComma <|>
74 parsePlusMinus <|>
100 parsePlusMinus <|>
101+ parsePM <|>
75 parseI <|>
102 parseI <|>
76 parseExp <|>
103 parseExp <|>
77 parseX <|>
104 parseX <|>
78 parseSpace
105 parseSpace
79 where
106 where
80− parseDecimalNum = do
107+ parseDecimalNum, parsePlusMinus, parsePM,
108+ parseComma, parseI, parseX,
109+ parseExp, parseSpace :: Parser Text () Inlines
110+ parseDecimalNum = try $ do
81− pref <- option mempty $ (mempty <$ char '+') <|> ("\x2212" <$ char '-')
111+ pref <- option mempty $ (mempty <$ char '+') <|> (minus <$ char '-')
82− basenum <- (pref <>) . T.pack
83− <$> many1 (satisfy (\c -> isDigit c || c == '.'))
112+ basenum' <- many1 (satisfy (\c -> isDigit c || c == '.'))
113+ let basenum = pref <> T.pack
114+ (case basenum' of
115+ '.':_ -> '0':basenum'
116+ _ -> basenum')
84 uncertainty <- option mempty $ T.pack <$> parseParens
117 uncertainty <- option mempty $ T.pack <$> parseParens
85 if T.null uncertainty
118 if T.null uncertainty
86 then return $ str basenum
119 then return $ str basenum
@@ -98,6 +131,7 @@ parseNumPart =
98 | otherwise -> "." <> t
131 | otherwise -> "." <> t
99 parseComma = str "." <$ char ','
132 parseComma = str "." <$ char ','
100 parsePlusMinus = str "\xa0\xb1\xa0" <$ try (string "+-")
133 parsePlusMinus = str "\xa0\xb1\xa0" <$ try (string "+-")
134+ parsePM = str "\xa0\xb1\xa0" <$ try (string "\\pm")
101 parseParens =
135 parseParens =
102 char '(' *> many1 (satisfy (\c -> isDigit c || c == '.')) <* char ')'
136 char '(' *> many1 (satisfy (\c -> isDigit c || c == '.')) <* char ')'
103 parseI = str "i" <$ char 'i'
137 parseI = str "i" <$ char 'i'
@@ -110,11 +144,14 @@ doSIang :: PandocMonad m => LP m Inlines
110doSIang = do
144doSIang = do
111 skipopts
145 skipopts
112 ps <- T.splitOn ";" . untokenize <$> braced
146 ps <- T.splitOn ";" . untokenize <$> braced
147+ let dropPlus t = case T.uncons t of
148+ Just ('+',t') -> t'
149+ _ -> t
113 case ps ++ repeat "" of
150 case ps ++ repeat "" of
114 (d:m:s:_) -> return $
151 (d:m:s:_) -> return $
115− (if T.null d then mempty else str d <> str "\xb0") <>
152+ (if T.null d then mempty else str (dropPlus d) <> str "\xb0") <>
116− (if T.null m then mempty else str m <> str "\x2032") <>
153+ (if T.null m then mempty else str (dropPlus m) <> str "\x2032") <>
117− (if T.null s then mempty else str s <> str "\x2033")
154+ (if T.null s then mempty else str (dropPlus s) <> str "\x2033")
118 _ -> return mempty
155 _ -> return mempty
119
156
120-- converts e.g. \SIrange{100}{200}{\ms} to "100 ms--200 ms"
157-- converts e.g. \SIrange{100}{200}{\ms} to "100 ms--200 ms"
@@ -143,40 +180,99 @@ doSIrange includeUnits tok = do
143emptyOr160 :: Inlines -> Inlines
180emptyOr160 :: Inlines -> Inlines
144emptyOr160 x = if x == mempty then x else str "\160"
181emptyOr160 x = if x == mempty then x else str "\160"
145
182
146−siUnit :: PandocMonad m => LP m Inlines -> LP m Inlines
183+siUnit :: forall m. PandocMonad m => [(Text,Text)] -> LP m Inlines -> LP m Inlines
147−siUnit tok = try (do
184+siUnit options tok = mconcat . intersperse (str "\xa0") <$> many1 siUnitPart
148− Tok _ (CtrlSeq name) _ <- anyControlSeq
185+ where
149− case name of
186+ siUnitPart :: LP m Inlines
187+ siUnitPart = try $ do
188+ skipMany (void (symbol '.') <|> void (symbol '~') <|> spaces1)
189+ x <- ((siPrefix <*> siBase)
190+ <|> (do u <- siBase <|> tok
191+ option u $ siSuffix <*> pure u))
192+ option x (siInfix x)
193+ siInfix :: Inlines -> LP m Inlines
194+ siInfix u1 = try $
195+ (do _ <- controlSeq "per"
196+ u2 <- siUnitPart
197+ let useSlash = lookup "per-mode" options == Just "symbol"
198+ if useSlash
199+ then return (u1 <> str "/" <> u2)
200+ else return (u1 <> str "\xa0" <> negateExponent u2))
201+ <|> (do _ <- symbol '/'
202+ u2 <- siUnitPart
203+ return (u1 <> str "/" <> u2))
204+ siPrefix :: LP m (Inlines -> Inlines)
205+ siPrefix =
150− "square" -> do
206+ (do _ <- controlSeq "square"
151− unit <- siUnit tok
207+ skipopts
152− return $ unit <> superscript "2"
208+ return (<> superscript "2"))
153− "cubic" -> do
209+ <|> (do _ <- controlSeq "cubic"
154− unit <- siUnit tok
210+ skipopts
155− return $ unit <> superscript "3"
211+ return (<> superscript "3"))
156− "raisetothe" -> do
212+ <|> (do _ <- controlSeq "raisetothe"
157− n <- tok
213+ skipopts
158− unit <- siUnit tok
214+ n <- walk hyphenToMinus <$> tok
159− return $ unit <> superscript n
215+ return (<> superscript n))
160− _ ->
216+ siSuffix :: LP m (Inlines -> Inlines)
161− case M.lookup name siUnitMap of
217+ siSuffix =
162− Just il ->
163− option il $
164− choice
165− [ (il <> superscript "2") <$ controlSeq "squared"
218+ (do _ <- controlSeq "squared"
219+ skipopts
220+ return (<> superscript "2"))
166− , (il <> superscript "3") <$ controlSeq "cubed"
221+ <|> (do _ <- controlSeq "cubed"
222+ skipopts
223+ return (<> superscript "3"))
167− , (\n -> il <> superscript n) <$> (controlSeq "tothe" *> tok)
224+ <|> (do _ <- controlSeq "tothe"
168− ]
225+ skipopts
226+ n <- walk hyphenToMinus <$> tok
227+ return (<> superscript n))
228+ <|> (symbol '^' *> (do n <- walk hyphenToMinus <$> tok
229+ return (<> superscript n)))
230+ <|> (symbol '_' *> (do n <- walk hyphenToMinus <$> tok
231+ return (<> subscript n)))
232+ negateExponent :: Inlines -> Inlines
233+ negateExponent ils =
234+ case Seq.viewr (unMany ils) of
235+ xs Seq.:> Superscript ss -> (Many xs) <>
236+ superscript (str minus <> fromList ss)
237+ _ -> ils <> superscript (str (minus <> "1"))
238+ siBase :: LP m Inlines
239+ siBase =
240+ ((try
241+ (do Tok _ (CtrlSeq name) _ <- anyControlSeq
242+ case M.lookup name siUnitModifierMap of
243+ Just il -> (il <>) <$> siBase
244+ Nothing ->
245+ case M.lookup name siUnitMap of
246+ Just il -> pure il
169− Nothing -> fail "not an siunit unit command")
247+ Nothing -> fail "not a unit command"))
170− <|> (lookAhead anyControlSeq >> tok)
171− <|> (do Tok _ Word t <- satisfyTok isWordTok
248+ <|> (do Tok _ Word t <- satisfyTok isWordTok
172− return $ str t)
249+ return $ str t)
173− <|> (symbol '^' *> (superscript <$> tok))
250+ )
174− <|> (symbol '_' *> (subscript <$> tok))
251+
175− <|> ("\xa0" <$ symbol '.')
252+siUnitModifierMap :: M.Map Text Inlines
176− <|> ("\xa0" <$ symbol '~')
253+siUnitModifierMap = M.fromList
177− <|> tok
254+ [ ("atto", str "a")
178− <|> (do Tok _ _ t <- anyTok
255+ , ("centi", str "c")
179− return (str t))
256+ , ("deca", str "d")
257+ , ("deci", str "d")
258+ , ("deka", str "d")
259+ , ("exa", str "E")
260+ , ("femto", str "f")
261+ , ("giga", str "G")
262+ , ("hecto", str "h")
263+ , ("kilo", str "k")
264+ , ("mega", str "M")
265+ , ("micro", str "μ")
266+ , ("milli", str "m")
267+ , ("nano", str "n")
268+ , ("peta", str "P")
269+ , ("pico", str "p")
270+ , ("tera", str "T")
271+ , ("yocto", str "y")
272+ , ("yotta", str "Y")
273+ , ("zepto", str "z")
274+ , ("zetta", str "Z")
275+ ]
180
276
181siUnitMap :: M.Map Text Inlines
277siUnitMap :: M.Map Text Inlines
182siUnitMap = M.fromList
278siUnitMap = M.fromList
@@ -276,7 +372,6 @@ siUnitMap = M.fromList
276 , ("arcsecond", str "″")
372 , ("arcsecond", str "″")
277 , ("astronomicalunit", str "ua")
373 , ("astronomicalunit", str "ua")
278 , ("atomicmassunit", str "u")
374 , ("atomicmassunit", str "u")
279− , ("atto", str "a")
280 , ("bar", str "bar")
375 , ("bar", str "bar")
281 , ("barn", str "b")
376 , ("barn", str "b")
282 , ("becquerel", str "Bq")
377 , ("becquerel", str "Bq")
@@ -284,51 +379,38 @@ siUnitMap = M.fromList
284 , ("bohr", emph (str "a") <> subscript (str "0"))
379 , ("bohr", emph (str "a") <> subscript (str "0"))
285 , ("candela", str "cd")
380 , ("candela", str "cd")
286 , ("celsius", str "°C")
381 , ("celsius", str "°C")
287− , ("centi", str "c")
288 , ("clight", emph (str "c") <> subscript (str "0"))
382 , ("clight", emph (str "c") <> subscript (str "0"))
289 , ("coulomb", str "C")
383 , ("coulomb", str "C")
290 , ("dalton", str "Da")
384 , ("dalton", str "Da")
291 , ("day", str "d")
385 , ("day", str "d")
292− , ("deca", str "d")
293− , ("deci", str "d")
294 , ("decibel", str "db")
386 , ("decibel", str "db")
295 , ("degreeCelsius",str "°C")
387 , ("degreeCelsius",str "°C")
296 , ("degree", str "°")
388 , ("degree", str "°")
297− , ("deka", str "d")
298 , ("electronmass", emph (str "m") <> subscript (str "e"))
389 , ("electronmass", emph (str "m") <> subscript (str "e"))
299 , ("electronvolt", str "eV")
390 , ("electronvolt", str "eV")
300 , ("elementarycharge", emph (str "e"))
391 , ("elementarycharge", emph (str "e"))
301− , ("exa", str "E")
302 , ("farad", str "F")
392 , ("farad", str "F")
303− , ("femto", str "f")
304− , ("giga", str "G")
305 , ("gram", str "g")
393 , ("gram", str "g")
306 , ("gray", str "Gy")
394 , ("gray", str "Gy")
307 , ("hartree", emph (str "E") <> subscript (str "h"))
395 , ("hartree", emph (str "E") <> subscript (str "h"))
308 , ("hectare", str "ha")
396 , ("hectare", str "ha")
309− , ("hecto", str "h")
310 , ("henry", str "H")
397 , ("henry", str "H")
311 , ("hertz", str "Hz")
398 , ("hertz", str "Hz")
312 , ("hour", str "h")
399 , ("hour", str "h")
313 , ("joule", str "J")
400 , ("joule", str "J")
314 , ("katal", str "kat")
401 , ("katal", str "kat")
315 , ("kelvin", str "K")
402 , ("kelvin", str "K")
316− , ("kilo", str "k")
317 , ("kilogram", str "kg")
403 , ("kilogram", str "kg")
318 , ("knot", str "kn")
404 , ("knot", str "kn")
319 , ("liter", str "L")
405 , ("liter", str "L")
320 , ("litre", str "l")
406 , ("litre", str "l")
321 , ("lumen", str "lm")
407 , ("lumen", str "lm")
322 , ("lux", str "lx")
408 , ("lux", str "lx")
323− , ("mega", str "M")
324 , ("meter", str "m")
409 , ("meter", str "m")
325 , ("metre", str "m")
410 , ("metre", str "m")
326− , ("micro", str "μ")
327− , ("milli", str "m")
328 , ("minute", str "min")
411 , ("minute", str "min")
329 , ("mmHg", str "mmHg")
412 , ("mmHg", str "mmHg")
330 , ("mole", str "mol")
413 , ("mole", str "mol")
331− , ("nano", str "n")
332 , ("nauticalmile", str "M")
414 , ("nauticalmile", str "M")
333 , ("neper", str "Np")
415 , ("neper", str "Np")
334 , ("newton", str "N")
416 , ("newton", str "N")
@@ -336,25 +418,17 @@ siUnitMap = M.fromList
336 , ("Pa", str "Pa")
418 , ("Pa", str "Pa")
337 , ("pascal", str "Pa")
419 , ("pascal", str "Pa")
338 , ("percent", str "%")
420 , ("percent", str "%")
339− , ("per", str "/")
340− , ("peta", str "P")
341− , ("pico", str "p")
342 , ("planckbar", emph (str "\x210f"))
421 , ("planckbar", emph (str "\x210f"))
343 , ("radian", str "rad")
422 , ("radian", str "rad")
344 , ("second", str "s")
423 , ("second", str "s")
345 , ("siemens", str "S")
424 , ("siemens", str "S")
346 , ("sievert", str "Sv")
425 , ("sievert", str "Sv")
347 , ("steradian", str "sr")
426 , ("steradian", str "sr")
348− , ("tera", str "T")
349 , ("tesla", str "T")
427 , ("tesla", str "T")
350 , ("tonne", str "t")
428 , ("tonne", str "t")
351 , ("volt", str "V")
429 , ("volt", str "V")
352 , ("watt", str "W")
430 , ("watt", str "W")
353 , ("weber", str "Wb")
431 , ("weber", str "Wb")
354− , ("yocto", str "y")
355− , ("yotta", str "Y")
356− , ("zepto", str "z")
357− , ("zetta", str "Z")
358 ]
432 ]
359
433
360
434
src/Text/Pandoc/Readers/LaTeX/Types.hs+14−1
@@ -1,3 +1,4 @@
1+{-# LANGUAGE FlexibleInstances #-}
1{- |
2{- |
2 Module : Text.Pandoc.Readers.LaTeX.Types
3 Module : Text.Pandoc.Readers.LaTeX.Types
3 Copyright : Copyright (C) 2017-2021 John MacFarlane
4 Copyright : Copyright (C) 2017-2021 John MacFarlane
@@ -18,7 +19,9 @@ module Text.Pandoc.Readers.LaTeX.Types ( Tok(..)
18 )
19 )
19where
20where
20import Data.Text (Text)
21import Data.Text (Text)
21−import Text.Parsec.Pos (SourcePos)
22+import Text.Parsec.Pos (SourcePos, sourceName)
23+import Text.Pandoc.Sources
24+import Data.List (groupBy)
22
25
23data TokType = CtrlSeq Text | Spaces | Newline | Symbol | Word | Comment |
26data TokType = CtrlSeq Text | Spaces | Newline | Symbol | Word | Comment |
24 Esc1 | Esc2 | Arg Int
27 Esc1 | Esc2 | Arg Int
@@ -27,6 +30,16 @@ data TokType = CtrlSeq Text | Spaces | Newline | Symbol | Word | Comment |
27data Tok = Tok SourcePos TokType Text
30data Tok = Tok SourcePos TokType Text
28 deriving (Eq, Ord, Show)
31 deriving (Eq, Ord, Show)
29
32
33+instance ToSources [Tok] where
34+ toSources = Sources
35+ . map (\ts -> case ts of
36+ Tok p _ _ : _ -> (p, mconcat $ map tokToText ts)
37+ _ -> error "toSources [Tok] encountered empty group")
38+ . groupBy (\(Tok p1 _ _) (Tok p2 _ _) -> sourceName p1 == sourceName p2)
39+
40+tokToText :: Tok -> Text
41+tokToText (Tok _ _ t) = t
42+
30data ExpansionPoint = ExpandWhenDefined | ExpandWhenUsed
43data ExpansionPoint = ExpandWhenDefined | ExpandWhenUsed
31 deriving (Eq, Ord, Show)
44 deriving (Eq, Ord, Show)
32
45
src/Text/Pandoc/Readers/Man.hs+18−11
@@ -20,7 +20,7 @@ import Control.Monad (liftM, mzero, guard, void)
20import Control.Monad.Trans (lift)
20import Control.Monad.Trans (lift)
21import Control.Monad.Except (throwError)
21import Control.Monad.Except (throwError)
22import Data.Maybe (catMaybes, isJust)
22import Data.Maybe (catMaybes, isJust)
23−import Data.List (intersperse, intercalate)
23+import Data.List (intersperse)
24import qualified Data.Text as T
24import qualified Data.Text as T
25import Text.Pandoc.Builder as B
25import Text.Pandoc.Builder as B
26import Text.Pandoc.Class.PandocMonad (PandocMonad(..), report)
26import Text.Pandoc.Class.PandocMonad (PandocMonad(..), report)
@@ -29,9 +29,8 @@ import Text.Pandoc.Logging (LogMessage(..))
29import Text.Pandoc.Options
29import Text.Pandoc.Options
30import Text.Pandoc.Parsing
30import Text.Pandoc.Parsing
31import Text.Pandoc.Walk (query)
31import Text.Pandoc.Walk (query)
32−import Text.Pandoc.Shared (crFilter, mapLeft)
32+import Text.Pandoc.Shared (mapLeft)
33import Text.Pandoc.Readers.Roff -- TODO explicit imports
33import Text.Pandoc.Readers.Roff -- TODO explicit imports
34−import Text.Parsec hiding (tokenPrim)
35import qualified Text.Parsec as Parsec
34import qualified Text.Parsec as Parsec
36import Text.Parsec.Pos (updatePosString)
35import Text.Parsec.Pos (updatePosString)
37import qualified Data.Foldable as Foldable
36import qualified Data.Foldable as Foldable
@@ -50,13 +49,20 @@ type ManParser m = ParserT [RoffToken] ManState m
50
49
51
50
52-- | Read man (troff) from an input string and return a Pandoc document.
51-- | Read man (troff) from an input string and return a Pandoc document.
53−readMan :: PandocMonad m => ReaderOptions -> T.Text -> m Pandoc
52+readMan :: (PandocMonad m, ToSources a)
53+ => ReaderOptions
54+ -> a
55+ -> m Pandoc
54−readMan opts txt = do
56+readMan opts s = do
55− tokenz <- lexRoff (initialPos "input") (crFilter txt)
57+ let Sources inps = toSources s
58+ tokenz <- mconcat <$> mapM (uncurry lexRoff) inps
56 let state = def {readerOptions = opts} :: ManState
59 let state = def {readerOptions = opts} :: ManState
60+ let fixError (PandocParsecError _ e) = PandocParsecError (Sources inps) e
61+ fixError e = e
57 eitherdoc <- readWithMTokens parseMan state
62 eitherdoc <- readWithMTokens parseMan state
58 (Foldable.toList . unRoffTokens $ tokenz)
63 (Foldable.toList . unRoffTokens $ tokenz)
59− either throwError return eitherdoc
64+ either (throwError . fixError) return eitherdoc
65+
60
66
61readWithMTokens :: PandocMonad m
67readWithMTokens :: PandocMonad m
62 => ParserT [RoffToken] ManState m a -- ^ parser
68 => ParserT [RoffToken] ManState m a -- ^ parser
@@ -64,9 +70,10 @@ readWithMTokens :: PandocMonad m
64 -> [RoffToken] -- ^ input
70 -> [RoffToken] -- ^ input
65 -> m (Either PandocError a)
71 -> m (Either PandocError a)
66readWithMTokens parser state input =
72readWithMTokens parser state input =
67− let leftF = PandocParsecError . T.pack . intercalate "\n" $ show <$> input
73+ let leftF = PandocParsecError mempty
68 in mapLeft leftF `liftM` runParserT parser state "source" input
74 in mapLeft leftF `liftM` runParserT parser state "source" input
69
75
76+
70parseMan :: PandocMonad m => ManParser m Pandoc
77parseMan :: PandocMonad m => ManParser m Pandoc
71parseMan = do
78parseMan = do
72 bs <- many parseBlock <* eof
79 bs <- many parseBlock <* eof
@@ -89,7 +96,7 @@ parseBlock = choice [ parseList
89
96
90parseTable :: PandocMonad m => ManParser m Blocks
97parseTable :: PandocMonad m => ManParser m Blocks
91parseTable = do
98parseTable = do
92− modifyState $ \st -> st { tableCellsPlain = True }
99+ updateState $ \st -> st { tableCellsPlain = True }
93 let isTbl Tbl{} = True
100 let isTbl Tbl{} = True
94 isTbl _ = False
101 isTbl _ = False
95 Tbl _opts rows pos <- msatisfy isTbl
102 Tbl _opts rows pos <- msatisfy isTbl
@@ -135,7 +142,7 @@ parseTable = do
135 case res' of
142 case res' of
136 Left _ -> Prelude.fail "Could not parse table cell"
143 Left _ -> Prelude.fail "Could not parse table cell"
137 Right x -> do
144 Right x -> do
138− modifyState $ \s -> s{ tableCellsPlain = False }
145+ updateState $ \s -> s{ tableCellsPlain = False }
139 return x
146 return x
140 Right x -> return x
147 Right x -> return x
141
148
@@ -222,7 +229,7 @@ parseTitle = do
222 setMeta "section" (linePartsToInlines y)
229 setMeta "section" (linePartsToInlines y)
223 [x] -> setMeta "title" (linePartsToInlines x)
230 [x] -> setMeta "title" (linePartsToInlines x)
224 [] -> id
231 [] -> id
225− modifyState $ \st -> st{ metadata = adjustMeta $ metadata st }
232+ updateState $ \st -> st{ metadata = adjustMeta $ metadata st }
226 return mempty
233 return mempty
227
234
228linePartsToInlines :: [LinePart] -> Inlines
235linePartsToInlines :: [LinePart] -> Inlines
src/Text/Pandoc/Readers/Markdown.hs+88−68
@@ -22,14 +22,16 @@ import Control.Monad
22import Control.Monad.Except (throwError)
22import Control.Monad.Except (throwError)
23import Data.Char (isAlphaNum, isPunctuation, isSpace)
23import Data.Char (isAlphaNum, isPunctuation, isSpace)
24import Data.List (transpose, elemIndex, sortOn, foldl')
24import Data.List (transpose, elemIndex, sortOn, foldl')
25+import Data.List.NonEmpty (NonEmpty(..))
25import qualified Data.Map as M
26import qualified Data.Map as M
26import Data.Maybe
27import Data.Maybe
27import qualified Data.Set as Set
28import qualified Data.Set as Set
28import Data.Text (Text)
29import Data.Text (Text)
29import qualified Data.Text as T
30import qualified Data.Text as T
30−import qualified Data.Text.Lazy as TL
31import qualified Data.ByteString.Lazy as BL
31import qualified Data.ByteString.Lazy as BL
32−import System.FilePath (addExtension, takeExtension)
32+import System.FilePath (addExtension, takeExtension, takeDirectory)
33+import qualified System.FilePath.Windows as Windows
34+import qualified System.FilePath.Posix as Posix
33import Text.HTML.TagSoup hiding (Row)
35import Text.HTML.TagSoup hiding (Row)
34import Text.Pandoc.Builder (Blocks, Inlines)
36import Text.Pandoc.Builder (Blocks, Inlines)
35import qualified Text.Pandoc.Builder as B
37import qualified Text.Pandoc.Builder as B
@@ -45,20 +47,22 @@ import Text.Pandoc.Readers.HTML (htmlInBalanced, htmlTag, isBlockTag,
45 isCommentTag, isInlineTag, isTextTag)
47 isCommentTag, isInlineTag, isTextTag)
46import Text.Pandoc.Readers.LaTeX (applyMacros, rawLaTeXBlock, rawLaTeXInline)
48import Text.Pandoc.Readers.LaTeX (applyMacros, rawLaTeXBlock, rawLaTeXInline)
47import Text.Pandoc.Shared
49import Text.Pandoc.Shared
48−import qualified Text.Pandoc.UTF8 as UTF8
49import Text.Pandoc.XML (fromEntities)
50import Text.Pandoc.XML (fromEntities)
50−import Text.Pandoc.Readers.Metadata (yamlBsToMeta, yamlBsToRefs)
51+import Text.Pandoc.Readers.Metadata (yamlBsToMeta, yamlBsToRefs, yamlMetaBlock)
52+-- import Debug.Trace (traceShowId)
51
53
52−type MarkdownParser m = ParserT Text ParserState m
54+type MarkdownParser m = ParserT Sources ParserState m
55+
56+type F = Future ParserState
53
57
54-- | Read markdown from an input string and return a Pandoc document.
58-- | Read markdown from an input string and return a Pandoc document.
55−readMarkdown :: PandocMonad m
59+readMarkdown :: (PandocMonad m, ToSources a)
56 => ReaderOptions -- ^ Reader options
60 => ReaderOptions -- ^ Reader options
57− -> Text -- ^ String to parse (assuming @'\n'@ line endings)
61+ -> a -- ^ Input
58 -> m Pandoc
62 -> m Pandoc
59readMarkdown opts s = do
63readMarkdown opts s = do
60 parsed <- readWithM parseMarkdown def{ stateOptions = opts }
64 parsed <- readWithM parseMarkdown def{ stateOptions = opts }
61− (crFilter s <> "\n\n")
65+ (ensureFinalNewlines 3 (toSources s))
62 case parsed of
66 case parsed of
63 Right result -> return result
67 Right result -> return result
64 Left e -> throwError e
68 Left e -> throwError e
@@ -79,7 +83,7 @@ yamlToMeta opts mbfp bstr = do
79 meta <- yamlBsToMeta (fmap B.toMetaValue <$> parseBlocks) bstr
83 meta <- yamlBsToMeta (fmap B.toMetaValue <$> parseBlocks) bstr
80 setPosition oldPos
84 setPosition oldPos
81 return $ runF meta defaultParserState
85 return $ runF meta defaultParserState
82− parsed <- readWithM parser def{ stateOptions = opts } ""
86+ parsed <- readWithM parser def{ stateOptions = opts } ("" :: Text)
83 case parsed of
87 case parsed of
84 Right result -> return result
88 Right result -> return result
85 Left e -> throwError e
89 Left e -> throwError e
@@ -95,14 +99,12 @@ yamlToRefs :: PandocMonad m
95 -> m [MetaValue]
99 -> m [MetaValue]
96yamlToRefs idpred opts mbfp bstr = do
100yamlToRefs idpred opts mbfp bstr = do
97 let parser = do
101 let parser = do
98− oldPos <- getPosition
99 case mbfp of
102 case mbfp of
100 Nothing -> return ()
103 Nothing -> return ()
101 Just fp -> setPosition $ initialPos fp
104 Just fp -> setPosition $ initialPos fp
102 refs <- yamlBsToRefs (fmap B.toMetaValue <$> parseBlocks) idpred bstr
105 refs <- yamlBsToRefs (fmap B.toMetaValue <$> parseBlocks) idpred bstr
103− setPosition oldPos
104 return $ runF refs defaultParserState
106 return $ runF refs defaultParserState
105− parsed <- readWithM parser def{ stateOptions = opts } ""
107+ parsed <- readWithM parser def{ stateOptions = opts } ("" :: Text)
106 case parsed of
108 case parsed of
107 Right result -> return result
109 Right result -> return result
108 Left e -> throwError e
110 Left e -> throwError e
@@ -145,14 +147,14 @@ inList = do
145 ctx <- stateParserContext <$> getState
147 ctx <- stateParserContext <$> getState
146 guard (ctx == ListItemState)
148 guard (ctx == ListItemState)
147
149
148−spnl :: PandocMonad m => ParserT Text st m ()
150+spnl :: PandocMonad m => ParserT Sources st m ()
149spnl = try $ do
151spnl = try $ do
150 skipSpaces
152 skipSpaces
151 optional newline
153 optional newline
152 skipSpaces
154 skipSpaces
153 notFollowedBy (char '\n')
155 notFollowedBy (char '\n')
154
156
155−spnl' :: PandocMonad m => ParserT Text st m Text
157+spnl' :: PandocMonad m => ParserT Sources st m Text
156spnl' = try $ do
158spnl' = try $ do
157 xs <- many spaceChar
159 xs <- many spaceChar
158 ys <- option "" $ try $ (:) <$> newline
160 ys <- option "" $ try $ (:) <$> newline
@@ -271,25 +273,13 @@ pandocTitleBlock = do
271 $ nullMeta
273 $ nullMeta
272 updateState $ \st -> st{ stateMeta' = stateMeta' st <> meta' }
274 updateState $ \st -> st{ stateMeta' = stateMeta' st <> meta' }
273
275
274−yamlMetaBlock :: PandocMonad m => MarkdownParser m (F Blocks)
276+yamlMetaBlock' :: PandocMonad m => MarkdownParser m (F Blocks)
275−yamlMetaBlock = do
277+yamlMetaBlock' = do
276 guardEnabled Ext_yaml_metadata_block
278 guardEnabled Ext_yaml_metadata_block
277− try $ do
278− string "---"
279− blankline
280− notFollowedBy blankline -- if --- is followed by a blank it's an HRULE
281− rawYamlLines <- manyTill anyLine stopLine
282− -- by including --- and ..., we allow yaml blocks with just comments:
283− let rawYaml = T.unlines ("---" : (rawYamlLines ++ ["..."]))
284− optional blanklines
285− newMetaF <- yamlBsToMeta (fmap B.toMetaValue <$> parseBlocks)
279+ newMetaF <- yamlMetaBlock (fmap B.toMetaValue <$> parseBlocks)
286− $ UTF8.fromTextLazy $ TL.fromStrict rawYaml
287− -- Since `<>` is left-biased, existing values are not touched:
280+ -- Since `<>` is left-biased, existing values are not touched:
288− updateState $ \st -> st{ stateMeta' = stateMeta' st <> newMetaF }
281+ updateState $ \st -> st{ stateMeta' = stateMeta' st <> newMetaF }
289− return mempty
282+ return mempty
290−
291−stopLine :: PandocMonad m => MarkdownParser m ()
292−stopLine = try $ (string "---" <|> string "...") >> blankline >> return ()
293
283
294mmdTitleBlock :: PandocMonad m => MarkdownParser m ()
284mmdTitleBlock :: PandocMonad m => MarkdownParser m ()
295mmdTitleBlock = do
285mmdTitleBlock = do
@@ -309,7 +299,7 @@ kvPair allowEmpty = try $ do
309 (try $ newline >> lookAhead (blankline <|> nonspaceChar))
299 (try $ newline >> lookAhead (blankline <|> nonspaceChar))
310 guard $ allowEmpty || not (T.null val)
300 guard $ allowEmpty || not (T.null val)
311 let key' = T.concat $ T.words $ T.toLower key
301 let key' = T.concat $ T.words $ T.toLower key
312− let val' = MetaBlocks $ B.toList $ B.plain $ B.text val
302+ let val' = MetaInlines $ B.toList $ B.text val
313 return (key',val')
303 return (key',val')
314
304
315parseMarkdown :: PandocMonad m => MarkdownParser m Pandoc
305parseMarkdown :: PandocMonad m => MarkdownParser m Pandoc
@@ -348,7 +338,9 @@ referenceKey = try $ do
348 notFollowedBy' (() <$ reference)
338 notFollowedBy' (() <$ reference)
349 many1Char $ notFollowedBy space >> litChar
339 many1Char $ notFollowedBy space >> litChar
350 let betweenAngles = try $ char '<' >> manyTillChar litChar (char '>')
340 let betweenAngles = try $ char '<' >> manyTillChar litChar (char '>')
341+ rebase <- option False (True <$ guardEnabled Ext_rebase_relative_paths)
342+ src <- (if rebase then rebasePath pos else id) <$>
351− src <- try betweenAngles <|> sourceURL
343+ (try betweenAngles <|> sourceURL)
352 tit <- option "" referenceTitle
344 tit <- option "" referenceTitle
353 attr <- option nullAttr $ try $
345 attr <- option nullAttr $ try $
354 do guardEnabled Ext_link_attributes
346 do guardEnabled Ext_link_attributes
@@ -453,7 +445,7 @@ block :: PandocMonad m => MarkdownParser m (F Blocks)
453block = do
445block = do
454 res <- choice [ mempty <$ blanklines
446 res <- choice [ mempty <$ blanklines
455 , codeBlockFenced
447 , codeBlockFenced
456− , yamlMetaBlock
448+ , yamlMetaBlock'
457 -- note: bulletList needs to be before header because of
449 -- note: bulletList needs to be before header because of
458 -- the possibility of empty list items: -
450 -- the possibility of empty list items: -
459 , bulletList
451 , bulletList
@@ -579,7 +571,7 @@ registerImplicitHeader raw attr@(ident, _, _)
579-- hrule block
571-- hrule block
580--
572--
581
573
582−hrule :: PandocMonad m => ParserT Text st m (F Blocks)
574+hrule :: PandocMonad m => ParserT Sources st m (F Blocks)
583hrule = try $ do
575hrule = try $ do
584 skipSpaces
576 skipSpaces
585 start <- satisfy isHruleChar
577 start <- satisfy isHruleChar
@@ -599,7 +591,7 @@ indentedLine = indentSpaces >> anyLineNewline
599blockDelimiter :: PandocMonad m
591blockDelimiter :: PandocMonad m
600 => (Char -> Bool)
592 => (Char -> Bool)
601 -> Maybe Int
593 -> Maybe Int
602− -> ParserT Text ParserState m Int
594+ -> ParserT Sources ParserState m Int
603blockDelimiter f len = try $ do
595blockDelimiter f len = try $ do
604 skipNonindentSpaces
596 skipNonindentSpaces
605 c <- lookAhead (satisfy f)
597 c <- lookAhead (satisfy f)
@@ -743,7 +735,7 @@ lhsCodeBlockBirdWith c = try $ do
743 blanklines
735 blanklines
744 return $ T.intercalate "\n" lns'
736 return $ T.intercalate "\n" lns'
745
737
746−birdTrackLine :: PandocMonad m => Char -> ParserT Text st m Text
738+birdTrackLine :: PandocMonad m => Char -> ParserT Sources st m Text
747birdTrackLine c = try $ do
739birdTrackLine c = try $ do
748 char c
740 char c
749 -- allow html tags on left margin:
741 -- allow html tags on left margin:
@@ -1036,7 +1028,7 @@ para = try $ do
1036 option (B.plain <$> result)
1028 option (B.plain <$> result)
1037 $ try $ do
1029 $ try $ do
1038 newline
1030 newline
1039− (blanklines >> return mempty)
1031+ (mempty <$ blanklines)
1040 <|> (guardDisabled Ext_blank_before_blockquote >> () <$ lookAhead blockQuote)
1032 <|> (guardDisabled Ext_blank_before_blockquote >> () <$ lookAhead blockQuote)
1041 <|> (guardEnabled Ext_backtick_code_blocks >> () <$ lookAhead codeBlockFenced)
1033 <|> (guardEnabled Ext_backtick_code_blocks >> () <$ lookAhead codeBlockFenced)
1042 <|> (guardDisabled Ext_blank_before_header >> () <$ lookAhead header)
1034 <|> (guardDisabled Ext_blank_before_header >> () <$ lookAhead header)
@@ -1181,7 +1173,7 @@ lineBlock = do
1181-- and the length including trailing space.
1173-- and the length including trailing space.
1182dashedLine :: PandocMonad m
1174dashedLine :: PandocMonad m
1183 => Char
1175 => Char
1184− -> ParserT Text st m (Int, Int)
1176+ -> ParserT Sources st m (Int, Int)
1185dashedLine ch = do
1177dashedLine ch = do
1186 dashes <- many1 (char ch)
1178 dashes <- many1 (char ch)
1187 sp <- many spaceChar
1179 sp <- many spaceChar
@@ -1250,7 +1242,7 @@ rawTableLine :: PandocMonad m
1250 -> MarkdownParser m [Text]
1242 -> MarkdownParser m [Text]
1251rawTableLine indices = do
1243rawTableLine indices = do
1252 notFollowedBy' (blanklines' <|> tableFooter)
1244 notFollowedBy' (blanklines' <|> tableFooter)
1253− line <- take1WhileP (/='\n') <* newline
1245+ line <- anyLine
1254 return $ map trim $ tail $
1246 return $ map trim $ tail $
1255 splitTextByIndices (init indices) line
1247 splitTextByIndices (init indices) line
1256
1248
@@ -1364,7 +1356,7 @@ pipeTable = try $ do
1364 lines' <- many pipeTableRow
1356 lines' <- many pipeTableRow
1365 let lines'' = map (take (length aligns) <$>) lines'
1357 let lines'' = map (take (length aligns) <$>) lines'
1366 let maxlength = maximum $
1358 let maxlength = maximum $
1367− map (\x -> T.length . stringify $ runF x def) (heads' : lines'')
1359+ fmap (\x -> T.length . stringify $ runF x def) (heads' :| lines'')
1368 numColumns <- getOption readerColumns
1360 numColumns <- getOption readerColumns
1369 let widths = if maxlength > numColumns
1361 let widths = if maxlength > numColumns
1370 then map (\len ->
1362 then map (\len ->
@@ -1401,7 +1393,7 @@ pipeTableCell =
1401 return $ B.plain <$> result)
1393 return $ B.plain <$> result)
1402 <|> return mempty
1394 <|> return mempty
1403
1395
1404−pipeTableHeaderPart :: PandocMonad m => ParserT Text st m (Alignment, Int)
1396+pipeTableHeaderPart :: PandocMonad m => ParserT Sources st m (Alignment, Int)
1405pipeTableHeaderPart = try $ do
1397pipeTableHeaderPart = try $ do
1406 skipMany spaceChar
1398 skipMany spaceChar
1407 left <- optionMaybe (char ':')
1399 left <- optionMaybe (char ':')
@@ -1417,10 +1409,14 @@ pipeTableHeaderPart = try $ do
1417 (Just _,Just _) -> AlignCenter, len)
1409 (Just _,Just _) -> AlignCenter, len)
1418
1410
1419-- Succeed only if current line contains a pipe.
1411-- Succeed only if current line contains a pipe.
1420−scanForPipe :: PandocMonad m => ParserT Text st m ()
1412+scanForPipe :: PandocMonad m => ParserT Sources st m ()
1421scanForPipe = do
1413scanForPipe = do
1422− inp <- getInput
1414+ Sources inps <- getInput
1415+ let ln = case inps of
1416+ [] -> ""
1417+ ((_,t):(_,t'):_) | T.null t -> t'
1418+ ((_,t):_) -> t
1423− case T.break (\c -> c == '\n' || c == '|') inp of
1419+ case T.break (\c -> c == '\n' || c == '|') ln of
1424 (_, T.uncons -> Just ('|', _)) -> return ()
1420 (_, T.uncons -> Just ('|', _)) -> return ()
1425 _ -> mzero
1421 _ -> mzero
1426
1422
@@ -1714,13 +1710,13 @@ whitespace = spaceChar >> return <$> (lb <|> regsp) <?> "whitespace"
1714 where lb = spaceChar >> skipMany spaceChar >> option B.space (endline >> return B.linebreak)
1710 where lb = spaceChar >> skipMany spaceChar >> option B.space (endline >> return B.linebreak)
1715 regsp = skipMany spaceChar >> return B.space
1711 regsp = skipMany spaceChar >> return B.space
1716
1712
1717−nonEndline :: PandocMonad m => ParserT Text st m Char
1713+nonEndline :: PandocMonad m => ParserT Sources st m Char
1718nonEndline = satisfy (/='\n')
1714nonEndline = satisfy (/='\n')
1719
1715
1720str :: PandocMonad m => MarkdownParser m (F Inlines)
1716str :: PandocMonad m => MarkdownParser m (F Inlines)
1721str = do
1717str = do
1722 result <- mconcat <$> many1
1718 result <- mconcat <$> many1
1723− ( take1WhileP isAlphaNum
1719+ ( T.pack <$> (many1 alphaNum)
1724 <|> "." <$ try (char '.' <* notFollowedBy (char '.')) )
1720 <|> "." <$ try (char '.' <* notFollowedBy (char '.')) )
1725 updateLastStrPos
1721 updateLastStrPos
1726 (do guardEnabled Ext_smart
1722 (do guardEnabled Ext_smart
@@ -1844,9 +1840,12 @@ regLink :: PandocMonad m
1844 -> MarkdownParser m (F Inlines)
1840 -> MarkdownParser m (F Inlines)
1845regLink constructor lab = try $ do
1841regLink constructor lab = try $ do
1846 (src, tit) <- source
1842 (src, tit) <- source
1843+ rebase <- option False (True <$ guardEnabled Ext_rebase_relative_paths)
1844+ pos <- getPosition
1845+ let src' = if rebase then rebasePath pos src else src
1847 attr <- option nullAttr $
1846 attr <- option nullAttr $
1848 guardEnabled Ext_link_attributes >> attributes
1847 guardEnabled Ext_link_attributes >> attributes
1849− return $ constructor attr src tit <$> lab
1848+ return $ constructor attr src' tit <$> lab
1850
1849
1851-- a link like [this][ref] or [this][] or [this]
1850-- a link like [this][ref] or [this][] or [this]
1852referenceLink :: PandocMonad m
1851referenceLink :: PandocMonad m
@@ -1886,7 +1885,8 @@ referenceLink constructor (lab, raw) = do
1886 Just ((src, tit), _) -> constructor nullAttr src tit <$> lab
1885 Just ((src, tit), _) -> constructor nullAttr src tit <$> lab
1887 Nothing -> makeFallback
1886 Nothing -> makeFallback
1888 else makeFallback
1887 else makeFallback
1888+ Just ((src,tit), attr) ->
1889− Just ((src,tit), attr) -> constructor attr src tit <$> lab
1889+ constructor attr src tit <$> lab
1890
1890
1891dropBrackets :: Text -> Text
1891dropBrackets :: Text -> Text
1892dropBrackets = dropRB . dropLB
1892dropBrackets = dropRB . dropLB
@@ -1919,15 +1919,33 @@ autoLink = try $ do
1919 return $ return $ B.linkWith attr (src <> escapeURI extra) ""
1919 return $ return $ B.linkWith attr (src <> escapeURI extra) ""
1920 (B.str $ orig <> extra)
1920 (B.str $ orig <> extra)
1921
1921
1922+-- | Rebase a relative path, by adding the (relative) directory
1923+-- of the containing source position. Absolute links and URLs
1924+-- are untouched.
1925+rebasePath :: SourcePos -> Text -> Text
1926+rebasePath pos path = do
1927+ let fp = sourceName pos
1928+ isFragment = T.take 1 path == "#"
1929+ path' = T.unpack path
1930+ isAbsolutePath = Posix.isAbsolute path' || Windows.isAbsolute path'
1931+ in if T.null path || isFragment || isAbsolutePath || isURI path
1932+ then path
1933+ else
1934+ case takeDirectory fp of
1935+ "" -> path
1936+ "." -> path
1937+ d -> T.pack d <> "/" <> path
1938+
1922image :: PandocMonad m => MarkdownParser m (F Inlines)
1939image :: PandocMonad m => MarkdownParser m (F Inlines)
1923image = try $ do
1940image = try $ do
1924 char '!'
1941 char '!'
1925 (lab,raw) <- reference
1942 (lab,raw) <- reference
1926 defaultExt <- getOption readerDefaultImageExtension
1943 defaultExt <- getOption readerDefaultImageExtension
1944+ let constructor attr' src =
1927− let constructor attr' src = case takeExtension (T.unpack src) of
1945+ case takeExtension (T.unpack src) of
1928− "" -> B.imageWith attr' (T.pack $ addExtension (T.unpack src)
1946+ "" -> B.imageWith attr' (T.pack $ addExtension (T.unpack src)
1929− $ T.unpack defaultExt)
1947+ $ T.unpack defaultExt)
1930− _ -> B.imageWith attr' src
1948+ _ -> B.imageWith attr' src
1931 regLink constructor lab <|> referenceLink constructor (lab,raw)
1949 regLink constructor lab <|> referenceLink constructor (lab,raw)
1932
1950
1933note :: PandocMonad m => MarkdownParser m (F Inlines)
1951note :: PandocMonad m => MarkdownParser m (F Inlines)
@@ -1973,7 +1991,7 @@ rawLaTeXInline' = do
1973 s <- rawLaTeXInline
1991 s <- rawLaTeXInline
1974 return $ return $ B.rawInline "tex" s -- "tex" because it might be context
1992 return $ return $ B.rawInline "tex" s -- "tex" because it might be context
1975
1993
1976−rawConTeXtEnvironment :: PandocMonad m => ParserT Text st m Text
1994+rawConTeXtEnvironment :: PandocMonad m => ParserT Sources st m Text
1977rawConTeXtEnvironment = try $ do
1995rawConTeXtEnvironment = try $ do
1978 string "\\start"
1996 string "\\start"
1979 completion <- inBrackets (letter <|> digit <|> spaceChar)
1997 completion <- inBrackets (letter <|> digit <|> spaceChar)
@@ -1982,7 +2000,7 @@ rawConTeXtEnvironment = try $ do
1982 (try $ string "\\stop" >> textStr completion)
2000 (try $ string "\\stop" >> textStr completion)
1983 return $ "\\start" <> completion <> T.concat contents <> "\\stop" <> completion
2001 return $ "\\start" <> completion <> T.concat contents <> "\\stop" <> completion
1984
2002
1985−inBrackets :: PandocMonad m => ParserT Text st m Char -> ParserT Text st m Text
2003+inBrackets :: PandocMonad m => ParserT Sources st m Char -> ParserT Sources st m Text
1986inBrackets parser = do
2004inBrackets parser = do
1987 char '['
2005 char '['
1988 contents <- manyChar parser
2006 contents <- manyChar parser
@@ -2102,7 +2120,7 @@ cite = do
2102
2120
2103textualCite :: PandocMonad m => MarkdownParser m (F Inlines)
2121textualCite :: PandocMonad m => MarkdownParser m (F Inlines)
2104textualCite = try $ do
2122textualCite = try $ do
2105− (suppressAuthor, key) <- citeKey
2123+ (suppressAuthor, key) <- citeKey True
2106 -- If this is a reference to an earlier example list item,
2124 -- If this is a reference to an earlier example list item,
2107 -- then don't parse it as a citation. If the example list
2125 -- then don't parse it as a citation. If the example list
2108 -- item comes later, we'll parse it here and figure out in
2126 -- item comes later, we'll parse it here and figure out in
@@ -2182,7 +2200,7 @@ prefix = trimInlinesF . mconcat <$>
2182 manyTill inline (char ']'
2200 manyTill inline (char ']'
2183 <|> lookAhead
2201 <|> lookAhead
2184 (try $ do optional (try (char ';' >> spnl))
2202 (try $ do optional (try (char ';' >> spnl))
2185− citeKey
2203+ citeKey True
2186 return ']'))
2204 return ']'))
2187
2205
2188citeList :: PandocMonad m => MarkdownParser m (F [Citation])
2206citeList :: PandocMonad m => MarkdownParser m (F [Citation])
@@ -2191,7 +2209,7 @@ citeList = fmap sequence $ sepBy1 citation (try $ char ';' >> spnl)
2191citation :: PandocMonad m => MarkdownParser m (F Citation)
2209citation :: PandocMonad m => MarkdownParser m (F Citation)
2192citation = try $ do
2210citation = try $ do
2193 pref <- prefix
2211 pref <- prefix
2194− (suppress_author, key) <- citeKey
2212+ (suppress_author, key) <- citeKey True
2195 suff <- suffix
2213 suff <- suffix
2196 noteNum <- stateNoteNumber <$> getState
2214 noteNum <- stateNoteNumber <$> getState
2197 return $ do
2215 return $ do
@@ -2210,28 +2228,30 @@ citation = try $ do
2210smart :: PandocMonad m => MarkdownParser m (F Inlines)
2228smart :: PandocMonad m => MarkdownParser m (F Inlines)
2211smart = do
2229smart = do
2212 guardEnabled Ext_smart
2230 guardEnabled Ext_smart
2213− doubleQuoted <|> singleQuoted <|>
2231+ doubleQuoted <|> singleQuoted <|> (return <$> doubleCloseQuote) <|>
2214− choice (map (return <$>) [apostrophe, dash, ellipses])
2232+ (return <$> apostrophe) <|> (return <$> dash) <|> (return <$> ellipses)
2215
2233
2216singleQuoted :: PandocMonad m => MarkdownParser m (F Inlines)
2234singleQuoted :: PandocMonad m => MarkdownParser m (F Inlines)
2217−singleQuoted = try $ do
2235+singleQuoted = do
2218 singleQuoteStart
2236 singleQuoteStart
2219− withQuoteContext InSingleQuote $
2237+ (try (withQuoteContext InSingleQuote $
2220 fmap B.singleQuoted . trimInlinesF . mconcat <$>
2238 fmap B.singleQuoted . trimInlinesF . mconcat <$>
2221− many1Till inline singleQuoteEnd
2239+ many1Till inline singleQuoteEnd))
2240+ <|> (return (return (B.str "\8217")))
2222
2241
2223-- doubleQuoted will handle regular double-quoted sections, as well
2242-- doubleQuoted will handle regular double-quoted sections, as well
2224-- as dialogues with an open double-quote without a close double-quote
2243-- as dialogues with an open double-quote without a close double-quote
2225-- in the same paragraph.
2244-- in the same paragraph.
2226doubleQuoted :: PandocMonad m => MarkdownParser m (F Inlines)
2245doubleQuoted :: PandocMonad m => MarkdownParser m (F Inlines)
2227−doubleQuoted = try $ do
2246+doubleQuoted = do
2228 doubleQuoteStart
2247 doubleQuoteStart
2229− withQuoteContext InDoubleQuote $
2248+ (try (withQuoteContext InDoubleQuote $
2230 fmap B.doubleQuoted . trimInlinesF . mconcat <$>
2249 fmap B.doubleQuoted . trimInlinesF . mconcat <$>
2231− many1Till inline doubleQuoteEnd
2250+ many1Till inline doubleQuoteEnd))
2251+ <|> (return (return (B.str "\8220")))
2232
2252
2233toRow :: [Blocks] -> Row
2253toRow :: [Blocks] -> Row
2234toRow = Row nullAttr . map B.simpleCell
2254toRow = Row nullAttr . map B.simpleCell
2235
2255
2236toHeaderRow :: [Blocks] -> [Row]
2256toHeaderRow :: [Blocks] -> [Row]
2237−toHeaderRow l = [toRow l | not (null l)]
2257+toHeaderRow l = [toRow l | not (null l) && not (all null l)]
src/Text/Pandoc/Readers/MediaWiki.hs+7−6
@@ -36,17 +36,18 @@ import Text.Pandoc.Logging
36import Text.Pandoc.Options
36import Text.Pandoc.Options
37import Text.Pandoc.Parsing hiding (nested)
37import Text.Pandoc.Parsing hiding (nested)
38import Text.Pandoc.Readers.HTML (htmlTag, isBlockTag, isCommentTag)
38import Text.Pandoc.Readers.HTML (htmlTag, isBlockTag, isCommentTag)
39−import Text.Pandoc.Shared (crFilter, safeRead, stringify, stripTrailingNewlines,
39+import Text.Pandoc.Shared (safeRead, stringify, stripTrailingNewlines,
40 trim, splitTextBy, tshow)
40 trim, splitTextBy, tshow)
41import Text.Pandoc.Walk (walk)
41import Text.Pandoc.Walk (walk)
42import Text.Pandoc.XML (fromEntities)
42import Text.Pandoc.XML (fromEntities)
43
43
44-- | Read mediawiki from an input string and return a Pandoc document.
44-- | Read mediawiki from an input string and return a Pandoc document.
45−readMediaWiki :: PandocMonad m
45+readMediaWiki :: (PandocMonad m, ToSources a)
46− => ReaderOptions -- ^ Reader options
46+ => ReaderOptions
47− -> Text -- ^ String to parse (assuming @'\n'@ line endings)
47+ -> a
48 -> m Pandoc
48 -> m Pandoc
49readMediaWiki opts s = do
49readMediaWiki opts s = do
50+ let sources = toSources s
50 parsed <- readWithM parseMediaWiki MWState{ mwOptions = opts
51 parsed <- readWithM parseMediaWiki MWState{ mwOptions = opts
51 , mwMaxNestingLevel = 4
52 , mwMaxNestingLevel = 4
52 , mwNextLinkNumber = 1
53 , mwNextLinkNumber = 1
@@ -55,7 +56,7 @@ readMediaWiki opts s = do
55 , mwLogMessages = []
56 , mwLogMessages = []
56 , mwInTT = False
57 , mwInTT = False
57 }
58 }
58− (crFilter s <> "\n")
59+ sources
59 case parsed of
60 case parsed of
60 Right result -> return result
61 Right result -> return result
61 Left e -> throwError e
62 Left e -> throwError e
@@ -69,7 +70,7 @@ data MWState = MWState { mwOptions :: ReaderOptions
69 , mwInTT :: Bool
70 , mwInTT :: Bool
70 }
71 }
71
72
72−type MWParser m = ParserT Text MWState m
73+type MWParser m = ParserT Sources MWState m
73
74
74instance HasReaderOptions MWState where
75instance HasReaderOptions MWState where
75 extractReaderOptions = mwOptions
76 extractReaderOptions = mwOptions
src/Text/Pandoc/Readers/Metadata.hs+44−17
@@ -14,6 +14,7 @@ Parse YAML/JSON metadata to 'Pandoc' 'Meta'.
14module Text.Pandoc.Readers.Metadata (
14module Text.Pandoc.Readers.Metadata (
15 yamlBsToMeta,
15 yamlBsToMeta,
16 yamlBsToRefs,
16 yamlBsToRefs,
17+ yamlMetaBlock,
17 yamlMap ) where
18 yamlMap ) where
18
19
19import Control.Monad
20import Control.Monad
@@ -30,11 +31,13 @@ import Text.Pandoc.Definition
30import Text.Pandoc.Error
31import Text.Pandoc.Error
31import Text.Pandoc.Parsing hiding (tableWith)
32import Text.Pandoc.Parsing hiding (tableWith)
32import Text.Pandoc.Shared
33import Text.Pandoc.Shared
34+import qualified Data.Text.Lazy as TL
35+import qualified Text.Pandoc.UTF8 as UTF8
33
36
34−yamlBsToMeta :: PandocMonad m
37+yamlBsToMeta :: (PandocMonad m, HasLastStrPosition st)
35− => ParserT Text ParserState m (F MetaValue)
38+ => ParserT Sources st m (Future st MetaValue)
36 -> BL.ByteString
39 -> BL.ByteString
37− -> ParserT Text ParserState m (F Meta)
40+ -> ParserT Sources st m (Future st Meta)
38yamlBsToMeta pMetaValue bstr = do
41yamlBsToMeta pMetaValue bstr = do
39 case YAML.decodeNode' YAML.failsafeSchemaResolver False False bstr of
42 case YAML.decodeNode' YAML.failsafeSchemaResolver False False bstr of
40 Right (YAML.Doc (YAML.Mapping _ _ o):_)
43 Right (YAML.Doc (YAML.Mapping _ _ o):_)
@@ -42,6 +45,9 @@ yamlBsToMeta pMetaValue bstr = do
42 Right [] -> return . return $ mempty
45 Right [] -> return . return $ mempty
43 Right [YAML.Doc (YAML.Scalar _ YAML.SNull)]
46 Right [YAML.Doc (YAML.Scalar _ YAML.SNull)]
44 -> return . return $ mempty
47 -> return . return $ mempty
48+ -- the following is what we get from a comment:
49+ Right [YAML.Doc (YAML.Scalar _ (YAML.SUnknown _ ""))]
50+ -> return . return $ mempty
45 Right _ -> Prelude.fail "expected YAML object"
51 Right _ -> Prelude.fail "expected YAML object"
46 Left (yamlpos, err')
52 Left (yamlpos, err')
47 -> do pos <- getPosition
53 -> do pos <- getPosition
@@ -63,11 +69,11 @@ lookupYAML t (YAML.Mapping _ _ m) =
63lookupYAML _ _ = Nothing
69lookupYAML _ _ = Nothing
64
70
65-- Returns filtered list of references.
71-- Returns filtered list of references.
66−yamlBsToRefs :: PandocMonad m
72+yamlBsToRefs :: (PandocMonad m, HasLastStrPosition st)
67− => ParserT Text ParserState m (F MetaValue)
73+ => ParserT Sources st m (Future st MetaValue)
68 -> (Text -> Bool) -- ^ Filter for id
74 -> (Text -> Bool) -- ^ Filter for id
69 -> BL.ByteString
75 -> BL.ByteString
70− -> ParserT Text ParserState m (F [MetaValue])
76+ -> ParserT Sources st m (Future st [MetaValue])
71yamlBsToRefs pMetaValue idpred bstr =
77yamlBsToRefs pMetaValue idpred bstr =
72 case YAML.decodeNode' YAML.failsafeSchemaResolver False False bstr of
78 case YAML.decodeNode' YAML.failsafeSchemaResolver False False bstr of
73 Right (YAML.Doc o@YAML.Mapping{}:_)
79 Right (YAML.Doc o@YAML.Mapping{}:_)
@@ -95,8 +101,12 @@ yamlBsToRefs pMetaValue idpred bstr =
95 Right [YAML.Doc (YAML.Scalar _ YAML.SNull)]
101 Right [YAML.Doc (YAML.Scalar _ YAML.SNull)]
96 -> return . return $ mempty
102 -> return . return $ mempty
97 Right _ -> Prelude.fail "expecting YAML object"
103 Right _ -> Prelude.fail "expecting YAML object"
98− Left (_pos, err')
104+ Left (yamlpos, err')
105+ -> do pos <- getPosition
106+ setPosition $ incSourceLine
107+ (setSourceColumn pos (YE.posColumn yamlpos))
108+ (YE.posLine yamlpos - 1)
99− -> Prelude.fail err'
109+ Prelude.fail err'
100
110
101
111
102nodeToKey :: YAML.Node YE.Pos -> Maybe Text
112nodeToKey :: YAML.Node YE.Pos -> Maybe Text
@@ -104,10 +114,10 @@ nodeToKey (YAML.Scalar _ (YAML.SStr t)) = Just t
104nodeToKey (YAML.Scalar _ (YAML.SUnknown _ t)) = Just t
114nodeToKey (YAML.Scalar _ (YAML.SUnknown _ t)) = Just t
105nodeToKey _ = Nothing
115nodeToKey _ = Nothing
106
116
107−normalizeMetaValue :: PandocMonad m
117+normalizeMetaValue :: (PandocMonad m, HasLastStrPosition st)
108− => ParserT Text ParserState m (F MetaValue)
118+ => ParserT Sources st m (Future st MetaValue)
109 -> Text
119 -> Text
110− -> ParserT Text ParserState m (F MetaValue)
120+ -> ParserT Sources st m (Future st MetaValue)
111normalizeMetaValue pMetaValue x =
121normalizeMetaValue pMetaValue x =
112 -- Note: a standard quoted or unquoted YAML value will
122 -- Note: a standard quoted or unquoted YAML value will
113 -- not end in a newline, but a "block" set off with
123 -- not end in a newline, but a "block" set off with
@@ -129,10 +139,10 @@ checkBoolean t
129 | t == T.pack "false" || t == T.pack "False" || t == T.pack "FALSE" = Just False
139 | t == T.pack "false" || t == T.pack "False" || t == T.pack "FALSE" = Just False
130 | otherwise = Nothing
140 | otherwise = Nothing
131
141
132−yamlToMetaValue :: PandocMonad m
142+yamlToMetaValue :: (PandocMonad m, HasLastStrPosition st)
133− => ParserT Text ParserState m (F MetaValue)
143+ => ParserT Sources st m (Future st MetaValue)
134 -> YAML.Node YE.Pos
144 -> YAML.Node YE.Pos
135− -> ParserT Text ParserState m (F MetaValue)
145+ -> ParserT Sources st m (Future st MetaValue)
136yamlToMetaValue pMetaValue (YAML.Scalar _ x) =
146yamlToMetaValue pMetaValue (YAML.Scalar _ x) =
137 case x of
147 case x of
138 YAML.SStr t -> normalizeMetaValue pMetaValue t
148 YAML.SStr t -> normalizeMetaValue pMetaValue t
@@ -152,10 +162,10 @@ yamlToMetaValue pMetaValue (YAML.Mapping _ _ o) =
152 fmap MetaMap <$> yamlMap pMetaValue o
162 fmap MetaMap <$> yamlMap pMetaValue o
153yamlToMetaValue _ _ = return $ return $ MetaString ""
163yamlToMetaValue _ _ = return $ return $ MetaString ""
154
164
155−yamlMap :: PandocMonad m
165+yamlMap :: (PandocMonad m, HasLastStrPosition st)
156− => ParserT Text ParserState m (F MetaValue)
166+ => ParserT Sources st m (Future st MetaValue)
157 -> M.Map (YAML.Node YE.Pos) (YAML.Node YE.Pos)
167 -> M.Map (YAML.Node YE.Pos) (YAML.Node YE.Pos)
158− -> ParserT Text ParserState m (F (M.Map Text MetaValue))
168+ -> ParserT Sources st m (Future st (M.Map Text MetaValue))
159yamlMap pMetaValue o = do
169yamlMap pMetaValue o = do
160 kvs <- forM (M.toList o) $ \(key, v) -> do
170 kvs <- forM (M.toList o) $ \(key, v) -> do
161 k <- maybe (throwError $ PandocParseError
171 k <- maybe (throwError $ PandocParseError
@@ -171,3 +181,20 @@ yamlMap pMetaValue o = do
171 return $ do
181 return $ do
172 v' <- fv
182 v' <- fv
173 return (k, v')
183 return (k, v')
184+
185+-- | Parse a YAML metadata block using the supplied 'MetaValue' parser.
186+yamlMetaBlock :: (HasLastStrPosition st, PandocMonad m)
187+ => ParserT Sources st m (Future st MetaValue)
188+ -> ParserT Sources st m (Future st Meta)
189+yamlMetaBlock parser = try $ do
190+ string "---"
191+ blankline
192+ notFollowedBy blankline -- if --- is followed by a blank it's an HRULE
193+ rawYamlLines <- manyTill anyLine stopLine
194+ -- by including --- and ..., we allow yaml blocks with just comments:
195+ let rawYaml = T.unlines ("---" : (rawYamlLines ++ ["..."]))
196+ optional blanklines
197+ yamlBsToMeta parser $ UTF8.fromTextLazy $ TL.fromStrict rawYaml
198+
199+stopLine :: Monad m => ParserT Sources st m ()
200+stopLine = try $ (string "---" <|> string "...") >> blankline >> return ()
src/Text/Pandoc/Readers/Muse.hs+10−9
@@ -36,19 +36,20 @@ import Text.Pandoc.Definition
36import Text.Pandoc.Error (PandocError (PandocParsecError))
36import Text.Pandoc.Error (PandocError (PandocParsecError))
37import Text.Pandoc.Logging
37import Text.Pandoc.Logging
38import Text.Pandoc.Options
38import Text.Pandoc.Options
39−import Text.Pandoc.Parsing hiding (F)
39+import Text.Pandoc.Parsing
40−import Text.Pandoc.Shared (crFilter, trimr, tshow)
40+import Text.Pandoc.Shared (trimr, tshow)
41
41
42-- | Read Muse from an input string and return a Pandoc document.
42-- | Read Muse from an input string and return a Pandoc document.
43−readMuse :: PandocMonad m
43+readMuse :: (PandocMonad m, ToSources a)
44 => ReaderOptions
44 => ReaderOptions
45− -> Text
45+ -> a
46 -> m Pandoc
46 -> m Pandoc
47readMuse opts s = do
47readMuse opts s = do
48− let input = crFilter s
48+ let sources = toSources s
49− res <- flip runReaderT def $ runParserT parseMuse def{ museOptions = opts } "source" input
49+ res <- flip runReaderT def $ runParserT parseMuse def{ museOptions = opts }
50+ (initialSourceName sources) sources
50 case res of
51 case res of
51− Left e -> throwError $ PandocParsecError input e
52+ Left e -> throwError $ PandocParsecError sources e
52 Right d -> return d
53 Right d -> return d
53
54
54type F = Future MuseState
55type F = Future MuseState
@@ -82,7 +83,7 @@ instance Default MuseEnv where
82 , museInPara = False
83 , museInPara = False
83 }
84 }
84
85
85−type MuseParser m = ParserT Text MuseState (ReaderT MuseEnv m)
86+type MuseParser m = ParserT Sources MuseState (ReaderT MuseEnv m)
86
87
87instance HasReaderOptions MuseState where
88instance HasReaderOptions MuseState where
88 extractReaderOptions = museOptions
89 extractReaderOptions = museOptions
@@ -155,7 +156,7 @@ firstColumn = getPosition >>= \pos -> guard (sourceColumn pos == 1)
155-- * Parsers
156-- * Parsers
156
157
157-- | Parse end-of-line, which can be either a newline or end-of-file.
158-- | Parse end-of-line, which can be either a newline or end-of-file.
158−eol :: Stream s m Char => ParserT s st m ()
159+eol :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m ()
159eol = void newline <|> eof
160eol = void newline <|> eof
160
161
161getIndent :: PandocMonad m
162getIndent :: PandocMonad m
src/Text/Pandoc/Readers/Native.hs+7−5
@@ -21,6 +21,7 @@ import Control.Monad.Except (throwError)
21import Data.Text (Text)
21import Data.Text (Text)
22import Text.Pandoc.Class.PandocMonad (PandocMonad)
22import Text.Pandoc.Class.PandocMonad (PandocMonad)
23import Text.Pandoc.Error
23import Text.Pandoc.Error
24+import Text.Pandoc.Sources (ToSources(..), sourcesToText)
24
25
25-- | Read native formatted text and return a Pandoc document.
26-- | Read native formatted text and return a Pandoc document.
26-- The input may be a full pandoc document, a block list, a block,
27-- The input may be a full pandoc document, a block list, a block,
@@ -32,14 +33,15 @@ import Text.Pandoc.Error
32--
33--
33-- > Pandoc nullMeta [Plain [Str "hi"]]
34-- > Pandoc nullMeta [Plain [Str "hi"]]
34--
35--
35−readNative :: PandocMonad m
36+readNative :: (PandocMonad m, ToSources a)
36 => ReaderOptions
37 => ReaderOptions
37− -> Text -- ^ String to parse (assuming @'\n'@ line endings)
38+ -> a
38 -> m Pandoc
39 -> m Pandoc
39readNative _ s =
40readNative _ s =
41+ let t = sourcesToText . toSources $ s
40− case maybe (Pandoc nullMeta <$> readBlocks s) Right (safeRead s) of
42+ in case maybe (Pandoc nullMeta <$> readBlocks t) Right (safeRead t) of
41− Right doc -> return doc
43+ Right doc -> return doc
42− Left _ -> throwError $ PandocParseError "couldn't read native"
44+ Left _ -> throwError $ PandocParseError "couldn't read native"
43
45
44readBlocks :: Text -> Either PandocError [Block]
46readBlocks :: Text -> Either PandocError [Block]
45readBlocks s = maybe ((:[]) <$> readBlock s) Right (safeRead s)
47readBlocks s = maybe ((:[]) <$> readBlock s) Right (safeRead s)
src/Text/Pandoc/Readers/OPML.hs+9−4
@@ -24,7 +24,8 @@ import Text.Pandoc.Options
24import Text.Pandoc.Error (PandocError(..))
24import Text.Pandoc.Error (PandocError(..))
25import Text.Pandoc.Readers.HTML (readHtml)
25import Text.Pandoc.Readers.HTML (readHtml)
26import Text.Pandoc.Readers.Markdown (readMarkdown)
26import Text.Pandoc.Readers.Markdown (readMarkdown)
27−import Text.Pandoc.Shared (crFilter, blocksToInlines')
27+import Text.Pandoc.Shared (blocksToInlines')
28+import Text.Pandoc.Sources (ToSources(..), sourcesToText)
28import Text.Pandoc.XML.Light
29import Text.Pandoc.XML.Light
29import Control.Monad.Except (throwError)
30import Control.Monad.Except (throwError)
30
31
@@ -46,10 +47,14 @@ instance Default OPMLState where
46 , opmlOptions = def
47 , opmlOptions = def
47 }
48 }
48
49
49−readOPML :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
50+readOPML :: (PandocMonad m, ToSources a)
51+ => ReaderOptions
52+ -> a
53+ -> m Pandoc
50readOPML opts inp = do
54readOPML opts inp = do
55+ let sources = toSources inp
51− (bs, st') <- runStateT
56+ (bs, st') <-
52− (case parseXMLContents (TL.fromStrict (crFilter inp)) of
57+ runStateT (case parseXMLContents (TL.fromStrict . sourcesToText $ sources) of
53 Left msg -> throwError $ PandocXMLError "" msg
58 Left msg -> throwError $ PandocXMLError "" msg
54 Right ns -> mapM parseBlock ns)
59 Right ns -> mapM parseBlock ns)
55 def{ opmlOptions = opts }
60 def{ opmlOptions = opts }
src/Text/Pandoc/Readers/Odt/ContentReader.hs+12−7
@@ -1,4 +1,5 @@
1{-# LANGUAGE Arrows #-}
1{-# LANGUAGE Arrows #-}
2+{-# LANGUAGE CPP #-}
2{-# LANGUAGE DeriveFoldable #-}
3{-# LANGUAGE DeriveFoldable #-}
3{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4{-# LANGUAGE PatternGuards #-}
5{-# LANGUAGE PatternGuards #-}
@@ -33,7 +34,7 @@ import Data.List (find)
33import qualified Data.Map as M
34import qualified Data.Map as M
34import qualified Data.Text as T
35import qualified Data.Text as T
35import Data.Maybe
36import Data.Maybe
36−import Data.Semigroup (First(..), Option(..))
37+import Data.Monoid (Alt (..))
37
38
38import Text.TeXMath (readMathML, writeTeX)
39import Text.TeXMath (readMathML, writeTeX)
39import qualified Text.Pandoc.XML.Light as XML
40import qualified Text.Pandoc.XML.Light as XML
@@ -505,13 +506,11 @@ type InlineMatcher = ElementMatcher Inlines
505
506
506type BlockMatcher = ElementMatcher Blocks
507type BlockMatcher = ElementMatcher Blocks
507
508
508−
509−newtype FirstMatch a = FirstMatch (Option (First a))
509+newtype FirstMatch a = FirstMatch (Alt Maybe a)
510− deriving (Foldable, Monoid, Semigroup)
510+ deriving (Foldable, Monoid, Semigroup)
511
511
512firstMatch :: a -> FirstMatch a
512firstMatch :: a -> FirstMatch a
513−firstMatch = FirstMatch . Option . Just . First
513+firstMatch = FirstMatch . Alt . Just
514−
515
514
516--
515--
517matchingElement :: (Monoid e)
516matchingElement :: (Monoid e)
@@ -577,7 +576,10 @@ read_spaces = matchingElement NsText "s" (
577read_line_break :: InlineMatcher
576read_line_break :: InlineMatcher
578read_line_break = matchingElement NsText "line-break"
577read_line_break = matchingElement NsText "line-break"
579 $ returnV linebreak
578 $ returnV linebreak
580−
579+--
580+read_tab :: InlineMatcher
581+read_tab = matchingElement NsText "tab"
582+ $ returnV space
581--
583--
582read_span :: InlineMatcher
584read_span :: InlineMatcher
583read_span = matchingElement NsText "span"
585read_span = matchingElement NsText "span"
@@ -585,6 +587,7 @@ read_span = matchingElement NsText "span"
585 $ matchChildContent [ read_span
587 $ matchChildContent [ read_span
586 , read_spaces
588 , read_spaces
587 , read_line_break
589 , read_line_break
590+ , read_tab
588 , read_link
591 , read_link
589 , read_note
592 , read_note
590 , read_citation
593 , read_citation
@@ -604,6 +607,7 @@ read_paragraph = matchingElement NsText "p"
604 $ matchChildContent [ read_span
607 $ matchChildContent [ read_span
605 , read_spaces
608 , read_spaces
606 , read_line_break
609 , read_line_break
610+ , read_tab
607 , read_link
611 , read_link
608 , read_note
612 , read_note
609 , read_citation
613 , read_citation
@@ -630,6 +634,7 @@ read_header = matchingElement NsText "h"
630 children <- ( matchChildContent [ read_span
634 children <- ( matchChildContent [ read_span
631 , read_spaces
635 , read_spaces
632 , read_line_break
636 , read_line_break
637+ , read_tab
633 , read_link
638 , read_link
634 , read_note
639 , read_note
635 , read_citation
640 , read_citation
src/Text/Pandoc/Readers/Org.hs+4−7
@@ -18,22 +18,19 @@ import Text.Pandoc.Class.PandocMonad (PandocMonad)
18import Text.Pandoc.Definition
18import Text.Pandoc.Definition
19import Text.Pandoc.Options
19import Text.Pandoc.Options
20import Text.Pandoc.Parsing (reportLogMessages)
20import Text.Pandoc.Parsing (reportLogMessages)
21−import Text.Pandoc.Shared (crFilter)
21+import Text.Pandoc.Sources (ToSources(..), ensureFinalNewlines)
22−
23import Control.Monad.Except (throwError)
22import Control.Monad.Except (throwError)
24import Control.Monad.Reader (runReaderT)
23import Control.Monad.Reader (runReaderT)
25
24
26−import Data.Text (Text)
27−
28-- | Parse org-mode string and return a Pandoc document.
25-- | Parse org-mode string and return a Pandoc document.
29−readOrg :: PandocMonad m
26+readOrg :: (PandocMonad m, ToSources a)
30 => ReaderOptions -- ^ Reader options
27 => ReaderOptions -- ^ Reader options
31− -> Text -- ^ String to parse (assuming @'\n'@ line endings)
28+ -> a
32 -> m Pandoc
29 -> m Pandoc
33readOrg opts s = do
30readOrg opts s = do
34 parsed <- flip runReaderT def $
31 parsed <- flip runReaderT def $
35 readWithM parseOrg (optionsToParserState opts)
32 readWithM parseOrg (optionsToParserState opts)
36− (crFilter s <> "\n\n")
33+ (ensureFinalNewlines 2 (toSources s))
37 case parsed of
34 case parsed of
38 Right result -> return result
35 Right result -> return result
39 Left e -> throwError e
36 Left e -> throwError e
src/Text/Pandoc/Readers/Org/Blocks.hs+7−4
@@ -39,10 +39,12 @@ import Data.Functor (($>))
39import Data.List (foldl', intersperse)
39import Data.List (foldl', intersperse)
40import Data.Maybe (fromMaybe, isJust, isNothing)
40import Data.Maybe (fromMaybe, isJust, isNothing)
41import Data.Text (Text)
41import Data.Text (Text)
42−
42+import Data.List.NonEmpty (nonEmpty)
43+import System.FilePath
43import qualified Data.Text as T
44import qualified Data.Text as T
44import qualified Text.Pandoc.Builder as B
45import qualified Text.Pandoc.Builder as B
45import qualified Text.Pandoc.Walk as Walk
46import qualified Text.Pandoc.Walk as Walk
47+import Text.Pandoc.Sources (ToSources(..))
46
48
47--
49--
48-- parsing blocks
50-- parsing blocks
@@ -526,7 +528,9 @@ include = try $ do
526 _ -> nullAttr
528 _ -> nullAttr
527 return $ pure . B.codeBlockWith attr <$> parseRaw
529 return $ pure . B.codeBlockWith attr <$> parseRaw
528 _ -> return $ return . B.fromList . blockFilter params <$> blockList
530 _ -> return $ return . B.fromList . blockFilter params <$> blockList
529− insertIncludedFileF blocksParser ["."] filename
531+ currentDir <- takeDirectory . sourceName <$> getPosition
532+ insertIncludedFile blocksParser toSources
533+ [currentDir] filename Nothing Nothing
530 where
534 where
531 includeTarget :: PandocMonad m => OrgParser m FilePath
535 includeTarget :: PandocMonad m => OrgParser m FilePath
532 includeTarget = do
536 includeTarget = do
@@ -542,8 +546,7 @@ include = try $ do
542 in case (minlvl >>= safeRead :: Maybe Int) of
546 in case (minlvl >>= safeRead :: Maybe Int) of
543 Nothing -> blks
547 Nothing -> blks
544 Just lvl -> let levels = Walk.query headerLevel blks
548 Just lvl -> let levels = Walk.query headerLevel blks
545− -- CAVE: partial function in else
546− curMin = if null levels then 0 else minimum levels
549+ curMin = maybe 0 minimum $ nonEmpty levels
547 in Walk.walk (shiftHeader (curMin - lvl)) blks
550 in Walk.walk (shiftHeader (curMin - lvl)) blks
548
551
549 headerLevel :: Block -> [Int]
552 headerLevel :: Block -> [Int]
src/Text/Pandoc/Readers/Org/Inlines.hs+6−5
@@ -29,6 +29,7 @@ import Text.Pandoc.Definition
29import Text.Pandoc.Options
29import Text.Pandoc.Options
30import Text.Pandoc.Readers.LaTeX (inlineCommand, rawLaTeXInline)
30import Text.Pandoc.Readers.LaTeX (inlineCommand, rawLaTeXInline)
31import Text.TeXMath (DisplayType (..), readTeX, writePandoc)
31import Text.TeXMath (DisplayType (..), readTeX, writePandoc)
32+import Text.Pandoc.Sources (ToSources(..))
32import qualified Text.TeXMath.Readers.MathML.EntityMap as MathMLEntityMap
33import qualified Text.TeXMath.Readers.MathML.EntityMap as MathMLEntityMap
33
34
34import Control.Monad (guard, mplus, mzero, unless, void, when)
35import Control.Monad (guard, mplus, mzero, unless, void, when)
@@ -262,7 +263,7 @@ berkeleyCitationList = try $ do
262 where
263 where
263 citationListPart :: PandocMonad m => OrgParser m (F Inlines)
264 citationListPart :: PandocMonad m => OrgParser m (F Inlines)
264 citationListPart = fmap (trimInlinesF . mconcat) . try . many1 $ do
265 citationListPart = fmap (trimInlinesF . mconcat) . try . many1 $ do
265− notFollowedBy' citeKey
266+ notFollowedBy' $ citeKey False
266 notFollowedBy (oneOf ";]")
267 notFollowedBy (oneOf ";]")
267 inline
268 inline
268
269
@@ -277,7 +278,7 @@ berkeleyBareTag' = try $ void (string "cite")
277
278
278berkeleyTextualCite :: PandocMonad m => OrgParser m (F [Citation])
279berkeleyTextualCite :: PandocMonad m => OrgParser m (F [Citation])
279berkeleyTextualCite = try $ do
280berkeleyTextualCite = try $ do
280− (suppressAuthor, key) <- citeKey
281+ (suppressAuthor, key) <- citeKey False
281 returnF . return $ Citation
282 returnF . return $ Citation
282 { citationId = key
283 { citationId = key
283 , citationPrefix = mempty
284 , citationPrefix = mempty
@@ -350,7 +351,7 @@ citeList = sequence <$> sepEndBy1 citation (try $ char ';' *> skipSpaces)
350citation :: PandocMonad m => OrgParser m (F Citation)
351citation :: PandocMonad m => OrgParser m (F Citation)
351citation = try $ do
352citation = try $ do
352 pref <- prefix
353 pref <- prefix
353− (suppress_author, key) <- citeKey
354+ (suppress_author, key) <- citeKey False
354 suff <- suffix
355 suff <- suffix
355 return $ do
356 return $ do
356 x <- pref
357 x <- pref
@@ -367,7 +368,7 @@ citation = try $ do
367 }
368 }
368 where
369 where
369 prefix = trimInlinesF . mconcat <$>
370 prefix = trimInlinesF . mconcat <$>
370− manyTill inline (char ']' <|> (']' <$ lookAhead citeKey))
371+ manyTill inline (char ']' <|> (']' <$ lookAhead (citeKey False)))
371 suffix = try $ do
372 suffix = try $ do
372 hasSpace <- option False (notFollowedBy nonspaceChar >> return True)
373 hasSpace <- option False (notFollowedBy nonspaceChar >> return True)
373 skipSpaces
374 skipSpaces
@@ -802,7 +803,7 @@ inlineLaTeX = try $ do
802 parseAsInlineLaTeX :: PandocMonad m
803 parseAsInlineLaTeX :: PandocMonad m
803 => Text -> TeXExport -> OrgParser m (Maybe Inlines)
804 => Text -> TeXExport -> OrgParser m (Maybe Inlines)
804 parseAsInlineLaTeX cs = \case
805 parseAsInlineLaTeX cs = \case
805− TeXExport -> maybeRight <$> runParserT inlineCommand state "" cs
806+ TeXExport -> maybeRight <$> runParserT inlineCommand state "" (toSources cs)
806 TeXIgnore -> return (Just mempty)
807 TeXIgnore -> return (Just mempty)
807 TeXVerbatim -> return (Just $ B.str cs)
808 TeXVerbatim -> return (Just $ B.str cs)
808
809
src/Text/Pandoc/Readers/Org/Parsing.hs+5−5
@@ -63,8 +63,7 @@ module Text.Pandoc.Readers.Org.Parsing
63 , ellipses
63 , ellipses
64 , citeKey
64 , citeKey
65 , gridTableWith
65 , gridTableWith
66− , insertIncludedFileF
66+ , insertIncludedFile
67− -- * Re-exports from Text.Pandoc.Parsec
68 , runParser
67 , runParser
69 , runParserT
68 , runParserT
70 , getInput
69 , getInput
@@ -100,21 +99,22 @@ module Text.Pandoc.Readers.Org.Parsing
100 , getState
99 , getState
101 , updateState
100 , updateState
102 , SourcePos
101 , SourcePos
102+ , sourceName
103 , getPosition
103 , getPosition
104 ) where
104 ) where
105
105
106import Data.Text (Text)
106import Data.Text (Text)
107import Text.Pandoc.Readers.Org.ParserState
107import Text.Pandoc.Readers.Org.ParserState
108
108
109−import Text.Pandoc.Parsing hiding (F, anyLine, blanklines, newline,
109+import Text.Pandoc.Parsing hiding (anyLine, blanklines, newline,
110− parseFromString)
110+ parseFromString)
111import qualified Text.Pandoc.Parsing as P
111import qualified Text.Pandoc.Parsing as P
112
112
113import Control.Monad (guard)
113import Control.Monad (guard)
114import Control.Monad.Reader (ReaderT)
114import Control.Monad.Reader (ReaderT)
115
115
116-- | The parser used to read org files.
116-- | The parser used to read org files.
117−type OrgParser m = ParserT Text OrgParserState (ReaderT OrgParserLocal m)
117+type OrgParser m = ParserT Sources OrgParserState (ReaderT OrgParserLocal m)
118
118
119--
119--
120-- Adaptions and specializations of parsing utilities
120-- Adaptions and specializations of parsing utilities
src/Text/Pandoc/Readers/RST.hs+76−109
@@ -27,8 +27,7 @@ import Data.Text (Text)
27import qualified Data.Text as T
27import qualified Data.Text as T
28import Text.Pandoc.Builder (Blocks, Inlines, fromList, setMeta, trimInlines)
28import Text.Pandoc.Builder (Blocks, Inlines, fromList, setMeta, trimInlines)
29import qualified Text.Pandoc.Builder as B
29import qualified Text.Pandoc.Builder as B
30−import Text.Pandoc.Class.PandocMonad (PandocMonad, fetchItem,
30+import Text.Pandoc.Class.PandocMonad (PandocMonad, fetchItem, getTimestamp)
31− readFileFromDirs, getTimestamp)
32import Text.Pandoc.CSV (CSVOptions (..), defaultCSVOptions, parseCSV)
31import Text.Pandoc.CSV (CSVOptions (..), defaultCSVOptions, parseCSV)
33import Text.Pandoc.Definition
32import Text.Pandoc.Definition
34import Text.Pandoc.Error
33import Text.Pandoc.Error
@@ -38,25 +37,25 @@ import Text.Pandoc.Options
38import Text.Pandoc.Parsing
37import Text.Pandoc.Parsing
39import Text.Pandoc.Shared
38import Text.Pandoc.Shared
40import qualified Text.Pandoc.UTF8 as UTF8
39import qualified Text.Pandoc.UTF8 as UTF8
41−import Text.Printf (printf)
42import Data.Time.Format
40import Data.Time.Format
41+import System.FilePath (takeDirectory)
43
42
44-- TODO:
43-- TODO:
45-- [ ] .. parsed-literal
44-- [ ] .. parsed-literal
46
45
47-- | Parse reStructuredText string and return Pandoc document.
46-- | Parse reStructuredText string and return Pandoc document.
48−readRST :: PandocMonad m
47+readRST :: (PandocMonad m, ToSources a)
49 => ReaderOptions -- ^ Reader options
48 => ReaderOptions -- ^ Reader options
50− -> Text -- ^ Text to parse (assuming @'\n'@ line endings)
49+ -> a
51 -> m Pandoc
50 -> m Pandoc
52readRST opts s = do
51readRST opts s = do
53 parsed <- readWithM parseRST def{ stateOptions = opts }
52 parsed <- readWithM parseRST def{ stateOptions = opts }
54− (crFilter s <> "\n\n")
53+ (ensureFinalNewlines 2 (toSources s))
55 case parsed of
54 case parsed of
56 Right result -> return result
55 Right result -> return result
57 Left e -> throwError e
56 Left e -> throwError e
58
57
59−type RSTParser m = ParserT Text ParserState m
58+type RSTParser m = ParserT Sources ParserState m
60
59
61--
60--
62-- Constants and data structure definitions
61-- Constants and data structure definitions
@@ -151,11 +150,19 @@ parseRST = do
151 startPos <- getPosition
150 startPos <- getPosition
152 -- go through once just to get list of reference keys and notes
151 -- go through once just to get list of reference keys and notes
153 -- docMinusKeys is the raw document with blanks where the keys were...
152 -- docMinusKeys is the raw document with blanks where the keys were...
154− docMinusKeys <- T.concat <$>
155− manyTill (referenceKey <|> anchorDef <|>
153+ let chunk = referenceKey
154+ <|> anchorDef
155+ <|> noteBlock
156− noteBlock <|> citationBlock <|>
156+ <|> citationBlock
157− (snd <$> withRaw comment) <|>
157+ <|> (snd <$> withRaw comment)
158− headerBlock <|> lineClump) eof
158+ <|> headerBlock
159+ <|> lineClump
160+ docMinusKeys <- Sources <$>
161+ manyTill (do pos <- getPosition
162+ t <- chunk
163+ return (pos, t)) eof
164+ -- UGLY: we collapse source position information.
165+ -- TODO: fix the parser to use the F monad instead of two passes
159 setInput docMinusKeys
166 setInput docMinusKeys
160 setPosition startPos
167 setPosition startPos
161 st' <- getState
168 st' <- getState
@@ -348,7 +355,7 @@ singleHeader' = try $ do
348-- hrule block
355-- hrule block
349--
356--
350
357
351−hrule :: Monad m => ParserT Text st m Blocks
358+hrule :: Monad m => ParserT Sources st m Blocks
352hrule = try $ do
359hrule = try $ do
353 chr <- oneOf underlineChars
360 chr <- oneOf underlineChars
354 count 3 (char chr)
361 count 3 (char chr)
@@ -363,7 +370,7 @@ hrule = try $ do
363
370
364-- read a line indented by a given string
371-- read a line indented by a given string
365indentedLine :: (HasReaderOptions st, Monad m)
372indentedLine :: (HasReaderOptions st, Monad m)
366− => Int -> ParserT Text st m Text
373+ => Int -> ParserT Sources st m Text
367indentedLine indents = try $ do
374indentedLine indents = try $ do
368 lookAhead spaceChar
375 lookAhead spaceChar
369 gobbleAtMostSpaces indents
376 gobbleAtMostSpaces indents
@@ -372,7 +379,7 @@ indentedLine indents = try $ do
372-- one or more indented lines, possibly separated by blank lines.
379-- one or more indented lines, possibly separated by blank lines.
373-- any amount of indentation will work.
380-- any amount of indentation will work.
374indentedBlock :: (HasReaderOptions st, Monad m)
381indentedBlock :: (HasReaderOptions st, Monad m)
375− => ParserT Text st m Text
382+ => ParserT Sources st m Text
376indentedBlock = try $ do
383indentedBlock = try $ do
377 indents <- length <$> lookAhead (many1 spaceChar)
384 indents <- length <$> lookAhead (many1 spaceChar)
378 lns <- many1 $ try $ do b <- option "" blanklines
385 lns <- many1 $ try $ do b <- option "" blanklines
@@ -381,20 +388,20 @@ indentedBlock = try $ do
381 optional blanklines
388 optional blanklines
382 return $ T.unlines lns
389 return $ T.unlines lns
383
390
384−quotedBlock :: Monad m => ParserT Text st m Text
391+quotedBlock :: Monad m => ParserT Sources st m Text
385quotedBlock = try $ do
392quotedBlock = try $ do
386 quote <- lookAhead $ oneOf "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
393 quote <- lookAhead $ oneOf "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
387 lns <- many1 $ lookAhead (char quote) >> anyLine
394 lns <- many1 $ lookAhead (char quote) >> anyLine
388 optional blanklines
395 optional blanklines
389 return $ T.unlines lns
396 return $ T.unlines lns
390
397
391−codeBlockStart :: Monad m => ParserT Text st m Char
398+codeBlockStart :: Monad m => ParserT Sources st m Char
392codeBlockStart = string "::" >> blankline >> blankline
399codeBlockStart = string "::" >> blankline >> blankline
393
400
394−codeBlock :: Monad m => ParserT Text ParserState m Blocks
401+codeBlock :: Monad m => ParserT Sources ParserState m Blocks
395codeBlock = try $ codeBlockStart >> codeBlockBody
402codeBlock = try $ codeBlockStart >> codeBlockBody
396
403
397−codeBlockBody :: Monad m => ParserT Text ParserState m Blocks
404+codeBlockBody :: Monad m => ParserT Sources ParserState m Blocks
398codeBlockBody = do
405codeBlockBody = do
399 lang <- stateRstHighlight <$> getState
406 lang <- stateRstHighlight <$> getState
400 try $ B.codeBlockWith ("", maybeToList lang, []) . stripTrailingNewlines <$>
407 try $ B.codeBlockWith ("", maybeToList lang, []) . stripTrailingNewlines <$>
@@ -410,14 +417,14 @@ lhsCodeBlock = try $ do
410 return $ B.codeBlockWith ("", ["haskell","literate"], [])
417 return $ B.codeBlockWith ("", ["haskell","literate"], [])
411 $ T.intercalate "\n" lns
418 $ T.intercalate "\n" lns
412
419
413−latexCodeBlock :: Monad m => ParserT Text st m [Text]
420+latexCodeBlock :: Monad m => ParserT Sources st m [Text]
414latexCodeBlock = try $ do
421latexCodeBlock = try $ do
415 try (latexBlockLine "\\begin{code}")
422 try (latexBlockLine "\\begin{code}")
416 many1Till anyLine (try $ latexBlockLine "\\end{code}")
423 many1Till anyLine (try $ latexBlockLine "\\end{code}")
417 where
424 where
418 latexBlockLine s = skipMany spaceChar >> string s >> blankline
425 latexBlockLine s = skipMany spaceChar >> string s >> blankline
419
426
420−birdCodeBlock :: Monad m => ParserT Text st m [Text]
427+birdCodeBlock :: Monad m => ParserT Sources st m [Text]
421birdCodeBlock = filterSpace <$> many1 birdTrackLine
428birdCodeBlock = filterSpace <$> many1 birdTrackLine
422 where filterSpace lns =
429 where filterSpace lns =
423 -- if (as is normal) there is always a space after >, drop it
430 -- if (as is normal) there is always a space after >, drop it
@@ -425,7 +432,7 @@ birdCodeBlock = filterSpace <$> many1 birdTrackLine
425 then map (T.drop 1) lns
432 then map (T.drop 1) lns
426 else lns
433 else lns
427
434
428−birdTrackLine :: Monad m => ParserT Text st m Text
435+birdTrackLine :: Monad m => ParserT Sources st m Text
429birdTrackLine = char '>' >> anyLine
436birdTrackLine = char '>' >> anyLine
430
437
431--
438--
@@ -446,64 +453,39 @@ encoding
446-}
453-}
447
454
448includeDirective :: PandocMonad m
455includeDirective :: PandocMonad m
456+ => Text
449− => Text -> [(Text, Text)] -> Text
457+ -> [(Text, Text)]
458+ -> Text
450 -> RSTParser m Blocks
459 -> RSTParser m Blocks
451includeDirective top fields body = do
460includeDirective top fields body = do
452− let f = trim top
461+ let f = T.unpack $ trim top
453− guard $ not (T.null f)
462+ guard $ not $ null f
454 guard $ T.null (trim body)
463 guard $ T.null (trim body)
455− -- options
456− let (startLine :: Maybe Int) = lookup "start-line" fields >>= safeRead
464+ let startLine = lookup "start-line" fields >>= safeRead
457− let (endLine :: Maybe Int) = lookup "end-line" fields >>= safeRead
465+ let endLine = lookup "end-line" fields >>= safeRead
458− oldPos <- getPosition
459− oldInput <- getInput
460− containers <- stateContainers <$> getState
461− when (f `elem` containers) $
462− throwError $ PandocParseError $ "Include file loop at " <> tshow oldPos
463− updateState $ \s -> s{ stateContainers = f : stateContainers s }
464− mbContents <- readFileFromDirs ["."] $ T.unpack f
465− contentLines <- case mbContents of
466− Just s -> return $ T.lines s
467− Nothing -> do
468− logMessage $ CouldNotLoadIncludeFile f oldPos
469− return []
470− let numLines = length contentLines
471− let startLine' = case startLine of
472− Nothing -> 1
473− Just x | x >= 0 -> x
474− | otherwise -> numLines + x -- negative from end
475− let endLine' = case endLine of
476− Nothing -> numLines + 1
477− Just x | x >= 0 -> x
478− | otherwise -> numLines + x -- negative from end
479− let contentLines' = drop (startLine' - 1)
480− $ take (endLine' - 1) contentLines
481− let contentLines'' = (case trim <$> lookup "end-before" fields of
482− Just patt -> takeWhile (not . (patt `T.isInfixOf`))
483− Nothing -> id) .
484− (case trim <$> lookup "start-after" fields of
485− Just patt -> drop 1 .
486− dropWhile (not . (patt `T.isInfixOf`))
487− Nothing -> id) $ contentLines'
488− let contents' = T.unlines contentLines''
489− case lookup "code" fields of
490− Just lang -> do
491− let classes = maybe [] T.words (lookup "class" fields)
466+ let classes = maybe [] T.words (lookup "class" fields)
492− let ident = maybe "" trimr $ lookup "name" fields
467+ let ident = maybe "" trimr $ lookup "name" fields
468+ let parser =
469+ case lookup "code" fields of
470+ Just lang ->
493− codeblock ident classes fields (trimr lang) contents' False
471+ (codeblock ident classes fields (trimr lang) False
472+ . sourcesToText) <$> getInput
473+ Nothing ->
494− Nothing -> case lookup "literal" fields of
474+ case lookup "literal" fields of
495− Just _ -> return $ B.rawBlock "rst" contents'
475+ Just _ -> B.rawBlock "rst" . sourcesToText <$> getInput
496− Nothing -> do
476+ Nothing -> parseBlocks
497− setPosition $ newPos (T.unpack f) 1 1
477+ let selectLines =
498− setInput $ contents' <> "\n"
478+ (case trim <$> lookup "end-before" fields of
499− bs <- optional blanklines >>
479+ Just patt -> takeWhile (not . (patt `T.isInfixOf`))
500− (mconcat <$> many block)
480+ Nothing -> id) .
501− setInput oldInput
481+ (case trim <$> lookup "start-after" fields of
502− setPosition oldPos
482+ Just patt -> drop 1 .
503− updateState $ \s -> s{ stateContainers =
483+ dropWhile (not . (patt `T.isInfixOf`))
504− tail $ stateContainers s }
484+ Nothing -> id)
505− return bs
485+ let toStream t =
506−
486+ toSources [(f, T.unlines . selectLines . T.lines $ t)]
487+ currentDir <- takeDirectory . sourceName <$> getPosition
488+ insertIncludedFile parser toStream [currentDir] f startLine endLine
507
489
508--
490--
509-- list blocks
491-- list blocks
@@ -526,7 +508,7 @@ definitionList :: PandocMonad m => RSTParser m Blocks
526definitionList = B.definitionList <$> many1 definitionListItem
508definitionList = B.definitionList <$> many1 definitionListItem
527
509
528-- parses bullet list start and returns its length (inc. following whitespace)
510-- parses bullet list start and returns its length (inc. following whitespace)
529−bulletListStart :: Monad m => ParserT Text st m Int
511+bulletListStart :: Monad m => ParserT Sources st m Int
530bulletListStart = try $ do
512bulletListStart = try $ do
531 notFollowedBy' hrule -- because hrules start out just like lists
513 notFollowedBy' hrule -- because hrules start out just like lists
532 marker <- oneOf bulletListMarkers
514 marker <- oneOf bulletListMarkers
@@ -732,8 +714,8 @@ directive' = do
732 "" -> stateRstHighlight def
714 "" -> stateRstHighlight def
733 lang -> Just lang })
715 lang -> Just lang })
734 x | x == "code" || x == "code-block" || x == "sourcecode" ->
716 x | x == "code" || x == "code-block" || x == "sourcecode" ->
735− codeblock name classes (map (second trimr) fields)
717+ return $ codeblock name classes (map (second trimr) fields)
736− (trim top) body True
718+ (trim top) True body
737 "aafig" -> do
719 "aafig" -> do
738 let attribs = (name, ["aafig"], map (second trimr) fields)
720 let attribs = (name, ["aafig"], map (second trimr) fields)
739 return $ B.codeBlockWith attribs $ stripTrailingNewlines body
721 return $ B.codeBlockWith attribs $ stripTrailingNewlines body
@@ -1019,10 +1001,10 @@ toChunks = dropWhile T.null
1019 then "\\begin{aligned}\n" <> s <> "\n\\end{aligned}"
1001 then "\\begin{aligned}\n" <> s <> "\n\\end{aligned}"
1020 else s
1002 else s
1021
1003
1022−codeblock :: Text -> [Text] -> [(Text, Text)] -> Text -> Text -> Bool
1004+codeblock :: Text -> [Text] -> [(Text, Text)] -> Text -> Bool -> Text
1023− -> RSTParser m Blocks
1005+ -> Blocks
1024−codeblock ident classes fields lang body rmTrailingNewlines =
1006+codeblock ident classes fields lang rmTrailingNewlines body =
1025− return $ B.codeBlockWith attribs $ stripTrailingNewlines' body
1007+ B.codeBlockWith attribs $ stripTrailingNewlines' body
1026 where stripTrailingNewlines' = if rmTrailingNewlines
1008 where stripTrailingNewlines' = if rmTrailingNewlines
1027 then stripTrailingNewlines
1009 then stripTrailingNewlines
1028 else id
1010 else id
@@ -1103,7 +1085,7 @@ quotedReferenceName = try $ do
1103-- plus isolated (no two adjacent) internal hyphens, underscores,
1085-- plus isolated (no two adjacent) internal hyphens, underscores,
1104-- periods, colons and plus signs; no whitespace or other characters
1086-- periods, colons and plus signs; no whitespace or other characters
1105-- are allowed.
1087-- are allowed.
1106−simpleReferenceName :: Monad m => ParserT Text st m Text
1088+simpleReferenceName :: Monad m => ParserT Sources st m Text
1107simpleReferenceName = do
1089simpleReferenceName = do
1108 x <- alphaNum
1090 x <- alphaNum
1109 xs <- many $ alphaNum
1091 xs <- many $ alphaNum
@@ -1122,7 +1104,7 @@ referenceKey = do
1122 -- return enough blanks to replace key
1104 -- return enough blanks to replace key
1123 return $ T.replicate (sourceLine endPos - sourceLine startPos) "\n"
1105 return $ T.replicate (sourceLine endPos - sourceLine startPos) "\n"
1124
1106
1125−targetURI :: Monad m => ParserT Text st m Text
1107+targetURI :: Monad m => ParserT Sources st m Text
1126targetURI = do
1108targetURI = do
1127 skipSpaces
1109 skipSpaces
1128 optional $ try $ newline >> notFollowedBy blankline
1110 optional $ try $ newline >> notFollowedBy blankline
@@ -1160,8 +1142,10 @@ anonymousKey :: Monad m => RSTParser m ()
1160anonymousKey = try $ do
1142anonymousKey = try $ do
1161 oneOfStrings [".. __:", "__"]
1143 oneOfStrings [".. __:", "__"]
1162 src <- targetURI
1144 src <- targetURI
1163− pos <- getPosition
1145+ -- we need to ensure that the keys are ordered by occurrence in
1146+ -- the document.
1147+ numKeys <- M.size . stateKeys <$> getState
1164− let key = toKey $ "_" <> T.pack (printf "%09d" (sourceLine pos))
1148+ let key = toKey $ "_" <> T.pack (show numKeys)
1165 updateState $ \s -> s { stateKeys = M.insert key ((src,""), nullAttr) $
1149 updateState $ \s -> s { stateKeys = M.insert key ((src,""), nullAttr) $
1166 stateKeys s }
1150 stateKeys s }
1167
1151
@@ -1250,13 +1234,13 @@ headerBlock = do
1250-- Grid tables TODO:
1234-- Grid tables TODO:
1251-- - column spans
1235-- - column spans
1252
1236
1253−dashedLine :: Monad m => Char -> ParserT Text st m (Int, Int)
1237+dashedLine :: Monad m => Char -> ParserT Sources st m (Int, Int)
1254dashedLine ch = do
1238dashedLine ch = do
1255 dashes <- many1 (char ch)
1239 dashes <- many1 (char ch)
1256 sp <- many (char ' ')
1240 sp <- many (char ' ')
1257 return (length dashes, length $ dashes ++ sp)
1241 return (length dashes, length $ dashes ++ sp)
1258
1242
1259−simpleDashedLines :: Monad m => Char -> ParserT Text st m [(Int,Int)]
1243+simpleDashedLines :: Monad m => Char -> ParserT Sources st m [(Int,Int)]
1260simpleDashedLines ch = try $ many1 (dashedLine ch)
1244simpleDashedLines ch = try $ many1 (dashedLine ch)
1261
1245
1262-- Parse a table row separator
1246-- Parse a table row separator
@@ -1382,7 +1366,7 @@ hyphens = do
1382 -- don't want to treat endline after hyphen or dash as a space
1366 -- don't want to treat endline after hyphen or dash as a space
1383 return $ B.str result
1367 return $ B.str result
1384
1368
1385−escapedChar :: Monad m => ParserT Text st m Inlines
1369+escapedChar :: Monad m => ParserT Sources st m Inlines
1386escapedChar = do c <- escaped anyChar
1370escapedChar = do c <- escaped anyChar
1387 return $ if c == ' ' || c == '\n' || c == '\r'
1371 return $ if c == ' ' || c == '\n' || c == '\r'
1388 -- '\ ' is null in RST
1372 -- '\ ' is null in RST
@@ -1658,21 +1642,4 @@ note = try $ do
1658 return $ B.note contents
1642 return $ B.note contents
1659
1643
1660smart :: PandocMonad m => RSTParser m Inlines
1644smart :: PandocMonad m => RSTParser m Inlines
1661−smart = do
1645+smart = smartPunctuation inline
1662− guardEnabled Ext_smart
1663− doubleQuoted <|> singleQuoted <|>
1664− choice [apostrophe, dash, ellipses]
1665−
1666−singleQuoted :: PandocMonad m => RSTParser m Inlines
1667−singleQuoted = try $ do
1668− singleQuoteStart
1669− withQuoteContext InSingleQuote $
1670− B.singleQuoted . trimInlines . mconcat <$>
1671− many1Till inline singleQuoteEnd
1672−
1673−doubleQuoted :: PandocMonad m => RSTParser m Inlines
1674−doubleQuoted = try $ do
1675− doubleQuoteStart
1676− withQuoteContext InDoubleQuote $
1677− B.doubleQuoted . trimInlines . mconcat <$>
1678− many1Till inline doubleQuoteEnd
src/Text/Pandoc/Readers/Roff.hs+16−18
@@ -42,7 +42,6 @@ import Text.Pandoc.Logging (LogMessage(..))
42import Text.Pandoc.Options
42import Text.Pandoc.Options
43import Text.Pandoc.Parsing
43import Text.Pandoc.Parsing
44import Text.Pandoc.Shared (safeRead)
44import Text.Pandoc.Shared (safeRead)
45−import Text.Parsec hiding (tokenPrim)
46import Text.Pandoc.RoffChar (characterCodes, combiningAccents)
45import Text.Pandoc.RoffChar (characterCodes, combiningAccents)
47import qualified Data.Sequence as Seq
46import qualified Data.Sequence as Seq
48import qualified Data.Foldable as Foldable
47import qualified Data.Foldable as Foldable
@@ -122,16 +121,16 @@ instance Default RoffState where
122 , afterConditional = False
121 , afterConditional = False
123 }
122 }
124
123
125−type RoffLexer m = ParserT T.Text RoffState m
124+type RoffLexer m = ParserT Sources RoffState m
126
125
127--
126--
128-- Lexer: T.Text -> RoffToken
127-- Lexer: T.Text -> RoffToken
129--
128--
130
129
131−eofline :: Stream s m Char => ParsecT s u m ()
130+eofline :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s u m ()
132eofline = void newline <|> eof <|> () <$ lookAhead (string "\\}")
131eofline = void newline <|> eof <|> () <$ lookAhead (string "\\}")
133
132
134−spacetab :: Stream s m Char => ParsecT s u m Char
133+spacetab :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s u m Char
135spacetab = char ' ' <|> char '\t'
134spacetab = char ' ' <|> char '\t'
136
135
137characterCodeMap :: M.Map T.Text Char
136characterCodeMap :: M.Map T.Text Char
@@ -303,8 +302,7 @@ expandString = try $ do
303 char '*'
302 char '*'
304 cs <- escapeArg <|> countChar 1 anyChar
303 cs <- escapeArg <|> countChar 1 anyChar
305 s <- linePartsToText <$> resolveText cs pos
304 s <- linePartsToText <$> resolveText cs pos
306− getInput >>= setInput . (s <>)
305+ addToInput s
307− return ()
308
306
309-- Parses: '..'
307-- Parses: '..'
310quoteArg :: PandocMonad m => RoffLexer m T.Text
308quoteArg :: PandocMonad m => RoffLexer m T.Text
@@ -316,7 +314,7 @@ escFont = do
316 font' <- if T.null font || font == "P"
314 font' <- if T.null font || font == "P"
317 then prevFont <$> getState
315 then prevFont <$> getState
318 else return $ foldr processFontLetter defaultFontSpec $ T.unpack font
316 else return $ foldr processFontLetter defaultFontSpec $ T.unpack font
319− modifyState $ \st -> st{ prevFont = currentFont st
317+ updateState $ \st -> st{ prevFont = currentFont st
320 , currentFont = font' }
318 , currentFont = font' }
321 return [Font font']
319 return [Font font']
322 where
320 where
@@ -372,8 +370,8 @@ lexTable pos = do
372 spaces
370 spaces
373 opts <- try tableOptions <|> [] <$ optional (char ';')
371 opts <- try tableOptions <|> [] <$ optional (char ';')
374 case lookup "tab" opts of
372 case lookup "tab" opts of
375− Just (T.uncons -> Just (c, _)) -> modifyState $ \st -> st{ tableTabChar = c }
373+ Just (T.uncons -> Just (c, _)) -> updateState $ \st -> st{ tableTabChar = c }
376− _ -> modifyState $ \st -> st{ tableTabChar = '\t' }
374+ _ -> updateState $ \st -> st{ tableTabChar = '\t' }
377 spaces
375 spaces
378 skipMany lexComment
376 skipMany lexComment
379 spaces
377 spaces
@@ -489,18 +487,18 @@ lexConditional mname = do
489 ifPart <- do
487 ifPart <- do
490 optional $ try $ char '\\' >> newline
488 optional $ try $ char '\\' >> newline
491 lexGroup
489 lexGroup
492− <|> do modifyState $ \s -> s{ afterConditional = True }
490+ <|> do updateState $ \s -> s{ afterConditional = True }
493 t <- manToken
491 t <- manToken
494− modifyState $ \s -> s{ afterConditional = False }
492+ updateState $ \s -> s{ afterConditional = False }
495 return t
493 return t
496 case mbtest of
494 case mbtest of
497 Nothing -> do
495 Nothing -> do
498− putState st -- reset state, so we don't record macros in skipped section
496+ setState st -- reset state, so we don't record macros in skipped section
499 report $ SkippedContent (T.cons '.' mname) pos
497 report $ SkippedContent (T.cons '.' mname) pos
500 return mempty
498 return mempty
501 Just True -> return ifPart
499 Just True -> return ifPart
502 Just False -> do
500 Just False -> do
503− putState st
501+ setState st
504 return mempty
502 return mempty
505
503
506expression :: PandocMonad m => RoffLexer m (Maybe Bool)
504expression :: PandocMonad m => RoffLexer m (Maybe Bool)
@@ -515,7 +513,7 @@ expression = do
515 _ -> Nothing
513 _ -> Nothing
516 where
514 where
517 returnValue v = do
515 returnValue v = do
518− modifyState $ \st -> st{ lastExpression = v }
516+ updateState $ \st -> st{ lastExpression = v }
519 return v
517 return v
520
518
521lexGroup :: PandocMonad m => RoffLexer m RoffTokens
519lexGroup :: PandocMonad m => RoffLexer m RoffTokens
@@ -536,7 +534,7 @@ lexIncludeFile args = do
536 result <- readFileFromDirs dirs $ T.unpack fp
534 result <- readFileFromDirs dirs $ T.unpack fp
537 case result of
535 case result of
538 Nothing -> report $ CouldNotLoadIncludeFile fp pos
536 Nothing -> report $ CouldNotLoadIncludeFile fp pos
539− Just s -> getInput >>= setInput . (s <>)
537+ Just s -> addToInput s
540 return mempty
538 return mempty
541 [] -> return mempty
539 [] -> return mempty
542
540
@@ -564,13 +562,13 @@ lexStringDef args = do -- string definition
564 (x:ys) -> do
562 (x:ys) -> do
565 let ts = singleTok $ TextLine (intercalate [RoffStr " " ] ys)
563 let ts = singleTok $ TextLine (intercalate [RoffStr " " ] ys)
566 let stringName = linePartsToText x
564 let stringName = linePartsToText x
567− modifyState $ \st ->
565+ updateState $ \st ->
568 st{ customMacros = M.insert stringName ts (customMacros st) }
566 st{ customMacros = M.insert stringName ts (customMacros st) }
569 return mempty
567 return mempty
570
568
571lexMacroDef :: PandocMonad m => [Arg] -> RoffLexer m RoffTokens
569lexMacroDef :: PandocMonad m => [Arg] -> RoffLexer m RoffTokens
572lexMacroDef args = do -- macro definition
570lexMacroDef args = do -- macro definition
573− modifyState $ \st -> st{ roffMode = CopyMode }
571+ updateState $ \st -> st{ roffMode = CopyMode }
574 (macroName, stopMacro) <-
572 (macroName, stopMacro) <-
575 case args of
573 case args of
576 (x : y : _) -> return (linePartsToText x, linePartsToText y)
574 (x : y : _) -> return (linePartsToText x, linePartsToText y)
@@ -584,7 +582,7 @@ lexMacroDef args = do -- macro definition
584 _ <- lexArgs
582 _ <- lexArgs
585 return ()
583 return ()
586 ts <- mconcat <$> manyTill manToken stop
584 ts <- mconcat <$> manyTill manToken stop
587− modifyState $ \st ->
585+ updateState $ \st ->
588 st{ customMacros = M.insert macroName ts (customMacros st)
586 st{ customMacros = M.insert macroName ts (customMacros st)
589 , roffMode = NormalMode }
587 , roffMode = NormalMode }
590 return mempty
588 return mempty
src/Text/Pandoc/Readers/TWiki.hs+7−27
@@ -28,22 +28,22 @@ import Text.Pandoc.Definition
28import Text.Pandoc.Options
28import Text.Pandoc.Options
29import Text.Pandoc.Parsing hiding (enclosed, nested)
29import Text.Pandoc.Parsing hiding (enclosed, nested)
30import Text.Pandoc.Readers.HTML (htmlTag, isCommentTag)
30import Text.Pandoc.Readers.HTML (htmlTag, isCommentTag)
31−import Text.Pandoc.Shared (crFilter, tshow)
31+import Text.Pandoc.Shared (tshow)
32import Text.Pandoc.XML (fromEntities)
32import Text.Pandoc.XML (fromEntities)
33
33
34-- | Read twiki from an input string and return a Pandoc document.
34-- | Read twiki from an input string and return a Pandoc document.
35−readTWiki :: PandocMonad m
35+readTWiki :: (PandocMonad m, ToSources a)
36 => ReaderOptions
36 => ReaderOptions
37− -> Text
37+ -> a
38 -> m Pandoc
38 -> m Pandoc
39readTWiki opts s = do
39readTWiki opts s = do
40+ let sources = ensureFinalNewlines 2 (toSources s)
40− res <- readWithM parseTWiki def{ stateOptions = opts }
41+ res <- readWithM parseTWiki def{ stateOptions = opts } sources
41− (crFilter s <> "\n\n")
42 case res of
42 case res of
43 Left e -> throwError e
43 Left e -> throwError e
44 Right d -> return d
44 Right d -> return d
45
45
46−type TWParser = ParserT Text ParserState
46+type TWParser = ParserT Sources ParserState
47
47
48--
48--
49-- utility functions
49-- utility functions
@@ -469,27 +469,7 @@ symbol :: PandocMonad m => TWParser m B.Inlines
469symbol = B.str <$> countChar 1 nonspaceChar
469symbol = B.str <$> countChar 1 nonspaceChar
470
470
471smart :: PandocMonad m => TWParser m B.Inlines
471smart :: PandocMonad m => TWParser m B.Inlines
472−smart = do
472+smart = smartPunctuation inline
473− guardEnabled Ext_smart
474− doubleQuoted <|> singleQuoted <|>
475− choice [ apostrophe
476− , dash
477− , ellipses
478− ]
479−
480−singleQuoted :: PandocMonad m => TWParser m B.Inlines
481−singleQuoted = try $ do
482− singleQuoteStart
483− withQuoteContext InSingleQuote
484− (B.singleQuoted . B.trimInlines . mconcat <$> many1Till inline singleQuoteEnd)
485−
486−doubleQuoted :: PandocMonad m => TWParser m B.Inlines
487−doubleQuoted = try $ do
488− doubleQuoteStart
489− contents <- mconcat <$> many (try $ notFollowedBy doubleQuoteEnd >> inline)
490− withQuoteContext InDoubleQuote (doubleQuoteEnd >>
491− return (B.doubleQuoted $ B.trimInlines contents))
492− <|> return (B.str "\8220" B.<> contents)
493
473
494link :: PandocMonad m => TWParser m B.Inlines
474link :: PandocMonad m => TWParser m B.Inlines
495link = try $ do
475link = try $ do
src/Text/Pandoc/Readers/Textile.hs+92−86
@@ -39,6 +39,7 @@ import Control.Monad (guard, liftM)
39import Control.Monad.Except (throwError)
39import Control.Monad.Except (throwError)
40import Data.Char (digitToInt, isUpper)
40import Data.Char (digitToInt, isUpper)
41import Data.List (intersperse, transpose, foldl')
41import Data.List (intersperse, transpose, foldl')
42+import Data.List.NonEmpty (NonEmpty(..), nonEmpty)
42import Data.Text (Text)
43import Data.Text (Text)
43import qualified Data.Text as T
44import qualified Data.Text as T
44import Text.HTML.TagSoup (Tag (..), fromAttrib)
45import Text.HTML.TagSoup (Tag (..), fromAttrib)
@@ -52,30 +53,34 @@ import Text.Pandoc.Options
52import Text.Pandoc.Parsing
53import Text.Pandoc.Parsing
53import Text.Pandoc.Readers.HTML (htmlTag, isBlockTag, isInlineTag)
54import Text.Pandoc.Readers.HTML (htmlTag, isBlockTag, isInlineTag)
54import Text.Pandoc.Readers.LaTeX (rawLaTeXBlock, rawLaTeXInline)
55import Text.Pandoc.Readers.LaTeX (rawLaTeXBlock, rawLaTeXInline)
55−import Text.Pandoc.Shared (crFilter, trim, tshow)
56+import Text.Pandoc.Shared (trim, tshow)
56
57
57-- | Parse a Textile text and return a Pandoc document.
58-- | Parse a Textile text and return a Pandoc document.
58−readTextile :: PandocMonad m
59+readTextile :: (PandocMonad m, ToSources a)
59 => ReaderOptions -- ^ Reader options
60 => ReaderOptions -- ^ Reader options
60− -> Text -- ^ String to parse (assuming @'\n'@ line endings)
61+ -> a
61 -> m Pandoc
62 -> m Pandoc
62readTextile opts s = do
63readTextile opts s = do
64+ let sources = ensureFinalNewlines 2 (toSources s)
63− parsed <- readWithM parseTextile def{ stateOptions = opts }
65+ parsed <- readWithM parseTextile def{ stateOptions = opts } sources
64− (crFilter s <> "\n\n")
65 case parsed of
66 case parsed of
66 Right result -> return result
67 Right result -> return result
67 Left e -> throwError e
68 Left e -> throwError e
68
69
70+type TextileParser = ParserT Sources ParserState
69
71
70-- | Generate a Pandoc ADT from a textile document
72-- | Generate a Pandoc ADT from a textile document
71−parseTextile :: PandocMonad m => ParserT Text ParserState m Pandoc
73+parseTextile :: PandocMonad m => TextileParser m Pandoc
72parseTextile = do
74parseTextile = do
73 many blankline
75 many blankline
74 startPos <- getPosition
76 startPos <- getPosition
75 -- go through once just to get list of reference keys and notes
77 -- go through once just to get list of reference keys and notes
76 -- docMinusKeys is the raw document with blanks where the keys/notes were...
78 -- docMinusKeys is the raw document with blanks where the keys/notes were...
79+ let firstPassParser = do
80+ pos <- getPosition
77− let firstPassParser = noteBlock <|> lineClump
81+ t <- noteBlock <|> lineClump
82+ return (pos, t)
78− manyTill firstPassParser eof >>= setInput . T.concat
83+ manyTill firstPassParser eof >>= setInput . Sources
79 setPosition startPos
84 setPosition startPos
80 st' <- getState
85 st' <- getState
81 let reversedNotes = stateNotes st'
86 let reversedNotes = stateNotes st'
@@ -83,10 +88,10 @@ parseTextile = do
83 -- now parse it for real...
88 -- now parse it for real...
84 Pandoc nullMeta . B.toList <$> parseBlocks -- FIXME
89 Pandoc nullMeta . B.toList <$> parseBlocks -- FIXME
85
90
86−noteMarker :: PandocMonad m => ParserT Text ParserState m Text
91+noteMarker :: PandocMonad m => TextileParser m Text
87noteMarker = skipMany spaceChar >> string "fn" >> T.pack <$> manyTill digit (char '.')
92noteMarker = skipMany spaceChar >> string "fn" >> T.pack <$> manyTill digit (char '.')
88
93
89−noteBlock :: PandocMonad m => ParserT Text ParserState m Text
94+noteBlock :: PandocMonad m => TextileParser m Text
90noteBlock = try $ do
95noteBlock = try $ do
91 startPos <- getPosition
96 startPos <- getPosition
92 ref <- noteMarker
97 ref <- noteMarker
@@ -101,11 +106,11 @@ noteBlock = try $ do
101 return $ T.replicate (sourceLine endPos - sourceLine startPos) "\n"
106 return $ T.replicate (sourceLine endPos - sourceLine startPos) "\n"
102
107
103-- | Parse document blocks
108-- | Parse document blocks
104−parseBlocks :: PandocMonad m => ParserT Text ParserState m Blocks
109+parseBlocks :: PandocMonad m => TextileParser m Blocks
105parseBlocks = mconcat <$> manyTill block eof
110parseBlocks = mconcat <$> manyTill block eof
106
111
107-- | Block parsers list tried in definition order
112-- | Block parsers list tried in definition order
108−blockParsers :: PandocMonad m => [ParserT Text ParserState m Blocks]
113+blockParsers :: PandocMonad m => [TextileParser m Blocks]
109blockParsers = [ codeBlock
114blockParsers = [ codeBlock
110 , header
115 , header
111 , blockQuote
116 , blockQuote
@@ -120,22 +125,22 @@ blockParsers = [ codeBlock
120 ]
125 ]
121
126
122-- | Any block in the order of definition of blockParsers
127-- | Any block in the order of definition of blockParsers
123−block :: PandocMonad m => ParserT Text ParserState m Blocks
128+block :: PandocMonad m => TextileParser m Blocks
124block = do
129block = do
125 res <- choice blockParsers <?> "block"
130 res <- choice blockParsers <?> "block"
126 trace (T.take 60 $ tshow $ B.toList res)
131 trace (T.take 60 $ tshow $ B.toList res)
127 return res
132 return res
128
133
129−commentBlock :: PandocMonad m => ParserT Text ParserState m Blocks
134+commentBlock :: PandocMonad m => TextileParser m Blocks
130commentBlock = try $ do
135commentBlock = try $ do
131 string "###."
136 string "###."
132 manyTill anyLine blanklines
137 manyTill anyLine blanklines
133 return mempty
138 return mempty
134
139
135−codeBlock :: PandocMonad m => ParserT Text ParserState m Blocks
140+codeBlock :: PandocMonad m => TextileParser m Blocks
136codeBlock = codeBlockTextile <|> codeBlockHtml
141codeBlock = codeBlockTextile <|> codeBlockHtml
137
142
138−codeBlockTextile :: PandocMonad m => ParserT Text ParserState m Blocks
143+codeBlockTextile :: PandocMonad m => TextileParser m Blocks
139codeBlockTextile = try $ do
144codeBlockTextile = try $ do
140 string "bc." <|> string "pre."
145 string "bc." <|> string "pre."
141 extended <- option False (True <$ char '.')
146 extended <- option False (True <$ char '.')
@@ -155,7 +160,7 @@ trimTrailingNewlines :: Text -> Text
155trimTrailingNewlines = T.dropWhileEnd (=='\n')
160trimTrailingNewlines = T.dropWhileEnd (=='\n')
156
161
157-- | Code Blocks in Textile are between <pre> and </pre>
162-- | Code Blocks in Textile are between <pre> and </pre>
158−codeBlockHtml :: PandocMonad m => ParserT Text ParserState m Blocks
163+codeBlockHtml :: PandocMonad m => TextileParser m Blocks
159codeBlockHtml = try $ do
164codeBlockHtml = try $ do
160 (t@(TagOpen _ attrs),_) <- htmlTag (tagOpen (=="pre") (const True))
165 (t@(TagOpen _ attrs),_) <- htmlTag (tagOpen (=="pre") (const True))
161 result' <- T.pack <$> manyTill anyChar (htmlTag (tagClose (=="pre")))
166 result' <- T.pack <$> manyTill anyChar (htmlTag (tagClose (=="pre")))
@@ -173,7 +178,7 @@ codeBlockHtml = try $ do
173 return $ B.codeBlockWith (ident,classes,kvs) result'''
178 return $ B.codeBlockWith (ident,classes,kvs) result'''
174
179
175-- | Header of the form "hN. content" with N in 1..6
180-- | Header of the form "hN. content" with N in 1..6
176−header :: PandocMonad m => ParserT Text ParserState m Blocks
181+header :: PandocMonad m => TextileParser m Blocks
177header = try $ do
182header = try $ do
178 char 'h'
183 char 'h'
179 level <- digitToInt <$> oneOf "123456"
184 level <- digitToInt <$> oneOf "123456"
@@ -185,14 +190,14 @@ header = try $ do
185 return $ B.headerWith attr' level name
190 return $ B.headerWith attr' level name
186
191
187-- | Blockquote of the form "bq. content"
192-- | Blockquote of the form "bq. content"
188−blockQuote :: PandocMonad m => ParserT Text ParserState m Blocks
193+blockQuote :: PandocMonad m => TextileParser m Blocks
189blockQuote = try $ do
194blockQuote = try $ do
190 string "bq" >> attributes >> char '.' >> whitespace
195 string "bq" >> attributes >> char '.' >> whitespace
191 B.blockQuote <$> para
196 B.blockQuote <$> para
192
197
193-- Horizontal rule
198-- Horizontal rule
194
199
195−hrule :: PandocMonad m => ParserT Text st m Blocks
200+hrule :: PandocMonad m => TextileParser m Blocks
196hrule = try $ do
201hrule = try $ do
197 skipSpaces
202 skipSpaces
198 start <- oneOf "-*"
203 start <- oneOf "-*"
@@ -207,39 +212,39 @@ hrule = try $ do
207-- | Can be a bullet list or an ordered list. This implementation is
212-- | Can be a bullet list or an ordered list. This implementation is
208-- strict in the nesting, sublist must start at exactly "parent depth
213-- strict in the nesting, sublist must start at exactly "parent depth
209-- plus one"
214-- plus one"
210−anyList :: PandocMonad m => ParserT Text ParserState m Blocks
215+anyList :: PandocMonad m => TextileParser m Blocks
211anyList = try $ anyListAtDepth 1 <* blanklines
216anyList = try $ anyListAtDepth 1 <* blanklines
212
217
213-- | This allow one type of list to be nested into an other type,
218-- | This allow one type of list to be nested into an other type,
214-- provided correct nesting
219-- provided correct nesting
215−anyListAtDepth :: PandocMonad m => Int -> ParserT Text ParserState m Blocks
220+anyListAtDepth :: PandocMonad m => Int -> TextileParser m Blocks
216anyListAtDepth depth = choice [ bulletListAtDepth depth,
221anyListAtDepth depth = choice [ bulletListAtDepth depth,
217 orderedListAtDepth depth,
222 orderedListAtDepth depth,
218 definitionList ]
223 definitionList ]
219
224
220-- | Bullet List of given depth, depth being the number of leading '*'
225-- | Bullet List of given depth, depth being the number of leading '*'
221−bulletListAtDepth :: PandocMonad m => Int -> ParserT Text ParserState m Blocks
226+bulletListAtDepth :: PandocMonad m => Int -> TextileParser m Blocks
222bulletListAtDepth depth = try $ B.bulletList <$> many1 (bulletListItemAtDepth depth)
227bulletListAtDepth depth = try $ B.bulletList <$> many1 (bulletListItemAtDepth depth)
223
228
224-- | Bullet List Item of given depth, depth being the number of
229-- | Bullet List Item of given depth, depth being the number of
225-- leading '*'
230-- leading '*'
226−bulletListItemAtDepth :: PandocMonad m => Int -> ParserT Text ParserState m Blocks
231+bulletListItemAtDepth :: PandocMonad m => Int -> TextileParser m Blocks
227bulletListItemAtDepth = genericListItemAtDepth '*'
232bulletListItemAtDepth = genericListItemAtDepth '*'
228
233
229-- | Ordered List of given depth, depth being the number of
234-- | Ordered List of given depth, depth being the number of
230-- leading '#'
235-- leading '#'
231−orderedListAtDepth :: PandocMonad m => Int -> ParserT Text ParserState m Blocks
236+orderedListAtDepth :: PandocMonad m => Int -> TextileParser m Blocks
232orderedListAtDepth depth = try $ do
237orderedListAtDepth depth = try $ do
233 items <- many1 (orderedListItemAtDepth depth)
238 items <- many1 (orderedListItemAtDepth depth)
234 return $ B.orderedList items
239 return $ B.orderedList items
235
240
236-- | Ordered List Item of given depth, depth being the number of
241-- | Ordered List Item of given depth, depth being the number of
237-- leading '#'
242-- leading '#'
238−orderedListItemAtDepth :: PandocMonad m => Int -> ParserT Text ParserState m Blocks
243+orderedListItemAtDepth :: PandocMonad m => Int -> TextileParser m Blocks
239orderedListItemAtDepth = genericListItemAtDepth '#'
244orderedListItemAtDepth = genericListItemAtDepth '#'
240
245
241-- | Common implementation of list items
246-- | Common implementation of list items
242−genericListItemAtDepth :: PandocMonad m => Char -> Int -> ParserT Text ParserState m Blocks
247+genericListItemAtDepth :: PandocMonad m => Char -> Int -> TextileParser m Blocks
243genericListItemAtDepth c depth = try $ do
248genericListItemAtDepth c depth = try $ do
244 count depth (char c) >> attributes >> whitespace
249 count depth (char c) >> attributes >> whitespace
245 contents <- mconcat <$> many ((B.plain . mconcat <$> many1 inline) <|>
250 contents <- mconcat <$> many ((B.plain . mconcat <$> many1 inline) <|>
@@ -249,25 +254,25 @@ genericListItemAtDepth c depth = try $ do
249 return $ contents <> sublist
254 return $ contents <> sublist
250
255
251-- | A definition list is a set of consecutive definition items
256-- | A definition list is a set of consecutive definition items
252−definitionList :: PandocMonad m => ParserT Text ParserState m Blocks
257+definitionList :: PandocMonad m => TextileParser m Blocks
253definitionList = try $ B.definitionList <$> many1 definitionListItem
258definitionList = try $ B.definitionList <$> many1 definitionListItem
254
259
255-- | List start character.
260-- | List start character.
256−listStart :: PandocMonad m => ParserT Text ParserState m ()
261+listStart :: PandocMonad m => TextileParser m ()
257listStart = genericListStart '*'
262listStart = genericListStart '*'
258 <|> () <$ genericListStart '#'
263 <|> () <$ genericListStart '#'
259 <|> () <$ definitionListStart
264 <|> () <$ definitionListStart
260
265
261−genericListStart :: PandocMonad m => Char -> ParserT Text st m ()
266+genericListStart :: PandocMonad m => Char -> TextileParser m ()
262genericListStart c = () <$ try (many1 (char c) >> whitespace)
267genericListStart c = () <$ try (many1 (char c) >> whitespace)
263
268
264−basicDLStart :: PandocMonad m => ParserT Text ParserState m ()
269+basicDLStart :: PandocMonad m => TextileParser m ()
265basicDLStart = do
270basicDLStart = do
266 char '-'
271 char '-'
267 whitespace
272 whitespace
268 notFollowedBy newline
273 notFollowedBy newline
269
274
270−definitionListStart :: PandocMonad m => ParserT Text ParserState m Inlines
275+definitionListStart :: PandocMonad m => TextileParser m Inlines
271definitionListStart = try $ do
276definitionListStart = try $ do
272 basicDLStart
277 basicDLStart
273 trimInlines . mconcat <$>
278 trimInlines . mconcat <$>
@@ -280,15 +285,15 @@ definitionListStart = try $ do
280-- the term defined, then spaces and ":=". The definition follows, on
285-- the term defined, then spaces and ":=". The definition follows, on
281-- the same single line, or spaned on multiple line, after a line
286-- the same single line, or spaned on multiple line, after a line
282-- break.
287-- break.
283−definitionListItem :: PandocMonad m => ParserT Text ParserState m (Inlines, [Blocks])
288+definitionListItem :: PandocMonad m => TextileParser m (Inlines, [Blocks])
284definitionListItem = try $ do
289definitionListItem = try $ do
285 term <- mconcat . intersperse B.linebreak <$> many1 definitionListStart
290 term <- mconcat . intersperse B.linebreak <$> many1 definitionListStart
286 def' <- string ":=" *> optional whitespace *> (multilineDef <|> inlineDef)
291 def' <- string ":=" *> optional whitespace *> (multilineDef <|> inlineDef)
287 return (term, def')
292 return (term, def')
288− where inlineDef :: PandocMonad m => ParserT Text ParserState m [Blocks]
293+ where inlineDef :: PandocMonad m => TextileParser m [Blocks]
289 inlineDef = liftM (\d -> [B.plain d])
294 inlineDef = liftM (\d -> [B.plain d])
290 $ optional whitespace >> (trimInlines . mconcat <$> many inline) <* newline
295 $ optional whitespace >> (trimInlines . mconcat <$> many inline) <* newline
291− multilineDef :: PandocMonad m => ParserT Text ParserState m [Blocks]
296+ multilineDef :: PandocMonad m => TextileParser m [Blocks]
292 multilineDef = try $ do
297 multilineDef = try $ do
293 optional whitespace >> newline
298 optional whitespace >> newline
294 s <- T.pack <$> many1Till anyChar (try (string "=:" >> newline))
299 s <- T.pack <$> many1Till anyChar (try (string "=:" >> newline))
@@ -299,7 +304,7 @@ definitionListItem = try $ do
299-- raw content
304-- raw content
300
305
301-- | A raw Html Block, optionally followed by blanklines
306-- | A raw Html Block, optionally followed by blanklines
302−rawHtmlBlock :: PandocMonad m => ParserT Text ParserState m Blocks
307+rawHtmlBlock :: PandocMonad m => TextileParser m Blocks
303rawHtmlBlock = try $ do
308rawHtmlBlock = try $ do
304 skipMany spaceChar
309 skipMany spaceChar
305 (_,b) <- htmlTag isBlockTag
310 (_,b) <- htmlTag isBlockTag
@@ -307,14 +312,14 @@ rawHtmlBlock = try $ do
307 return $ B.rawBlock "html" b
312 return $ B.rawBlock "html" b
308
313
309-- | Raw block of LaTeX content
314-- | Raw block of LaTeX content
310−rawLaTeXBlock' :: PandocMonad m => ParserT Text ParserState m Blocks
315+rawLaTeXBlock' :: PandocMonad m => TextileParser m Blocks
311rawLaTeXBlock' = do
316rawLaTeXBlock' = do
312 guardEnabled Ext_raw_tex
317 guardEnabled Ext_raw_tex
313 B.rawBlock "latex" <$> (rawLaTeXBlock <* spaces)
318 B.rawBlock "latex" <$> (rawLaTeXBlock <* spaces)
314
319
315
320
316-- | In textile, paragraphs are separated by blank lines.
321-- | In textile, paragraphs are separated by blank lines.
317−para :: PandocMonad m => ParserT Text ParserState m Blocks
322+para :: PandocMonad m => TextileParser m Blocks
318para = B.para . trimInlines . mconcat <$> many1 inline
323para = B.para . trimInlines . mconcat <$> many1 inline
319
324
320-- Tables
325-- Tables
@@ -325,7 +330,7 @@ toAlignment '>' = AlignRight
325toAlignment '=' = AlignCenter
330toAlignment '=' = AlignCenter
326toAlignment _ = AlignDefault
331toAlignment _ = AlignDefault
327
332
328−cellAttributes :: PandocMonad m => ParserT Text ParserState m (Bool, Alignment)
333+cellAttributes :: PandocMonad m => TextileParser m (Bool, Alignment)
329cellAttributes = try $ do
334cellAttributes = try $ do
330 isHeader <- option False (True <$ char '_')
335 isHeader <- option False (True <$ char '_')
331 -- we just ignore colspan and rowspan markers:
336 -- we just ignore colspan and rowspan markers:
@@ -338,7 +343,7 @@ cellAttributes = try $ do
338 return (isHeader, alignment)
343 return (isHeader, alignment)
339
344
340-- | A table cell spans until a pipe |
345-- | A table cell spans until a pipe |
341−tableCell :: PandocMonad m => ParserT Text ParserState m ((Bool, Alignment), Blocks)
346+tableCell :: PandocMonad m => TextileParser m ((Bool, Alignment), Blocks)
342tableCell = try $ do
347tableCell = try $ do
343 char '|'
348 char '|'
344 (isHeader, alignment) <- option (False, AlignDefault) cellAttributes
349 (isHeader, alignment) <- option (False, AlignDefault) cellAttributes
@@ -349,7 +354,7 @@ tableCell = try $ do
349 return ((isHeader, alignment), B.plain content)
354 return ((isHeader, alignment), B.plain content)
350
355
351-- | A table row is made of many table cells
356-- | A table row is made of many table cells
352−tableRow :: PandocMonad m => ParserT Text ParserState m [((Bool, Alignment), Blocks)]
357+tableRow :: PandocMonad m => TextileParser m [((Bool, Alignment), Blocks)]
353tableRow = try $ do
358tableRow = try $ do
354 -- skip optional row attributes
359 -- skip optional row attributes
355 optional $ try $ do
360 optional $ try $ do
@@ -359,7 +364,7 @@ tableRow = try $ do
359 many1 tableCell <* char '|' <* blankline
364 many1 tableCell <* char '|' <* blankline
360
365
361-- | A table with an optional header.
366-- | A table with an optional header.
362−table :: PandocMonad m => ParserT Text ParserState m Blocks
367+table :: PandocMonad m => TextileParser m Blocks
363table = try $ do
368table = try $ do
364 -- ignore table attributes
369 -- ignore table attributes
365 caption <- option mempty $ try $ do
370 caption <- option mempty $ try $ do
@@ -375,8 +380,9 @@ table = try $ do
375 (toprow:rest) | any (fst . fst) toprow ->
380 (toprow:rest) | any (fst . fst) toprow ->
376 (toprow, rest)
381 (toprow, rest)
377 _ -> (mempty, rawrows)
382 _ -> (mempty, rawrows)
378− let nbOfCols = maximum $ map length (headers:rows)
383+ let nbOfCols = maximum $ fmap length (headers :| rows)
384+ let aligns = map (maybe AlignDefault minimum . nonEmpty) $
379− let aligns = map minimum $ transpose $ map (map (snd . fst)) (headers:rows)
385+ transpose $ map (map (snd . fst)) (headers:rows)
380 let toRow = Row nullAttr . map B.simpleCell
386 let toRow = Row nullAttr . map B.simpleCell
381 toHeaderRow l = [toRow l | not (null l)]
387 toHeaderRow l = [toRow l | not (null l)]
382 return $ B.table (B.simpleCaption $ B.plain caption)
388 return $ B.table (B.simpleCaption $ B.plain caption)
@@ -386,7 +392,7 @@ table = try $ do
386 (TableFoot nullAttr [])
392 (TableFoot nullAttr [])
387
393
388-- | Ignore markers for cols, thead, tfoot.
394-- | Ignore markers for cols, thead, tfoot.
389−ignorableRow :: PandocMonad m => ParserT Text ParserState m ()
395+ignorableRow :: PandocMonad m => TextileParser m ()
390ignorableRow = try $ do
396ignorableRow = try $ do
391 char '|'
397 char '|'
392 oneOf ":^-~"
398 oneOf ":^-~"
@@ -395,7 +401,7 @@ ignorableRow = try $ do
395 _ <- anyLine
401 _ <- anyLine
396 return ()
402 return ()
397
403
398−explicitBlockStart :: PandocMonad m => Text -> ParserT Text ParserState m ()
404+explicitBlockStart :: PandocMonad m => Text -> TextileParser m ()
399explicitBlockStart name = try $ do
405explicitBlockStart name = try $ do
400 string (T.unpack name)
406 string (T.unpack name)
401 attributes
407 attributes
@@ -407,8 +413,8 @@ explicitBlockStart name = try $ do
407-- However, they can be used to set HTML/CSS attributes when needed.
413-- However, they can be used to set HTML/CSS attributes when needed.
408maybeExplicitBlock :: PandocMonad m
414maybeExplicitBlock :: PandocMonad m
409 => Text -- ^ block tag name
415 => Text -- ^ block tag name
410− -> ParserT Text ParserState m Blocks -- ^ implicit block
416+ -> TextileParser m Blocks -- ^ implicit block
411− -> ParserT Text ParserState m Blocks
417+ -> TextileParser m Blocks
412maybeExplicitBlock name blk = try $ do
418maybeExplicitBlock name blk = try $ do
413 optional $ explicitBlockStart name
419 optional $ explicitBlockStart name
414 blk
420 blk
@@ -421,11 +427,11 @@ maybeExplicitBlock name blk = try $ do
421
427
422
428
423-- | Any inline element
429-- | Any inline element
424−inline :: PandocMonad m => ParserT Text ParserState m Inlines
430+inline :: PandocMonad m => TextileParser m Inlines
425inline = choice inlineParsers <?> "inline"
431inline = choice inlineParsers <?> "inline"
426
432
427-- | Inline parsers tried in order
433-- | Inline parsers tried in order
428−inlineParsers :: PandocMonad m => [ParserT Text ParserState m Inlines]
434+inlineParsers :: PandocMonad m => [TextileParser m Inlines]
429inlineParsers = [ str
435inlineParsers = [ str
430 , whitespace
436 , whitespace
431 , endline
437 , endline
@@ -445,7 +451,7 @@ inlineParsers = [ str
445 ]
451 ]
446
452
447-- | Inline markups
453-- | Inline markups
448−inlineMarkup :: PandocMonad m => ParserT Text ParserState m Inlines
454+inlineMarkup :: PandocMonad m => TextileParser m Inlines
449inlineMarkup = choice [ simpleInline (string "??") (B.cite [])
455inlineMarkup = choice [ simpleInline (string "??") (B.cite [])
450 , simpleInline (string "**") B.strong
456 , simpleInline (string "**") B.strong
451 , simpleInline (string "__") B.emph
457 , simpleInline (string "__") B.emph
@@ -459,29 +465,29 @@ inlineMarkup = choice [ simpleInline (string "??") (B.cite [])
459 ]
465 ]
460
466
461-- | Trademark, registered, copyright
467-- | Trademark, registered, copyright
462−mark :: PandocMonad m => ParserT Text st m Inlines
468+mark :: PandocMonad m => TextileParser m Inlines
463mark = try $ char '(' >> (try tm <|> try reg <|> copy)
469mark = try $ char '(' >> (try tm <|> try reg <|> copy)
464
470
465−reg :: PandocMonad m => ParserT Text st m Inlines
471+reg :: PandocMonad m => TextileParser m Inlines
466reg = do
472reg = do
467 oneOf "Rr"
473 oneOf "Rr"
468 char ')'
474 char ')'
469 return $ B.str "\174"
475 return $ B.str "\174"
470
476
471−tm :: PandocMonad m => ParserT Text st m Inlines
477+tm :: PandocMonad m => TextileParser m Inlines
472tm = do
478tm = do
473 oneOf "Tt"
479 oneOf "Tt"
474 oneOf "Mm"
480 oneOf "Mm"
475 char ')'
481 char ')'
476 return $ B.str "\8482"
482 return $ B.str "\8482"
477
483
478−copy :: PandocMonad m => ParserT Text st m Inlines
484+copy :: PandocMonad m => TextileParser m Inlines
479copy = do
485copy = do
480 oneOf "Cc"
486 oneOf "Cc"
481 char ')'
487 char ')'
482 return $ B.str "\169"
488 return $ B.str "\169"
483
489
484−note :: PandocMonad m => ParserT Text ParserState m Inlines
490+note :: PandocMonad m => TextileParser m Inlines
485note = try $ do
491note = try $ do
486 ref <- char '[' *> many1 digit <* char ']'
492 ref <- char '[' *> many1 digit <* char ']'
487 notes <- stateNotes <$> getState
493 notes <- stateNotes <$> getState
@@ -505,13 +511,13 @@ wordBoundaries :: [Char]
505wordBoundaries = markupChars <> stringBreakers
511wordBoundaries = markupChars <> stringBreakers
506
512
507-- | Parse a hyphened sequence of words
513-- | Parse a hyphened sequence of words
508−hyphenedWords :: PandocMonad m => ParserT Text ParserState m Text
514+hyphenedWords :: PandocMonad m => TextileParser m Text
509hyphenedWords = do
515hyphenedWords = do
510 x <- wordChunk
516 x <- wordChunk
511 xs <- many (try $ char '-' >> wordChunk)
517 xs <- many (try $ char '-' >> wordChunk)
512 return $ T.intercalate "-" (x:xs)
518 return $ T.intercalate "-" (x:xs)
513
519
514−wordChunk :: PandocMonad m => ParserT Text ParserState m Text
520+wordChunk :: PandocMonad m => TextileParser m Text
515wordChunk = try $ do
521wordChunk = try $ do
516 hd <- noneOf wordBoundaries
522 hd <- noneOf wordBoundaries
517 tl <- many ( noneOf wordBoundaries <|>
523 tl <- many ( noneOf wordBoundaries <|>
@@ -520,7 +526,7 @@ wordChunk = try $ do
520 return $ T.pack $ hd:tl
526 return $ T.pack $ hd:tl
521
527
522-- | Any string
528-- | Any string
523−str :: PandocMonad m => ParserT Text ParserState m Inlines
529+str :: PandocMonad m => TextileParser m Inlines
524str = do
530str = do
525 baseStr <- hyphenedWords
531 baseStr <- hyphenedWords
526 -- RedCloth compliance : if parsed word is uppercase and immediately
532 -- RedCloth compliance : if parsed word is uppercase and immediately
@@ -533,11 +539,11 @@ str = do
533 return $ B.str fullStr
539 return $ B.str fullStr
534
540
535-- | Some number of space chars
541-- | Some number of space chars
536−whitespace :: PandocMonad m => ParserT Text st m Inlines
542+whitespace :: PandocMonad m => TextileParser m Inlines
537whitespace = many1 spaceChar >> return B.space <?> "whitespace"
543whitespace = many1 spaceChar >> return B.space <?> "whitespace"
538
544
539-- | In Textile, an isolated endline character is a line break
545-- | In Textile, an isolated endline character is a line break
540−endline :: PandocMonad m => ParserT Text ParserState m Inlines
546+endline :: PandocMonad m => TextileParser m Inlines
541endline = try $ do
547endline = try $ do
542 newline
548 newline
543 notFollowedBy blankline
549 notFollowedBy blankline
@@ -545,18 +551,18 @@ endline = try $ do
545 notFollowedBy rawHtmlBlock
551 notFollowedBy rawHtmlBlock
546 return B.linebreak
552 return B.linebreak
547
553
548−rawHtmlInline :: PandocMonad m => ParserT Text ParserState m Inlines
554+rawHtmlInline :: PandocMonad m => TextileParser m Inlines
549rawHtmlInline = B.rawInline "html" . snd <$> htmlTag isInlineTag
555rawHtmlInline = B.rawInline "html" . snd <$> htmlTag isInlineTag
550
556
551-- | Raw LaTeX Inline
557-- | Raw LaTeX Inline
552−rawLaTeXInline' :: PandocMonad m => ParserT Text ParserState m Inlines
558+rawLaTeXInline' :: PandocMonad m => TextileParser m Inlines
553rawLaTeXInline' = try $ do
559rawLaTeXInline' = try $ do
554 guardEnabled Ext_raw_tex
560 guardEnabled Ext_raw_tex
555 B.rawInline "latex" <$> rawLaTeXInline
561 B.rawInline "latex" <$> rawLaTeXInline
556
562
557-- | Textile standard link syntax is "label":target. But we
563-- | Textile standard link syntax is "label":target. But we
558-- can also have ["label":target].
564-- can also have ["label":target].
559−link :: PandocMonad m => ParserT Text ParserState m Inlines
565+link :: PandocMonad m => TextileParser m Inlines
560link = try $ do
566link = try $ do
561 bracketed <- (True <$ char '[') <|> return False
567 bracketed <- (True <$ char '[') <|> return False
562 char '"' *> notFollowedBy (oneOf " \t\n\r")
568 char '"' *> notFollowedBy (oneOf " \t\n\r")
@@ -576,7 +582,7 @@ link = try $ do
576 else B.spanWith attr $ B.link url "" name'
582 else B.spanWith attr $ B.link url "" name'
577
583
578-- | image embedding
584-- | image embedding
579−image :: PandocMonad m => ParserT Text ParserState m Inlines
585+image :: PandocMonad m => TextileParser m Inlines
580image = try $ do
586image = try $ do
581 char '!' >> notFollowedBy space
587 char '!' >> notFollowedBy space
582 (ident, cls, kvs) <- attributes
588 (ident, cls, kvs) <- attributes
@@ -588,51 +594,51 @@ image = try $ do
588 char '!'
594 char '!'
589 return $ B.imageWith attr src alt (B.str alt)
595 return $ B.imageWith attr src alt (B.str alt)
590
596
591−escapedInline :: PandocMonad m => ParserT Text ParserState m Inlines
597+escapedInline :: PandocMonad m => TextileParser m Inlines
592escapedInline = escapedEqs <|> escapedTag
598escapedInline = escapedEqs <|> escapedTag
593
599
594−escapedEqs :: PandocMonad m => ParserT Text ParserState m Inlines
600+escapedEqs :: PandocMonad m => TextileParser m Inlines
595escapedEqs = B.str . T.pack <$>
601escapedEqs = B.str . T.pack <$>
596 try (string "==" *> manyTill anyChar' (try $ string "=="))
602 try (string "==" *> manyTill anyChar' (try $ string "=="))
597
603
598-- | literal text escaped btw <notextile> tags
604-- | literal text escaped btw <notextile> tags
599−escapedTag :: PandocMonad m => ParserT Text ParserState m Inlines
605+escapedTag :: PandocMonad m => TextileParser m Inlines
600escapedTag = B.str . T.pack <$>
606escapedTag = B.str . T.pack <$>
601 try (string "<notextile>" *>
607 try (string "<notextile>" *>
602 manyTill anyChar' (try $ string "</notextile>"))
608 manyTill anyChar' (try $ string "</notextile>"))
603
609
604-- | Any special symbol defined in wordBoundaries
610-- | Any special symbol defined in wordBoundaries
605−symbol :: PandocMonad m => ParserT Text ParserState m Inlines
611+symbol :: PandocMonad m => TextileParser m Inlines
606symbol = B.str . T.singleton <$> (notFollowedBy newline *>
612symbol = B.str . T.singleton <$> (notFollowedBy newline *>
607 notFollowedBy rawHtmlBlock *>
613 notFollowedBy rawHtmlBlock *>
608 oneOf wordBoundaries)
614 oneOf wordBoundaries)
609
615
610-- | Inline code
616-- | Inline code
611−code :: PandocMonad m => ParserT Text ParserState m Inlines
617+code :: PandocMonad m => TextileParser m Inlines
612code = code1 <|> code2
618code = code1 <|> code2
613
619
614-- any character except a newline before a blank line
620-- any character except a newline before a blank line
615−anyChar' :: PandocMonad m => ParserT Text ParserState m Char
621+anyChar' :: PandocMonad m => TextileParser m Char
616anyChar' =
622anyChar' =
617 satisfy (/='\n') <|>
623 satisfy (/='\n') <|>
618 try (char '\n' <* notFollowedBy blankline)
624 try (char '\n' <* notFollowedBy blankline)
619
625
620−code1 :: PandocMonad m => ParserT Text ParserState m Inlines
626+code1 :: PandocMonad m => TextileParser m Inlines
621code1 = B.code . T.pack <$> surrounded (char '@') anyChar'
627code1 = B.code . T.pack <$> surrounded (char '@') anyChar'
622
628
623−code2 :: PandocMonad m => ParserT Text ParserState m Inlines
629+code2 :: PandocMonad m => TextileParser m Inlines
624code2 = do
630code2 = do
625 htmlTag (tagOpen (=="tt") null)
631 htmlTag (tagOpen (=="tt") null)
626 B.code . T.pack <$> manyTill anyChar' (try $ htmlTag $ tagClose (=="tt"))
632 B.code . T.pack <$> manyTill anyChar' (try $ htmlTag $ tagClose (=="tt"))
627
633
628-- | Html / CSS attributes
634-- | Html / CSS attributes
629−attributes :: PandocMonad m => ParserT Text ParserState m Attr
635+attributes :: PandocMonad m => TextileParser m Attr
630attributes = foldl' (flip ($)) ("",[],[]) <$>
636attributes = foldl' (flip ($)) ("",[],[]) <$>
631 try (do special <- option id specialAttribute
637 try (do special <- option id specialAttribute
632 attrs <- many attribute
638 attrs <- many attribute
633 return (special : attrs))
639 return (special : attrs))
634
640
635−specialAttribute :: PandocMonad m => ParserT Text ParserState m (Attr -> Attr)
641+specialAttribute :: PandocMonad m => TextileParser m (Attr -> Attr)
636specialAttribute = do
642specialAttribute = do
637 alignStr <- ("center" <$ char '=') <|>
643 alignStr <- ("center" <$ char '=') <|>
638 ("justify" <$ try (string "<>")) <|>
644 ("justify" <$ try (string "<>")) <|>
@@ -641,11 +647,11 @@ specialAttribute = do
641 notFollowedBy spaceChar
647 notFollowedBy spaceChar
642 return $ addStyle $ T.pack $ "text-align:" ++ alignStr
648 return $ addStyle $ T.pack $ "text-align:" ++ alignStr
643
649
644−attribute :: PandocMonad m => ParserT Text ParserState m (Attr -> Attr)
650+attribute :: PandocMonad m => TextileParser m (Attr -> Attr)
645attribute = try $
651attribute = try $
646 (classIdAttr <|> styleAttr <|> langAttr) <* notFollowedBy spaceChar
652 (classIdAttr <|> styleAttr <|> langAttr) <* notFollowedBy spaceChar
647
653
648−classIdAttr :: PandocMonad m => ParserT Text ParserState m (Attr -> Attr)
654+classIdAttr :: PandocMonad m => TextileParser m (Attr -> Attr)
649classIdAttr = try $ do -- (class class #id)
655classIdAttr = try $ do -- (class class #id)
650 char '('
656 char '('
651 ws <- T.words `fmap` T.pack <$> manyTill anyChar' (char ')')
657 ws <- T.words `fmap` T.pack <$> manyTill anyChar' (char ')')
@@ -657,7 +663,7 @@ classIdAttr = try $ do -- (class class #id)
657 classes'
663 classes'
658 -> return $ \(_,_,keyvals) -> ("",classes',keyvals)
664 -> return $ \(_,_,keyvals) -> ("",classes',keyvals)
659
665
660−styleAttr :: PandocMonad m => ParserT Text ParserState m (Attr -> Attr)
666+styleAttr :: PandocMonad m => TextileParser m (Attr -> Attr)
661styleAttr = do
667styleAttr = do
662 style <- try $ enclosed (char '{') (char '}') anyChar'
668 style <- try $ enclosed (char '{') (char '}') anyChar'
663 return $ addStyle $ T.pack style
669 return $ addStyle $ T.pack style
@@ -668,23 +674,23 @@ addStyle style (id',classes,keyvals) =
668 where keyvals' = ("style", style') : [(k,v) | (k,v) <- keyvals, k /= "style"]
674 where keyvals' = ("style", style') : [(k,v) | (k,v) <- keyvals, k /= "style"]
669 style' = style <> ";" <> T.concat [v | ("style",v) <- keyvals]
675 style' = style <> ";" <> T.concat [v | ("style",v) <- keyvals]
670
676
671−langAttr :: PandocMonad m => ParserT Text ParserState m (Attr -> Attr)
677+langAttr :: PandocMonad m => TextileParser m (Attr -> Attr)
672langAttr = do
678langAttr = do
673 lang <- try $ enclosed (char '[') (char ']') alphaNum
679 lang <- try $ enclosed (char '[') (char ']') alphaNum
674 return $ \(id',classes,keyvals) -> (id',classes,("lang",T.pack lang):keyvals)
680 return $ \(id',classes,keyvals) -> (id',classes,("lang",T.pack lang):keyvals)
675
681
676-- | Parses material surrounded by a parser.
682-- | Parses material surrounded by a parser.
677surrounded :: (PandocMonad m, Show t)
683surrounded :: (PandocMonad m, Show t)
678− => ParserT Text st m t -- ^ surrounding parser
684+ => ParserT Sources st m t -- ^ surrounding parser
679− -> ParserT Text st m a -- ^ content parser (to be used repeatedly)
685+ -> ParserT Sources st m a -- ^ content parser (to be used repeatedly)
680− -> ParserT Text st m [a]
686+ -> ParserT Sources st m [a]
681surrounded border =
687surrounded border =
682 enclosed (border *> notFollowedBy (oneOf " \t\n\r")) (try border)
688 enclosed (border *> notFollowedBy (oneOf " \t\n\r")) (try border)
683
689
684simpleInline :: PandocMonad m
690simpleInline :: PandocMonad m
685− => ParserT Text ParserState m t -- ^ surrounding parser
691+ => TextileParser m t -- ^ surrounding parser
686 -> (Inlines -> Inlines) -- ^ Inline constructor
692 -> (Inlines -> Inlines) -- ^ Inline constructor
687− -> ParserT Text ParserState m Inlines -- ^ content parser (to be used repeatedly)
693+ -> TextileParser m Inlines -- ^ content parser (to be used repeatedly)
688simpleInline border construct = try $ do
694simpleInline border construct = try $ do
689 notAfterString
695 notAfterString
690 border *> notFollowedBy (oneOf " \t\n\r")
696 border *> notFollowedBy (oneOf " \t\n\r")
@@ -698,7 +704,7 @@ simpleInline border construct = try $ do
698 then body
704 then body
699 else B.spanWith attr body
705 else B.spanWith attr body
700
706
701−groupedInlineMarkup :: PandocMonad m => ParserT Text ParserState m Inlines
707+groupedInlineMarkup :: PandocMonad m => TextileParser m Inlines
702groupedInlineMarkup = try $ do
708groupedInlineMarkup = try $ do
703 char '['
709 char '['
704 sp1 <- option mempty $ B.space <$ whitespace
710 sp1 <- option mempty $ B.space <$ whitespace
@@ -707,5 +713,5 @@ groupedInlineMarkup = try $ do
707 char ']'
713 char ']'
708 return $ sp1 <> result <> sp2
714 return $ sp1 <> result <> sp2
709
715
710−eof' :: Monad m => ParserT Text s m Char
716+eof' :: Monad m => ParserT Sources s m Char
711eof' = '\n' <$ eof
717eof' = '\n' <$ eof
src/Text/Pandoc/Readers/TikiWiki.hs+6−6
@@ -30,23 +30,23 @@ import Text.Pandoc.Definition
30import Text.Pandoc.Logging (Verbosity (..))
30import Text.Pandoc.Logging (Verbosity (..))
31import Text.Pandoc.Options
31import Text.Pandoc.Options
32import Text.Pandoc.Parsing hiding (enclosed, nested)
32import Text.Pandoc.Parsing hiding (enclosed, nested)
33−import Text.Pandoc.Shared (crFilter, safeRead)
33+import Text.Pandoc.Shared (safeRead)
34import Text.Pandoc.XML (fromEntities)
34import Text.Pandoc.XML (fromEntities)
35import Text.Printf (printf)
35import Text.Printf (printf)
36
36
37-- | Read TikiWiki from an input string and return a Pandoc document.
37-- | Read TikiWiki from an input string and return a Pandoc document.
38−readTikiWiki :: PandocMonad m
38+readTikiWiki :: (PandocMonad m, ToSources a)
39 => ReaderOptions
39 => ReaderOptions
40− -> Text
40+ -> a
41 -> m Pandoc
41 -> m Pandoc
42readTikiWiki opts s = do
42readTikiWiki opts s = do
43+ let sources = ensureFinalNewlines 2 (toSources s)
43− res <- readWithM parseTikiWiki def{ stateOptions = opts }
44+ res <- readWithM parseTikiWiki def{ stateOptions = opts } sources
44− (crFilter s <> "\n\n")
45 case res of
45 case res of
46 Left e -> throwError e
46 Left e -> throwError e
47 Right d -> return d
47 Right d -> return d
48
48
49−type TikiWikiParser = ParserT Text ParserState
49+type TikiWikiParser = ParserT Sources ParserState
50
50
51--
51--
52-- utility functions
52-- utility functions
src/Text/Pandoc/Readers/Txt2Tags.hs+41−16
@@ -1,4 +1,5 @@
1{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE LambdaCase #-}
2{- |
3{- |
3 Module : Text.Pandoc.Readers.Txt2Tags
4 Module : Text.Pandoc.Readers.Txt2Tags
4 Copyright : Copyright (C) 2014 Matthew Pickering
5 Copyright : Copyright (C) 2014 Matthew Pickering
@@ -19,6 +20,7 @@ import Control.Monad.Except (catchError, throwError)
19import Control.Monad.Reader (Reader, asks, runReader)
20import Control.Monad.Reader (Reader, asks, runReader)
20import Data.Default
21import Data.Default
21import Data.List (intercalate, transpose)
22import Data.List (intercalate, transpose)
23+import Data.List.NonEmpty (nonEmpty)
22import Data.Maybe (fromMaybe)
24import Data.Maybe (fromMaybe)
23import Data.Text (Text)
25import Data.Text (Text)
24import qualified Data.Text as T
26import qualified Data.Text as T
@@ -31,9 +33,9 @@ import Data.Time (defaultTimeLocale)
31import Text.Pandoc.Definition
33import Text.Pandoc.Definition
32import Text.Pandoc.Options
34import Text.Pandoc.Options
33import Text.Pandoc.Parsing hiding (space, spaces, uri)
35import Text.Pandoc.Parsing hiding (space, spaces, uri)
34−import Text.Pandoc.Shared (compactify, compactifyDL, crFilter, escapeURI)
36+import Text.Pandoc.Shared (compactify, compactifyDL, escapeURI)
35
37
36−type T2T = ParserT Text ParserState (Reader T2TMeta)
38+type T2T = ParserT Sources ParserState (Reader T2TMeta)
37
39
38-- | An object for the T2T macros meta information
40-- | An object for the T2T macros meta information
39-- the contents of each field is simply substituted verbatim into the file
41-- the contents of each field is simply substituted verbatim into the file
@@ -53,25 +55,28 @@ getT2TMeta = do
53 inps <- P.getInputFiles
55 inps <- P.getInputFiles
54 outp <- fromMaybe "" <$> P.getOutputFile
56 outp <- fromMaybe "" <$> P.getOutputFile
55 curDate <- formatTime defaultTimeLocale "%F" <$> P.getZonedTime
57 curDate <- formatTime defaultTimeLocale "%F" <$> P.getZonedTime
56− let getModTime = fmap (formatTime defaultTimeLocale "%T") .
57− P.getModificationTime
58− curMtime <- case inps of
58+ curMtime <- catchError
59+ (mapM P.getModificationTime inps >>=
60+ (\case
61+ Nothing ->
59− [] -> formatTime defaultTimeLocale "%T" <$> P.getZonedTime
62+ formatTime defaultTimeLocale "%T" <$> P.getZonedTime
60− _ -> catchError
63+ Just ts -> return $
61− (maximum <$> mapM getModTime inps)
64+ formatTime defaultTimeLocale "%T" $ maximum ts)
65+ . nonEmpty)
62− (const (return ""))
66+ (const (return ""))
63− return $ T2TMeta (T.pack curDate) (T.pack curMtime) (intercalate ", " inps) outp
67+ return $ T2TMeta (T.pack curDate) (T.pack curMtime)
68+ (intercalate ", " inps) outp
64
69
65-- | Read Txt2Tags from an input string returning a Pandoc document
70-- | Read Txt2Tags from an input string returning a Pandoc document
66−readTxt2Tags :: PandocMonad m
71+readTxt2Tags :: (PandocMonad m, ToSources a)
67 => ReaderOptions
72 => ReaderOptions
68− -> Text
73+ -> a
69 -> m Pandoc
74 -> m Pandoc
70readTxt2Tags opts s = do
75readTxt2Tags opts s = do
76+ let sources = ensureFinalNewlines 2 (toSources s)
71 meta <- getT2TMeta
77 meta <- getT2TMeta
72 let parsed = flip runReader meta $
78 let parsed = flip runReader meta $
73− readWithM parseT2T (def {stateOptions = opts}) $
79+ readWithM parseT2T (def {stateOptions = opts}) sources
74− crFilter s <> "\n\n"
75 case parsed of
80 case parsed of
76 Right result -> return result
81 Right result -> return result
77 Left e -> throwError e
82 Left e -> throwError e
@@ -263,7 +268,7 @@ table = try $ do
263 let ncolumns = length columns
268 let ncolumns = length columns
264 let aligns = map (fromMaybe AlignDefault . foldr findAlign Nothing) columns
269 let aligns = map (fromMaybe AlignDefault . foldr findAlign Nothing) columns
265 let rows' = map (map snd) rows
270 let rows' = map (map snd) rows
266− let size = maximum (map length rows')
271+ let size = maybe 0 maximum $ nonEmpty $ map length rows'
267 let rowsPadded = map (pad size) rows'
272 let rowsPadded = map (pad size) rows'
268 let headerPadded = if null tableHeader then mempty else pad size tableHeader
273 let headerPadded = if null tableHeader then mempty else pad size tableHeader
269 let toRow = Row nullAttr . map B.simpleCell
274 let toRow = Row nullAttr . map B.simpleCell
@@ -473,9 +478,29 @@ macro = try $ do
473-- raw URLs in text are automatically linked
478-- raw URLs in text are automatically linked
474url :: T2T Inlines
479url :: T2T Inlines
475url = try $ do
480url = try $ do
476− (rawUrl, escapedUrl) <- try uri <|> emailAddress
481+ (rawUrl, escapedUrl) <- try uri <|> emailAddress'
477 return $ B.link rawUrl "" (B.str escapedUrl)
482 return $ B.link rawUrl "" (B.str escapedUrl)
478
483
484+emailAddress' :: T2T (Text, Text)
485+emailAddress' = do
486+ (base, mailURI) <- emailAddress
487+ query <- option "" emailQuery
488+ return (base <> query, mailURI <> query)
489+
490+emailQuery :: T2T Text
491+emailQuery = do
492+ char '?'
493+ parts <- kv `sepBy1` (char '&')
494+ return $ "?" <> T.intercalate "&" parts
495+
496+kv :: T2T Text
497+kv = do
498+ k <- T.pack <$> many1 alphaNum
499+ char '='
500+ let vchar = alphaNum <|> try (oneOf "%._/~:,=$@&+-;*" <* lookAhead alphaNum)
501+ v <- T.pack <$> many1 vchar
502+ return (k <> "=" <> v)
503+
479uri :: T2T (Text, Text)
504uri :: T2T (Text, Text)
480uri = try $ do
505uri = try $ do
481 address <- t2tURI
506 address <- t2tURI
src/Text/Pandoc/Readers/Vimwiki.hs+12−7
@@ -74,23 +74,28 @@ import Text.Pandoc.Parsing (ParserState, ParserT, blanklines, emailAddress,
74 many1Till, orderedListMarker, readWithM,
74 many1Till, orderedListMarker, readWithM,
75 registerHeader, spaceChar, stateMeta,
75 registerHeader, spaceChar, stateMeta,
76 stateOptions, uri, manyTillChar, manyChar, textStr,
76 stateOptions, uri, manyTillChar, manyChar, textStr,
77− many1Char, countChar, many1TillChar)
77+ many1Char, countChar, many1TillChar,
78+ alphaNum, anyChar, char, newline, noneOf, oneOf,
79+ space, spaces, string)
80+import Text.Pandoc.Sources (ToSources(..), Sources)
78−import Text.Pandoc.Shared (crFilter, splitTextBy, stringify, stripFirstAndLast,
81+import Text.Pandoc.Shared (splitTextBy, stringify, stripFirstAndLast,
79 isURI, tshow)
82 isURI, tshow)
80−import Text.Parsec.Char (alphaNum, anyChar, char, newline, noneOf, oneOf, space,
81− spaces, string)
82import Text.Parsec.Combinator (between, choice, eof, lookAhead, many1,
83import Text.Parsec.Combinator (between, choice, eof, lookAhead, many1,
83 manyTill, notFollowedBy, option, skipMany1)
84 manyTill, notFollowedBy, option, skipMany1)
84import Text.Parsec.Prim (getState, many, try, updateState, (<|>))
85import Text.Parsec.Prim (getState, many, try, updateState, (<|>))
85
86
86−readVimwiki :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
87+readVimwiki :: (PandocMonad m, ToSources a)
88+ => ReaderOptions
89+ -> a
90+ -> m Pandoc
87readVimwiki opts s = do
91readVimwiki opts s = do
92+ let sources = toSources s
88− res <- readWithM parseVimwiki def{ stateOptions = opts } $ crFilter s
93+ res <- readWithM parseVimwiki def{ stateOptions = opts } sources
89 case res of
94 case res of
90 Left e -> throwError e
95 Left e -> throwError e
91 Right result -> return result
96 Right result -> return result
92
97
93−type VwParser = ParserT Text ParserState
98+type VwParser = ParserT Sources ParserState
94
99
95
100
96-- constants
101-- constants
src/Text/Pandoc/SelfContained.hs+4−7
@@ -16,7 +16,6 @@ the HTML using data URIs.
16module Text.Pandoc.SelfContained ( makeDataURI, makeSelfContained ) where
16module Text.Pandoc.SelfContained ( makeDataURI, makeSelfContained ) where
17import Codec.Compression.GZip as Gzip
17import Codec.Compression.GZip as Gzip
18import Control.Applicative ((<|>))
18import Control.Applicative ((<|>))
19−import Control.Monad.Except (throwError)
20import Control.Monad.Trans (lift)
19import Control.Monad.Trans (lift)
21import Data.ByteString (ByteString)
20import Data.ByteString (ByteString)
22import Data.ByteString.Base64
21import Data.ByteString.Base64
@@ -29,7 +28,6 @@ import System.FilePath (takeDirectory, takeExtension, (</>))
29import Text.HTML.TagSoup
28import Text.HTML.TagSoup
30import Text.Pandoc.Class.PandocMonad (PandocMonad (..), fetchItem,
29import Text.Pandoc.Class.PandocMonad (PandocMonad (..), fetchItem,
31 getInputFiles, report, setInputFiles)
30 getInputFiles, report, setInputFiles)
32−import Text.Pandoc.Error
33import Text.Pandoc.Logging
31import Text.Pandoc.Logging
34import Text.Pandoc.MIME (MimeType)
32import Text.Pandoc.MIME (MimeType)
35import Text.Pandoc.Shared (isURI, renderTags', trim)
33import Text.Pandoc.Shared (isURI, renderTags', trim)
@@ -244,11 +242,10 @@ getData mimetype src
244 let raw' = if ext `elem` [".gz", ".svgz"]
242 let raw' = if ext `elem` [".gz", ".svgz"]
245 then B.concat $ L.toChunks $ Gzip.decompress $ L.fromChunks [raw]
243 then B.concat $ L.toChunks $ Gzip.decompress $ L.fromChunks [raw]
246 else raw
244 else raw
247− mime <- case (mimetype, respMime) of
245+ let mime = case (mimetype, respMime) of
248− ("",Nothing) -> throwError $ PandocSomeError
246+ ("",Nothing) -> "application/octet-stream"
249− $ "Could not determine mime type for `" <> src <> "'"
250− (x, Nothing) -> return x
247+ (x, Nothing) -> x
251− (_, Just x ) -> return x
248+ (_, Just x ) -> x
252 result <- if "text/css" `T.isPrefixOf` mime
249 result <- if "text/css" `T.isPrefixOf` mime
253 then do
250 then do
254 oldInputs <- getInputFiles
251 oldInputs <- getInputFiles
src/Text/Pandoc/Shared.hs+16−41
@@ -25,11 +25,7 @@ module Text.Pandoc.Shared (
25 ordNub,
25 ordNub,
26 findM,
26 findM,
27 -- * Text processing
27 -- * Text processing
28− ToString (..),
29− ToText (..),
30 tshow,
28 tshow,
31− backslashEscapes,
32− escapeStringUsing,
33 elemText,
29 elemText,
34 notElemText,
30 notElemText,
35 stripTrailingNewlines,
31 stripTrailingNewlines,
@@ -127,7 +123,7 @@ import Text.HTML.TagSoup (RenderOptions (..), Tag (..), renderOptions,
127import Text.Pandoc.Builder (Blocks, Inlines, ToMetaValue (..))
123import Text.Pandoc.Builder (Blocks, Inlines, ToMetaValue (..))
128import qualified Text.Pandoc.Builder as B
124import qualified Text.Pandoc.Builder as B
129import Data.Time
125import Data.Time
130−import Text.Pandoc.Asciify (toAsciiChar)
126+import Text.Pandoc.Asciify (toAsciiText)
131import Text.Pandoc.Definition
127import Text.Pandoc.Definition
132import Text.Pandoc.Extensions (Extensions, Extension(..), extensionEnabled)
128import Text.Pandoc.Extensions (Extensions, Extension(..), extensionEnabled)
133import Text.Pandoc.Generic (bottomUp)
129import Text.Pandoc.Generic (bottomUp)
@@ -157,12 +153,20 @@ splitTextBy isSep t
157 in first : splitTextBy isSep (T.dropWhile isSep rest)
153 in first : splitTextBy isSep (T.dropWhile isSep rest)
158
154
159splitTextByIndices :: [Int] -> T.Text -> [T.Text]
155splitTextByIndices :: [Int] -> T.Text -> [T.Text]
160−splitTextByIndices ns = splitTextByRelIndices (zipWith (-) ns (0:ns))
156+splitTextByIndices ns = splitTextByRelIndices (zipWith (-) ns (0:ns)) . T.unpack
161 where
157 where
162− splitTextByRelIndices [] t = [t]
158+ splitTextByRelIndices [] cs = [T.pack cs]
163− splitTextByRelIndices (x:xs) t =
159+ splitTextByRelIndices (x:xs) cs =
164− let (first, rest) = T.splitAt x t
160+ let (first, rest) = splitAt' x cs
165− in first : splitTextByRelIndices xs rest
161+ in T.pack first : splitTextByRelIndices xs rest
162+
163+-- Note: don't replace this with T.splitAt, which is not sensitive
164+-- to character widths!
165+splitAt' :: Int -> [Char] -> ([Char],[Char])
166+splitAt' _ [] = ([],[])
167+splitAt' n xs | n <= 0 = ([],xs)
168+splitAt' n (x:xs) = (x:ys,zs)
169+ where (ys,zs) = splitAt' (n - charWidth x) xs
166
170
167ordNub :: (Ord a) => [a] -> [a]
171ordNub :: (Ord a) => [a] -> [a]
168ordNub l = go Set.empty l
172ordNub l = go Set.empty l
@@ -183,38 +187,9 @@ findM p = foldr go (pure Nothing)
183-- Text processing
187-- Text processing
184--
188--
185
189
186−class ToString a where
187− toString :: a -> String
188−
189−instance ToString String where
190− toString = id
191−
192−instance ToString T.Text where
193− toString = T.unpack
194−
195−class ToText a where
196− toText :: a -> T.Text
197−
198−instance ToText String where
199− toText = T.pack
200−
201−instance ToText T.Text where
202− toText = id
203−
204tshow :: Show a => a -> T.Text
190tshow :: Show a => a -> T.Text
205tshow = T.pack . show
191tshow = T.pack . show
206
192
207−-- | Returns an association list of backslash escapes for the
208−-- designated characters.
209−backslashEscapes :: [Char] -- ^ list of special characters to escape
210− -> [(Char, T.Text)]
211−backslashEscapes = map (\ch -> (ch, T.pack ['\\',ch]))
212−
213−-- | Escape a string of characters, using an association list of
214−-- characters and strings.
215−escapeStringUsing :: [(Char, T.Text)] -> T.Text -> T.Text
216−escapeStringUsing tbl = T.concatMap $ \c -> fromMaybe (T.singleton c) $ lookup c tbl
217−
218-- | @True@ exactly when the @Char@ appears in the @Text@.
193-- | @True@ exactly when the @Char@ appears in the @Text@.
219elemText :: Char -> T.Text -> Bool
194elemText :: Char -> T.Text -> Bool
220elemText c = T.any (== c)
195elemText c = T.any (== c)
@@ -323,6 +298,7 @@ tabFilter tabStop = T.unlines . map go . T.lines
323 (tabStop - (T.length s1 `mod` tabStop)) (T.pack " ")
298 (tabStop - (T.length s1 `mod` tabStop)) (T.pack " ")
324 <> go (T.drop 1 s2)
299 <> go (T.drop 1 s2)
325
300
301+{-# DEPRECATED crFilter "readers filter crs automatically" #-}
326-- | Strip out DOS line endings.
302-- | Strip out DOS line endings.
327crFilter :: T.Text -> T.Text
303crFilter :: T.Text -> T.Text
328crFilter = T.filter (/= '\r')
304crFilter = T.filter (/= '\r')
@@ -511,7 +487,7 @@ inlineListToIdentifier exts =
511 | otherwise = T.dropWhile (not . isAlpha)
487 | otherwise = T.dropWhile (not . isAlpha)
512 filterAscii
488 filterAscii
513 | extensionEnabled Ext_ascii_identifiers exts
489 | extensionEnabled Ext_ascii_identifiers exts
514− = T.pack . mapMaybe toAsciiChar . T.unpack
490+ = toAsciiText
515 | otherwise = id
491 | otherwise = id
516 toIdent
492 toIdent
517 | extensionEnabled Ext_gfm_auto_identifiers exts =
493 | extensionEnabled Ext_gfm_auto_identifiers exts =
@@ -877,7 +853,6 @@ filteredFilesFromArchive zf f =
877 fileAndBinary :: Archive -> FilePath -> Maybe (FilePath, BL.ByteString)
853 fileAndBinary :: Archive -> FilePath -> Maybe (FilePath, BL.ByteString)
878 fileAndBinary a fp = findEntryByPath fp a >>= \e -> Just (fp, fromEntry e)
854 fileAndBinary a fp = findEntryByPath fp a >>= \e -> Just (fp, fromEntry e)
879
855
880−
881--
856--
882-- IANA URIs
857-- IANA URIs
883--
858--
src/Text/Pandoc/Sources.hsnew file+195
@@ -0,0 +1,195 @@
1+{-# LANGUAGE FlexibleInstances #-}
2+{-# LANGUAGE FlexibleContexts #-}
3+{-# LANGUAGE MultiParamTypeClasses #-}
4+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5+{-# LANGUAGE OverloadedStrings #-}
6+{- |
7+ Module : Text.Pandoc.Sources
8+ Copyright : Copyright (C) 2021 John MacFarlane
9+ License : GNU GPL, version 2 or above
10+
11+ Maintainer : John MacFarlane <jgm@berkeley.edu>
12+ Stability : alpha
13+ Portability : portable
14+
15+Defines Sources object to be used as input to pandoc parsers and redefines Char
16+parsers so they get source position information from it.
17+-}
18+
19+module Text.Pandoc.Sources
20+ ( Sources(..)
21+ , ToSources(..)
22+ , UpdateSourcePos(..)
23+ , sourcesToText
24+ , initialSourceName
25+ , addToSources
26+ , ensureFinalNewlines
27+ , addToInput
28+ , satisfy
29+ , oneOf
30+ , noneOf
31+ , anyChar
32+ , char
33+ , string
34+ , newline
35+ , space
36+ , spaces
37+ , letter
38+ , digit
39+ , hexDigit
40+ , alphaNum
41+ )
42+where
43+import qualified Text.Parsec as P
44+import Text.Parsec (Stream(..), ParsecT)
45+import Text.Parsec.Pos as P
46+import Data.Text (Text)
47+import qualified Data.Text as T
48+import Data.Char (isSpace, isLetter, isAlphaNum, isDigit, isHexDigit)
49+import Data.String (IsString(..))
50+import qualified Data.List.NonEmpty as NonEmpty
51+
52+-- | A list of inputs labeled with source positions. It is assumed
53+-- that the 'Text's have @\n@ line endings.
54+newtype Sources = Sources { unSources :: [(SourcePos, Text)] }
55+ deriving (Show, Semigroup, Monoid)
56+
57+instance Monad m => Stream Sources m Char where
58+ uncons (Sources []) = return Nothing
59+ uncons (Sources ((pos,t):rest)) =
60+ case T.uncons t of
61+ Nothing -> uncons (Sources rest)
62+ Just (c,t') -> return $ Just (c, Sources ((pos,t'):rest))
63+
64+instance IsString Sources where
65+ fromString s = Sources [(P.initialPos "", T.pack (filter (/='\r') s))]
66+
67+class ToSources a where
68+ toSources :: a -> Sources
69+
70+instance ToSources Text where
71+ toSources t = Sources [(P.initialPos "", T.filter (/='\r') t)]
72+
73+instance ToSources [(FilePath, Text)] where
74+ toSources = Sources
75+ . map (\(fp,t) ->
76+ (P.initialPos fp, T.snoc (T.filter (/='\r') t) '\n'))
77+
78+instance ToSources Sources where
79+ toSources = id
80+
81+sourcesToText :: Sources -> Text
82+sourcesToText (Sources xs) = mconcat $ map snd xs
83+
84+addToSources :: Monad m => SourcePos -> Text -> ParsecT Sources u m ()
85+addToSources pos t = do
86+ curpos <- P.getPosition
87+ Sources xs <- P.getInput
88+ let xs' = case xs of
89+ [] -> []
90+ ((_,t'):rest) -> (curpos,t'):rest
91+ P.setInput $ Sources ((pos, T.filter (/='\r') t):xs')
92+
93+ensureFinalNewlines :: Int -- ^ number of trailing newlines
94+ -> Sources
95+ -> Sources
96+ensureFinalNewlines n (Sources xs) =
97+ case NonEmpty.nonEmpty xs of
98+ Nothing -> Sources [(initialPos "", T.replicate n "\n")]
99+ Just lst ->
100+ case NonEmpty.last lst of
101+ (spos, t) ->
102+ case T.length (T.takeWhileEnd (=='\n') t) of
103+ len | len >= n -> Sources xs
104+ | otherwise -> Sources (NonEmpty.init lst ++
105+ [(spos,
106+ t <> T.replicate (n - len) "\n")])
107+
108+class UpdateSourcePos s c where
109+ updateSourcePos :: SourcePos -> c -> s -> SourcePos
110+
111+instance UpdateSourcePos Text Char where
112+ updateSourcePos pos c _ = updatePosChar pos c
113+
114+instance UpdateSourcePos Sources Char where
115+ updateSourcePos pos c sources =
116+ case sources of
117+ Sources [] -> updatePosChar pos c
118+ Sources ((_,t):(pos',_):_)
119+ | T.null t -> pos'
120+ Sources _ ->
121+ case c of
122+ '\n' -> incSourceLine (setSourceColumn pos 1) 1
123+ '\t' -> incSourceColumn pos (4 - ((sourceColumn pos - 1) `mod` 4))
124+ _ -> incSourceColumn pos 1
125+
126+-- | Get name of first source in 'Sources'.
127+initialSourceName :: Sources -> FilePath
128+initialSourceName (Sources []) = ""
129+initialSourceName (Sources ((pos,_):_)) = sourceName pos
130+
131+-- | Add some text to the beginning of the input sources.
132+-- This simplifies code that expands macros.
133+addToInput :: Monad m => Text -> ParsecT Sources u m ()
134+addToInput t = do
135+ Sources xs <- P.getInput
136+ case xs of
137+ [] -> P.setInput $ Sources [(initialPos "",t)]
138+ (pos,t'):rest -> P.setInput $ Sources ((pos, t <> t'):rest)
139+
140+-- We need to redefine the parsers in Text.Parsec.Char so that they
141+-- update source positions properly from the Sources stream.
142+
143+satisfy :: (Monad m, Stream s m Char, UpdateSourcePos s Char)
144+ => (Char -> Bool) -> ParsecT s u m Char
145+satisfy f = P.tokenPrim show updateSourcePos matcher
146+ where
147+ matcher c = if f c then Just c else Nothing
148+
149+oneOf :: (Monad m, Stream s m Char, UpdateSourcePos s Char)
150+ => [Char] -> ParsecT s u m Char
151+oneOf cs = satisfy (`elem` cs)
152+
153+noneOf :: (Monad m, Stream s m Char, UpdateSourcePos s Char)
154+ => [Char] -> ParsecT s u m Char
155+noneOf cs = satisfy (`notElem` cs)
156+
157+anyChar :: (Monad m, Stream s m Char, UpdateSourcePos s Char)
158+ => ParsecT s u m Char
159+anyChar = satisfy (const True)
160+
161+char :: (Monad m, Stream s m Char, UpdateSourcePos s Char)
162+ => Char -> ParsecT s u m Char
163+char c = satisfy (== c)
164+
165+string :: (Monad m, Stream s m Char, UpdateSourcePos s Char)
166+ => [Char] -> ParsecT s u m [Char]
167+string = mapM char
168+
169+newline :: (Monad m, Stream s m Char, UpdateSourcePos s Char)
170+ => ParsecT s u m Char
171+newline = satisfy (== '\n')
172+
173+space :: (Monad m, Stream s m Char, UpdateSourcePos s Char)
174+ => ParsecT s u m Char
175+space = satisfy isSpace
176+
177+spaces :: (Monad m, Stream s m Char, UpdateSourcePos s Char)
178+ => ParsecT s u m ()
179+spaces = P.skipMany space P.<?> "white space"
180+
181+letter :: (Monad m, Stream s m Char, UpdateSourcePos s Char)
182+ => ParsecT s u m Char
183+letter = satisfy isLetter
184+
185+alphaNum :: (Monad m, Stream s m Char, UpdateSourcePos s Char)
186+ => ParsecT s u m Char
187+alphaNum = satisfy isAlphaNum
188+
189+digit :: (Monad m, Stream s m Char, UpdateSourcePos s Char)
190+ => ParsecT s u m Char
191+digit = satisfy isDigit
192+
193+hexDigit :: (Monad m, Stream s m Char, UpdateSourcePos s Char)
194+ => ParsecT s u m Char
195+hexDigit = satisfy isHexDigit
src/Text/Pandoc/Templates.hs+4
@@ -34,6 +34,7 @@ import Control.Monad.Except (catchError, throwError)
34import Data.Text (Text)
34import Data.Text (Text)
35import qualified Data.Text as T
35import qualified Data.Text as T
36import Text.Pandoc.Error
36import Text.Pandoc.Error
37+import System.IO.Error (isDoesNotExistError)
37
38
38-- | Wrap a Monad in this if you want partials to
39-- | Wrap a Monad in this if you want partials to
39-- be taken only from the default data files.
40-- be taken only from the default data files.
@@ -70,6 +71,9 @@ getTemplate tp = UTF8.toText <$>
70 PandocResourceNotFound _ ->
71 PandocResourceNotFound _ ->
71 -- see #5987 on reason for takeFileName
72 -- see #5987 on reason for takeFileName
72 readDataFile ("templates" </> takeFileName tp)
73 readDataFile ("templates" </> takeFileName tp)
74+ PandocIOError _ ioe | isDoesNotExistError ioe ->
75+ -- see #5987 on reason for takeFileName
76+ readDataFile ("templates" </> takeFileName tp)
73 _ -> throwError e))
77 _ -> throwError e))
74
78
75-- | Get default template for the specified writer.
79-- | Get default template for the specified writer.
src/Text/Pandoc/Writers.hs+3−3
@@ -81,6 +81,7 @@ import Data.Aeson
81import qualified Data.ByteString.Lazy as BL
81import qualified Data.ByteString.Lazy as BL
82import Data.Text (Text)
82import Data.Text (Text)
83import qualified Data.Text as T
83import qualified Data.Text as T
84+import Text.Pandoc.Shared (tshow)
84import Text.Pandoc.Class
85import Text.Pandoc.Class
85import Text.Pandoc.Definition
86import Text.Pandoc.Definition
86import Text.Pandoc.Options
87import Text.Pandoc.Options
@@ -122,7 +123,6 @@ import Text.Pandoc.Writers.Texinfo
122import Text.Pandoc.Writers.Textile
123import Text.Pandoc.Writers.Textile
123import Text.Pandoc.Writers.XWiki
124import Text.Pandoc.Writers.XWiki
124import Text.Pandoc.Writers.ZimWiki
125import Text.Pandoc.Writers.ZimWiki
125−import Text.Parsec.Error
126
126
127data Writer m = TextWriter (WriterOptions -> Pandoc -> m Text)
127data Writer m = TextWriter (WriterOptions -> Pandoc -> m Text)
128 | ByteStringWriter (WriterOptions -> Pandoc -> m BL.ByteString)
128 | ByteStringWriter (WriterOptions -> Pandoc -> m BL.ByteString)
@@ -196,8 +196,8 @@ writers = [
196getWriter :: PandocMonad m => Text -> m (Writer m, Extensions)
196getWriter :: PandocMonad m => Text -> m (Writer m, Extensions)
197getWriter s =
197getWriter s =
198 case parseFormatSpec s of
198 case parseFormatSpec s of
199− Left e -> throwError $ PandocAppError
199+ Left e -> throwError $ PandocAppError $
200− $ T.intercalate "\n" [T.pack m | Message m <- errorMessages e]
200+ "Error parsing writer format " <> tshow s <> ": " <> tshow e
201 Right (writerName, extsToEnable, extsToDisable) ->
201 Right (writerName, extsToEnable, extsToDisable) ->
202 case lookup writerName writers of
202 case lookup writerName writers of
203 Nothing -> throwError $
203 Nothing -> throwError $
src/Text/Pandoc/Writers/AsciiDoc.hs+10−4
@@ -22,6 +22,7 @@ module Text.Pandoc.Writers.AsciiDoc (writeAsciiDoc, writeAsciiDoctor) where
22import Control.Monad.State.Strict
22import Control.Monad.State.Strict
23import Data.Char (isPunctuation, isSpace)
23import Data.Char (isPunctuation, isSpace)
24import Data.List (intercalate, intersperse)
24import Data.List (intercalate, intersperse)
25+import Data.List.NonEmpty (NonEmpty(..))
25import Data.Maybe (fromMaybe, isJust)
26import Data.Maybe (fromMaybe, isJust)
26import qualified Data.Set as Set
27import qualified Data.Set as Set
27import qualified Data.Text as T
28import qualified Data.Text as T
@@ -104,8 +105,11 @@ pandocToAsciiDoc opts (Pandoc meta blocks) = do
104
105
105-- | Escape special characters for AsciiDoc.
106-- | Escape special characters for AsciiDoc.
106escapeString :: Text -> Text
107escapeString :: Text -> Text
107−escapeString = escapeStringUsing escs
108+escapeString t
108− where escs = backslashEscapes "{"
109+ | T.any (== '{') t = T.concatMap escChar t
110+ | otherwise = t
111+ where escChar '{' = "\\{"
112+ escChar c = T.singleton c
109
113
110-- | Ordered list start parser for use in Para below.
114-- | Ordered list start parser for use in Para below.
111olMarker :: Parser Text ParserState Char
115olMarker :: Parser Text ParserState Char
@@ -274,7 +278,7 @@ blockToAsciiDoc opts block@(Table _ blkCapt specs thead tbody tfoot) = do
274 let colwidth = if writerWrapText opts == WrapAuto
278 let colwidth = if writerWrapText opts == WrapAuto
275 then writerColumns opts
279 then writerColumns opts
276 else 100000
280 else 100000
277− let maxwidth = maximum $ map offset (head':rows')
281+ let maxwidth = maximum $ fmap offset (head' :| rows')
278 let body = if maxwidth > colwidth then vsep rows' else vcat rows'
282 let body = if maxwidth > colwidth then vsep rows' else vcat rows'
279 let border = separator <> text "==="
283 let border = separator <> text "==="
280 return $
284 return $
@@ -495,7 +499,9 @@ inlineToAsciiDoc opts (Quoted qt lst) = do
495 | otherwise -> [Str "``"] ++ lst ++ [Str "''"]
499 | otherwise -> [Str "``"] ++ lst ++ [Str "''"]
496inlineToAsciiDoc _ (Code _ str) = do
500inlineToAsciiDoc _ (Code _ str) = do
497 isAsciidoctor <- gets asciidoctorVariant
501 isAsciidoctor <- gets asciidoctorVariant
498− let contents = literal (escapeStringUsing (backslashEscapes "`") str)
502+ let escChar '`' = "\\'"
503+ escChar c = T.singleton c
504+ let contents = literal (T.concatMap escChar str)
499 return $
505 return $
500 if isAsciidoctor
506 if isAsciidoctor
501 then text "`+" <> contents <> "+`"
507 then text "`+" <> contents <> "+`"
src/Text/Pandoc/Writers/BibTeX.hs+1−1
@@ -43,7 +43,7 @@ writeBibTeX' :: PandocMonad m => Variant -> WriterOptions -> Pandoc -> m Text
43writeBibTeX' variant opts (Pandoc meta _) = do
43writeBibTeX' variant opts (Pandoc meta _) = do
44 let mblang = case lookupMetaString "lang" meta of
44 let mblang = case lookupMetaString "lang" meta of
45 "" -> Nothing
45 "" -> Nothing
46− t -> Just $ parseLang t
46+ t -> either (const Nothing) Just $ parseLang t
47 let refs = case lookupMeta "references" meta of
47 let refs = case lookupMeta "references" meta of
48 Just (MetaList xs) -> mapMaybe metaValueToReference xs
48 Just (MetaList xs) -> mapMaybe metaValueToReference xs
49 _ -> []
49 _ -> []
src/Text/Pandoc/Writers/ConTeXt.hs+44−38
@@ -20,7 +20,7 @@ import Data.Maybe (mapMaybe)
20import Data.Text (Text)
20import Data.Text (Text)
21import qualified Data.Text as T
21import qualified Data.Text as T
22import Network.URI (unEscapeString)
22import Network.URI (unEscapeString)
23−import Text.Pandoc.BCP47
23+import Text.Collate.Lang (Lang(..))
24import Text.Pandoc.Class.PandocMonad (PandocMonad, report, toLang)
24import Text.Pandoc.Class.PandocMonad (PandocMonad, report, toLang)
25import Text.Pandoc.Definition
25import Text.Pandoc.Definition
26import Text.Pandoc.ImageSize
26import Text.Pandoc.ImageSize
@@ -177,8 +177,12 @@ blockToConTeXt (Para lst) = do
177 contents <- inlineListToConTeXt lst
177 contents <- inlineListToConTeXt lst
178 return $ contents <> blankline
178 return $ contents <> blankline
179blockToConTeXt (LineBlock lns) = do
179blockToConTeXt (LineBlock lns) = do
180+ let emptyToBlankline doc = if isEmpty doc
181+ then blankline
182+ else doc
180− doclines <- nowrap . vcat <$> mapM inlineListToConTeXt lns
183+ doclines <- mapM inlineListToConTeXt lns
184+ let contextLines = vcat . map emptyToBlankline $ doclines
181− return $ "\\startlines" $$ doclines $$ "\\stoplines" <> blankline
185+ return $ "\\startlines" $$ contextLines $$ "\\stoplines" <> blankline
182blockToConTeXt (BlockQuote lst) = do
186blockToConTeXt (BlockQuote lst) = do
183 contents <- blockListToConTeXt lst
187 contents <- blockListToConTeXt lst
184 return $ "\\startblockquote" $$ nest 0 contents $$ "\\stopblockquote" <> blankline
188 return $ "\\startblockquote" $$ nest 0 contents $$ "\\stopblockquote" <> blankline
@@ -228,13 +232,7 @@ blockToConTeXt (OrderedList (start, style', delim) lst) = do
228 Period -> "stopper=."
232 Period -> "stopper=."
229 OneParen -> "stopper=)"
233 OneParen -> "stopper=)"
230 TwoParens -> "left=(,stopper=)"
234 TwoParens -> "left=(,stopper=)"
231− let width = maximum $ map T.length $ take (length contents)
232− (orderedListMarkers (start, style', delim))
233− let width' = (toEnum width + 1) / 2
234− let width'' = if width' > (1.5 :: Double)
235− then "width=" <> tshow width' <> "em"
236− else ""
237− let specs2Items = filter (not . T.null) [start', delim', width'']
235+ let specs2Items = filter (not . T.null) [start', delim']
238 let specs2 = if null specs2Items
236 let specs2 = if null specs2Items
239 then ""
237 then ""
240 else "[" <> T.intercalate "," specs2Items <> "]"
238 else "[" <> T.intercalate "," specs2Items <> "]"
@@ -248,8 +246,8 @@ blockToConTeXt (OrderedList (start, style', delim) lst) = do
248 UpperAlpha -> 'A') :
246 UpperAlpha -> 'A') :
249 if isTightList lst then ",packed]" else "]"
247 if isTightList lst then ",packed]" else "]"
250 let specs = T.pack style'' <> specs2
248 let specs = T.pack style'' <> specs2
251− return $ "\\startitemize" <> literal specs $$ vcat contents $$
249+ return $ "\\startenumerate" <> literal specs $$ vcat contents $$
252− "\\stopitemize" <> blankline
250+ "\\stopenumerate" <> blankline
253blockToConTeXt (DefinitionList lst) =
251blockToConTeXt (DefinitionList lst) =
254 liftM vcat $ mapM defListItemToConTeXt lst
252 liftM vcat $ mapM defListItemToConTeXt lst
255blockToConTeXt HorizontalRule = return $ "\\thinrule" <> blankline
253blockToConTeXt HorizontalRule = return $ "\\thinrule" <> blankline
@@ -432,9 +430,13 @@ inlineToConTeXt (Link _ txt (src, _)) = do
432 put $ st {stNextRef = next + 1}
430 put $ st {stNextRef = next + 1}
433 let ref = "url" <> tshow next
431 let ref = "url" <> tshow next
434 contents <- inlineListToConTeXt txt
432 contents <- inlineListToConTeXt txt
433+ let escChar '#' = "\\#"
434+ escChar '%' = "\\%"
435+ escChar c = T.singleton c
436+ let escContextURL = T.concatMap escChar
435 return $ "\\useURL"
437 return $ "\\useURL"
436 <> brackets (literal ref)
438 <> brackets (literal ref)
437− <> brackets (literal $ escapeStringUsing [('#',"\\#"),('%',"\\%")] src)
439+ <> brackets (literal $ escContextURL src)
438 <> (if isAutolink
440 <> (if isAutolink
439 then empty
441 then empty
440 else brackets empty <> brackets contents)
442 else brackets empty <> brackets contents)
@@ -477,7 +479,7 @@ inlineToConTeXt (Note contents) = do
477 then literal "\\footnote{" <> nest 2 (chomp contents') <> char '}'
479 then literal "\\footnote{" <> nest 2 (chomp contents') <> char '}'
478 else literal "\\startbuffer " <> nest 2 (chomp contents') <>
480 else literal "\\startbuffer " <> nest 2 (chomp contents') <>
479 literal "\\stopbuffer\\footnote{\\getbuffer}"
481 literal "\\stopbuffer\\footnote{\\getbuffer}"
480−inlineToConTeXt (Span (_,_,kvs) ils) = do
482+inlineToConTeXt (Span (ident,_,kvs) ils) = do
481 mblang <- fromBCP47 (lookup "lang" kvs)
483 mblang <- fromBCP47 (lookup "lang" kvs)
482 let wrapDir txt = case lookup "dir" kvs of
484 let wrapDir txt = case lookup "dir" kvs of
483 Just "rtl" -> braces $ "\\righttoleft " <> txt
485 Just "rtl" -> braces $ "\\righttoleft " <> txt
@@ -487,7 +489,11 @@ inlineToConTeXt (Span (_,_,kvs) ils) = do
487 Just lng -> braces ("\\language" <>
489 Just lng -> braces ("\\language" <>
488 brackets (literal lng) <> txt)
490 brackets (literal lng) <> txt)
489 Nothing -> txt
491 Nothing -> txt
492+ addReference =
493+ if T.null ident
494+ then id
495+ else (("\\reference" <> brackets (literal ident) <> "{}") <>)
490− wrapLang . wrapDir <$> inlineListToConTeXt ils
496+ addReference . wrapLang . wrapDir <$> inlineListToConTeXt ils
491
497
492-- | Craft the section header, inserting the section reference, if supplied.
498-- | Craft the section header, inserting the section reference, if supplied.
493sectionHeader :: PandocMonad m
499sectionHeader :: PandocMonad m
@@ -549,26 +555,26 @@ fromBCP47 mbs = fromBCP47' <$> toLang mbs
549-- https://tools.ietf.org/html/bcp47#section-2.1
555-- https://tools.ietf.org/html/bcp47#section-2.1
550-- http://wiki.contextgarden.net/Language_Codes
556-- http://wiki.contextgarden.net/Language_Codes
551fromBCP47' :: Maybe Lang -> Maybe Text
557fromBCP47' :: Maybe Lang -> Maybe Text
552−fromBCP47' (Just (Lang "ar" _ "SY" _) ) = Just "ar-sy"
558+fromBCP47' (Just (Lang "ar" _ (Just "SY") _ _ _)) = Just "ar-sy"
553−fromBCP47' (Just (Lang "ar" _ "IQ" _) ) = Just "ar-iq"
559+fromBCP47' (Just (Lang "ar" _ (Just "IQ") _ _ _)) = Just "ar-iq"
554−fromBCP47' (Just (Lang "ar" _ "JO" _) ) = Just "ar-jo"
560+fromBCP47' (Just (Lang "ar" _ (Just "JO") _ _ _)) = Just "ar-jo"
555−fromBCP47' (Just (Lang "ar" _ "LB" _) ) = Just "ar-lb"
561+fromBCP47' (Just (Lang "ar" _ (Just "LB") _ _ _)) = Just "ar-lb"
556−fromBCP47' (Just (Lang "ar" _ "DZ" _) ) = Just "ar-dz"
562+fromBCP47' (Just (Lang "ar" _ (Just "DZ") _ _ _)) = Just "ar-dz"
557−fromBCP47' (Just (Lang "ar" _ "MA" _) ) = Just "ar-ma"
563+fromBCP47' (Just (Lang "ar" _ (Just "MA") _ _ _)) = Just "ar-ma"
558−fromBCP47' (Just (Lang "de" _ _ ["1901"]) ) = Just "deo"
564+fromBCP47' (Just (Lang "de" _ _ ["1901"] _ _)) = Just "deo"
559−fromBCP47' (Just (Lang "de" _ "DE" _) ) = Just "de-de"
565+fromBCP47' (Just (Lang "de" _ (Just "DE") _ _ _)) = Just "de-de"
560−fromBCP47' (Just (Lang "de" _ "AT" _) ) = Just "de-at"
566+fromBCP47' (Just (Lang "de" _ (Just "AT") _ _ _)) = Just "de-at"
561−fromBCP47' (Just (Lang "de" _ "CH" _) ) = Just "de-ch"
567+fromBCP47' (Just (Lang "de" _ (Just "CH") _ _ _)) = Just "de-ch"
562−fromBCP47' (Just (Lang "el" _ _ ["poly"]) ) = Just "agr"
568+fromBCP47' (Just (Lang "el" _ _ ["poly"] _ _)) = Just "agr"
563−fromBCP47' (Just (Lang "en" _ "US" _) ) = Just "en-us"
569+fromBCP47' (Just (Lang "en" _ (Just "US") _ _ _)) = Just "en-us"
564−fromBCP47' (Just (Lang "en" _ "GB" _) ) = Just "en-gb"
570+fromBCP47' (Just (Lang "en" _ (Just "GB") _ _ _)) = Just "en-gb"
565−fromBCP47' (Just (Lang "grc"_ _ _) ) = Just "agr"
571+fromBCP47' (Just (Lang "grc"_ _ _ _ _)) = Just "agr"
566−fromBCP47' (Just (Lang "el" _ _ _) ) = Just "gr"
572+fromBCP47' (Just (Lang "el" _ _ _ _ _)) = Just "gr"
567−fromBCP47' (Just (Lang "eu" _ _ _) ) = Just "ba"
573+fromBCP47' (Just (Lang "eu" _ _ _ _ _)) = Just "ba"
568−fromBCP47' (Just (Lang "he" _ _ _) ) = Just "il"
574+fromBCP47' (Just (Lang "he" _ _ _ _ _)) = Just "il"
569−fromBCP47' (Just (Lang "jp" _ _ _) ) = Just "ja"
575+fromBCP47' (Just (Lang "jp" _ _ _ _ _)) = Just "ja"
570−fromBCP47' (Just (Lang "uk" _ _ _) ) = Just "ua"
576+fromBCP47' (Just (Lang "uk" _ _ _ _ _)) = Just "ua"
571−fromBCP47' (Just (Lang "vi" _ _ _) ) = Just "vn"
577+fromBCP47' (Just (Lang "vi" _ _ _ _ _)) = Just "vn"
572−fromBCP47' (Just (Lang "zh" _ _ _) ) = Just "cn"
578+fromBCP47' (Just (Lang "zh" _ _ _ _ _)) = Just "cn"
573−fromBCP47' (Just (Lang l _ _ _) ) = Just l
579+fromBCP47' (Just (Lang l _ _ _ _ _)) = Just l
574−fromBCP47' Nothing = Nothing
580+fromBCP47' Nothing = Nothing
src/Text/Pandoc/Writers/CslJson.hs+4−3
@@ -34,15 +34,16 @@ import Control.Monad.Identity
34import Citeproc.Locale (getLocale)
34import Citeproc.Locale (getLocale)
35import Citeproc.CslJson
35import Citeproc.CslJson
36import Text.Pandoc.Options (WriterOptions)
36import Text.Pandoc.Options (WriterOptions)
37−import Data.Maybe (mapMaybe)
37+import Data.Maybe (mapMaybe, fromMaybe)
38import Data.Aeson.Encode.Pretty (Config (..), Indent (Spaces),
38import Data.Aeson.Encode.Pretty (Config (..), Indent (Spaces),
39 NumberFormat (Generic),
39 NumberFormat (Generic),
40 defConfig, encodePretty')
40 defConfig, encodePretty')
41
41
42writeCslJson :: PandocMonad m => WriterOptions -> Pandoc -> m Text
42writeCslJson :: PandocMonad m => WriterOptions -> Pandoc -> m Text
43writeCslJson _opts (Pandoc meta _) = do
43writeCslJson _opts (Pandoc meta _) = do
44− let lang = maybe (Lang "en" (Just "US")) parseLang
44+ let lang = fromMaybe (Lang "en" Nothing (Just "US") [] [] [])
45− (lookupMeta "lang" meta >>= metaValueToText)
45+ (lookupMeta "lang" meta >>= metaValueToText >>=
46+ either (const Nothing) Just . parseLang)
46 locale <- case getLocale lang of
47 locale <- case getLocale lang of
47 Left e -> throwError $ PandocCiteprocError e
48 Left e -> throwError $ PandocCiteprocError e
48 Right l -> return l
49 Right l -> return l
src/Text/Pandoc/Writers/Docbook.hs+50−7
@@ -168,7 +168,7 @@ blockToDocbook :: PandocMonad m => WriterOptions -> Block -> DB m (Doc Text)
168blockToDocbook _ Null = return empty
168blockToDocbook _ Null = return empty
169-- Add ids to paragraphs in divs with ids - this is needed for
169-- Add ids to paragraphs in divs with ids - this is needed for
170-- pandoc-citeproc to get link anchors in bibliographies:
170-- pandoc-citeproc to get link anchors in bibliographies:
171−blockToDocbook opts (Div (id',"section":_,_) (Header lvl _ ils : xs)) = do
171+blockToDocbook opts (Div (id',"section":_,_) (Header lvl (_,_,attrs) ils : xs)) = do
172 version <- ask
172 version <- ask
173 -- Docbook doesn't allow sections with no content, so insert some if needed
173 -- Docbook doesn't allow sections with no content, so insert some if needed
174 let bs = if null xs
174 let bs = if null xs
@@ -188,15 +188,17 @@ blockToDocbook opts (Div (id',"section":_,_) (Header lvl _ ils : xs)) = do
188 -- standalone documents will include them in the template.
188 -- standalone documents will include them in the template.
189 then [("xmlns", "http://docbook.org/ns/docbook"),("xmlns:xlink", "http://www.w3.org/1999/xlink")]
189 then [("xmlns", "http://docbook.org/ns/docbook"),("xmlns:xlink", "http://www.w3.org/1999/xlink")]
190 else []
190 else []
191+
192+ -- Populate miscAttr with Header.Attr.attributes, filtering out non-valid DocBook section attributes, id, and xml:id
193+ miscAttr = filter (isSectionAttr version) attrs
191− attribs = nsAttr <> idAttr
194+ attribs = nsAttr <> idAttr <> miscAttr
192 title' <- inlinesToDocbook opts ils
195 title' <- inlinesToDocbook opts ils
193 contents <- blocksToDocbook opts bs
196 contents <- blocksToDocbook opts bs
194 return $ inTags True tag attribs $ inTagsSimple "title" title' $$ contents
197 return $ inTags True tag attribs $ inTagsSimple "title" title' $$ contents
195blockToDocbook opts (Div (ident,classes,_) bs) = do
198blockToDocbook opts (Div (ident,classes,_) bs) = do
196 version <- ask
199 version <- ask
197 let identAttribs = [(idName version, ident) | not (T.null ident)]
200 let identAttribs = [(idName version, ident) | not (T.null ident)]
198− admonitions = ["attention","caution","danger","error","hint",
199− "important","note","tip","warning"]
201+ admonitions = ["caution","danger","important","note","tip","warning"]
200 case classes of
202 case classes of
201 (l:_) | l `elem` admonitions -> do
203 (l:_) | l `elem` admonitions -> do
202 let (mTitleBs, bodyBs) =
204 let (mTitleBs, bodyBs) =
@@ -250,17 +252,18 @@ blockToDocbook opts (LineBlock lns) =
250 blockToDocbook opts $ linesToPara lns
252 blockToDocbook opts $ linesToPara lns
251blockToDocbook opts (BlockQuote blocks) =
253blockToDocbook opts (BlockQuote blocks) =
252 inTagsIndented "blockquote" <$> blocksToDocbook opts blocks
254 inTagsIndented "blockquote" <$> blocksToDocbook opts blocks
253−blockToDocbook _ (CodeBlock (_,classes,_) str) = return $
255+blockToDocbook opts (CodeBlock (_,classes,_) str) = return $
254 literal ("<programlisting" <> lang <> ">") <> cr <>
256 literal ("<programlisting" <> lang <> ">") <> cr <>
255 flush (literal (escapeStringForXML str) <> cr <> literal "</programlisting>")
257 flush (literal (escapeStringForXML str) <> cr <> literal "</programlisting>")
256 where lang = if null langs
258 where lang = if null langs
257 then ""
259 then ""
258 else " language=\"" <> escapeStringForXML (head langs) <>
260 else " language=\"" <> escapeStringForXML (head langs) <>
259 "\""
261 "\""
262+ syntaxMap = writerSyntaxMap opts
260− isLang l = T.toLower l `elem` map T.toLower languages
263+ isLang l = T.toLower l `elem` map T.toLower (languages syntaxMap)
261 langsFrom s = if isLang s
264 langsFrom s = if isLang s
262 then [s]
265 then [s]
263− else languagesByExtension . T.toLower $ s
266+ else (languagesByExtension syntaxMap) . T.toLower $ s
264 langs = concatMap langsFrom classes
267 langs = concatMap langsFrom classes
265blockToDocbook opts (BulletList lst) = do
268blockToDocbook opts (BulletList lst) = do
266 let attribs = [("spacing", "compact") | isTightList lst]
269 let attribs = [("spacing", "compact") | isTightList lst]
@@ -451,3 +454,43 @@ idAndRole (id',cls,_) = ident <> role
451 where
454 where
452 ident = [("id", id') | not (T.null id')]
455 ident = [("id", id') | not (T.null id')]
453 role = [("role", T.unwords cls) | not (null cls)]
456 role = [("role", T.unwords cls) | not (null cls)]
457+
458+isSectionAttr :: DocBookVersion -> (Text, Text) -> Bool
459+isSectionAttr _ ("label",_) = True
460+isSectionAttr _ ("status",_) = True
461+isSectionAttr DocBook5 ("annotations",_) = True
462+isSectionAttr DocBook5 ("dir","ltr") = True
463+isSectionAttr DocBook5 ("dir","rtl") = True
464+isSectionAttr DocBook5 ("dir","lro") = True
465+isSectionAttr DocBook5 ("dir","rlo") = True
466+isSectionAttr _ ("remap",_) = True
467+isSectionAttr _ ("revisionflag","changed") = True
468+isSectionAttr _ ("revisionflag","added") = True
469+isSectionAttr _ ("revisionflag","deleted") = True
470+isSectionAttr _ ("revisionflag","off") = True
471+isSectionAttr _ ("role",_) = True
472+isSectionAttr DocBook5 ("version",_) = True
473+isSectionAttr DocBook5 ("xml:base",_) = True
474+isSectionAttr DocBook5 ("xml:lang",_) = True
475+isSectionAttr _ ("xreflabel",_) = True
476+isSectionAttr DocBook5 ("linkend",_) = True
477+isSectionAttr DocBook5 ("linkends",_) = True
478+isSectionAttr DocBook5 ("xlink:actuate",_) = True
479+isSectionAttr DocBook5 ("xlink:arcrole",_) = True
480+isSectionAttr DocBook5 ("xlink:from",_) = True
481+isSectionAttr DocBook5 ("xlink:href",_) = True
482+isSectionAttr DocBook5 ("xlink:label",_) = True
483+isSectionAttr DocBook5 ("xlink:role",_) = True
484+isSectionAttr DocBook5 ("xlink:show",_) = True
485+isSectionAttr DocBook5 ("xlink:title",_) = True
486+isSectionAttr DocBook5 ("xlink:to",_) = True
487+isSectionAttr DocBook5 ("xlink:type",_) = True
488+isSectionAttr DocBook4 ("arch",_) = True
489+isSectionAttr DocBook4 ("condition",_) = True
490+isSectionAttr DocBook4 ("conformance",_) = True
491+isSectionAttr DocBook4 ("lang",_) = True
492+isSectionAttr DocBook4 ("os",_) = True
493+isSectionAttr DocBook4 ("revision",_) = True
494+isSectionAttr DocBook4 ("security",_) = True
495+isSectionAttr DocBook4 ("vendor",_) = True
496+isSectionAttr _ (_,_) = False
src/Text/Pandoc/Writers/Docx.hs+56−238
@@ -22,7 +22,6 @@ import Control.Applicative ((<|>))
22import Control.Monad.Except (catchError, throwError)
22import Control.Monad.Except (catchError, throwError)
23import Control.Monad.Reader
23import Control.Monad.Reader
24import Control.Monad.State.Strict
24import Control.Monad.State.Strict
25−import qualified Data.ByteString as B
26import qualified Data.ByteString.Lazy as BL
25import qualified Data.ByteString.Lazy as BL
27import Data.Char (isSpace, isLetter)
26import Data.Char (isSpace, isLetter)
28import Data.List (intercalate, isPrefixOf, isSuffixOf)
27import Data.List (intercalate, isPrefixOf, isSuffixOf)
@@ -36,8 +35,9 @@ import qualified Data.Text.Lazy as TL
36import Data.Time.Clock.POSIX
35import Data.Time.Clock.POSIX
37import Data.Digest.Pure.SHA (sha1, showDigest)
36import Data.Digest.Pure.SHA (sha1, showDigest)
38import Skylighting
37import Skylighting
39−import Text.Pandoc.BCP47 (getLang, renderLang)
38+import Text.Collate.Lang (renderLang)
40−import Text.Pandoc.Class.PandocMonad (PandocMonad, report, toLang)
39+import Text.Pandoc.Class.PandocMonad (PandocMonad, report, toLang, translateTerm)
40+import qualified Text.Pandoc.Translations as Term
41import qualified Text.Pandoc.Class.PandocMonad as P
41import qualified Text.Pandoc.Class.PandocMonad as P
42import Data.Time
42import Data.Time
43import Text.Pandoc.UTF8 (fromTextLazy)
43import Text.Pandoc.UTF8 (fromTextLazy)
@@ -47,123 +47,25 @@ import Text.Pandoc.Highlighting (highlight)
47import Text.Pandoc.Error
47import Text.Pandoc.Error
48import Text.Pandoc.ImageSize
48import Text.Pandoc.ImageSize
49import Text.Pandoc.Logging
49import Text.Pandoc.Logging
50−import Text.Pandoc.MIME (MimeType, extensionFromMimeType, getMimeType,
50+import Text.Pandoc.MIME (extensionFromMimeType, getMimeType, getMimeTypeDef)
51− getMimeTypeDef)
52import Text.Pandoc.Options
51import Text.Pandoc.Options
53import Text.Pandoc.Writers.Docx.StyleMap
52import Text.Pandoc.Writers.Docx.StyleMap
53+import Text.Pandoc.Writers.Docx.Table
54+import Text.Pandoc.Writers.Docx.Types
54import Text.Pandoc.Shared
55import Text.Pandoc.Shared
55import Text.Pandoc.Walk
56import Text.Pandoc.Walk
57+import qualified Text.Pandoc.Writers.GridTable as Grid
56import Text.Pandoc.Writers.Math
58import Text.Pandoc.Writers.Math
57import Text.Pandoc.Writers.Shared
59import Text.Pandoc.Writers.Shared
58−import Text.Printf (printf)
59import Text.TeXMath
60import Text.TeXMath
60import Text.Pandoc.Writers.OOXML
61import Text.Pandoc.Writers.OOXML
61import Text.Pandoc.XML.Light as XML
62import Text.Pandoc.XML.Light as XML
62import Data.Generics (mkT, everywhere)
63import Data.Generics (mkT, everywhere)
63
64
64−data ListMarker = NoMarker
65− | BulletMarker
66− | NumberMarker ListNumberStyle ListNumberDelim Int
67− deriving (Show, Read, Eq, Ord)
68−
69−listMarkerToId :: ListMarker -> Text
70−listMarkerToId NoMarker = "990"
71−listMarkerToId BulletMarker = "991"
72−listMarkerToId (NumberMarker sty delim n) = T.pack $
73− '9' : '9' : styNum : delimNum : show n
74− where styNum = case sty of
75− DefaultStyle -> '2'
76− Example -> '3'
77− Decimal -> '4'
78− LowerRoman -> '5'
79− UpperRoman -> '6'
80− LowerAlpha -> '7'
81− UpperAlpha -> '8'
82− delimNum = case delim of
83− DefaultDelim -> '0'
84− Period -> '1'
85− OneParen -> '2'
86− TwoParens -> '3'
87−
88−data EnvProps = EnvProps{ styleElement :: Maybe Element
89− , otherElements :: [Element]
90− }
91−
92−instance Semigroup EnvProps where
93− EnvProps s es <> EnvProps s' es' = EnvProps (s <|> s') (es ++ es')
94−
95−instance Monoid EnvProps where
96− mempty = EnvProps Nothing []
97− mappend = (<>)
98−
99squashProps :: EnvProps -> [Element]
65squashProps :: EnvProps -> [Element]
100squashProps (EnvProps Nothing es) = es
66squashProps (EnvProps Nothing es) = es
101squashProps (EnvProps (Just e) es) = e : es
67squashProps (EnvProps (Just e) es) = e : es
102
68
103−data WriterEnv = WriterEnv{ envTextProperties :: EnvProps
104− , envParaProperties :: EnvProps
105− , envRTL :: Bool
106− , envListLevel :: Int
107− , envListNumId :: Int
108− , envInDel :: Bool
109− , envChangesAuthor :: Text
110− , envChangesDate :: Text
111− , envPrintWidth :: Integer
112− }
113−
114−defaultWriterEnv :: WriterEnv
115−defaultWriterEnv = WriterEnv{ envTextProperties = mempty
116− , envParaProperties = mempty
117− , envRTL = False
118− , envListLevel = -1
119− , envListNumId = 1
120− , envInDel = False
121− , envChangesAuthor = "unknown"
122− , envChangesDate = "1969-12-31T19:00:00Z"
123− , envPrintWidth = 1
124− }
125−
126−data WriterState = WriterState{
127− stFootnotes :: [Element]
128− , stComments :: [([(Text, Text)], [Inline])]
129− , stSectionIds :: Set.Set Text
130− , stExternalLinks :: M.Map Text Text
131− , stImages :: M.Map FilePath (String, String, Maybe MimeType, B.ByteString)
132− , stLists :: [ListMarker]
133− , stInsId :: Int
134− , stDelId :: Int
135− , stStyleMaps :: StyleMaps
136− , stFirstPara :: Bool
137− , stInTable :: Bool
138− , stInList :: Bool
139− , stTocTitle :: [Inline]
140− , stDynamicParaProps :: Set.Set ParaStyleName
141− , stDynamicTextProps :: Set.Set CharStyleName
142− , stCurId :: Int
143− }
144−
145−defaultWriterState :: WriterState
146−defaultWriterState = WriterState{
147− stFootnotes = defaultFootnotes
148− , stComments = []
149− , stSectionIds = Set.empty
150− , stExternalLinks = M.empty
151− , stImages = M.empty
152− , stLists = [NoMarker]
153− , stInsId = 1
154− , stDelId = 1
155− , stStyleMaps = StyleMaps M.empty M.empty
156− , stFirstPara = False
157− , stInTable = False
158− , stInList = False
159− , stTocTitle = [Str "Table of Contents"]
160− , stDynamicParaProps = Set.empty
161− , stDynamicTextProps = Set.empty
162− , stCurId = 20
163− }
164−
165−type WS m = ReaderT WriterEnv (StateT WriterState m)
166−
167renumIdMap :: Int -> [Element] -> M.Map Text Text
69renumIdMap :: Int -> [Element] -> M.Map Text Text
168renumIdMap _ [] = M.empty
70renumIdMap _ [] = M.empty
169renumIdMap n (e:es)
71renumIdMap n (e:es)
@@ -568,12 +470,27 @@ writeDocx opts doc = do
568 -- adds references to footnotes or endnotes we don't have...
470 -- adds references to footnotes or endnotes we don't have...
569 -- we do, however, copy some settings over from reference
471 -- we do, however, copy some settings over from reference
570 let settingsPath = "word/settings.xml"
472 let settingsPath = "word/settings.xml"
473+ settingsList = [ "zoom"
474+ , "embedSystemFonts"
475+ , "doNotTrackMoves"
476+ , "defaultTabStop"
477+ , "drawingGridHorizontalSpacing"
478+ , "drawingGridVerticalSpacing"
479+ , "displayHorizontalDrawingGridEvery"
480+ , "displayVerticalDrawingGridEvery"
481+ , "characterSpacingControl"
482+ , "savePreviewPicture"
483+ , "mathPr"
484+ , "themeFontLang"
485+ , "decimalSymbol"
486+ , "listSeparator"
571− settingsList = [ "w:autoHyphenation"
487+ , "autoHyphenation"
572− , "w:consecutiveHyphenLimit"
488+ , "consecutiveHyphenLimit"
573− , "w:hyphenationZone"
489+ , "hyphenationZone"
574− , "w:doNotHyphenateCap"
490+ , "doNotHyphenateCap"
575− , "w:evenAndOddHeaders"
491+ , "evenAndOddHeaders"
576− , "w:proofState"
492+ , "proofState"
493+ , "compat"
577 ]
494 ]
578 settingsEntry <- copyChildren refArchive distArchive settingsPath epochtime settingsList
495 settingsEntry <- copyChildren refArchive distArchive settingsPath epochtime settingsList
579
496
@@ -676,16 +593,17 @@ copyChildren :: (PandocMonad m)
676copyChildren refArchive distArchive path timestamp elNames = do
593copyChildren refArchive distArchive path timestamp elNames = do
677 ref <- parseXml refArchive distArchive path
594 ref <- parseXml refArchive distArchive path
678 dist <- parseXml distArchive distArchive path
595 dist <- parseXml distArchive distArchive path
596+ let elsToCopy =
597+ map cleanElem $ filterChildrenName (\e -> qName e `elem` elNames) ref
598+ let elsToKeep =
599+ [e | Elem e <- elContent dist, not (any (hasSameNameAs e) elsToCopy)]
679 return $ toEntry path timestamp $ renderXml dist{
600 return $ toEntry path timestamp $ renderXml dist{
680− elContent = elContent dist ++ copyContent ref
601+ elContent = map Elem elsToKeep ++ map Elem elsToCopy
681 }
602 }
682 where
603 where
683− strName QName{qName=name, qPrefix=prefix}
604+ hasSameNameAs (Element {elName = n1}) (Element {elName = n2}) =
684− | Just p <- prefix = p <> ":" <> name
605+ qName n1 == qName n2
685− | otherwise = name
686− shouldCopy = (`elem` elNames) . strName
687− cleanElem el@Element{elName=name} = Elem el{elName=name{qURI=Nothing}}
606+ cleanElem el@Element{elName=name} = el{elName=name{qURI=Nothing}}
688− copyContent = map cleanElem . filterChildrenName shouldCopy
689
607
690-- this is the lowest number used for a list numId
608-- this is the lowest number used for a list numId
691baseListId :: Int
609baseListId :: Int
@@ -858,12 +776,6 @@ separateTables (x@Table{}:xs@(Table{}:_)) =
858 x : RawBlock (Format "openxml") "<w:p />" : separateTables xs
776 x : RawBlock (Format "openxml") "<w:p />" : separateTables xs
859separateTables (x:xs) = x : separateTables xs
777separateTables (x:xs) = x : separateTables xs
860
778
861−pStyleM :: (PandocMonad m) => ParaStyleName -> WS m XML.Element
862−pStyleM styleName = do
863− pStyleMap <- gets (smParaStyle . stStyleMaps)
864− let sty' = getStyleIdFromName styleName pStyleMap
865− return $ mknode "w:pStyle" [("w:val", fromStyleId sty')] ()
866−
867rStyleM :: (PandocMonad m) => CharStyleName -> WS m XML.Element
779rStyleM :: (PandocMonad m) => CharStyleName -> WS m XML.Element
868rStyleM styleName = do
780rStyleM styleName = do
869 cStyleMap <- gets (smCharStyle . stStyleMaps)
781 cStyleMap <- gets (smCharStyle . stStyleMaps)
@@ -943,14 +855,28 @@ blockToOpenXML' opts (Plain lst) = do
943-- title beginning with fig: indicates that the image is a figure
855-- title beginning with fig: indicates that the image is a figure
944blockToOpenXML' opts (Para [Image attr alt (src,T.stripPrefix "fig:" -> Just tit)]) = do
856blockToOpenXML' opts (Para [Image attr alt (src,T.stripPrefix "fig:" -> Just tit)]) = do
945 setFirstPara
857 setFirstPara
858+ fignum <- gets stNextFigureNum
859+ unless (null alt) $ modify $ \st -> st{ stNextFigureNum = fignum + 1 }
860+ let figid = "fig" <> tshow fignum
861+ figname <- translateTerm Term.Figure
946 prop <- pStyleM $
862 prop <- pStyleM $
947 if null alt
863 if null alt
948 then "Figure"
864 then "Figure"
949 else "Captioned Figure"
865 else "Captioned Figure"
950 paraProps <- local (\env -> env { envParaProperties = EnvProps (Just prop) [] <> envParaProperties env }) (getParaProps False)
866 paraProps <- local (\env -> env { envParaProperties = EnvProps (Just prop) [] <> envParaProperties env }) (getParaProps False)
951 contents <- inlinesToOpenXML opts [Image attr alt (src,tit)]
867 contents <- inlinesToOpenXML opts [Image attr alt (src,tit)]
868+ captionNode <- if null alt
869+ then return []
952− captionNode <- withParaPropM (pStyleM "Image Caption")
870+ else withParaPropM (pStyleM "Image Caption")
953− $ blockToOpenXML opts (Para alt)
871+ $ blockToOpenXML opts
872+ (Para $ Span (figid,[],[])
873+ [Str (figname <> "\160"),
874+ RawInline (Format "openxml")
875+ ("<w:fldSimple w:instr=\"SEQ Figure"
876+ <> " \\* ARABIC \"><w:r><w:t>"
877+ <> tshow fignum
878+ <> "</w:t></w:r></w:fldSimple>"),
879+ Str ":", Space] : alt)
954 return $
880 return $
955 Elem (mknode "w:p" [] (map Elem paraProps ++ contents))
881 Elem (mknode "w:p" [] (map Elem paraProps ++ contents))
956 : captionNode
882 : captionNode
@@ -995,78 +921,9 @@ blockToOpenXML' _ HorizontalRule = do
995 $ mknode "v:rect" [("style","width:0;height:1.5pt"),
921 $ mknode "v:rect" [("style","width:0;height:1.5pt"),
996 ("o:hralign","center"),
922 ("o:hralign","center"),
997 ("o:hrstd","t"),("o:hr","t")] () ]
923 ("o:hrstd","t"),("o:hr","t")] () ]
998−blockToOpenXML' opts (Table _ blkCapt specs thead tbody tfoot) = do
924+blockToOpenXML' opts (Table attr caption colspecs thead tbodies tfoot) =
999− let (caption, aligns, widths, headers, rows) = toLegacyTable blkCapt specs thead tbody tfoot
1000− setFirstPara
1001− modify $ \s -> s { stInTable = True }
1002− let captionStr = stringify caption
1003− caption' <- if null caption
1004− then return []
1005− else withParaPropM (pStyleM "Table Caption")
1006− $ blockToOpenXML opts (Para caption)
1007− let alignmentFor al = mknode "w:jc" [("w:val",alignmentToString al)] ()
1008− -- Table cells require a <w:p> element, even an empty one!
1009− -- Not in the spec but in Word 2007, 2010. See #4953. And
1010− -- apparently the last element must be a <w:p>, see #6983.
1011− let cellToOpenXML (al, cell) = do
1012− es <- withParaProp (alignmentFor al) $ blocksToOpenXML opts cell
925+ tableToOpenXML (blocksToOpenXML opts)
1013− return $
926+ (Grid.toTable attr caption colspecs thead tbodies tfoot)
1014− case reverse (onlyElems es) of
1015− b:e:_ | qName (elName b) == "bookmarkEnd"
1016− , qName (elName e) == "p" -> es
1017− e:_ | qName (elName e) == "p" -> es
1018− _ -> es ++ [Elem $ mknode "w:p" [] ()]
1019− headers' <- mapM cellToOpenXML $ zip aligns headers
1020− rows' <- mapM (mapM cellToOpenXML . zip aligns) rows
1021− compactStyle <- pStyleM "Compact"
1022− let emptyCell' = [Elem $ mknode "w:p" [] [mknode "w:pPr" [] [compactStyle]]]
1023− let mkcell contents = mknode "w:tc" []
1024− $ if null contents
1025− then emptyCell'
1026− else contents
1027− let mkrow cells =
1028− mknode "w:tr" [] $
1029− map mkcell cells
1030− let textwidth = 7920 -- 5.5 in in twips, 1/20 pt
1031− let fullrow = 5000 -- 100% specified in pct
1032− let (rowwidth :: Int) = round $ fullrow * sum widths
1033− let mkgridcol w = mknode "w:gridCol"
1034− [("w:w", tshow (floor (textwidth * w) :: Integer))] ()
1035− let hasHeader = not $ all null headers
1036− modify $ \s -> s { stInTable = False }
1037− -- for compatibility with Word <= 2007, we include a val with a bitmask
1038− -- 0×0020 Apply first row conditional formatting
1039− -- 0×0040 Apply last row conditional formatting
1040− -- 0×0080 Apply first column conditional formatting
1041− -- 0×0100 Apply last column conditional formatting
1042− -- 0×0200 Do not apply row banding conditional formatting
1043− -- 0×0400 Do not apply column banding conditional formattin
1044− let tblLookVal :: Int
1045− tblLookVal = if hasHeader then 0x20 else 0
1046− return $
1047− caption' ++
1048− [Elem $
1049− mknode "w:tbl" []
1050− ( mknode "w:tblPr" []
1051− ( mknode "w:tblStyle" [("w:val","Table")] () :
1052− mknode "w:tblW" [("w:type", "pct"), ("w:w", tshow rowwidth)] () :
1053− mknode "w:tblLook" [("w:firstRow",if hasHeader then "1" else "0")
1054− ,("w:lastRow","0")
1055− ,("w:firstColumn","0")
1056− ,("w:lastColumn","0")
1057− ,("w:noHBand","0")
1058− ,("w:noVBand","0")
1059− ,("w:val", T.pack $ printf "%04x" tblLookVal)
1060− ] () :
1061− [ mknode "w:tblCaption" [("w:val", captionStr)] ()
1062− | not (null caption) ] )
1063− : mknode "w:tblGrid" []
1064− (if all (==0) widths
1065− then []
1066− else map mkgridcol widths)
1067− : [ mkrow headers' | hasHeader ] ++
1068− map mkrow rows'
1069− )]
1070blockToOpenXML' opts el
927blockToOpenXML' opts el
1071 | BulletList lst <- el = addOpenXMLList BulletMarker lst
928 | BulletList lst <- el = addOpenXMLList BulletMarker lst
1072 | OrderedList (start, numstyle, numdelim) lst <- el
929 | OrderedList (start, numstyle, numdelim) lst <- el
@@ -1121,13 +978,6 @@ listItemToOpenXML opts numid (first:rest) = do
1121 modify $ \st -> st{ stInList = oldInList }
978 modify $ \st -> st{ stInList = oldInList }
1122 return $ first'' ++ rest''
979 return $ first'' ++ rest''
1123
980
1124−alignmentToString :: Alignment -> Text
1125−alignmentToString alignment = case alignment of
1126− AlignLeft -> "left"
1127− AlignRight -> "right"
1128− AlignCenter -> "center"
1129− AlignDefault -> "left"
1130−
1131-- | Convert a list of inline elements to OpenXML.
981-- | Convert a list of inline elements to OpenXML.
1132inlinesToOpenXML :: PandocMonad m => WriterOptions -> [Inline] -> WS m [Content]
982inlinesToOpenXML :: PandocMonad m => WriterOptions -> [Inline] -> WS m [Content]
1133inlinesToOpenXML opts lst = concat `fmap` mapM (inlineToOpenXML opts) lst
983inlinesToOpenXML opts lst = concat `fmap` mapM (inlineToOpenXML opts) lst
@@ -1138,10 +988,6 @@ withNumId numid = local $ \env -> env{ envListNumId = numid }
1138asList :: (PandocMonad m) => WS m a -> WS m a
988asList :: (PandocMonad m) => WS m a -> WS m a
1139asList = local $ \env -> env{ envListLevel = envListLevel env + 1 }
989asList = local $ \env -> env{ envListLevel = envListLevel env + 1 }
1140
990
1141−isStyle :: Element -> Bool
1142−isStyle e = isElem [] "w" "rStyle" e ||
1143− isElem [] "w" "pStyle" e
1144−
1145getTextProps :: (PandocMonad m) => WS m [Element]
991getTextProps :: (PandocMonad m) => WS m [Element]
1146getTextProps = do
992getTextProps = do
1147 props <- asks envTextProperties
993 props <- asks envTextProperties
@@ -1170,16 +1016,6 @@ getParaProps displayMathPara = do
1170 [] -> []
1016 [] -> []
1171 ps -> [mknode "w:pPr" [] ps]
1017 ps -> [mknode "w:pPr" [] ps]
1172
1018
1173−withParaProp :: PandocMonad m => Element -> WS m a -> WS m a
1174−withParaProp d p =
1175− local (\env -> env {envParaProperties = ep <> envParaProperties env}) p
1176− where ep = if isStyle d then EnvProps (Just d) [] else EnvProps Nothing [d]
1177−
1178−withParaPropM :: PandocMonad m => WS m Element -> WS m a -> WS m a
1179−withParaPropM md p = do
1180− d <- md
1181− withParaProp d p
1182−
1183formattedString :: PandocMonad m => Text -> WS m [Element]
1019formattedString :: PandocMonad m => Text -> WS m [Element]
1184formattedString str =
1020formattedString str =
1185 -- properly handle soft hyphens
1021 -- properly handle soft hyphens
@@ -1200,9 +1036,6 @@ formattedRun els = do
1200 props <- getTextProps
1036 props <- getTextProps
1201 return [ mknode "w:r" [] $ props ++ els ]
1037 return [ mknode "w:r" [] $ props ++ els ]
1202
1038
1203−setFirstPara :: PandocMonad m => WS m ()
1204−setFirstPara = modify $ \s -> s { stFirstPara = True }
1205−
1206-- | Convert an inline element to OpenXML.
1039-- | Convert an inline element to OpenXML.
1207inlineToOpenXML :: PandocMonad m => WriterOptions -> Inline -> WS m [Content]
1040inlineToOpenXML :: PandocMonad m => WriterOptions -> Inline -> WS m [Content]
1208inlineToOpenXML opts il = withDirection $ inlineToOpenXML' opts il
1041inlineToOpenXML opts il = withDirection $ inlineToOpenXML' opts il
@@ -1471,6 +1304,7 @@ inlineToOpenXML' opts (Image attr@(imgident, _, _) alt (src, title)) = do
1471 Just Eps -> ".eps"
1304 Just Eps -> ".eps"
1472 Just Svg -> ".svg"
1305 Just Svg -> ".svg"
1473 Just Emf -> ".emf"
1306 Just Emf -> ".emf"
1307+ Just Tiff -> ".tiff"
1474 Nothing -> ""
1308 Nothing -> ""
1475 imgpath = "media/" <> ident <> imgext
1309 imgpath = "media/" <> ident <> imgext
1476 mbMimeType = mt <|> getMimeType (T.unpack imgpath)
1310 mbMimeType = mt <|> getMimeType (T.unpack imgpath)
@@ -1494,22 +1328,6 @@ inlineToOpenXML' opts (Image attr@(imgident, _, _) alt (src, title)) = do
1494br :: Element
1328br :: Element
1495br = mknode "w:r" [] [mknode "w:br" [] ()]
1329br = mknode "w:r" [] [mknode "w:br" [] ()]
1496
1330
1497−-- Word will insert these footnotes into the settings.xml file
1498−-- (whether or not they're visible in the document). If they're in the
1499−-- file, but not in the footnotes.xml file, it will produce
1500−-- problems. So we want to make sure we insert them into our document.
1501−defaultFootnotes :: [Element]
1502−defaultFootnotes = [ mknode "w:footnote"
1503− [("w:type", "separator"), ("w:id", "-1")]
1504− [ mknode "w:p" []
1505− [mknode "w:r" []
1506− [ mknode "w:separator" [] ()]]]
1507− , mknode "w:footnote"
1508− [("w:type", "continuationSeparator"), ("w:id", "0")]
1509− [ mknode "w:p" []
1510− [ mknode "w:r" []
1511− [ mknode "w:continuationSeparator" [] ()]]]]
1512−
1513
1331
1514withDirection :: PandocMonad m => WS m a -> WS m a
1332withDirection :: PandocMonad m => WS m a -> WS m a
1515withDirection x = do
1333withDirection x = do
src/Text/Pandoc/Writers/Docx/Table.hsnew file+227
@@ -0,0 +1,227 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE ScopedTypeVariables #-}
4+{- |
5+Module : Text.Pandoc.Writers.Docx.Table
6+Copyright : Copyright (C) 2012-2021 John MacFarlane
7+License : GNU GPL, version 2 or above
8+Maintainer : John MacFarlane <jgm@berkeley.edu>
9+
10+Conversion of table blocks to docx.
11+-}
12+module Text.Pandoc.Writers.Docx.Table
13+ ( tableToOpenXML
14+ ) where
15+
16+import Control.Monad.State.Strict
17+import Data.Array
18+import Data.Text (Text)
19+import Text.Pandoc.Definition
20+import Text.Pandoc.Class.PandocMonad (PandocMonad, translateTerm)
21+import Text.Pandoc.Writers.Docx.Types
22+import Text.Pandoc.Shared
23+import Text.Printf (printf)
24+import Text.Pandoc.Writers.GridTable hiding (Table)
25+import Text.Pandoc.Writers.OOXML
26+import Text.Pandoc.XML.Light as XML hiding (Attr)
27+import qualified Data.Text as T
28+import qualified Text.Pandoc.Translations as Term
29+import qualified Text.Pandoc.Writers.GridTable as Grid
30+
31+tableToOpenXML :: PandocMonad m
32+ => ([Block] -> WS m [Content])
33+ -> Grid.Table
34+ -> WS m [Content]
35+tableToOpenXML blocksToOpenXML gridTable = do
36+ setFirstPara
37+ let (Grid.Table (ident,_,_) caption colspecs _rowheads thead tbodies tfoot) =
38+ gridTable
39+ let (Caption _maybeShortCaption captionBlocks) = caption
40+ tablenum <- gets stNextTableNum
41+ unless (null captionBlocks) $
42+ modify $ \st -> st{ stNextTableNum = tablenum + 1 }
43+ let tableid = if T.null ident
44+ then "table" <> tshow tablenum
45+ else ident
46+ tablename <- translateTerm Term.Table
47+ let captionStr = stringify captionBlocks
48+ let aligns = map fst $ elems colspecs
49+ captionXml <- if null captionBlocks
50+ then return []
51+ else withParaPropM (pStyleM "Table Caption")
52+ $ blocksToOpenXML
53+ $ addLabel tableid tablename tablenum captionBlocks
54+ -- We set "in table" after processing the caption, because we don't
55+ -- want the "Table Caption" style to be overwritten with "Compact".
56+ modify $ \s -> s { stInTable = True }
57+ head' <- cellGridToOpenXML blocksToOpenXML HeadRow aligns thead
58+ bodies <- mapM (cellGridToOpenXML blocksToOpenXML BodyRow aligns) tbodies
59+ foot' <- cellGridToOpenXML blocksToOpenXML FootRow aligns tfoot
60+
61+ let hasHeader = not . null . indices . partRowAttrs $ thead
62+ let hasFooter = not . null . indices . partRowAttrs $ tfoot
63+ -- for compatibility with Word <= 2007, we include a val with a bitmask
64+ -- 0×0020 Apply first row conditional formatting
65+ -- 0×0040 Apply last row conditional formatting
66+ -- 0×0080 Apply first column conditional formatting
67+ -- 0×0100 Apply last column conditional formatting
68+ -- 0×0200 Do not apply row banding conditional formatting
69+ -- 0×0400 Do not apply column banding conditional formattin
70+ let tblLookVal = if hasHeader then (0x20 :: Int) else 0
71+ let (gridCols, tblWattr) = tableLayout (elems colspecs)
72+ let tbl = mknode "w:tbl" []
73+ ( mknode "w:tblPr" []
74+ ( mknode "w:tblStyle" [("w:val","Table")] () :
75+ mknode "w:tblW" tblWattr () :
76+ mknode "w:tblLook" [("w:firstRow",if hasHeader then "1" else "0")
77+ ,("w:lastRow",if hasFooter then "1" else "0")
78+ ,("w:firstColumn","0")
79+ ,("w:lastColumn","0")
80+ ,("w:noHBand","0")
81+ ,("w:noVBand","0")
82+ ,("w:val", T.pack $ printf "%04x" tblLookVal)
83+ ] () :
84+ [ mknode "w:tblCaption" [("w:val", captionStr)] ()
85+ | not (T.null captionStr) ]
86+ )
87+ : mknode "w:tblGrid" [] gridCols
88+ : head' ++ mconcat bodies ++ foot'
89+ )
90+ modify $ \s -> s { stInTable = False }
91+ return $ captionXml ++ [Elem tbl]
92+
93+addLabel :: Text -> Text -> Int -> [Block] -> [Block]
94+addLabel tableid tablename tablenum bs =
95+ case bs of
96+ (Para ils : rest) -> Para (label : Space : ils) : rest
97+ (Plain ils : rest) -> Plain (label : Space : ils) : rest
98+ _ -> Para [label] : bs
99+ where
100+ label = Span (tableid,[],[])
101+ [Str (tablename <> "\160"),
102+ RawInline (Format "openxml")
103+ ("<w:fldSimple w:instr=\"SEQ Table"
104+ <> " \\* ARABIC \"><w:r><w:t>"
105+ <> tshow tablenum
106+ <> "</w:t></w:r></w:fldSimple>"),
107+ Str ":"]
108+
109+-- | Parts of a table
110+data RowType = HeadRow | BodyRow | FootRow
111+
112+alignmentToString :: Alignment -> Text
113+alignmentToString = \case
114+ AlignLeft -> "left"
115+ AlignRight -> "right"
116+ AlignCenter -> "center"
117+ AlignDefault -> "left"
118+
119+tableLayout :: [ColSpec] -> ([Element], [(Text, Text)])
120+tableLayout specs =
121+ let
122+ textwidth = 7920 -- 5.5 in in twips (1 twip == 1/20 pt)
123+ fullrow = 5000 -- 100% specified in pct (1 pct == 1/50th of a percent)
124+ ncols = length specs
125+ getWidth = \case
126+ ColWidth n -> n
127+ _ -> 0
128+ widths = map (getWidth . snd) specs
129+ rowwidth = round (fullrow * sum widths) :: Int
130+ widthToTwips w = floor (textwidth * w) :: Int
131+ mkGridCol w = mknode "w:gridCol" [("w:w", tshow (widthToTwips w))] ()
132+ in if all (== 0) widths
133+ then ( replicate ncols $ mkGridCol (1.0 / fromIntegral ncols)
134+ , [ ("w:type", "auto"), ("w:w", "0")])
135+ else ( map mkGridCol widths
136+ , [ ("w:type", "pct"), ("w:w", tshow rowwidth) ])
137+
138+cellGridToOpenXML :: PandocMonad m
139+ => ([Block] -> WS m [Content])
140+ -> RowType
141+ -> [Alignment]
142+ -> Part
143+ -> WS m [Element]
144+cellGridToOpenXML blocksToOpenXML rowType aligns part@(Part _ cellArray _) =
145+ if null (elems cellArray)
146+ then return mempty
147+ else mapM (rowToOpenXML blocksToOpenXML) $
148+ partToRows rowType aligns part
149+
150+data OOXMLCell
151+ = OOXMLCell Attr Alignment RowSpan ColSpan [Block]
152+ | OOXMLCellMerge ColSpan
153+
154+data OOXMLRow = OOXMLRow RowType Attr [OOXMLCell]
155+
156+partToRows :: RowType -> [Alignment] -> Part -> [OOXMLRow]
157+partToRows rowType aligns part =
158+ let
159+ toOOXMLCell :: Alignment -> RowIndex -> ColIndex -> GridCell -> [OOXMLCell]
160+ toOOXMLCell columnAlign ridx cidx = \case
161+ ContentCell attr align rowspan colspan blocks ->
162+ -- Respect non-default, cell specific alignment.
163+ let align' = case align of
164+ AlignDefault -> columnAlign
165+ _ -> align
166+ in [OOXMLCell attr align' rowspan colspan blocks]
167+ ContinuationCell idx'@(ridx',cidx') | ridx /= ridx', cidx == cidx' ->
168+ case (partCellArray part)!idx' of
169+ (ContentCell _ _ _ colspan _) -> [OOXMLCellMerge colspan]
170+ x -> error $ "Content cell expected, got, " ++ show x ++
171+ " at index " ++ show idx'
172+ _ -> mempty
173+ mkRow :: (RowIndex, Attr) -> OOXMLRow
174+ mkRow (ridx, attr) = OOXMLRow rowType attr
175+ . mconcat
176+ . zipWith (\align -> uncurry $ toOOXMLCell align ridx)
177+ aligns
178+ . assocs
179+ . rowArray ridx
180+ $ partCellArray part
181+ in map mkRow $ assocs (partRowAttrs part)
182+
183+rowToOpenXML :: PandocMonad m
184+ => ([Block] -> WS m [Content])
185+ -> OOXMLRow
186+ -> WS m Element
187+rowToOpenXML blocksToOpenXML (OOXMLRow rowType _attr cells) = do
188+ xmlcells <- mapM (ooxmlCellToOpenXML blocksToOpenXML) cells
189+ let addTrPr = case rowType of
190+ HeadRow -> (mknode "w:trPr" []
191+ [mknode "w:tblHeader" [("w:val", "true")] ()] :)
192+ BodyRow -> id
193+ FootRow -> id
194+ return $ mknode "w:tr" [] (addTrPr xmlcells)
195+
196+ooxmlCellToOpenXML :: PandocMonad m
197+ => ([Block] -> WS m [Content])
198+ -> OOXMLCell
199+ -> WS m Element
200+ooxmlCellToOpenXML blocksToOpenXML = \case
201+ OOXMLCellMerge (ColSpan colspan) -> do
202+ return $ mknode "w:tc" []
203+ [ mknode "w:tcPr" [] [ mknode "w:gridSpan" [("w:val", tshow colspan)] ()
204+ , mknode "w:vMerge" [("w:val", "continue")] () ]
205+ , mknode "w:p" [] [mknode "w:pPr" [] ()]]
206+ OOXMLCell _attr align rowspan (ColSpan colspan) contents -> do
207+ compactStyle <- pStyleM "Compact"
208+ es <- withParaProp (alignmentFor align) $ blocksToOpenXML contents
209+ -- Table cells require a <w:p> element, even an empty one!
210+ -- Not in the spec but in Word 2007, 2010. See #4953. And
211+ -- apparently the last element must be a <w:p>, see #6983.
212+ return . mknode "w:tc" [] $
213+ Elem
214+ (mknode "w:tcPr" [] ([ mknode "w:gridSpan" [("w:val", tshow colspan)] ()
215+ | colspan > 1] ++
216+ [ mknode "w:vMerge" [("w:val", "restart")] ()
217+ | rowspan > RowSpan 1 ])) :
218+ if null contents
219+ then [Elem $ mknode "w:p" [] [mknode "w:pPr" [] [compactStyle]]]
220+ else case reverse (onlyElems es) of
221+ b:e:_ | qName (elName b) == "bookmarkEnd" -- y tho?
222+ , qName (elName e) == "p" -> es
223+ e:_ | qName (elName e) == "p" -> es
224+ _ -> es ++ [Elem $ mknode "w:p" [] ()]
225+
226+alignmentFor :: Alignment -> Element
227+alignmentFor al = mknode "w:jc" [("w:val",alignmentToString al)] ()
src/Text/Pandoc/Writers/Docx/Types.hsnew file+185
@@ -0,0 +1,185 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{- |
3+Module : Text.Pandoc.Writers.Docx
4+Copyright : Copyright (C) 2012-2021 John MacFarlane
5+License : GNU GPL, version 2 or above
6+Maintainer : John MacFarlane <jgm@berkeley.edu>
7+
8+Conversion of table blocks to docx.
9+-}
10+module Text.Pandoc.Writers.Docx.Types
11+ ( EnvProps (..)
12+ , WriterEnv (..)
13+ , defaultWriterEnv
14+ , WriterState (..)
15+ , defaultWriterState
16+ , WS
17+ , ListMarker (..)
18+ , listMarkerToId
19+ , pStyleM
20+ , isStyle
21+ , setFirstPara
22+ , withParaProp
23+ , withParaPropM
24+ ) where
25+
26+import Control.Applicative ((<|>))
27+import Control.Monad.Reader
28+import Control.Monad.State.Strict
29+import Data.Text (Text)
30+import Text.Pandoc.Class.PandocMonad (PandocMonad)
31+import Text.Pandoc.Definition
32+import Text.Pandoc.MIME (MimeType)
33+import Text.Pandoc.Writers.Docx.StyleMap
34+import Text.Pandoc.Writers.OOXML
35+import Text.Pandoc.XML.Light as XML
36+import qualified Data.ByteString as B
37+import qualified Data.Map as M
38+import qualified Data.Set as Set
39+import qualified Data.Text as T
40+
41+data ListMarker = NoMarker
42+ | BulletMarker
43+ | NumberMarker ListNumberStyle ListNumberDelim Int
44+ deriving (Show, Read, Eq, Ord)
45+
46+listMarkerToId :: ListMarker -> Text
47+listMarkerToId NoMarker = "990"
48+listMarkerToId BulletMarker = "991"
49+listMarkerToId (NumberMarker sty delim n) = T.pack $
50+ '9' : '9' : styNum : delimNum : show n
51+ where styNum = case sty of
52+ DefaultStyle -> '2'
53+ Example -> '3'
54+ Decimal -> '4'
55+ LowerRoman -> '5'
56+ UpperRoman -> '6'
57+ LowerAlpha -> '7'
58+ UpperAlpha -> '8'
59+ delimNum = case delim of
60+ DefaultDelim -> '0'
61+ Period -> '1'
62+ OneParen -> '2'
63+ TwoParens -> '3'
64+
65+
66+data EnvProps = EnvProps{ styleElement :: Maybe Element
67+ , otherElements :: [Element]
68+ }
69+
70+instance Semigroup EnvProps where
71+ EnvProps s es <> EnvProps s' es' = EnvProps (s <|> s') (es ++ es')
72+
73+instance Monoid EnvProps where
74+ mempty = EnvProps Nothing []
75+ mappend = (<>)
76+
77+data WriterEnv = WriterEnv
78+ { envTextProperties :: EnvProps
79+ , envParaProperties :: EnvProps
80+ , envRTL :: Bool
81+ , envListLevel :: Int
82+ , envListNumId :: Int
83+ , envInDel :: Bool
84+ , envChangesAuthor :: Text
85+ , envChangesDate :: Text
86+ , envPrintWidth :: Integer
87+ }
88+
89+defaultWriterEnv :: WriterEnv
90+defaultWriterEnv = WriterEnv
91+ { envTextProperties = mempty
92+ , envParaProperties = mempty
93+ , envRTL = False
94+ , envListLevel = -1
95+ , envListNumId = 1
96+ , envInDel = False
97+ , envChangesAuthor = "unknown"
98+ , envChangesDate = "1969-12-31T19:00:00Z"
99+ , envPrintWidth = 1
100+ }
101+
102+
103+data WriterState = WriterState{
104+ stFootnotes :: [Element]
105+ , stComments :: [([(Text, Text)], [Inline])]
106+ , stSectionIds :: Set.Set Text
107+ , stExternalLinks :: M.Map Text Text
108+ , stImages :: M.Map FilePath (String, String, Maybe MimeType, B.ByteString)
109+ , stLists :: [ListMarker]
110+ , stInsId :: Int
111+ , stDelId :: Int
112+ , stStyleMaps :: StyleMaps
113+ , stFirstPara :: Bool
114+ , stInTable :: Bool
115+ , stInList :: Bool
116+ , stTocTitle :: [Inline]
117+ , stDynamicParaProps :: Set.Set ParaStyleName
118+ , stDynamicTextProps :: Set.Set CharStyleName
119+ , stCurId :: Int
120+ , stNextFigureNum :: Int
121+ , stNextTableNum :: Int
122+ }
123+
124+defaultWriterState :: WriterState
125+defaultWriterState = WriterState{
126+ stFootnotes = defaultFootnotes
127+ , stComments = []
128+ , stSectionIds = Set.empty
129+ , stExternalLinks = M.empty
130+ , stImages = M.empty
131+ , stLists = [NoMarker]
132+ , stInsId = 1
133+ , stDelId = 1
134+ , stStyleMaps = StyleMaps M.empty M.empty
135+ , stFirstPara = False
136+ , stInTable = False
137+ , stInList = False
138+ , stTocTitle = [Str "Table of Contents"]
139+ , stDynamicParaProps = Set.empty
140+ , stDynamicTextProps = Set.empty
141+ , stCurId = 20
142+ , stNextFigureNum = 1
143+ , stNextTableNum = 1
144+ }
145+
146+setFirstPara :: PandocMonad m => WS m ()
147+setFirstPara = modify $ \s -> s { stFirstPara = True }
148+
149+type WS m = ReaderT WriterEnv (StateT WriterState m)
150+
151+-- Word will insert these footnotes into the settings.xml file
152+-- (whether or not they're visible in the document). If they're in the
153+-- file, but not in the footnotes.xml file, it will produce
154+-- problems. So we want to make sure we insert them into our document.
155+defaultFootnotes :: [Element]
156+defaultFootnotes = [ mknode "w:footnote"
157+ [("w:type", "separator"), ("w:id", "-1")]
158+ [ mknode "w:p" []
159+ [mknode "w:r" []
160+ [ mknode "w:separator" [] ()]]]
161+ , mknode "w:footnote"
162+ [("w:type", "continuationSeparator"), ("w:id", "0")]
163+ [ mknode "w:p" []
164+ [ mknode "w:r" []
165+ [ mknode "w:continuationSeparator" [] ()]]]]
166+
167+pStyleM :: (PandocMonad m) => ParaStyleName -> WS m XML.Element
168+pStyleM styleName = do
169+ pStyleMap <- gets (smParaStyle . stStyleMaps)
170+ let sty' = getStyleIdFromName styleName pStyleMap
171+ return $ mknode "w:pStyle" [("w:val", fromStyleId sty')] ()
172+
173+withParaProp :: PandocMonad m => Element -> WS m a -> WS m a
174+withParaProp d p =
175+ local (\env -> env {envParaProperties = ep <> envParaProperties env}) p
176+ where ep = if isStyle d then EnvProps (Just d) [] else EnvProps Nothing [d]
177+
178+withParaPropM :: PandocMonad m => WS m Element -> WS m a -> WS m a
179+withParaPropM md p = do
180+ d <- md
181+ withParaProp d p
182+
183+isStyle :: Element -> Bool
184+isStyle e = isElem [] "w" "rStyle" e ||
185+ isElem [] "w" "pStyle" e
src/Text/Pandoc/Writers/DokuWiki.hs+3−1
@@ -27,6 +27,7 @@ import Control.Monad.Reader (ReaderT, asks, local, runReaderT)
27import Control.Monad.State.Strict (StateT, evalStateT)
27import Control.Monad.State.Strict (StateT, evalStateT)
28import Data.Default (Default (..))
28import Data.Default (Default (..))
29import Data.List (transpose)
29import Data.List (transpose)
30+import Data.List.NonEmpty (nonEmpty)
30import Data.Text (Text)
31import Data.Text (Text)
31import qualified Data.Text as T
32import qualified Data.Text as T
32import Text.Pandoc.Class.PandocMonad (PandocMonad, report)
33import Text.Pandoc.Class.PandocMonad (PandocMonad, report)
@@ -172,7 +173,8 @@ blockToDokuWiki opts (Table _ blkCapt specs thead tbody tfoot) = do
172 then return []
173 then return []
173 else zipWithM (tableItemToDokuWiki opts) aligns headers
174 else zipWithM (tableItemToDokuWiki opts) aligns headers
174 rows' <- mapM (zipWithM (tableItemToDokuWiki opts) aligns) rows
175 rows' <- mapM (zipWithM (tableItemToDokuWiki opts) aligns) rows
175− let widths = map (maximum . map T.length) $ transpose (headers':rows')
176+ let widths = map (maybe 0 maximum . nonEmpty . map T.length)
177+ $ transpose (headers':rows')
176 let padTo (width, al) s =
178 let padTo (width, al) s =
177 case width - T.length s of
179 case width - T.length s of
178 x | x > 0 ->
180 x | x > 0 ->
src/Text/Pandoc/Writers/EPUB.hs+3−3
@@ -991,12 +991,12 @@ metadataElement version md currentTime =
991 showDateTimeISO8601 currentTime | version == EPUB3 ]
991 showDateTimeISO8601 currentTime | version == EPUB3 ]
992 belongsToCollectionNodes =
992 belongsToCollectionNodes =
993 maybe []
993 maybe []
994− (\belongsToCollection -> (unode "meta" ! [("property", "belongs-to-collection"), ("id", "epub-id-1")] $ belongsToCollection )
994+ (\belongsToCollection -> (unode "meta" ! [("property", "belongs-to-collection"), ("id", "epub-collection-1")] $ belongsToCollection )
995 :
995 :
996− [unode "meta" ! [("refines", "#epub-id-1"), ("property", "collection-type")] $ ("series" :: Text) ])
996+ [unode "meta" ! [("refines", "#epub-collection-1"), ("property", "collection-type")] $ ("series" :: Text) ])
997 (epubBelongsToCollection md)++
997 (epubBelongsToCollection md)++
998 maybe []
998 maybe []
999− (\groupPosition -> [unode "meta" ! [("refines", "#epub-id-1"), ("property", "group-position")] $ groupPosition ])
999+ (\groupPosition -> [unode "meta" ! [("refines", "#epub-collection-1"), ("property", "group-position")] $ groupPosition ])
1000 (epubGroupPosition md)
1000 (epubGroupPosition md)
1001 dcTag n s = unode ("dc:" <> n) s
1001 dcTag n s = unode ("dc:" <> n) s
1002 dcTag' n s = [dcTag n s]
1002 dcTag' n s = [dcTag n s]
src/Text/Pandoc/Writers/GridTable.hsnew file+157
@@ -0,0 +1,157 @@
1+{-# LANGUAGE FlexibleContexts #-}
2+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3+{-# LANGUAGE LambdaCase #-}
4+{-# LANGUAGE TupleSections #-}
5+
6+{- |
7+Module : Text.Pandoc.Writers.GridTable
8+Copyright : © 2020-2021 Albert Krewinkel
9+License : GNU GPL, version 2 or above
10+
11+Maintainer : Albert Krewinkel <albert@zeitkraut.de>
12+
13+Grid representation of pandoc tables.
14+-}
15+module Text.Pandoc.Writers.GridTable
16+ ( Table (..)
17+ , GridCell (..)
18+ , RowIndex (..)
19+ , ColIndex (..)
20+ , CellIndex
21+ , Part (..)
22+ , toTable
23+ , rowArray
24+ ) where
25+
26+import Control.Monad (forM_)
27+import Control.Monad.ST
28+import Data.Array
29+import Data.Array.MArray
30+import Data.Array.ST
31+import Data.Maybe (listToMaybe)
32+import Data.STRef
33+import Text.Pandoc.Definition hiding (Table)
34+import qualified Text.Pandoc.Builder as B
35+
36+-- | A grid cell contains either a real table cell, or is the
37+-- continuation of a column or row-spanning cell. In the latter case,
38+-- the index of the continued cell is provided.
39+data GridCell
40+ = ContentCell Attr Alignment RowSpan ColSpan [Block]
41+ | ContinuationCell CellIndex
42+ deriving (Show)
43+
44+-- | Row index in a table part.
45+newtype RowIndex = RowIndex Int deriving (Enum, Eq, Ix, Ord, Show)
46+-- | Column index in a table part.
47+newtype ColIndex = ColIndex Int deriving (Enum, Eq, Ix, Ord, Show)
48+
49+-- | Index to a cell in a table part.
50+type CellIndex = (RowIndex, ColIndex)
51+
52+-- | Cells are placed on a grid. Row attributes are stored in a separate
53+-- array.
54+data Part = Part
55+ { partAttr :: Attr
56+ , partCellArray :: Array (RowIndex,ColIndex) GridCell
57+ , partRowAttrs :: Array RowIndex Attr
58+ }
59+
60+data Table = Table
61+ { tableAttr :: Attr
62+ , tableCaption :: Caption
63+ , tableColSpecs :: Array ColIndex ColSpec
64+ , tableRowHeads :: RowHeadColumns
65+ , tableHead :: Part
66+ , tableBodies :: [Part]
67+ , tableFoot :: Part
68+ }
69+
70+toTable
71+ :: B.Attr
72+ -> B.Caption
73+ -> [B.ColSpec]
74+ -> B.TableHead
75+ -> [B.TableBody]
76+ -> B.TableFoot
77+ -> Table
78+toTable attr caption colSpecs thead tbodies tfoot =
79+ Table attr caption colSpecs' rowHeads thGrid tbGrids tfGrid
80+ where
81+ colSpecs' = listArray (ColIndex 1, ColIndex $ length colSpecs) colSpecs
82+ rowHeads = case listToMaybe tbodies of
83+ Nothing -> RowHeadColumns 0
84+ Just (TableBody _attr rowHeadCols _headerRows _rows) -> rowHeadCols
85+ thGrid = let (TableHead headAttr rows) = thead
86+ in rowsToPart headAttr rows
87+ tbGrids = map bodyToGrid tbodies
88+ tfGrid = let (TableFoot footAttr rows) = tfoot
89+ in rowsToPart footAttr rows
90+ bodyToGrid (TableBody bodyAttr _rowHeadCols headRows rows) =
91+ rowsToPart bodyAttr (headRows ++ rows)
92+
93+data BuilderCell
94+ = FilledCell GridCell
95+ | FreeCell
96+
97+fromBuilderCell :: BuilderCell -> GridCell
98+fromBuilderCell = \case
99+ FilledCell c -> c
100+ FreeCell -> error "Found an unassigned cell."
101+
102+rowsToPart :: Attr -> [B.Row] -> Part
103+rowsToPart attr = \case
104+ [] -> Part
105+ attr
106+ (listArray ((RowIndex 1, ColIndex 1), (RowIndex 0, ColIndex 0)) [])
107+ (listArray (RowIndex 1, RowIndex 0) [])
108+ rows@(Row _attr firstRow:_) ->
109+ let nrows = length rows
110+ ncols = sum $ map (\(Cell _ _ _ (ColSpan cs) _) -> cs) firstRow
111+ gbounds = ((RowIndex 1, ColIndex 1), (RowIndex nrows, ColIndex ncols))
112+ mutableGrid :: ST s (STArray s CellIndex GridCell)
113+ mutableGrid = do
114+ grid <- newArray gbounds FreeCell
115+ ridx <- newSTRef (RowIndex 1)
116+ forM_ rows $ \(Row _attr cells) -> do
117+ cidx <- newSTRef (ColIndex 1)
118+ forM_ cells $ \(Cell cellAttr align rs cs blks) -> do
119+ ridx' <- readSTRef ridx
120+ let nextFreeInRow colindex@(ColIndex c) = do
121+ readArray grid (ridx', colindex) >>= \case
122+ FreeCell -> pure colindex
123+ _ -> nextFreeInRow $ ColIndex (c + 1)
124+ cidx' <- readSTRef cidx >>= nextFreeInRow
125+ writeArray grid (ridx', cidx') . FilledCell $
126+ ContentCell cellAttr align rs cs blks
127+ forM_ (continuationIndices ridx' cidx' rs cs) $ \idx -> do
128+ writeArray grid idx . FilledCell $
129+ ContinuationCell (ridx', cidx')
130+ -- go to new column
131+ writeSTRef cidx cidx'
132+ -- go to next row
133+ modifySTRef ridx (incrRowIndex 1)
134+ -- Swap BuilderCells with normal GridCells.
135+ mapArray fromBuilderCell grid
136+ in Part
137+ { partCellArray = runSTArray mutableGrid
138+ , partRowAttrs = listArray (RowIndex 1, RowIndex nrows) $
139+ map (\(Row rowAttr _) -> rowAttr) rows
140+ , partAttr = attr
141+ }
142+
143+continuationIndices :: RowIndex -> ColIndex -> RowSpan -> ColSpan -> [CellIndex]
144+continuationIndices (RowIndex ridx) (ColIndex cidx) rowspan colspan =
145+ let (RowSpan rs) = rowspan
146+ (ColSpan cs) = colspan
147+ in [ (RowIndex r, ColIndex c) | r <- [ridx..(ridx + rs - 1)]
148+ , c <- [cidx..(cidx + cs - 1)]
149+ , (r, c) /= (ridx, cidx)]
150+
151+rowArray :: RowIndex -> Array CellIndex GridCell -> Array ColIndex GridCell
152+rowArray ridx grid =
153+ let ((_minRidx, minCidx), (_maxRidx, maxCidx)) = bounds grid
154+ in ixmap (minCidx, maxCidx) (ridx,) grid
155+
156+incrRowIndex :: RowSpan -> RowIndex -> RowIndex
157+incrRowIndex (RowSpan n) (RowIndex r) = RowIndex $ r + n
src/Text/Pandoc/Writers/HTML.hs+80−12
@@ -26,8 +26,13 @@ module Text.Pandoc.Writers.HTML (
26 writeSlideous,
26 writeSlideous,
27 writeDZSlides,
27 writeDZSlides,
28 writeRevealJs,
28 writeRevealJs,
29− tagWithAttributes
29+ tagWithAttributes,
30+ inlineToHtml,
31+ blockToHtml,
32+ WriterState(..),
33+ defaultWriterState
30 ) where
34 ) where
35+
31import Control.Monad.State.Strict
36import Control.Monad.State.Strict
32import Data.Char (ord)
37import Data.Char (ord)
33import Data.List (intercalate, intersperse, partition, delete, (\\), foldl')
38import Data.List (intercalate, intersperse, partition, delete, (\\), foldl')
@@ -344,6 +349,52 @@ pandocToHtml opts (Pandoc meta blocks) = do
344 PlainMath -> defField "displaymath-css" True
349 PlainMath -> defField "displaymath-css" True
345 WebTeX _ -> defField "displaymath-css" True
350 WebTeX _ -> defField "displaymath-css" True
346 _ -> id) .
351 _ -> id) .
352+ (if slideVariant == RevealJsSlides
353+ then -- set boolean options explicitly, since
354+ -- template can't distinguish False/undefined
355+ defField "controls" True .
356+ defField "controlsTutorial" True .
357+ defField "controlsLayout" ("bottom-right" :: Text) .
358+ defField "controlsBackArrows" ("faded" :: Text) .
359+ defField "progress" True .
360+ defField "slideNumber" False .
361+ defField "showSlideNumber" ("all" :: Text) .
362+ defField "hashOneBasedIndex" False .
363+ defField "hash" False .
364+ defField "respondToHashChanges" True .
365+ defField "history" False .
366+ defField "keyboard" True .
367+ defField "overview" True .
368+ defField "disableLayout" False .
369+ defField "center" True .
370+ defField "touch" True .
371+ defField "loop" False .
372+ defField "rtl" False .
373+ defField "navigationMode" ("default" :: Text) .
374+ defField "shuffle" False .
375+ defField "fragments" True .
376+ defField "fragmentInURL" True .
377+ defField "embedded" False .
378+ defField "help" True .
379+ defField "pause" True .
380+ defField "showNotes" False .
381+ defField "autoPlayMedia" ("null" :: Text) .
382+ defField "preloadIframes" ("null" :: Text) .
383+ defField "autoSlide" ("0" :: Text) .
384+ defField "autoSlideStoppable" True .
385+ defField "autoSlideMethod" ("null" :: Text) .
386+ defField "defaultTiming" ("null" :: Text) .
387+ defField "mouseWheel" False .
388+ defField "display" ("block" :: Text) .
389+ defField "hideInactiveCursor" True .
390+ defField "hideCursorTime" ("5000" :: Text) .
391+ defField "previewLinks" False .
392+ defField "transition" ("slide" :: Text) .
393+ defField "transitionSpeed" ("default" :: Text) .
394+ defField "backgroundTransition" ("fade" :: Text) .
395+ defField "viewDistance" ("3" :: Text) .
396+ defField "mobileViewDistance" ("2" :: Text)
397+ else id) .
347 defField "document-css" (isNothing mCss && slideVariant == NoSlides) .
398 defField "document-css" (isNothing mCss && slideVariant == NoSlides) .
348 defField "quotes" (stQuotes st) .
399 defField "quotes" (stQuotes st) .
349 -- for backwards compatibility we populate toc
400 -- for backwards compatibility we populate toc
@@ -613,17 +664,20 @@ dimensionsToAttrList attr = consolidateStyles $ go Width ++ go Height
613figure :: PandocMonad m
664figure :: PandocMonad m
614 => WriterOptions -> Attr -> [Inline] -> (Text, Text)
665 => WriterOptions -> Attr -> [Inline] -> (Text, Text)
615 -> StateT WriterState m Html
666 -> StateT WriterState m Html
616−figure opts attr txt (s,tit) = do
667+figure opts attr@(_, _, attrList) txt (s,tit) = do
617 html5 <- gets stHtml5
668 html5 <- gets stHtml5
618 -- Screen-readers will normally read the @alt@ text and the figure; we
669 -- Screen-readers will normally read the @alt@ text and the figure; we
619 -- want to avoid them reading the same text twice. With HTML5 we can
670 -- want to avoid them reading the same text twice. With HTML5 we can
620 -- use aria-hidden for the caption; with HTML4, we use an empty
671 -- use aria-hidden for the caption; with HTML4, we use an empty
621 -- alt-text instead.
672 -- alt-text instead.
673+ -- When the alt text differs from the caption both should be read.
622 let alt = if html5 then txt else [Str ""]
674 let alt = if html5 then txt else [Str ""]
623 let tocapt = if html5
675 let tocapt = if html5
624− then H5.figcaption !
676+ then (H5.figcaption !) $
677+ if isJust (lookup "alt" attrList)
678+ then mempty
625− H5.customAttribute (textTag "aria-hidden")
679+ else H5.customAttribute (textTag "aria-hidden")
626− (toValue @Text "true")
680+ (toValue @Text "true")
627 else H.p ! A.class_ "caption"
681 else H.p ! A.class_ "caption"
628 img <- inlineToHtml opts (Image attr alt (s,tit))
682 img <- inlineToHtml opts (Image attr alt (s,tit))
629 capt <- if null txt
683 capt <- if null txt
@@ -770,9 +824,10 @@ blockToHtml opts (Div attr@(ident, classes, kvs') bs) = do
770 lookup "entry-spacing" kvs' >>=
824 lookup "entry-spacing" kvs' >>=
771 safeRead }
825 safeRead }
772 let isCslBibEntry = "csl-entry" `elem` classes
826 let isCslBibEntry = "csl-entry" `elem` classes
773− let kvs = [(k,v) | (k,v) <- kvs', k /= "width"] ++
827+ let kvs = [(k,v) | (k,v) <- kvs'
828+ , k /= "width" || "column" `notElem` classes] ++
774− [("style", "width:" <> w <> ";") | "column" `elem` classes,
829+ [("style", "width:" <> w <> ";") | "column" `elem` classes
775− ("width", w) <- kvs'] ++
830+ , ("width", w) <- kvs'] ++
776 [("role", "doc-bibliography") | isCslBibBody && html5] ++
831 [("role", "doc-bibliography") | isCslBibBody && html5] ++
777 [("role", "doc-biblioentry") | isCslBibEntry && html5]
832 [("role", "doc-biblioentry") | isCslBibEntry && html5]
778 let speakerNotes = "notes" `elem` classes
833 let speakerNotes = "notes" `elem` classes
@@ -882,7 +937,7 @@ blockToHtml opts (BlockQuote blocks) = do
882 else do
937 else do
883 contents <- blockListToHtml opts blocks
938 contents <- blockListToHtml opts blocks
884 return $ H.blockquote $ nl opts >> contents >> nl opts
939 return $ H.blockquote $ nl opts >> contents >> nl opts
885−blockToHtml opts (Header level attr@(_,classes,kvs) lst) = do
940+blockToHtml opts (Header level (ident,classes,kvs) lst) = do
886 contents <- inlineListToHtml opts lst
941 contents <- inlineListToHtml opts lst
887 let secnum = fromMaybe mempty $ lookup "number" kvs
942 let secnum = fromMaybe mempty $ lookup "number" kvs
888 let contents' = if writerNumberSections opts && not (T.null secnum)
943 let contents' = if writerNumberSections opts && not (T.null secnum)
@@ -890,7 +945,13 @@ blockToHtml opts (Header level attr@(_,classes,kvs) lst) = do
890 then (H.span ! A.class_ "header-section-number"
945 then (H.span ! A.class_ "header-section-number"
891 $ toHtml secnum) >> strToHtml " " >> contents
946 $ toHtml secnum) >> strToHtml " " >> contents
892 else contents
947 else contents
948+ html5 <- gets stHtml5
949+ let kvs' = if html5
950+ then kvs
951+ else [ (k, v) | (k, v) <- kvs
952+ , k `elem` (["lang", "dir", "title", "style"
953+ , "align"] ++ intrinsicEventsHTML4)]
893− addAttrs opts attr
954+ addAttrs opts (ident,classes,kvs')
894 $ case level of
955 $ case level of
895 1 -> H.h1 contents'
956 1 -> H.h1 contents'
896 2 -> H.h2 contents'
957 2 -> H.h2 contents'
@@ -1380,7 +1441,7 @@ inlineToHtml opts inline = do
1380 return $ if T.null tit
1441 return $ if T.null tit
1381 then link'
1442 then link'
1382 else link' ! A.title (toValue tit)
1443 else link' ! A.title (toValue tit)
1383− (Image attr txt (s,tit)) -> do
1444+ (Image attr@(_, _, attrList) txt (s, tit)) -> do
1384 let alternate = stringify txt
1445 let alternate = stringify txt
1385 slideVariant <- gets stSlideVariant
1446 slideVariant <- gets stSlideVariant
1386 let isReveal = slideVariant == RevealJsSlides
1447 let isReveal = slideVariant == RevealJsSlides
@@ -1393,7 +1454,8 @@ inlineToHtml opts inline = do
1393 [A.title $ toValue tit | not (T.null tit)] ++
1454 [A.title $ toValue tit | not (T.null tit)] ++
1394 attrs
1455 attrs
1395 imageTag = (if html5 then H5.img else H.img
1456 imageTag = (if html5 then H5.img else H.img
1396− , [A.alt $ toValue alternate | not (null txt)] )
1457+ , [A.alt $ toValue alternate | not (null txt) &&
1458+ isNothing (lookup "alt" attrList)] )
1397 mediaTag tg fallbackTxt =
1459 mediaTag tg fallbackTxt =
1398 let linkTxt = if null txt
1460 let linkTxt = if null txt
1399 then fallbackTxt
1461 then fallbackTxt
@@ -1526,6 +1588,12 @@ allowsMathEnvironments MathML = True
1526allowsMathEnvironments (WebTeX _) = True
1588allowsMathEnvironments (WebTeX _) = True
1527allowsMathEnvironments _ = False
1589allowsMathEnvironments _ = False
1528
1590
1591+-- | List of intrinsic event attributes allowed on all elements in HTML4.
1592+intrinsicEventsHTML4 :: [Text]
1593+intrinsicEventsHTML4 =
1594+ [ "onclick", "ondblclick", "onmousedown", "onmouseup", "onmouseover"
1595+ , "onmouseout", "onmouseout", "onkeypress", "onkeydown", "onkeyup"]
1596+
1529isRawHtml :: PandocMonad m => Format -> StateT WriterState m Bool
1597isRawHtml :: PandocMonad m => Format -> StateT WriterState m Bool
1530isRawHtml f = do
1598isRawHtml f = do
1531 html5 <- gets stHtml5
1599 html5 <- gets stHtml5
src/Text/Pandoc/Writers/Haddock.hs+13−2
@@ -15,6 +15,7 @@ Haddock: <http://www.haskell.org/haddock/doc/html/>
15-}
15-}
16module Text.Pandoc.Writers.Haddock (writeHaddock) where
16module Text.Pandoc.Writers.Haddock (writeHaddock) where
17import Control.Monad.State.Strict
17import Control.Monad.State.Strict
18+import Data.Char (isAlphaNum)
18import Data.Default
19import Data.Default
19import Data.Text (Text)
20import Data.Text (Text)
20import qualified Data.Text as T
21import qualified Data.Text as T
@@ -71,8 +72,18 @@ notesToHaddock opts notes =
71
72
72-- | Escape special characters for Haddock.
73-- | Escape special characters for Haddock.
73escapeString :: Text -> Text
74escapeString :: Text -> Text
74−escapeString = escapeStringUsing haddockEscapes
75+escapeString t
75− where haddockEscapes = backslashEscapes "\\/'`\"@<"
76+ | T.all isAlphaNum t = t
77+ | otherwise = T.concatMap escChar t
78+ where
79+ escChar '\\' = "\\\\"
80+ escChar '/' = "\\/"
81+ escChar '\'' = "\\'"
82+ escChar '`' = "\\`"
83+ escChar '"' = "\\\""
84+ escChar '@' = "\\@"
85+ escChar '<' = "\\<"
86+ escChar c = T.singleton c
76
87
77-- | Convert Pandoc block element to haddock.
88-- | Convert Pandoc block element to haddock.
78blockToHaddock :: PandocMonad m
89blockToHaddock :: PandocMonad m
src/Text/Pandoc/Writers/JATS.hs+67−44
@@ -1,6 +1,7 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE ScopedTypeVariables #-}
3{-# LANGUAGE ScopedTypeVariables #-}
2−{-# LANGUAGE OverloadedStrings #-}
3−{-# LANGUAGE ViewPatterns #-}
4+{-# LANGUAGE ViewPatterns #-}
4{- |
5{- |
5 Module : Text.Pandoc.Writers.JATS
6 Module : Text.Pandoc.Writers.JATS
6 Copyright : 2017-2021 John MacFarlane
7 Copyright : 2017-2021 John MacFarlane
@@ -20,12 +21,13 @@ module Text.Pandoc.Writers.JATS
20 , writeJatsPublishing
21 , writeJatsPublishing
21 , writeJatsArticleAuthoring
22 , writeJatsArticleAuthoring
22 ) where
23 ) where
24+import Control.Applicative ((<|>))
23import Control.Monad.Reader
25import Control.Monad.Reader
24import Control.Monad.State
26import Control.Monad.State
25import Data.Generics (everywhere, mkT)
27import Data.Generics (everywhere, mkT)
26import Data.List (partition)
28import Data.List (partition)
27import qualified Data.Map as M
29import qualified Data.Map as M
28−import Data.Maybe (fromMaybe)
30+import Data.Maybe (fromMaybe, listToMaybe)
29import Data.Time (toGregorian, Day, parseTimeM, defaultTimeLocale, formatTime)
31import Data.Time (toGregorian, Day, parseTimeM, defaultTimeLocale, formatTime)
30import qualified Data.Text as T
32import qualified Data.Text as T
31import Data.Text (Text)
33import Data.Text (Text)
@@ -80,7 +82,7 @@ writeJats tagSet opts d = do
80 let environment = JATSEnv
82 let environment = JATSEnv
81 { jatsTagSet = tagSet
83 { jatsTagSet = tagSet
82 , jatsInlinesWriter = inlinesToJATS
84 , jatsInlinesWriter = inlinesToJATS
83− , jatsBlockWriter = blockToJATS
85+ , jatsBlockWriter = wrappedBlocksToJATS
84 , jatsReferences = refs
86 , jatsReferences = refs
85 }
87 }
86 let initialState = JATSState { jatsNotes = [] }
88 let initialState = JATSState { jatsNotes = [] }
@@ -162,11 +164,9 @@ wrappedBlocksToJATS needsWrap opts =
162 wrappedBlockToJATS b = do
164 wrappedBlockToJATS b = do
163 inner <- blockToJATS opts b
165 inner <- blockToJATS opts b
164 return $
166 return $
165− if needsWrap b || isBlockQuote b -- see #7041
167+ if needsWrap b
166 then inTags True "p" [("specific-use","wrapper")] inner
168 then inTags True "p" [("specific-use","wrapper")] inner
167 else inner
169 else inner
168− isBlockQuote (BlockQuote _) = True
169− isBlockQuote _ = False
170
170
171-- | Auxiliary function to convert Plain block to Para.
171-- | Auxiliary function to convert Plain block to Para.
172plainToPara :: Block -> Block
172plainToPara :: Block -> Block
@@ -225,33 +225,36 @@ imageMimeType src kvs =
225 (T.drop 1 . T.dropWhile (/='/') <$> mbMT)
225 (T.drop 1 . T.dropWhile (/='/') <$> mbMT)
226 in (maintype, subtype)
226 in (maintype, subtype)
227
227
228−languageFor :: [Text] -> Text
228+languageFor :: WriterOptions -> [Text] -> Text
229−languageFor classes =
229+languageFor opts classes =
230 case langs of
230 case langs of
231 (l:_) -> escapeStringForXML l
231 (l:_) -> escapeStringForXML l
232 [] -> ""
232 [] -> ""
233+ where
234+ syntaxMap = writerSyntaxMap opts
233− where isLang l = T.toLower l `elem` map T.toLower languages
235+ isLang l = T.toLower l `elem` map T.toLower (languages syntaxMap)
234 langsFrom s = if isLang s
236 langsFrom s = if isLang s
235 then [s]
237 then [s]
236− else languagesByExtension . T.toLower $ s
238+ else (languagesByExtension syntaxMap) . T.toLower $ s
237 langs = concatMap langsFrom classes
239 langs = concatMap langsFrom classes
238
240
239−codeAttr :: Attr -> (Text, [(Text, Text)])
241+codeAttr :: WriterOptions -> Attr -> (Text, [(Text, Text)])
240−codeAttr (ident,classes,kvs) = (lang, attr)
242+codeAttr opts (ident,classes,kvs) = (lang, attr)
241 where
243 where
242− attr = [("id",ident) | not (T.null ident)] ++
244+ attr = [("id", escapeNCName ident) | not (T.null ident)] ++
243 [("language",lang) | not (T.null lang)] ++
245 [("language",lang) | not (T.null lang)] ++
244 [(k,v) | (k,v) <- kvs, k `elem` ["code-type",
246 [(k,v) | (k,v) <- kvs, k `elem` ["code-type",
245 "code-version", "executable",
247 "code-version", "executable",
246 "language-version", "orientation",
248 "language-version", "orientation",
247 "platforms", "position", "specific-use"]]
249 "platforms", "position", "specific-use"]]
248− lang = languageFor classes
250+ lang = languageFor opts classes
249
251
250-- | Convert a Pandoc block element to JATS.
252-- | Convert a Pandoc block element to JATS.
251blockToJATS :: PandocMonad m => WriterOptions -> Block -> JATS m (Doc Text)
253blockToJATS :: PandocMonad m => WriterOptions -> Block -> JATS m (Doc Text)
252blockToJATS _ Null = return empty
254blockToJATS _ Null = return empty
253blockToJATS opts (Div (id',"section":_,kvs) (Header _lvl _ ils : xs)) = do
255blockToJATS opts (Div (id',"section":_,kvs) (Header _lvl _ ils : xs)) = do
254− let idAttr = [("id", writerIdentifierPrefix opts <> id') | not (T.null id')]
256+ let idAttr = [ ("id", writerIdentifierPrefix opts <> escapeNCName id')
257+ | not (T.null id')]
255 let otherAttrs = ["sec-type", "specific-use"]
258 let otherAttrs = ["sec-type", "specific-use"]
256 let attribs = idAttr ++ [(k,v) | (k,v) <- kvs, k `elem` otherAttrs]
259 let attribs = idAttr ++ [(k,v) | (k,v) <- kvs, k `elem` otherAttrs]
257 title' <- inlinesToJATS opts ils
260 title' <- inlinesToJATS opts ils
@@ -260,7 +263,7 @@ blockToJATS opts (Div (id',"section":_,kvs) (Header _lvl _ ils : xs)) = do
260 inTagsSimple "title" title' $$ contents
263 inTagsSimple "title" title' $$ contents
261-- Bibliography reference:
264-- Bibliography reference:
262blockToJATS opts (Div (ident,_,_) [Para lst]) | "ref-" `T.isPrefixOf` ident =
265blockToJATS opts (Div (ident,_,_) [Para lst]) | "ref-" `T.isPrefixOf` ident =
263− inTags True "ref" [("id", ident)] .
266+ inTags True "ref" [("id", escapeNCName ident)] .
264 inTagsSimple "mixed-citation" <$>
267 inTagsSimple "mixed-citation" <$>
265 inlinesToJATS opts lst
268 inlinesToJATS opts lst
266blockToJATS opts (Div ("refs",_,_) xs) = do
269blockToJATS opts (Div ("refs",_,_) xs) = do
@@ -271,14 +274,14 @@ blockToJATS opts (Div ("refs",_,_) xs) = do
271 return $ inTagsIndented "ref-list" contents
274 return $ inTagsIndented "ref-list" contents
272blockToJATS opts (Div (ident,[cls],kvs) bs) | cls `elem` ["fig", "caption", "table-wrap"] = do
275blockToJATS opts (Div (ident,[cls],kvs) bs) | cls `elem` ["fig", "caption", "table-wrap"] = do
273 contents <- blocksToJATS opts bs
276 contents <- blocksToJATS opts bs
274− let attr = [("id", ident) | not (T.null ident)] ++
277+ let attr = [("id", escapeNCName ident) | not (T.null ident)] ++
275 [("xml:lang",l) | ("lang",l) <- kvs] ++
278 [("xml:lang",l) | ("lang",l) <- kvs] ++
276 [(k,v) | (k,v) <- kvs, k `elem` ["specific-use",
279 [(k,v) | (k,v) <- kvs, k `elem` ["specific-use",
277 "content-type", "orientation", "position"]]
280 "content-type", "orientation", "position"]]
278 return $ inTags True cls attr contents
281 return $ inTags True cls attr contents
279blockToJATS opts (Div (ident,_,kvs) bs) = do
282blockToJATS opts (Div (ident,_,kvs) bs) = do
280 contents <- blocksToJATS opts bs
283 contents <- blocksToJATS opts bs
281− let attr = [("id", ident) | not (T.null ident)] ++
284+ let attr = [("id", escapeNCName ident) | not (T.null ident)] ++
282 [("xml:lang",l) | ("lang",l) <- kvs] ++
285 [("xml:lang",l) | ("lang",l) <- kvs] ++
283 [(k,v) | (k,v) <- kvs, k `elem` ["specific-use",
286 [(k,v) | (k,v) <- kvs, k `elem` ["specific-use",
284 "content-type", "orientation", "position"]]
287 "content-type", "orientation", "position"]]
@@ -296,7 +299,7 @@ blockToJATS opts (Para [Image (ident,_,kvs) txt
296 let capt = if null txt
299 let capt = if null txt
297 then empty
300 then empty
298 else inTagsSimple "caption" $ inTagsSimple "p" alt
301 else inTagsSimple "caption" $ inTagsSimple "p" alt
299− let attr = [("id", ident) | not (T.null ident)] ++
302+ let attr = [("id", escapeNCName ident) | not (T.null ident)] ++
300 [(k,v) | (k,v) <- kvs, k `elem` ["fig-type", "orientation",
303 [(k,v) | (k,v) <- kvs, k `elem` ["fig-type", "orientation",
301 "position", "specific-use"]]
304 "position", "specific-use"]]
302 let graphicattr = [("mimetype",maintype),
305 let graphicattr = [("mimetype",maintype),
@@ -307,7 +310,7 @@ blockToJATS opts (Para [Image (ident,_,kvs) txt
307 capt $$ selfClosingTag "graphic" graphicattr
310 capt $$ selfClosingTag "graphic" graphicattr
308blockToJATS _ (Para [Image (ident,_,kvs) _ (src, tit)]) = do
311blockToJATS _ (Para [Image (ident,_,kvs) _ (src, tit)]) = do
309 let (maintype, subtype) = imageMimeType src kvs
312 let (maintype, subtype) = imageMimeType src kvs
310− let attr = [("id", ident) | not (T.null ident)] ++
313+ let attr = [("id", escapeNCName ident) | not (T.null ident)] ++
311 [("mimetype", maintype),
314 [("mimetype", maintype),
312 ("mime-subtype", subtype),
315 ("mime-subtype", subtype),
313 ("xlink:href", src)] ++
316 ("xlink:href", src)] ++
@@ -323,13 +326,16 @@ blockToJATS opts (LineBlock lns) =
323 blockToJATS opts $ linesToPara lns
326 blockToJATS opts $ linesToPara lns
324blockToJATS opts (BlockQuote blocks) = do
327blockToJATS opts (BlockQuote blocks) = do
325 tagSet <- asks jatsTagSet
328 tagSet <- asks jatsTagSet
326− let blocksToJats' = if tagSet == TagSetArticleAuthoring
329+ let needsWrap = if tagSet == TagSetArticleAuthoring
327− then wrappedBlocksToJATS (not . isPara)
330+ then not . isPara
328− else blocksToJATS
331+ else \case
332+ Header{} -> True
333+ HorizontalRule -> True
334+ _ -> False
329− inTagsIndented "disp-quote" <$> blocksToJats' opts blocks
335+ inTagsIndented "disp-quote" <$> wrappedBlocksToJATS needsWrap opts blocks
330−blockToJATS _ (CodeBlock a str) = return $
336+blockToJATS opts (CodeBlock a str) = return $
331 inTags False tag attr (flush (text (T.unpack $ escapeStringForXML str)))
337 inTags False tag attr (flush (text (T.unpack $ escapeStringForXML str)))
332− where (lang, attr) = codeAttr a
338+ where (lang, attr) = codeAttr opts a
333 tag = if T.null lang then "preformat" else "code"
339 tag = if T.null lang then "preformat" else "code"
334blockToJATS _ (BulletList []) = return empty
340blockToJATS _ (BulletList []) = return empty
335blockToJATS opts (BulletList lst) =
341blockToJATS opts (BulletList lst) =
@@ -409,9 +415,9 @@ inlineToJATS opts (Quoted SingleQuote lst) = do
409inlineToJATS opts (Quoted DoubleQuote lst) = do
415inlineToJATS opts (Quoted DoubleQuote lst) = do
410 contents <- inlinesToJATS opts lst
416 contents <- inlinesToJATS opts lst
411 return $ char '“' <> contents <> char '”'
417 return $ char '“' <> contents <> char '”'
412−inlineToJATS _ (Code a str) =
418+inlineToJATS opts (Code a str) =
413 return $ inTags False tag attr $ literal (escapeStringForXML str)
419 return $ inTags False tag attr $ literal (escapeStringForXML str)
414− where (lang, attr) = codeAttr a
420+ where (lang, attr) = codeAttr opts a
415 tag = if T.null lang then "monospace" else "code"
421 tag = if T.null lang then "monospace" else "code"
416inlineToJATS _ il@(RawInline f x)
422inlineToJATS _ il@(RawInline f x)
417 | f == "jats" = return $ literal x
423 | f == "jats" = return $ literal x
@@ -434,7 +440,8 @@ inlineToJATS opts (Note contents) = do
434 let notenum = case notes of
440 let notenum = case notes of
435 (n, _):_ -> n + 1
441 (n, _):_ -> n + 1
436 [] -> 1
442 [] -> 1
437− thenote <- inTags True "fn" [("id","fn" <> tshow notenum)]
443+ thenote <- inTags True "fn" [("id", "fn" <> tshow notenum)]
444+ . (inTagsSimple "label" (literal $ tshow notenum) <>)
438 <$> wrappedBlocksToJATS (not . isPara) opts
445 <$> wrappedBlocksToJATS (not . isPara) opts
439 (walk demoteHeaderAndRefs contents)
446 (walk demoteHeaderAndRefs contents)
440 modify $ \st -> st{ jatsNotes = (notenum, thenote) : notes }
447 modify $ \st -> st{ jatsNotes = (notenum, thenote) : notes }
@@ -442,18 +449,34 @@ inlineToJATS opts (Note contents) = do
442 ("rid", "fn" <> tshow notenum)]
449 ("rid", "fn" <> tshow notenum)]
443 $ text (show notenum)
450 $ text (show notenum)
444inlineToJATS opts (Cite _ lst) =
451inlineToJATS opts (Cite _ lst) =
445− -- TODO revisit this after examining the jats.csl pipeline
446 inlinesToJATS opts lst
452 inlinesToJATS opts lst
447−inlineToJATS opts (Span ("",_,[]) ils) = inlinesToJATS opts ils
453+inlineToJATS opts (Span (ident,classes,kvs) ils) = do
448−inlineToJATS opts (Span (ident,_,kvs) ils) = do
449 contents <- inlinesToJATS opts ils
454 contents <- inlinesToJATS opts ils
450− let attr = [("id",ident) | not (T.null ident)] ++
455+ let commonAttr = [("id", escapeNCName ident) | not (T.null ident)] ++
451− [("xml:lang",l) | ("lang",l) <- kvs] ++
456+ [("xml:lang",l) | ("lang",l) <- kvs] ++
452− [(k,v) | (k,v) <- kvs
453− , k `elem` ["content-type", "rationale",
454− "rid", "specific-use"]]
457+ [(k,v) | (k,v) <- kvs, k `elem` ["alt", "specific-use"]]
455− return $ selfClosingTag "milestone-start" attr <> contents <>
458+ -- A named-content element is a good fit for spans, but requires a
456− selfClosingTag "milestone-end" []
459+ -- content-type attribute to be present. We use either the explicit
460+ -- attribute or the first class as content type. If neither is
461+ -- available, then we fall back to using a @styled-content@ element.
462+ let (tag, specificAttr) =
463+ case lookup "content-type" kvs <|> listToMaybe classes of
464+ Just ct -> ( "named-content"
465+ , ("content-type", ct) :
466+ [(k, v) | (k, v) <- kvs
467+ , k `elem` ["rid", "vocab", "vocab-identifier",
468+ "vocab-term", "vocab-term-identifier"]])
469+ -- Fall back to styled-content
470+ Nothing -> ("styled-content"
471+ , [(k, v) | (k,v) <- kvs
472+ , k `elem` ["style", "style-type", "style-detail",
473+ "toggle"]])
474+ let attr = commonAttr ++ specificAttr
475+ -- unwrap if wrapping element would have no attributes
476+ return $
477+ if null attr
478+ then contents
479+ else inTags False tag attr contents
457inlineToJATS _ (Math t str) = do
480inlineToJATS _ (Math t str) = do
458 let addPref (Xml.Attr q v)
481 let addPref (Xml.Attr q v)
459 | Xml.qName q == "xmlns" = Xml.Attr q{ Xml.qName = "xmlns:mml" } v
482 | Xml.qName q == "xmlns" = Xml.Attr q{ Xml.qName = "xmlns:mml" } v
@@ -488,9 +511,9 @@ inlineToJATS _ (Link _attr [Str t] (T.stripPrefix "mailto:" -> Just email, _))
488 return $ inTagsSimple "email" $ literal (escapeStringForXML email)
511 return $ inTagsSimple "email" $ literal (escapeStringForXML email)
489inlineToJATS opts (Link (ident,_,kvs) txt (T.uncons -> Just ('#', src), _)) = do
512inlineToJATS opts (Link (ident,_,kvs) txt (T.uncons -> Just ('#', src), _)) = do
490 let attr = mconcat
513 let attr = mconcat
491− [ [("id", ident) | not (T.null ident)]
514+ [ [("id", escapeNCName ident) | not (T.null ident)]
492 , [("alt", stringify txt) | not (null txt)]
515 , [("alt", stringify txt) | not (null txt)]
493− , [("rid", src)]
516+ , [("rid", escapeNCName src)]
494 , [(k,v) | (k,v) <- kvs, k `elem` ["ref-type", "specific-use"]]
517 , [(k,v) | (k,v) <- kvs, k `elem` ["ref-type", "specific-use"]]
495 , [("ref-type", "bibr") | "ref-" `T.isPrefixOf` src]
518 , [("ref-type", "bibr") | "ref-" `T.isPrefixOf` src]
496 ]
519 ]
@@ -500,7 +523,7 @@ inlineToJATS opts (Link (ident,_,kvs) txt (T.uncons -> Just ('#', src), _)) = do
500 contents <- inlinesToJATS opts txt
523 contents <- inlinesToJATS opts txt
501 return $ inTags False "xref" attr contents
524 return $ inTags False "xref" attr contents
502inlineToJATS opts (Link (ident,_,kvs) txt (src, tit)) = do
525inlineToJATS opts (Link (ident,_,kvs) txt (src, tit)) = do
503− let attr = [("id", ident) | not (T.null ident)] ++
526+ let attr = [("id", escapeNCName ident) | not (T.null ident)] ++
504 [("ext-link-type", "uri"),
527 [("ext-link-type", "uri"),
505 ("xlink:href", src)] ++
528 ("xlink:href", src)] ++
506 [("xlink:title", tit) | not (T.null tit)] ++
529 [("xlink:title", tit) | not (T.null tit)] ++
@@ -518,7 +541,7 @@ inlineToJATS _ (Image (ident,_,kvs) _ (src, tit)) = do
518 let subtype = fromMaybe "" $
541 let subtype = fromMaybe "" $
519 lookup "mime-subtype" kvs `mplus`
542 lookup "mime-subtype" kvs `mplus`
520 (T.drop 1 . T.dropWhile (/='/') <$> mbMT)
543 (T.drop 1 . T.dropWhile (/='/') <$> mbMT)
521− let attr = [("id", ident) | not (T.null ident)] ++
544+ let attr = [("id", escapeNCName ident) | not (T.null ident)] ++
522 [("mimetype", maintype),
545 [("mimetype", maintype),
523 ("mime-subtype", subtype),
546 ("mime-subtype", subtype),
524 ("xlink:href", src)] ++
547 ("xlink:href", src)] ++
src/Text/Pandoc/Writers/JATS/References.hs+3−2
@@ -29,7 +29,7 @@ import Text.Pandoc.Builder (Inlines)
29import Text.Pandoc.Options (WriterOptions)
29import Text.Pandoc.Options (WriterOptions)
30import Text.Pandoc.Shared (tshow)
30import Text.Pandoc.Shared (tshow)
31import Text.Pandoc.Writers.JATS.Types
31import Text.Pandoc.Writers.JATS.Types
32−import Text.Pandoc.XML (escapeStringForXML, inTags)
32+import Text.Pandoc.XML (escapeNCName, escapeStringForXML, inTags)
33import qualified Data.Text as T
33import qualified Data.Text as T
34
34
35referencesToJATS :: PandocMonad m
35referencesToJATS :: PandocMonad m
@@ -46,7 +46,8 @@ referenceToJATS :: PandocMonad m
46referenceToJATS _opts ref = do
46referenceToJATS _opts ref = do
47 let refType = referenceType ref
47 let refType = referenceType ref
48 let pubType = [("publication-type", refType) | not (T.null refType)]
48 let pubType = [("publication-type", refType) | not (T.null refType)]
49+ let ident = escapeNCName $ "ref-" <> unItemId (referenceId ref)
49− let wrap = inTags True "ref" [("id", "ref-" <> unItemId (referenceId ref))]
50+ let wrap = inTags True "ref" [("id", ident)]
50 . inTags True "element-citation" pubType
51 . inTags True "element-citation" pubType
51 return . wrap . vcat $
52 return . wrap . vcat $
52 [ authors
53 [ authors
src/Text/Pandoc/Writers/JATS/Table.hs+25−5
@@ -24,7 +24,7 @@ import Text.Pandoc.Definition
24import Text.Pandoc.Options (WriterOptions)
24import Text.Pandoc.Options (WriterOptions)
25import Text.Pandoc.Shared (tshow)
25import Text.Pandoc.Shared (tshow)
26import Text.Pandoc.Writers.JATS.Types
26import Text.Pandoc.Writers.JATS.Types
27−import Text.Pandoc.XML (inTags, inTagsIndented, selfClosingTag)
27+import Text.Pandoc.XML (escapeNCName, inTags, inTagsIndented, selfClosingTag)
28import qualified Data.Text as T
28import qualified Data.Text as T
29import qualified Text.Pandoc.Writers.AnnotatedTable as Ann
29import qualified Text.Pandoc.Writers.AnnotatedTable as Ann
30
30
@@ -34,13 +34,19 @@ tableToJATS :: PandocMonad m
34 -> JATS m (Doc Text)
34 -> JATS m (Doc Text)
35tableToJATS opts (Ann.Table attr caption colspecs thead tbodies tfoot) = do
35tableToJATS opts (Ann.Table attr caption colspecs thead tbodies tfoot) = do
36 let (Caption _maybeShortCaption captionBlocks) = caption
36 let (Caption _maybeShortCaption captionBlocks) = caption
37+ -- Only paragraphs are allowed in captions, all other blocks must be
38+ -- wrapped in @<p>@ elements.
39+ let needsWrapping = \case
40+ Plain{} -> False
41+ Para{} -> False
42+ _ -> True
37 tbl <- captionlessTable opts attr colspecs thead tbodies tfoot
43 tbl <- captionlessTable opts attr colspecs thead tbodies tfoot
38 captionDoc <- if null captionBlocks
44 captionDoc <- if null captionBlocks
39 then return empty
45 then return empty
40 else do
46 else do
41 blockToJATS <- asks jatsBlockWriter
47 blockToJATS <- asks jatsBlockWriter
42− inTagsIndented "caption" . vcat <$>
48+ inTagsIndented "caption" <$>
43− mapM (blockToJATS opts) captionBlocks
49+ blockToJATS needsWrapping opts captionBlocks
44 return $ inTags True "table-wrap" [] $ captionDoc $$ tbl
50 return $ inTags True "table-wrap" [] $ captionDoc $$ tbl
45
51
46captionlessTable :: PandocMonad m
52captionlessTable :: PandocMonad m
@@ -216,7 +222,7 @@ cellToJats opts celltype (Ann.Cell (colspec :| _) _colNum cell) =
216
222
217toAttribs :: Attr -> [Text] -> [(Text, Text)]
223toAttribs :: Attr -> [Text] -> [(Text, Text)]
218toAttribs (ident, _classes, kvs) knownAttribs =
224toAttribs (ident, _classes, kvs) knownAttribs =
219− (if T.null ident then id else (("id", ident) :)) $
225+ (if T.null ident then id else (("id", escapeNCName ident) :)) $
220 filter ((`elem` knownAttribs) . fst) kvs
226 filter ((`elem` knownAttribs) . fst) kvs
221
227
222tableCellToJats :: PandocMonad m
228tableCellToJats :: PandocMonad m
@@ -230,7 +236,7 @@ tableCellToJats opts ctype colAlign (Cell attr align rowspan colspan item) = do
230 inlinesToJats <- asks jatsInlinesWriter
236 inlinesToJats <- asks jatsInlinesWriter
231 let cellContents = \case
237 let cellContents = \case
232 [Plain inlines] -> inlinesToJats opts inlines
238 [Plain inlines] -> inlinesToJats opts inlines
233− blocks -> vcat <$> mapM (blockToJats opts) blocks
239+ blocks -> blockToJats needsWrapInCell opts blocks
234 let tag' = case ctype of
240 let tag' = case ctype of
235 BodyCell -> "td"
241 BodyCell -> "td"
236 HeaderCell -> "th"
242 HeaderCell -> "th"
@@ -246,3 +252,17 @@ tableCellToJats opts ctype colAlign (Cell attr align rowspan colspan item) = do
246 . maybeCons (colspanAttrib colspan)
252 . maybeCons (colspanAttrib colspan)
247 $ toAttribs attr validAttribs
253 $ toAttribs attr validAttribs
248 inTags False tag' attribs <$> cellContents item
254 inTags False tag' attribs <$> cellContents item
255+
256+-- | Whether the JATS produced from this block should be wrapped in a
257+-- @<p>@ element when put directly below a @<td>@ element.
258+needsWrapInCell :: Block -> Bool
259+needsWrapInCell = \case
260+ Plain{} -> False -- should be unwrapped anyway
261+ Para{} -> False
262+ BulletList{} -> False
263+ OrderedList{} -> False
264+ DefinitionList{} -> False
265+ HorizontalRule -> False
266+ CodeBlock{} -> False
267+ RawBlock{} -> False -- responsibility of the user
268+ _ -> True
src/Text/Pandoc/Writers/JATS/Types.hs+12−3
@@ -37,11 +37,20 @@ newtype JATSState = JATSState
37 { jatsNotes :: [(Int, Doc Text)]
37 { jatsNotes :: [(Int, Doc Text)]
38 }
38 }
39
39
40+-- | Environment containing all information relevant for rendering.
40data JATSEnv m = JATSEnv
41data JATSEnv m = JATSEnv
41− { jatsTagSet :: JATSTagSet
42+ { jatsTagSet :: JATSTagSet -- ^ The tag set that's being ouput
43+
44+ , jatsBlockWriter :: (Block -> Bool)
45+ -> WriterOptions -> [Block] -> JATS m (Doc Text)
46+ -- ^ Converts a block list to JATS, wrapping top-level blocks into a
47+ -- @<p>@ element if the property evaluates to @True@.
48+ -- See #7227.
49+
42 , jatsInlinesWriter :: WriterOptions -> [Inline] -> JATS m (Doc Text)
50 , jatsInlinesWriter :: WriterOptions -> [Inline] -> JATS m (Doc Text)
43− , jatsBlockWriter :: WriterOptions -> Block -> JATS m (Doc Text)
51+ -- ^ Converts an inline list to JATS.
52+
44− , jatsReferences :: [Reference Inlines]
53+ , jatsReferences :: [Reference Inlines] -- ^ List of references
45 }
54 }
46
55
47-- | JATS writer type
56-- | JATS writer type
src/Text/Pandoc/Writers/Jira.hs+9−3
@@ -280,6 +280,8 @@ toJiraLink (_, classes, _) (url, _) alias = do
280 | Just email <- T.stripPrefix "mailto:" url' = (Jira.Email, email)
280 | Just email <- T.stripPrefix "mailto:" url' = (Jira.Email, email)
281 | "user-account" `elem` classes = (Jira.User, dropTilde url)
281 | "user-account" `elem` classes = (Jira.User, dropTilde url)
282 | "attachment" `elem` classes = (Jira.Attachment, url)
282 | "attachment" `elem` classes = (Jira.Attachment, url)
283+ | "smart-card" `elem` classes = (Jira.SmartCard, url)
284+ | "smart-link" `elem` classes = (Jira.SmartLink, url)
283 | otherwise = (Jira.External, url)
285 | otherwise = (Jira.External, url)
284 dropTilde txt = case T.uncons txt of
286 dropTilde txt = case T.uncons txt of
285 Just ('~', username) -> username
287 Just ('~', username) -> username
@@ -309,9 +311,13 @@ quotedToJira qtype xs = do
309spanToJira :: PandocMonad m
311spanToJira :: PandocMonad m
310 => Attr -> [Inline]
312 => Attr -> [Inline]
311 -> JiraConverter m [Jira.Inline]
313 -> JiraConverter m [Jira.Inline]
312−spanToJira (ident, _classes, _attribs) inls = case ident of
314+spanToJira (ident, _classes, attribs) inls =
315+ let wrap = case lookup "color" attribs of
316+ Nothing -> id
317+ Just color -> singleton . Jira.ColorInline (Jira.ColorName color)
318+ in wrap <$> case ident of
313− "" -> toJiraInlines inls
319+ "" -> toJiraInlines inls
314− _ -> (Jira.Anchor ident :) <$> toJiraInlines inls
320+ _ -> (Jira.Anchor ident :) <$> toJiraInlines inls
315
321
316registerNotes :: PandocMonad m => [Block] -> JiraConverter m [Jira.Inline]
322registerNotes :: PandocMonad m => [Block] -> JiraConverter m [Jira.Inline]
317registerNotes contents = do
323registerNotes contents = do
src/Text/Pandoc/Writers/LaTeX.hs+27−10
@@ -29,7 +29,7 @@ import qualified Data.Text as T
29import Network.URI (unEscapeString)
29import Network.URI (unEscapeString)
30import Text.DocTemplates (FromContext(lookupContext), renderTemplate,
30import Text.DocTemplates (FromContext(lookupContext), renderTemplate,
31 Val(..), Context(..))
31 Val(..), Context(..))
32−import Text.Pandoc.BCP47 (Lang (..), getLang, renderLang)
32+import Text.Collate.Lang (Lang (..), renderLang)
33import Text.Pandoc.Class.PandocMonad (PandocMonad, report, toLang)
33import Text.Pandoc.Class.PandocMonad (PandocMonad, report, toLang)
34import Text.Pandoc.Definition
34import Text.Pandoc.Definition
35import Text.Pandoc.Highlighting (formatLaTeXBlock, formatLaTeXInline, highlight,
35import Text.Pandoc.Highlighting (formatLaTeXBlock, formatLaTeXInline, highlight,
@@ -173,6 +173,7 @@ pandocToLaTeX options (Pandoc meta blocks) = do
173 defField "has-chapters" (stHasChapters st) $
173 defField "has-chapters" (stHasChapters st) $
174 defField "has-frontmatter" (documentClass `elem` frontmatterClasses) $
174 defField "has-frontmatter" (documentClass `elem` frontmatterClasses) $
175 defField "listings" (writerListings options || stLHS st) $
175 defField "listings" (writerListings options || stLHS st) $
176+ defField "zero-width-non-joiner" (stZwnj st) $
176 defField "beamer" beamer $
177 defField "beamer" beamer $
177 (if stHighlighting st
178 (if stHighlighting st
178 then case writerHighlightStyle options of
179 then case writerHighlightStyle options of
@@ -290,7 +291,12 @@ blockToLaTeX :: PandocMonad m
290 => Block -- ^ Block to convert
291 => Block -- ^ Block to convert
291 -> LW m (Doc Text)
292 -> LW m (Doc Text)
292blockToLaTeX Null = return empty
293blockToLaTeX Null = return empty
293−blockToLaTeX (Div attr@(identifier,"block":_,_) (Header _ _ ils : bs)) = do
294+blockToLaTeX (Div attr@(identifier,"block":dclasses,_)
295+ (Header _ _ ils : bs)) = do
296+ let blockname
297+ | "example" `elem` dclasses = "exampleblock"
298+ | "alert" `elem` dclasses = "alertblock"
299+ | otherwise = "block"
294 ref <- toLabel identifier
300 ref <- toLabel identifier
295 let anchor = if T.null identifier
301 let anchor = if T.null identifier
296 then empty
302 then empty
@@ -298,8 +304,8 @@ blockToLaTeX (Div attr@(identifier,"block":_,_) (Header _ _ ils : bs)) = do
298 braces (literal ref) <> braces empty
304 braces (literal ref) <> braces empty
299 title' <- inlineListToLaTeX ils
305 title' <- inlineListToLaTeX ils
300 contents <- blockListToLaTeX bs
306 contents <- blockListToLaTeX bs
301− wrapDiv attr $ ("\\begin{block}" <> braces title' <> anchor) $$
307+ wrapDiv attr $ ("\\begin" <> braces blockname <> braces title' <> anchor) $$
302− contents $$ "\\end{block}"
308+ contents $$ "\\end" <> braces blockname
303blockToLaTeX (Div (identifier,"slide":dclasses,dkvs)
309blockToLaTeX (Div (identifier,"slide":dclasses,dkvs)
304 (Header _ (_,hclasses,hkvs) ils : bs)) = do
310 (Header _ (_,hclasses,hkvs) ils : bs)) = do
305 -- note: [fragile] is required or verbatim breaks
311 -- note: [fragile] is required or verbatim breaks
@@ -825,7 +831,19 @@ inlineToLaTeX (Code (_,classes,kvs) str) = do
825 let chr = case "!\"'()*,-./:;?@" \\ T.unpack str of
831 let chr = case "!\"'()*,-./:;?@" \\ T.unpack str of
826 (c:_) -> c
832 (c:_) -> c
827 [] -> '!'
833 [] -> '!'
828− let str' = escapeStringUsing (backslashEscapes "\\{}%~_&#^") str
834+ let isEscapable '\\' = True
835+ isEscapable '{' = True
836+ isEscapable '}' = True
837+ isEscapable '%' = True
838+ isEscapable '~' = True
839+ isEscapable '_' = True
840+ isEscapable '&' = True
841+ isEscapable '#' = True
842+ isEscapable '^' = True
843+ isEscapable _ = False
844+ let escChar c | isEscapable c = T.pack ['\\',c]
845+ | otherwise = T.singleton c
846+ let str' = T.concatMap escChar str
829 -- we always put lstinline in a dummy 'passthrough' command
847 -- we always put lstinline in a dummy 'passthrough' command
830 -- (defined in the default template) so that we don't have
848 -- (defined in the default template) so that we don't have
831 -- to change the way we escape characters depending on whether
849 -- to change the way we escape characters depending on whether
@@ -876,8 +894,9 @@ inlineToLaTeX (Quoted qt lst) = do
876 then char '`' <> inner <> char '\''
894 then char '`' <> inner <> char '\''
877 else char '\x2018' <> inner <> char '\x2019'
895 else char '\x2018' <> inner <> char '\x2019'
878 where
896 where
897+ isQuoted (Span _ (x:_)) = isQuoted x
879− isQuoted (Quoted _ _) = True
898+ isQuoted (Quoted _ _) = True
880− isQuoted _ = False
899+ isQuoted _ = False
881inlineToLaTeX (Str str) = do
900inlineToLaTeX (Str str) = do
882 setEmptyLine False
901 setEmptyLine False
883 liftM literal $ stringToLaTeX TextString str
902 liftM literal $ stringToLaTeX TextString str
@@ -900,7 +919,7 @@ inlineToLaTeX il@(RawInline f str) = do
900inlineToLaTeX LineBreak = do
919inlineToLaTeX LineBreak = do
901 emptyLine <- gets stEmptyLine
920 emptyLine <- gets stEmptyLine
902 setEmptyLine True
921 setEmptyLine True
903− return $ (if emptyLine then "~" else "") <> "\\\\" <> cr
922+ return $ (if emptyLine then "\\strut " else "") <> "\\\\" <> cr
904inlineToLaTeX SoftBreak = do
923inlineToLaTeX SoftBreak = do
905 wrapText <- gets (writerWrapText . stOptions)
924 wrapText <- gets (writerWrapText . stOptions)
906 case wrapText of
925 case wrapText of
@@ -1031,5 +1050,3 @@ extractInline _ _ = []
1031-- Look up a key in an attribute and give a list of its values
1050-- Look up a key in an attribute and give a list of its values
1032lookKey :: Text -> Attr -> [Text]
1051lookKey :: Text -> Attr -> [Text]
1033lookKey key (_,_,kvs) = maybe [] T.words $ lookup key kvs
1052lookKey key (_,_,kvs) = maybe [] T.words $ lookup key kvs
1034−
1035−
src/Text/Pandoc/Writers/LaTeX/Lang.hs+61−60
@@ -15,7 +15,7 @@ module Text.Pandoc.Writers.LaTeX.Lang
15 toBabel
15 toBabel
16 ) where
16 ) where
17import Data.Text (Text)
17import Data.Text (Text)
18−import Text.Pandoc.BCP47 (Lang (..))
18+import Text.Collate.Lang (Lang(..))
19
19
20
20
21-- In environments \Arabic instead of \arabic is used
21-- In environments \Arabic instead of \arabic is used
@@ -25,88 +25,89 @@ toPolyglossiaEnv l =
25 ("arabic", o) -> ("Arabic", o)
25 ("arabic", o) -> ("Arabic", o)
26 x -> x
26 x -> x
27
27
28−-- Takes a list of the constituents of a BCP 47 language code and
28+-- Takes a list of the constituents of a BCP47 language code and
29-- converts it to a Polyglossia (language, options) tuple
29-- converts it to a Polyglossia (language, options) tuple
30-- http://mirrors.ctan.org/macros/latex/contrib/polyglossia/polyglossia.pdf
30-- http://mirrors.ctan.org/macros/latex/contrib/polyglossia/polyglossia.pdf
31toPolyglossia :: Lang -> (Text, Text)
31toPolyglossia :: Lang -> (Text, Text)
32−toPolyglossia (Lang "ar" _ "DZ" _) = ("arabic", "locale=algeria")
32+toPolyglossia (Lang "ar" _ (Just "DZ") _ _ _) = ("arabic", "locale=algeria")
33−toPolyglossia (Lang "ar" _ "IQ" _) = ("arabic", "locale=mashriq")
33+toPolyglossia (Lang "ar" _ (Just "IQ") _ _ _) = ("arabic", "locale=mashriq")
34−toPolyglossia (Lang "ar" _ "JO" _) = ("arabic", "locale=mashriq")
34+toPolyglossia (Lang "ar" _ (Just "JO") _ _ _) = ("arabic", "locale=mashriq")
35−toPolyglossia (Lang "ar" _ "LB" _) = ("arabic", "locale=mashriq")
35+toPolyglossia (Lang "ar" _ (Just "LB") _ _ _) = ("arabic", "locale=mashriq")
36−toPolyglossia (Lang "ar" _ "LY" _) = ("arabic", "locale=libya")
36+toPolyglossia (Lang "ar" _ (Just "LY") _ _ _) = ("arabic", "locale=libya")
37−toPolyglossia (Lang "ar" _ "MA" _) = ("arabic", "locale=morocco")
37+toPolyglossia (Lang "ar" _ (Just "MA") _ _ _) = ("arabic", "locale=morocco")
38−toPolyglossia (Lang "ar" _ "MR" _) = ("arabic", "locale=mauritania")
38+toPolyglossia (Lang "ar" _ (Just "MR") _ _ _) = ("arabic", "locale=mauritania")
39−toPolyglossia (Lang "ar" _ "PS" _) = ("arabic", "locale=mashriq")
39+toPolyglossia (Lang "ar" _ (Just "PS") _ _ _) = ("arabic", "locale=mashriq")
40−toPolyglossia (Lang "ar" _ "SY" _) = ("arabic", "locale=mashriq")
40+toPolyglossia (Lang "ar" _ (Just "SY") _ _ _) = ("arabic", "locale=mashriq")
41−toPolyglossia (Lang "ar" _ "TN" _) = ("arabic", "locale=tunisia")
41+toPolyglossia (Lang "ar" _ (Just "TN") _ _ _) = ("arabic", "locale=tunisia")
42−toPolyglossia (Lang "de" _ _ vars)
42+toPolyglossia (Lang "de" _ _ vars _ _)
43− | "1901" `elem` vars = ("german", "spelling=old")
43+ | "1901" `elem` vars = ("german", "spelling=old")
44−toPolyglossia (Lang "de" _ "AT" vars)
44+toPolyglossia (Lang "de" _ (Just "AT") vars _ _)
45− | "1901" `elem` vars = ("german", "variant=austrian, spelling=old")
45+ | "1901" `elem` vars = ("german", "variant=austrian, spelling=old")
46−toPolyglossia (Lang "de" _ "AT" _) = ("german", "variant=austrian")
46+toPolyglossia (Lang "de" _ (Just "AT") _ _ _) = ("german", "variant=austrian")
47−toPolyglossia (Lang "de" _ "CH" vars)
47+toPolyglossia (Lang "de" _ (Just "CH") vars _ _)
48− | "1901" `elem` vars = ("german", "variant=swiss, spelling=old")
48+ | "1901" `elem` vars = ("german", "variant=swiss, spelling=old")
49−toPolyglossia (Lang "de" _ "CH" _) = ("german", "variant=swiss")
49+toPolyglossia (Lang "de" _ (Just "CH") _ _ _) = ("german", "variant=swiss")
50−toPolyglossia (Lang "de" _ _ _) = ("german", "")
50+toPolyglossia (Lang "de" _ _ _ _ _) = ("german", "")
51−toPolyglossia (Lang "dsb" _ _ _) = ("lsorbian", "")
51+toPolyglossia (Lang "dsb" _ _ _ _ _) = ("lsorbian", "")
52+toPolyglossia (Lang "el" _ _ vars _ _)
52−toPolyglossia (Lang "el" _ "polyton" _) = ("greek", "variant=poly")
53+ | "polyton" `elem` vars = ("greek", "variant=poly")
53−toPolyglossia (Lang "en" _ "AU" _) = ("english", "variant=australian")
54+toPolyglossia (Lang "en" _ (Just "AU") _ _ _) = ("english", "variant=australian")
54−toPolyglossia (Lang "en" _ "CA" _) = ("english", "variant=canadian")
55+toPolyglossia (Lang "en" _ (Just "CA") _ _ _) = ("english", "variant=canadian")
55−toPolyglossia (Lang "en" _ "GB" _) = ("english", "variant=british")
56+toPolyglossia (Lang "en" _ (Just "GB") _ _ _) = ("english", "variant=british")
56−toPolyglossia (Lang "en" _ "NZ" _) = ("english", "variant=newzealand")
57+toPolyglossia (Lang "en" _ (Just "NZ") _ _ _) = ("english", "variant=newzealand")
57−toPolyglossia (Lang "en" _ "UK" _) = ("english", "variant=british")
58+toPolyglossia (Lang "en" _ (Just "UK") _ _ _) = ("english", "variant=british")
58−toPolyglossia (Lang "en" _ "US" _) = ("english", "variant=american")
59+toPolyglossia (Lang "en" _ (Just "US") _ _ _) = ("english", "variant=american")
59−toPolyglossia (Lang "grc" _ _ _) = ("greek", "variant=ancient")
60+toPolyglossia (Lang "grc" _ _ _ _ _) = ("greek", "variant=ancient")
60−toPolyglossia (Lang "hsb" _ _ _) = ("usorbian", "")
61+toPolyglossia (Lang "hsb" _ _ _ _ _) = ("usorbian", "")
61−toPolyglossia (Lang "la" _ _ vars)
62+toPolyglossia (Lang "la" _ _ vars _ _)
62− | "x-classic" `elem` vars = ("latin", "variant=classic")
63+ | "x-classic" `elem` vars = ("latin", "variant=classic")
63−toPolyglossia (Lang "pt" _ "BR" _) = ("portuguese", "variant=brazilian")
64+toPolyglossia (Lang "pt" _ (Just "BR") _ _ _) = ("portuguese", "variant=brazilian")
64−toPolyglossia (Lang "sl" _ _ _) = ("slovenian", "")
65+toPolyglossia (Lang "sl" _ _ _ _ _) = ("slovenian", "")
65−toPolyglossia x = (commonFromBcp47 x, "")
66+toPolyglossia x = (commonFromBcp47 x, "")
66
67
67−-- Takes a list of the constituents of a BCP 47 language code and
68+-- Takes a list of the constituents of a BCP47 language code and
68-- converts it to a Babel language string.
69-- converts it to a Babel language string.
69-- http://mirrors.ctan.org/macros/latex/required/babel/base/babel.pdf
70-- http://mirrors.ctan.org/macros/latex/required/babel/base/babel.pdf
70-- List of supported languages (slightly outdated):
71-- List of supported languages (slightly outdated):
71-- http://tug.ctan.org/language/hyph-utf8/doc/generic/hyph-utf8/hyphenation.pdf
72-- http://tug.ctan.org/language/hyph-utf8/doc/generic/hyph-utf8/hyphenation.pdf
72toBabel :: Lang -> Text
73toBabel :: Lang -> Text
73−toBabel (Lang "de" _ "AT" vars)
74+toBabel (Lang "de" _ (Just "AT") vars _ _)
74 | "1901" `elem` vars = "austrian"
75 | "1901" `elem` vars = "austrian"
75 | otherwise = "naustrian"
76 | otherwise = "naustrian"
76−toBabel (Lang "de" _ "CH" vars)
77+toBabel (Lang "de" _ (Just "CH") vars _ _)
77 | "1901" `elem` vars = "swissgerman"
78 | "1901" `elem` vars = "swissgerman"
78 | otherwise = "nswissgerman"
79 | otherwise = "nswissgerman"
79−toBabel (Lang "de" _ _ vars)
80+toBabel (Lang "de" _ _ vars _ _)
80 | "1901" `elem` vars = "german"
81 | "1901" `elem` vars = "german"
81 | otherwise = "ngerman"
82 | otherwise = "ngerman"
82−toBabel (Lang "dsb" _ _ _) = "lowersorbian"
83+toBabel (Lang "dsb" _ _ _ _ _) = "lowersorbian"
83−toBabel (Lang "el" _ _ vars)
84+toBabel (Lang "el" _ _ vars _ _)
84 | "polyton" `elem` vars = "polutonikogreek"
85 | "polyton" `elem` vars = "polutonikogreek"
85−toBabel (Lang "en" _ "AU" _) = "australian"
86+toBabel (Lang "en" _ (Just "AU") _ _ _) = "australian"
86−toBabel (Lang "en" _ "CA" _) = "canadian"
87+toBabel (Lang "en" _ (Just "CA") _ _ _) = "canadian"
87−toBabel (Lang "en" _ "GB" _) = "british"
88+toBabel (Lang "en" _ (Just "GB") _ _ _) = "british"
88−toBabel (Lang "en" _ "NZ" _) = "newzealand"
89+toBabel (Lang "en" _ (Just "NZ") _ _ _) = "newzealand"
89−toBabel (Lang "en" _ "UK" _) = "british"
90+toBabel (Lang "en" _ (Just "UK") _ _ _) = "british"
90−toBabel (Lang "en" _ "US" _) = "american"
91+toBabel (Lang "en" _ (Just "US") _ _ _) = "american"
91−toBabel (Lang "fr" _ "CA" _) = "canadien"
92+toBabel (Lang "fr" _ (Just "CA") _ _ _) = "canadien"
92−toBabel (Lang "fra" _ _ vars)
93+toBabel (Lang "fra" _ _ vars _ _)
93 | "aca" `elem` vars = "acadian"
94 | "aca" `elem` vars = "acadian"
94−toBabel (Lang "grc" _ _ _) = "polutonikogreek"
95+toBabel (Lang "grc" _ _ _ _ _) = "polutonikogreek"
95−toBabel (Lang "hsb" _ _ _) = "uppersorbian"
96+toBabel (Lang "hsb" _ _ _ _ _) = "uppersorbian"
96−toBabel (Lang "la" _ _ vars)
97+toBabel (Lang "la" _ _ vars _ _)
97 | "x-classic" `elem` vars = "classiclatin"
98 | "x-classic" `elem` vars = "classiclatin"
98−toBabel (Lang "pt" _ "BR" _) = "brazilian"
99+toBabel (Lang "pt" _ (Just "BR") _ _ _) = "brazilian"
99−toBabel (Lang "sl" _ _ _) = "slovene"
100+toBabel (Lang "sl" _ _ _ _ _) = "slovene"
100toBabel x = commonFromBcp47 x
101toBabel x = commonFromBcp47 x
101
102
102−-- Takes a list of the constituents of a BCP 47 language code
103+-- Takes a list of the constituents of a BCP47 language code
103-- and converts it to a string shared by Babel and Polyglossia.
104-- and converts it to a string shared by Babel and Polyglossia.
104-- https://tools.ietf.org/html/bcp47#section-2.1
105-- https://tools.ietf.org/html/bcp47#section-2.1
105commonFromBcp47 :: Lang -> Text
106commonFromBcp47 :: Lang -> Text
106−commonFromBcp47 (Lang "sr" "Cyrl" _ _) = "serbianc"
107+commonFromBcp47 (Lang "sr" (Just "Cyrl") _ _ _ _) = "serbianc"
107−commonFromBcp47 (Lang "zh" "Latn" _ vars)
108+commonFromBcp47 (Lang "zh" (Just "Latn") _ vars _ _)
108− | "pinyin" `elem` vars = "pinyin"
109+ | "pinyin" `elem` vars = "pinyin"
109−commonFromBcp47 (Lang l _ _ _) = fromIso l
110+commonFromBcp47 (Lang l _ _ _ _ _) = fromIso l
110 where
111 where
111 fromIso "af" = "afrikaans"
112 fromIso "af" = "afrikaans"
112 fromIso "am" = "amharic"
113 fromIso "am" = "amharic"
src/Text/Pandoc/Writers/LaTeX/Table.hs+21−8
@@ -16,6 +16,7 @@ module Text.Pandoc.Writers.LaTeX.Table
16 ) where
16 ) where
17import Control.Monad.State.Strict
17import Control.Monad.State.Strict
18import Data.List (intersperse)
18import Data.List (intersperse)
19+import qualified Data.List.NonEmpty as NonEmpty
19import Data.List.NonEmpty (NonEmpty ((:|)))
20import Data.List.NonEmpty (NonEmpty ((:|)))
20import Data.Text (Text)
21import Data.Text (Text)
21import qualified Data.Text as T
22import qualified Data.Text as T
@@ -25,7 +26,8 @@ import Text.DocLayout
25 ( Doc, braces, cr, empty, hcat, hsep, isEmpty, literal, nest
26 ( Doc, braces, cr, empty, hcat, hsep, isEmpty, literal, nest
26 , text, vcat, ($$) )
27 , text, vcat, ($$) )
27import Text.Pandoc.Shared (blocksToInlines, splitBy, tshow)
28import Text.Pandoc.Shared (blocksToInlines, splitBy, tshow)
28−import Text.Pandoc.Walk (walk)
29+import Text.Pandoc.Walk (walk, query)
30+import Data.Monoid (Any(..))
29import Text.Pandoc.Writers.LaTeX.Caption (getCaption)
31import Text.Pandoc.Writers.LaTeX.Caption (getCaption)
30import Text.Pandoc.Writers.LaTeX.Notes (notesToLaTeX)
32import Text.Pandoc.Writers.LaTeX.Notes (notesToLaTeX)
31import Text.Pandoc.Writers.LaTeX.Types
33import Text.Pandoc.Writers.LaTeX.Types
@@ -219,9 +221,7 @@ footRows (Ann.TableFoot _attr rows) = map headerRowCells rows
219-- we need to go to some lengths to get line breaks working:
221-- we need to go to some lengths to get line breaks working:
220-- as LineBreak bs = \vtop{\hbox{\strut as}\hbox{\strut bs}}.
222-- as LineBreak bs = \vtop{\hbox{\strut as}\hbox{\strut bs}}.
221fixLineBreaks :: Block -> Block
223fixLineBreaks :: Block -> Block
222−fixLineBreaks (Para ils) = Para $ fixLineBreaks' ils
224+fixLineBreaks = walk fixLineBreaks'
223−fixLineBreaks (Plain ils) = Plain $ fixLineBreaks' ils
224−fixLineBreaks x = x
225
225
226fixLineBreaks' :: [Inline] -> [Inline]
226fixLineBreaks' :: [Inline] -> [Inline]
227fixLineBreaks' ils = case splitBy (== LineBreak) ils of
227fixLineBreaks' ils = case splitBy (== LineBreak) ils of
@@ -245,8 +245,13 @@ cellToLaTeX :: PandocMonad m
245 -> Ann.Cell
245 -> Ann.Cell
246 -> LW m (Doc Text)
246 -> LW m (Doc Text)
247cellToLaTeX blockListToLaTeX celltype annotatedCell = do
247cellToLaTeX blockListToLaTeX celltype annotatedCell = do
248− let (Ann.Cell _specs _colnum cell) = annotatedCell
248+ let (Ann.Cell specs _colnum cell) = annotatedCell
249+ let hasWidths = snd (NonEmpty.head specs) /= ColWidthDefault
250+ let specAlign = fst (NonEmpty.head specs)
249− let (Cell _attr align rowspan colspan blocks) = cell
251+ let (Cell _attr align' rowspan colspan blocks) = cell
252+ let align = case align' of
253+ AlignDefault -> specAlign
254+ _ -> align'
250 beamer <- gets stBeamer
255 beamer <- gets stBeamer
251 externalNotes <- gets stExternalNotes
256 externalNotes <- gets stExternalNotes
252 inMinipage <- gets stInMinipage
257 inMinipage <- gets stInMinipage
@@ -257,8 +262,13 @@ cellToLaTeX blockListToLaTeX celltype annotatedCell = do
257 Para{} -> True
262 Para{} -> True
258 Plain{} -> True
263 Plain{} -> True
259 _ -> False
264 _ -> False
265+ let hasLineBreak LineBreak = Any True
266+ hasLineBreak _ = Any False
267+ let hasLineBreaks = getAny $ query hasLineBreak blocks
260 result <-
268 result <-
269+ if not hasWidths || (celltype /= HeaderCell
261− if all isPlainOrPara blocks
270+ && all isPlainOrPara blocks
271+ && not hasLineBreaks)
262 then
272 then
263 blockListToLaTeX $ walk fixLineBreaks $ walk displayMathToInline blocks
273 blockListToLaTeX $ walk fixLineBreaks $ walk displayMathToInline blocks
264 else do
274 else do
@@ -271,7 +281,9 @@ cellToLaTeX blockListToLaTeX celltype annotatedCell = do
271 let halign = literal $ alignCommand align
281 let halign = literal $ alignCommand align
272 return $ "\\begin{minipage}" <> valign <>
282 return $ "\\begin{minipage}" <> valign <>
273 braces "\\linewidth" <> halign <> cr <>
283 braces "\\linewidth" <> halign <> cr <>
274− cellContents <> cr <>
284+ cellContents <>
285+ (if hasLineBreaks then "\\strut" else mempty)
286+ <> cr <>
275 "\\end{minipage}"
287 "\\end{minipage}"
276 modify $ \st -> st{ stExternalNotes = externalNotes }
288 modify $ \st -> st{ stExternalNotes = externalNotes }
277 when (rowspan /= RowSpan 1) $
289 when (rowspan /= RowSpan 1) $
@@ -292,3 +304,4 @@ cellToLaTeX blockListToLaTeX celltype annotatedCell = do
292data CellType
304data CellType
293 = HeaderCell
305 = HeaderCell
294 | BodyCell
306 | BodyCell
307+ deriving Eq
src/Text/Pandoc/Writers/LaTeX/Types.hs+2−1
@@ -40,7 +40,7 @@ data WriterState =
40 , stCsquotes :: Bool -- ^ true if document uses csquotes
40 , stCsquotes :: Bool -- ^ true if document uses csquotes
41 , stHighlighting :: Bool -- ^ true if document has highlighted code
41 , stHighlighting :: Bool -- ^ true if document has highlighted code
42 , stIncremental :: Bool -- ^ true if beamer lists should be
42 , stIncremental :: Bool -- ^ true if beamer lists should be
43− -- displayed bit by bit
43+ , stZwnj :: Bool -- ^ true if document has a ZWNJ character
44 , stInternalLinks :: [Text] -- ^ list of internal link targets
44 , stInternalLinks :: [Text] -- ^ list of internal link targets
45 , stBeamer :: Bool -- ^ produce beamer
45 , stBeamer :: Bool -- ^ produce beamer
46 , stEmptyLine :: Bool -- ^ true if no content on line
46 , stEmptyLine :: Bool -- ^ true if no content on line
@@ -74,6 +74,7 @@ startingState options =
74 , stCsquotes = False
74 , stCsquotes = False
75 , stHighlighting = False
75 , stHighlighting = False
76 , stIncremental = writerIncremental options
76 , stIncremental = writerIncremental options
77+ , stZwnj = False
77 , stInternalLinks = []
78 , stInternalLinks = []
78 , stBeamer = False
79 , stBeamer = False
79 , stEmptyLine = True
80 , stEmptyLine = True
src/Text/Pandoc/Writers/LaTeX/Util.hs+4−3
@@ -22,6 +22,7 @@ module Text.Pandoc.Writers.LaTeX.Util (
22where
22where
23
23
24import Control.Applicative ((<|>))
24import Control.Applicative ((<|>))
25+import Control.Monad (when)
25import Text.Pandoc.Class (PandocMonad, toLang)
26import Text.Pandoc.Class (PandocMonad, toLang)
26import Text.Pandoc.Options (WriterOptions(..), isEnabled)
27import Text.Pandoc.Options (WriterOptions(..), isEnabled)
27import Text.Pandoc.Writers.LaTeX.Types (LW, WriterState(..))
28import Text.Pandoc.Writers.LaTeX.Types (LW, WriterState(..))
@@ -30,7 +31,7 @@ import Text.Pandoc.Highlighting (toListingsLanguage)
30import Text.DocLayout
31import Text.DocLayout
31import Text.Pandoc.Definition
32import Text.Pandoc.Definition
32import Text.Pandoc.ImageSize (showFl)
33import Text.Pandoc.ImageSize (showFl)
33−import Control.Monad.State.Strict (gets)
34+import Control.Monad.State.Strict (gets, modify)
34import Data.Text (Text)
35import Data.Text (Text)
35import qualified Data.Text as T
36import qualified Data.Text as T
36import Text.Pandoc.Extensions (Extension(Ext_smart))
37import Text.Pandoc.Extensions (Extension(Ext_smart))
@@ -49,6 +50,8 @@ data StringContext = TextString
49stringToLaTeX :: PandocMonad m => StringContext -> Text -> LW m Text
50stringToLaTeX :: PandocMonad m => StringContext -> Text -> LW m Text
50stringToLaTeX context zs = do
51stringToLaTeX context zs = do
51 opts <- gets stOptions
52 opts <- gets stOptions
53+ when ('\x200c' `elemText` zs) $
54+ modify (\s -> s { stZwnj = True })
52 return $ T.pack $
55 return $ T.pack $
53 foldr (go opts context) mempty $ T.unpack $
56 foldr (go opts context) mempty $ T.unpack $
54 if writerPreferAscii opts
57 if writerPreferAscii opts
@@ -270,5 +273,3 @@ mbBraced :: Text -> Text
270mbBraced x = if not (T.all isAlphaNum x)
273mbBraced x = if not (T.all isAlphaNum x)
271 then "{" <> x <> "}"
274 then "{" <> x <> "}"
272 else x
275 else x
273−
274−
src/Text/Pandoc/Writers/Man.hs+2−2
@@ -16,6 +16,7 @@ Conversion of 'Pandoc' documents to roff man page format.
16module Text.Pandoc.Writers.Man ( writeMan ) where
16module Text.Pandoc.Writers.Man ( writeMan ) where
17import Control.Monad.State.Strict
17import Control.Monad.State.Strict
18import Data.List (intersperse)
18import Data.List (intersperse)
19+import Data.List.NonEmpty (nonEmpty)
19import Data.Maybe (fromMaybe)
20import Data.Maybe (fromMaybe)
20import Data.Text (Text)
21import Data.Text (Text)
21import qualified Data.Text as T
22import qualified Data.Text as T
@@ -175,8 +176,7 @@ blockToMan opts (BulletList items) = do
175 return (vcat contents)
176 return (vcat contents)
176blockToMan opts (OrderedList attribs items) = do
177blockToMan opts (OrderedList attribs items) = do
177 let markers = take (length items) $ orderedListMarkers attribs
178 let markers = take (length items) $ orderedListMarkers attribs
178− let indent = 1 +
179− maximum (map T.length markers)
179+ let indent = 1 + maybe 0 maximum (nonEmpty (map T.length markers))
180 contents <- mapM (\(num, item) -> orderedListItemToMan opts num indent item) $
180 contents <- mapM (\(num, item) -> orderedListItemToMan opts num indent item) $
181 zip markers items
181 zip markers items
182 return (vcat contents)
182 return (vcat contents)
src/Text/Pandoc/Writers/Markdown.hs+54−56
@@ -24,8 +24,9 @@ import Control.Monad.Reader
24import Control.Monad.State.Strict
24import Control.Monad.State.Strict
25import Data.Default
25import Data.Default
26import Data.List (intersperse, sortOn, transpose)
26import Data.List (intersperse, sortOn, transpose)
27+import Data.List.NonEmpty (nonEmpty, NonEmpty(..))
27import qualified Data.Map as M
28import qualified Data.Map as M
28−import Data.Maybe (fromMaybe, mapMaybe)
29+import Data.Maybe (fromMaybe, mapMaybe, isNothing)
29import qualified Data.Set as Set
30import qualified Data.Set as Set
30import Data.Text (Text)
31import Data.Text (Text)
31import qualified Data.Text as T
32import qualified Data.Text as T
@@ -42,7 +43,7 @@ import Text.Pandoc.Templates (renderTemplate)
42import Text.DocTemplates (Val(..), Context(..), FromContext(..))
43import Text.DocTemplates (Val(..), Context(..), FromContext(..))
43import Text.Pandoc.Walk
44import Text.Pandoc.Walk
44import Text.Pandoc.Writers.HTML (writeHtml5String)
45import Text.Pandoc.Writers.HTML (writeHtml5String)
45−import Text.Pandoc.Writers.Markdown.Inline (inlineListToMarkdown)
46+import Text.Pandoc.Writers.Markdown.Inline (inlineListToMarkdown, linkAttributes, attrsToMarkdown)
46import Text.Pandoc.Writers.Markdown.Types (MarkdownVariant(..),
47import Text.Pandoc.Writers.Markdown.Types (MarkdownVariant(..),
47 WriterState(..),
48 WriterState(..),
48 WriterEnv(..),
49 WriterEnv(..),
@@ -66,7 +67,16 @@ writePlain opts document =
66-- | Convert Pandoc to Commonmark.
67-- | Convert Pandoc to Commonmark.
67writeCommonMark :: PandocMonad m => WriterOptions -> Pandoc -> m Text
68writeCommonMark :: PandocMonad m => WriterOptions -> Pandoc -> m Text
68writeCommonMark opts document =
69writeCommonMark opts document =
69− evalMD (pandocToMarkdown opts document) def{ envVariant = Commonmark } def
70+ evalMD (pandocToMarkdown opts' document) def{ envVariant = Commonmark } def
71+ where
72+ opts' = opts{ writerExtensions =
73+ -- These extensions can't be enabled or disabled
74+ -- for commonmark because they're part of the core;
75+ -- we set them here so that escapeText will behave
76+ -- properly.
77+ enableExtension Ext_all_symbols_escapable $
78+ enableExtension Ext_intraword_underscores $
79+ writerExtensions opts }
70
80
71pandocTitleBlock :: Doc Text -> [Doc Text] -> Doc Text -> Doc Text
81pandocTitleBlock :: Doc Text -> [Doc Text] -> Doc Text -> Doc Text
72pandocTitleBlock tit auths dat =
82pandocTitleBlock tit auths dat =
@@ -131,18 +141,17 @@ valToYaml (SimpleVal x)
131 | otherwise =
141 | otherwise =
132 if hasNewlines x
142 if hasNewlines x
133 then hang 0 ("|" <> cr) x
143 then hang 0 ("|" <> cr) x
134− else if fst $ foldr needsDoubleQuotes (False, True) x
144+ else if isNothing $ foldM needsDoubleQuotes True x
135 then "\"" <> fmap escapeInDoubleQuotes x <> "\""
145 then "\"" <> fmap escapeInDoubleQuotes x <> "\""
136 else x
146 else x
137 where
147 where
138− needsDoubleQuotes t (positive, isFirst)
148+ needsDoubleQuotes isFirst t
139 = if T.any isBadAnywhere t ||
149 = if T.any isBadAnywhere t ||
140 (isFirst && T.any isYamlPunct (T.take 1 t))
150 (isFirst && T.any isYamlPunct (T.take 1 t))
141− then (True, False)
151+ then Nothing
142− else (positive, False)
152+ else Just False
143 isBadAnywhere '#' = True
153 isBadAnywhere '#' = True
144 isBadAnywhere ':' = True
154 isBadAnywhere ':' = True
145− isBadAnywhere '`' = False
146 isBadAnywhere _ = False
155 isBadAnywhere _ = False
147 hasNewlines NewLine = True
156 hasNewlines NewLine = True
148 hasNewlines BlankLines{} = True
157 hasNewlines BlankLines{} = True
@@ -247,32 +256,11 @@ noteToMarkdown opts num blocks = do
247 then hang (writerTabStop opts) (marker <> spacer) contents
256 then hang (writerTabStop opts) (marker <> spacer) contents
248 else marker <> spacer <> contents
257 else marker <> spacer <> contents
249
258
250−attrsToMarkdown :: Attr -> Doc Text
259+-- | (Code) blocks with a single class and no attributes can just use it
251−attrsToMarkdown attribs = braces $ hsep [attribId, attribClasses, attribKeys]
260+-- standalone, no need to bother with curly braces.
252− where attribId = case attribs of
261+classOrAttrsToMarkdown :: Attr -> Doc Text
253− ("",_,_) -> empty
262+classOrAttrsToMarkdown ("",[cls],[]) = literal cls
254− (i,_,_) -> "#" <> escAttr i
255− attribClasses = case attribs of
256− (_,[],_) -> empty
257− (_,cs,_) -> hsep $
258− map (escAttr . ("."<>))
259− cs
260− attribKeys = case attribs of
261− (_,_,[]) -> empty
262− (_,_,ks) -> hsep $
263− map (\(k,v) -> escAttr k
264− <> "=\"" <>
265− escAttr v <> "\"") ks
266− escAttr = mconcat . map escAttrChar . T.unpack
267− escAttrChar '"' = literal "\\\""
268− escAttrChar '\\' = literal "\\\\"
269− escAttrChar c = literal $ T.singleton c
270−
271−linkAttributes :: WriterOptions -> Attr -> Doc Text
272−linkAttributes opts attr =
273− if isEnabled Ext_link_attributes opts && attr /= nullAttr
274− then attrsToMarkdown attr
263+classOrAttrsToMarkdown attrs = attrsToMarkdown attrs
275− else empty
276
264
277-- | Ordered list start parser for use in Para below.
265-- | Ordered list start parser for use in Para below.
278olMarker :: Parser Text ParserState ()
266olMarker :: Parser Text ParserState ()
@@ -333,9 +321,12 @@ blockToMarkdown' opts (Div attrs ils) = do
333 case () of
321 case () of
334 _ | isEnabled Ext_fenced_divs opts &&
322 _ | isEnabled Ext_fenced_divs opts &&
335 attrs /= nullAttr ->
323 attrs /= nullAttr ->
324+ let attrsToMd = if variant == Commonmark
325+ then attrsToMarkdown
326+ else classOrAttrsToMarkdown
336− nowrap (literal ":::" <+> attrsToMarkdown attrs) $$
327+ in nowrap (literal ":::" <+> attrsToMd attrs) $$
337− chomp contents $$
328+ chomp contents $$
338− literal ":::" <> blankline
329+ literal ":::" <> blankline
339 | isEnabled Ext_native_divs opts ||
330 | isEnabled Ext_native_divs opts ||
340 (isEnabled Ext_raw_html opts &&
331 (isEnabled Ext_raw_html opts &&
341 (variant == Commonmark ||
332 (variant == Commonmark ||
@@ -377,7 +368,7 @@ blockToMarkdown' opts (Plain inlines) = do
377-- title beginning with fig: indicates figure
368-- title beginning with fig: indicates figure
378blockToMarkdown' opts (Para [Image attr alt (src,tgt@(T.stripPrefix "fig:" -> Just tit))])
369blockToMarkdown' opts (Para [Image attr alt (src,tgt@(T.stripPrefix "fig:" -> Just tit))])
379 | isEnabled Ext_raw_html opts &&
370 | isEnabled Ext_raw_html opts &&
380− not (isEnabled Ext_link_attributes opts) &&
371+ not (isEnabled Ext_link_attributes opts || isEnabled Ext_attributes opts) &&
381 attr /= nullAttr = -- use raw HTML
372 attr /= nullAttr = -- use raw HTML
382 (<> blankline) . literal . T.strip <$>
373 (<> blankline) . literal . T.strip <$>
383 writeHtml5String opts{ writerTemplate = Nothing }
374 writeHtml5String opts{ writerTemplate = Nothing }
@@ -442,7 +433,8 @@ blockToMarkdown' opts (Header level attr inlines) = do
442 && id' == autoId -> empty
433 && id' == autoId -> empty
443 (id',_,_) | isEnabled Ext_mmd_header_identifiers opts ->
434 (id',_,_) | isEnabled Ext_mmd_header_identifiers opts ->
444 space <> brackets (literal id')
435 space <> brackets (literal id')
445− _ | isEnabled Ext_header_attributes opts ->
436+ _ | isEnabled Ext_header_attributes opts ||
437+ isEnabled Ext_attributes opts ->
446 space <> attrsToMarkdown attr
438 space <> attrsToMarkdown attr
447 | otherwise -> empty
439 | otherwise -> empty
448 contents <- inlineListToMarkdown opts $
440 contents <- inlineListToMarkdown opts $
@@ -492,19 +484,21 @@ blockToMarkdown' opts (CodeBlock attribs str) = do
492 | isEnabled Ext_fenced_code_blocks opts ->
484 | isEnabled Ext_fenced_code_blocks opts ->
493 tildes <> attrs <> cr <> literal str <> cr <> tildes <> blankline
485 tildes <> attrs <> cr <> literal str <> cr <> tildes <> blankline
494 _ -> nest (writerTabStop opts) (literal str) <> blankline
486 _ -> nest (writerTabStop opts) (literal str) <> blankline
487+ where
488+ endlineLen c = maybe 3 ((+1) . maximum) $ nonEmpty $
495− where endline c = literal $ case [T.length ln
489+ [T.length ln
496− | ln <- map trim (T.lines str)
490+ | ln <- map trim (T.lines str)
497− , T.pack [c,c,c] `T.isPrefixOf` ln
491+ , T.pack [c,c,c] `T.isPrefixOf` ln
498− , T.all (== c) ln] of
492+ , T.all (== c) ln]
499− [] -> T.replicate 3 $ T.singleton c
500− xs -> T.replicate (maximum xs + 1) $ T.singleton c
493+ endline c = literal $ T.replicate (endlineLen c) $ T.singleton c
501− backticks = endline '`'
494+ backticks = endline '`'
502− tildes = endline '~'
495+ tildes = endline '~'
503− attrs = if isEnabled Ext_fenced_code_attributes opts
496+ attrs = if isEnabled Ext_fenced_code_attributes opts ||
497+ isEnabled Ext_attributes opts
504− then nowrap $ " " <> attrsToMarkdown attribs
498+ then nowrap $ " " <> classOrAttrsToMarkdown attribs
505− else case attribs of
499+ else case attribs of
506− (_,cls:_,_) -> " " <> literal cls
500+ (_,cls:_,_) -> " " <> literal cls
507− _ -> empty
501+ _ -> empty
508blockToMarkdown' opts (BlockQuote blocks) = do
502blockToMarkdown' opts (BlockQuote blocks) = do
509 variant <- asks envVariant
503 variant <- asks envVariant
510 -- if we're writing literate haskell, put a space before the bird tracks
504 -- if we're writing literate haskell, put a space before the bird tracks
@@ -517,7 +511,7 @@ blockToMarkdown' opts (BlockQuote blocks) = do
517 return $ prefixed leader contents <> blankline
511 return $ prefixed leader contents <> blankline
518blockToMarkdown' opts t@(Table _ blkCapt specs thead tbody tfoot) = do
512blockToMarkdown' opts t@(Table _ blkCapt specs thead tbody tfoot) = do
519 let (caption, aligns, widths, headers, rows) = toLegacyTable blkCapt specs thead tbody tfoot
513 let (caption, aligns, widths, headers, rows) = toLegacyTable blkCapt specs thead tbody tfoot
520− let numcols = maximum (length aligns : length widths :
514+ let numcols = maximum (length aligns :| length widths :
521 map length (headers:rows))
515 map length (headers:rows))
522 caption' <- inlineListToMarkdown opts caption
516 caption' <- inlineListToMarkdown opts caption
523 let caption''
517 let caption''
@@ -619,7 +613,8 @@ pipeTable headless aligns rawHeaders rawRows = do
619 blockFor AlignCenter x y = cblock (x + 2) (sp <> y <> sp) <> lblock 0 empty
613 blockFor AlignCenter x y = cblock (x + 2) (sp <> y <> sp) <> lblock 0 empty
620 blockFor AlignRight x y = rblock (x + 2) (y <> sp) <> lblock 0 empty
614 blockFor AlignRight x y = rblock (x + 2) (y <> sp) <> lblock 0 empty
621 blockFor _ x y = lblock (x + 2) (sp <> y) <> lblock 0 empty
615 blockFor _ x y = lblock (x + 2) (sp <> y) <> lblock 0 empty
622− let widths = map (max 3 . maximum . map offset) $ transpose (rawHeaders : rawRows)
616+ let widths = map (max 3 . maybe 3 maximum . nonEmpty . map offset) $
617+ transpose (rawHeaders : rawRows)
623 let torow cs = nowrap $ literal "|" <>
618 let torow cs = nowrap $ literal "|" <>
624 hcat (intersperse (literal "|") $
619 hcat (intersperse (literal "|") $
625 zipWith3 blockFor aligns widths (map chomp cs))
620 zipWith3 blockFor aligns widths (map chomp cs))
@@ -653,11 +648,11 @@ pandocTable opts multiline headless aligns widths rawHeaders rawRows = do
653 -- Number of characters per column necessary to output every cell
648 -- Number of characters per column necessary to output every cell
654 -- without requiring a line break.
649 -- without requiring a line break.
655 -- The @+2@ is needed for specifying the alignment.
650 -- The @+2@ is needed for specifying the alignment.
656− let numChars = (+ 2) . maximum . map offset
651+ let numChars = (+ 2) . maybe 0 maximum . nonEmpty . map offset
657 -- Number of characters per column necessary to output every cell
652 -- Number of characters per column necessary to output every cell
658 -- without requiring a line break *inside a word*.
653 -- without requiring a line break *inside a word*.
659 -- The @+2@ is needed for specifying the alignment.
654 -- The @+2@ is needed for specifying the alignment.
660− let minNumChars = (+ 2) . maximum . map minOffset
655+ let minNumChars = (+ 2) . maybe 0 maximum . nonEmpty . map minOffset
661 let columns = transpose (rawHeaders : rawRows)
656 let columns = transpose (rawHeaders : rawRows)
662 -- minimal column width without wrapping a single word
657 -- minimal column width without wrapping a single word
663 let relWidth w col =
658 let relWidth w col =
@@ -796,6 +791,9 @@ blockListToMarkdown opts blocks = do
796 b1 : commentSep : fixBlocks (b2:bs)
791 b1 : commentSep : fixBlocks (b2:bs)
797 fixBlocks (Plain ils : bs@(RawBlock{}:_)) =
792 fixBlocks (Plain ils : bs@(RawBlock{}:_)) =
798 Plain ils : fixBlocks bs
793 Plain ils : fixBlocks bs
794+ fixBlocks (Plain ils : bs@(Div{}:_))
795+ | isEnabled Ext_fenced_divs opts =
796+ Para ils : fixBlocks bs
799 fixBlocks (Plain ils : bs) | inlist =
797 fixBlocks (Plain ils : bs) | inlist =
800 Plain ils : fixBlocks bs
798 Plain ils : fixBlocks bs
801 fixBlocks (Plain ils : bs) =
799 fixBlocks (Plain ils : bs) =
src/Text/Pandoc/Writers/Markdown/Inline.hs+36−21
@@ -11,12 +11,15 @@
11 Portability : portable
11 Portability : portable
12-}
12-}
13module Text.Pandoc.Writers.Markdown.Inline (
13module Text.Pandoc.Writers.Markdown.Inline (
14− inlineListToMarkdown
14+ inlineListToMarkdown,
15+ linkAttributes,
16+ attrsToMarkdown
15 ) where
17 ) where
16import Control.Monad.Reader
18import Control.Monad.Reader
17import Control.Monad.State.Strict
19import Control.Monad.State.Strict
18import Data.Char (isAlphaNum, isDigit)
20import Data.Char (isAlphaNum, isDigit)
19import Data.List (find, intersperse)
21import Data.List (find, intersperse)
22+import Data.List.NonEmpty (nonEmpty)
20import qualified Data.Map as M
23import qualified Data.Map as M
21import Data.Maybe (fromMaybe)
24import Data.Maybe (fromMaybe)
22import Data.Text (Text)
25import Data.Text (Text)
@@ -42,7 +45,11 @@ import Text.Pandoc.Writers.Markdown.Types (MarkdownVariant(..),
42-- | Escape special characters for Markdown.
45-- | Escape special characters for Markdown.
43escapeText :: WriterOptions -> Text -> Text
46escapeText :: WriterOptions -> Text -> Text
44escapeText opts = T.pack . go . T.unpack
47escapeText opts = T.pack . go . T.unpack
45− where
48+ where
49+ startsWithSpace (' ':_) = True
50+ startsWithSpace ('\t':_) = True
51+ startsWithSpace [] = True
52+ startsWithSpace _ = False
46 go [] = []
53 go [] = []
47 go (c:cs) =
54 go (c:cs) =
48 case c of
55 case c of
@@ -55,10 +62,13 @@ escapeText opts = T.pack . go . T.unpack
55 '@' | isEnabled Ext_citations opts ->
62 '@' | isEnabled Ext_citations opts ->
56 case cs of
63 case cs of
57 (d:_)
64 (d:_)
58− | isAlphaNum d || d == '_'
65+ | isAlphaNum d || d == '_' || d == '{'
59 -> '\\':'@':go cs
66 -> '\\':'@':go cs
60 _ -> '@':go cs
67 _ -> '@':go cs
68+ '#' | isEnabled Ext_space_in_atx_header opts
69+ , startsWithSpace cs
70+ -> '\\':'#':go cs
61− _ | c `elem` ['\\','`','*','_','[',']','#'] ->
71+ _ | c `elem` ['\\','`','*','_','[',']'] ->
62 '\\':c:go cs
72 '\\':c:go cs
63 '|' | isEnabled Ext_pipe_tables opts -> '\\':'|':go cs
73 '|' | isEnabled Ext_pipe_tables opts -> '\\':'|':go cs
64 '^' | isEnabled Ext_superscript opts -> '\\':'^':go cs
74 '^' | isEnabled Ext_superscript opts -> '\\':'^':go cs
@@ -80,6 +90,8 @@ escapeText opts = T.pack . go . T.unpack
80 | isEnabled Ext_intraword_underscores opts
90 | isEnabled Ext_intraword_underscores opts
81 , isAlphaNum c
91 , isAlphaNum c
82 , isAlphaNum x -> c : '_' : x : go xs
92 , isAlphaNum x -> c : '_' : x : go xs
93+ '#':xs -> c : '#' : go xs
94+ '>':xs -> c : '>' : go xs
83 _ -> c : go cs
95 _ -> c : go cs
84
96
85attrsToMarkdown :: Attr -> Doc Text
97attrsToMarkdown :: Attr -> Doc Text
@@ -105,7 +117,7 @@ attrsToMarkdown attribs = braces $ hsep [attribId, attribClasses, attribKeys]
105
117
106linkAttributes :: WriterOptions -> Attr -> Doc Text
118linkAttributes :: WriterOptions -> Attr -> Doc Text
107linkAttributes opts attr =
119linkAttributes opts attr =
108− if isEnabled Ext_link_attributes opts && attr /= nullAttr
120+ if (isEnabled Ext_link_attributes opts || isEnabled Ext_attributes opts) && attr /= nullAttr
109 then attrsToMarkdown attr
121 then attrsToMarkdown attr
110 else empty
122 else empty
111
123
@@ -382,15 +394,15 @@ inlineToMarkdown opts (Quoted DoubleQuote lst) = do
382 then "&ldquo;" <> contents <> "&rdquo;"
394 then "&ldquo;" <> contents <> "&rdquo;"
383 else "“" <> contents <> "”"
395 else "“" <> contents <> "”"
384inlineToMarkdown opts (Code attr str) = do
396inlineToMarkdown opts (Code attr str) = do
385− let tickGroups = filter (T.any (== '`')) $ T.group str
397+ let tickGroups = filter (T.any (== '`')) $ T.group str
386− let longest = if null tickGroups
387− then 0
388− else maximum $ map T.length tickGroups
398+ let longest = maybe 0 maximum $ nonEmpty $ map T.length tickGroups
389− let marker = T.replicate (longest + 1) "`"
399+ let marker = T.replicate (longest + 1) "`"
390− let spacer = if longest == 0 then "" else " "
400+ let spacer = if longest == 0 then "" else " "
391− let attrs = if isEnabled Ext_inline_code_attributes opts && attr /= nullAttr
401+ let attrsEnabled = isEnabled Ext_inline_code_attributes opts ||
402+ isEnabled Ext_attributes opts
403+ let attrs = if attrsEnabled && attr /= nullAttr
392− then attrsToMarkdown attr
404+ then attrsToMarkdown attr
393− else empty
405+ else empty
394 variant <- asks envVariant
406 variant <- asks envVariant
395 case variant of
407 case variant of
396 PlainText -> return $ literal str
408 PlainText -> return $ literal str
@@ -438,9 +450,7 @@ inlineToMarkdown opts (Math DisplayMath str) =
438 (texMathToInlines DisplayMath str >>= inlineListToMarkdown opts)
450 (texMathToInlines DisplayMath str >>= inlineListToMarkdown opts)
439inlineToMarkdown opts il@(RawInline f str) = do
451inlineToMarkdown opts il@(RawInline f str) = do
440 let tickGroups = filter (T.any (== '`')) $ T.group str
452 let tickGroups = filter (T.any (== '`')) $ T.group str
441− let numticks = if null tickGroups
442− then 1
443− else 1 + maximum (map T.length tickGroups)
453+ let numticks = 1 + maybe 0 maximum (nonEmpty (map T.length tickGroups))
444 variant <- asks envVariant
454 variant <- asks envVariant
445 let Format fmt = f
455 let Format fmt = f
446 let rawAttribInline = return $
456 let rawAttribInline = return $
@@ -494,11 +504,16 @@ inlineToMarkdown opts (Cite (c:cs) lst)
494 rest <- mapM convertOne cs
504 rest <- mapM convertOne cs
495 let inbr = suffs <+> joincits rest
505 let inbr = suffs <+> joincits rest
496 br = if isEmpty inbr then empty else char '[' <> inbr <> char ']'
506 br = if isEmpty inbr then empty else char '[' <> inbr <> char ']'
497− return $ literal ("@" <> citationId c) <+> br
507+ return $ literal ("@" <> maybeInBraces (citationId c)) <+> br
498 else do
508 else do
499 cits <- mapM convertOne (c:cs)
509 cits <- mapM convertOne (c:cs)
500 return $ literal "[" <> joincits cits <> literal "]"
510 return $ literal "[" <> joincits cits <> literal "]"
501 where
511 where
512+ maybeInBraces key =
513+ case readWith (citeKey False >> spaces >> eof)
514+ defaultParserState ("@" <> key) of
515+ Left _ -> "{" <> key <> "}"
516+ Right _ -> key
502 joincits = hcat . intersperse (literal "; ") . filter (not . isEmpty)
517 joincits = hcat . intersperse (literal "; ") . filter (not . isEmpty)
503 convertOne Citation { citationId = k
518 convertOne Citation { citationId = k
504 , citationPrefix = pinlines
519 , citationPrefix = pinlines
@@ -507,7 +522,7 @@ inlineToMarkdown opts (Cite (c:cs) lst)
507 = do
522 = do
508 pdoc <- inlineListToMarkdown opts pinlines
523 pdoc <- inlineListToMarkdown opts pinlines
509 sdoc <- inlineListToMarkdown opts sinlines
524 sdoc <- inlineListToMarkdown opts sinlines
510− let k' = literal (modekey m <> "@" <> k)
525+ let k' = literal (modekey m <> "@" <> maybeInBraces k)
511 r = case sinlines of
526 r = case sinlines of
512 Str (T.uncons -> Just (y,_)):_ | y `elem` (",;]@" :: String) -> k' <> sdoc
527 Str (T.uncons -> Just (y,_)):_ | y `elem` (",;]@" :: String) -> k' <> sdoc
513 _ -> k' <+> sdoc
528 _ -> k' <+> sdoc
@@ -546,7 +561,7 @@ inlineToMarkdown opts lnk@(Link attr txt (src, tit)) = do
546 else "[" <> reftext <> "]"
561 else "[" <> reftext <> "]"
547 in return $ first <> second
562 in return $ first <> second
548 | isEnabled Ext_raw_html opts
563 | isEnabled Ext_raw_html opts
549− , not (isEnabled Ext_link_attributes opts)
564+ , not (isEnabled Ext_link_attributes opts || isEnabled Ext_attributes opts)
550 , attr /= nullAttr -> -- use raw HTML to render attributes
565 , attr /= nullAttr -> -- use raw HTML to render attributes
551 literal . T.strip <$>
566 literal . T.strip <$>
552 writeHtml5String opts{ writerTemplate = Nothing }
567 writeHtml5String opts{ writerTemplate = Nothing }
@@ -556,7 +571,7 @@ inlineToMarkdown opts lnk@(Link attr txt (src, tit)) = do
556 linkAttributes opts attr
571 linkAttributes opts attr
557inlineToMarkdown opts img@(Image attr alternate (source, tit))
572inlineToMarkdown opts img@(Image attr alternate (source, tit))
558 | isEnabled Ext_raw_html opts &&
573 | isEnabled Ext_raw_html opts &&
559− not (isEnabled Ext_link_attributes opts) &&
574+ not (isEnabled Ext_link_attributes opts || isEnabled Ext_attributes opts) &&
560 attr /= nullAttr = -- use raw HTML
575 attr /= nullAttr = -- use raw HTML
561 literal . T.strip <$>
576 literal . T.strip <$>
562 writeHtml5String opts{ writerTemplate = Nothing } (Pandoc nullMeta [Plain [img]])
577 writeHtml5String opts{ writerTemplate = Nothing } (Pandoc nullMeta [Plain [img]])
src/Text/Pandoc/Writers/Ms.hs+24−8
@@ -23,6 +23,7 @@ module Text.Pandoc.Writers.Ms ( writeMs ) where
23import Control.Monad.State.Strict
23import Control.Monad.State.Strict
24import Data.Char (isLower, isUpper, ord)
24import Data.Char (isLower, isUpper, ord)
25import Data.List (intercalate, intersperse)
25import Data.List (intercalate, intersperse)
26+import Data.List.NonEmpty (nonEmpty)
26import qualified Data.Map as Map
27import qualified Data.Map as Map
27import Data.Maybe (catMaybes)
28import Data.Maybe (catMaybes)
28import Data.Text (Text)
29import Data.Text (Text)
@@ -244,13 +245,17 @@ blockToMs opts (Table _ blkCapt specs thead tbody tfoot) =
244 aligncode AlignDefault = "l"
245 aligncode AlignDefault = "l"
245 in do
246 in do
246 caption' <- inlineListToMs' opts caption
247 caption' <- inlineListToMs' opts caption
247− let iwidths = if all (== 0) widths
248+ let isSimple = all (== 0) widths
248− then repeat ""
249+ let totalWidth = 70
249− else map (T.pack . printf "w(%0.1fn)" . (70 *)) widths
250 -- 78n default width - 8n indent = 70n
250 -- 78n default width - 8n indent = 70n
251 let coldescriptions = literal $ T.unwords
251 let coldescriptions = literal $ T.unwords
252− (zipWith (\align width -> aligncode align <> width)
252+ (zipWith (\align width -> aligncode align <>
253+ if width == 0
254+ then ""
255+ else T.pack $
256+ printf "w(%0.1fn)"
257+ (totalWidth * width))
253− alignments iwidths) <> "."
258+ alignments widths) <> "."
254 colheadings <- mapM (blockListToMs opts) headers
259 colheadings <- mapM (blockListToMs opts) headers
255 let makeRow cols = literal "T{" $$
260 let makeRow cols = literal "T{" $$
256 vcat (intersperse (literal "T}\tT{") cols) $$
261 vcat (intersperse (literal "T}\tT{") cols) $$
@@ -259,13 +264,25 @@ blockToMs opts (Table _ blkCapt specs thead tbody tfoot) =
259 then empty
264 then empty
260 else makeRow colheadings $$ char '_'
265 else makeRow colheadings $$ char '_'
261 body <- mapM (\row -> do
266 body <- mapM (\row -> do
267+ cols <- mapM (\(cell, w) ->
268+ (if isSimple
269+ then id
270+ else (literal (".nr LL " <>
271+ T.pack (printf "%0.1fn"
272+ (w * totalWidth))) $$)) <$>
262− cols <- mapM (blockListToMs opts) row
273+ blockListToMs opts cell) (zip row widths)
263 return $ makeRow cols) rows
274 return $ makeRow cols) rows
264 setFirstPara
275 setFirstPara
265 return $ literal ".PP" $$ caption' $$
276 return $ literal ".PP" $$ caption' $$
266 literal ".na" $$ -- we don't want justification in table cells
277 literal ".na" $$ -- we don't want justification in table cells
278+ (if isSimple
279+ then ""
280+ else ".nr LLold \\n[LL]") $$
267 literal ".TS" $$ literal "delim(@@) tab(\t);" $$ coldescriptions $$
281 literal ".TS" $$ literal "delim(@@) tab(\t);" $$ coldescriptions $$
268 colheadings' $$ vcat body $$ literal ".TE" $$
282 colheadings' $$ vcat body $$ literal ".TE" $$
283+ (if isSimple
284+ then ""
285+ else ".nr LL \\n[LLold]") $$
269 literal ".ad"
286 literal ".ad"
270
287
271blockToMs opts (BulletList items) = do
288blockToMs opts (BulletList items) = do
@@ -274,8 +291,7 @@ blockToMs opts (BulletList items) = do
274 return (vcat contents)
291 return (vcat contents)
275blockToMs opts (OrderedList attribs items) = do
292blockToMs opts (OrderedList attribs items) = do
276 let markers = take (length items) $ orderedListMarkers attribs
293 let markers = take (length items) $ orderedListMarkers attribs
277− let indent = 2 +
278− maximum (map T.length markers)
294+ let indent = 2 + maybe 0 maximum (nonEmpty (map T.length markers))
279 contents <- mapM (\(num, item) -> orderedListItemToMs opts num indent item) $
295 contents <- mapM (\(num, item) -> orderedListItemToMs opts num indent item) $
280 zip markers items
296 zip markers items
281 setFirstPara
297 setFirstPara
src/Text/Pandoc/Writers/Muse.hs+6−3
@@ -31,6 +31,7 @@ import Control.Monad.State.Strict
31import Data.Char (isAlphaNum, isAsciiLower, isAsciiUpper, isDigit, isSpace)
31import Data.Char (isAlphaNum, isAsciiLower, isAsciiUpper, isDigit, isSpace)
32import Data.Default
32import Data.Default
33import Data.List (intersperse, transpose)
33import Data.List (intersperse, transpose)
34+import Data.List.NonEmpty (nonEmpty, NonEmpty(..))
34import qualified Data.Set as Set
35import qualified Data.Set as Set
35import qualified Data.Text as T
36import qualified Data.Text as T
36import Data.Text (Text)
37import Data.Text (Text)
@@ -158,7 +159,8 @@ simpleTable caption headers rows = do
158 caption' <- inlineListToMuse caption
159 caption' <- inlineListToMuse caption
159 headers' <- mapM blockListToMuse headers
160 headers' <- mapM blockListToMuse headers
160 rows' <- mapM (mapM blockListToMuse) rows
161 rows' <- mapM (mapM blockListToMuse) rows
161− let widthsInChars = maximum . map offset <$> transpose (headers' : rows')
162+ let widthsInChars = maybe 0 maximum . nonEmpty . map offset <$>
163+ transpose (headers' : rows')
162 let hpipeBlocks sep blocks = hcat $ intersperse sep' blocks
164 let hpipeBlocks sep blocks = hcat $ intersperse sep' blocks
163 where sep' = lblock (T.length sep) $ literal sep
165 where sep' = lblock (T.length sep) $ literal sep
164 let makeRow sep = hpipeBlocks sep . zipWith lblock widthsInChars
166 let makeRow sep = hpipeBlocks sep . zipWith lblock widthsInChars
@@ -238,7 +240,7 @@ blockToMuse (DefinitionList items) = do
238 label' <- local (\env -> env { envOneLine = True, envAfterSpace = True }) $ inlineListToMuse' label
240 label' <- local (\env -> env { envOneLine = True, envAfterSpace = True }) $ inlineListToMuse' label
239 let ind = offset' label' -- using Text.DocLayout.offset results in round trip failures
241 let ind = offset' label' -- using Text.DocLayout.offset results in round trip failures
240 hang ind (nowrap label') . vcat <$> mapM descriptionToMuse defs
242 hang ind (nowrap label') . vcat <$> mapM descriptionToMuse defs
241− where offset' d = maximum (0: map T.length
243+ where offset' d = maximum (0 :| map T.length
242 (T.lines $ render Nothing d))
244 (T.lines $ render Nothing d))
243 descriptionToMuse :: PandocMonad m
245 descriptionToMuse :: PandocMonad m
244 => [Block]
246 => [Block]
@@ -269,7 +271,8 @@ blockToMuse (Table _ blkCapt specs thead tbody tfoot) =
269 (caption, aligns, widths, headers, rows) = toLegacyTable blkCapt specs thead tbody tfoot
271 (caption, aligns, widths, headers, rows) = toLegacyTable blkCapt specs thead tbody tfoot
270 blocksToDoc opts blocks =
272 blocksToDoc opts blocks =
271 local (\env -> env { envOptions = opts }) $ blockListToMuse blocks
273 local (\env -> env { envOptions = opts }) $ blockListToMuse blocks
274+ numcols = maximum
272− numcols = maximum (length aligns : length widths : map length (headers:rows))
275+ (length aligns :| length widths : map length (headers:rows))
273 isSimple = onlySimpleTableCells (headers : rows) && all (== 0) widths
276 isSimple = onlySimpleTableCells (headers : rows) && all (== 0) widths
274blockToMuse (Div _ bs) = flatBlockListToMuse bs
277blockToMuse (Div _ bs) = flatBlockListToMuse bs
275blockToMuse Null = return empty
278blockToMuse Null = return empty
src/Text/Pandoc/Writers/ODT.hs+4−3
@@ -16,6 +16,7 @@ import Codec.Archive.Zip
16import Control.Monad.Except (catchError, throwError)
16import Control.Monad.Except (catchError, throwError)
17import Control.Monad.State.Strict
17import Control.Monad.State.Strict
18import qualified Data.ByteString.Lazy as B
18import qualified Data.ByteString.Lazy as B
19+import Data.Maybe (fromMaybe)
19import Data.Generics (everywhere', mkT)
20import Data.Generics (everywhere', mkT)
20import Data.List (isPrefixOf)
21import Data.List (isPrefixOf)
21import qualified Data.Map as Map
22import qualified Data.Map as Map
@@ -23,7 +24,7 @@ import qualified Data.Text as T
23import qualified Data.Text.Lazy as TL
24import qualified Data.Text.Lazy as TL
24import Data.Time
25import Data.Time
25import System.FilePath (takeDirectory, takeExtension, (<.>))
26import System.FilePath (takeDirectory, takeExtension, (<.>))
26−import Text.Pandoc.BCP47 (Lang (..), getLang, renderLang)
27+import Text.Collate.Lang (Lang (..), renderLang)
27import Text.Pandoc.Class.PandocMonad (PandocMonad, report, toLang)
28import Text.Pandoc.Class.PandocMonad (PandocMonad, report, toLang)
28import qualified Text.Pandoc.Class.PandocMonad as P
29import qualified Text.Pandoc.Class.PandocMonad as P
29import Text.Pandoc.Definition
30import Text.Pandoc.Definition
@@ -35,7 +36,7 @@ import Text.Pandoc.Options (WrapOption (..), WriterOptions (..))
35import Text.DocLayout
36import Text.DocLayout
36import Text.Pandoc.Shared (stringify, pandocVersion, tshow)
37import Text.Pandoc.Shared (stringify, pandocVersion, tshow)
37import Text.Pandoc.Writers.Shared (lookupMetaString, lookupMetaBlocks,
38import Text.Pandoc.Writers.Shared (lookupMetaString, lookupMetaBlocks,
38− fixDisplayMath)
39+ fixDisplayMath, getLang)
39import Text.Pandoc.UTF8 (fromStringLazy, fromTextLazy, toTextLazy)
40import Text.Pandoc.UTF8 (fromStringLazy, fromTextLazy, toTextLazy)
40import Text.Pandoc.Walk
41import Text.Pandoc.Walk
41import Text.Pandoc.Writers.OpenDocument (writeOpenDocument)
42import Text.Pandoc.Writers.OpenDocument (writeOpenDocument)
@@ -194,7 +195,7 @@ addLang lang = everywhere' (mkT updateLangAttr)
194 where updateLangAttr (Attr n@(QName "language" _ (Just "fo")) _)
195 where updateLangAttr (Attr n@(QName "language" _ (Just "fo")) _)
195 = Attr n (langLanguage lang)
196 = Attr n (langLanguage lang)
196 updateLangAttr (Attr n@(QName "country" _ (Just "fo")) _)
197 updateLangAttr (Attr n@(QName "country" _ (Just "fo")) _)
197− = Attr n (langRegion lang)
198+ = Attr n (fromMaybe "" $ langRegion lang)
198 updateLangAttr x = x
199 updateLangAttr x = x
199
200
200-- | transform both Image and Math elements
201-- | transform both Image and Math elements
src/Text/Pandoc/Writers/OpenDocument.hs+50−54
@@ -1,4 +1,5 @@
1{-# LANGUAGE FlexibleContexts #-}
1{-# LANGUAGE FlexibleContexts #-}
2+{-# LANGUAGE LambdaCase #-}
2{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE PatternGuards #-}
4{-# LANGUAGE PatternGuards #-}
4{-# LANGUAGE ViewPatterns #-}
5{-# LANGUAGE ViewPatterns #-}
@@ -25,7 +26,7 @@ import Data.Ord (comparing)
25import qualified Data.Set as Set
26import qualified Data.Set as Set
26import Data.Text (Text)
27import Data.Text (Text)
27import qualified Data.Text as T
28import qualified Data.Text as T
28−import Text.Pandoc.BCP47 (Lang (..), parseBCP47)
29+import Text.Collate.Lang (Lang (..), parseLang)
29import Text.Pandoc.Class.PandocMonad (PandocMonad, report, translateTerm,
30import Text.Pandoc.Class.PandocMonad (PandocMonad, report, translateTerm,
30 setTranslations, toLang)
31 setTranslations, toLang)
31import Text.Pandoc.Definition
32import Text.Pandoc.Definition
@@ -236,7 +237,7 @@ handleSpaces s = case T.uncons s of
236-- | Convert Pandoc document to string in OpenDocument format.
237-- | Convert Pandoc document to string in OpenDocument format.
237writeOpenDocument :: PandocMonad m => WriterOptions -> Pandoc -> m Text
238writeOpenDocument :: PandocMonad m => WriterOptions -> Pandoc -> m Text
238writeOpenDocument opts (Pandoc meta blocks) = do
239writeOpenDocument opts (Pandoc meta blocks) = do
239− let defLang = Lang "en" "US" "" []
240+ let defLang = Lang "en" (Just "US") Nothing [] [] []
240 lang <- case lookupMetaString "lang" meta of
241 lang <- case lookupMetaString "lang" meta of
241 "" -> pure defLang
242 "" -> pure defLang
242 s -> fromMaybe defLang <$> toLang (Just s)
243 s -> fromMaybe defLang <$> toLang (Just s)
@@ -372,36 +373,32 @@ blocksToOpenDocument o b = vcat <$> mapM (blockToOpenDocument o) b
372
373
373-- | Convert a Pandoc block element to OpenDocument.
374-- | Convert a Pandoc block element to OpenDocument.
374blockToOpenDocument :: PandocMonad m => WriterOptions -> Block -> OD m (Doc Text)
375blockToOpenDocument :: PandocMonad m => WriterOptions -> Block -> OD m (Doc Text)
375−blockToOpenDocument o bs
376+blockToOpenDocument o = \case
376− | Plain b <- bs = if null b
377+ Plain b -> if null b
377− then return empty
378+ then return empty
378− else inParagraphTags =<< inlinesToOpenDocument o b
379+ else inParagraphTags =<< inlinesToOpenDocument o b
379− | Para [Image attr c (s,T.stripPrefix "fig:" -> Just t)] <- bs
380+ Para [Image attr c (s,T.stripPrefix "fig:" -> Just t)] -> figure attr c s t
380− = figure attr c s t
381− | Para b <- bs = if null b &&
381+ Para b -> if null b &&
382− not (isEnabled Ext_empty_paragraphs o)
382+ not (isEnabled Ext_empty_paragraphs o)
383− then return empty
383+ then return empty
384− else inParagraphTags =<< inlinesToOpenDocument o b
384+ else inParagraphTags =<< inlinesToOpenDocument o b
385− | LineBlock b <- bs = blockToOpenDocument o $ linesToPara b
385+ LineBlock b -> blockToOpenDocument o $ linesToPara b
386− | Div attr xs <- bs = mkDiv attr xs
386+ Div attr xs -> mkDiv attr xs
387− | Header i (ident,_,_) b
387+ Header i (ident,_,_) b -> do
388− <- bs = setFirstPara >> (inHeaderTags i ident
388+ setFirstPara
389− =<< inlinesToOpenDocument o b)
389+ inHeaderTags i ident =<< inlinesToOpenDocument o b
390− | BlockQuote b <- bs = setFirstPara >> mkBlockQuote b
390+ BlockQuote b -> setFirstPara >> mkBlockQuote b
391− | DefinitionList b <- bs = setFirstPara >> defList b
391+ DefinitionList b -> setFirstPara >> defList b
392− | BulletList b <- bs = setFirstPara >> bulletListToOpenDocument o b
392+ BulletList b -> setFirstPara >> bulletListToOpenDocument o b
393− | OrderedList a b <- bs = setFirstPara >> orderedList a b
393+ OrderedList a b -> setFirstPara >> orderedList a b
394− | CodeBlock _ s <- bs = setFirstPara >> preformatted s
394+ CodeBlock _ s -> setFirstPara >> preformatted s
395− | Table a bc s th tb tf <- bs = setFirstPara >> table (Ann.toTable a bc s th tb tf)
395+ Table a bc s th tb tf -> setFirstPara >> table (Ann.toTable a bc s th tb tf)
396− | HorizontalRule <- bs = setFirstPara >> return (selfClosingTag "text:p"
396+ HorizontalRule -> setFirstPara >> return (selfClosingTag "text:p"
397− [ ("text:style-name", "Horizontal_20_Line") ])
397+ [ ("text:style-name", "Horizontal_20_Line") ])
398− | RawBlock f s <- bs = if f == Format "opendocument"
398+ b@(RawBlock f s) -> if f == Format "opendocument"
399− then return $ text $ T.unpack s
399+ then return $ text $ T.unpack s
400− else do
401− report $ BlockNotRendered bs
400+ else empty <$ report (BlockNotRendered b)
402− return empty
403− | Null <- bs = return empty
404− | otherwise = return empty
401+ Null -> return empty
405 where
402 where
406 defList b = do setInDefinitionList True
403 defList b = do setInDefinitionList True
407 r <- vcat <$> mapM (deflistItemToOpenDocument o) b
404 r <- vcat <$> mapM (deflistItemToOpenDocument o) b
@@ -874,34 +871,33 @@ data TextStyle = Italic
874textStyleAttr :: Map.Map Text Text
871textStyleAttr :: Map.Map Text Text
875 -> TextStyle
872 -> TextStyle
876 -> Map.Map Text Text
873 -> Map.Map Text Text
877−textStyleAttr m s
874+textStyleAttr m = \case
878− | Italic <- s = Map.insert "fo:font-style" "italic" .
875+ Italic -> Map.insert "fo:font-style" "italic" .
879− Map.insert "style:font-style-asian" "italic" .
876+ Map.insert "style:font-style-asian" "italic" .
880− Map.insert "style:font-style-complex" "italic" $ m
877+ Map.insert "style:font-style-complex" "italic" $ m
881− | Bold <- s = Map.insert "fo:font-weight" "bold" .
878+ Bold -> Map.insert "fo:font-weight" "bold" .
882− Map.insert "style:font-weight-asian" "bold" .
879+ Map.insert "style:font-weight-asian" "bold" .
883− Map.insert "style:font-weight-complex" "bold" $ m
880+ Map.insert "style:font-weight-complex" "bold" $ m
884− | Under <- s = Map.insert "style:text-underline-style" "solid" .
881+ Under -> Map.insert "style:text-underline-style" "solid" .
885− Map.insert "style:text-underline-width" "auto" .
882+ Map.insert "style:text-underline-width" "auto" .
886− Map.insert "style:text-underline-color" "font-color" $ m
883+ Map.insert "style:text-underline-color" "font-color" $ m
887− | Strike <- s = Map.insert "style:text-line-through-style" "solid" m
884+ Strike -> Map.insert "style:text-line-through-style" "solid" m
888− | Sub <- s = Map.insert "style:text-position" "sub 58%" m
885+ Sub -> Map.insert "style:text-position" "sub 58%" m
889− | Sup <- s = Map.insert "style:text-position" "super 58%" m
886+ Sup -> Map.insert "style:text-position" "super 58%" m
890− | SmallC <- s = Map.insert "fo:font-variant" "small-caps" m
887+ SmallC -> Map.insert "fo:font-variant" "small-caps" m
891− | Pre <- s = Map.insert "style:font-name" "Courier New" .
888+ Pre -> Map.insert "style:font-name" "Courier New" .
892− Map.insert "style:font-name-asian" "Courier New" .
889+ Map.insert "style:font-name-asian" "Courier New" .
893− Map.insert "style:font-name-complex" "Courier New" $ m
890+ Map.insert "style:font-name-complex" "Courier New" $ m
894− | Language lang <- s
891+ Language lang ->
895− = Map.insert "fo:language" (langLanguage lang) .
892+ Map.insert "fo:language" (langLanguage lang) .
896− Map.insert "fo:country" (langRegion lang) $ m
893+ maybe id (Map.insert "fo:country") (langRegion lang) $ m
897− | otherwise = m
898
894
899withLangFromAttr :: PandocMonad m => Attr -> OD m a -> OD m a
895withLangFromAttr :: PandocMonad m => Attr -> OD m a -> OD m a
900withLangFromAttr (_,_,kvs) action =
896withLangFromAttr (_,_,kvs) action =
901 case lookup "lang" kvs of
897 case lookup "lang" kvs of
902 Nothing -> action
898 Nothing -> action
903 Just l ->
899 Just l ->
904− case parseBCP47 l of
900+ case parseLang l of
905 Right lang -> withTextStyle (Language lang) action
901 Right lang -> withTextStyle (Language lang) action
906 Left _ -> do
902 Left _ -> do
907 report $ InvalidLang l
903 report $ InvalidLang l
src/Text/Pandoc/Writers/Org.hs+16−10
@@ -19,6 +19,7 @@ module Text.Pandoc.Writers.Org (writeOrg) where
19import Control.Monad.State.Strict
19import Control.Monad.State.Strict
20import Data.Char (isAlphaNum, isDigit)
20import Data.Char (isAlphaNum, isDigit)
21import Data.List (intersect, intersperse, partition, transpose)
21import Data.List (intersect, intersperse, partition, transpose)
22+import Data.List.NonEmpty (nonEmpty)
22import Data.Text (Text)
23import Data.Text (Text)
23import qualified Data.Text as T
24import qualified Data.Text as T
24import Text.Pandoc.Class.PandocMonad (PandocMonad, report)
25import Text.Pandoc.Class.PandocMonad (PandocMonad, report)
@@ -83,12 +84,15 @@ noteToOrg num note = do
83
84
84-- | Escape special characters for Org.
85-- | Escape special characters for Org.
85escapeString :: Text -> Text
86escapeString :: Text -> Text
86−escapeString = escapeStringUsing
87+escapeString t
88+ | T.all (\c -> c < '\x2013' || c > '\x2026') t = t
89+ | otherwise = T.concatMap escChar t
90+ where
91+ escChar '\x2013' = "--"
87− [ ('\x2014',"---")
92+ escChar '\x2014' = "---"
88− , ('\x2013',"--")
89− , ('\x2019',"'")
93+ escChar '\x2019' = "'"
90− , ('\x2026',"...")
94+ escChar '\x2026' = "..."
91− ]
95+ escChar c = T.singleton c
92
96
93isRawFormat :: Format -> Bool
97isRawFormat :: Format -> Bool
94isRawFormat f =
98isRawFormat f =
@@ -163,7 +167,7 @@ blockToOrg (Table _ blkCapt specs thead tbody tfoot) = do
163 else "#+caption: " <> caption''
167 else "#+caption: " <> caption''
164 headers' <- mapM blockListToOrg headers
168 headers' <- mapM blockListToOrg headers
165 rawRows <- mapM (mapM blockListToOrg) rows
169 rawRows <- mapM (mapM blockListToOrg) rows
166− let numChars = maximum . map offset
170+ let numChars = maybe 0 maximum . nonEmpty . map offset
167 -- FIXME: width is not being used.
171 -- FIXME: width is not being used.
168 let widthsInChars =
172 let widthsInChars =
169 map numChars $ transpose (headers' : rawRows)
173 map numChars $ transpose (headers' : rawRows)
@@ -198,7 +202,7 @@ blockToOrg (OrderedList (start, _, delim) items) = do
198 x -> x
202 x -> x
199 let markers = take (length items) $ orderedListMarkers
203 let markers = take (length items) $ orderedListMarkers
200 (start, Decimal, delim')
204 (start, Decimal, delim')
201− let maxMarkerLength = maximum $ map T.length markers
205+ let maxMarkerLength = maybe 0 maximum . nonEmpty $ map T.length markers
202 let markers' = map (\m -> let s = maxMarkerLength - T.length m
206 let markers' = map (\m -> let s = maxMarkerLength - T.length m
203 in m <> T.replicate s " ") markers
207 in m <> T.replicate s " ") markers
204 contents <- zipWithM orderedListItemToOrg markers' items
208 contents <- zipWithM orderedListItemToOrg markers' items
@@ -400,9 +404,11 @@ inlineToOrg (Str str) = return . literal $ escapeString str
400inlineToOrg (Math t str) = do
404inlineToOrg (Math t str) = do
401 modify $ \st -> st{ stHasMath = True }
405 modify $ \st -> st{ stHasMath = True }
402 return $ if t == InlineMath
406 return $ if t == InlineMath
403− then "$" <> literal str <> "$"
407+ then "\\(" <> literal str <> "\\)"
404− else "$$" <> literal str <> "$$"
408+ else "\\[" <> literal str <> "\\]"
405inlineToOrg il@(RawInline f str)
409inlineToOrg il@(RawInline f str)
410+ | elem f ["tex", "latex"] && T.isPrefixOf "\\begin" str =
411+ return $ cr <> literal str <> cr
406 | isRawFormat f = return $ literal str
412 | isRawFormat f = return $ literal str
407 | otherwise = do
413 | otherwise = do
408 report $ InlineNotRendered il
414 report $ InlineNotRendered il
src/Text/Pandoc/Writers/Powerpoint.hs+1−1
@@ -39,5 +39,5 @@ writePowerpoint opts (Pandoc meta blks) = do
39 let blks' = walk fixDisplayMath blks
39 let blks' = walk fixDisplayMath blks
40 let (pres, logMsgs) = documentToPresentation opts (Pandoc meta blks')
40 let (pres, logMsgs) = documentToPresentation opts (Pandoc meta blks')
41 mapM_ report logMsgs
41 mapM_ report logMsgs
42− archv <- presentationToArchive opts pres
42+ archv <- presentationToArchive opts meta pres
43 return $ fromArchive archv
43 return $ fromArchive archv
src/Text/Pandoc/Writers/Powerpoint/Output.hs+43−31
@@ -38,18 +38,21 @@ import qualified Text.Pandoc.Class.PandocMonad as P
38import Text.Pandoc.Options
38import Text.Pandoc.Options
39import Text.Pandoc.MIME
39import Text.Pandoc.MIME
40import qualified Data.ByteString.Lazy as BL
40import qualified Data.ByteString.Lazy as BL
41+import Text.Pandoc.Writers.Shared (metaToContext)
41import Text.Pandoc.Writers.OOXML
42import Text.Pandoc.Writers.OOXML
42import qualified Data.Map as M
43import qualified Data.Map as M
43import Data.Maybe (mapMaybe, listToMaybe, fromMaybe, maybeToList, catMaybes, isJust)
44import Data.Maybe (mapMaybe, listToMaybe, fromMaybe, maybeToList, catMaybes, isJust)
44import Text.Pandoc.ImageSize
45import Text.Pandoc.ImageSize
45import Control.Applicative ((<|>))
46import Control.Applicative ((<|>))
46import System.FilePath.Glob
47import System.FilePath.Glob
47−import Text.DocTemplates (FromContext(lookupContext))
48+import Text.DocTemplates (FromContext(lookupContext), Context)
49+import Text.DocLayout (literal)
48import Text.TeXMath
50import Text.TeXMath
49import Text.Pandoc.Writers.Math (convertMath)
51import Text.Pandoc.Writers.Math (convertMath)
50import Text.Pandoc.Writers.Powerpoint.Presentation
52import Text.Pandoc.Writers.Powerpoint.Presentation
51−import Text.Pandoc.Shared (tshow)
53+import Text.Pandoc.Shared (tshow, stringify)
52import Skylighting (fromColor)
54import Skylighting (fromColor)
55+import Data.List.NonEmpty (nonEmpty)
53
56
54-- |The 'EMU' type is used to specify sizes in English Metric Units.
57-- |The 'EMU' type is used to specify sizes in English Metric Units.
55type EMU = Integer
58type EMU = Integer
@@ -96,6 +99,7 @@ data WriterEnv = WriterEnv { envRefArchive :: Archive
96 , envDistArchive :: Archive
99 , envDistArchive :: Archive
97 , envUTCTime :: UTCTime
100 , envUTCTime :: UTCTime
98 , envOpts :: WriterOptions
101 , envOpts :: WriterOptions
102+ , envContext :: Context Text
99 , envPresentationSize :: (Integer, Integer)
103 , envPresentationSize :: (Integer, Integer)
100 , envSlideHasHeader :: Bool
104 , envSlideHasHeader :: Bool
101 , envInList :: Bool
105 , envInList :: Bool
@@ -121,6 +125,7 @@ instance Default WriterEnv where
121 , envDistArchive = emptyArchive
125 , envDistArchive = emptyArchive
122 , envUTCTime = posixSecondsToUTCTime 0
126 , envUTCTime = posixSecondsToUTCTime 0
123 , envOpts = def
127 , envOpts = def
128+ , envContext = mempty
124 , envPresentationSize = (720, 540)
129 , envPresentationSize = (720, 540)
125 , envSlideHasHeader = False
130 , envSlideHasHeader = False
126 , envInList = False
131 , envInList = False
@@ -167,7 +172,7 @@ runP env st p = evalStateT (runReaderT p env) st
167
172
168monospaceFont :: Monad m => P m T.Text
173monospaceFont :: Monad m => P m T.Text
169monospaceFont = do
174monospaceFont = do
170− vars <- writerVariables <$> asks envOpts
175+ vars <- asks envContext
171 case lookupContext "monofont" vars of
176 case lookupContext "monofont" vars of
172 Just s -> return s
177 Just s -> return s
173 Nothing -> return "Courier"
178 Nothing -> return "Courier"
@@ -303,8 +308,9 @@ makeSpeakerNotesMap (Presentation _ slides) =
303 then Nothing
308 then Nothing
304 else Just n
309 else Just n
305
310
306−presentationToArchive :: PandocMonad m => WriterOptions -> Presentation -> m Archive
311+presentationToArchive :: PandocMonad m
312+ => WriterOptions -> Meta -> Presentation -> m Archive
307−presentationToArchive opts pres = do
313+presentationToArchive opts meta pres = do
308 distArchive <- toArchive . BL.fromStrict <$>
314 distArchive <- toArchive . BL.fromStrict <$>
309 P.readDefaultDataFile "reference.pptx"
315 P.readDefaultDataFile "reference.pptx"
310 refArchive <- case writerReferenceDoc opts of
316 refArchive <- case writerReferenceDoc opts of
@@ -320,10 +326,18 @@ presentationToArchive opts pres = do
320 PandocSomeError
326 PandocSomeError
321 "Could not determine presentation size"
327 "Could not determine presentation size"
322
328
329+ -- note, we need writerTemplate to be Just _ or metaToContext does
330+ -- nothing
331+ context <- metaToContext opts{ writerTemplate =
332+ writerTemplate opts <|> Just mempty }
333+ (return . literal . stringify)
334+ (return . literal . stringify) meta
335+
323 let env = def { envRefArchive = refArchive
336 let env = def { envRefArchive = refArchive
324 , envDistArchive = distArchive
337 , envDistArchive = distArchive
325 , envUTCTime = utctime
338 , envUTCTime = utctime
326 , envOpts = opts
339 , envOpts = opts
340+ , envContext = context
327 , envPresentationSize = presSize
341 , envPresentationSize = presSize
328 , envSlideIdMap = makeSlideIdMap pres
342 , envSlideIdMap = makeSlideIdMap pres
329 , envSpeakerNotesIdMap = makeSpeakerNotesMap pres
343 , envSpeakerNotesIdMap = makeSpeakerNotesMap pres
@@ -474,15 +488,16 @@ registerLink link = do
474 linkReg <- gets stLinkIds
488 linkReg <- gets stLinkIds
475 mediaReg <- gets stMediaIds
489 mediaReg <- gets stMediaIds
476 hasSpeakerNotes <- curSlideHasSpeakerNotes
490 hasSpeakerNotes <- curSlideHasSpeakerNotes
477− let maxLinkId = case M.lookup curSlideId linkReg of
491+ let maxLinkId = case M.lookup curSlideId linkReg >>= nonEmpty . M.keys of
478− Just mp -> case M.keys mp of
479− [] -> if hasSpeakerNotes then 2 else 1
480− ks -> maximum ks
492+ Just xs -> maximum xs
493+ Nothing
481− Nothing -> if hasSpeakerNotes then 2 else 1
494+ | hasSpeakerNotes -> 2
495+ | otherwise -> 1
482− maxMediaId = case M.lookup curSlideId mediaReg of
496+ maxMediaId = case M.lookup curSlideId mediaReg >>= nonEmpty of
483− Just [] -> if hasSpeakerNotes then 2 else 1
484− Just mInfos -> maximum $ map mInfoLocalId mInfos
497+ Just mInfos -> maximum $ fmap mInfoLocalId mInfos
498+ Nothing
485− Nothing -> if hasSpeakerNotes then 2 else 1
499+ | hasSpeakerNotes -> 2
500+ | otherwise -> 1
486 maxId = max maxLinkId maxMediaId
501 maxId = max maxLinkId maxMediaId
487 slideLinks = case M.lookup curSlideId linkReg of
502 slideLinks = case M.lookup curSlideId linkReg of
488 Just mp -> M.insert (maxId + 1) link mp
503 Just mp -> M.insert (maxId + 1) link mp
@@ -497,20 +512,19 @@ registerMedia fp caption = do
497 mediaReg <- gets stMediaIds
512 mediaReg <- gets stMediaIds
498 globalIds <- gets stMediaGlobalIds
513 globalIds <- gets stMediaGlobalIds
499 hasSpeakerNotes <- curSlideHasSpeakerNotes
514 hasSpeakerNotes <- curSlideHasSpeakerNotes
500− let maxLinkId = case M.lookup curSlideId linkReg of
515+ let maxLinkId = case M.lookup curSlideId linkReg >>= nonEmpty . M.keys of
501− Just mp -> case M.keys mp of
502− [] -> if hasSpeakerNotes then 2 else 1
503− ks -> maximum ks
516+ Just ks -> maximum ks
517+ Nothing
504− Nothing -> if hasSpeakerNotes then 2 else 1
518+ | hasSpeakerNotes -> 2
519+ | otherwise -> 1
505− maxMediaId = case M.lookup curSlideId mediaReg of
520+ maxMediaId = case M.lookup curSlideId mediaReg >>= nonEmpty of
506− Just [] -> if hasSpeakerNotes then 2 else 1
507− Just mInfos -> maximum $ map mInfoLocalId mInfos
521+ Just mInfos -> maximum $ fmap mInfoLocalId mInfos
522+ Nothing
508− Nothing -> if hasSpeakerNotes then 2 else 1
523+ | hasSpeakerNotes -> 2
524+ | otherwise -> 1
509 maxLocalId = max maxLinkId maxMediaId
525 maxLocalId = max maxLinkId maxMediaId
510
526
511− maxGlobalId = case M.elems globalIds of
527+ maxGlobalId = maybe 0 maximum $ nonEmpty $ M.elems globalIds
512− [] -> 0
513− ids -> maximum ids
514
528
515 (imgBytes, mbMt) <- P.fetchItem $ T.pack fp
529 (imgBytes, mbMt) <- P.fetchItem $ T.pack fp
516 let imgExt = (mbMt >>= extensionFromMimeType >>= (\x -> return $ "." <> x))
530 let imgExt = (mbMt >>= extensionFromMimeType >>= (\x -> return $ "." <> x))
@@ -523,6 +537,7 @@ registerMedia fp caption = do
523 Just Eps -> Just ".eps"
537 Just Eps -> Just ".eps"
524 Just Svg -> Just ".svg"
538 Just Svg -> Just ".svg"
525 Just Emf -> Just ".emf"
539 Just Emf -> Just ".emf"
540+ Just Tiff -> Just ".tiff"
526 Nothing -> Nothing
541 Nothing -> Nothing
527
542
528 let newGlobalId = fromMaybe (maxGlobalId + 1) (M.lookup fp globalIds)
543 let newGlobalId = fromMaybe (maxGlobalId + 1) (M.lookup fp globalIds)
@@ -1427,11 +1442,8 @@ presentationToRels pres@(Presentation _ slides) = do
1427 -- all relWithoutSlide rels (unless they're 1)
1442 -- all relWithoutSlide rels (unless they're 1)
1428 -- 3. If we have a notesmaster slide, we make space for that as well.
1443 -- 3. If we have a notesmaster slide, we make space for that as well.
1429
1444
1445+ let minRelNotOne = maybe 0 minimum $ nonEmpty
1430− let minRelNotOne = case filter (1<) $ map relId relsWeKeep of
1446+ $ filter (1 <) $ map relId relsWeKeep
1431− [] -> 0 -- doesn't matter in this case, since
1432− -- there will be nothing to map the
1433− -- function over
1434− l -> minimum l
1435
1447
1436 modifyRelNum :: Int -> Int
1448 modifyRelNum :: Int -> Int
1437 modifyRelNum 1 = 1
1449 modifyRelNum 1 = 1
src/Text/Pandoc/Writers/Powerpoint/Presentation.hs+2−3
@@ -45,6 +45,7 @@ module Text.Pandoc.Writers.Powerpoint.Presentation ( documentToPresentation
45import Control.Monad.Reader
45import Control.Monad.Reader
46import Control.Monad.State
46import Control.Monad.State
47import Data.List (intercalate)
47import Data.List (intercalate)
48+import Data.List.NonEmpty (nonEmpty)
48import Data.Default
49import Data.Default
49import Text.Pandoc.Definition
50import Text.Pandoc.Definition
50import Text.Pandoc.ImageSize
51import Text.Pandoc.ImageSize
@@ -363,9 +364,7 @@ inlineToParElems (Note blks) = do
363 then return []
364 then return []
364 else do
365 else do
365 notes <- gets stNoteIds
366 notes <- gets stNoteIds
366− let maxNoteId = case M.keys notes of
367+ let maxNoteId = maybe 0 maximum $ nonEmpty $ M.keys notes
367− [] -> 0
368− lst -> maximum lst
369 curNoteId = maxNoteId + 1
368 curNoteId = maxNoteId + 1
370 modify $ \st -> st { stNoteIds = M.insert curNoteId blks notes }
369 modify $ \st -> st { stNoteIds = M.insert curNoteId blks notes }
371 local (\env -> env{envRunProps = (envRunProps env){rLink = Just $ InternalTarget endNotesSlideId}}) $
370 local (\env -> env{envRunProps = (envRunProps env){rLink = Just $ InternalTarget endNotesSlideId}}) $
src/Text/Pandoc/Writers/RST.hs+12−8
@@ -17,6 +17,7 @@ module Text.Pandoc.Writers.RST ( writeRST, flatten ) where
17import Control.Monad.State.Strict
17import Control.Monad.State.Strict
18import Data.Char (isSpace)
18import Data.Char (isSpace)
19import Data.List (transpose, intersperse, foldl')
19import Data.List (transpose, intersperse, foldl')
20+import qualified Data.List.NonEmpty as NE
20import Data.Maybe (fromMaybe)
21import Data.Maybe (fromMaybe)
21import qualified Data.Text as T
22import qualified Data.Text as T
22import Data.Text (Text)
23import Data.Text (Text)
@@ -335,7 +336,7 @@ blockToRST (OrderedList (start, style', delim) items) = do
335 then replicate (length items) "#."
336 then replicate (length items) "#."
336 else take (length items) $ orderedListMarkers
337 else take (length items) $ orderedListMarkers
337 (start, style', delim)
338 (start, style', delim)
338− let maxMarkerLength = maximum $ map T.length markers
339+ let maxMarkerLength = maybe 0 maximum $ NE.nonEmpty $ map T.length markers
339 let markers' = map (\m -> let s = maxMarkerLength - T.length m
340 let markers' = map (\m -> let s = maxMarkerLength - T.length m
340 in m <> T.replicate s " ") markers
341 in m <> T.replicate s " ") markers
341 contents <- zipWithM orderedListItemToRST markers' items
342 contents <- zipWithM orderedListItemToRST markers' items
@@ -537,11 +538,15 @@ flatten outer
537 collapse f i = appendToLast f $ dropInlineParent i
538 collapse f i = appendToLast f $ dropInlineParent i
538
539
539 appendToLast :: [Inline] -> [Inline] -> [Inline]
540 appendToLast :: [Inline] -> [Inline] -> [Inline]
541+ appendToLast flattened toAppend =
542+ case NE.nonEmpty flattened of
540− appendToLast [] toAppend = [setInlineChildren outer toAppend]
543+ Nothing -> [setInlineChildren outer toAppend]
541− appendToLast flattened toAppend
544+ Just xs ->
545+ if isOuter lastFlat
542− | isOuter lastFlat = init flattened <> [appendTo lastFlat toAppend]
546+ then NE.init xs <> [appendTo lastFlat toAppend]
543− | otherwise = flattened <> [setInlineChildren outer toAppend]
547+ else flattened <> [setInlineChildren outer toAppend]
548+ where
544− where lastFlat = last flattened
549+ lastFlat = NE.last xs
545 appendTo o i = mapNested (<> i) o
550 appendTo o i = mapNested (<> i) o
546 isOuter i = emptyParent i == emptyParent outer
551 isOuter i = emptyParent i == emptyParent outer
547 emptyParent i = setInlineChildren i []
552 emptyParent i = setInlineChildren i []
@@ -761,8 +766,7 @@ simpleTable opts blocksToDoc headers rows = do
761 then return []
766 then return []
762 else fixEmpties <$> mapM (blocksToDoc opts) headers
767 else fixEmpties <$> mapM (blocksToDoc opts) headers
763 rowDocs <- mapM (fmap fixEmpties . mapM (blocksToDoc opts)) rows
768 rowDocs <- mapM (fmap fixEmpties . mapM (blocksToDoc opts)) rows
764− let numChars [] = 0
765− numChars xs = maximum . map offset $ xs
769+ let numChars = maybe 0 maximum . NE.nonEmpty . map offset
766 let colWidths = map numChars $ transpose (headerDocs : rowDocs)
770 let colWidths = map numChars $ transpose (headerDocs : rowDocs)
767 let toRow = mconcat . intersperse (lblock 1 " ") . zipWith lblock colWidths
771 let toRow = mconcat . intersperse (lblock 1 " ") . zipWith lblock colWidths
768 let hline = nowrap $ hsep (map (\n -> literal (T.replicate n "=")) colWidths)
772 let hline = nowrap $ hsep (map (\n -> literal (T.replicate n "=")) colWidths)
src/Text/Pandoc/Writers/RTF.hs+16−10
@@ -16,7 +16,7 @@ module Text.Pandoc.Writers.RTF ( writeRTF
16import Control.Monad.Except (catchError, throwError)
16import Control.Monad.Except (catchError, throwError)
17import Control.Monad
17import Control.Monad
18import qualified Data.ByteString as B
18import qualified Data.ByteString as B
19−import Data.Char (chr, isDigit, ord)
19+import Data.Char (chr, isDigit, ord, isAlphaNum)
20import qualified Data.Map as M
20import qualified Data.Map as M
21import Data.Text (Text)
21import Data.Text (Text)
22import qualified Data.Text as T
22import qualified Data.Text as T
@@ -137,15 +137,21 @@ handleUnicode = T.concatMap $ \c ->
137
137
138-- | Escape special characters.
138-- | Escape special characters.
139escapeSpecial :: Text -> Text
139escapeSpecial :: Text -> Text
140−escapeSpecial = escapeStringUsing $
140+escapeSpecial t
141+ | T.all isAlphaNum t = t
142+ | otherwise = T.concatMap escChar t
143+ where
141− [ ('\t',"\\tab ")
144+ escChar '\t' = "\\tab "
142− , ('\8216',"\\u8216'")
145+ escChar '\8216' = "\\u8216'"
143− , ('\8217',"\\u8217'")
146+ escChar '\8217' = "\\u8217'"
144− , ('\8220',"\\u8220\"")
147+ escChar '\8220' = "\\u8220\""
145− , ('\8221',"\\u8221\"")
148+ escChar '\8221' = "\\u8221\""
146− , ('\8211',"\\u8211-")
149+ escChar '\8211' = "\\u8211-"
147− , ('\8212',"\\u8212-")
150+ escChar '\8212' = "\\u8212-"
148− ] <> backslashEscapes "{\\}"
151+ escChar '{' = "\\{"
152+ escChar '}' = "\\}"
153+ escChar '\\' = "\\\\"
154+ escChar c = T.singleton c
149
155
150-- | Escape strings as needed for rich text format.
156-- | Escape strings as needed for rich text format.
151stringToRTF :: Text -> Text
157stringToRTF :: Text -> Text
src/Text/Pandoc/Writers/Shared.hs+18−3
@@ -20,6 +20,7 @@ module Text.Pandoc.Writers.Shared (
20 , setField
20 , setField
21 , resetField
21 , resetField
22 , defField
22 , defField
23+ , getLang
23 , tagWithAttrs
24 , tagWithAttrs
24 , isDisplayMath
25 , isDisplayMath
25 , fixDisplayMath
26 , fixDisplayMath
@@ -44,6 +45,7 @@ import Control.Monad (zipWithM)
44import Data.Aeson (ToJSON (..), encode)
45import Data.Aeson (ToJSON (..), encode)
45import Data.Char (chr, ord, isSpace)
46import Data.Char (chr, ord, isSpace)
46import Data.List (groupBy, intersperse, transpose, foldl')
47import Data.List (groupBy, intersperse, transpose, foldl')
48+import Data.List.NonEmpty (NonEmpty(..), nonEmpty)
47import Data.Text.Conversions (FromText(..))
49import Data.Text.Conversions (FromText(..))
48import qualified Data.Map as M
50import qualified Data.Map as M
49import qualified Data.Text as T
51import qualified Data.Text as T
@@ -146,6 +148,19 @@ defField field val (Context m) =
146 where
148 where
147 f _newval oldval = oldval
149 f _newval oldval = oldval
148
150
151+-- | Get the contents of the `lang` metadata field or variable.
152+getLang :: WriterOptions -> Meta -> Maybe T.Text
153+getLang opts meta =
154+ case lookupContext "lang" (writerVariables opts) of
155+ Just s -> Just s
156+ _ ->
157+ case lookupMeta "lang" meta of
158+ Just (MetaBlocks [Para [Str s]]) -> Just s
159+ Just (MetaBlocks [Plain [Str s]]) -> Just s
160+ Just (MetaInlines [Str s]) -> Just s
161+ Just (MetaString s) -> Just s
162+ _ -> Nothing
163+
149-- | Produce an HTML tag with the given pandoc attributes.
164-- | Produce an HTML tag with the given pandoc attributes.
150tagWithAttrs :: HasChars a => T.Text -> Attr -> Doc a
165tagWithAttrs :: HasChars a => T.Text -> Attr -> Doc a
151tagWithAttrs tag (ident,classes,kvs) = hsep
166tagWithAttrs tag (ident,classes,kvs) = hsep
@@ -224,7 +239,7 @@ gridTable :: (Monad m, HasChars a)
224 -> m (Doc a)
239 -> m (Doc a)
225gridTable opts blocksToDoc headless aligns widths headers rows = do
240gridTable opts blocksToDoc headless aligns widths headers rows = do
226 -- the number of columns will be used in case of even widths
241 -- the number of columns will be used in case of even widths
227− let numcols = maximum (length aligns : length widths :
242+ let numcols = maximum (length aligns :| length widths :
228 map length (headers:rows))
243 map length (headers:rows))
229 let officialWidthsInChars widths' = map (
244 let officialWidthsInChars widths' = map (
230 (\x -> if x < 1 then 1 else x) .
245 (\x -> if x < 1 then 1 else x) .
@@ -253,8 +268,7 @@ gridTable opts blocksToDoc headless aligns widths headers rows = do
253 let handleFullWidths widths' = do
268 let handleFullWidths widths' = do
254 rawHeaders' <- mapM (blocksToDoc opts) headers
269 rawHeaders' <- mapM (blocksToDoc opts) headers
255 rawRows' <- mapM (mapM (blocksToDoc opts)) rows
270 rawRows' <- mapM (mapM (blocksToDoc opts)) rows
256− let numChars [] = 0
257− numChars xs = maximum . map offset $ xs
271+ let numChars = maybe 0 maximum . nonEmpty . map offset
258 let minWidthsInChars =
272 let minWidthsInChars =
259 map numChars $ transpose (rawHeaders' : rawRows')
273 map numChars $ transpose (rawHeaders' : rawRows')
260 let widthsInChars' = zipWith max
274 let widthsInChars' = zipWith max
@@ -380,6 +394,7 @@ toSuperscript '2' = Just '\x00B2'
380toSuperscript '3' = Just '\x00B3'
394toSuperscript '3' = Just '\x00B3'
381toSuperscript '+' = Just '\x207A'
395toSuperscript '+' = Just '\x207A'
382toSuperscript '-' = Just '\x207B'
396toSuperscript '-' = Just '\x207B'
397+toSuperscript '\x2212' = Just '\x207B' -- unicode minus
383toSuperscript '=' = Just '\x207C'
398toSuperscript '=' = Just '\x207C'
384toSuperscript '(' = Just '\x207D'
399toSuperscript '(' = Just '\x207D'
385toSuperscript ')' = Just '\x207E'
400toSuperscript ')' = Just '\x207E'
src/Text/Pandoc/Writers/TEI.hs+4−3
@@ -146,16 +146,17 @@ blockToTEI opts (LineBlock lns) =
146 blockToTEI opts $ linesToPara lns
146 blockToTEI opts $ linesToPara lns
147blockToTEI opts (BlockQuote blocks) =
147blockToTEI opts (BlockQuote blocks) =
148 inTagsIndented "quote" <$> blocksToTEI opts blocks
148 inTagsIndented "quote" <$> blocksToTEI opts blocks
149−blockToTEI _ (CodeBlock (_,classes,_) str) =
149+blockToTEI opts (CodeBlock (_,classes,_) str) =
150 return $ literal ("<ab type='codeblock " <> lang <> "'>") <> cr <>
150 return $ literal ("<ab type='codeblock " <> lang <> "'>") <> cr <>
151 flush (literal (escapeStringForXML str) <> cr <> text "</ab>")
151 flush (literal (escapeStringForXML str) <> cr <> text "</ab>")
152 where lang = if null langs
152 where lang = if null langs
153 then ""
153 then ""
154 else escapeStringForXML (head langs)
154 else escapeStringForXML (head langs)
155+ syntaxMap = writerSyntaxMap opts
155− isLang l = T.toLower l `elem` map T.toLower languages
156+ isLang l = T.toLower l `elem` map T.toLower (languages syntaxMap)
156 langsFrom s = if isLang s
157 langsFrom s = if isLang s
157 then [s]
158 then [s]
158− else languagesByExtension . T.toLower $ s
159+ else (languagesByExtension syntaxMap) . T.toLower $ s
159 langs = concatMap langsFrom classes
160 langs = concatMap langsFrom classes
160blockToTEI opts (BulletList lst) = do
161blockToTEI opts (BulletList lst) = do
161 let attribs = [("type", "unordered")]
162 let attribs = [("type", "unordered")]
src/Text/Pandoc/Writers/Texinfo.hs+20−13
@@ -14,8 +14,9 @@ Conversion of 'Pandoc' format into Texinfo.
14module Text.Pandoc.Writers.Texinfo ( writeTexinfo ) where
14module Text.Pandoc.Writers.Texinfo ( writeTexinfo ) where
15import Control.Monad.Except (throwError)
15import Control.Monad.Except (throwError)
16import Control.Monad.State.Strict
16import Control.Monad.State.Strict
17−import Data.Char (chr, ord)
17+import Data.Char (chr, ord, isAlphaNum)
18import Data.List (maximumBy, transpose, foldl')
18import Data.List (maximumBy, transpose, foldl')
19+import Data.List.NonEmpty (nonEmpty)
19import Data.Ord (comparing)
20import Data.Ord (comparing)
20import qualified Data.Set as Set
21import qualified Data.Set as Set
21import Data.Text (Text)
22import Data.Text (Text)
@@ -84,16 +85,18 @@ pandocToTexinfo options (Pandoc meta blocks) = do
84
85
85-- | Escape things as needed for Texinfo.
86-- | Escape things as needed for Texinfo.
86stringToTexinfo :: Text -> Text
87stringToTexinfo :: Text -> Text
87−stringToTexinfo = escapeStringUsing texinfoEscapes
88+stringToTexinfo t
88− where texinfoEscapes = [ ('{', "@{")
89+ | T.all isAlphaNum t = t
90+ | otherwise = T.concatMap escChar t
91+ where escChar '{' = "@{"
89− , ('}', "@}")
92+ escChar '}' = "@}"
90− , ('@', "@@")
93+ escChar '@' = "@@"
91− , ('\160', "@ ")
94+ escChar '\160' = "@ "
92− , ('\x2014', "---")
95+ escChar '\x2014' = "---"
93− , ('\x2013', "--")
96+ escChar '\x2013' = "--"
94− , ('\x2026', "@dots{}")
97+ escChar '\x2026' = "@dots{}"
95− , ('\x2019', "'")
98+ escChar '\x2019' = "'"
96− ]
99+ escChar c = T.singleton c
97
100
98escapeCommas :: PandocMonad m => TI m (Doc Text) -> TI m (Doc Text)
101escapeCommas :: PandocMonad m => TI m (Doc Text) -> TI m (Doc Text)
99escapeCommas parser = do
102escapeCommas parser = do
@@ -238,9 +241,13 @@ blockToTexinfo (Table _ blkCapt specs thead tbody tfoot) = do
238 colDescriptors <-
241 colDescriptors <-
239 if all (== 0) widths
242 if all (== 0) widths
240 then do -- use longest entry instead of column widths
243 then do -- use longest entry instead of column widths
241− cols <- mapM (mapM (liftM (T.unpack . render Nothing . hcat) . mapM blockToTexinfo)) $
244+ cols <- mapM (mapM (fmap (T.unpack . render Nothing . hcat) .
245+ mapM blockToTexinfo)) $
242 transpose $ heads : rows
246 transpose $ heads : rows
247+ return $ concatMap
248+ ((\x -> "{"++x++"} ") .
243− return $ concatMap ((\x -> "{"++x++"} ") . maximumBy (comparing length)) cols
249+ maybe "" (maximumBy (comparing length)) . nonEmpty)
250+ cols
244 else return $ "@columnfractions " ++ concatMap (printf "%.2f ") widths
251 else return $ "@columnfractions " ++ concatMap (printf "%.2f ") widths
245 let tableBody = text ("@multitable " ++ colDescriptors) $$
252 let tableBody = text ("@multitable " ++ colDescriptors) $$
246 headers $$
253 headers $$
src/Text/Pandoc/Writers/ZimWiki.hs+4−2
@@ -20,6 +20,7 @@ import Control.Monad (zipWithM)
20import Control.Monad.State.Strict (StateT, evalStateT, gets, modify)
20import Control.Monad.State.Strict (StateT, evalStateT, gets, modify)
21import Data.Default (Default (..))
21import Data.Default (Default (..))
22import Data.List (transpose)
22import Data.List (transpose)
23+import Data.List.NonEmpty (nonEmpty)
23import qualified Data.Map as Map
24import qualified Data.Map as Map
24import Text.DocLayout (render, literal)
25import Text.DocLayout (render, literal)
25import Data.Maybe (fromMaybe)
26import Data.Maybe (fromMaybe)
@@ -115,7 +116,7 @@ blockToZimWiki opts b@(RawBlock f str)
115blockToZimWiki _ HorizontalRule = return "\n----\n"
116blockToZimWiki _ HorizontalRule = return "\n----\n"
116
117
117blockToZimWiki opts (Header level _ inlines) = do
118blockToZimWiki opts (Header level _ inlines) = do
118− contents <- inlineListToZimWiki opts $ removeFormatting inlines -- emphasis, links etc. not allowed in headers
119+ contents <- inlineListToZimWiki opts inlines
119 let eqs = T.replicate ( 7 - level ) "="
120 let eqs = T.replicate ( 7 - level ) "="
120 return $ eqs <> " " <> contents <> " " <> eqs <> "\n"
121 return $ eqs <> " " <> contents <> " " <> eqs <> "\n"
121
122
@@ -143,7 +144,8 @@ blockToZimWiki opts (Table _ blkCapt specs thead tbody tfoot) = do
143 then zipWithM (tableItemToZimWiki opts) aligns (head rows)
144 then zipWithM (tableItemToZimWiki opts) aligns (head rows)
144 else mapM (inlineListToZimWiki opts . removeFormatting)headers -- emphasis, links etc. are not allowed in table headers
145 else mapM (inlineListToZimWiki opts . removeFormatting)headers -- emphasis, links etc. are not allowed in table headers
145 rows' <- mapM (zipWithM (tableItemToZimWiki opts) aligns) rows
146 rows' <- mapM (zipWithM (tableItemToZimWiki opts) aligns) rows
146− let widths = map (maximum . map T.length) $ transpose (headers':rows')
147+ let widths = map (maybe 0 maximum . nonEmpty . map T.length) $
148+ transpose (headers':rows')
147 let padTo (width, al) s =
149 let padTo (width, al) s =
148 case width - T.length s of
150 case width - T.length s of
149 x | x > 0 ->
151 x | x > 0 ->
src/Text/Pandoc/XML.hs+28−2
@@ -13,6 +13,7 @@ Functions for escaping and formatting XML.
13-}
13-}
14module Text.Pandoc.XML ( escapeCharForXML,
14module Text.Pandoc.XML ( escapeCharForXML,
15 escapeStringForXML,
15 escapeStringForXML,
16+ escapeNCName,
16 inTags,
17 inTags,
17 selfClosingTag,
18 selfClosingTag,
18 inTagsSimple,
19 inTagsSimple,
@@ -24,7 +25,7 @@ module Text.Pandoc.XML ( escapeCharForXML,
24 html5Attributes,
25 html5Attributes,
25 rdfaAttributes ) where
26 rdfaAttributes ) where
26
27
27−import Data.Char (isAscii, isSpace, ord)
28+import Data.Char (isAscii, isSpace, ord, isLetter, isDigit)
28import Data.Text (Text)
29import Data.Text (Text)
29import qualified Data.Text as T
30import qualified Data.Text as T
30import Text.HTML.TagSoup.Entity (lookupEntity, htmlEntities)
31import Text.HTML.TagSoup.Entity (lookupEntity, htmlEntities)
@@ -119,8 +120,33 @@ html5EntityMap = foldr go mempty htmlEntities
119 where ent' = T.takeWhile (/=';') (T.pack ent)
120 where ent' = T.takeWhile (/=';') (T.pack ent)
120 _ -> entmap
121 _ -> entmap
121
122
123+-- | Converts a string into an NCName, i.e., an XML name without colons.
124+-- Disallowed characters are escaped using @ux%x@, where @%x@ is the
125+-- hexadecimal unicode identifier of the escaped character.
126+escapeNCName :: Text -> Text
127+escapeNCName t = case T.uncons t of
128+ Nothing -> T.empty
129+ Just (c, cs) -> escapeStartChar c <> T.concatMap escapeNCNameChar cs
130+ where
131+ escapeStartChar :: Char -> Text
132+ escapeStartChar c = if isLetter c || c == '_'
133+ then T.singleton c
134+ else escapeChar c
122
135
136+ escapeNCNameChar :: Char -> Text
137+ escapeNCNameChar c = if isNCNameChar c
138+ then T.singleton c
139+ else escapeChar c
140+
141+ isNCNameChar :: Char -> Bool
142+ isNCNameChar c = isLetter c || c `elem` ("_-.·" :: String) || isDigit c
143+ || '\x0300' <= c && c <= '\x036f'
144+ || '\x203f' <= c && c <= '\x2040'
145+
146+ escapeChar :: Char -> Text
147+ escapeChar = T.pack . printf "U%04X" . ord
148+
123−-- Unescapes XML entities
149+-- | Unescapes XML entities
124fromEntities :: Text -> Text
150fromEntities :: Text -> Text
125fromEntities t
151fromEntities t
126 = let (x, y) = T.break (== '&') t
152 = let (x, y) = T.break (== '&') t
src/Text/Pandoc/XML/Light/Types.hs+4−4
@@ -53,7 +53,7 @@ type Line = Integer
53data Content = Elem Element
53data Content = Elem Element
54 | Text CData
54 | Text CData
55 | CRef Text
55 | CRef Text
56− deriving (Show, Typeable, Data)
56+ deriving (Show, Typeable, Data, Ord, Eq)
57
57
58-- | XML elements
58-- | XML elements
59data Element = Element {
59data Element = Element {
@@ -61,7 +61,7 @@ data Element = Element {
61 elAttribs :: [Attr],
61 elAttribs :: [Attr],
62 elContent :: [Content],
62 elContent :: [Content],
63 elLine :: Maybe Line
63 elLine :: Maybe Line
64− } deriving (Show, Typeable, Data)
64+ } deriving (Show, Typeable, Data, Ord, Eq)
65
65
66-- | XML attributes
66-- | XML attributes
67data Attr = Attr {
67data Attr = Attr {
@@ -74,13 +74,13 @@ data CData = CData {
74 cdVerbatim :: CDataKind,
74 cdVerbatim :: CDataKind,
75 cdData :: Text,
75 cdData :: Text,
76 cdLine :: Maybe Line
76 cdLine :: Maybe Line
77− } deriving (Show, Typeable, Data)
77+ } deriving (Show, Typeable, Data, Ord, Eq)
78
78
79data CDataKind
79data CDataKind
80 = CDataText -- ^ Ordinary character data; pretty printer escapes &, < etc.
80 = CDataText -- ^ Ordinary character data; pretty printer escapes &, < etc.
81 | CDataVerbatim -- ^ Unescaped character data; pretty printer embeds it in <![CDATA[..
81 | CDataVerbatim -- ^ Unescaped character data; pretty printer embeds it in <![CDATA[..
82 | CDataRaw -- ^ As-is character data; pretty printer passes it along without any escaping or CDATA wrap-up.
82 | CDataRaw -- ^ As-is character data; pretty printer passes it along without any escaping or CDATA wrap-up.
83− deriving ( Eq, Show, Typeable, Data )
83+ deriving ( Eq, Ord, Show, Typeable, Data )
84
84
85-- | XML qualified names
85-- | XML qualified names
86data QName = QName {
86data QName = QName {
stack.yaml+9−10
@@ -7,17 +7,16 @@ flags:
7packages:
7packages:
8- '.'
8- '.'
9extra-deps:
9extra-deps:
10−- hslua-1.3.0
10+- commonmark-0.2.1
11−- hslua-module-path-0.1.0
11+- commonmark-pandoc-0.2.1.1
12−- jira-wiki-markup-1.3.4
13−- skylighting-core-0.10.4.1
12+- skylighting-core-0.10.5.2
14−- skylighting-0.10.4.1
13+- skylighting-0.10.5.2
15−- doclayout-0.3.0.2
14+- git: https://github.com/jgm/doctemplates
15+ commit: 428c26d5303cf7a2b1051fe1ffd9aafe9ba71c81
16−- citeproc-0.3.0.9
16+- git: https://github.com/jgm/citeproc
17−- texmath-0.12.2
17+ commit: 4ce0501cd6f9c86eee087afcf878c256e49b9615
18−- random-1.2.0
19ghc-options:
18ghc-options:
20 "$locals": -fhide-source-paths -Wno-missing-home-modules
19 "$locals": -fhide-source-paths -Wno-missing-home-modules
21−resolver: lts-17.5
20+resolver: lts-18.0
22nix:
21nix:
23 packages: [zlib]
22 packages: [zlib]
test/Tests/Command.hs+7−14
@@ -1,4 +1,3 @@
1−{-# LANGUAGE TupleSections #-}
2{- |
1{- |
3 Module : Tests.Command
2 Module : Tests.Command
4 Copyright : © 2006-2021 John MacFarlane
3 Copyright : © 2006-2021 John MacFarlane
@@ -14,14 +13,13 @@ module Tests.Command (runTest, tests)
14where
13where
15
14
16import Data.Algorithm.Diff
15import Data.Algorithm.Diff
17−import System.Environment.Executable (getExecutablePath)
16+import System.Environment (getExecutablePath)
18import qualified Data.ByteString as BS
17import qualified Data.ByteString as BS
19import qualified Data.Text as T
18import qualified Data.Text as T
20import Data.List (isSuffixOf)
19import Data.List (isSuffixOf)
21import System.Directory
20import System.Directory
22−import qualified System.Environment as Env
23import System.Exit
21import System.Exit
24−import System.FilePath (takeDirectory, (</>))
22+import System.FilePath ((</>))
25import System.IO (hPutStr, stderr)
23import System.IO (hPutStr, stderr)
26import System.IO.Unsafe (unsafePerformIO)
24import System.IO.Unsafe (unsafePerformIO)
27import System.Process
25import System.Process
@@ -38,15 +36,7 @@ execTest :: String -- ^ Path to test executable
38 -> String -- ^ Input text
36 -> String -- ^ Input text
39 -> IO (ExitCode, String) -- ^ Exit code and actual output
37 -> IO (ExitCode, String) -- ^ Exit code and actual output
40execTest testExePath cmd inp = do
38execTest testExePath cmd inp = do
41− mldpath <- Env.lookupEnv "LD_LIBRARY_PATH"
42− mdyldpath <- Env.lookupEnv "DYLD_LIBRARY_PATH"
43− let env' = ("PATH",takeDirectory testExePath) :
39+ env' <- setupEnvironment testExePath
44− ("TMP",".") :
45− ("LANG","en_US.UTF-8") :
46− ("HOME", "./") :
47− ("pandoc_datadir", "..") :
48− maybe [] ((:[]) . ("LD_LIBRARY_PATH",)) mldpath ++
49− maybe [] ((:[]) . ("DYLD_LIBRARY_PATH",)) mdyldpath
50 let pr = (shell (pandocToEmulate True cmd)){ env = Just env' }
40 let pr = (shell (pandocToEmulate True cmd)){ env = Just env' }
51 (ec, out', err') <- readCreateProcessWithExitCode pr inp
41 (ec, out', err') <- readCreateProcessWithExitCode pr inp
52 -- filter \r so the tests will work on Windows machines
42 -- filter \r so the tests will work on Windows machines
@@ -140,4 +130,7 @@ extractCommandTest testExePath fp = unsafePerformIO $ do
140 def{ readerExtensions = pandocExtensions } contents)
130 def{ readerExtensions = pandocExtensions } contents)
141 let codeblocks = map extractCode $ filter isCodeBlock blocks
131 let codeblocks = map extractCode $ filter isCodeBlock blocks
142 let cases = zipWith (runCommandTest testExePath fp) [1..] codeblocks
132 let cases = zipWith (runCommandTest testExePath fp) [1..] codeblocks
143− return $ testGroup fp cases
133+ return $ testGroup fp
134+ $ if null cases
135+ then [testCase "!!" $ assertFailure "No command tests defined"]
136+ else cases
test/Tests/Helpers.hs+23
@@ -1,4 +1,5 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2+{-# LANGUAGE TupleSections #-}
2{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE FlexibleInstances #-}
3{- |
4{- |
4 Module : Tests.Helpers
5 Module : Tests.Helpers
@@ -13,6 +14,7 @@ Utility functions for the test suite.
13-}
14-}
14module Tests.Helpers ( test
15module Tests.Helpers ( test
15 , TestResult(..)
16 , TestResult(..)
17+ , setupEnvironment
16 , showDiff
18 , showDiff
17 , (=?>)
19 , (=?>)
18 , purely
20 , purely
@@ -25,6 +27,8 @@ import Data.Algorithm.Diff
25import qualified Data.Map as M
27import qualified Data.Map as M
26import Data.Text (Text, unpack)
28import Data.Text (Text, unpack)
27import System.Exit
29import System.Exit
30+import System.FilePath (takeDirectory)
31+import qualified System.Environment as Env
28import Test.Tasty
32import Test.Tasty
29import Test.Tasty.HUnit
33import Test.Tasty.HUnit
30import Text.Pandoc.Builder (Blocks, Inlines, doc, plain)
34import Text.Pandoc.Builder (Blocks, Inlines, doc, plain)
@@ -57,6 +61,25 @@ test fn name (input, expected) =
57 dashes "" = replicate 72 '-'
61 dashes "" = replicate 72 '-'
58 dashes x = replicate (72 - length x - 5) '-' ++ " " ++ x ++ " ---"
62 dashes x = replicate (72 - length x - 5) '-' ++ " " ++ x ++ " ---"
59
63
64+-- | Set up environment for pandoc command tests.
65+setupEnvironment :: FilePath -> IO [(String, String)]
66+setupEnvironment testExePath = do
67+ mldpath <- Env.lookupEnv "LD_LIBRARY_PATH"
68+ mdyldpath <- Env.lookupEnv "DYLD_LIBRARY_PATH"
69+ mpdd <- Env.lookupEnv "pandoc_datadir"
70+ -- Note that Cabal sets the pandoc_datadir environment variable
71+ -- to point to the source directory, since otherwise getDataFilename
72+ -- will look in the data directory into which pandoc will be installed
73+ -- (but has not yet been). So when we spawn a new process with
74+ -- pandoc, we need to make sure this environment variable is set.
75+ return $ ("PATH",takeDirectory testExePath) :
76+ ("TMP",".") :
77+ ("LANG","en_US.UTF-8") :
78+ ("HOME", "./") :
79+ maybe [] ((:[]) . ("pandoc_datadir",)) mpdd ++
80+ maybe [] ((:[]) . ("LD_LIBRARY_PATH",)) mldpath ++
81+ maybe [] ((:[]) . ("DYLD_LIBRARY_PATH",)) mdyldpath
82+
60data TestResult = TestPassed
83data TestResult = TestPassed
61 | TestError ExitCode
84 | TestError ExitCode
62 | TestFailed String FilePath [Diff String]
85 | TestFailed String FilePath [Diff String]
test/Tests/Old.hs+3−12
@@ -1,4 +1,3 @@
1−{-# LANGUAGE TupleSections #-}
2{- |
1{- |
3 Module : Tests.Old
2 Module : Tests.Old
4 Copyright : © 2006-2021 John MacFarlane
3 Copyright : © 2006-2021 John MacFarlane
@@ -15,8 +14,7 @@ module Tests.Old (tests) where
15import Data.Algorithm.Diff
14import Data.Algorithm.Diff
16import System.Exit
15import System.Exit
17import System.FilePath ((<.>), (</>))
16import System.FilePath ((<.>), (</>))
18−import qualified System.Environment as Env
19−import System.Environment.Executable (getExecutablePath)
17+import System.Environment (getExecutablePath)
20import Text.Pandoc.Process (pipeProcess)
18import Text.Pandoc.Process (pipeProcess)
21import Test.Tasty (TestTree, testGroup)
19import Test.Tasty (TestTree, testGroup)
22import Test.Tasty.Golden.Advanced (goldenTest)
20import Test.Tasty.Golden.Advanced (goldenTest)
@@ -319,14 +317,7 @@ testWithNormalize normalizer pandocPath testname opts inp norm =
319 (compareValues norm options) updateGolden
317 (compareValues norm options) updateGolden
320 where getExpected = normalizer <$> readFile' norm
318 where getExpected = normalizer <$> readFile' norm
321 getActual = do
319 getActual = do
322− mldpath <- Env.lookupEnv "LD_LIBRARY_PATH"
320+ env <- setupEnvironment pandocPath
323− mdyldpath <- Env.lookupEnv "DYLD_LIBRARY_PATH"
324− let env = ("TMP",".") :
325− ("LANG","en_US.UTF-8") :
326− ("HOME", "./") :
327− maybe [] ((:[]) . ("LD_LIBRARY_PATH",)) mldpath ++
328− maybe [] ((:[]) . ("DYLD_LIBRARY_PATH",)) mdyldpath
329−
330 (ec, out) <- pipeProcess (Just env) pandocPath
321 (ec, out) <- pipeProcess (Just env) pandocPath
331 ("--emulate":options) mempty
322 ("--emulate":options) mempty
332 if ec == ExitSuccess
323 if ec == ExitSuccess
@@ -335,7 +326,7 @@ testWithNormalize normalizer pandocPath testname opts inp norm =
335 -- filter \r so the tests will work on Windows machines
326 -- filter \r so the tests will work on Windows machines
336 else fail $ "Pandoc failed with error code " ++ show ec
327 else fail $ "Pandoc failed with error code " ++ show ec
337 updateGolden = UTF8.writeFile norm . T.pack
328 updateGolden = UTF8.writeFile norm . T.pack
338− options = ["--data-dir=../data","--quiet"] ++ [inp] ++ opts
329+ options = ["--quiet"] ++ [inp] ++ opts
339
330
340compareValues :: FilePath -> [String] -> String -> String -> IO (Maybe String)
331compareValues :: FilePath -> [String] -> String -> String -> IO (Maybe String)
341compareValues norm options expected actual = do
332compareValues norm options expected actual = do
test/Tests/Readers/Docx.hs+25−5
@@ -24,7 +24,7 @@ import Test.Tasty.HUnit
24import Tests.Helpers
24import Tests.Helpers
25import Text.Pandoc
25import Text.Pandoc
26import qualified Text.Pandoc.Class as P
26import qualified Text.Pandoc.Class as P
27−import Text.Pandoc.MediaBag (MediaBag, lookupMedia, mediaDirectory)
27+import qualified Text.Pandoc.MediaBag as MB
28import Text.Pandoc.UTF8 as UTF8
28import Text.Pandoc.UTF8 as UTF8
29
29
30-- We define a wrapper around pandoc that doesn't normalize in the
30-- We define a wrapper around pandoc that doesn't normalize in the
@@ -91,11 +91,11 @@ getMedia :: FilePath -> FilePath -> IO (Maybe B.ByteString)
91getMedia archivePath mediaPath = fmap fromEntry . findEntryByPath
91getMedia archivePath mediaPath = fmap fromEntry . findEntryByPath
92 ("word/" ++ mediaPath) . toArchive <$> B.readFile archivePath
92 ("word/" ++ mediaPath) . toArchive <$> B.readFile archivePath
93
93
94−compareMediaPathIO :: FilePath -> MediaBag -> FilePath -> IO Bool
94+compareMediaPathIO :: FilePath -> MB.MediaBag -> FilePath -> IO Bool
95compareMediaPathIO mediaPath mediaBag docxPath = do
95compareMediaPathIO mediaPath mediaBag docxPath = do
96 docxMedia <- getMedia docxPath mediaPath
96 docxMedia <- getMedia docxPath mediaPath
97− let mbBS = case lookupMedia mediaPath mediaBag of
97+ let mbBS = case MB.lookupMedia mediaPath mediaBag of
98− Just (_, bs) -> bs
98+ Just item -> MB.mediaContents item
99 Nothing -> error ("couldn't find " ++
99 Nothing -> error ("couldn't find " ++
100 mediaPath ++
100 mediaPath ++
101 " in media bag")
101 " in media bag")
@@ -110,7 +110,7 @@ compareMediaBagIO docxFile = do
110 mb <- runIOorExplode $ readDocx defopts df >> P.getMediaBag
110 mb <- runIOorExplode $ readDocx defopts df >> P.getMediaBag
111 bools <- mapM
111 bools <- mapM
112 (\(fp, _, _) -> compareMediaPathIO fp mb docxFile)
112 (\(fp, _, _) -> compareMediaPathIO fp mb docxFile)
113− (mediaDirectory mb)
113+ (MB.mediaDirectory mb)
114 return $ and bools
114 return $ and bools
115
115
116testMediaBagIO :: String -> FilePath -> IO TestTree
116testMediaBagIO :: String -> FilePath -> IO TestTree
@@ -155,6 +155,10 @@ tests = [ testGroup "document"
155 "VML image"
155 "VML image"
156 "docx/image_vml.docx"
156 "docx/image_vml.docx"
157 "docx/image_vml.native"
157 "docx/image_vml.native"
158+ , testCompare
159+ "VML image as object"
160+ "docx/image_vml_as_object.docx"
161+ "docx/image_vml_as_object.native"
158 , testCompare
162 , testCompare
159 "inline image in links"
163 "inline image in links"
160 "docx/inline_images.docx"
164 "docx/inline_images.docx"
@@ -313,14 +317,30 @@ tests = [ testGroup "document"
313 "tables with lists in cells"
317 "tables with lists in cells"
314 "docx/table_with_list_cell.docx"
318 "docx/table_with_list_cell.docx"
315 "docx/table_with_list_cell.native"
319 "docx/table_with_list_cell.native"
320+ , testCompare
321+ "a table with a header which contains rowspans greater than 1"
322+ "docx/table_header_rowspan.docx"
323+ "docx/table_header_rowspan.native"
316 , testCompare
324 , testCompare
317 "tables with one row"
325 "tables with one row"
318 "docx/table_one_row.docx"
326 "docx/table_one_row.docx"
319 "docx/table_one_row.native"
327 "docx/table_one_row.native"
328+ , testCompare
329+ "tables with just one row, which is a header"
330+ "docx/table_one_header_row.docx"
331+ "docx/table_one_header_row.native"
320 , testCompare
332 , testCompare
321 "tables with variable width"
333 "tables with variable width"
322 "docx/table_variable_width.docx"
334 "docx/table_variable_width.docx"
323 "docx/table_variable_width.native"
335 "docx/table_variable_width.native"
336+ , testCompare
337+ "tables with captions which contain a Table field"
338+ "docx/table_captions_with_field.docx"
339+ "docx/table_captions_with_field.native"
340+ , testCompare
341+ "tables with captions which don't contain a Table field"
342+ "docx/table_captions_no_field.docx"
343+ "docx/table_captions_no_field.native"
324 , testCompare
344 , testCompare
325 "code block"
345 "code block"
326 "docx/codeblock.docx"
346 "docx/codeblock.docx"
test/Tests/Readers/EPUB.hs+1−1
@@ -47,7 +47,7 @@ featuresBag = [("img/check.gif","image/gif",1340)
47
47
48-- with additional meta tag for cover in EPUB2 format
48-- with additional meta tag for cover in EPUB2 format
49epub3CoverBag :: [(String, String, Int)]
49epub3CoverBag :: [(String, String, Int)]
50−epub3CoverBag = [("wasteland-cover.jpg","image/jpeg",103477)]
50+epub3CoverBag = [("wasteland-cover.jpg","image/jpeg", 16586)]
51
51
52epub3NoCoverBag :: [(String, String, Int)]
52epub3NoCoverBag :: [(String, String, Int)]
53epub3NoCoverBag = [("img/check.gif","image/gif",1340)
53epub3NoCoverBag = [("img/check.gif","image/gif",1340)
test/Tests/Readers/HTML.hs+20−5
@@ -99,11 +99,26 @@ tests = [ testGroup "base tag"
99 plain (codeWith ("",["sample"],[]) "Answer is 42")
99 plain (codeWith ("",["sample"],[]) "Answer is 42")
100 ]
100 ]
101 , testGroup "var"
101 , testGroup "var"
102− [
103− test html "inline var block" $
102+ [ test html "inline var block" $
104− "<var>result</var>" =?>
103+ "<var>result</var>" =?>
105− plain (codeWith ("",["variable"],[]) "result")
104+ plain (codeWith ("",["variable"],[]) "result")
105+ ]
106+ , testGroup "header"
107+ [ test htmlNativeDivs "<header> is parsed as a div" $
108+ "<header id=\"title\">Title</header>" =?>
109+ divWith ("title", mempty, mempty) (plain "Title")
110+ ]
111+ , testGroup "code block"
112+ [ test html "attributes in pre > code element" $
113+ "<pre><code id=\"a\" class=\"python\">\nprint('hi')\n</code></pre>"
114+ =?>
115+ codeBlockWith ("a", ["python"], []) "print('hi')"
116+
117+ , test html "attributes in pre take precendence" $
118+ "<pre id=\"c\"><code id=\"d\">\nprint('hi mom!')\n</code></pre>"
119+ =?>
120+ codeBlockWith ("c", [], []) "print('hi mom!')"
106− ]
121+ ]
107 , askOption $ \(QuickCheckTests numtests) ->
122 , askOption $ \(QuickCheckTests numtests) ->
108 testProperty "Round trip" $
123 testProperty "Round trip" $
109 withMaxSuccess (if QuickCheckTests numtests == defaultValue
124 withMaxSuccess (if QuickCheckTests numtests == defaultValue
test/Tests/Readers/Jira.hs+8
@@ -167,6 +167,14 @@ tests =
167 , "user with description" =:
167 , "user with description" =:
168 "[John Doe|~johndoe]" =?>
168 "[John Doe|~johndoe]" =?>
169 para (linkWith ("", ["user-account"], []) "~johndoe" "" "John Doe")
169 para (linkWith ("", ["user-account"], []) "~johndoe" "" "John Doe")
170+
171+ , "'smart' link" =:
172+ "[x|http://example.com|smart-link]" =?>
173+ para (linkWith ("", ["smart-link"], []) "http://example.com" "" "x")
174+
175+ , "'smart' card" =:
176+ "[x|http://example.com|smart-card]" =?>
177+ para (linkWith ("", ["smart-card"], []) "http://example.com" "" "x")
170 ]
178 ]
171
179
172 , "image" =:
180 , "image" =:
test/Tests/Readers/Markdown.hs+3−3
@@ -358,7 +358,7 @@ tests = [ testGroup "inline code"
358 para (text "The value of the " <> math "x" <> text "\8217s and the systems\8217 condition.")
358 para (text "The value of the " <> math "x" <> text "\8217s and the systems\8217 condition.")
359 , test markdownSmart "unclosed double quote"
359 , test markdownSmart "unclosed double quote"
360 ("**this should \"be bold**"
360 ("**this should \"be bold**"
361− =?> para (strong "this should \"be bold"))
361+ =?> para (strong "this should \8220be bold"))
362 ]
362 ]
363 , testGroup "footnotes"
363 , testGroup "footnotes"
364 [ "indent followed by newline and flush-left text" =:
364 [ "indent followed by newline and flush-left text" =:
@@ -374,8 +374,8 @@ tests = [ testGroup "inline code"
374 , testGroup "lhs"
374 , testGroup "lhs"
375 [ test (purely $ readMarkdown def{ readerExtensions = enableExtension
375 [ test (purely $ readMarkdown def{ readerExtensions = enableExtension
376 Ext_literate_haskell pandocExtensions })
376 Ext_literate_haskell pandocExtensions })
377− "inverse bird tracks and html" $
377+ "inverse bird tracks and html"
378− "> a\n\n< b\n\n<div>\n"
378+ $ ("> a\n\n< b\n\n<div>\n" :: Text)
379 =?> codeBlockWith ("",["haskell","literate"],[]) "a"
379 =?> codeBlockWith ("",["haskell","literate"],[]) "a"
380 <>
380 <>
381 codeBlockWith ("",["haskell"],[]) "b"
381 codeBlockWith ("",["haskell"],[]) "b"
test/Tests/Readers/Odt.hs+1
@@ -176,6 +176,7 @@ namesOfTestsComparingToNative = [ "blockquote"
176 , "referenceToText"
176 , "referenceToText"
177 , "simpleTable"
177 , "simpleTable"
178 , "simpleTableWithCaption"
178 , "simpleTableWithCaption"
179+ , "tab"
179-- , "table"
180-- , "table"
180 , "textMixedStyles"
181 , "textMixedStyles"
181 , "tableWithContents"
182 , "tableWithContents"
test/Tests/Writers/ConTeXt.hs+122−113
@@ -39,116 +39,125 @@ infix 4 =:
39(=:) = test context
39(=:) = test context
40
40
41tests :: [TestTree]
41tests :: [TestTree]
42−tests = [ testGroup "inline code"
42+tests =
43− [ "with '}'" =: code "}" =?> "\\mono{\\}}"
43+ [ testGroup "inline code"
44− , "without '}'" =: code "]" =?> "\\type{]}"
44+ [ "with '}'" =: code "}" =?> "\\mono{\\}}"
45− , testProperty "code property" $ \s -> null s || '\n' `elem` s ||
45+ , "without '}'" =: code "]" =?> "\\type{]}"
46− if '{' `elem` s || '}' `elem` s
46+ , "span with ID" =:
47− then context' (code $ pack s) == "\\mono{" ++
47+ spanWith ("city", [], []) "Berlin" =?>
48− context' (str $ pack s) ++ "}"
48+ "\\reference[city]{}Berlin"
49− else context' (code $ pack s) == "\\type{" ++ s ++ "}"
49+ , testProperty "code property" $ \s -> null s || '\n' `elem` s ||
50− ]
50+ if '{' `elem` s || '}' `elem` s
51− , testGroup "headers"
51+ then context' (code $ pack s) == "\\mono{" ++
52− [ "level 1" =:
52+ context' (str $ pack s) ++ "}"
53− headerWith ("my-header",[],[]) 1 "My header" =?> "\\section[title={My header},reference={my-header}]"
53+ else context' (code $ pack s) == "\\type{" ++ s ++ "}"
54− , test contextDiv "section-divs" $
54+ ]
55− ( headerWith ("header1", [], []) 1 (text "Header1")
55+ , testGroup "headers"
56− <> headerWith ("header2", [], []) 2 (text "Header2")
56+ [ "level 1" =:
57− <> headerWith ("header3", [], []) 3 (text "Header3")
57+ headerWith ("my-header",[],[]) 1 "My header" =?>
58− <> headerWith ("header4", [], []) 4 (text "Header4")
58+ "\\section[title={My header},reference={my-header}]"
59− <> headerWith ("header5", [], []) 5 (text "Header5")
59+ , test contextDiv "section-divs" $
60− <> headerWith ("header6", [], []) 6 (text "Header6"))
60+ ( headerWith ("header1", [], []) 1 (text "Header1")
61− =?>
61+ <> headerWith ("header2", [], []) 2 (text "Header2")
62− unlines [ "\\startsection[title={Header1},reference={header1}]\n"
62+ <> headerWith ("header3", [], []) 3 (text "Header3")
63− , "\\startsubsection[title={Header2},reference={header2}]\n"
63+ <> headerWith ("header4", [], []) 4 (text "Header4")
64− , "\\startsubsubsection[title={Header3},reference={header3}]\n"
64+ <> headerWith ("header5", [], []) 5 (text "Header5")
65− , "\\startsubsubsubsection[title={Header4},reference={header4}]\n"
65+ <> headerWith ("header6", [], []) 6 (text "Header6"))
66− , "\\startsubsubsubsubsection[title={Header5},reference={header5}]\n"
66+ =?>
67− , "\\startsubsubsubsubsubsection[title={Header6},reference={header6}]\n"
67+ unlines
68− , "\\stopsubsubsubsubsubsection\n"
68+ [ "\\startsection[title={Header1},reference={header1}]\n"
69− , "\\stopsubsubsubsubsection\n"
69+ , "\\startsubsection[title={Header2},reference={header2}]\n"
70− , "\\stopsubsubsubsection\n"
70+ , "\\startsubsubsection[title={Header3},reference={header3}]\n"
71− , "\\stopsubsubsection\n"
71+ , "\\startsubsubsubsection[title={Header4},reference={header4}]\n"
72− , "\\stopsubsection\n"
72+ , "\\startsubsubsubsubsection[title={Header5},reference={header5}]\n"
73− , "\\stopsection" ]
73+ , "\\startsubsubsubsubsubsection[title={Header6},reference={header6}]\n"
74− ]
74+ , "\\stopsubsubsubsubsubsection\n"
75− , testGroup "bullet lists"
75+ , "\\stopsubsubsubsubsection\n"
76− [ "nested" =:
76+ , "\\stopsubsubsubsection\n"
77− bulletList [
77+ , "\\stopsubsubsection\n"
78− plain (text "top")
78+ , "\\stopsubsection\n"
79− <> bulletList [
79+ , "\\stopsection" ]
80− plain (text "next")
80+ ]
81− <> bulletList [plain (text "bot")]
81+ , testGroup "bullet lists"
82− ]
82+ [ "nested" =:
83− ] =?> unlines
83+ bulletList [
84− [ "\\startitemize[packed]"
84+ plain (text "top")
85− , "\\item"
85+ <> bulletList [
86− , " top"
86+ plain (text "next")
87− , " \\startitemize[packed]"
87+ <> bulletList [plain (text "bot")]
88− , " \\item"
88+ ]
89− , " next"
89+ ] =?> unlines
90− , " \\startitemize[packed]"
90+ [ "\\startitemize[packed]"
91− , " \\item"
91+ , "\\item"
92− , " bot"
92+ , " top"
93− , " \\stopitemize"
93+ , " \\startitemize[packed]"
94− , " \\stopitemize"
94+ , " \\item"
95− , "\\stopitemize" ]
95+ , " next"
96− ]
96+ , " \\startitemize[packed]"
97− , testGroup "natural tables"
97+ , " \\item"
98− [ test contextNtb "table with header and caption" $
98+ , " bot"
99− let capt = text "Table 1"
99+ , " \\stopitemize"
100− aligns = [(AlignRight, ColWidthDefault), (AlignLeft, ColWidthDefault), (AlignCenter, ColWidthDefault), (AlignDefault, ColWidthDefault)]
100+ , " \\stopitemize"
101− headers = [plain $ text "Right",
101+ , "\\stopitemize" ]
102− plain $ text "Left",
102+ ]
103− plain $ text "Center",
103+ , testGroup "natural tables"
104− plain $ text "Default"]
104+ [ test contextNtb "table with header and caption" $
105− rows = [[plain $ text "1.1",
105+ let capt = text "Table 1"
106− plain $ text "1.2",
106+ aligns = [ (AlignRight, ColWidthDefault)
107− plain $ text "1.3",
107+ , (AlignLeft, ColWidthDefault)
108− plain $ text "1.4"]
108+ , (AlignCenter, ColWidthDefault)
109− ,[plain $ text "2.1",
109+ , (AlignDefault, ColWidthDefault) ]
110− plain $ text "2.2",
110+ headers = [plain $ text "Right",
111− plain $ text "2.3",
111+ plain $ text "Left",
112− plain $ text "2.4"]
112+ plain $ text "Center",
113− ,[plain $ text "3.1",
113+ plain $ text "Default"]
114− plain $ text "3.2",
114+ rows = [[plain $ text "1.1",
115− plain $ text "3.3",
115+ plain $ text "1.2",
116− plain $ text "3.4"]]
116+ plain $ text "1.3",
117− toRow = Row nullAttr . map simpleCell
117+ plain $ text "1.4"]
118− in table (simpleCaption $ plain capt)
118+ ,[plain $ text "2.1",
119− aligns
119+ plain $ text "2.2",
120− (TableHead nullAttr [toRow headers])
120+ plain $ text "2.3",
121− [TableBody nullAttr 0 [] $ map toRow rows]
121+ plain $ text "2.4"]
122− (TableFoot nullAttr [])
122+ ,[plain $ text "3.1",
123− =?> unlines [ "\\startplacetable[title={Table 1}]"
123+ plain $ text "3.2",
124− , "\\startTABLE"
124+ plain $ text "3.3",
125− , "\\startTABLEhead"
125+ plain $ text "3.4"]]
126− , "\\NC[align=left] Right"
126+ toRow = Row nullAttr . map simpleCell
127− , "\\NC[align=right] Left"
127+ in table (simpleCaption $ plain capt)
128− , "\\NC[align=middle] Center"
128+ aligns
129− , "\\NC Default"
129+ (TableHead nullAttr [toRow headers])
130− , "\\NC\\NR"
130+ [TableBody nullAttr 0 [] $ map toRow rows]
131− , "\\stopTABLEhead"
131+ (TableFoot nullAttr [])
132− , "\\startTABLEbody"
132+ =?> unlines [ "\\startplacetable[title={Table 1}]"
133− , "\\NC[align=left] 1.1"
133+ , "\\startTABLE"
134− , "\\NC[align=right] 1.2"
134+ , "\\startTABLEhead"
135− , "\\NC[align=middle] 1.3"
135+ , "\\NC[align=left] Right"
136− , "\\NC 1.4"
136+ , "\\NC[align=right] Left"
137− , "\\NC\\NR"
137+ , "\\NC[align=middle] Center"
138− , "\\NC[align=left] 2.1"
138+ , "\\NC Default"
139− , "\\NC[align=right] 2.2"
139+ , "\\NC\\NR"
140− , "\\NC[align=middle] 2.3"
140+ , "\\stopTABLEhead"
141− , "\\NC 2.4"
141+ , "\\startTABLEbody"
142− , "\\NC\\NR"
142+ , "\\NC[align=left] 1.1"
143− , "\\stopTABLEbody"
143+ , "\\NC[align=right] 1.2"
144− , "\\startTABLEfoot"
144+ , "\\NC[align=middle] 1.3"
145− , "\\NC[align=left] 3.1"
145+ , "\\NC 1.4"
146− , "\\NC[align=right] 3.2"
146+ , "\\NC\\NR"
147− , "\\NC[align=middle] 3.3"
147+ , "\\NC[align=left] 2.1"
148− , "\\NC 3.4"
148+ , "\\NC[align=right] 2.2"
149− , "\\NC\\NR"
149+ , "\\NC[align=middle] 2.3"
150− , "\\stopTABLEfoot"
150+ , "\\NC 2.4"
151− , "\\stopTABLE"
151+ , "\\NC\\NR"
152− , "\\stopplacetable" ]
152+ , "\\stopTABLEbody"
153− ]
153+ , "\\startTABLEfoot"
154− ]
154+ , "\\NC[align=left] 3.1"
155+ , "\\NC[align=right] 3.2"
156+ , "\\NC[align=middle] 3.3"
157+ , "\\NC 3.4"
158+ , "\\NC\\NR"
159+ , "\\stopTABLEfoot"
160+ , "\\stopTABLE"
161+ , "\\stopplacetable" ]
162+ ]
163+ ]
test/Tests/Writers/Docbook.hs+43−6
@@ -11,9 +11,14 @@ import Text.Pandoc.Builder
11docbook :: (ToPandoc a) => a -> String
11docbook :: (ToPandoc a) => a -> String
12docbook = docbookWithOpts def{ writerWrapText = WrapNone }
12docbook = docbookWithOpts def{ writerWrapText = WrapNone }
13
13
14+docbook5 :: (ToPandoc a) => a -> String
15+docbook5 = docbook5WithOpts def{ writerWrapText = WrapNone }
16+
14docbookWithOpts :: ToPandoc a => WriterOptions -> a -> String
17docbookWithOpts :: ToPandoc a => WriterOptions -> a -> String
15docbookWithOpts opts = unpack . purely (writeDocbook4 opts) . toPandoc
18docbookWithOpts opts = unpack . purely (writeDocbook4 opts) . toPandoc
16
19
20+docbook5WithOpts :: ToPandoc a => WriterOptions -> a -> String
21+docbook5WithOpts opts = unpack . purely (writeDocbook5 opts) . toPandoc
17{-
22{-
18 "my test" =: X =?> Y
23 "my test" =: X =?> Y
19
24
@@ -78,32 +83,32 @@ tests = [ testGroup "line blocks"
78 , "</warning>"
83 , "</warning>"
79 ]
84 ]
80 , "admonition-with-title" =:
85 , "admonition-with-title" =:
81− divWith ("foo", ["attention"], []) (
86+ divWith ("foo", ["note"], []) (
82 divWith ("foo", ["title"], [])
87 divWith ("foo", ["title"], [])
83 (plain (text "This is title")) <>
88 (plain (text "This is title")) <>
84 para "This is a test"
89 para "This is a test"
85 )
90 )
86 =?> unlines
91 =?> unlines
87− [ "<attention id=\"foo\">"
92+ [ "<note id=\"foo\">"
88 , " <title>This is title</title>"
93 , " <title>This is title</title>"
89 , " <para>"
94 , " <para>"
90 , " This is a test"
95 , " This is a test"
91 , " </para>"
96 , " </para>"
92− , "</attention>"
97+ , "</note>"
93 ]
98 ]
94 , "admonition-with-title-in-para" =:
99 , "admonition-with-title-in-para" =:
95− divWith ("foo", ["attention"], []) (
100+ divWith ("foo", ["note"], []) (
96 divWith ("foo", ["title"], [])
101 divWith ("foo", ["title"], [])
97 (para "This is title") <>
102 (para "This is title") <>
98 para "This is a test"
103 para "This is a test"
99 )
104 )
100 =?> unlines
105 =?> unlines
101− [ "<attention id=\"foo\">"
106+ [ "<note id=\"foo\">"
102 , " <title>This is title</title>"
107 , " <title>This is title</title>"
103 , " <para>"
108 , " <para>"
104 , " This is a test"
109 , " This is a test"
105 , " </para>"
110 , " </para>"
106− , "</attention>"
111+ , "</note>"
107 ]
112 ]
108 , "single-child" =:
113 , "single-child" =:
109 divWith ("foo", [], []) (para "This is a test")
114 divWith ("foo", [], []) (para "This is a test")
@@ -366,4 +371,36 @@ tests = [ testGroup "line blocks"
366 ]
371 ]
367 ]
372 ]
368 ]
373 ]
374+ , testGroup "section attributes" $
375+ let
376+ headers = headerWith ("myid1",[],[("role","internal"),("xml:id","anotherid"),("dir","rtl")]) 1 "header1"
377+ <> headerWith ("myid2",[],[("invalidname","value"),("arch","linux"),("dir","invaliddir")]) 1 "header2"
378+ in
379+ [ test docbook5 "sections with attributes (db5)" $
380+ headers =?>
381+ unlines [ "<section xmlns=\"http://docbook.org/ns/docbook\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xml:id=\"myid1\" role=\"internal\" dir=\"rtl\">"
382+ , " <title>header1</title>"
383+ , " <para>"
384+ , " </para>"
385+ , "</section>"
386+ , "<section xmlns=\"http://docbook.org/ns/docbook\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xml:id=\"myid2\">"
387+ , " <title>header2</title>"
388+ , " <para>"
389+ , " </para>"
390+ , "</section>"
391+ ]
392+ , test docbook "sections with attributes (db4)" $
393+ headers =?>
394+ unlines [ "<sect1 id=\"myid1\" role=\"internal\">"
395+ , " <title>header1</title>"
396+ , " <para>"
397+ , " </para>"
398+ , "</sect1>"
399+ , "<sect1 id=\"myid2\" arch=\"linux\">"
400+ , " <title>header2</title>"
401+ , " <para>"
402+ , " </para>"
403+ , "</sect1>"
404+ ]
405+ ]
369 ]
406 ]
test/Tests/Writers/Docx.hs+5
@@ -111,6 +111,11 @@ tests = [ testGroup "inlines"
111 def
111 def
112 "docx/tables.native"
112 "docx/tables.native"
113 "docx/golden/tables.docx"
113 "docx/golden/tables.docx"
114+ , docxTest
115+ "tables without explicit column widths"
116+ def
117+ "docx/tables-default-widths.native"
118+ "docx/golden/tables-default-widths.docx"
114 , docxTest
119 , docxTest
115 "tables with lists in cells"
120 "tables with lists in cells"
116 def
121 def
test/Tests/Writers/HTML.hs+57−52
@@ -34,55 +34,60 @@ infix 4 =:
34(=:) = test html
34(=:) = test html
35
35
36tests :: [TestTree]
36tests :: [TestTree]
37−tests = [ testGroup "inline code"
37+tests =
38− [ "basic" =: code "@&" =?> "<code>@&amp;</code>"
38+ [ testGroup "inline code"
39− , "haskell" =: codeWith ("",["haskell"],[]) ">>="
39+ [ "basic" =: code "@&" =?> "<code>@&amp;</code>"
40− =?> "<code class=\"sourceCode haskell\"><span class=\"op\">&gt;&gt;=</span></code>"
40+ , "haskell" =: codeWith ("",["haskell"],[]) ">>="
41− , "nolanguage" =: codeWith ("",["nolanguage"],[]) ">>="
41+ =?> "<code class=\"sourceCode haskell\"><span class=\"op\">&gt;&gt;=</span></code>"
42− =?> "<code class=\"nolanguage\">&gt;&gt;=</code>"
42+ , "nolanguage" =: codeWith ("",["nolanguage"],[]) ">>="
43− ]
43+ =?> "<code class=\"nolanguage\">&gt;&gt;=</code>"
44− , testGroup "images"
44+ ]
45− [ "alt with formatting" =:
45+ , testGroup "images"
46− image "/url" "title" ("my " <> emph "image")
46+ [ "alt with formatting" =:
47− =?> "<img src=\"/url\" title=\"title\" alt=\"my image\" />"
47+ image "/url" "title" ("my " <> emph "image")
48− ]
48+ =?> "<img src=\"/url\" title=\"title\" alt=\"my image\" />"
49− , testGroup "blocks"
49+ ]
50− [ "definition list with empty <dt>" =:
50+ , testGroup "blocks"
51− definitionList [(mempty, [para $ text "foo bar"])]
51+ [ "definition list with empty <dt>" =:
52− =?> "<dl><dt></dt><dd><p>foo bar</p></dd></dl>"
52+ definitionList [(mempty, [para $ text "foo bar"])]
53− ]
53+ =?> "<dl><dt></dt><dd><p>foo bar</p></dd></dl>"
54− , testGroup "quotes"
54+ , "heading with disallowed attributes" =:
55− [ "quote with cite attribute (without q-tags)" =:
55+ headerWith ("", [], [("invalid","1"), ("lang", "en")]) 1 "test"
56− doubleQuoted (spanWith ("", [], [("cite", "http://example.org")]) (str "examples"))
56+ =?>
57− =?> "“<span cite=\"http://example.org\">examples</span>”"
57+ "<h1 lang=\"en\">test</h1>"
58− , tQ "quote with cite attribute (with q-tags)" $
58+ ]
59− doubleQuoted (spanWith ("", [], [("cite", "http://example.org")]) (str "examples"))
59+ , testGroup "quotes"
60− =?> "<q cite=\"http://example.org\">examples</q>"
60+ [ "quote with cite attribute (without q-tags)" =:
61− ]
61+ doubleQuoted (spanWith ("", [], [("cite", "http://example.org")]) (str "examples"))
62− , testGroup "sample"
62+ =?> "“<span cite=\"http://example.org\">examples</span>”"
63− [ "sample should be rendered correctly" =:
63+ , tQ "quote with cite attribute (with q-tags)" $
64− plain (codeWith ("",["sample"],[]) "Answer is 42") =?>
64+ doubleQuoted (spanWith ("", [], [("cite", "http://example.org")]) (str "examples"))
65− "<samp>Answer is 42</samp>"
65+ =?> "<q cite=\"http://example.org\">examples</q>"
66− ]
66+ ]
67− , testGroup "variable"
67+ , testGroup "sample"
68− [ "variable should be rendered correctly" =:
68+ [ "sample should be rendered correctly" =:
69− plain (codeWith ("",["variable"],[]) "result") =?>
69+ plain (codeWith ("",["sample"],[]) "Answer is 42") =?>
70− "<var>result</var>"
70+ "<samp>Answer is 42</samp>"
71− ]
71+ ]
72− , testGroup "sample with style"
72+ , testGroup "variable"
73− [ "samp should wrap highlighted code" =:
73+ [ "variable should be rendered correctly" =:
74− codeWith ("",["sample","haskell"],[]) ">>="
74+ plain (codeWith ("",["variable"],[]) "result") =?>
75− =?> ("<samp><code class=\"sourceCode haskell\">" ++
75+ "<var>result</var>"
76− "<span class=\"op\">&gt;&gt;=</span></code></samp>")
76+ ]
77− ]
77+ , testGroup "sample with style"
78− , testGroup "variable with style"
78+ [ "samp should wrap highlighted code" =:
79− [ "var should wrap highlighted code" =:
79+ codeWith ("",["sample","haskell"],[]) ">>="
80− codeWith ("",["haskell","variable"],[]) ">>="
80+ =?> ("<samp><code class=\"sourceCode haskell\">" ++
81− =?> ("<var><code class=\"sourceCode haskell\">" ++
81+ "<span class=\"op\">&gt;&gt;=</span></code></samp>")
82− "<span class=\"op\">&gt;&gt;=</span></code></var>")
82+ ]
83− ]
83+ , testGroup "variable with style"
84− ]
84+ [ "var should wrap highlighted code" =:
85− where
85+ codeWith ("",["haskell","variable"],[]) ">>="
86− tQ :: (ToString a, ToPandoc a)
86+ =?> ("<var><code class=\"sourceCode haskell\">" ++
87− => String -> (a, String) -> TestTree
87+ "<span class=\"op\">&gt;&gt;=</span></code></var>")
88− tQ = test htmlQTags
88+ ]
89+ ]
90+ where
91+ tQ :: (ToString a, ToPandoc a)
92+ => String -> (a, String) -> TestTree
93+ tQ = test htmlQTags
test/Tests/Writers/JATS.hs+135−91
@@ -1,21 +1,21 @@
1{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
2module Tests.Writers.JATS (tests) where
2module Tests.Writers.JATS (tests) where
3
3
4−import Data.Text (unpack)
4+import Data.Text (Text)
5import Test.Tasty
5import Test.Tasty
6import Tests.Helpers
6import Tests.Helpers
7import Text.Pandoc
7import Text.Pandoc
8import Text.Pandoc.Arbitrary ()
8import Text.Pandoc.Arbitrary ()
9import Text.Pandoc.Builder
9import Text.Pandoc.Builder
10+import qualified Data.Text as T
10
11
11−jats :: (ToPandoc a) => a -> String
12+jats :: (ToPandoc a) => a -> Text
12−jats = unpack
13+jats = purely (writeJATS def{ writerWrapText = WrapNone })
13− . purely (writeJATS def{ writerWrapText = WrapNone })
14+ . toPandoc
14− . toPandoc
15
15
16−jatsArticleAuthoring :: (ToPandoc a) => a -> String
16+jatsArticleAuthoring :: (ToPandoc a) => a -> Text
17−jatsArticleAuthoring = unpack
17+jatsArticleAuthoring =
18− . purely (writeJatsArticleAuthoring def{ writerWrapText = WrapNone })
18+ purely (writeJatsArticleAuthoring def{ writerWrapText = WrapNone })
19 . toPandoc
19 . toPandoc
20
20
21{-
21{-
@@ -32,89 +32,133 @@ which is in turn shorthand for
32
32
33infix 4 =:
33infix 4 =:
34(=:) :: (ToString a, ToPandoc a)
34(=:) :: (ToString a, ToPandoc a)
35− => String -> (a, String) -> TestTree
35+ => String -> (a, Text) -> TestTree
36(=:) = test jats
36(=:) = test jats
37
37
38tests :: [TestTree]
38tests :: [TestTree]
39−tests = [ testGroup "inline code"
39+tests =
40− [ "basic" =: code "@&" =?> "<p><monospace>@&amp;</monospace></p>"
40+ [ testGroup "inline code"
41− , "lang" =: codeWith ("", ["c"], []) "@&" =?> "<p><code language=\"c\">@&amp;</code></p>"
41+ [ "basic" =: code "@&" =?> "<p><monospace>@&amp;</monospace></p>"
42− ]
42+ , "lang" =: codeWith ("", ["c"], []) "@&" =?> "<p><code language=\"c\">@&amp;</code></p>"
43− , testGroup "block code"
43+ ]
44− [ "basic" =: codeBlock "@&" =?> "<preformat>@&amp;</preformat>"
44+ , testGroup "block code"
45− , "lang" =: codeBlockWith ("", ["c"], []) "@&" =?> "<code language=\"c\">@&amp;</code>"
45+ [ "basic" =: codeBlock "@&" =?> "<preformat>@&amp;</preformat>"
46− ]
46+ , "lang" =: codeBlockWith ("", ["c"], []) "@&" =?> "<code language=\"c\">@&amp;</code>"
47− , testGroup "images"
47+ ]
48− [ "basic" =:
48+ , testGroup "images"
49− image "/url" "title" mempty
49+ [ "basic" =:
50− =?> "<graphic mimetype=\"image\" mime-subtype=\"\" xlink:href=\"/url\" xlink:title=\"title\" />"
50+ image "/url" "title" mempty
51− ]
51+ =?> "<graphic mimetype=\"image\" mime-subtype=\"\" xlink:href=\"/url\" xlink:title=\"title\" />"
52− , testGroup "inlines"
52+ ]
53− [ "Emphasis" =: emph "emphasized"
53+ , testGroup "inlines"
54− =?> "<p><italic>emphasized</italic></p>"
54+ [ "Emphasis" =: emph "emphasized"
55−
55+ =?> "<p><italic>emphasized</italic></p>"
56− , test jatsArticleAuthoring "footnote in articleauthoring tag set"
56+
57− ("test" <> note (para "footnote") =?>
57+ , test jatsArticleAuthoring "footnote in articleauthoring tag set"
58− unlines [ "<p>test<fn>"
58+ ("test" <> note (para "footnote") =?>
59− , " <p>footnote</p>"
59+ unlines [ "<p>test<fn>"
60− , "</fn></p>"
60+ , " <p>footnote</p>"
61− ])
61+ , "</fn></p>"
62− ]
62+ ])
63− , "bullet list" =: bulletList [ plain $ text "first"
63+ ]
64− , plain $ text "second"
64+ , "bullet list" =: bulletList [ plain $ text "first"
65− , plain $ text "third"
65+ , plain $ text "second"
66− ]
66+ , plain $ text "third"
67− =?> "<list list-type=\"bullet\">\n\
67+ ]
68− \ <list-item>\n\
68+ =?> "<list list-type=\"bullet\">\n\
69− \ <p>first</p>\n\
69+ \ <list-item>\n\
70− \ </list-item>\n\
70+ \ <p>first</p>\n\
71− \ <list-item>\n\
71+ \ </list-item>\n\
72− \ <p>second</p>\n\
72+ \ <list-item>\n\
73− \ </list-item>\n\
73+ \ <p>second</p>\n\
74− \ <list-item>\n\
74+ \ </list-item>\n\
75− \ <p>third</p>\n\
75+ \ <list-item>\n\
76− \ </list-item>\n\
76+ \ <p>third</p>\n\
77− \</list>"
77+ \ </list-item>\n\
78− , testGroup "definition lists"
78+ \</list>"
79− [ "with internal link" =: definitionList [(link "#go" "" (str "testing"),
79+ , testGroup "definition lists"
80− [plain (text "hi there")])] =?>
80+ [ "with internal link" =: definitionList [(link "#go" "" (str "testing"),
81− "<def-list>\n\
81+ [plain (text "hi there")])] =?>
82− \ <def-item>\n\
82+ "<def-list>\n\
83− \ <term><xref alt=\"testing\" rid=\"go\">testing</xref></term>\n\
83+ \ <def-item>\n\
84− \ <def>\n\
84+ \ <term><xref alt=\"testing\" rid=\"go\">testing</xref></term>\n\
85− \ <p>hi there</p>\n\
85+ \ <def>\n\
86− \ </def>\n\
86+ \ <p>hi there</p>\n\
87− \ </def-item>\n\
87+ \ </def>\n\
88− \</def-list>"
88+ \ </def-item>\n\
89− ]
89+ \</def-list>"
90− , testGroup "math"
90+ ]
91− [ "escape |" =: para (math "\\sigma|_{\\{x\\}}") =?>
91+ , testGroup "math"
92− "<p><inline-formula><alternatives>\n\
92+ [ "escape |" =: para (math "\\sigma|_{\\{x\\}}") =?>
93− \<tex-math><![CDATA[\\sigma|_{\\{x\\}}]]></tex-math>\n\
93+ "<p><inline-formula><alternatives>\n\
94− \<mml:math display=\"inline\" xmlns:mml=\"http://www.w3.org/1998/Math/MathML\"><mml:mrow><mml:mi>σ</mml:mi><mml:msub><mml:mo stretchy=\"false\" form=\"prefix\">|</mml:mo><mml:mrow><mml:mo stretchy=\"false\" form=\"prefix\">{</mml:mo><mml:mi>x</mml:mi><mml:mo stretchy=\"false\" form=\"postfix\">}</mml:mo></mml:mrow></mml:msub></mml:mrow></mml:math></alternatives></inline-formula></p>"
94+ \<tex-math><![CDATA[\\sigma|_{\\{x\\}}]]></tex-math>\n\
95− ]
95+ \<mml:math display=\"inline\" xmlns:mml=\"http://www.w3.org/1998/Math/MathML\"><mml:mrow><mml:mi>σ</mml:mi><mml:msub><mml:mo stretchy=\"false\" form=\"prefix\">|</mml:mo><mml:mrow><mml:mo stretchy=\"false\" form=\"prefix\">{</mml:mo><mml:mi>x</mml:mi><mml:mo stretchy=\"false\" form=\"postfix\">}</mml:mo></mml:mrow></mml:msub></mml:mrow></mml:math></alternatives></inline-formula></p>"
96− , testGroup "headers"
96+ ]
97− [ "unnumbered header" =:
97+ , testGroup "headers"
98− headerWith ("foo",["unnumbered"],[]) 1
98+ [ "unnumbered header" =:
99− (text "Header 1" <> note (plain $ text "note")) =?>
99+ headerWith ("foo",["unnumbered"],[]) 1
100− "<sec id=\"foo\">\n\
100+ (text "Header 1" <> note (plain $ text "note")) =?>
101− \ <title>Header 1<xref ref-type=\"fn\" rid=\"fn1\">1</xref></title>\n\
101+ "<sec id=\"foo\">\n\
102− \</sec>"
102+ \ <title>Header 1<xref ref-type=\"fn\" rid=\"fn1\">1</xref></title>\n\
103− , "unnumbered sub header" =:
103+ \</sec>"
104− headerWith ("foo",["unnumbered"],[]) 1
104+ , "unnumbered sub header" =:
105− (text "Header")
105+ headerWith ("foo",["unnumbered"],[]) 1
106− <> headerWith ("foo",["unnumbered"],[]) 2
106+ (text "Header")
107− (text "Sub-Header") =?>
107+ <> headerWith ("foo",["unnumbered"],[]) 2
108− "<sec id=\"foo\">\n\
108+ (text "Sub-Header") =?>
109− \ <title>Header</title>\n\
109+ "<sec id=\"foo\">\n\
110− \ <sec id=\"foo\">\n\
110+ \ <title>Header</title>\n\
111− \ <title>Sub-Header</title>\n\
111+ \ <sec id=\"foo\">\n\
112− \ </sec>\n\
112+ \ <title>Sub-Header</title>\n\
113− \</sec>"
113+ \ </sec>\n\
114− , "containing image" =:
114+ \</sec>"
115− header 1 (image "imgs/foo.jpg" "" (text "Alt text")) =?>
115+ , "containing image" =:
116− "<sec>\n\
116+ header 1 (image "imgs/foo.jpg" "" (text "Alt text")) =?>
117− \ <title><inline-graphic mimetype=\"image\" mime-subtype=\"jpeg\" xlink:href=\"imgs/foo.jpg\" /></title>\n\
117+ "<sec>\n\
118− \</sec>"
118+ \ <title><inline-graphic mimetype=\"image\" mime-subtype=\"jpeg\" xlink:href=\"imgs/foo.jpg\" /></title>\n\
119− ]
119+ \</sec>"
120− ]
120+ ]
121+
122+ , testGroup "ids"
123+ [ "non-ASCII in header ID" =:
124+ headerWith ("smørbrød",[],[]) 1 (text "smørbrød") =?>
125+ T.unlines [ "<sec id=\"smørbrød\">"
126+ , " <title>smørbrød</title>"
127+ , "</sec>"
128+ ]
129+
130+ , "disallowed symbol in header id" =:
131+ headerWith ("i/o",[],[]) 1 (text "I/O") =?>
132+ T.unlines [ "<sec id=\"iU002Fo\">"
133+ , " <title>I/O</title>"
134+ , "</sec>"
135+ ]
136+
137+ , "disallowed symbols in internal link target" =:
138+ link "#foo:bar" "" "baz" =?>
139+ "<p><xref alt=\"baz\" rid=\"fooU003Abar\">baz</xref></p>"
140+
141+ , "code id starting with a number" =:
142+ codeWith ("7y",[],[]) "print 5" =?>
143+ "<p><monospace id=\"U0037y\">print 5</monospace></p>"
144+ ]
145+
146+ , testGroup "spans"
147+ [ "unwrapped if no attributes given" =:
148+ spanWith nullAttr "text in span" =?>
149+ "<p>text in span</p>"
150+
151+ , "converted to named-content element if class given" =:
152+ spanWith ("a", ["genus-species"], [("alt", "aa")]) "C. elegans" =?>
153+ ("<p><named-content id=\"a\" alt=\"aa\" content-type=\"genus-species\">"
154+ <> "C. elegans</named-content></p>")
155+
156+ , "unwrapped if styled-content element would have no attributes" =:
157+ spanWith ("", [], [("hidden", "true")]) "text in span" =?>
158+ "<p>text in span</p>"
159+
160+ , "use content-type attribute if present" =:
161+ spanWith ("", [], [("content-type", "species")]) "E. coli" =?>
162+ "<p><named-content content-type=\"species\">E. coli</named-content></p>"
163+ ]
164+ ]
test/Tests/Writers/Jira.hs+12
@@ -61,12 +61,24 @@ tests =
61 , "user link with user as description" =:
61 , "user link with user as description" =:
62 linkWith ("", ["user-account"], []) "~johndoe" "" "~johndoe" =?>
62 linkWith ("", ["user-account"], []) "~johndoe" "" "~johndoe" =?>
63 "[~johndoe]"
63 "[~johndoe]"
64+
65+ , "'smart' link" =:
66+ para (linkWith ("", ["smart-link"], []) "http://example.com" "" "x") =?>
67+ "[x|http://example.com|smart-link]"
68+
69+ , "'smart' card" =:
70+ para (linkWith ("", ["smart-card"], []) "http://example.org" "" "x") =?>
71+ "[x|http://example.org|smart-card]"
64 ]
72 ]
65
73
66 , testGroup "spans"
74 , testGroup "spans"
67 [ "id is used as anchor" =:
75 [ "id is used as anchor" =:
68 spanWith ("unicorn", [], []) (str "Unicorn") =?>
76 spanWith ("unicorn", [], []) (str "Unicorn") =?>
69 "{anchor:unicorn}Unicorn"
77 "{anchor:unicorn}Unicorn"
78+
79+ , "use `color` attribute" =:
80+ spanWith ("",[],[("color","red")]) "ruby" =?>
81+ "{color:red}ruby{color}"
70 ]
82 ]
71
83
72 , testGroup "code"
84 , testGroup "code"
test/Tests/Writers/OOXML.hs+3−1
@@ -55,7 +55,9 @@ testArchive :: (WriterOptions -> Pandoc -> PandocIO BL.ByteString)
55 -> IO Archive
55 -> IO Archive
56testArchive writerFn opts fp = do
56testArchive writerFn opts fp = do
57 txt <- T.readFile fp
57 txt <- T.readFile fp
58− bs <- runIOorExplode $ readNative def txt >>= writerFn opts
58+ bs <- runIOorExplode $ do
59+ setTranslations "en-US"
60+ readNative def txt >>= writerFn opts
59 return $ toArchive bs
61 return $ toArchive bs
60
62
61compareFileList :: FilePath -> Archive -> Archive -> Maybe String
63compareFileList :: FilePath -> Archive -> Archive -> Maybe String
test/command/1279.md+1−1
@@ -9,7 +9,7 @@ title: My Article
9[^1]: Dept. of This and That
9[^1]: Dept. of This and That
10^D
10^D
11---
11---
12−author: "John Doe[^1]"
12+author: John Doe[^1]
13date: 2014
13date: 2014
14title: My Article
14title: My Article
15---
15---
test/command/2103.mdnew file+8
@@ -0,0 +1,8 @@
1+```
2+pandoc -t latex
3+| A happy pandoc user said "fix this bug please
4+| or I'll go crazy!"
5+^D
6+A happy pandoc user said ``fix this bug please\\
7+or I'll go crazy!''
8+```
test/command/2874.md+2−2
@@ -3,12 +3,12 @@
3<a></a>
3<a></a>
4<br/>
4<br/>
5^D
5^D
6−{}~\\
6+{}\strut \\
7```
7```
8
8
9```
9```
10% pandoc -f html -t latex
10% pandoc -f html -t latex
11<a name="foo"></a><br/>
11<a name="foo"></a><br/>
12^D
12^D
13−\protect\hypertarget{foo}{}{}~\\
13+\protect\hypertarget{foo}{}{}\strut \\
14```
14```
test/command/3752.mdnew file+60
@@ -0,0 +1,60 @@
1+```
2+% pandoc command/chap1/text.md command/chap2/text.md -f markdown+rebase_relative_paths --verbose -t docx -o - | pandoc -f docx -t plain
3+^D
4+[INFO] Loaded command/chap1/spider.png from command/chap1/spider.png
5+[INFO] Loaded command/chap2/spider.png from command/chap2/spider.png
6+[INFO] Loaded command/chap1/../../lalune.jpg from command/chap1/../../lalune.jpg
7+Chapter one
8+
9+A spider: [spider]
10+
11+Another spider: [another spider]
12+
13+The moon: [moon]
14+
15+Link to spider picture.
16+
17+URL left alone: manual.
18+
19+Absolute path left alone: absolute.
20+
21+Link to fragment: chapter two.
22+
23+Empty path: empty.
24+
25+Chapter two
26+
27+A spider: [spider]
28+```
29+
30+```
31+% pandoc command/chap1/text.md command/chap2/text.md -f markdown+rebase_relative_paths -t html
32+^D
33+<h1 id="chapter-one">Chapter one</h1>
34+<p>A spider: <img src="command/chap1/spider.png" alt="spider" /></p>
35+<p>Another spider: <img src="command/chap2/spider.png" alt="another spider" /></p>
36+<p>The moon: <img src="command/chap1/../../lalune.jpg" alt="moon" /></p>
37+<p>Link to <a href="command/chap1/spider.png">spider picture</a>.</p>
38+<p>URL left alone: <a href="https://pandoc.org/MANUAL.html">manual</a>.</p>
39+<p>Absolute path left alone: <a href="/foo/bar/baz.png">absolute</a>.</p>
40+<p>Link to fragment: <a href="#chapter-two">chapter two</a>.</p>
41+<p>Empty path: <a href="">empty</a>.</p>
42+<h1 id="chapter-two">Chapter two</h1>
43+<p>A spider: <img src="command/chap2/spider.png" alt="spider" /></p>
44+```
45+
46+```
47+% pandoc command/chap1/text.md command/chap2/text.md -f commonmark+rebase_relative_paths -t html
48+^D
49+<h1>Chapter one</h1>
50+<p>A spider: <img src="command/chap1/spider.png" alt="spider" /></p>
51+<p>Another spider: <img src="command/chap2/spider.png" alt="another spider" /></p>
52+<p>The moon: <img src="command/chap1/../../lalune.jpg" alt="moon" /></p>
53+<p>Link to <a href="command/chap1/spider.png">spider picture</a>.</p>
54+<p>URL left alone: <a href="https://pandoc.org/MANUAL.html">manual</a>.</p>
55+<p>Absolute path left alone: <a href="/foo/bar/baz.png">absolute</a>.</p>
56+<p>Link to fragment: <a href="#chapter-two">chapter two</a>.</p>
57+<p>Empty path: <a href="">empty</a>.</p>
58+<h1>Chapter two</h1>
59+<p>A spider: <img src="command/chap2/spider.png" alt="spider" /></p>
60+```
test/command/3792.md+1−1
@@ -6,7 +6,7 @@ and properly escaped.
6ok
6ok
7^D
7^D
8---
8---
9−title: \<this\> \*that\*
9+title: \<this> \*that\*
10---
10---
11
11
12ok
12ok
test/command/4063.mdnew file+29
@@ -0,0 +1,29 @@
1+```
2+% pandoc -f html -t native
3+<table>
4+<colgroup>
5+ <col width="30%" />
6+ <col width="*" />
7+</colgroup>
8+<tr>
9+ <td>1</td>
10+ <td>2</td>
11+</tr>
12+</table>
13+^D
14+[Table ("",[],[]) (Caption Nothing
15+ [])
16+ [(AlignDefault,ColWidth 0.3)
17+ ,(AlignDefault,ColWidth 0.7)]
18+ (TableHead ("",[],[])
19+ [])
20+ [(TableBody ("",[],[]) (RowHeadColumns 0)
21+ []
22+ [Row ("",[],[])
23+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
24+ [Plain [Str "1"]]
25+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
26+ [Plain [Str "2"]]]])]
27+ (TableFoot ("",[],[])
28+ [])]
29+```
test/command/4164.md+1−1
@@ -26,6 +26,6 @@ Here is inline html:
26
26
27Here is inline html:
27Here is inline html:
28
28
29−\<div\> \<balise\> bla bla \</div\>
29+\<div> \<balise> bla bla \</div>
30
30
31```
31```
test/command/4442.md+1−1
@@ -5,5 +5,5 @@
5^D
5^D
6\newcommand{\myFruit}{Mango\xspace}
6\newcommand{\myFruit}{Mango\xspace}
7
7
8−Mango\xspace is the king of fruits.
8+Mango is the king of fruits.
9```
9```
test/command/4465.mdnew file+15
@@ -0,0 +1,15 @@
1+```
2+% pandoc -f html -t markdown
3+<ol>
4+ <li>An ordered list can contain block-level elements ind html, it means that divs are also allowed.</li>
5+ <li>Let's see the problem! <div class="example">This is an example.</div></li>
6+</ol>
7+^D
8+1. An ordered list can contain block-level elements ind html, it means
9+ that divs are also allowed.
10+2. Let\'s see the problem!
11+
12+ ::: example
13+ This is an example.
14+ :::
15+```
test/command/5304.md+1−1
@@ -11,7 +11,7 @@
11...
11...
12```
12```
13^D
13^D
14−``` {.markdown}
14+``` markdown
15`«sträng»`
15`«sträng»`
16
16
17`` «sträng» ``
17`` «sträng» ``
test/command/5367.md+6−2
@@ -24,11 +24,15 @@ hello\footnote{doc footnote}
24 >{\centering\arraybackslash}p{(\columnwidth - 0\tabcolsep) * \real{0.17}}@{}}
24 >{\centering\arraybackslash}p{(\columnwidth - 0\tabcolsep) * \real{0.17}}@{}}
25\caption[Sample table.]{Sample table.\footnote{caption footnote}}\tabularnewline
25\caption[Sample table.]{Sample table.\footnote{caption footnote}}\tabularnewline
26\toprule
26\toprule
27−Fruit\footnote{header footnote} \\
27+\begin{minipage}[b]{\linewidth}\centering
28+Fruit\footnote{header footnote}
29+\end{minipage} \\
28\midrule
30\midrule
29\endfirsthead
31\endfirsthead
30\toprule
32\toprule
31−Fruit{} \\
33+\begin{minipage}[b]{\linewidth}\centering
34+Fruit{}
35+\end{minipage} \\
32\midrule
36\midrule
33\endhead
37\endhead
34Bans\footnote{table cell footnote} \\
38Bans\footnote{table cell footnote} \\
test/command/5519.md+1−1
@@ -6,7 +6,7 @@
6 ```
6 ```
7``````
7``````
8^D
8^D
9−```` {.attr}
9+```` attr
10 ```
10 ```
11 code
11 code
12 ```
12 ```
test/command/6026.mdnew file+19
@@ -0,0 +1,19 @@
1+```
2+% pandoc -t native
3+@{https://openreview.net/forum?id=HkwoSDPgg}
4+
5+@https://openreview.net/forum?id=HkwoSDPgg
6+^D
7+[Para [Cite [Citation {citationId = "https://openreview.net/forum?id=HkwoSDPgg", citationPrefix = [], citationSuffix = [], citationMode = AuthorInText, citationNoteNum = 1, citationHash = 0}] [Str "@https://openreview.net/forum?id=HkwoSDPgg"]]
8+,Para [Cite [Citation {citationId = "https://openreview.net/forum?id", citationPrefix = [], citationSuffix = [], citationMode = AuthorInText, citationNoteNum = 2, citationHash = 0}] [Str "@https://openreview.net/forum?id"],Str "=HkwoSDPgg"]]
9+```
10+```
11+% pandoc -t markdown
12+@{https://openreview.net/forum?id=HkwoSDPgg}
13+
14+@https://openreview.net/forum?id=HkwoSDPgg
15+^D
16+@{https://openreview.net/forum?id=HkwoSDPgg}
17+
18+@https://openreview.net/forum?id=HkwoSDPgg
19+```
test/command/6541.mdnew file+27
@@ -0,0 +1,27 @@
1+```
2+% pandoc -f docbook -t markdown -s
3+<?xml version="1.0"?>
4+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
5+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
6+<book>
7+
8+<bookinfo>
9+<title>Title</title>
10+<author>
11+<firstname>Firstname</firstname><surname>Lastname</surname>
12+</author>
13+<releaseinfo>1.17</releaseinfo>
14+</bookinfo>
15+
16+<para>Text.</para>
17+
18+</book>
19+^D
20+---
21+author: Firstname Lastname
22+releaseinfo: 1.17
23+title: Title
24+---
25+
26+Text.
27+```
test/command/6620.md+3
@@ -7,9 +7,12 @@
7\SI{0.135(21)}{\m}
7\SI{0.135(21)}{\m}
8
8
9\SI{12.3(60)}{\m}
9\SI{12.3(60)}{\m}
10+
11+\SI{10.0 \pm 3.3}{\ms}
10^D
12^D
11<p>23 ± 2 m</p>
13<p>23 ± 2 m</p>
12<p>125 ± 12 m</p>
14<p>125 ± 12 m</p>
13<p>0.135 ± 0.021 m</p>
15<p>0.135 ± 0.021 m</p>
14<p>12.3 ± 6 m</p>
16<p>12.3 ± 6 m</p>
17+<p>10.0 ± 3.3 ms</p>
15```
18```
test/command/6658.mdnew file+75
@@ -0,0 +1,75 @@
1+```
2+pandoc -f latex -t html
3+\num{12345,67890}
4+
5+\num{1+-2i}
6+
7+\num{.3e45}
8+
9+\num{1.654 x 2.34 x 3.430}
10+
11+\si{kg.m.s^{-1}}
12+
13+\si{\kilogram\metre\per\second}
14+
15+\si[per-mode=symbol]{\kilogram\metre\per\second}
16+
17+\si[per-mode=symbol]{\kilogram\metre\per\ampere\per\second}
18+
19+\numlist{10;20;30}
20+
21+\SIlist{0.13;0.67;0.80}{\milli\metre}
22+
23+\numrange{10}{20}
24+
25+\SIrange{0.13}{0.67}{\milli\metre}
26+
27+\ang{10}
28+
29+\ang{1;2;3}
30+
31+\ang{;;1}
32+
33+\ang{+10;;}
34+
35+\ang{-0;1;}
36+
37+\si{kg.m/s^2}
38+
39+\si{g_{polymer}~mol_{cat}.s^{-1}}
40+
41+\si{\kilo\gram\metre\per\square\second}
42+
43+\si{\gram\per\cubic\centi\metre}
44+
45+\si{\square\volt\cubic\lumen\per\farad}
46+
47+\si{\metre\squared\per\gray\cubic\lux}
48+
49+\si{\henry\second}
50+^D
51+<p>12345.67890</p>
52+<p>1 ± 2i</p>
53+<p>0.3 × 10<sup>45</sup></p>
54+<p>1.654 × 2.34 × 3.430</p>
55+<p>kg m s<sup>−1</sup></p>
56+<p>kg m s<sup>−1</sup></p>
57+<p>kg m/s</p>
58+<p>kg m/A/s</p>
59+<p>10, 20, &amp; 30</p>
60+<p>0.13 mm, 0.67 mm, &amp; 0.80 mm</p>
61+<p>10–20</p>
62+<p>0.13 mm–0.67 mm</p>
63+<p>10°</p>
64+<p>1°2′3″</p>
65+<p>1″</p>
66+<p>10°</p>
67+<p>-0°1′</p>
68+<p>kg m/s<sup>2</sup></p>
69+<p>g<sub>polymer</sub> mol<sub>cat</sub> s<sup>−1</sup></p>
70+<p>kg m s<sup>−2</sup></p>
71+<p>g cm<sup>−3</sup></p>
72+<p>V<sup>2</sup> lm<sup>3</sup> F<sup>−1</sup></p>
73+<p>m<sup>2</sup> Gy<sup>−1</sup> lx<sup>3</sup></p>
74+<p>H s</p>
75+```
test/command/6709.mdnew file+11
@@ -0,0 +1,11 @@
1+Tabs must be expanded even if --file-scope is used
2+````
3+% pandoc -t native --file-scope --tab-stop=2
4+```
5+if true; then
6+ echo "yup"
7+fi
8+```
9+^D
10+[CodeBlock ("",[],[]) "if true; then\n echo \"yup\"\nfi"]
11+````
test/command/6890.md+2−2
@@ -23,12 +23,12 @@ references:
23
23
24@fruchtel-sozialer-2013a
24@fruchtel-sozialer-2013a
25
25
26−Some text [^1].
26+Some text.[^1]
27
27
28[^1]: @fruchtel-sozialer-2013a
28[^1]: @fruchtel-sozialer-2013a
29^D
29^D
30[Para [Cite [Citation {citationId = "fruchtel-sozialer-2013a", citationPrefix = [], citationSuffix = [], citationMode = AuthorInText, citationNoteNum = 1, citationHash = 0}] [Str "Fr\252chtel,",Space,Str "Budde,",Space,Str "and",Space,Str "Cyprian",Space,Str "(2013)"]]
30[Para [Cite [Citation {citationId = "fruchtel-sozialer-2013a", citationPrefix = [], citationSuffix = [], citationMode = AuthorInText, citationNoteNum = 1, citationHash = 0}] [Str "Fr\252chtel,",Space,Str "Budde,",Space,Str "and",Space,Str "Cyprian",Space,Str "(2013)"]]
31−,Para [Str "Some",Space,Str "text",Str ".",Note [Para [Cite [Citation {citationId = "fruchtel-sozialer-2013a", citationPrefix = [], citationSuffix = [], citationMode = AuthorInText, citationNoteNum = 2, citationHash = 0}] [Str "Fr\252chtel,",Space,Str "Budde,",Space,Str "and",Space,Str "Cyprian",Space,Str "(2013)"]]],Str ""]
31+,Para [Str "Some",Space,Str "text.",Note [Para [Cite [Citation {citationId = "fruchtel-sozialer-2013a", citationPrefix = [], citationSuffix = [], citationMode = AuthorInText, citationNoteNum = 2, citationHash = 0}] [Str "Fr\252chtel,",Space,Str "Budde,",Space,Str "and",Space,Str "Cyprian",Space,Str "(2013)"]]]]
32,Div ("refs",["references","csl-bib-body","hanging-indent"],[])
32,Div ("refs",["references","csl-bib-body","hanging-indent"],[])
33 [Div ("ref-fruchtel-sozialer-2013a",["csl-entry"],[])
33 [Div ("ref-fruchtel-sozialer-2013a",["csl-entry"],[])
34 [Para [Str "Fr\252chtel,",Space,Str "Frank,",Space,Str "Wolfgang",Space,Str "Budde,",Space,Str "and",Space,Str "Gudrun",Space,Str "Cyprian.",Space,Str "2013.",Space,Emph [Str "Sozialer",Space,Str "Raum",Space,Str "und",Space,Str "Soziale",Space,Str "Arbeit",Space,Str "Fieldbook:",Space,Str "Methoden",Space,Str "und",Space,Str "Techniken"],Str ".",Space,Str "3rd",Space,Str "ed.",Space,Str "Wiesbaden,",Space,Str "Germany:",Space,Str "Springer",Space,Str "VS."]]]]
34 [Para [Str "Fr\252chtel,",Space,Str "Frank,",Space,Str "Wolfgang",Space,Str "Budde,",Space,Str "and",Space,Str "Gudrun",Space,Str "Cyprian.",Space,Str "2013.",Space,Emph [Str "Sozialer",Space,Str "Raum",Space,Str "und",Space,Str "Soziale",Space,Str "Arbeit",Space,Str "Fieldbook:",Space,Str "Methoden",Space,Str "und",Space,Str "Techniken"],Str ".",Space,Str "3rd",Space,Str "ed.",Space,Str "Wiesbaden,",Space,Str "Germany:",Space,Str "Springer",Space,Str "VS."]]]]
test/command/6925.md+2−2
@@ -20,13 +20,13 @@ a
20\end{thm2}
20\end{thm2}
21\end{document}
21\end{document}
22^D
22^D
23−::: {.thm}
23+::: thm
24**Theorem 1**. *a*
24**Theorem 1**. *a*
25
25
26![image](1.png)
26![image](1.png)
27:::
27:::
28
28
29−::: {.thm2}
29+::: thm2
30**Theorem 1**. a
30**Theorem 1**. a
31
31
32![image](1.png)
32![image](1.png)
test/command/6958.mdnew file+10
@@ -0,0 +1,10 @@
1+Add thin space between single and double quotes.
2+```
3+% pandoc -t latex+smart
4+---
5+lang: en-GB
6+---
7+'["On the Outside"]{}: Constructing Cycling Citizenship.'
8+^D
9+`\,{``On the Outside''}: Constructing Cycling Citizenship.'
10+```
test/command/7041.mdnew file+23
@@ -0,0 +1,23 @@
1+```
2+% pandoc -f html -t jats
3+<table>
4+ <tr><td><blockquote>Fly, you fools!</blockquote></td></tr>
5+</table>
6+^D
7+<table-wrap>
8+ <table>
9+ <colgroup>
10+ <col width="100%" />
11+ </colgroup>
12+ <tbody>
13+ <tr>
14+ <td><p specific-use="wrapper">
15+ <disp-quote>
16+ <p>Fly, you fools!</p>
17+ </disp-quote>
18+ </p></td>
19+ </tr>
20+ </tbody>
21+ </table>
22+</table-wrap>
23+```
test/command/7099.md+1−1
@@ -11,7 +11,7 @@
11<iframe src="h:invalid@url"></iframe>
11<iframe src="h:invalid@url"></iframe>
12^D
12^D
13[INFO] Fetching h:invalid@url...
13[INFO] Fetching h:invalid@url...
14−[WARNING] Could not fetch resource 'h:invalid@url': Could not fetch h:invalid@url
14+[WARNING] Could not fetch resource h:invalid@url: Could not fetch h:invalid@url
15 InvalidUrlException "h:invalid@url" "Invalid scheme"
15 InvalidUrlException "h:invalid@url" "Invalid scheme"
16[INFO] Skipped '<iframe src="h:invalid@url"></iframe>' at input line 1 column 29
16[INFO] Skipped '<iframe src="h:invalid@url"></iframe>' at input line 1 column 29
17[]
17[]
test/command/7173.mdnew file+137
@@ -0,0 +1,137 @@
1+```
2+% pandoc -f docbook -t latex
3+<?xml version="1.0" encoding="UTF-8"?>
4+<!DOCTYPE article PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">
5+<?xml-model href="http://www.oxygenxml.com/docbook/xml/5.0/rng/dbmathml.rng" schematypens="http://relaxng.org/ns/structure/1.0"?>
6+<?xml-model href="http://docbook.org/xml/5.0/rng/docbook.rng" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>
7+<article xmlns="http://docbook.org/ns/docbook"
8+ xmlns:xlink="http://www.w3.org/1999/xlink"
9+ version="5.1">
10+ <title>Untitled Document</title>
11+ <para>Word</para>
12+ <informalequation>
13+ <alt role='tex'>1+2</alt>
14+ <m:math xmlns:m="http://www.w3.org/1998/Math/MathML">
15+ <m:mrow>
16+ <m:mrow><m:mn>1</m:mn><m:mo>+</m:mo><m:mn>2</m:mn>
17+ </m:mrow>
18+ </m:mrow>
19+ </m:math>
20+ </informalequation>
21+</article>
22+^D
23+Word
24+
25+\[1 + 2\]
26+```
27+
28+```
29+% pandoc -f docbook -t latex
30+<?xml version="1.0" encoding="UTF-8"?>
31+<!DOCTYPE article PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">
32+<?xml-model href="http://www.oxygenxml.com/docbook/xml/5.0/rng/dbmathml.rng" schematypens="http://relaxng.org/ns/structure/1.0"?>
33+<?xml-model href="http://docbook.org/xml/5.0/rng/docbook.rng" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>
34+<article xmlns="http://docbook.org/ns/docbook"
35+ xmlns:xlink="http://www.w3.org/1999/xlink"
36+ version="5.1">
37+ <title>Untitled Document</title>
38+ <para>Word</para>
39+ <informalequation>
40+ <alt role='tex'>1+2</alt>
41+ <mml:math xmlns:mml="http://www.w3.org/1998/Math/MathML">
42+ <mml:mrow>
43+ <mml:mrow><mml:mn>1</mml:mn><mml:mo>+</mml:mo><mml:mn>2</mml:mn>
44+ </mml:mrow>
45+ </mml:mrow>
46+ </mml:math>
47+ </informalequation>
48+</article>
49+^D
50+Word
51+
52+\[1 + 2\]
53+```
54+
55+```
56+% pandoc -f docbook -t latex
57+<?xml version="1.0" encoding="UTF-8"?>
58+<!DOCTYPE article PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">
59+<?xml-model href="http://www.oxygenxml.com/docbook/xml/5.0/rng/dbmathml.rng" schematypens="http://relaxng.org/ns/structure/1.0"?>
60+<?xml-model href="http://docbook.org/xml/5.0/rng/docbook.rng" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>
61+<article xmlns="http://docbook.org/ns/docbook"
62+ xmlns:xlink="http://www.w3.org/1999/xlink"
63+ version="5.1">
64+ <title>Untitled Document</title>
65+ <para>Word</para>
66+ <informalequation>
67+ <alt role='tex'>1+2</alt>
68+ <math xmlns="http://www.w3.org/1998/Math/MathML">
69+ <mrow>
70+ <mrow><mn>1</mn><mo>+</mo><mn>2</mn>
71+ </mrow>
72+ </mrow>
73+ </math>
74+ </informalequation>
75+</article>
76+^D
77+Word
78+
79+\[1 + 2\]
80+```
81+
82+```
83+% pandoc -f docbook -t latex
84+<?xml version="1.0" encoding="UTF-8"?>
85+<!DOCTYPE article PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">
86+<?xml-model href="http://www.oxygenxml.com/docbook/xml/5.0/rng/dbmathml.rng" schematypens="http://relaxng.org/ns/structure/1.0"?>
87+<?xml-model href="http://docbook.org/xml/5.0/rng/docbook.rng" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>
88+<article xmlns="http://docbook.org/ns/docbook"
89+ xmlns:xlink="http://www.w3.org/1999/xlink"
90+ xmlns:m="http://www.w3.org/1998/Math/MathML"
91+ version="5.1">
92+ <title>Untitled Document</title>
93+ <para>Word</para>
94+ <informalequation>
95+ <alt role='tex'>1+2</alt>
96+ <m:math>
97+ <m:mrow>
98+ <m:mrow><m:mn>1</m:mn><m:mo>+</m:mo><m:mn>2</m:mn>
99+ </m:mrow>
100+ </m:mrow>
101+ </m:math>
102+ </informalequation>
103+</article>
104+^D
105+Word
106+
107+\[1 + 2\]
108+```
109+
110+```
111+% pandoc -f docbook -t latex
112+<?xml version="1.0" encoding="UTF-8"?>
113+<!DOCTYPE article PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">
114+<?xml-model href="http://www.oxygenxml.com/docbook/xml/5.0/rng/dbmathml.rng" schematypens="http://relaxng.org/ns/structure/1.0"?>
115+<?xml-model href="http://docbook.org/xml/5.0/rng/docbook.rng" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>
116+<article xmlns="http://docbook.org/ns/docbook"
117+ xmlns:xlink="http://www.w3.org/1999/xlink"
118+ xmlns:mml="http://www.w3.org/1998/Math/MathML"
119+ version="5.1">
120+ <title>Untitled Document</title>
121+ <para>Word</para>
122+ <informalequation>
123+ <alt role='tex'>1+2</alt>
124+ <mml:math>
125+ <mml:mrow>
126+ <mml:mrow><mml:mn>1</mml:mn><mml:mo>+</mml:mo><mml:mn>2</mml:mn>
127+ </mml:mrow>
128+ </mml:mrow>
129+ </mml:math>
130+ </informalequation>
131+</article>
132+^D
133+Word
134+
135+\[1 + 2\]
136+```
137+
test/command/7208.mdnew file+6
@@ -0,0 +1,6 @@
1+```
2+% pandoc -t gfm
3+\<hi\>
4+^D
5+\<hi>
6+```
test/command/7214.mdnew file+28
@@ -0,0 +1,28 @@
1+```
2+% pandoc
3++------------+----------+------------------+
4+|日本語 | の文字列 | words in english |
5++------------+----------+------------------+
6+|abc defghij | def | xyz |
7++------------+----------+------------------+
8+^D
9+<table style="width:60%;">
10+<colgroup>
11+<col style="width: 18%" />
12+<col style="width: 15%" />
13+<col style="width: 26%" />
14+</colgroup>
15+<tbody>
16+<tr class="odd">
17+<td>日本語</td>
18+<td>の文字列</td>
19+<td>words in english</td>
20+</tr>
21+<tr class="even">
22+<td>abc defghij</td>
23+<td>def</td>
24+<td>xyz</td>
25+</tr>
26+</tbody>
27+</table>
28+```
test/command/7216.mdnew file+19
@@ -0,0 +1,19 @@
1+```
2+pandoc -t latex
3+"This is some text in quotes. Another paragraph by the same speaker follows. The first paragraph should have no close quote.
4+
5+"The second paragraph should have open and close quotes."
6+
7+| "Open quote on this line,
8+| Close quote on the next line."
9+| "Quotes on the same line."
10+^D
11+``This is some text in quotes. Another paragraph by the same speaker
12+follows. The first paragraph should have no close quote.
13+
14+``The second paragraph should have open and close quotes.''
15+
16+``Open quote on this line,\\
17+Close quote on the next line.''\\
18+``Quotes on the same line.''
19+```
test/command/7266.mdnew file+10
@@ -0,0 +1,10 @@
1+```
2+% pandoc -f biblatex -t biblatex -s
3+@article{id,
4+ annote = "annotation"
5+}
6+^D
7+@article{id,
8+ annote = {annotation}
9+}
10+```
test/command/7272.mdnew file+27
@@ -0,0 +1,27 @@
1+```
2+% pandoc -t latex -f html
3+<table>
4+ <tbody>
5+ <tr>
6+ <td>
7+ <span>
8+ text
9+ <br />
10+ text2
11+ </span>
12+ </td>
13+ </tr>
14+ </tbody>
15+</table>
16+^D
17+\begin{longtable}[]{@{}
18+ >{\raggedright\arraybackslash}p{(\columnwidth - 0\tabcolsep) * \real{1.00}}@{}}
19+\toprule
20+\endhead
21+\begin{minipage}[t]{\linewidth}\raggedright
22+{ text\\
23+text2 }\strut
24+\end{minipage} \\
25+\bottomrule
26+\end{longtable}
27+```
test/command/7278.mdnew file+38
@@ -0,0 +1,38 @@
1+```
2+% pandoc -t beamer
3+# Slide
4+
5+Some blocks:
6+
7+## example block title {.example}
8+
9+text in block
10+
11+## alert block title {.alert}
12+
13+text in block
14+
15+## block title
16+
17+text in block
18+^D
19+\begin{frame}{Slide}
20+\protect\hypertarget{slide}{}
21+Some blocks:
22+
23+\begin{exampleblock}{example block title}
24+\protect\hypertarget{example-block-title}{}
25+text in block
26+\end{exampleblock}
27+
28+\begin{alertblock}{alert block title}
29+\protect\hypertarget{alert-block-title}{}
30+text in block
31+\end{alertblock}
32+
33+\begin{block}{block title}
34+\protect\hypertarget{block-title}{}
35+text in block
36+\end{block}
37+\end{frame}
38+```
test/command/7282.mdnew file+7
@@ -0,0 +1,7 @@
1+Don't crash on unmatched closing tag.
2+```
3+% pandoc -f html -t native
4+</script>
5+^D
6+[]
7+```
test/command/7288.mdnew file+40
@@ -0,0 +1,40 @@
1+```
2+% pandoc -f rst -t ms
3+.. list-table::
4+ :widths: 50 50
5+ :header-rows: 1
6+
7+ * - Left
8+ - Right
9+ * - Long text that should be easy to break up into multiple lines
10+ - Another long text that should be easy to break up into multiple lines
11+
12+ Bar
13+^D
14+.PP
15+.na
16+.nr LLold \n[LL]
17+.TS
18+delim(@@) tab( );
19+lw(35.0n) lw(35.0n).
20+T{
21+Left
22+T} T{
23+Right
24+T}
25+_
26+T{
27+.nr LL 35.0n
28+.LP
29+Long text that should be easy to break up into multiple lines
30+T} T{
31+.nr LL 35.0n
32+.PP
33+Another long text that should be easy to break up into multiple lines
34+.PP
35+Bar
36+T}
37+.TE
38+.nr LL \n[LLold]
39+.ad
40+```
test/command/7299.mdnew file+23
@@ -0,0 +1,23 @@
1+```
2+% pandoc -f latex -t plain
3+$1-{\ensuremath{r}\xspace}$
4+^D
5+1 − r
6+```
7+
8+```
9+% pandoc -f latex -t plain
10+\newcommand{\foo}{Foo\xspace}
11+
12+$\text{\foo bar}$
13+^D
14+Foo bar
15+```
16+
17+```
18+% pandoc -f latex -t plain
19+a\xspace b
20+^D
21+a b
22+```
23+
test/command/7321.mdnew file+24
@@ -0,0 +1,24 @@
1+```
2+% pandoc -t plain --citeproc --wrap=none
3+---
4+references:
5+- id: fenner2012a
6+ title: One-click science marketing
7+ author:
8+ - family: Fenner
9+ given: Martin
10+ container-title: Nature Materials
11+ volume: 11
12+ issue: 4
13+ publisher: Nature Publishing Group
14+ type: article-journal
15+ issued:
16+ year: 2012
17+---
18+
19+[@fenner2012a, $a^2+b^2=c^2$]
20+^D
21+(Fenner 2012, a² + b² = c²)
22+
23+Fenner, Martin. 2012. “One-Click Science Marketing.” Nature Materials 11 (4).
24+```
test/command/7323.mdnew file+29
@@ -0,0 +1,29 @@
1+```
2+% pandoc --citeproc -t plain
3+---
4+references:
5+- id: smith
6+ author: John Smith
7+ issued: 2019
8+ title: Insects
9+ type: book
10+...
11+
12+@smith [chap. 6]
13+
14+@smith [chapter 6]
15+
16+@smith [Chap. 6]
17+
18+@smith [Chapter 6]
19+^D
20+John Smith (2019, chap. 6)
21+
22+John Smith (2019, chap. 6)
23+
24+John Smith (2019, chap. 6)
25+
26+John Smith (2019, chap. 6)
27+
28+John Smith. 2019. Insects.
29+```
test/command/7324.mdnew file+25
@@ -0,0 +1,25 @@
1+```
2+% pandoc --citeproc -t plain
3+---
4+references:
5+- id: smith
6+ author: John Smith
7+ issued: 2019
8+ title: Insects
9+ type: book
10+...
11+
12+@smith [, among others]
13+
14+@smith [ among others]
15+
16+@smith [among others]
17+^D
18+John Smith (2019, among others)
19+
20+John Smith (2019 among others)
21+
22+John Smith (2019, among others)
23+
24+John Smith. 2019. Insects.
25+```
test/command/7339.mdnew file+11
@@ -0,0 +1,11 @@
1+```
2+% pandoc -f gfm -s -t native
3+---
4+title: Test
5+---
6+
7+Hi
8+^D
9+Pandoc (Meta {unMeta = fromList [("title",MetaInlines [Str "Test"])]})
10+[Para [Str "Hi"]]
11+```
test/command/7340.mdnew file+6
@@ -0,0 +1,6 @@
1+```
2+% pandoc -f latex -t native
3+\(*\)
4+^D
5+[Para [Math InlineMath "*"]]
6+```
test/command/7376.mdnew file+16
@@ -0,0 +1,16 @@
1+```
2+% pandoc --citeproc -t plain
3+---
4+references:
5+- id: item1
6+ type: book
7+ author:
8+ - family: Doe
9+ given: Jane
10+ issued: 2020
11+ title: The title
12+...
13+^D
14+
15+
16+```
test/command/7394.mdnew file+85
@@ -0,0 +1,85 @@
1+```
2+% pandoc -f markdown -t plain --citeproc
3+---
4+csl: command/chicago-fullnote-bibliography.csl
5+references:
6+- author:
7+ - family: Wandt
8+ given: Manfred
9+ edition: 6
10+ id: wandt2014ges-sv
11+ issued: 2014
12+ publisher: Franz Vahlen
13+ publisher-place: München
14+ title: Gesetzliche schuldverhältnisse
15+ title-short: Gesetzl SV
16+ type: book
17+- author:
18+ - family: Smith
19+ given: Zenda
20+ edition: 6
21+ id: smith2015
22+ issued: 2015
23+ publisher: Macmillan
24+ publisher-place: New York
25+ title: A verb and a noun
26+ type: book
27+---
28+
29+Hi^[@wandt2014ges-sv.].
30+
31+Hi^[[@wandt2014ges-sv].].
32+
33+Hi^[[See also @wandt2014ges-sv].].
34+
35+Hi^[See also @wandt2014ges-sv.].
36+
37+Hi^[@wandt2014ges-sv [@smith2015].].
38+
39+Hi^[[@wandt2014ges-sv; @smith2015].].
40+
41+Hi [@wandt2014ges-sv].
42+
43+Hi [see also @wandt2014ges-sv].
44+
45+^D
46+Hi[1].
47+
48+Hi[2].
49+
50+Hi[3].
51+
52+Hi[4].
53+
54+Hi[5].
55+
56+Hi[6].
57+
58+Hi.[7]
59+
60+Hi.[8]
61+
62+Smith, Zenda. A Verb and a Noun. 6th ed. New York: Macmillan, 2015.
63+
64+Wandt, Manfred. Gesetzliche Schuldverhältnisse. 6th ed. München: Franz
65+Vahlen, 2014.
66+
67+[1] Manfred Wandt, Gesetzliche Schuldverhältnisse, 6th ed. (München:
68+Franz Vahlen, 2014).
69+
70+[2] Wandt.
71+
72+[3] See also Wandt.
73+
74+[4] See also Wandt.
75+
76+[5] Wandt, Zenda Smith, A Verb and a Noun, 6th ed. (New York: Macmillan,
77+2015).
78+
79+[6] Wandt, Gesetzl SV; Smith, A Verb and a Noun.
80+
81+[7] Wandt, Gesetzl SV.
82+
83+[8] See also Wandt.
84+```
85+
test/command/7397.mdnew file+14
@@ -0,0 +1,14 @@
1+````
2+% pandoc -t markdown
3+~~~~ { .haskell startFrom="100"}
4+qsort [] = []
5+qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++
6+ qsort (filter (>= x) xs)
7+~~~~
8+^D
9+``` {.haskell startFrom="100"}
10+qsort [] = []
11+qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++
12+ qsort (filter (>= x) xs)
13+```
14+````
test/command/7400.mdnew file+9
@@ -0,0 +1,9 @@
1+```
2+% pandoc -t native -s
3+---
4+# Comment only
5+...
6+^D
7+Pandoc (Meta {unMeta = fromList []})
8+[]
9+```
test/command/7416.mdnew file+19
@@ -0,0 +1,19 @@
1+```
2+% pandoc -f markdown -t html
3+![caption](../media/rId25.jpg "title"){alt="alt"}
4+
5+^D
6+<figure>
7+<img src="../media/rId25.jpg" title="title" alt="alt" /><figcaption>caption</figcaption>
8+</figure>
9+```
10+
11+```
12+% pandoc -f markdown -t html
13+![caption](../media/rId25.jpg "title")
14+
15+^D
16+<figure>
17+<img src="../media/rId25.jpg" title="title" alt="caption" /><figcaption aria-hidden="true">caption</figcaption>
18+</figure>
19+```
test/command/averroes.bibnew file+95
@@ -0,0 +1,95 @@
1+@string{anch-ie = {Angew.~Chem. Int.~Ed.}}
2+@string{cup = {Cambridge University Press}}
3+@string{dtv = {Deutscher Taschenbuch-Verlag}}
4+@string{hup = {Harvard University Press}}
5+@string{jams = {J.~Amer. Math. Soc.}}
6+@string{jchph = {J.~Chem. Phys.}}
7+@string{jomch = {J.~Organomet. Chem.}}
8+@string{pup = {Princeton University Press}}
9+
10+@book{averroes/bland,
11+ author = {Averroes},
12+ title = {The Epistle on the Possibility of Conjunction with the Active
13+ Intellect by {Ibn Rushd} with the Commentary of {Moses Narboni}},
14+ date = 1982,
15+ editor = {Bland, Kalman P.},
16+ translator = {Bland, Kalman P.},
17+ series = {Moreshet: Studies in {Jewish} History, Literature and Thought},
18+ number = 7,
19+ publisher = {Jewish Theological Seminary of America},
20+ location = {New York},
21+ keywords = {primary},
22+ langid = {english},
23+ langidopts = {variant=american},
24+ indextitle = {Epistle on the Possibility of Conjunction, The},
25+ shorttitle = {Possibility of Conjunction},
26+ annotation = {A \texttt{book} entry with a \texttt{series} and a
27+ \texttt{number}. Note the concatenation of the \texttt{editor}
28+ and \texttt{translator} fields as well as the
29+ \texttt{indextitle} field},
30+}
31+
32+@book{averroes/hannes,
33+ author = {Averroes},
34+ title = {Des Averro{\"e}s Abhandlung: \mkbibquote{{\"U}ber die
35+ M{\"o}glichkeit der Conjunktion} oder \mkbibquote{{\"U}ber den
36+ materiellen Intellekt}},
37+ date = 1892,
38+ editor = {Hannes, Ludwig},
39+ translator = {Hannes, Ludwig},
40+ annotator = {Hannes, Ludwig},
41+ publisher = {C.~A. Kaemmerer},
42+ location = {Halle an der Saale},
43+ keywords = {primary},
44+ langid = {german},
45+ sorttitle = {Uber die Moglichkeit der Conjunktion},
46+ indexsorttitle= {Uber die Moglichkeit der Conjunktion},
47+ indextitle = {{\"U}ber die M{\"o}glichkeit der Conjunktion},
48+ shorttitle = {{\"U}ber die M{\"o}glichkeit der Conjunktion},
49+ annotation = {An annotated edition. Note the concatenation of the
50+ \texttt{editor}, \texttt{translator}, and \texttt{annotator}
51+ fields. Also note the \texttt{shorttitle},
52+ \texttt{indextitle}, \texttt{sorttitle}, and
53+ \texttt{indexsorttitle} fields},
54+}
55+
56+@book{averroes/hercz,
57+ author = {Averroes},
58+ title = {Drei Abhandlungen {\"u}ber die Conjunction des separaten
59+ Intellects mit dem Menschen},
60+ date = 1869,
61+ editor = {Hercz, J.},
62+ translator = {Hercz, J.},
63+ publisher = {S.~Hermann},
64+ location = {Berlin},
65+ keywords = {primary},
66+ langid = {german},
67+ indexsorttitle= {Drei Abhandlungen uber die Conjunction},
68+ indextitle = {Drei Abhandlungen {\"u}ber die Conjunction},
69+ subtitle = {Von Averroes (Vater und Sohn), aus dem Arabischen
70+ {\"u}bersetzt von Samuel Ibn Tibbon},
71+ shorttitle = {Drei Abhandlungen},
72+ annotation = {A \texttt{book} entry. Note the concatenation of the
73+ \texttt{editor} and \texttt{translator} fields as well as the
74+ \texttt{indextitle} and \texttt{indexsorttitle} fields},
75+}
76+
77+@book{cicero,
78+ author = {Cicero, Marcus Tullius},
79+ title = {De natura deorum. {\"U}ber das Wesen der G{\"o}tter},
80+ date = 1995,
81+ editor = {Blank-Sangmeister, Ursula},
82+ translator = {Blank-Sangmeister, Ursula},
83+ afterword = {Thraede, Klaus},
84+ language = {langlatin and langgerman},
85+ publisher = {Reclam},
86+ location = {Stuttgart},
87+ langid = {german},
88+ indextitle = {De natura deorum},
89+ shorttitle = {De natura deorum},
90+ annotation = {A bilingual edition of Cicero's \emph{De natura deorum}, with
91+ a German translation. Note the format of the \texttt{language}
92+ field in the database file, the concatenation of the
93+ \texttt{editor} and \texttt{translator} fields, and the
94+ \texttt{afterword} field},
95+}
test/command/biblatex-basic.md+5−3
@@ -1,3 +1,5 @@
1+```
2+% pandoc -f biblatex -t markdown -s
1@Book{item1,
3@Book{item1,
2author="John Doe",
4author="John Doe",
3title="First Book",
5title="First Book",
@@ -27,7 +29,7 @@ year="2007"
27
29
28^D
30^D
29---
31---
30−nocite: '[@*]'
32+nocite: "[@*]"
31references:
33references:
32- author:
34- author:
33 - family: Doe
35 - family: Doe
@@ -44,9 +46,9 @@ references:
44 container-title: Journal of Generic Studies
46 container-title: Journal of Generic Studies
45 id: item2
47 id: item2
46 issued: 2006
48 issued: 2006
47− page: '33-34'
49+ page: 33-34
48 title: Article
50 title: Article
49− type: 'article-journal'
51+ type: article-journal
50 volume: 6
52 volume: 6
51- author:
53- author:
52 - family: Doe
54 - family: Doe
test/command/biblatex-examples.bibdeleted−1674
@@ -1,1674 +0,0 @@
1−@string{anch-ie = {Angew.~Chem. Int.~Ed.}}
2−@string{cup = {Cambridge University Press}}
3−@string{dtv = {Deutscher Taschenbuch-Verlag}}
4−@string{hup = {Harvard University Press}}
5−@string{jams = {J.~Amer. Math. Soc.}}
6−@string{jchph = {J.~Chem. Phys.}}
7−@string{jomch = {J.~Organomet. Chem.}}
8−@string{pup = {Princeton University Press}}
9−
10−@incollection{westfahl:space,
11− author = {Westfahl, Gary},
12− title = {The True Frontier},
13− subtitle = {Confronting and Avoiding the Realities of Space in {American}
14− Science Fiction Films},
15− pages = {55-65},
16− crossref = {westfahl:frontier},
17− langid = {english},
18− langidopts = {variant=american},
19− indextitle = {True Frontier, The},
20− annotation = {A cross-referenced article from a \texttt{collection}. This is
21− an \texttt{incollection} entry with a \texttt{crossref}
22− field. Note the \texttt{subtitle} and \texttt{indextitle}
23− fields},
24−}
25−
26−@set{set,
27− entryset = {herrmann,aksin,yoon},
28− annotation = {A \texttt{set} with three members. The \texttt{crossref} field
29− in the \texttt{@set} entry and the \texttt{entryset} field in
30− each set member entry is needed only when using BibTeX as the
31− backend},
32−}
33−
34−@set{stdmodel,
35− entryset = {glashow,weinberg,salam},
36− annotation = {A \texttt{set} with three members discussing the standard
37− model of particle physics. The \texttt{crossref} field
38− in the \texttt{@set} entry and the \texttt{entryset} field in
39− each set member entry is needed only when using BibTeX as the
40− backend},
41−}
42−
43−@article{aksin,
44− author = {Aks{\i}n, {\"O}zge and T{\"u}rkmen, Hayati and Artok, Levent
45− and {\c{C}}etinkaya, Bekir and Ni, Chaoying and
46− B{\"u}y{\"u}kg{\"u}ng{\"o}r, Orhan and {\"O}zkal, Erhan},
47− title = {Effect of immobilization on catalytic characteristics of
48− saturated {Pd-N}-heterocyclic carbenes in {Mizoroki-Heck}
49− reactions},
50− journaltitle = jomch,
51− date = 2006,
52− volume = 691,
53− number = 13,
54− pages = {3027-3036},
55− indextitle = {Effect of immobilization on catalytic characteristics},
56−}
57−
58−@article{angenendt,
59− author = {Angenendt, Arnold},
60− title = {In Honore Salvatoris~-- Vom Sinn und Unsinn der
61− Patrozinienkunde},
62− journaltitle = {Revue d'Histoire Eccl{\'e}siastique},
63− date = 2002,
64− volume = 97,
65− pages = {431--456, 791--823},
66− langid = {german},
67− indextitle = {In Honore Salvatoris},
68− shorttitle = {In Honore Salvatoris},
69− annotation = {A German article in a French journal. Apart from that, a
70− typical \texttt{article} entry. Note the \texttt{indextitle}
71− field},
72−}
73−
74−@article{baez/article,
75− author = {Baez, John C. and Lauda, Aaron D.},
76− title = {Higher-Dimensional Algebra {V}: 2-Groups},
77− journaltitle = {Theory and Applications of Categories},
78− date = 2004,
79− volume = 12,
80− pages = {423-491},
81− version = 3,
82− eprint = {math/0307200v3},
83− eprinttype = {arxiv},
84− langid = {english},
85− langidopts = {variant=american},
86− annotation = {An \texttt{article} with \texttt{eprint} and
87− \texttt{eprinttype} fields. Note that the arXiv reference is
88− transformed into a clickable link if \texttt{hyperref} support
89− has been enabled. Compare \texttt{baez\slash online}, which
90− is the same item given as an \texttt{online} entry},
91−}
92−
93−@article{bertram,
94− author = {Bertram, Aaron and Wentworth, Richard},
95− title = {Gromov invariants for holomorphic maps on {Riemann} surfaces},
96− journaltitle = jams,
97− date = 1996,
98− volume = 9,
99− number = 2,
100− pages = {529-571},
101− langid = {english},
102− langidopts = {variant=american},
103− shorttitle = {Gromov invariants},
104− annotation = {An \texttt{article} entry with a \texttt{volume} and a
105− \texttt{number} field},
106−}
107−
108−@article{doody,
109− author = {Doody, Terrence},
110− title = {Hemingway's Style and {Jake's} Narration},
111− year = 1974,
112− volume = 4,
113− number = 3,
114− pages = {212-225},
115− langid = {english},
116− langidopts = {variant=american},
117− related = {matuz:doody},
118− relatedstring= {\autocap{e}xcerpt in},
119− journal = {The Journal of Narrative Technique},
120− annotation = {An \texttt{article} entry cited as an excerpt from a
121− \texttt{collection} entry. Note the format of the
122− \texttt{related} and \texttt{relatedstring} fields},
123−}
124−
125−@collection{matuz:doody,
126− editor = {Matuz, Roger},
127− title = {Contemporary Literary Criticism},
128− year = 1990,
129− volume = 61,
130− publisher = {Gale},
131− location = {Detroit},
132− pages = {204-208},
133− langid = {english},
134− langidopts = {variant=american},
135− annotation = {A \texttt{collection} entry providing the excerpt information
136− for the \texttt{doody} entry. Note the format of the
137− \texttt{pages} field},
138−}
139−
140−@article{gillies,
141− author = {Gillies, Alexander},
142− title = {Herder and the Preparation of {Goethe's} Idea of World
143− Literature},
144− journaltitle = {Publications of the English Goethe Society},
145− date = 1933,
146− series = {newseries},
147− volume = 9,
148− pages = {46-67},
149− langid = {english},
150− langidopts = {variant=british},
151− annotation = {An \texttt{article} entry with a \texttt{series} and a
152− \texttt{volume} field. Note that format of the \texttt{series}
153− field in the database file},
154−}
155−
156−@article{glashow,
157− author = {Glashow, Sheldon},
158− title = {Partial Symmetries of Weak Interactions},
159− journaltitle = {Nucl.~Phys.},
160− date = 1961,
161− volume = 22,
162− pages = {579-588},
163−}
164−
165−@article{herrmann,
166− author = {Herrmann, Wolfgang A. and {\"O}fele, Karl and Schneider,
167− Sabine K. and Herdtweck, Eberhardt and Hoffmann, Stephan D.},
168− title = {A carbocyclic carbene as an efficient catalyst ligand for {C--C}
169− coupling reactions},
170− journaltitle = anch-ie,
171− date = 2006,
172− volume = 45,
173− number = 23,
174− pages = {3859-3862},
175− indextitle = {Carbocyclic carbene as an efficient catalyst, A},
176−}
177−
178−@article{kastenholz,
179− author = {Kastenholz, M. A. and H{\"u}nenberger, Philippe H.},
180− title = {Computation of methodology\hyphen independent ionic solvation
181− free energies from molecular simulations},
182− journaltitle = jchph,
183− date = 2006,
184− subtitle = {{I}. {The} electrostatic potential in molecular liquids},
185− volume = 124,
186− eid = 124106,
187− doi = {10.1063/1.2172593},
188− langid = {english},
189− langidopts = {variant=american},
190− indextitle = {Computation of ionic solvation free energies},
191− annotation = {An \texttt{article} entry with an \texttt{eid} and a
192− \texttt{doi} field. Note that the \textsc{doi} is transformed
193− into a clickable link if \texttt{hyperref} support has been
194− enabled},
195− abstract = {The computation of ionic solvation free energies from
196− atomistic simulations is a surprisingly difficult problem that
197− has found no satisfactory solution for more than 15 years. The
198− reason is that the charging free energies evaluated from such
199− simulations are affected by very large errors. One of these is
200− related to the choice of a specific convention for summing up
201− the contributions of solvent charges to the electrostatic
202− potential in the ionic cavity, namely, on the basis of point
203− charges within entire solvent molecules (M scheme) or on the
204− basis of individual point charges (P scheme). The use of an
205− inappropriate convention may lead to a charge-independent
206− offset in the calculated potential, which depends on the
207− details of the summation scheme, on the quadrupole-moment
208− trace of the solvent molecule, and on the approximate form
209− used to represent electrostatic interactions in the
210− system. However, whether the M or P scheme (if any) represents
211− the appropriate convention is still a matter of on-going
212− debate. The goal of the present article is to settle this
213− long-standing controversy by carefully analyzing (both
214− analytically and numerically) the properties of the
215− electrostatic potential in molecular liquids (and inside
216− cavities within them).},
217−}
218−
219−@article{murray,
220− author = {Hostetler, Michael J. and Wingate, Julia E. and Zhong,
221− Chuan-Jian and Harris, Jay E. and Vachet, Richard W. and
222− Clark, Michael R. and Londono, J. David and Green, Stephen
223− J. and Stokes, Jennifer J. and Wignall, George D. and Glish,
224− Gary L. and Porter, Marc D. and Evans, Neal D. and Murray,
225− Royce W.},
226− title = {Alkanethiolate gold cluster molecules with core diameters from
227− 1.5 to 5.2~{nm}},
228− journaltitle = {Langmuir},
229− date = 1998,
230− subtitle = {Core and monolayer properties as a function of core size},
231− volume = 14,
232− number = 1,
233− pages = {17-30},
234− langid = {english},
235− langidopts = {variant=american},
236− indextitle = {Alkanethiolate gold cluster molecules},
237− shorttitle = {Alkanethiolate gold cluster molecules},
238− annotation = {An \texttt{article} entry with \arabic{author} authors. By
239− default, long author and editor lists are automatically
240− truncated. This is configurable},
241−}
242−
243−@article{reese,
244− author = {Reese, Trevor R.},
245− title = {Georgia in {Anglo-Spanish} Diplomacy, 1736--1739},
246− journaltitle = {William and Mary Quarterly},
247− date = 1958,
248− series = 3,
249− volume = 15,
250− pages = {168-190},
251− langid = {english},
252− langidopts = {variant=american},
253− annotation = {An \texttt{article} entry with a \texttt{series} and a
254− \texttt{volume} field. Note the format of the series. If the
255− value of the \texttt{series} field is an integer, this number
256− is printed as an ordinal and the string \enquote*{series} is
257− appended automatically},
258−}
259−
260−@article{sarfraz,
261− author = {M. Sarfraz and M. F. A. Razzak},
262− title = {Technical section: {An} algorithm for automatic capturing of
263− the font outlines},
264− year = 2002,
265− volume = 26,
266− number = 5,
267− pages = {795-804},
268− issn = {0097-8493},
269− journal = {Computers and Graphics},
270− annotation = {An \texttt{article} entry with an \texttt{issn} field},
271−}
272−
273−@article{shore,
274− author = {Shore, Bradd},
275− title = {Twice-Born, Once Conceived},
276− journaltitle = {American Anthropologist},
277− date = {1991-03},
278− subtitle = {Meaning Construction and Cultural Cognition},
279− series = {newseries},
280− volume = 93,
281− number = 1,
282− pages = {9-27},
283− annotation = {An \texttt{article} entry with \texttt{series},
284− \texttt{volume}, and \texttt{number} fields. Note the format
285− of the \texttt{series} which is a localization key},
286−}
287−
288−@article{sigfridsson,
289− author = {Sigfridsson, Emma and Ryde, Ulf},
290− title = {Comparison of methods for deriving atomic charges from the
291− electrostatic potential and moments},
292− journaltitle = {Journal of Computational Chemistry},
293− date = 1998,
294− volume = 19,
295− number = 4,
296− pages = {377-395},
297− doi = {10.1002/(SICI)1096-987X(199803)19:4<377::AID-JCC1>3.0.CO;2-P},
298− langid = {english},
299− langidopts = {variant=american},
300− indextitle = {Methods for deriving atomic charges},
301− annotation = {An \texttt{article} entry with \texttt{volume},
302− \texttt{number}, and \texttt{doi} fields. Note that the
303− \textsc{doi} is transformed into a clickable link if
304− \texttt{hyperref} support has been enabled},
305− abstract = {Four methods for deriving partial atomic charges from the
306− quantum chemical electrostatic potential (CHELP, CHELPG,
307− Merz-Kollman, and RESP) have been compared and critically
308− evaluated. It is shown that charges strongly depend on how and
309− where the potential points are selected. Two alternative
310− methods are suggested to avoid the arbitrariness in the
311− point-selection schemes and van der Waals exclusion radii:
312− CHELP-BOW, which also estimates the charges from the
313− electrostatic potential, but with potential points that are
314− Boltzmann-weighted after their occurrence in actual
315− simulations using the energy function of the program in which
316− the charges will be used, and CHELMO, which estimates the
317− charges directly from the electrostatic multipole
318− moments. Different criteria for the quality of the charges are
319− discussed.},
320−}
321−
322−@article{spiegelberg,
323− author = {Spiegelberg, Herbert},
324− title = {\mkbibquote{Intention} und \mkbibquote{Intentionalit{\"a}t} in
325− der Scholastik, bei Brentano und Husserl},
326− journaltitle = {Studia Philosophica},
327− date = 1969,
328− volume = 29,
329− pages = {189-216},
330− langid = {german},
331− sorttitle = {Intention und Intentionalitat in der Scholastik, bei Brentano
332− und Husserl},
333− indexsorttitle= {Intention und Intentionalitat in der Scholastik, bei Brentano
334− und Husserl},
335− shorttitle = {Intention und Intentionalit{\"a}t},
336− annotation = {An \texttt{article} entry. Note the \texttt{sorttitle} and
337− \texttt{indexsorttitle} fields and the markup of the quotes in
338− the database file},
339−}
340−
341−@article{springer,
342− author = {Springer, Otto},
343− title = {Mediaeval Pilgrim Routes from {Scandinavia} to {Rome}},
344− journaltitle = {Mediaeval Studies},
345− date = 1950,
346− volume = 12,
347− pages = {92-122},
348− langid = {english},
349− langidopts = {variant=british},
350− shorttitle = {Mediaeval Pilgrim Routes},
351− annotation = {A plain \texttt{article} entry},
352−}
353−
354−@article{weinberg,
355− author = {Weinberg, Steven},
356− title = {A Model of Leptons},
357− journaltitle = {Phys.~Rev.~Lett.},
358− date = 1967,
359− volume = 19,
360− pages = {1264-1266},
361−}
362−
363−@article{yoon,
364− author = {Yoon, Myeong S. and Ryu, Dowook and Kim, Jeongryul and Ahn,
365− Kyo Han},
366− title = {Palladium pincer complexes with reduced bond angle strain:
367− efficient catalysts for the {Heck} reaction},
368− journaltitle = {Organometallics},
369− date = 2006,
370− volume = 25,
371− number = 10,
372− pages = {2409-2411},
373− indextitle = {Palladium pincer complexes},
374−}
375−
376−@book{aristotle:anima,
377− author = {Aristotle},
378− title = {De Anima},
379− date = 1907,
380− editor = {Hicks, Robert Drew},
381− publisher = cup,
382− location = {Cambridge},
383− keywords = {primary},
384− langid = {english},
385− langidopts = {variant=british},
386− annotation = {A \texttt{book} entry with an \texttt{author} and an
387− \texttt{editor}},
388−}
389−
390−@book{aristotle:physics,
391− author = {Aristotle},
392− title = {Physics},
393− date = 1929,
394− translator = {Wicksteed, P. H. and Cornford, F. M.},
395− publisher = {G. P. Putnam},
396− location = {New York},
397− keywords = {primary},
398− langid = {english},
399− langidopts = {variant=american},
400− shorttitle = {Physics},
401− annotation = {A \texttt{book} entry with a \texttt{translator} field},
402−}
403−
404−@book{aristotle:poetics,
405− author = {Aristotle},
406− title = {Poetics},
407− date = 1968,
408− editor = {Lucas, D. W.},
409− series = {Clarendon {Aristotle}},
410− publisher = {Clarendon Press},
411− location = {Oxford},
412− keywords = {primary},
413− langid = {english},
414− langidopts = {variant=british},
415− shorttitle = {Poetics},
416− annotation = {A \texttt{book} entry with an \texttt{author} and an
417− \texttt{editor} as well as a \texttt{series} field},
418−}
419−
420−@book{aristotle:rhetoric,
421− author = {Aristotle},
422− title = {The Rhetoric of {Aristotle} with a commentary by the late {Edward
423− Meredith Cope}},
424− date = 1877,
425− editor = {Cope, Edward Meredith},
426− commentator = {Cope, Edward Meredith},
427− volumes = 3,
428− publisher = cup,
429− keywords = {primary},
430− langid = {english},
431− langidopts = {variant=british},
432− sorttitle = {Rhetoric of Aristotle},
433− indextitle = {Rhetoric of {Aristotle}, The},
434− shorttitle = {Rhetoric},
435− annotation = {A commented edition. Note the concatenation of the
436− \texttt{editor} and \texttt{commentator} fields as well as the
437− \texttt{volumes}, \texttt{sorttitle}, and \texttt{indextitle}
438− fields},
439−}
440−
441−@book{augustine,
442− author = {Augustine, Robert L.},
443− title = {Heterogeneous catalysis for the synthetic chemist},
444− date = 1995,
445− publisher = {Marcel Dekker},
446− location = {New York},
447− langid = {english},
448− langidopts = {variant=american},
449− shorttitle = {Heterogeneous catalysis},
450− annotation = {A plain \texttt{book} entry},
451−}
452−
453−@book{averroes/bland,
454− author = {Averroes},
455− title = {The Epistle on the Possibility of Conjunction with the Active
456− Intellect by {Ibn Rushd} with the Commentary of {Moses Narboni}},
457− date = 1982,
458− editor = {Bland, Kalman P.},
459− translator = {Bland, Kalman P.},
460− series = {Moreshet: Studies in {Jewish} History, Literature and Thought},
461− number = 7,
462− publisher = {Jewish Theological Seminary of America},
463− location = {New York},
464− keywords = {primary},
465− langid = {english},
466− langidopts = {variant=american},
467− indextitle = {Epistle on the Possibility of Conjunction, The},
468− shorttitle = {Possibility of Conjunction},
469− annotation = {A \texttt{book} entry with a \texttt{series} and a
470− \texttt{number}. Note the concatenation of the \texttt{editor}
471− and \texttt{translator} fields as well as the
472− \texttt{indextitle} field},
473−}
474−
475−@book{averroes/hannes,
476− author = {Averroes},
477− title = {Des Averro{\"e}s Abhandlung: \mkbibquote{{\"U}ber die
478− M{\"o}glichkeit der Conjunktion} oder \mkbibquote{{\"U}ber den
479− materiellen Intellekt}},
480− date = 1892,
481− editor = {Hannes, Ludwig},
482− translator = {Hannes, Ludwig},
483− annotator = {Hannes, Ludwig},
484− publisher = {C.~A. Kaemmerer},
485− location = {Halle an der Saale},
486− keywords = {primary},
487− langid = {german},
488− sorttitle = {Uber die Moglichkeit der Conjunktion},
489− indexsorttitle= {Uber die Moglichkeit der Conjunktion},
490− indextitle = {{\"U}ber die M{\"o}glichkeit der Conjunktion},
491− shorttitle = {{\"U}ber die M{\"o}glichkeit der Conjunktion},
492− annotation = {An annotated edition. Note the concatenation of the
493− \texttt{editor}, \texttt{translator}, and \texttt{annotator}
494− fields. Also note the \texttt{shorttitle},
495− \texttt{indextitle}, \texttt{sorttitle}, and
496− \texttt{indexsorttitle} fields},
497−}
498−
499−@book{averroes/hercz,
500− author = {Averroes},
501− title = {Drei Abhandlungen {\"u}ber die Conjunction des separaten
502− Intellects mit dem Menschen},
503− date = 1869,
504− editor = {Hercz, J.},
505− translator = {Hercz, J.},
506− publisher = {S.~Hermann},
507− location = {Berlin},
508− keywords = {primary},
509− langid = {german},
510− indexsorttitle= {Drei Abhandlungen uber die Conjunction},
511− indextitle = {Drei Abhandlungen {\"u}ber die Conjunction},
512− subtitle = {Von Averroes (Vater und Sohn), aus dem Arabischen
513− {\"u}bersetzt von Samuel Ibn Tibbon},
514− shorttitle = {Drei Abhandlungen},
515− annotation = {A \texttt{book} entry. Note the concatenation of the
516− \texttt{editor} and \texttt{translator} fields as well as the
517− \texttt{indextitle} and \texttt{indexsorttitle} fields},
518−}
519−
520−@book{cicero,
521− author = {Cicero, Marcus Tullius},
522− title = {De natura deorum. {\"U}ber das Wesen der G{\"o}tter},
523− date = 1995,
524− editor = {Blank-Sangmeister, Ursula},
525− translator = {Blank-Sangmeister, Ursula},
526− afterword = {Thraede, Klaus},
527− language = {langlatin and langgerman},
528− publisher = {Reclam},
529− location = {Stuttgart},
530− langid = {german},
531− indextitle = {De natura deorum},
532− shorttitle = {De natura deorum},
533− annotation = {A bilingual edition of Cicero's \emph{De natura deorum}, with
534− a German translation. Note the format of the \texttt{language}
535− field in the database file, the concatenation of the
536− \texttt{editor} and \texttt{translator} fields, and the
537− \texttt{afterword} field},
538−}
539−
540−@book{coleridge,
541− author = {Coleridge, Samuel Taylor},
542− title = {Biographia literaria, or {Biographical} sketches of my literary
543− life and opinions},
544− date = 1983,
545− editor = {Coburn, Kathleen and Engell, James and Bate, W. Jackson},
546− maintitle = {The collected works of {Samuel Taylor Coleridge}},
547− volume = 7,
548− part = 2,
549− series = {Bollingen Series},
550− number = 75,
551− publisher = {Routledge {and} Kegan Paul},
552− location = {London},
553− langid = {english},
554− langidopts = {variant=british},
555− indextitle = {Biographia literaria},
556− shorttitle = {Biographia literaria},
557− annotation = {One (partial) volume of a multivolume book. This is a
558− \texttt{book} entry with a \texttt{volume} and a \texttt{part}
559− field which explicitly refers to the second (physical) part of
560− the seventh (logical) volume. Also note the \texttt{series}
561− and \texttt{number} fields},
562−}
563−
564−@book{companion,
565− author = {Goossens, Michel and Mittelbach, Frank and Samarin, Alexander},
566− title = {The {LaTeX} Companion},
567− date = 1994,
568− edition = 1,
569− publisher = {Addison-Wesley},
570− location = {Reading, Mass.},
571− pagetotal = 528,
572− langid = {english},
573− langidopts = {variant=american},
574− sorttitle = {LaTeX Companion},
575− indextitle = {LaTeX Companion, The},
576− shorttitle = {LaTeX Companion},
577− annotation = {A book with three authors. Note the formatting of the author
578− list. By default, only the first name is reversed in the
579− bibliography},
580−}
581−
582−@book{cotton,
583− author = {Cotton, Frank Albert and Wilkinson, Geoffrey and Murillio,
584− Carlos A. and Bochmann, Manfred},
585− title = {Advanced inorganic chemistry},
586− date = 1999,
587− edition = 6,
588− publisher = {Wiley},
589− location = {Chichester},
590− langid = {english},
591− langidopts = {variant=british},
592− annotation = {A \texttt{book} entry with \arabic{author} authors and an
593− \texttt{edition} field. By default, long \texttt{author} and
594− \texttt{editor} lists are automatically truncated. This is
595− configurable},
596−}
597−
598−@book{gerhardt,
599− author = {Gerhardt, Michael J.},
600− title = {The Federal Appointments Process},
601− date = 2000,
602− publisher = {Duke University Press},
603− location = {Durham and London},
604− langid = {english},
605− langidopts = {variant=american},
606− sorttitle = {Federal Appointments Process},
607− indextitle = {Federal Appointments Process, The},
608− subtitle = {A Constitutional and Historical Analysis},
609− shorttitle = {Federal Appointments Process},
610− annotation = {This is a \texttt{book} entry. Note the format of the
611− \texttt{location} field as well as the \texttt{sorttitle} and
612− \texttt{indextitle} fields},
613−}
614−
615−@book{gonzalez,
616− author = {Gonzalez, Ray},
617− title = {The Ghost of {John Wayne} and Other Stories},
618− date = 2001,
619− publisher = {The University of Arizona Press},
620− location = {Tucson},
621− isbn = {0-816-52066-6},
622− langid = {english},
623− langidopts = {variant=american},
624− sorttitle = {Ghost of John Wayne and Other Stories},
625− indextitle = {Ghost of {John Wayne} and Other Stories, The},
626− shorttitle = {Ghost of {John Wayne}},
627− annotation = {A collection of short stories. This is a \texttt{book} entry.
628− Note the \texttt{sorttitle} and \texttt{indextitle} fields in
629− the database file. There's also an \texttt{isbn} field},
630−}
631−
632−@book{hammond,
633− author = {Hammond, Christopher},
634− title = {The basics of crystallography and diffraction},
635− date = 1997,
636− publisher = {International Union of Crystallography and Oxford University
637− Press},
638− location = {Oxford},
639− langid = {english},
640− langidopts = {variant=british},
641− sorttitle = {Basics of crystallography and diffraction},
642− indextitle = {Basics of crystallography and diffraction, The},
643− shorttitle = {Crystallography and diffraction},
644− annotation = {A \texttt{book} entry. Note the \texttt{sorttitle} and
645− \texttt{indextitle} fields as well as the format of the
646− \texttt{publisher} field},
647−}
648−
649−@book{iliad,
650− author = {Homer},
651− title = {Die Ilias},
652− date = 2004,
653− translator = {Schadewaldt, Wolfgang},
654− introduction = {Latacz, Joachim},
655− edition = 3,
656− publisher = {Artemis \& Winkler},
657− location = {D{\"u}sseldorf and Z{\"u}rich},
658− langid = {german},
659− sorttitle = {Ilias},
660− indextitle = {Ilias, Die},
661− shorttitle = {Ilias},
662− annotation = {A German translation of the \emph{Iliad}. Note the
663− \texttt{translator} and \texttt{introduction} fields and the
664− format of the \texttt{location} field in the database
665− file. Also note the \texttt{sorttitle} and \texttt{indextitle}
666− fields},
667−}
668−
669−@book{knuth:ct,
670− author = {Knuth, Donald E.},
671− title = {Computers \& Typesetting},
672− date = {1984/1986},
673− volumes = 5,
674− publisher = {Addison-Wesley},
675− location = {Reading, Mass.},
676− langid = {english},
677− langidopts = {variant=american},
678− sortyear = {1984-0},
679− sorttitle = {Computers & Typesetting},
680− indexsorttitle= {Computers & Typesetting},
681− annotation = {A five-volume book cited as a whole. This is a \texttt{book}
682− entry, note the \texttt{volumes} field},
683−}
684−
685−@book{knuth:ct:a,
686− author = {Knuth, Donald E.},
687− title = {The {\TeX} book},
688− date = 1984,
689− maintitle = {Computers \& Typesetting},
690− volume = {A},
691− publisher = {Addison-Wesley},
692− location = {Reading, Mass.},
693− langid = {english},
694− langidopts = {variant=american},
695− sortyear = {1984-1},
696− sorttitle = {Computers & Typesetting A},
697− indexsorttitle= {The TeXbook},
698− indextitle = {\protect\TeX book, The},
699− shorttitle = {\TeX book},
700− annotation = {The first volume of a five-volume book. Note the
701− \texttt{sorttitle} and \texttt{sortyear} fields. We want this
702− volume to be listed after the entry referring to the entire
703− five-volume set. Also note the \texttt{indextitle} and
704− \texttt{indexsorttitle} fields. Indexing packages that don't
705− generate robust index entries require some control sequences
706− to be protected from expansion},
707−}
708−
709−@book{knuth:ct:b,
710− author = {Knuth, Donald E.},
711− title = {\TeX: The Program},
712− date = 1986,
713− maintitle = {Computers \& Typesetting},
714− volume = {B},
715− publisher = {Addison-Wesley},
716− location = {Reading, Mass.},
717− langid = {english},
718− langidopts = {variant=american},
719− sortyear = {1986-1},
720− sorttitle = {Computers & Typesetting B},
721− indexsorttitle= {TeX: The Program},
722− shorttitle = {\TeX},
723− annotation = {The second volume of a five-volume book. Note the
724− \texttt{sorttitle} and \texttt{sortyear} fields. Also note the
725− \texttt{indexsorttitle} field},
726−}
727−
728−@book{knuth:ct:c,
729− author = {Knuth, Donald E.},
730− title = {The {METAFONTbook}},
731− date = 1986,
732− maintitle = {Computers \& Typesetting},
733− volume = {C},
734− publisher = {Addison-Wesley},
735− location = {Reading, Mass.},
736− langid = {english},
737− langidopts = {variant=american},
738− sortyear = {1986-2},
739− sorttitle = {Computers & Typesetting C},
740− indextitle = {METAFONTbook, The},
741− shorttitle = {METAFONTbook},
742− annotation = {The third volume of a five-volume book. Note the
743− \texttt{sorttitle} and \texttt{sortyear} fields as well as the
744− \texttt{indextitle} field},
745−}
746−
747−@book{knuth:ct:d,
748− author = {Knuth, Donald E.},
749− title = {METAFONT: The Program},
750− date = 1986,
751− maintitle = {Computers \& Typesetting},
752− volume = {D},
753− publisher = {Addison-Wesley},
754− location = {Reading, Mass.},
755− langid = {english},
756− langidopts = {variant=american},
757− sortyear = {1986-3},
758− sorttitle = {Computers & Typesetting D},
759− shorttitle = {METAFONT},
760− annotation = {The fourth volume of a five-volume book. Note the
761− \texttt{sorttitle} and \texttt{sortyear} fields},
762−}
763−
764−@book{knuth:ct:e,
765− author = {Knuth, Donald E.},
766− title = {{Computer Modern} Typefaces},
767− date = 1986,
768− maintitle = {Computers \& Typesetting},
769− volume = {E},
770− publisher = {Addison-Wesley},
771− location = {Reading, Mass.},
772− langid = {english},
773− langidopts = {variant=american},
774− sortyear = {1986-4},
775− sorttitle = {Computers & Typesetting E},
776− annotation = {The fifth volume of a five-volume book. Note the
777− \texttt{sorttitle} and \texttt{sortyear} fields},
778−}
779−
780−@book{knuth:ct:related,
781− author = {Knuth, Donald E.},
782− title = {Computers \& Typesetting},
783− date = {1984/1986},
784− volumes = 5,
785− publisher = {Addison-Wesley},
786− location = {Reading, Mass.},
787− langid = {english},
788− langidopts = {variant=american},
789− sortyear = {1984-0},
790− sorttitle = {Computers & Typesetting},
791− indexsorttitle= {Computers & Typesetting},
792− related = {knuth:ct:a,knuth:ct:b,knuth:ct:c,knuth:ct:d,knuth:ct:e},
793− relatedtype = {multivolume},
794− annotation = {A five-volume book cited as a whole and related to its
795− individual volumes. Note the \texttt{related} and
796− \texttt{relatedtype} fields},
797−}
798−
799−@book{kullback,
800− author = {Kullback, Solomon},
801− title = {Information Theory and Statistics},
802− year = 1959,
803− publisher = {John Wiley \& Sons},
804− location = {New York},
805− langid = {english},
806− langidopts = {variant=american},
807−}
808−
809−@book{kullback:reprint,
810− author = {Kullback, Solomon},
811− title = {Information Theory and Statistics},
812− year = 1997,
813− publisher = {Dover Publications},
814− location = {New York},
815− origyear = 1959,
816− origpublisher= {John Wiley \& Sons},
817− langid = {english},
818− langidopts = {variant=american},
819− annotation = {A reprint of the \texttt{kullback} entry. Note the format of
820− \texttt{origyear} and \texttt{origpublisher}. These fields are
821− not used by the standard bibliography styles},
822−}
823−
824−@book{kullback:related,
825− author = {Kullback, Solomon},
826− title = {Information Theory and Statistics},
827− year = 1997,
828− publisher = {Dover Publications},
829− location = {New York},
830− langid = {english},
831− langidopts = {variant=american},
832− related = {kullback},
833− relatedtype = {origpubin},
834− annotation = {A reprint of the \texttt{kullback} entry. Note the format of
835− the \texttt{related} and \texttt{relatedtype} fields},
836−}
837−
838−@book{malinowski,
839− author = {Malinowski, Bronis{\l}aw},
840− title = {Argonauts of the {Western Pacific}},
841− date = 1972,
842− edition = 8,
843− publisher = {Routledge {and} Kegan Paul},
844− location = {London},
845− langid = {english},
846− langidopts = {variant=british},
847− subtitle = {An account of native enterprise and adventure in the
848− Archipelagoes of {Melanesian New Guinea}},
849− shorttitle = {Argonauts},
850− annotation = {This is a \texttt{book} entry. Note the format of the
851− \texttt{publisher} and \texttt{edition} fields as well as the
852− \texttt{subtitle} field},
853−}
854−
855−@book{maron,
856− author = {Maron, Monika},
857− title = {Animal Triste},
858− date = 2000,
859− translator = {Brigitte Goldstein},
860− origlanguage = {german},
861− publisher = {University of Nebraska Press},
862− location = {Lincoln},
863− langid = {english},
864− langidopts = {variant=american},
865− shorttitle = {Animal Triste},
866− annotation = {An English translation of a German novel with a French title.
867− In other words: a \texttt{book} entry with a
868− \texttt{translator} field. Note the \texttt{origlanguage}
869− field which is concatenated with the \texttt{translator}},
870−}
871−
872−@book{massa,
873− author = {Werner Massa},
874− title = {Crystal structure determination},
875− date = 2004,
876− edition = 2,
877− publisher = {Spinger},
878− location = {Berlin},
879− langid = {english},
880− langidopts = {variant=british},
881− annotation = {A \texttt{book} entry with an \texttt{edition} field},
882−}
883−
884−@article{moore,
885− author = {Moore, Gordon E.},
886− title = {Cramming more components onto integrated circuits},
887− journaltitle = {Electronics},
888− year = 1965,
889− volume = 38,
890− number = 8,
891− pages = {114-117},
892− langid = {english},
893− langidopts = {variant=american},
894−}
895−
896−@article{moore:related,
897− author = {Moore, Gordon E.},
898− title = {Cramming more components onto integrated circuits},
899− journaltitle = {Proceedings of the {IEEE}},
900− year = 1998,
901− volume = 86,
902− number = 1,
903− pages = {82-85},
904− langid = {english},
905− langidopts = {variant=american},
906− related = {moore},
907− relatedtype = {reprintfrom},
908− annotation = {A reprint of Moore's law. Note the \texttt{related} and
909− \texttt{relatedtype} fields},
910−}
911−
912−@book{nietzsche:ksa,
913− author = {Nietzsche, Friedrich},
914− title = {S{\"a}mtliche Werke},
915− date = 1988,
916− editor = {Colli, Giorgio and Montinari, Mazzino},
917− edition = 2,
918− volumes = 15,
919− publisher = dtv # { and Walter de Gruyter},
920− location = {M{\"u}nchen and Berlin and New York},
921− langid = {german},
922− sortyear = {1988-0},
923− sorttitle = {Werke-00-000},
924− indexsorttitle= {Samtliche Werke},
925− subtitle = {Kritische Studienausgabe},
926− annotation = {The critical edition of Nietzsche's works. This is a
927− \texttt{book} entry referring to a 15-volume work as a
928− whole. Note the \texttt{volumes} field and the format of the
929− \texttt{publisher} and \texttt{location} fields in the
930− database file. Also note the \texttt{sorttitle} and
931− \texttt{sortyear} fields which are used to fine-tune the
932− sorting order of the bibliography. We want this item listed
933− first in the bibliography},
934−}
935−
936−@book{nietzsche:ksa1,
937− author = {Nietzsche, Friedrich},
938− title = {Die Geburt der Trag{\"o}die. Unzeitgem{\"a}{\ss}e
939− Betrachtungen I--IV. Nachgelassene Schriften 1870--1973},
940− date = 1988,
941− editor = {Colli, Giorgio and Montinari, Mazzino},
942− maintitle = {S{\"a}mtliche Werke},
943− mainsubtitle = {Kritische Studienausgabe},
944− volume = 1,
945− edition = 2,
946− publisher = dtv # { and Walter de Gruyter},
947− location = {M{\"u}nchen and Berlin and New York},
948− langid = {german},
949− sortyear = {1988-1},
950− sorttitle = {Werke-01-000},
951− indexsorttitle= {Samtliche Werke I},
952− bookauthor = {Nietzsche, Friedrich},
953− indextitle = {S{\"a}mtliche Werke I},
954− shorttitle = {S{\"a}mtliche Werke I},
955− annotation = {A single volume from the critical edition of Nietzsche's
956− works. This \texttt{book} entry explicitly refers to the first
957− volume only. Note the \texttt{title} and \texttt{maintitle}
958− fields. Also note the \texttt{sorttitle} and \texttt{sortyear}
959− fields. We want this entry to be listed after the entry
960− referring to the entire edition},
961−}
962−
963−@book{nussbaum,
964− author = {Nussbaum, Martha},
965− title = {Aristotle's \mkbibquote{De Motu Animalium}},
966− date = 1978,
967− publisher = pup,
968− location = {Princeton},
969− keywords = {secondary},
970− langid = {english},
971− langidopts = {variant=american},
972− sorttitle = {Aristotle's De Motu Animalium},
973− indexsorttitle= {Aristotle's De Motu Animalium},
974− annotation = {A \texttt{book} entry. Note the \texttt{sorttitle} and
975− \texttt{indexsorttitle} fields and the markup of the quotes in
976− the database file},
977−}
978−
979−@book{piccato,
980− author = {Piccato, Pablo},
981− title = {City of Suspects},
982− date = 2001,
983− publisher = {Duke University Press},
984− location = {Durham and London},
985− langid = {english},
986− langidopts = {variant=american},
987− subtitle = {Crime in {Mexico City}, 1900--1931},
988− shorttitle = {City of Suspects},
989− annotation = {This is a \texttt{book} entry. Note the format of the
990− \texttt{location} field in the database file},
991−}
992−
993−@book{vangennep,
994− author = {van Gennep, Arnold},
995− title = {Les rites de passage},
996− date = 1909,
997− publisher = {Nourry},
998− location = {Paris},
999− options = {useprefix},
1000− langid = {french},
1001− sorttitle = {Rites de passage},
1002− indextitle = {Rites de passage, Les},
1003− shorttitle = {Rites de passage},
1004− annotation = {A \texttt{book} entry. Note the format of the printed name and
1005− compare the \texttt{useprefix} option in the \texttt{options}
1006− field as well as \texttt{brandt} and \texttt{geer}},
1007−}
1008−
1009−@book{vangennep:trans,
1010− author = {van Gennep, Arnold},
1011− title = {The Rites of Passage},
1012− year = 1960,
1013− translator = {Vizedom, Monika B. and Caffee, Gabrielle L.},
1014− language = {english},
1015− origlanguage = {french},
1016− publisher = {University of Chicago Press},
1017− options = {useprefix},
1018− indextitle = {Rites of Passage, The},
1019− sorttitle = {Rites of Passage},
1020− shorttitle = {Rites of Passage},
1021− langid = {english},
1022− langidopts = {variant=american},
1023− annotation = {A translation of the \texttt{vangennep} entry. Note the
1024− \texttt{translator} and \texttt{origlanguage} fields. Compare
1025− with the \texttt{vangennep:related} entry.},
1026−}
1027−
1028−@book{vangennep:related,
1029− author = {van Gennep, Arnold},
1030− title = {Les rites de passage},
1031− date = 1909,
1032− publisher = {Nourry},
1033− location = {Paris},
1034− options = {useprefix},
1035− langid = {french},
1036− related = {vizedom:related},
1037− relatedtype = {bytranslator},
1038− sorttitle = {Rites de passage},
1039− indextitle = {Rites de passage, Les},
1040− shorttitle = {Rites de passage},
1041− annotation = {A variant of the \texttt{vangennep} entry related to its
1042− translation. Note the format of the \texttt{related} and
1043− \texttt{relatedtype} fields},
1044−}
1045−
1046−@book{vizedom:related,
1047− title = {The Rites of Passage},
1048− year = 1960,
1049− translator = {Vizedom, Monika B. and Caffee, Gabrielle L.},
1050− language = {english},
1051− publisher = {University of Chicago Press},
1052− langid = {english},
1053− langidopts = {variant=american},
1054− options = {usetranslator},
1055− related = {vangennep},
1056− relatedtype = {translationof},
1057− indextitle = {Rites of Passage, The},
1058− sorttitle = {Rites of Passage},
1059− shorttitle = {Rites of Passage},
1060− annotation = {A translated work from \texttt{vangennep}. Note the format of
1061− the \texttt{related} and \texttt{relatedtype} fields},
1062−}
1063−
1064−@book{vazques-de-parga,
1065− author = {V{\'a}zques{ de }Parga, Luis and Lacarra, Jos{\'e} Mar{\'i}a
1066− and Ur{\'i}a R{\'i}u, Juan},
1067− title = {Las Peregrinaciones a Santiago de Compostela},
1068− date = 1993,
1069− volumes = 3,
1070− note = {Ed. facs. de la realizada en 1948--49},
1071− publisher = {Iberdrola},
1072− location = {Pamplona},
1073− langid = {spanish},
1074− sorttitle = {Peregrinaciones a Santiago de Compostela},
1075− indextitle = {Peregrinaciones a Santiago de Compostela, Las},
1076− shorttitle = {Peregrinaciones},
1077− annotation = {A multivolume book cited as a whole. This is a \texttt{book}
1078− entry with \texttt{volumes}, \texttt{note},
1079− \texttt{sorttitle}, and \texttt{indextitle} fields},
1080−}
1081−
1082−@book{wilde,
1083− author = {Wilde, Oscar},
1084− title = {The Importance of Being Earnest: A Trivial Comedy for Serious
1085− People},
1086− year = 1899,
1087− series = {English and {American} drama of the Nineteenth Century},
1088− publisher = {Leonard Smithers {and} Company},
1089− eprint = {4HIWAAAAYAAJ},
1090− eprinttype = {googlebooks},
1091− annotation = {A \texttt{book} with \texttt{eprint} and \texttt{eprinttype}
1092− fields.},
1093−}
1094−
1095−@book{worman,
1096− author = {Worman, Nancy},
1097− title = {The Cast of Character},
1098− date = 2002,
1099− publisher = {University of Texas Press},
1100− location = {Austin},
1101− langid = {english},
1102− langidopts = {variant=american},
1103− sorttitle = {Cast of Character},
1104− indextitle = {Cast of Character, The},
1105− subtitle = {Style in {Greek} Literature},
1106− shorttitle = {Cast of Character},
1107− annotation = {A \texttt{book} entry. Note the \texttt{sorttitle} and
1108− \texttt{indextitle} fields},
1109−}
1110−
1111−@collection{britannica,
1112− editor = {Preece, Warren E.},
1113− title = {The {New Encyclop{\ae}dia Britannica}},
1114− date = 2003,
1115− edition = 15,
1116− volumes = 32,
1117− publisher = {Encyclop{\ae}dia Britannica},
1118− location = {Chicago, Ill.},
1119− options = {useeditor=false},
1120− label = {EB},
1121− langid = {english},
1122− langidopts = {variant=british},
1123− sorttitle = {Encyclop{\ae}dia Britannica},
1124− indextitle = {{Encyclop{\ae}dia Britannica}, The {New}},
1125− shorttitle = {{Encyclop{\ae}dia Britannica}},
1126− annotation = {This is a \texttt{collection} entry for an encyclopedia. Note
1127− the \texttt{useeditor} option in the \texttt{options} field as
1128− well as the \texttt{sorttitle} field. We want this entry to be
1129− cited and alphabetized by title even though there is an
1130− editor. In addition to that, we want the title to be
1131− alphabetized under \enquote*{E} rather than \enquote*{T}. Also
1132− note the \texttt{label} field which is provided for
1133− author-year citation styles},
1134−}
1135−
1136−@collection{gaonkar,
1137− editor = {Gaonkar, Dilip Parameshwar},
1138− title = {Alternative Modernities},
1139− date = 2001,
1140− publisher = {Duke University Press},
1141− location = {Durham and London},
1142− isbn = {0-822-32714-7},
1143− langid = {english},
1144− langidopts = {variant=american},
1145− annotation = {This is a \texttt{collection} entry. Note the format of the
1146− \texttt{location} field in the database file as well as the
1147− \texttt{isbn} field},
1148−}
1149−
1150−@InCollection{gaonkar:in,
1151− author = {Gaonkar, Dilip Parameshwar},
1152− editor = {Gaonkar, Dilip Parameshwar},
1153− title = {On Alternative Modernities},
1154− date = 2001,
1155− booktitle = {Alternative Modernities},
1156− publisher = {Duke University Press},
1157− location = {Durham and London},
1158− isbn = {0-822-32714-7},
1159− pages = {1-23},
1160−}
1161−
1162−@collection{jaffe,
1163− editor = {Jaff{\'e}, Philipp},
1164− title = {Regesta Pontificum Romanorum ab condita ecclesia ad annum post
1165− Christum natum \textsc{mcxcviii}},
1166− date = {1885/1888},
1167− editora = {Loewenfeld, Samuel and Kaltenbrunner, Ferdinand and Ewald,
1168− Paul},
1169− edition = 2,
1170− volumes = 2,
1171− location = {Leipzig},
1172− langid = {latin},
1173− editoratype = {redactor},
1174− indextitle = {Regesta Pontificum Romanorum},
1175− shorttitle = {Regesta Pontificum Romanorum},
1176− annotation = {A \texttt{collection} entry with \texttt{edition} and
1177− \texttt{volumes} fields. Note the \texttt{editora} and
1178− \texttt{editoratype} fields},
1179−}
1180−
1181−@collection{westfahl:frontier,
1182− editor = {Westfahl, Gary},
1183− title = {Space and Beyond},
1184− date = 2000,
1185− subtitle = {The Frontier Theme in Science Fiction},
1186− publisher = {Greenwood},
1187− location = {Westport, Conn. and London},
1188− langid = {english},
1189− langidopts = {variant=american},
1190− booktitle = {Space and Beyond},
1191− booksubtitle = {The Frontier Theme in Science Fiction},
1192− annotation = {This is a \texttt{collection} entry. Note the format of the
1193− \texttt{location} field as well as the \texttt{subtitle} and
1194− \texttt{booksubtitle} fields},
1195−}
1196−
1197−@inbook{kant:kpv,
1198− title = {Kritik der praktischen Vernunft},
1199− date = 1968,
1200− author = {Kant, Immanuel},
1201− booktitle = {Kritik der praktischen Vernunft. Kritik der Urtheilskraft},
1202− bookauthor = {Kant, Immanuel},
1203− maintitle = {Kants Werke. Akademie Textausgabe},
1204− volume = 5,
1205− publisher = {Walter de Gruyter},
1206− location = {Berlin},
1207− pages = {1-163},
1208− shorthand = {KpV},
1209− langid = {german},
1210− shorttitle = {Kritik der praktischen Vernunft},
1211− annotation = {An edition of Kant's \emph{Collected Works}, volume five. This
1212− is an \texttt{inbook} entry which explicitly refers to the
1213− \emph{Critique of Practical Reason} only, not to the entire
1214− fifth volume. Note the \texttt{author} and \texttt{bookauthor}
1215− fields in the database file. By default, the
1216− \texttt{bookauthor} is omitted if the values of the
1217− \texttt{author} and \texttt{bookauthor} fields are identical},
1218−}
1219−
1220−@inbook{kant:ku,
1221− title = {Kritik der Urtheilskraft},
1222− date = 1968,
1223− author = {Kant, Immanuel},
1224− booktitle = {Kritik der praktischen Vernunft. Kritik der Urtheilskraft},
1225− bookauthor = {Kant, Immanuel},
1226− maintitle = {Kants Werke. Akademie Textausgabe},
1227− volume = 5,
1228− publisher = {Walter de Gruyter},
1229− location = {Berlin},
1230− pages = {165-485},
1231− shorthand = {KU},
1232− langid = {german},
1233− annotation = {An edition of Kant's \emph{Collected Works}, volume five. This
1234− is an \texttt{inbook} entry which explicitly refers to the
1235− \emph{Critique of Judgment} only, not to the entire fifth
1236− volume},
1237−}
1238−
1239−@inbook{nietzsche:historie,
1240− title = {Unzeitgem{\"a}sse Betrachtungen. Zweites St{\"u}ck},
1241− date = 1988,
1242− author = {Nietzsche, Friedrich},
1243− booktitle = {Die Geburt der Trag{\"o}die. Unzeitgem{\"a}{\ss}e
1244− Betrachtungen I--IV. Nachgelassene Schriften 1870--1973},
1245− bookauthor = {Nietzsche, Friedrich},
1246− editor = {Colli, Giorgio and Montinari, Mazzino},
1247− subtitle = {Vom Nutzen und Nachtheil der Historie f{\"u}r das Leben},
1248− maintitle = {S{\"a}mtliche Werke},
1249− mainsubtitle = {Kritische Studienausgabe},
1250− volume = 1,
1251− publisher = dtv # { and Walter de Gruyter},
1252− location = {M{\"u}nchen and Berlin and New York},
1253− pages = {243-334},
1254− langid = {german},
1255− sortyear = {1988-2},
1256− sorttitle = {Werke-01-243},
1257− indexsorttitle= {Vom Nutzen und Nachtheil der Historie fur das Leben},
1258− indextitle = {Vom Nutzen und Nachtheil der Historie f{\"u}r das Leben},
1259− shorttitle = {Vom Nutzen und Nachtheil der Historie},
1260− annotation = {A single essay from the critical edition of Nietzsche's works.
1261− This \texttt{inbook} entry explicitly refers to an essay found
1262− in the first volume. Note the \texttt{title},
1263− \texttt{booktitle}, and \texttt{maintitle} fields. Also note
1264− the \texttt{sorttitle} and \texttt{sortyear} fields. We want
1265− this entry to be listed after the entry referring to the
1266− entire first volume},
1267−}
1268−
1269−@incollection{brandt,
1270− author = {von Brandt, Ahasver and Erich Hoffmann},
1271− editor = {Ferdinand Seibt},
1272− title = {Die nordischen L{\"a}nder von der Mitte des 11.~Jahrhunderts
1273− bis 1448},
1274− date = 1987,
1275− booktitle = {Europa im Hoch- und Sp{\"a}tmittelalter},
1276− series = {Handbuch der europ{\"a}ischen Geschichte},
1277− number = 2,
1278− publisher = {Klett-Cotta},
1279− location = {Stuttgart},
1280− pages = {884-917},
1281− options = {useprefix=false},
1282− langid = {german},
1283− indexsorttitle= {Nordischen Lander von der Mitte des 11. Jahrhunderts bis
1284− 1448},
1285− indextitle = {Nordischen L{\"a}nder von der Mitte des 11.~Jahrhunderts bis
1286− 1448, Die},
1287− shorttitle = {Die nordischen L{\"a}nder},
1288− annotation = {An \texttt{incollection} entry with a \texttt{series} and a
1289− \texttt{number}. Note the format of the printed name and
1290− compare the \texttt{useprefix} option in the \texttt{options}
1291− field as well as \texttt{vangennep}. Also note the
1292− \texttt{indextitle, and \texttt{indexsorttitle} fields}},
1293−}
1294−
1295−@incollection{hyman,
1296− author = {Arthur Hyman},
1297− editor = {O'Meara, Dominic J.},
1298− title = {Aristotle's Theory of the Intellect and its Interpretation by
1299− {Averroes}},
1300− date = 1981,
1301− booktitle = {Studies in {Aristotle}},
1302− series = {Studies in Philosophy and the History of Philosophy},
1303− number = 9,
1304− publisher = {The Catholic University of America Press},
1305− location = {Washington, D.C.},
1306− pages = {161-191},
1307− keywords = {secondary},
1308− langid = {english},
1309− langidopts = {variant=american},
1310− indextitle = {Aristotle's Theory of the Intellect},
1311− shorttitle = {Aristotle's Theory of the Intellect},
1312− annotation = {An \texttt{incollection} entry with a \texttt{series} and
1313− \texttt{number} field},
1314−}
1315−
1316−@incollection{pines,
1317− author = {Pines, Shlomo},
1318− editor = {Twersky, Isadore},
1319− title = {The Limitations of Human Knowledge According to {Al-Farabi}, {ibn
1320− Bajja}, and {Maimonides}},
1321− date = 1979,
1322− booktitle = {Studies in Medieval {Jewish} History and Literature},
1323− publisher = hup,
1324− location = {Cambridge, Mass.},
1325− pages = {82-109},
1326− keywords = {secondary},
1327− langid = {english},
1328− langidopts = {variant=american},
1329− indextitle = {Limitations of Human Knowledge According to {Al-Farabi}, {ibn
1330− Bajja}, and {Maimonides}, The},
1331− shorttitle = {Limitations of Human Knowledge},
1332− annotation = {A typical \texttt{incollection} entry. Note the
1333− \texttt{indextitle} field},
1334−}
1335−
1336−@inproceedings{moraux,
1337− author = {Moraux, Paul},
1338− editor = {Lloyd, G. E. R. and Owen, G. E. L.},
1339− title = {Le \emph{De Anima} dans la tradition gr{\`e}cque},
1340− date = 1979,
1341− booktitle = {Aristotle on Mind and the Senses},
1342− subtitle = {Quelques aspects de l'interpretation du trait{\'e}, de
1343− Theophraste {\`a} Themistius},
1344− booktitleaddon= {Proceedings of the Seventh Symposium Aristotelicum},
1345− eventdate = 1975,
1346− publisher = cup,
1347− location = {Cambridge},
1348− pages = {281-324},
1349− keywords = {secondary},
1350− langid = {french},
1351− indexsorttitle= {De Anima dans la tradition grecque},
1352− indextitle = {\emph{De Anima} dans la tradition gr{\`e}cque, Le},
1353− shorttitle = {\emph{De Anima} dans la tradition gr{\`e}cque},
1354− annotation = {This is a typical \texttt{inproceedings} entry. Note the
1355− \texttt{booksubtitle}, \texttt{shorttitle},
1356− \texttt{indextitle}, and \texttt{indexsorttitle} fields. Also
1357− note the \texttt{eventdate} field.},
1358−}
1359−
1360−@inproceedings{salam,
1361− author = {Salam, Abdus},
1362− editor = {Svartholm, Nils},
1363− title = {Weak and Electromagnetic Interactions},
1364− date = 1968,
1365− booktitle = {Elementary particle theory},
1366− booksubtitle = {Relativistic groups and analyticity},
1367− booktitleaddon= {Proceedings of the {Eighth Nobel Symposium}},
1368− eventdate = {1968-05-19/1968-05-25},
1369− venue = {Aspen{\"a}sgarden, Lerum},
1370− publisher = {Almquist \& Wiksell},
1371− location = {Stockholm},
1372− pages = {367-377},
1373−}
1374−
1375−@manual{cms,
1376− title = {The {Chicago} Manual of Style},
1377− date = 2003,
1378− subtitle = {The Essential Guide for Writers, Editors, and Publishers},
1379− edition = 15,
1380− publisher = {University of Chicago Press},
1381− location = {Chicago, Ill.},
1382− isbn = {0-226-10403-6},
1383− label = {CMS},
1384− langid = {english},
1385− langidopts = {variant=american},
1386− sorttitle = {Chicago Manual of Style},
1387− indextitle = {Chicago Manual of Style, The},
1388− shorttitle = {Chicago Manual of Style},
1389− annotation = {This is a \texttt{manual} entry without an \texttt{author} or
1390− \texttt{editor}. Note the \texttt{label} field in the database
1391− file which is provided for author-year citation styles. Also
1392− note the \texttt{sorttitle} and \texttt{indextitle} fields. By
1393− default, all entries without an \texttt{author} or
1394− \texttt{editor} are alphabetized by \texttt{title} but we want
1395− this entry to be alphabetized under \enquote*{C} rather than
1396− \enquote*{T}. There's also an \texttt{isbn} field},
1397−}
1398−
1399−@online{baez/online,
1400− author = {Baez, John C. and Lauda, Aaron D.},
1401− title = {Higher-Dimensional Algebra {V}: 2-Groups},
1402− date = {2004-10-27},
1403− version = 3,
1404− langid = {english},
1405− langidopts = {variant=american},
1406− eprinttype = {arxiv},
1407− eprint = {math/0307200v3},
1408− annotation = {An \texttt{online} reference from arXiv. Note the
1409− \texttt{eprint} and \texttt{eprinttype} fields. Compare
1410− \texttt{baez\slash article} which is the same item given as an
1411− \texttt{article} entry with eprint information},
1412−}
1413−
1414−@online{ctan,
1415− title = {CTAN},
1416− date = 2006,
1417− url = {http://www.ctan.org},
1418− subtitle = {The {Comprehensive TeX Archive Network}},
1419− urldate = {2006-10-01},
1420− label = {CTAN},
1421− langid = {english},
1422− langidopts = {variant=american},
1423− annotation = {This is an \texttt{online} entry. The \textsc{url}, which is
1424− given in the \texttt{url} field, is transformed into a
1425− clickable link if \texttt{hyperref} support has been
1426− enabled. Note the format of the \texttt{urldate} field
1427− (\texttt{yyyy-mm-dd}) in the database file. Also note the
1428− \texttt{label} field which may be used as a fallback by
1429− citation styles which need an \texttt{author} and\slash or a
1430− \texttt{year}},
1431−}
1432−
1433−@online{itzhaki,
1434− author = {Itzhaki, Nissan},
1435− title = {Some remarks on {'t Hooft's} {S}-matrix for black holes},
1436− date = {1996-03-11},
1437− version = 1,
1438− langid = {english},
1439− langidopts = {variant=american},
1440− eprinttype = {arxiv},
1441− eprint = {hep-th/9603067},
1442− annotation = {An \texttt{online} reference from arXiv. Note the
1443− \texttt{eprint} and \texttt{eprinttype} fields. Also note that
1444− the arXiv reference is transformed into a clickable link if
1445− \texttt{hyperref} support has been enabled},
1446− abstract = {We discuss the limitations of 't Hooft's proposal for the
1447− black hole S-matrix. We find that the validity of the S-matrix
1448− implies violation of the semi-classical approximation at
1449− scales large compared to the Planck scale. We also show that
1450− the effect of the centrifugal barrier on the S-matrix is
1451− crucial even for large transverse distances.},
1452−}
1453−
1454−@online{markey,
1455− author = {Markey, Nicolas},
1456− title = {Tame the {BeaST}},
1457− date = {2005-10-16},
1458− url = {http://mirror.ctan.org/info/bibtex/tamethebeast/ttb_en.pdf},
1459− subtitle = {The {B} to {X} of {BibTeX}},
1460− version = {1.3},
1461− urldate = {2006-10-01},
1462− langid = {english},
1463− langidopts = {variant=american},
1464− sorttitle = {Tame the Beast},
1465− annotation = {An \texttt{online} entry for a tutorial. Note the format of
1466− the \texttt{date} field (\texttt{yyyy-mm-dd}) in the database
1467− file.},
1468−}
1469−
1470−@online{wassenberg,
1471− author = {Wassenberg, Jan and Sanders, Peter},
1472− title = {Faster Radix Sort via Virtual Memory and Write-Combining},
1473− date = {2010-08-17},
1474− version = 1,
1475− langid = {english},
1476− langidopts = {variant=american},
1477− eprinttype = {arxiv},
1478− eprintclass = {cs.DS},
1479− eprint = {1008.2849v1},
1480− annotation = {A recent \texttt{online} reference from arXiv using the new
1481− (April 2007 onward) identifier format. Note the
1482− \texttt{eprint}, \texttt{eprinttype}, and \texttt{eprintclass}
1483− fields. Also note that the arXiv reference is transformed into
1484− a clickable link if \texttt{hyperref} support has been
1485− enabled},
1486− abstract = {Sorting algorithms are the deciding factor for the performance
1487− of common operations such as removal of duplicates or database
1488− sort-merge joins. This work focuses on 32-bit integer keys,
1489− optionally paired with a 32-bit value. We present a fast radix
1490− sorting algorithm that builds upon a microarchitecture-aware
1491− variant of counting sort},
1492−}
1493−
1494−@patent{almendro,
1495− author = {Almendro, Jos{\'e} L. and Mart{\'i}n, Jacinto and S{\'a}nchez,
1496− Alberto and Nozal, Fernando},
1497− title = {Elektromagnetisches Signalhorn},
1498− number = {EU-29702195U},
1499− date = 1998,
1500− location = {countryfr and countryuk and countryde},
1501− langid = {german},
1502− annotation = {This is a \texttt{patent} entry with a \texttt{location}
1503− field. The number is given in the \texttt{number} field. Note
1504− the format of the \texttt{location} field in the database
1505− file. Compare \texttt{laufenberg}, \texttt{sorace}, and
1506− \texttt{kowalik}},
1507−}
1508−
1509−@patent{kowalik,
1510− author = {Kowalik, F. and Isard, M.},
1511− title = {Estimateur d'un d{\'e}faut de fonctionnement d'un modulateur
1512− en quadrature et {\'e}tage de modulation l'utilisant},
1513− number = 9500261,
1514− date = {1995-01-11},
1515− type = {patreqfr},
1516− langid = {french},
1517− indextitle = {Estimateur d'un d{\'e}faut de fonctionnement},
1518− annotation = {This is a \texttt{patent} entry for a French patent request
1519− with a full date. The number is given in the \texttt{number}
1520− field. Note the format of the \texttt{type} and \texttt{date}
1521− fields in the database file. Compare \texttt{almendro},
1522− \texttt{laufenberg}, and \texttt{sorace}},
1523−}
1524−
1525−@patent{laufenberg,
1526− author = {Laufenberg, Xaver and Eynius, Dominique and Suelzle, Helmut
1527− and Usbeck, Stephan and Spaeth, Matthias and Neuser-Hoffmann,
1528− Miriam and Myrzik, Christian and Schmid, Manfred and Nietfeld,
1529− Franz and Thiel, Alexander and Braun, Harald and Ebner,
1530− Norbert},
1531− title = {Elektrische Einrichtung und Betriebsverfahren},
1532− number = 1700367,
1533− date = {2006-09-13},
1534− holder = {{Robert Bosch GmbH} and {Daimler Chrysler AG} and {Bayerische
1535− Motoren Werke AG}},
1536− type = {patenteu},
1537− langid = {german},
1538− annotation = {This is a \texttt{patent} entry with a \texttt{holder} field.
1539− Note the format of the \texttt{type} and \texttt{location}
1540− fields in the database file. Compare \texttt{almendro},
1541− \texttt{sorace}, and \texttt{kowalik}},
1542− abstract = {The invention relates to an electric device comprising a
1543− generator, in particular for use in the vehicle electric
1544− system of a motor vehicle and a controller for controlling the
1545− generator voltage. The device is equipped with a control zone,
1546− in which the voltage is controlled and zones, in which the
1547− torque is controlled. The invention also relates to methods
1548− for operating a device of this type.},
1549− file = {http://v3.espacenet.com/textdoc?IDX=EP1700367},
1550−}
1551−
1552−@patent{sorace,
1553− author = {Sorace, Ronald E. and Reinhardt, Victor S. and Vaughn, Steven
1554− A.},
1555− title = {High-Speed Digital-to-{RF} Converter},
1556− number = 5668842,
1557− date = {1997-09-16},
1558− holder = {{Hughes Aircraft Company}},
1559− type = {patentus},
1560− langid = {english},
1561− langidopts = {variant=american},
1562− annotation = {This is a \texttt{patent} entry with a \texttt{holder} field.
1563− Note the format of the \texttt{type} and \texttt{date} fields
1564− in the database file. Compare \texttt{almendro},
1565− \texttt{laufenberg}, and \texttt{kowalik}},
1566−}
1567−
1568−@periodical{jcg,
1569− title = {Computers and Graphics},
1570− year = 2011,
1571− issuetitle = {Semantic {3D} Media and Content},
1572− volume = 35,
1573− number = 4,
1574− issn = {0097-8493},
1575− annotation = {This is a \texttt{periodical} entry with an \texttt{issn}
1576− field.},
1577−}
1578−
1579−@report{chiu,
1580− author = {Chiu, Willy W. and Chow, We Min},
1581− title = {A Hybrid Hierarchical Model of a {Multiple Virtual Storage}
1582− ({MVS}) Operating System},
1583− type = {resreport},
1584− institution = {IBM},
1585− date = 1978,
1586− number = {RC-6947},
1587− langid = {english},
1588− langidopts = {variant=american},
1589− sorttitle = {Hybrid Hierarchical Model of a Multiple Virtual Storage (MVS)
1590− Operating System},
1591− indextitle = {Hybrid Hierarchical Model, A},
1592− annotation = {This is a \texttt{report} entry for a research report. Note
1593− the format of the \texttt{type} field in the database file
1594− which uses a localization key. The number of the report is
1595− given in the \texttt{number} field. Also note the
1596− \texttt{sorttitle} and \texttt{indextitle} fields},
1597−}
1598−
1599−@report{padhye,
1600− author = {Padhye, Jitendra and Firoiu, Victor and Towsley, Don},
1601− title = {A Stochastic Model of {TCP Reno} Congestion Avoidance and
1602− Control},
1603− type = {techreport},
1604− institution = {University of Massachusetts},
1605− date = 1999,
1606− number = {99-02},
1607− location = {Amherst, Mass.},
1608− langid = {english},
1609− langidopts = {variant=american},
1610− sorttitle = {A Stochastic Model of TCP Reno Congestion Avoidance and
1611− Control},
1612− indextitle = {Stochastic Model of {TCP Reno} Congestion Avoidance and Control,
1613− A},
1614− annotation = {This is a \texttt{report} entry for a technical report. Note
1615− the format of the \texttt{type} field in the database file
1616− which uses a localization key. The number of the report is
1617− given in the \texttt{number} field. Also note the
1618− \texttt{sorttitle} and \texttt{indextitle} fields},
1619− abstract = {The steady state performance of a bulk transfer TCP flow
1620− (i.e. a flow with a large amount of data to send, such as FTP
1621− transfers) may be characterized by three quantities. The first
1622− is the send rate, which is the amount of data sent by the
1623− sender in unit time. The second is the throughput, which is
1624− the amount of data received by the receiver in unit time. Note
1625− that the throughput will always be less than or equal to the
1626− send rate due to losses. Finally, the number of non-duplicate
1627− packets received by the receiver in unit time gives us the
1628− goodput of the connection. The goodput is always less than or
1629− equal to the throughput, since the receiver may receive two
1630− copies of the same packet due to retransmissions by the
1631− sender. In a previous paper, we presented a simple model for
1632− predicting the steady state send rate of a bulk transfer TCP
1633− flow as a function of loss rate and round trip time. In this
1634− paper, we extend that work in two ways. First, we analyze the
1635− performance of bulk transfer TCP flows using more precise,
1636− stochastic analysis. Second, we build upon the previous
1637− analysis to provide both an approximate formula as well as a
1638− more accurate stochastic model for the steady state throughput
1639− of a bulk transfer TCP flow.},
1640− file = {ftp://gaia.cs.umass.edu/pub/Padhey99-markov.ps},
1641−}
1642−
1643−@thesis{geer,
1644− author = {de Geer, Ingrid},
1645− title = {Earl, Saint, Bishop, Skald~-- and Music},
1646− type = {phdthesis},
1647− institution = {Uppsala Universitet},
1648− date = 1985,
1649− subtitle = {The {Orkney Earldom} of the Twelfth Century. {A} Musicological
1650− Study},
1651− location = {Uppsala},
1652− options = {useprefix=false},
1653− langid = {english},
1654− langidopts = {variant=british},
1655− annotation = {This is a typical \texttt{thesis} entry for a PhD thesis. Note
1656− the \texttt{type} field in the database file which uses a
1657− localization key. Also note the format of the printed name and
1658− compare the \texttt{useprefix} option in the \texttt{options}
1659− field as well as \texttt{vangennep}},
1660−}
1661−
1662−@thesis{loh,
1663− author = {Loh, Nin C.},
1664− title = {High-Resolution Micromachined Interferometric Accelerometer},
1665− type = {mathesis},
1666− institution = {Massachusetts Institute of Technology},
1667− date = 1992,
1668− location = {Cambridge, Mass.},
1669− langid = {english},
1670− langidopts = {variant=american},
1671− annotation = {This is a typical \texttt{thesis} entry for an MA thesis. Note
1672− the \texttt{type} field in the database file which uses a
1673− localization key},
1674−}
test/command/biblatex-inproceedings.md+1−1
@@ -63,7 +63,7 @@ references:
63 publisher-place: Cambridge
63 publisher-place: Cambridge
64 title: "Le *De Anima* dans la tradition grècque: Quelques aspects de
64 title: "Le *De Anima* dans la tradition grècque: Quelques aspects de
65 l'interpretation du traité, de Theophraste à Themistius"
65 l'interpretation du traité, de Theophraste à Themistius"
66− title-short: *De Anima* dans la tradition grècque
66+ title-short: "*De Anima* dans la tradition grècque"
67 type: paper-conference
67 type: paper-conference
68- author:
68- author:
69 - family: Salam
69 - family: Salam
test/command/biblatex-jaffe.md+2−2
@@ -72,8 +72,8 @@ references:
72 language: la
72 language: la
73 number-of-volumes: 2
73 number-of-volumes: 2
74 publisher-place: Leipzig
74 publisher-place: Leipzig
75− title: "Regesta Pontificum Romanorum ab condita ecclesia ad annum post
75+ title: Regesta Pontificum Romanorum ab condita ecclesia ad annum post
76− Christum natum [mcxcviii]{.smallcaps}"
76+ Christum natum [mcxcviii]{.smallcaps}
77 title-short: Regesta Pontificum Romanorum
77 title-short: Regesta Pontificum Romanorum
78 type: book
78 type: book
79---
79---
test/command/biblatex-moraux.md+1−1
@@ -86,7 +86,7 @@ references:
86 publisher-place: Cambridge
86 publisher-place: Cambridge
87 title: "Le *De Anima* dans la tradition grècque: Quelques aspects de
87 title: "Le *De Anima* dans la tradition grècque: Quelques aspects de
88 l'interpretation du traité, de Theophraste à Themistius"
88 l'interpretation du traité, de Theophraste à Themistius"
89− title-short: *De Anima* dans la tradition grècque
89+ title-short: "*De Anima* dans la tradition grècque"
90 type: paper-conference
90 type: paper-conference
91---
91---
92
92
test/command/biblatex-nussbaum.mddeleted−63
@@ -1,63 +0,0 @@
1−```
2−% pandoc -f biblatex -t markdown -s
3−@comment{
4−
5−Adapted from biblatex-example.bib
6−
7−
8−Formatted with pandoc and chicago-author-date.csl, 2013-10-23:
9−
10−(Nussbaum 1978)
11−
12−Nussbaum, Martha. 1978. *Aristotle’s “De Motu Animalium”*. Princeton:
13−Princeton University Press.
14−
15−
16−Formatted with pandoc and apa.csl, 2013-10-23:
17−
18−(Nussbaum, 1978)
19−
20−Nussbaum, M. (1978). *Aristotle’s “De Motu Animalium”*. Princeton:
21−Princeton University Press.
22−
23−
24−}
25−
26−@string{ pup = {Princeton University Press} }
27−
28−@Book{nussbaum,
29− author = {Nussbaum, Martha},
30− title = {Aristotle's \mkbibquote{De Motu Animalium}},
31− date = 1978,
32− publisher = pup,
33− location = {Princeton},
34− keywords = {secondary},
35− hyphenation = {american},
36− sorttitle = {Aristotle's De Motu Animalium},
37− indexsorttitle= {Aristotle's De Motu Animalium},
38− annotation = {A book entry. Note the sorttitle and
39− indexsorttitle fields and the markup of the quotes in
40− the database file},
41−}
42−
43−^D
44−---
45−nocite: "[@*]"
46−references:
47−- annote: A book entry. Note the sorttitle and indexsorttitle fields and
48− the markup of the quotes in the database file
49− author:
50− - family: Nussbaum
51− given: Martha
52− id: nussbaum
53− issued: 1978
54− keyword: secondary
55− language: en-US
56− publisher: Princeton University Press
57− publisher-place: Princeton
58− title: "Aristotle's \"De Motu Animalium\""
59− type: book
60−---
61−
62−
63−```
test/command/biblatex-quotes.md+1−1
@@ -36,7 +36,7 @@ references:
36 language: en-US
36 language: en-US
37 publisher: Princeton University Press
37 publisher: Princeton University Press
38 publisher-place: Princeton
38 publisher-place: Princeton
39− title: "Aristotle's \"De Motu Animalium\""
39+ title: Aristotle's "De Motu Animalium"
40 type: book
40 type: book
41---
41---
42
42
test/command/biblatex-sigfridsson.md+1−1
@@ -90,7 +90,7 @@ references:
90 - family: Ryde
90 - family: Ryde
91 given: Ulf
91 given: Ulf
92 container-title: Journal of Computational Chemistry
92 container-title: Journal of Computational Chemistry
93− doi: "10.1002/(SICI)1096-987X(199803)19:4\\<377::AID-JCC1\\>3.0.CO;2-P"
93+ doi: "10.1002/(SICI)1096-987X(199803)19:4\\<377::AID-JCC1>3.0.CO;2-P"
94 id: sigfridsson
94 id: sigfridsson
95 issue: 4
95 issue: 4
96 issued: 1998
96 issued: 1998
test/command/biblatex-spiegelberg.md+2−2
@@ -63,8 +63,8 @@ references:
63 issued: 1969
63 issued: 1969
64 language: de-DE
64 language: de-DE
65 page: 189-216
65 page: 189-216
66− title: "Intention" und "Intentionalität" in der Scholastik, bei
66+ title: "\"Intention\" und \"Intentionalität\" in der Scholastik, bei
67− Brentano und Husserl
67+ Brentano und Husserl"
68 title-short: Intention und Intentionalität
68 title-short: Intention und Intentionalität
69 type: article-journal
69 type: article-journal
70 volume: 29
70 volume: 29
test/command/biblatex-test-case-conversion.md+2−2
@@ -63,9 +63,9 @@ references:
63 id: item1
63 id: item1
64 issued: 2013
64 issued: 2013
65 language: en-US
65 language: en-US
66− title: "A title, in English, with a Proper Name and an ACRONYM and a
66+ title: A title, in English, with a Proper Name and an ACRONYM and a
67 [camelCase]{.nocase} word and some units, 400 [nm]{.nocase},
67 [camelCase]{.nocase} word and some units, 400 [nm]{.nocase},
68− 3 [cm]{.nocase}, and a quote, *Alea [iacta est]{.nocase}*"
68+ 3 [cm]{.nocase}, and a quote, *Alea [iacta est]{.nocase}*
69 type: article-journal
69 type: article-journal
70---
70---
71
71
test/command/biblatex-textnormal.md+1−1
@@ -9,7 +9,7 @@
9nocite: "[@*]"
9nocite: "[@*]"
10references:
10references:
11- id: item1
11- id: item1
12− title: "The title [of this book]{.nodecor}"
12+ title: The title [of this book]{.nodecor}
13 type: book
13 type: book
14---
14---
15
15
test/command/chap1/spider.pngnew file

Binary file not shown.

test/command/chap1/text.mdnew file+17
@@ -0,0 +1,17 @@
1+# Chapter one
2+
3+A spider: ![spider](spider.png)
4+
5+Another spider: ![another spider][refspider]
6+
7+The moon: ![moon](../../lalune.jpg)
8+
9+Link to [spider picture](spider.png).
10+
11+URL left alone: [manual](https://pandoc.org/MANUAL.html).
12+
13+Absolute path left alone: [absolute](/foo/bar/baz.png).
14+
15+Link to fragment: [chapter two](#chapter-two).
16+
17+Empty path: [empty]().
test/command/chap2/spider.pngnew file

Binary file not shown.

test/command/chap2/text.mdnew file+5
@@ -0,0 +1,5 @@
1+# Chapter two
2+
3+A spider: ![spider](spider.png)
4+
5+[refspider]: spider.png
test/command/defaults-inheritance-2.md+1−1
@@ -1,5 +1,5 @@
1```
1```
2−% pandoc -d command/defaults6
2+% pandoc -d command/defaults6 2>&1
3^D
3^D
4Error: Circular defaults file reference in 'command/defaults7.yaml'
4Error: Circular defaults file reference in 'command/defaults7.yaml'
5```
5```
test/command/mmd-metadata.mdnew file+20
@@ -0,0 +1,20 @@
1+```
2+% pandoc -f markdown_mmd -t markdown -s
3+Title: Blah blah blah
4+Author: Doo de Doo
5+Base Header Level: 1
6+Bibliography: Pubs.bib
7+Lang: en-GB
8+
9+body
10+^D
11+---
12+author: Doo de Doo
13+baseheaderlevel: 1
14+bibliography: Pubs.bib
15+lang: en-GB
16+title: Blah blah blah
17+---
18+
19+body
20+```
test/command/newif.mdnew file+55
@@ -0,0 +1,55 @@
1+```
2+% pandoc -f latex -t plain
3+\iftrue
4+should print
5+\iftrue
6+should print
7+\else
8+should not print
9+\fi
10+\else
11+should not print
12+\fi
13+
14+\iffalse
15+should not print
16+\else
17+\iftrue
18+should print
19+\else
20+should not print
21+\fi
22+\fi
23+
24+\newif\ifepub
25+
26+\ifepub
27+should not print
28+\fi
29+
30+\epubtrue
31+
32+\ifepub
33+should print
34+\else
35+should not print
36+\fi
37+
38+\epubfalse
39+
40+\ifepub
41+should not print
42+\else
43+should print
44+\fi
45+^D
46+should print
47+
48+should print
49+
50+should print
51+
52+should print
53+
54+should print
55+```
test/command/pandoc-citeproc-119.md+1−1
@@ -1,7 +1,7 @@
1```
1```
2% pandoc --citeproc -t markdown-citations
2% pandoc --citeproc -t markdown-citations
3---
3---
4−bibliography: 'command/biblatex-examples.bib'
4+bibliography: 'command/averroes.bib'
5csl: command/apa.csl
5csl: command/apa.csl
6---
6---
7
7
test/command/pandoc-citeproc-320a.md+3−3
@@ -49,7 +49,7 @@ references:
49Foo [@item1; @item2; @item3; @item4; @item5; @item6; @item7; @item8].
49Foo [@item1; @item2; @item3; @item4; @item5; @item6; @item7; @item8].
50^D
50^D
51Foo (al-ʾUdhrī, n.d.; al-ʿUdhrī, n.d.; al-\'Udhrī, n.d.; al-'Udhrī,
51Foo (al-ʾUdhrī, n.d.; al-ʿUdhrī, n.d.; al-\'Udhrī, n.d.; al-'Udhrī,
52−n.d.; al-'Udhrī, n.d.; Uch, n.d.; Uebel, n.d.; Zzz, n.d.).
52+n.d.a, n.d.b; Uch, n.d.; Uebel, n.d.; Zzz, n.d.).
53
53
54::: {#refs .references .csl-bib-body .hanging-indent}
54::: {#refs .references .csl-bib-body .hanging-indent}
55::: {#ref-item6 .csl-entry}
55::: {#ref-item6 .csl-entry}
@@ -69,11 +69,11 @@ Uch, Ann. n.d.
69:::
69:::
70
70
71::: {#ref-item4 .csl-entry}
71::: {#ref-item4 .csl-entry}
72−'Udhrī, Jamīl al-. n.d.
72+'Udhrī, Jamīl al-. n.d.a.
73:::
73:::
74
74
75::: {#ref-item5 .csl-entry}
75::: {#ref-item5 .csl-entry}
76−'Udhrī, Jamīl al-. n.d.
76+---------. n.d.b.
77:::
77:::
78
78
79::: {#ref-item7 .csl-entry}
79::: {#ref-item7 .csl-entry}
test/command/pandoc-citeproc-322.md+1−1
@@ -19,7 +19,7 @@ references:
19 type: 'article-journal'
19 type: 'article-journal'
20---
20---
21
21
22−Foo[@timmory__justice_1950].
22+Foo [@timmory__justice_1950].
23^D
23^D
24Foo.[^1]
24Foo.[^1]
25
25
test/command/pandoc-citeproc-356.md+2−7
@@ -15,11 +15,6 @@ references:
15
15
16[@bar]
16[@bar]
17^D
17^D
18−(Alice 2042)
18+[WARNING] Citeproc: citation bar not found
19−
19+(**bar?**)
20−::: {#refs .references .csl-bib-body .hanging-indent}
21−::: {#ref-foo .csl-entry}
22−Alice. 2042.
23−:::
24−:::
25```
20```
test/command/pandoc-citeproc-65.md+1−1
@@ -14,7 +14,7 @@ references:
14 id: 'stotz:1996handbuch'
14 id: 'stotz:1996handbuch'
15 issued:
15 issued:
16 literal: 1996_2004
16 literal: 1996_2004
17− language: German
17+ language: de
18 number-of-volumes: 5
18 number-of-volumes: 5
19 publisher: Beck
19 publisher: Beck
20 publisher-place: Munich
20 publisher-place: Munich
test/command/pandoc-citeproc-70.md+2−2
@@ -22,7 +22,7 @@ references:
22 issued:
22 issued:
23 date-parts:
23 date-parts:
24 - - 2009
24 - - 2009
25− language: French
25+ language: fr
26 page: '155--174'
26 page: '155--174'
27 publisher: 'Fédération Internationale des Instituts d''Études
27 publisher: 'Fédération Internationale des Instituts d''Études
28 Médiévales'
28 Médiévales'
@@ -42,7 +42,7 @@ references:
42 issued:
42 issued:
43 date-parts:
43 date-parts:
44 - - 1955
44 - - 1955
45− language: Latin
45+ language: la
46 note: 'ArticleType: research-article / Full publication date: 1955 /
46 note: 'ArticleType: research-article / Full publication date: 1955 /
47 Copyright © 1955 Fordham University'
47 Copyright © 1955 Fordham University'
48 page: '163--193'
48 page: '163--193'
test/command/pandoc-citeproc-chicago-author-date.md+7−7
@@ -54,14 +54,14 @@ References {#references .unnumbered}
54
54
55([**nonexistent?**](#ref-nonexistent))
55([**nonexistent?**](#ref-nonexistent))
56
56
57−[Doe](#ref-item1) ([2005](#ref-item1)) says blah.
57+Doe ([2005](#ref-item1)) says blah.
58
58
59−[Doe](#ref-item1) ([2005, 30](#ref-item1)) says blah.
59+Doe ([2005, 30](#ref-item1)) says blah.
60
60
61−[Doe](#ref-item1) ([2005, 30](#ref-item1), with suffix) says blah.
61+Doe ([2005, 30](#ref-item1), with suffix) says blah.
62
62
63−[Doe](#ref-item1) ([2005](#ref-item1); [2006, 30](#ref-item2); see also
63+Doe ([2005](#ref-item1); [2006, 30](#ref-item2); see also [Doe and Roe
64−[Doe and Roe 2007](#ref-пункт3)) says blah.
64+2007](#ref-пункт3)) says blah.
65
65
66In a note.[^1]
66In a note.[^1]
67
67
@@ -98,8 +98,8 @@ edited by Sam Smith. Oxford: Oxford University Press.
98:::
98:::
99:::
99:::
100
100
101−[^1]: [Doe and Roe](#ref-пункт3) ([2007, 12](#ref-пункт3)) and a
101+[^1]: Doe and Roe ([2007, 12](#ref-пункт3)) and a citation without
102− citation without locators ([Doe and Roe 2007](#ref-пункт3)).
102+ locators ([Doe and Roe 2007](#ref-пункт3)).
103
103
104[^2]: Some citations (see [Doe 2005, chap. 3](#ref-item1);
104[^2]: Some citations (see [Doe 2005, chap. 3](#ref-item1);
105 [2006](#ref-item2); [Doe and Roe 2007](#ref-пункт3)).
105 [2006](#ref-item2); [Doe and Roe 2007](#ref-пункт3)).
test/command/pandoc-citeproc-chicago-fullnote-bibliography.md+6−7
@@ -55,13 +55,13 @@ References {#references .unnumbered}
55
55
56[^2]
56[^2]
57
57
58−[John Doe](#ref-item1)[^3] says blah.
58+John Doe[^3] says blah.
59
59
60−[Doe](#ref-item1)[^4] says blah.
60+Doe[^4] says blah.
61
61
62−[Doe](#ref-item1)[^5] says blah.
62+Doe[^5] says blah.
63
63
64−[Doe](#ref-item1)[^6] says blah.
64+Doe[^6] says blah.
65
65
66In a note.[^7]
66In a note.[^7]
67
67
@@ -112,9 +112,8 @@ Sam Smith. Oxford: Oxford University Press, 2007.
112 Roe, "Why Water Is Wet," in *Third Book*, ed. Sam Smith (Oxford:
112 Roe, "Why Water Is Wet," in *Third Book*, ed. Sam Smith (Oxford:
113 Oxford University Press, 2007)](#ref-пункт3).
113 Oxford University Press, 2007)](#ref-пункт3).
114
114
115−[^7]: [Doe and Roe](#ref-пункт3), ["Why Water Is Wet," 12](#ref-пункт3)
115+[^7]: Doe and Roe, ["Why Water Is Wet," 12](#ref-пункт3) and a citation
116− and a citation without locators ([Doe and Roe, "Why Water Is
116+ without locators ([Doe and Roe, "Why Water Is Wet"](#ref-пункт3)).
117− Wet"](#ref-пункт3)).
118
117
119[^8]: See [Doe, *First Book*, chap. 3](#ref-item1); also [Doe and Roe,
118[^8]: See [Doe, *First Book*, chap. 3](#ref-item1); also [Doe and Roe,
120 "Why Water Is Wet," 34--35](#ref-пункт3).
119 "Why Water Is Wet," 34--35](#ref-пункт3).
test/command/svg.md+1−1
@@ -2,7 +2,7 @@
2% pandoc -f latex -t icml
2% pandoc -f latex -t icml
3\includegraphics{command/corrupt.svg}
3\includegraphics{command/corrupt.svg}
4^D
4^D
5−[WARNING] Could not determine image size for 'command/corrupt.svg': could not determine image type
5+[WARNING] Could not determine image size for command/corrupt.svg: could not determine image type
6<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
6<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
7 <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
7 <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
8 <Rectangle Self="uec" StrokeWeight="0" ItemTransform="1 0 0 1 150 -100">
8 <Rectangle Self="uec" StrokeWeight="0" ItemTransform="1 0 0 1 150 -100">
test/command/toc.md+2−2
@@ -31,7 +31,7 @@
31
31
32## b
32## b
33
33
34−::: {.interior}
34+::: interior
35# C
35# C
36
36
37## cc
37## cc
@@ -39,7 +39,7 @@
39# D
39# D
40:::
40:::
41
41
42−::: {.blue}
42+::: blue
43# E
43# E
44
44
45## e
45## e
test/command/unicode-collation.mdnew file+130
@@ -0,0 +1,130 @@
1+```
2+% pandoc --citeproc -t plain
3+---
4+lang: en-US
5+csl: command/apa.csl
6+references:
7+- id: a1
8+ type: book
9+ author:
10+ - family: Ubina
11+ given: A. John
12+ issued: 1985
13+- id: a2
14+ type: book
15+ author:
16+ - family: Über
17+ given: Aglaia
18+ issued: 1996
19+- id: a3
20+ type: book
21+ author:
22+ - family: Oñate
23+ given: José
24+ issued: 1985
25+- id: a4
26+ type: book
27+ author:
28+ - family: Onush
29+ given: Frank
30+ issued: 2002
31+- id: a5
32+ type: book
33+ author:
34+ - family: O'Neil
35+ given: Timothy
36+ issued: 2010
37+---
38+
39+[@a1;@a2;@a3;@a4;@a5]
40+^D
41+(O’Neil, 2010; Oñate, 1985; Onush, 2002; Über, 1996; Ubina, 1985)
42+
43+O’Neil, T. (2010).
44+
45+Oñate, J. (1985).
46+
47+Onush, F. (2002).
48+
49+Über, A. (1996).
50+
51+Ubina, A. J. (1985).
52+```
53+
54+```
55+% pandoc --citeproc -t plain
56+---
57+lang: es
58+csl: command/apa.csl
59+references:
60+- id: a1
61+ type: book
62+ author:
63+ - family: Ubina
64+ given: A. John
65+ issued: 1985
66+- id: a2
67+ type: book
68+ author:
69+ - family: Über
70+ given: Aglaia
71+ issued: 1996
72+- id: a3
73+ type: book
74+ author:
75+ - family: Oñate
76+ given: José
77+ issued: 1985
78+- id: a4
79+ type: book
80+ author:
81+ - family: Onush
82+ given: Frank
83+ issued: 2002
84+- id: a5
85+ type: book
86+ author:
87+ - family: O'Neil
88+ given: Timothy
89+ issued: 2010
90+---
91+
92+[@a1;@a2;@a3;@a4;@a5]
93+^D
94+(O’Neil, 2010; Onush, 2002; Oñate, 1985; Über, 1996; Ubina, 1985)
95+
96+O’Neil, T. (2010).
97+
98+Onush, F. (2002).
99+
100+Oñate, J. (1985).
101+
102+Über, A. (1996).
103+
104+Ubina, A. J. (1985).
105+```
106+
107+```
108+% pandoc -C -t plain
109+---
110+nocite: '@*'
111+lang: fr-FR-u-kb-true
112+references:
113+- id: cote
114+ author: cote
115+- id: côte
116+ author: côte
117+- id: coté
118+ author: coté
119+- id: côté
120+ author: côté
121+...
122+^D
123+cote. s. d.
124+
125+côte. s. d.
126+
127+coté. s. d.
128+
129+côté. s. d.
130+```
test/docbook-reader.docbook+3−1
@@ -6,7 +6,9 @@
6<!ENTITY let "LET" >
6<!ENTITY let "LET" >
7<!ENTITY case "CASE" >
7<!ENTITY case "CASE" >
8]>
8]>
9−<article>
9+<article xmlns="http://docbook.org/ns/docbook"
10+ xmlns:xlink="http://www.w3.org/1999/xlink"
11+ xmlns:mml="http://www.w3.org/1998/Math/MathML">
10 <articleinfo>
12 <articleinfo>
11 <title>Pandoc Test Suite</title>
13 <title>Pandoc Test Suite</title>
12 <authorgroup>
14 <authorgroup>
test/docx/0_level_headers.native+2−2
@@ -1,6 +1,6 @@
1[Table ("",[],[]) (Caption Nothing
1[Table ("",[],[]) (Caption Nothing
2 [])
2 [])
3− [(AlignDefault,ColWidthDefault)]
3+ [(AlignDefault,ColWidth 1.0)]
4 (TableHead ("",[],[])
4 (TableHead ("",[],[])
5 [])
5 [])
6 [(TableBody ("",[],[]) (RowHeadColumns 0)
6 [(TableBody ("",[],[]) (RowHeadColumns 0)
@@ -49,4 +49,4 @@
49,Para [Strong [Str "Table",Space,Str "Page"]]
49,Para [Strong [Str "Table",Space,Str "Page"]]
50,Para [Strong [Str "No",Space,Str "table",Space,Str "of",Space,Str "figures",Space,Str "entries",Space,Str "found."]]
50,Para [Strong [Str "No",Space,Str "table",Space,Str "of",Space,Str "figures",Space,Str "entries",Space,Str "found."]]
51,Header 1 ("introduction",[],[]) [Str "Introduction"]
51,Header 1 ("introduction",[],[]) [Str "Introduction"]
52−,Para [Str "Nothing",Space,Str "to",Space,Str "introduce,",Space,Str "yet."]]
52+,Para [Str "Nothing",Space,Str "to",Space,Str "introduce,",Space,Str "yet."]]
test/docx/golden/block_quotes.docx

Binary file not shown.

test/docx/golden/codeblock.docx

Binary file not shown.

test/docx/golden/comments.docx

Binary file not shown.

test/docx/golden/custom_style_no_reference.docx

Binary file not shown.

test/docx/golden/custom_style_preserve.docx

Binary file not shown.

test/docx/golden/custom_style_reference.docx

Binary file not shown.

test/docx/golden/definition_list.docx

Binary file not shown.

test/docx/golden/document-properties-short-desc.docx

Binary file not shown.

test/docx/golden/document-properties.docx

Binary file not shown.

test/docx/golden/headers.docx

Binary file not shown.

test/docx/golden/image.docx

Binary file not shown.

test/docx/golden/inline_code.docx

Binary file not shown.

test/docx/golden/inline_formatting.docx

Binary file not shown.

test/docx/golden/inline_images.docx

Binary file not shown.

test/docx/golden/link_in_notes.docx

Binary file not shown.

test/docx/golden/links.docx

Binary file not shown.

test/docx/golden/lists.docx

Binary file not shown.

test/docx/golden/lists_continuing.docx

Binary file not shown.

test/docx/golden/lists_multiple_initial.docx

Binary file not shown.

test/docx/golden/lists_restarting.docx

Binary file not shown.

test/docx/golden/nested_anchors_in_header.docx

Binary file not shown.

test/docx/golden/notes.docx

Binary file not shown.

test/docx/golden/raw-blocks.docx

Binary file not shown.

test/docx/golden/raw-bookmarks.docx

Binary file not shown.

test/docx/golden/table_one_row.docx

Binary file not shown.

test/docx/golden/table_with_list_cell.docx

Binary file not shown.

test/docx/golden/tables-default-widths.docxnew file

Binary file not shown.

test/docx/golden/tables.docx

Binary file not shown.

test/docx/golden/track_changes_deletion.docx

Binary file not shown.

test/docx/golden/track_changes_insertion.docx

Binary file not shown.

test/docx/golden/track_changes_move.docx

Binary file not shown.

test/docx/golden/track_changes_scrubbed_metadata.docx

Binary file not shown.

test/docx/golden/unicode.docx

Binary file not shown.

test/docx/golden/verbatim_subsuper.docx

Binary file not shown.

test/docx/image_vml_as_object.docxnew file

Binary file not shown.

test/docx/image_vml_as_object.nativenew file+2
@@ -0,0 +1,2 @@
1+[Para [Str "Test",Space,Str "with",Space,Str "object",Space,Str "as",Space,Str "image:"]
2+,Para [Image ("",[],[]) [] ("media/image1.emf","")]]
test/docx/sdt_elements.native+9−10
@@ -1,20 +1,19 @@
1[Table ("",[],[]) (Caption Nothing
1[Table ("",[],[]) (Caption Nothing
2 [])
2 [])
3− [(AlignDefault,ColWidthDefault)
3+ [(AlignDefault,ColWidth 0.22069570301081556)
4− ,(AlignDefault,ColWidthDefault)
4+ ,(AlignDefault,ColWidth 0.22069570301081556)
5− ,(AlignDefault,ColWidthDefault)]
5+ ,(AlignDefault,ColWidth 0.5586085939783689)]
6 (TableHead ("",[],[])
6 (TableHead ("",[],[])
7− [])
7+ [Row ("",[],[])
8− [(TableBody ("",[],[]) (RowHeadColumns 0)
9− []
10− [Row ("",[],[])
11 [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
8 [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
12 [Plain [Strong [Str "col1Header"]]]
9 [Plain [Strong [Str "col1Header"]]]
13 ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
10 ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
14 [Plain [Strong [Str "col2Header"]]]
11 [Plain [Strong [Str "col2Header"]]]
15 ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
12 ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
16− [Plain [Strong [Str "col3Header"]]]]
13+ [Plain [Strong [Str "col3Header"]]]]])
17− ,Row ("",[],[])
14+ [(TableBody ("",[],[]) (RowHeadColumns 0)
15+ []
16+ [Row ("",[],[])
18 [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
17 [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
19 [Plain [Str "col1",Space,Str "content"]]
18 [Plain [Str "col1",Space,Str "content"]]
20 ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
19 ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
@@ -22,4 +21,4 @@
22 ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
21 ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
23 [Plain [Str "col3",Space,Str "content"]]]])]
22 [Plain [Str "col3",Space,Str "content"]]]])]
24 (TableFoot ("",[],[])
23 (TableFoot ("",[],[])
25− [])]
24+ [])]
test/docx/table_captions_no_field.docxnew file

Binary file not shown.

test/docx/table_captions_no_field.nativenew file+34
@@ -0,0 +1,34 @@
1+[Para [Str "See",Space,Str "Table",Space,Str "5.1."]
2+,Para [Str "Table",Space,Str "5.1"]
3+,Table ("",[],[]) (Caption Nothing
4+ [])
5+ [(AlignDefault,ColWidth 0.7605739372523825)
6+ ,(AlignDefault,ColWidth 0.11971303137380876)
7+ ,(AlignDefault,ColWidth 0.11971303137380876)]
8+ (TableHead ("",[],[])
9+[Row ("",[],[])
10+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
11+ []
12+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
13+ [Plain [Str "Count"]]
14+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
15+ [Plain [Str "%"]]]])
16+ [(TableBody ("",[],[]) (RowHeadColumns 0)
17+ []
18+ [Row ("",[],[])
19+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
20+ [Plain [Str "First",Space,Str "option"]]
21+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
22+ [Plain [Str "242"]]
23+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
24+ [Plain [Str "45"]]]
25+,Row ("",[],[])
26+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
27+ [Plain [Str "Second",Space,Str "option"]]
28+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
29+ [Plain [Str "99"]]
30+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
31+ [Plain [Str "18"]]]])]
32+ (TableFoot ("",[],[])
33+ [])
34+,Header 2 ("section", [], []) []]
test/docx/table_captions_with_field.docxnew file

Binary file not shown.

test/docx/table_captions_with_field.nativenew file+54
@@ -0,0 +1,54 @@
1+[Para [Str "See",Space,Str "Table",Space,Str "1."]
2+,Para []
3+,Table ("",[],[]) (Caption Nothing
4+ [Para [Str "Table",Space,Str "1"]])
5+ [(AlignDefault,ColWidth 0.7605739372523825)
6+ ,(AlignDefault,ColWidth 0.11971303137380876)
7+ ,(AlignDefault,ColWidth 0.11971303137380876)]
8+ (TableHead ("",[],[])
9+[Row ("",[],[])
10+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
11+ []
12+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
13+ [Plain [Str "Count"]]
14+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
15+ [Plain [Str "%"]]]])
16+ [(TableBody ("",[],[]) (RowHeadColumns 0)
17+ []
18+ [Row ("",[],[])
19+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
20+ [Plain [Str "First",Space,Str "option"]]
21+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
22+ [Plain [Str "242"]]
23+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
24+ [Plain [Str "45"]]]
25+,Row ("",[],[])
26+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
27+ [Plain [Str "Second",Space,Str "option"]]
28+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
29+ [Plain [Str "99"]]
30+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
31+ [Plain [Str "18"]]]])]
32+ (TableFoot ("",[],[])
33+ [])
34+,Header 2 ("section", [], []) []
35+,Table ("",[],[]) (Caption Nothing
36+ [Para [Str "Table",Space,Str "2"]])
37+ [(AlignDefault,ColWidth 0.3332963620230701)
38+ ,(AlignDefault,ColWidth 0.3332963620230701)
39+ ,(AlignDefault,ColWidth 0.3334072759538598)]
40+ (TableHead ("",[],[])
41+ [Row ("",[],[])
42+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
43+ [Plain [Str "One"]]
44+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
45+ [Plain [Str "Two"]]
46+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
47+ [Plain [Str "Three"]]]])
48+ [(TableBody ("",[],[]) (RowHeadColumns 0)
49+ []
50+ [])]
51+ (TableFoot ("",[],[])
52+ [])
53+,Para []
54+,Para [Str "See",Space,Str "Table",Space,Str "2."]]
test/docx/table_header_rowspan.docxnew file

Binary file not shown.

test/docx/table_header_rowspan.nativenew file+189
@@ -0,0 +1,189 @@
1+[Table ("",[],[]) (Caption Nothing
2+ [])
3+ [(AlignDefault,ColWidth 0.30701754385964913)
4+ ,(AlignDefault,ColWidth 0.1364522417153996)
5+ ,(AlignDefault,ColWidth 0.10009746588693957)
6+ ,(AlignDefault,ColWidth 9.707602339181287e-2)
7+ ,(AlignDefault,ColWidth 7.719298245614035e-2)
8+ ,(AlignDefault,ColWidth 7.085769980506823e-2)
9+ ,(AlignDefault,ColWidth 7.09551656920078e-2)
10+ ,(AlignDefault,ColWidth 0.14035087719298245)]
11+ (TableHead ("",[],[])
12+[Row ("",[],[])
13+ [Cell ("",[],[]) AlignDefault (RowSpan 2) (ColSpan 1)
14+ [Plain [Str "A"]]
15+ ,Cell ("",[],[]) AlignDefault (RowSpan 2) (ColSpan 1)
16+ [Plain [Strong [Str "B"]]]
17+ ,Cell ("",[],[]) AlignDefault (RowSpan 2) (ColSpan 1)
18+ [Plain [Strong [Str "C"]]]
19+ ,Cell ("",[],[]) AlignDefault (RowSpan 2) (ColSpan 1)
20+ [Plain [Strong [Str "D"]]]
21+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 3)
22+ [Plain [Str "E"]]
23+ ,Cell ("",[],[]) AlignDefault (RowSpan 2) (ColSpan 1)
24+ [Plain [Str "F"]]]
25+,Row ("",[],[])
26+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
27+ [Plain [Strong [Str "G"]]]
28+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
29+ [Plain [Strong [Str "H"]]]
30+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
31+ [Plain [Strong [Str "I"]]]]])
32+ [(TableBody ("",[],[]) (RowHeadColumns 0)
33+ []
34+ [Row ("",[],[])
35+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
36+ [Plain [Str "1"]]
37+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
38+ [Plain [Str "2"]]
39+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
40+ [Plain [Str "3"]]
41+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
42+ [Plain [Str "4"]]
43+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
44+ [Plain [Str "5"]]
45+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
46+ [Plain [Str "6"]]
47+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
48+ [Plain [Str "7"]]
49+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
50+ [Plain [Str "8"]]]
51+ ,Row ("",[],[])
52+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
53+ [Plain [Str "1"]]
54+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
55+ [Plain [Str "2"]]
56+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
57+ [Plain [Str "3"]]
58+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
59+ [Plain [Str "4"]]
60+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
61+ [Plain [Str "5"]]
62+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
63+ [Plain [Str "6"]]
64+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
65+ [Plain [Str "7"]]
66+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
67+ [Plain [Str "8"]]]
68+ ,Row ("",[],[])
69+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
70+ [Plain [Str "1"]]
71+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
72+ [Plain [Str "2"]]
73+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
74+ [Plain [Str "3"]]
75+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
76+ [Plain [Str "4"]]
77+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
78+ [Plain [Str "5"]]
79+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
80+ [Plain [Str "6"]]
81+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
82+ [Plain [Str "7"]]
83+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
84+ [Plain [Str "8"]]]
85+ ,Row ("",[],[])
86+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
87+ [Plain [Str "1"]]
88+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
89+ [Plain [Str "2"]]
90+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
91+ [Plain [Str "3"]]
92+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
93+ [Plain [Str "4"]]
94+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
95+ [Plain [Str "5"]]
96+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
97+ [Plain [Str "6"]]
98+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
99+ [Plain [Str "7"]]
100+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
101+ [Plain [Str "8"]]]
102+ ,Row ("",[],[])
103+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
104+ [Plain [Str "1"]]
105+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
106+ [Plain [Str "2"]]
107+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
108+ [Plain [Str "3"]]
109+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
110+ [Plain [Str "4"]]
111+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
112+ [Plain [Str "5"]]
113+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
114+ [Plain [Str "6"]]
115+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
116+ [Plain [Str "7"]]
117+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
118+ [Plain [Str "8"]]]
119+ ,Row ("",[],[])
120+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
121+ [Plain [Str "1"]]
122+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
123+ [Plain [Str "2"]]
124+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
125+ [Plain [Str "3"]]
126+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
127+ [Plain [Str "4"]]
128+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
129+ [Plain [Str "5"]]
130+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
131+ [Plain [Str "6"]]
132+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
133+ [Plain [Str "7"]]
134+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
135+ [Plain [Str "8"]]]
136+ ,Row ("",[],[])
137+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
138+ [Plain [Str "1"]]
139+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
140+ [Plain [Str "2"]]
141+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
142+ [Plain [Str "3"]]
143+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
144+ [Plain [Str "4"]]
145+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
146+ [Plain [Str "5"]]
147+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
148+ [Plain [Str "6"]]
149+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
150+ [Plain [Str "7"]]
151+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
152+ [Plain [Str "8"]]]
153+ ,Row ("",[],[])
154+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
155+ [Plain [Str "1"]]
156+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
157+ [Plain [Str "2"]]
158+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
159+ [Plain [Str "3"]]
160+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
161+ [Plain [Str "4"]]
162+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
163+ [Plain [Str "5"]]
164+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
165+ [Plain [Str "6"]]
166+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
167+ [Plain [Str "7"]]
168+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
169+ [Plain [Str "8"]]]
170+ ,Row ("",[],[])
171+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
172+ [Plain [Str "1"]]
173+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
174+ [Plain [Str "2"]]
175+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
176+ [Plain [Str "3"]]
177+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
178+ [Plain [Str "4"]]
179+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
180+ [Plain [Str "5"]]
181+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
182+ [Plain [Str "6"]]
183+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
184+ [Plain [Str "7"]]
185+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
186+ [Plain [Str "8"]]]
187+ ])]
188+ (TableFoot ("",[],[])
189+ [])]
test/docx/table_one_header_row.docxnew file

Binary file not shown.

test/docx/table_one_header_row.nativenew file+18
@@ -0,0 +1,18 @@
1+[Table ("",[],[]) (Caption Nothing
2+ [])
3+ [(AlignDefault,ColWidth 0.33302433371958284)
4+ ,(AlignDefault,ColWidth 0.3332560834298957)
5+ ,(AlignDefault,ColWidth 0.33371958285052145)]
6+ (TableHead ("",[],[])
7+ [Row ("",[],[])
8+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
9+ [Plain [Str "One"]]
10+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
11+ [Plain [Str "Row"]]
12+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
13+ [Plain [Str "Table"]]]])
14+ [(TableBody ("",[],[]) (RowHeadColumns 0)
15+ []
16+ [])]
17+ (TableFoot ("",[],[])
18+ [])]
test/docx/table_one_row.docx

Binary file not shown.

test/docx/table_one_row.native+4−4
@@ -1,8 +1,8 @@
1[Table ("",[],[]) (Caption Nothing
1[Table ("",[],[]) (Caption Nothing
2 [])
2 [])
3− [(AlignDefault,ColWidthDefault)
3+ [(AlignDefault,ColWidth 0.3333333333333333)
4− ,(AlignDefault,ColWidthDefault)
4+ ,(AlignDefault,ColWidth 0.3333333333333333)
5− ,(AlignDefault,ColWidthDefault)]
5+ ,(AlignDefault,ColWidth 0.3333333333333333)]
6 (TableHead ("",[],[])
6 (TableHead ("",[],[])
7 [])
7 [])
8 [(TableBody ("",[],[]) (RowHeadColumns 0)
8 [(TableBody ("",[],[]) (RowHeadColumns 0)
@@ -15,4 +15,4 @@
15 ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
15 ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
16 [Plain [Str "Table"]]]])]
16 [Plain [Str "Table"]]]])]
17 (TableFoot ("",[],[])
17 (TableFoot ("",[],[])
18− [])]
18+ [])]
test/docx/table_variable_width.native+12−17
@@ -1,10 +1,11 @@
1[Table ("",[],[]) (Caption Nothing
1[Table ("",[],[]) (Caption Nothing
2 [])
2 [])
3− [(AlignDefault,ColWidthDefault)
3+ [(AlignDefault,ColWidth 2.0096205237840725e-2)
4− ,(AlignDefault,ColWidthDefault)
4+ ,(AlignDefault,ColWidth 1.9882415820416888e-2)
5− ,(AlignDefault,ColWidthDefault)
5+ ,(AlignDefault,ColWidth 0.22202030999465527)
6− ,(AlignDefault,ColWidthDefault)
6+ ,(AlignDefault,ColWidth 0.4761090326028862)
7− ,(AlignDefault,ColWidthDefault)]
7+ ,(AlignDefault,ColWidth 1.0689470871191876e-4)
8+ ,(AlignDefault,ColWidth 0.26178514163548905)]
8 (TableHead ("",[],[])
9 (TableHead ("",[],[])
9 [Row ("",[],[])
10 [Row ("",[],[])
10 [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
11 [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
@@ -13,33 +14,27 @@
13 []
14 []
14 ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
15 ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
15 [Plain [Str "h3"]]
16 [Plain [Str "h3"]]
16− ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
17+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 2)
17 [Plain [Str "h4"]]
18 [Plain [Str "h4"]]
18 ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
19 ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
19 [Plain [Str "h5"]]]])
20 [Plain [Str "h5"]]]])
20 [(TableBody ("",[],[]) (RowHeadColumns 0)
21 [(TableBody ("",[],[]) (RowHeadColumns 0)
21 []
22 []
22 [Row ("",[],[])
23 [Row ("",[],[])
23− [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
24+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 3)
24 [Plain [Str "c11"]]
25 [Plain [Str "c11"]]
25 ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
26 ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
26 []
27 []
27− ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
28+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 2)
28− []
29− ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
30− []
31− ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
32 []]
29 []]
33 ,Row ("",[],[])
30 ,Row ("",[],[])
34 [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
31 [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
35 []
32 []
36− ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
33+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 2)
37 [Plain [Str "c22"]]
34 [Plain [Str "c22"]]
38 ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
35 ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
39 [Plain [Str "c23"]]
36 [Plain [Str "c23"]]
40− ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
37+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 2)
41− []
42− ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
43 []]])]
38 []]])]
44 (TableFoot ("",[],[])
39 (TableFoot ("",[],[])
45− [])]
40+ [])]
test/docx/table_with_list_cell.native+3−3
@@ -1,7 +1,7 @@
1[Table ("",[],[]) (Caption Nothing
1[Table ("",[],[]) (Caption Nothing
2 [])
2 [])
3− [(AlignDefault,ColWidthDefault)
3+ [(AlignDefault,ColWidth 0.5)
4− ,(AlignDefault,ColWidthDefault)]
4+ ,(AlignDefault,ColWidth 0.5)]
5 (TableHead ("",[],[])
5 (TableHead ("",[],[])
6 [Row ("",[],[])
6 [Row ("",[],[])
7 [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
7 [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
@@ -22,4 +22,4 @@
22 ,[Para [Str "A"]]
22 ,[Para [Str "A"]]
23 ,[Para [Str "Numbered",Space,Str "list."]]]]]])]
23 ,[Para [Str "Numbered",Space,Str "list."]]]]]])]
24 (TableFoot ("",[],[])
24 (TableFoot ("",[],[])
25− [])]
25+ [])]
test/docx/tables-default-widths.nativenew file+92
@@ -0,0 +1,92 @@
1+[Header 2 ("a-table-with-and-without-a-header-row",[],[]) [Str "A",Space,Str "table,",Space,Str "with",Space,Str "and",Space,Str "without",Space,Str "a",Space,Str "header",Space,Str "row"]
2+,Table ("",[],[]) (Caption Nothing
3+ [])
4+ [(AlignDefault,ColWidthDefault)
5+ ,(AlignDefault,ColWidthDefault)
6+ ,(AlignDefault,ColWidthDefault)
7+ ,(AlignDefault,ColWidthDefault)]
8+ (TableHead ("",[],[])
9+ [Row ("",[],[])
10+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
11+ [Plain [Str "Name"]]
12+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
13+ [Plain [Str "Game"]]
14+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
15+ [Plain [Str "Fame"]]
16+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
17+ [Plain [Str "Blame"]]]])
18+ [(TableBody ("",[],[]) (RowHeadColumns 0)
19+ []
20+ [Row ("",[],[])
21+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
22+ [Plain [Str "Lebron",Space,Str "James"]]
23+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
24+ [Plain [Str "Basketball"]]
25+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
26+ [Plain [Str "Very",Space,Str "High"]]
27+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
28+ [Plain [Str "Leaving",Space,Str "Cleveland"]]]
29+ ,Row ("",[],[])
30+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
31+ [Plain [Str "Ryan",Space,Str "Braun"]]
32+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
33+ [Plain [Str "Baseball"]]
34+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
35+ [Plain [Str "Moderate"]]
36+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
37+ [Plain [Str "Steroids"]]]
38+ ,Row ("",[],[])
39+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
40+ [Plain [Str "Russell",Space,Str "Wilson"]]
41+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
42+ [Plain [Str "Football"]]
43+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
44+ [Plain [Str "High"]]
45+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
46+ [Plain [Str "Tacky",Space,Str "uniform"]]]])]
47+ (TableFoot ("",[],[])
48+ [])
49+,Table ("",[],[]) (Caption Nothing
50+ [])
51+ [(AlignDefault,ColWidthDefault)
52+ ,(AlignDefault,ColWidthDefault)]
53+ (TableHead ("",[],[])
54+ [])
55+ [(TableBody ("",[],[]) (RowHeadColumns 0)
56+ []
57+ [Row ("",[],[])
58+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
59+ [Plain [Str "Sinple"]]
60+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
61+ [Plain [Str "Table"]]]
62+ ,Row ("",[],[])
63+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
64+ [Plain [Str "Without"]]
65+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
66+ [Plain [Str "Header"]]]])]
67+ (TableFoot ("",[],[])
68+ [])
69+,Table ("",[],[]) (Caption Nothing
70+ [])
71+ [(AlignDefault,ColWidthDefault)
72+ ,(AlignDefault,ColWidthDefault)]
73+ (TableHead ("",[],[])
74+ [])
75+ [(TableBody ("",[],[]) (RowHeadColumns 0)
76+ []
77+ [Row ("",[],[])
78+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
79+ [Para [Str "Simple"]
80+ ,Para [Str "Multiparagraph"]]
81+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
82+ [Para [Str "Table"]
83+ ,Para [Str "Full"]]]
84+ ,Row ("",[],[])
85+ [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
86+ [Para [Str "Of"]
87+ ,Para [Str "Paragraphs"]]
88+ ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
89+ [Para [Str "In",Space,Str "each"]
90+ ,Para [Str "Cell."]]]])]
91+ (TableFoot ("",[],[])
92+ [])]
test/docx/tables.native+9−9
@@ -1,10 +1,10 @@
1[Header 2 ("a-table-with-and-without-a-header-row",[],[]) [Str "A",Space,Str "table,",Space,Str "with",Space,Str "and",Space,Str "without",Space,Str "a",Space,Str "header",Space,Str "row"]
1[Header 2 ("a-table-with-and-without-a-header-row",[],[]) [Str "A",Space,Str "table,",Space,Str "with",Space,Str "and",Space,Str "without",Space,Str "a",Space,Str "header",Space,Str "row"]
2,Table ("",[],[]) (Caption Nothing
2,Table ("",[],[]) (Caption Nothing
3 [])
3 [])
4− [(AlignDefault,ColWidthDefault)
4+ [(AlignDefault,ColWidth 0.25)
5− ,(AlignDefault,ColWidthDefault)
5+ ,(AlignDefault,ColWidth 0.25)
6− ,(AlignDefault,ColWidthDefault)
6+ ,(AlignDefault,ColWidth 0.25)
7− ,(AlignDefault,ColWidthDefault)]
7+ ,(AlignDefault,ColWidth 0.25)]
8 (TableHead ("",[],[])
8 (TableHead ("",[],[])
9 [Row ("",[],[])
9 [Row ("",[],[])
10 [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
10 [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
@@ -48,8 +48,8 @@
48 [])
48 [])
49,Table ("",[],[]) (Caption Nothing
49,Table ("",[],[]) (Caption Nothing
50 [])
50 [])
51− [(AlignDefault,ColWidthDefault)
51+ [(AlignDefault,ColWidth 0.5)
52− ,(AlignDefault,ColWidthDefault)]
52+ ,(AlignDefault,ColWidth 0.5)]
53 (TableHead ("",[],[])
53 (TableHead ("",[],[])
54 [])
54 [])
55 [(TableBody ("",[],[]) (RowHeadColumns 0)
55 [(TableBody ("",[],[]) (RowHeadColumns 0)
@@ -68,8 +68,8 @@
68 [])
68 [])
69,Table ("",[],[]) (Caption Nothing
69,Table ("",[],[]) (Caption Nothing
70 [])
70 [])
71− [(AlignDefault,ColWidthDefault)
71+ [(AlignDefault,ColWidth 0.5)
72− ,(AlignDefault,ColWidthDefault)]
72+ ,(AlignDefault,ColWidth 0.5)]
73 (TableHead ("",[],[])
73 (TableHead ("",[],[])
74 [])
74 [])
75 [(TableBody ("",[],[]) (RowHeadColumns 0)
75 [(TableBody ("",[],[]) (RowHeadColumns 0)
@@ -89,4 +89,4 @@
89 [Para [Str "In",Space,Str "each"]
89 [Para [Str "In",Space,Str "each"]
90 ,Para [Str "Cell."]]]])]
90 ,Para [Str "Cell."]]]])]
91 (TableFoot ("",[],[])
91 (TableFoot ("",[],[])
92− [])]
92+ [])]
test/epub/wasteland.epub

Binary file not shown.

test/fb2/images.fb2+1−1
@@ -1,2 +1,2 @@
1<?xml version="1.0" encoding="UTF-8"?>
1<?xml version="1.0" encoding="UTF-8"?>
2−<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><genre>unrecognised</genre></title-info><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><section><p>This example test if Pandoc correctly embeds images into FictionBook.</p><p>Small inline image: <image l:href="#image1" l:type="inlineImageType" alt="alt text a small PNG image" />.</p><p>Paragraph image:</p><image l:href="#image2" l:type="imageType" alt="alt text of a big JPEG image" title="image title text" /><p>alt text of a big missing image</p><p>A missing image inline: alt text of missing image.</p></section></body><binary id="image2" content-type="image/jpeg">/9j/4AAQSkZJRgABAQEASABIAAD/4QOoRXhpZgAATU0AKgAAAAgAFgD+AAQAAAABAAAAAQEPAAIAAAAUAAABFgEQAAIAAAAUAAABKgESAAMAAAABAAEAAAExAAIAAAAdAAABPgEyAAIAAAAUAAABXEdGAAkAAAABAAAAAkdJAAkAAAABAAAAKIdpAAQAAAABAAACXMYSAAEAAAAEAQEAAMYTAAEAAAAEAQEAAMYUAAIAAAAMAAABcMYhAAoAAAAJAAABfMYiAAoAAAAJAAABxMYnAAUAAAADAAACDMYoAAUAAAADAAACJMYqAAoAAAABAAACPMYrAAUAAAABAAACRMYsAAUAAAABAAACTMYuAAUAAAABAAACVMZaAAMAAAABABEAAMZbAAMAAAABABUAAAAAAABQRU5UQVggICAgICAgICAgICAgAFBFTlRBWCBLMjBEICAgICAgICAAZGFya3RhYmxlIDAuNy4xKzkxM35nYTA5MzllYQAAMjAxMTowMjowNiAwNzoyOToxNgBQRU5UQVggSzIwRAAAAZM/AAEAAP//NuAAAQAA///jlgABAAD//2viAAEAAAABh0EAAQAAAABNLwABAAD//+62AAEAAAAAKd8AAQAAAAFHQAABAAAAASNbAAEAAP//py8AAQAA///Z7gABAAD//4X3AAEAAAABWGsAAQAAAAAZVgABAAD//9qsAAEAAAAAUBMAAQAAAACr2QABAAAAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAEAAAABdAAAAQAAAAEAAAABAAAAAWX//4AAAAEAAAAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAVgpoABQAAAAEAAANegp0ABQAAAAEAAANmiCIAAwAAAAEAAQAAiCcAAwAAAAEAyAAAkAMAAgAAABQAAANukAQAAgAAABQAAAOCkgQACgAAAAEAAAOWkgcAAwAAAAEABQAAkgkAAwAAAAEAEAAAkgoABQAAAAEAAAOeoAEAAwAAAAEAAQAAohcAAwAAAAEAAgAApAEAAwAAAAEAAAAApAIAAwAAAAEAAQAApAMAAwAAAAEAAAAApAUAAwAAAAEAhwAApAYAAwAAAAEAAAAApAgAAwAAAAEAAAAApAkAAwAAAAEAAAAApAoAAwAAAAEAAAAApAwAAwAAAAEAAwAAAAAAAAAAAAEAAAAyAAAAHAAAAAoyMDExOjAyOjA2IDA3OjI5OjE2ADIwMTE6MDI6MDYgMDc6Mjk6MTYAAAAACgAAAAoAAP/iAxhJQ0NfUFJPRklMRQABAQAAAwhsY21zBCAAAG1udHJSR0IgWFlaIAfbAAIACgAWABAAGmFjc3BBUFBMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD21gABAAAAANMtbGNtcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADWRlc2MAAAEgAAAAUGNwcnQAAAFwAAAAgHd0cHQAAAHwAAAAFGNoYWQAAAIEAAAALHJYWVoAAAIwAAAAFGJYWVoAAAJEAAAAFGdYWVoAAAJYAAAAFHJUUkMAAAJsAAAAIGdUUkMAAAKMAAAAIGJUUkMAAAKsAAAAIGNocm0AAALMAAAAJGRtbmQAAALwAAAADWRtZGQAAAMAAAAABW1sdWMAAAAAAAAAAQAAAAxlblVTAAAANAAAABwAUgAAAEcAAABCAAAAIAAAAGIAAAB1AAAAaQAAAGwAAAB0AAAALQAAAGkAAABuAAAAAAAAbWx1YwAAAAAAAAABAAAADGVuVVMAAABkAAAAHABOAAAAbwAAACAAAABjAAAAbwAAAHAAAAB5AAAAcgAAAGkAAABnAAAAaAAAAHQAAAAsAAAAIAAAAHUAAABzAAAAZQAAACAAAABmAAAAcgAAAGUAAABlAAAAbAAAAHkAAAAAAABYWVogAAAAAAAA9tYAAQAAAADTLXNmMzIAAAAAAAEMSgAABeP///MqAAAHmwAA/Yf///ui///9owAAA9gAAMCUWFlaIAAAAAAAAG+UAAA47gAAA5BYWVogAAAAAAAAJJ0AAA+DAAC2vlhZWiAAAAAAAABipQAAt5AAABjecGFyYQAAAAAAAwAAAAJmZgAA8qcAAA1ZAAAT0AAACltwYXJhAAAAAAADAAAAAmZmAADypwAADVkAABPQAAAKW3BhcmEAAAAAAAMAAAACZmYAAPKnAAANWQAAE9AAAApbY2hybQAAAAAAAwAAAACj1wAAVHsAAEzNAACZmgAAJmYAAA9cKGR0IGludGVybmFsKQAAAHNSR0IAAAAA/9sAQwABAQEBAQEBAQEBAQEBAgIDAgICAgIEAwMCAwUEBQUFBAQEBQYHBgUFBwYEBAYJBgcICAgICAUGCQoJCAoHCAgI/9sAQwEBAQECAgIEAgIECAUEBQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI/8AAEQgBqQKAAwERAAIRAQMRAf/EAB8AAAEDBQEBAQAAAAAAAAAAAAMCBAgAAQUGBwkKC//EAFQQAAIBAwMCAwUFBQUFAwoCCwECAwQFEQAGBxIhCBMxFCJBUWEJFTJxgSORobHBFjNCctEkNFJi8BeC4QoYJUNTc5KywvE1Y4Oi0iZUZDZEhIWj/8QAHQEAAgMBAQEBAQAAAAAAAAAAAQIAAwQFBgcICf/EAEQRAAEDAgQEAwYEBQMDBAICAwEAAhEDIQQSMUEFIlFhEzJxBhSBkaHwQrHB0RUjUuHxBzNiJHKSFkOCojRTCLLCY+L/2gAMAwEAAhEDEQA/APstdMAYBGvaZl9gY610gKfiDqFyh0Suj1wdAPQSeg9sDTZ0UoIfj6aGZSEroXGMaGYqEqukfIamdAqukfLRBUVwo+mdEuQlW6BnOo5ygVigP56mdLN1foHx0MyEKwQfHTBycOsq6BjGiHKFUEHx1JCiuFAOpITKgoHpjU9EJVdPp8DqI5tlXSPTGjKit0D11M0KFW6fn30WvKRW6e2caBPRMNFbpPf/AKzohyhCSVyfgdSUQFfpwfTRzKQk4+HbUzJFWP01MyaEkJnAwM+mmzoR1TWkqIK6miq6aRZYXGVKnI9cEfoQR+mmJIMFAshGIAYKSOsjOPpqZ+igburlcH4Z0MyMFJI/XULoUhJ6RnONNmQhJ6PXvpsxUI3SShH11A5CLKxUkYI9dHOpEJJXIGc6mfooAd0hkPwBOi1yI7pJUjOiHqEJJBz27H8tHOmISCudTOEggWSSnft2GjnvdEgJJHx7euiHlQJBUYxqB+6m6Gy4+ujKASCv5HRzJtEgp2ONQFTdIKnv6Y0wejZIIyMdz+ujnUkpDLj6agegEMqPkM6bNsiEMr8vT56mcI6pBHzGiCgUIocakqQhMv076aUShlT31JSpBUdxjRzbowhlPl30Q5SEIrnUzKQhMpGmDghCEyE9sZ0A9EJDJ8x30cwUIQmQ57DOmlQITIO/bRLiigMgPqMaIcpKEyYyQO2mD+qiAy/IHvoZkShsnzAB0S9QlBK/D4fXT5+qhQmXPcAk6AepKCykg4zps6KC6egPcabOiCEBk7kgfu0Q5QCUFkxnGjmTaXQGX176YPlKTKAynHV302aNUSEArkjI0c/RAgILDue2nDksILKB37Y0Q9RAZcjP9NMH9VCDupxOpx6d9eAlVNch9B0C5WJXR+ulLkFboP002ZQFX6D20ZRV+jUkKEXVdHbuDj4HQDglVdGPj/DTAhMVXRqSgrFPqSdSZQ0VBPTPb56kpQOqv0DH11ApZV0DRlNFlYL2ORg6gKkjQKug4+B0Q5AC11fo7/TUzFPKt0evw1MyVV0Zz8NEORMJJXGpnSgXsq6To50wVdJ7dtTN1RA6q/QD6HQLlIScH5aIcorFcn0OdTMirFc59dTMgEhSjNIo7lTg/uz/AF0S7opCUUB+g0M6isU+XY/P5aOZRcupLhXbe3rJZKqjxZ7jIGjnSRmRKhkJXpjOfLV/LdT8DIo+L62kB9PNNx+X39JTkDVbTeb1TWmv22s08YFfO9FCoIzNK0ZdFUk47+W2qaTM0joJ/dANMFbHgHOMMM41XKVJJBPTkhsZH+uhKm0rHWyup7rRR1lKwePrkib4YdHKOD+TKw07xBui5pBgp+U+RzpQdksJPSf10ZUhW6Tj07ageoQkkA6MqQklPlol6kJJT9dMHKQkFPiR30cyBCSUB1A5EJBQ/PUDhohCSyYwMaaUoCGy/Eagcp6pJQ/nqSpF0PpGScd9EuUIvKQU+XbRzqJBU5xjRlGEMoPXRzIhJKfLvqNd1UF0IoP104dCMhIKEenfULlPRDK/MaIcpKGyY76YOUPVCKg5OO+pmMolDKn5Z0c6CGV7k9tEvRhIZMemdEuUQiuSc6OYKEITJjPy1A5EITIPUZ0wUQyvx9DqSpCEyfLuNQlSEMrnPbTZlIQSnzGpmU7IJU/LA0xchCCU+f8A0dEnojCEVwe4GofVSEFo/wAydNmQQmTHwxqByl0Jkz6jRBTAoLp69m0Q5QDdBZNNnUBQHQ9+300Q9MU3ZMfTRzpQdkB1z9dNm3TdkEpg57jTZrIFAZPoTohykoLR5+GRo5lB3TdlOPidOHjVMSpyMpI+WvArIzVC6D393RJVoSuj66TMpF1RQd/XGnlTdUE+edAlFX6Ae+dCVFcqDn5nRDkFbox8dGbKQq6BjGTqBxQBKro+uoCoSrdA0cxShXKdu2pnKOVW6PTUDkQqCflps6gKsE+fbQzo6q4T6/lqZ9woq6O2pn6Iqug6Oe6EQklDnsO2iHoZVXSRo5kysB9dQlBWx2z8NFRVooBYqOp6LjV0FQ0ahkSWEE4LqfdYD8mA9O/vD6aaOWU4FpTC03ACSa01c0k9bEVxIwXMyuSUPu9s4BHb/hPz07x+IJ3M3TG+VM1oS4XgStLQy0pUDq6EppEVmErkZJU9gSB2wM9snQZDuXdOy5DYuFmXraW2wWiKuqYUlqGSBGDHpkkK57E+oJ+J+Y+egbkxsqWNcRJWU6ckgEHHY/TSSgub8pbFi33toW2OpqrXe4KmGqttfTTLFNR1KOGRg7AjpLBQykdLdge3cacJiPCeHG43HVWMeQC0biFzXf7XvkDjm37p2hLctq1sVPFcY6KpeOBKmohPmiikUk+S6zRFBICMEFT1K51rY8UKpY+99Rex37yNt+xVmGa19iJmdvv6LJcZ8sLu+3W26S0F8+974sN3jtMlKqTWOklCokdSFJEbAr1N1HJZmUZ6OxxWBNM5ZENsTNidbf29So9oIDtBFup6/WV1uO4yy193daKrlp6VVhJj6WLydRLBVByTjobvj17Z1gDYAM6qoiAAtK2NPRTbj33bqD2wCgucxnjkaRQklQfNXCt2YYVsMD26iOxBA0VQRSY47j8tfzTV3XibwPyXUSpHy1lzKpUUPy0cyiTj9+jmRCSVHyGiUFYp+eoCpKQUPxwdQFRJ6c/DtoyokFB21FFboPw1JQSSp9NQFGEgqP8A7abMpCQUPwxqZuqEIbL8x21A9QhIKA+miHqRukFSM47/ANNM1ykJBUfLUzbKRdIKYxjTZghlQ2TBOjmUi6GUHwOhmKKQyeue+ma5RBZMZxnTZ1CUMp6g5zoB0KNQmXuB8NHOoSkFPTt202dFDKEdu502YKAoTJ2+OpmCEoTKfiPrqZjsmlDKZOc40c5COyEyDtnB00qIRQj8tNnRkITKT89EOvChiEJlwcYGjmQiUArj8tEOlEJDJ8+x0Q5BAZPUdtEOUIlCKn4DUlQtQmXPfuTokqbILL8xoyohMvx9fz0Q5RBZc+moHIi2qAyaaUCgMnx0Q5QSm7pgk4I0QUyCyHOO+mzdUEJk9cgnRzKEoDJgaOdQlAZCfodNmuopwlcjXgyZKqQipGhmKZWAzqSmjol9OfhjQlKkY02ZMG9UoIe2fTUzFSBsrhPnjGpmKUBK6RnONQOIUVujsR2zo5lFcqNHNKit0frqB6BCt0fqdQORVdH11C4qQrdB750Q5RV0H89EuQVivSCWIAHx1JRV+j8s+miSoFY9hkkAfM6kqSr9I+ulzIqxU/EaYGVDCrpOceh0QUEnpGM41JQgKinzGiHKELXb9bq2qSmqbXBRyXKncSwGaZkUN8VOFYYYZGcZB6T8NW0agBh2iYGAZXGNw3OOOS/bwtFXJR1FuqzRwRVLiNaSpkRYvLqgpbEDtMnSxGFdeoHB6jupsjLTdfMPpO3ex30K1U3yMpGn1i6cx72NFvXbNkNnu021qiCaioJkzKsssULtOlTHgCORQFXBOGLEDI9IaOZj3mJ1O0AkRH3+qRzRlAJh33+X3KjZ4gt03ba+zK2k2zdrYL9bqykqKCGVZatrlRR1YaGKFcftJBGXSSE+8ysjq2UZ9bMIMz2l03+F4v8AA2vte2y00WG8aQfhpJ/P5RF7Sf2zycI9mbfve7glBuy4mgqqyjAZlpzWuojEJwDLEnWqdYA/AxYKSQMVXCxUyMFhafQSZ6TcrKGZiSNAPv4/ei6XeKlJorlQiGOenWJWqWyCYkPqekj3jgEjHy+eM42E66Kpg07rz2tXJNsjpeWJKRabc/8AZjeX37FUQ1cK1c1TJ5TGJ6dsI83tCVFN1t2LjqxGVXXoJJFM9RliDpJ0IuBBn0B1W+ngHhzmPNnXnYCBr/4/ULeuMb7e6PdXKJ21T7u3NSV1ZBd6ZKuuhFFY4A0sclHGoVWjZK6GbrXplkPnZLAdlSqA6kwOIEW3kzEfDLMaC3Uqirlzw6dJ0+Pz0N+ogRZSlqr1BsW07kku8ktatHTSXSaRCWnqM5JRUUdyOjy1C5yAg7sTrkn+ZlFMdgPvrqe/ZV02Go4Rafp/j9yuacXXeppauTcd2ucMdmu9BNXSLPD5UtBMJ0lCSscA4SqlDEBQGQ9sHJ6GNY0NyAXbAtpERb5DXqlq5nvaG3bfa/btsRH1Ui4JEqIoZoyDHIoZTnsQRn+uuS61lWm1BWQ3CnFTB1eX1uncEEFWKn1/I6JBGqL25TCeY0JSkpPSPlokqaqxQamZGEgrjRBUKTgfTRzKSklQfhqZ1FYoMamcqJHTg49dHMokFQfhqFAobLjOPTTZkYSOkE5xoyiklAdQlBDKnvoyokED5DOpKMIZQ/DRzIJBHqCM6kqQhFPljUBRKQR8CNEOUQyo74I0c51QIQyuSQRogqQhlMH6aYOCkIZX17aMhSEgoPh21A9DRBKDOSNGUUIqfQDOmzFSEMrn46IKiEY/U/HRkqBCKH4aIcmQnT9+mDkQN0JlwfTRDrKRuglDkYxqAo9UJkHxGdMXKR0QWX1GpmspBQWU57aaVNUJk+WNQPMKeqAyfD002ZEBCZcflo5lIQWX0xoyiEEr39B9dGUMqCy+hPfQlDKITd1HcemmzIwglPn6aYuQhCKgep1A5SCEFkHppwUE3Zcj0xqSiApvMvu9gO2vDF0KtDK4GSNLJUVsD5ahdOicq4BPp30M0JSrAH4Dtoh2ybQqgPlpp6pi3qlBfoTqSkVyp+WNQOUVdB+R0ZUsq6DkD01JQVug/LUJUKrpPfUJUCsFJzgaMqBWxlimfexn+mpKib1kpgpamZfxIvUfTsPif0GT+mi2JTNbKx1+uMVus9wrxiaOLCN0nv3YKcfM9/TTU2y4BNTZJgrH2Hc9Nd6FZZg1NXrMKWenZSrxTB/LZWU5x74JHfuuD3zqypRLT21+Gv5KPZ00WUu1fDQ0ZqJCxiEkYJAzn9oo6fzOcAfHSUwSYCDWXhZVvdYqxGc4/XSAykDSqx3x6aOYoQqx8PTTFyirpycYzqZ1AE0pqqmrYPaKeRHjDMjEH8LKcEH6gjUJITOaQYWsTSXdK2tthnpah3V5oYiSJCvu9LI3pgNnKt8/xemrhlIn7+/uFY0DVcf3fcutmtu87PdaSarMMNtudHCjGRj78lNM464THmE+7IHjbrHYntrpYbl5qZkCZH5EaGb7Qe6cU81m2MfnZcK3byfPsCx7yum59o0lx2YtqpqnbNTArUSU1XIiI8M87jyYahQtH5ahwknSVViwKjoUMO6qfDa+HEw7e06gakXdNrbqhxbSLOWB2Pr1I0A6ydk4se2rXsyyis3ed48gcibGKva77uKVRLd7KMyVEtOUCQwq9OrIyRop66SLAKorBKmLJ8gDWvmQNibCdze+sQdlZ4T3ENz6X0H5R8JPe5W3VVRx9zBtG3RrfZaVprbHRCoo4eiopqmQdMUkZfICdLyHHSylVb1C9Qppuq0HEtFwZ7WuZjeQOn1V1RodfUGYOtjaIPXvutbr9wXb/s8rtz33dF0uG4IaqWkSvoa+OGO4vIvWY5xh4IllwpTq64oxlWPmHoNjHtDw1rQAbwQbRvMzbeL9LXQOGz1MhcWgaxHa0ESfTc3NlFu07tXatTu3kHatTZ+RrRuFNyUCU0spjWonpqh6wVFNMxePzVgqrqwL9DSRQxAq3UOnUB/JFIkgDKZ7aQR/4Wvcm8q+thmnEh0X0jWTAP0gibbbQsxw5vqpoOYJNsVu37gzihhqau9U9bVSia2VlZFVx3OveT9lHNLIktOyqG6MydZULovZFJ0RAOkDVocIG52M7xaZSV3seQ4G5mO85RpFgNpvp3Ui/EFu+43W87Jsu1ZLc9qorlbKu41E8yJAtUKmE01PCzNiSVTmZh0tjMIOWZVOHh1GJe+0yB10MnsALfPoSGp0AGkPFyJ+E76anTsL2IBY8r7Nv9qvdNcKzclTt+03qjvNHWSxU8S+05tkk4eaUq8kbO1M8RVAxeN16elhkW8PxDC4M1iCBJ/rb84mfUXtrW+tDC9oFj+hFtgANzN7qR+3a/7i27Z6Vq56u/Xu4TyxR1EhE87lcyEqT7gTA7L7oUIAPf7YKwzvyRZov/frM77+iqIDnGpsI9OwHwH5ldXtlugtdvo7bTdXs8MYjjBAHSuPQAdgPprHVrFzi46rNG6JTzw1SSvCWIWR4m6lIwynB9froOJGu6nZHK5yOx/pqZt1Ekp+7UzqSmtPMk6yAFTJGxSQA56GHr/r+R0S6LokEFFGGUMO4PcH56OZQFDXpbrAOek4YfI+v9dSVCqKkdyO2pKiSR6/A6JKBQynbt66JUSMH641CiAk4+mNSVEkpn0wNEGFEMqfiNGUUgoDnI1MykpBQg/TRDkYCQV+Y1CUIQinc4zjRzWUKGyZHy0cyOiQU+I1MyBQiCfjjTBEBDZcZ+WpKgCGRn10cyCGUP66kpkMgjtpg5CJQiuPTAGmL1MqGVB/PQLlIQ2XB0wdKEILKPgBqB15TNQmUemMabMgZQymO/ro5ijMoJQflo5kfRCKfMYOoHIygsuM9johykILL8v5aObdSEBk7nt30Q9GEJlP1A0S5SUEqcn1OjmUhBKY9NMHIlBZQcjt9dEOUQGXGRj6aYOUQHX4YOmzIwgsv6n5akqQgFDpid1AJQmXP56kpYQGXTByBFlNorgEj014WVUrY+nbUlRWwPz1EwV8dhoI5VWOx+WiCpoqx3+OjKJCrH7tBAq5Uj10Q4pVbRlEhXxpSUIVYPy7aM2UAVsEfAjRDioAr4+OO2pmKMStD3FuZNvyUd2njeW2wzSUtwkUkLTRsR0PjHvHq8texyBJ6fEaaNMulo1Onf7/AEVzKc8vVB3pfWsFPdaqoigqKNKeJ5YXl8oxqsg8yR3/AMKKmS3ywMkDJEw7QSP8o02ZgA3Urkt4vlxodvbYssNdVVFHdq6BKOtKtIqRtIwRWlDd2KlR1EscqjEOHI1qaWlxcRED9On30tCvDRmcTt8/v6arS7hzWtrtQ82Kvtty9qhs/tlxpWhpai4xpJ0TSSKMxIpjKOHVe7wgEZGbvd8x7XOtwLTv8td0zcOGv5rzGgJmTp0+K71brm122JJHQ11NXXRIizMYyvXL1GSMeWxypbCFQT3BUg4YE43hoqdB9z/dZ3NLXSR9+q3SW4otJS1sgdkE0C9lwcucHsT8nHb1/XtqrKJgKtonRZyNw3utlZAASp9RkZ/odVk2VZCX0gZ1GmVJVdH0yP46mYKErC1tDUo809D1SRyBRNCHIJwwy0eewYr1Aj/F27gjvY143RzLEVtWbrT3SW1VdFFWRIDA8jFDE4JDlxjqQd+nBHqPyOmAiA5O0CRZc6qa6rroLrtuppqy239I4ZUQt1w+xMOhqiB0XuqGBmCoSyO0fUvvAHZoBVHlv89YPrMfOE3LMG/7rld43ls+S2yTbut9z2/ba6gSz3p7Ksaw0zVTPC6yRHJk6usZEkWAGGR8daOZ0tbczadbDY7R2KuGCgDSG3g6GN/v81onAd2p+RONt5eH3llLpFyds2WKyVP37WwS1V8sbZprdfFaJinl1sNO6yAEBaiOeMke6TdxB0OGIpRlfMxoHalt+mo7HsslFzqVUMIu3QwRIG+n3EqLOxPEHtHghdn7c3pHvHe1BYCLFUvR2qGlqEvUHXSxU9SSkSSrLFRe0QMpfsfKLNJJGJd+NpOrtdVbaepkQRJI7jQ6fS1uHcQfBdadwDNjEECYmbSZPxCJfOaGoeWNvcTUlVvO68X7rs9vulfa4Nr1FHV7et1RRzzJFUSwhZkM06xwiAqpZJJXLgBSYMKXBxe3maSASRBIgQAbGBLtTECyvZWy+G5pAzWGtr3cTcDTKJF3G2hXNeVuJppdvbM3fwvdaDbnEm2N22S8v7ZY5DHdY+v2B6ny2WExU8Iq2qCz9Sz9IfowQZN2HdU8QNqWeZAHQG43idAALieulGIfTZhyLOAu686RIG/rrYEbFdcuVJyXx346tubF4otu171Bf9n3lLrT3mjehpNm1MEtBIK6iRJ2kq45JGQimWOJUkqyfNUTHHOwz6dTDudUJa0RcEEm5EaWsYkm4BsYVWOrOa+lmOYOJsJuAJJJIixG0m46gqXF62BLZ7XaKabeIuFXQXZax7DaaaCnStmZaj2h1Y+ZM9bUJJIxmLorsQvSgbAye/Nc/MG2IiSTYWtsA0WnU7yVspscQZAF5k66gg/DYAQFovLd6o948s+G7j/j+ONKK4NedyVtdDL1iz263UtNSgRB5F6pZDdI6fsQE81m6upOlruHy0ValS4AA9S51tjblnS+XoVkxbCGMafOXCJ2gEkkSDoYF7FwJClbY9oXiK9JuC81CGrjQRQyTOEeOIsMgRQN5ahiqnpJIX0+Jxzq+IZlLGb/AB+p/bp0vZ4gIA+/1P73+Gs0/JFTcbu+yrZJPXXuCVJ7lUPC0K2undWYGTAIEzDBEBw3fLdIIyzcMI8Rw5fnJ6D9ToO5Vr6IaM3XQddvl+e3VdSgvtuo6RKamgnZlqWpKaJpMvO2V/xHOCfMyS2CCGz6ay5S4z9j7hUmiZknun9Deqa43CppaZo5adURo5EcN1nv1enwHugHPc9X/CdA0yGhxSVKRbqswroxlGQChIIJ9PrquUmVaFUMDfLzbqIU6xVE8HtEUfaSpdoY+tmYY8sCMKev1Y4HyzsYZYCdp+An63OnxV4BADj01+cR92Wbt10iq7nX22BE8uliVXKuW6XDEdI/7vQfXIzg+ms+Uluc/f2bKt9OI7pVonWsrb3NG9U0aziHpcYEZRQCACAQSc/PtjTPGVone6FTYLNFO2kDiq0kr8xoSokdGjmUhJKkfA6mZRIKgZ7dvXT50Ugp8tEOCiQVI9QdTMFEMoPhogoykFSProgqIZUd/gdEORCGUI+GpKISCMjUa5CUIqR9dGUbQhlfp30Q4qAIZTHx0Q9QBDK5z66IciG7oRU/HtpsykIZUEknOpKMQhspBx31AVA1CZfkNSUcqGR9dNmtCmVBYY+WoSpG6GVB+miHIZUEr69tTMUwCEUx6HI0cyhQyvf0GdNnCWLIRXGM41M26bVBZcZOpnRhAZckY7HTZ0sbFBdSR3GDqByIQipGcjtpgUQgMvf46bMogso7k6AcoEBl9cY0+bdSJQWX4HOjnTEFBZT8Rpg7oiGoDL9e2iHKITIP10ZQATdlz8dEEoAKbRGR3HbXiS5ZlbHy7HQzKKxQaBcd00K/QB2xqZkXKukfLUzISqK+mRjRBTG+iuB27aJco4KsagKRVjGO2mzBGFWBqIwkgp1eWGXrxnpz3x+X6ahQITGvrYbesNRO5SAE+YfXpTH4seuAcenz1BfRO1s2TajvFPVzpSANFVBZWkjfCtGEcLkr8Ac5H0GnLDlzbKOZBWBv37CH2qlZDaK7KV7N0yRqrKVDkNnKd+lgBjBByMEF6XfUaffVM0TYrVL/AEtXaLVNcCovdJSQElZqfzJ6VekxqsyDPmw48wMSCUBLEMF6lvY8OdAsT8j6dD+fZBkAAO0+/wA1yvbVtse5uNL1snoXyqOrFx2+JJ4jLa4+oPSEyA4IUlAjg4kgliKkZONVeo5lQP3Ig636/wBxsQVaGnODPrHbXe4Xlty9v6svexOfKvlPan3DBaYLnPyBarbUeY0lVJb0poUBRcunu0dUlRGI0OJ0LZyB1mA0g1zDmP4ZtN5J/MXvpC6VJ2Z5psJaOtzEfqQQYH+ZlcRcm3y57R4y5YutDRxbMvVpiqaimjqvZkqameOGQRwxTEtPJIVwqu6lRTOMymYOcuMosBNIG409L9LCJv6jSCs4OYQ0GTF97D7077iF0bZ/J1GlbT8eWu90t9jtm5Lrbon6et5umV6gUkvUQRNFHJTh+xAHqq4JGTww7+YbS0ftPpP31d9GA4u1t8JAPz6KRcl9rNr3yrqrya6otNVNFTUkzBCkQLkJ8Qe6iXLHH4B8++UUw5kN13+/lZY8oeIbst3h3B5tDeJzBIs9FUmnlUggN+FhgkY/C65+R1nLLC9iFU2nzAdVi7PvCh3FYpLnZ2jrnhpo6kssqkM+TiMkE4YlHBB9D+7TPGXXSVbUw7mvDXWlZHbm7dv7rtBu9ku1vu1u62iMsEgZeoZBU/EMCGBBwQQR8NCtTcww4Qs7mmbfd4/MQtW3HbbZaLw98pbcKW5VwSlerplaf2tOkALWU47zIAvSHzlQB7y6vpVi5uUmR00j0Ox+7p2Mkei4Bfd9vQ2qr2atNuKx72VPa7KlTFUSQR1SKpNLT3IReVOis0fqeuVH6ChcEa6LcMZ8QRl3OlupG29ttdE1NwAzPudIFz/cnquccYVnKXI+1d0U1PxzS7c36N8Vn3jDuOthqae1vHIEneiMEjSiMH9oiyIuY50yq9Z1oqtosLDn5cu2t5127a7dkzalnl4k6RfKdIuRe1xbX5jCcteEGwbw3XtblFd+bY29y7bYaaOzNHtinFsiaOSab2OsKt7RLQysZ/OQOGGIpk6JYELW4TjIptyNaS0m5LrmwFhESLR8rgrPim1ql2ACBbWdRN+h6RFttRxOm21tvnHcHic2Fs3jraWwt3GzWqHkXZ9/kiqLZQ7gner6h5M8Xl1NJWU0fmpcKaSPzeqN8LI0sa63VXU2U3VHktDuVwBBLQB0OrTaCDuOhVVGoKk5pzEOEEyRMAdCAfqIMKHe59lczch/9qXgt3DuCm4erdsR1++rbva5U1yq7puG3RV/TJFFc1mp2nBjeOhq5pImMMC0pPtBljliudUptDcVdzRAyiIm5FoMSRMA3cSBEGUwIrkGk3krOGuaYFhazZgcokCGgE6gCWe0PGNxdyZxPHZr1Rbl3JQ7hWbYG39pQXxZL9fq+eHoFFFRySh0kRQzLJOEjhihmkldAj9OB+Dq589MDP5piwDZOYmD2JidgASRO8eCKRLnZWtFzEiTaALF0mbC53gCU38EaUW8ardXiC5atEdz5Tvlisdu3Bda9yKGO6mKOorIY6mWQI8FEBaaRQCAs61En4pcjbxd3hsbh6AhuYkdSLwYvdxLo/4gD1zYSnVc4VKr5c1sQNW7BsjSWjM6NXOJJIgCVFPyVDvHj+6X20JX7O49ttwvdklsctMjXGoqY6uSkBlWL9rFG0iOscODPKCC3vME1x3MDHtDyHPcG72E3joTGv4R6XHYp0z4jiASQbu001jsP6vlG/HPD5bLHunxNcqcnU8l4g4/jqJNh7DFOj08FJRUEUdRc6ql60Mb081yiqlRYB0xvQHGBIoGvEVXtw0uu5/OZ6TDAbzMEmTqHeq5rg51UgAQzl/+brv+UNad5Bnopkb35G2QbhFZbXuvdt8rpKY+3z2uGuurUFIzMhYRUULxlywKqDk9XwADMuTB4N7muLmAD4CTrEuNvhtedAb6QLG+I4gdJgXHW8wNx8N4WvUsV/s63e0cb8ZT2uzXQ0K0Uty6LBThlZllNYJmkrZZHIDHEMhlzhiPe1a9oJDq1QS0nTm6QGhoyiL7gD5KmniGuaXQXESN5J65iNNIN+wlbDs6mhs24LhDyNuinuFfTdNRBDA7Q0Kz1UqoVcMS81SXBReo9PSx6EGTjLUqhzYoCdr6wATbYCNTra5W2u5xbLGhoOvW287D0iTrJXRV35Rxci23ZEENJTK9DLJK/WVIZWCxQxoqlGIJkyOoFcL294aytoOdSdVN4/vefQLI6m1oAOpvHYRJ+oWZvV0lstPU7hoaRq1W8hq6np1UyzJ09KyJ1EAkAj3cjq6QMg+opjNFOesdJSsZJgrCbCuSXesu9wmo6eineaXz0aJVkE0Ajp2DHLZChVwQcEEEEg6trvd4YBMgaehJKavRa02m/X0+nVa1t/edBbN38s0csVVUz22sgNdDTwyO01VNCjxRxgjLyyJ0MFUBeklh8cX+CX0KZbuSBpsbk9huT6JarASL7T6AfcdZXR9oVdxqbbTtdpbOJ5IlmRaWpEpfqJLuRj0LN2wT2x8dZMQGgkN27fJLVaZmCtqjkjlDNG4cBmQ4+BBwR+8aqzWuq3NI1SiM/lpcyVI6Ox+emm6iQV9cjtoZuiKQVGMaYFBIKEfXRJUSSPgRqZpRSCo79u+pmUQuk6JKCQUHp30S6bpo3Q2XGfQ6bMjrZIKA49dAvKB6ofQfmNMXKITISfpqZ4TbIZX5d9HN1Q3uhFP36OZNskFD27Z1A5CbobLn6aaU0IRX17dtSUUIofpoz0UQiM9tQlFBKkeuNPmsohMnyxqB4RKEyn8jqSghMhH5aOZRDZcn0xoByKCynuD6acFQILKR+WpKIEoTKfUDUUgoLLn17HRBUhBZcYzjTBxRI2QSh+WjmQyoLLnvjvpsyEILLnUDk2VN2UEY0ZUI6ITJ9e2mLkxagMmASNHMla1BZMA/PRzlNFkBk7Z087IQVNkgHXilmLQBdWC/+OllLCrpz6aMogbquntgdtQlPlVdI1JQaCrlRjGNGU0FVj1zjUQcFWB8hqSUpar4B+GgjlVsA/DOjKGVNqmiiqkCuOiUAhJF7NGT8VPqNEORIharU7WuSyCW2bgmjjWCaJaepgWROp1UdXWvSyjK5I7g5PbVwrNiCE4qR5hMrhFztG89vV26hdy3szUqPBVyHot0cTQvBUeS/UxjlVUilKSiNCzHpYdTa6DHMc1uX++oIkfSRJ6p6dcZxbS5/wA/f7N75yltbbezLbums3ElfsWpb9kKSmcyW+VJQHiYx5KCOTrUqyk+oIPSc1Noue8tA5/znT5+q0MozP4YGp0jr+6fSXy/8X0Ox9t7pp933zc9XQSrMttphVBauNVbDtnzAGYdAd8Drx2GdFzW1HuNOIB3MW+gVNJ3is8V0AW6kaXvF/kB+SitzdLY9tX3a3K1kvHK2w7TYR0Xy11tsr4WtEdROrTVCARkNHAsTgw9RpvLlaWNRLBH19ag4EGnWAcToQReB66m1/NaDYmDQZUgGjldMmOtgB3+HZQ58btbsrdGx+CN58V8k0O46HkOReOtxVlgro7n7fSXONqqnaWp6wKcsKapWOcCI5VohG5lHRbRrPAfSeCAzmAIiI1/uL7dEjA1tTx3gcxygjeTlAbG41n6wsL4ZubLPujjvhvZc9t22vD229tUUN6u89TJU08qimjFNUUSiMxytPU0pRY8qFklVQwLdAj8O4Pe4znJsI1+xv023W+mGEBjIOonNpHmk9t9x8CuqcUcX8h0+87iu293UW47/VbgqNy1VuuNBNDb7pb4IaaNYpKqmUTJUzCZoQsgnPVHGp8zyD5dj6tEU7yMttiZJOxtAibRqTabx1eoSXQMpiIsYtJk73iTtadlN/kXelv3pctv09Vc5tjPbquiuDWuZ1N0k6WjnhZYGlEStHJA7Bm8zKrKAD7ynlYcCkSTzajtuDeJuCNI9UKdB3h8rZJ3/wAXv8B6rrdRuSk27tO8SXcW2lrK+pEUyR1DyqHZgghSUDqkZCRnA62DCTv1YFRGd4bT0H3MbfkIhUUWOe6Tt+X38tNlr1notqcQtydbbDSwUVrvc1ZcYqR38uFKvq6Kgr1HJLFzKY1yR0v6FtPVc+qxnUfkdP0HxTNaaj2lxnSfkPl+SJwralgsG6bfHXUtRZIN31qUqRRMn3iQIyyswLO/VIZlaSUlmaMfDOji3XYYvl+Qk/AegtukxNQl5MQYE/Lrv8NBouybqqaajsFdFUQrZa1q0PFH0YadVbqAjKHDMVGOxJXucdtYKZ5hNwqqIzExey0OuprfU2eWh3HQy7u25WVkdT5NxmWaC4DKhRVoECFSqiTLqyv7ue6lRpY9zXSyzh029Py6j5J2tBtO236f2/VRituztp8O773Pv3a9oprJxvcbyYL7UR3Gq8rYt1CJHLKyda9VBWJDSIHZxDSSxI4CxzMV7bcQ+vS8N5l8SLDmGsbwQZNhJBjVc11Q0nAOJLT1O99TrYWjrvuugy7hsdLvW1bPqts8s8qUlIsUFumt8LV9RbqxX6SlQRIlPCIRhjOzuVDsshUqvXTSoPfTdUAawm8mwjtNzOwAgxbor8TiXMYHF09QBvI2AmbzBjqFyvl+n5ts6bR5S4/8N254OfdtU09HSU9s3Dbq2Hd1sqZDUVFkukfnRBaepljd4qhDKaGpEboWQzRy3YV9J2ak+oCx0dRBAgOaSNR0MZhI1uMXE8NTd/1LHHM3TlPa1ie23raZjxzhyXZ+XducNcn26muEG4LHy5ta01m19y3CG0bh2hd7rPDa6qz10BMdSGlpat26kbEhgSoiMsbCVNGHwhpVRRtzNdcXBaA52YaixA9NDBsrfeKVWgajZMQbAgiCBGsAnNppcaysb4KuCLzvfkfdXio21vW0+ZtWW6ca7Y3DeKGKprd6rRX2qqbze2uMQjkK1U2LfE8iOUgpJWCssirocQxbKWFbRqBw8RrXEbNblhggzrd50nl3Vb8O2pjXQwHISL/1k30JEMbyCI5s/wAc59l1PX8v+Ebg7c9Gaap4Rkve46230FXWS091vV4F+uHnTVaANEKcTSqEiV+7p1YIMYWvibxRqSP93K0aWaMoFjrJveNDrMrdSxtMvqimLFzszv8A5GwBGkASZ7C2uO3/ALkn8Rt73h4WfDJxDtHbG9bVdFq75vimuEVBYtvXCOsiWpWkvlJHJUS32CRiRFDE7xSzwyVBTDRyX4JjmtGLxbyaUWEHmEGwbblIkEyGxmAJMRMfXoUCcLTl1UiY/puDLySQDo7KZLrSA0yurcu7C3NZeILHxpU7l2txdtuxyWX7u2lsa2zU8dNZ/N9lMZuEjNWPCSmS8C05kDsJM9UinOMXTrVzUIL3uJuSImJAyi3oCSBAhXcIwtZjGlvKGgyZzEmxJzECDckuyz33XZeM9ybIqKUbM21tuksO1qSGnYNW3v2esvEcFHl44yJ2naSKZ1jbzHAjRgMjKjVGMqOzGtUcCb2ABA5ovaAIvOpIVmHwx8NtRgdM63gZpJI9ZsAB1suoVF/t1daKf2S9S1N/lqWmtkxuDFIqbrWUSuQZRFGo6lMhwf8AhBBOMbCA7bKNdP7T1gfFaCx4JLm26RvEfP7K45d930lNyDuWuuL2Ox0dNYw9PLX1lWsy+ZIzeZO3R0ws6QoIogS4LOvuhio0spsFLLcmQLAEWFwL3IOp0tutIYTAmRrrE9CBEQOvoReJw+4ee4NjTcWVk1ZZbTapnuVJX3Rp4nWz0lMjsJ5TkpAonpY4HPYCWRwWynSB4JJe13SfU6CDvIJI6gCJmVU7DNdzbSAJ3mJJBvp8RuF0K8cmXe08Y2Xkex2KrqNvW2SkutXTrMrSewM6SVc0iMSoYRdcqgufL6gEDN7ogofzcjzfT6QAPiQDa99AgaTZc2ZJ3/LvEf3W78R7mt163dvC42ncVovWwrncKutthoFjZUEjxzRyOwBKpPFP1o3ZWVB37jNWIpllABwIcAJn4/lY/ErJXBMQLix3kwP1t6hB4kpG37unkXlKwV9urdoXS9imsNwpoGVVttLTx0zzxGQkSyTTQ1AWdQU9n8vyyoduqyu51Gk2jVF4kg2PNcC2gAhxFpOosElZzmk0z+GBrN9Tm00JgC8EdTKkpcJ7Zt201t2NNGsEUXV/s9OC8mSAqKEGWJJUAfHI/PXLl7zk1J/P71VNNmYgEwFex0lTSUXl18dLDcpXeqqEhPuiRzlsdgSAe2SMnHfUquBMN0FkpANxosuV7fHOdVyhCQQRnUCJYkEdsAnUlQBIKnRBRAlJIxoygWJGD/y6IcUSxIYd/XtqSpCRj17Y0Q5GAkdA7aOZANKERg9/XTSiWpLLnvoypHRCIx8MaEqABDK50ZUhDYAHOPpqSp2KGVz6flohyiGVI9RokowhFPU6hcQohFQfkdEvUhDK4Pro50UIqCc6OboohMuPUaOZGEJl+WNNKkITJ37jvoZkcqCwxjGjKKEUwO3fUmVIshEHuNQFTKhMPX0I+Ojm6JgBsgMuO+dNmlEDZCYZ+R1MyKCy4Pr30cykITLj00Q5RAcfHRDroZbIDKCM9gdNKkIDDOjmuiQglT6986OZSOiEy4+o0WuUhBZc/TRDuihCbuowf4aYOlGNlNhx2JGNeNL1lypAU+uM6WVIV+kj1A1Ad1I2Vun886IKZXC5+OhmUV+j176OZCFXR2GNQOgIwr9AOiHKK/SMdux1MyBCoLjPYaJeoQq6R8MDUzKQrFdQOUhaxeK2OB6gSpR1EUcfUAT1PGfiWjJ99cEY6fe9dWMBMIhuwUGfEFwHUchw0t246E/EO5Fr4LjX3K3tU0tLXSQnKi4W9SILhRszftOoRzMidKyID37WDxjo8OpzbCYkeh1B6C4B2lX03CmCWvI+RH166WhRe3TyLf7ZuThrYvL0W9tn3+mvdPZaS5WZWuljaOsjlcwQXZulpo5Gpo2SkrpIamGRafpSoKoT0Tg3NYajAC2J/pMjtFtbkAtN7hSljGlxBEPM2P4tvl6AHrbWXtsitm57RuO9WO4UVPvCJ5Hugr6FTcqSoRmWMvQVUcciq4VsskjqcZQufTn1KjgGB9mnSNL6wRb6fJNRxDc5awZoMHWO8wfpA+S8cftK+PYE4Lr5uFntzXyrulHIsdG0Ap4a2lu0OYqatJp5KOaqmd3ZKlJ4gx81YonkabXZwGIe6sKdfXvOhB1F7BtpBHQkiypxGGeMO+pQHygQRBN9+YACxE+i5vyTylS7wvvHe6PD/cn495ur7621Ny7HqlJbb/s1Kktv3JWw4eOGmFNIzCWEup80ilZmeWbULHuBFW1icwGoJILQdSZt1Ng6AIUwlX3dpayXCA3KSNbHSLD8RJkTcSSuweF7lva2xN37dt1LuCbkHdl3uF1aukr6Tzrq11AlWpniFPI0KJJVR3OnDTHDKYTGWLl9ZqlRxYRT5QANIiNQCYB0h2nWbBdd2ElsVzN+pF4uI0hvTYiZkgKZXK95445l2VJbt17NodwXNbVFW1NZDWGgqqBykk6Tw1cJV44agCPDNlJYVce80RAy4YPpkwYHcSNreo16gxYApjhMxADiCDsfgeulwdtfRYLjy8bjsu1au48pbnu29OLLrXUtVQ3v2VaG6We9QSR+TTXCnTy41AmFOwqWaOnkJmSYQq6ebfTw8v8A5YAeLwdIvJB7XtcixEnTNXxYcQwaRGYaRa3WTsBrotw5a8TvG+xt7RXDkDdtmsm+YVvFiqqWpqY/ZKCslSjq6yVUcdJp4qaoSXz2BaWJI0VQ7FTRToZqRZTkg5esmCQBAvJcIAA1NzCtZh25WPIAaCTBIEiDF56NzG8NEkqS3FklwsPEHF8e05bbRtQxyStQXCFKGorrhLU+dLDV/iWCVmecMvdkdHDFfexVjY8Uh4iwFrgACLdY+R2lYqQDy9x5sxmfWYgdIiPnC23lberbl4B3veq/bUtfUQ2SqrbhRB0Z6ONIpJI3BYxukxUoAyggnqGQPe1kFI06ljBkR3001EKzBU2+8tYDvr/iV5sUPic5WrKDj6+7V463Zu993BrRS0FVOLVX1FTFRSz9FcZ4wiTqADDWROyM8HS6Fz1Hsv4fzZHENOs3IFwNjcHca31hamCn4Yc6SBE6Te/aALzIhSo4csvPG4+Pq+33TZm2Zt5V01RTbneS+tT025K6JxBUtWxhJmipQuMLDKfP62jLCMt5gc+i2CX2GlpgbEaAk3sbAQb2jmVK1Nzs72Fpi4gbyQAdJFiTePW43PwnzXfg+73vg/lva1q2VcbruS6ybAudLXNU2u8WUTSNS2WnmcBoKyihToWhYBWp0R4DIElWOriLHVqTarHZsoGbqCfxHrM3d1sYtPH94YyqWE22noP206nUk3idl8slsulK8tdJLAI181Z0bBhKjPWAexxj0PYj9+vPsqlplbwXaN3Xz0/bA7js/wD2KbO8aux9lXTaPNnEW4rLXVF8q7NXU1BeLb7esf3dNUQxN7VTLUGjrYEmChJaYKjZlZH9Ngm1KZ8B7uV8iJBIJGsTYwTp6xYKivgxTYapgkXIBs4NMkG29xoddRK9A/Dfuja1Pxl4c+IOJTLYNqVWzaJhWSU0scFXQiiWQ3G2VUuPb2kZPMMkY6VaZWZlLBSOIsL6tTEVoIBsN4mACASQIgX17rRw/IygMrs7tjMyTJJ0A1Mx8xC89/BTT758QHh33FwjxAm4uOPDDZ99b52/dd2QVYtcu+qT+01wkgo9vTReZJT0RWojNXcQEf8AYmmpss8k8fSrmm008RiBL8jIaRNw0DM8WsIOVn4iZdDRfLhnmjWq0KMy2o8lwjlkyQ2fM+5BOjPNd5bl9HN18V3PifaFvtezq/ab23a1PFdrBaLPQCzx2egjeJbhJSNSZMiiBQskcimKUd2CPhhz6XEW162arJLjDi689LbX06bWWmnQp0qctYGtAjW83IzF3zkXJ1ub6Z4hYrFyLcK3duw7xd9j7i295kt23LJRzVtNS2tUDR2+NIvN9okqKZvaEiwYo1linkUyNHG9eANSmwF+h0A1LjE9IDTAJ1kFrdCRtIBHhEgyI1AABMkneDeBYujUASod7B35x1t6+827p3lLtTiPk662OFNzCru9NuO6XO4xO9KKuipeg1Iar9+Voj5RMUcD9ETYXXSrU3PoeHSMtzaMBDRI3IJHLG+aCbk3TB3hVm13tOUAklxAGUXBA7g2yxOgG5P4Qtu1G8OOtiXfkXaG5anjyigq7LYtzw7ZM0lyti03sxkjhkCC2xTCIx9flyyMrqFMIc9N2LfklwPM4A5S4WuCJve98oI0uTCWnjX1GhlJwgHUE3sbgARYdTF5AMyu9888M8ZWXiTe1Bwpuzd3HXJq09y3TTWaC4T28V0DSeVWs0QVJY6d0XyutWAVpIgBg65Da9bEPBqiRYTrE6dp3j1lW4QGgQ0Rl9ekEi86ehj5LSuLeFeMeS7nxrw7aqPf+4qrbApIuUZL5dauv9prqZStRbqiLz1iid5QWeMAo/SE6ZAszjqPrClnxRDQy4ZAFzoDJF4/MTYZQc9WpVNDw3VZeY0gDKTJ0kjMIm83kmSImfunfdstW8uMeBaE0FDSbvavNVHSO9LJZbZSxOtS+IlK/tVkgpoo26felkZSViOOHhafiZ6tTmFMT1BJiBruZJPQdSjWcaTQ5o5iYGn/AJXGjbablo3WM3fS2WTkHdnF+3Ky27U4p3Ftm3VW6K6MOlTAkTtRR2ynlXAiiqKaB1abr6olpisQLTB4tFAudT8SsC5zXSBHmLhJJG8EC34s0GGgyho1Bly2MOEgwWxFx/y5jB2iTeFJ202aZts0+3LdST0NJSUS0EVBTRR0tJRwBE8uFVj7riPpRYwT0Ad+wA1y69Yl5q1DJJkkmSTNz3vqVXSYykAymAGjQdtPvcq9Pcqq943HBS1lJt2lRa23PVrGYpR0gST9XXlVVPMC9YUdPU3YMDpnt8PlcbnXsOmmptMdh1VmQf7cX0+Ow+f19Fse2T97Tz7kW61lVTVESxU0EqRr0RKzHzMBQwD9SsAT+FYz6sdV1oYMkX316aeo37yNklU7DQdN/v7stxZPXAyNZs3VVNG6RjHwxpi5MEgoMdvXRDlCEjpPy1MyhSCudTMoksowMA6IcEUMjGiCpCGUH5aIKiQUIP01JUQyuTnONTPCiQUPwB0S5RDKg+udAFEoRUjGmBhSEgjOoHKFIKfLTeIpBQyAfqNDPdGDCEykE49NHMplKGQD8NTOoAhFceuNTOoGoTKDkgHOnndTL0QSo+OpmRCGVx6DRzJssIRUHuRnRDkwCCRnTEqFCZMdx6aBcgQgsvb6/wA9MHIgITL6jsfz0Qd1AIQGU+vfTAqAITgDB1JRhBYA4zoyiEEj1BGpMqQgsvr8tHMjCAy4B+OpKAagOvxA0Q5SEIqDo5k2VBZPj2xo5kC1BZcZOP8Aw0wcplQGXt29NEO6KbKamvHuMLKq0ocoq1C9SFWiHhRVqB4UVaGdRVpwVFWhKirUzKKtSVFWiCokO4jCkgnLBe3zJ1J2QJVGKNpFlaNGlAwrEAlfyPw0wcQoQtfu1WKi2yVdFLXxzQv1fsITI5IfpZCi9yDgg9PfGSPQaZkzCbL1i/VcV3FP/wBre395bZuqbdrrLJ1UF6sF8UlaWMqFeKoiYASQzIGdWbox1o6PkYG6nNFzXXB2I/Q9t/iCEuIw9IgMiR8L/wB9v0XlXtvjHxkbe25fePuOZeLuWbBZTXUdop79v6en3Jsi50jH2SGkuUkDLNEpdEehrDjySE9pmRgdd91bDF2Yuyl0SMhyuBFzA0P/ACG+jQqMVXfTcHCk57BJzAtLoJmI3BHprzOOiglzty7vXxick8e8BHhOs2tzltRqKr33bLzQex3bb89Ky0MULXFFnSvo6u4V1NNHNRiRPJidutC2rKOEfSzOc/8AlmSI8pm8gWPK0OmYvAWscQwtRjWRD3G4JggC99ruytETMzFjBOdfCT4mLftraHiE4X3VDcqjjcXKoodqVkNZWbmntTS1DvHBcKanhSbyDWTXOCmqY6hfNVVSRBJKjXUhTc4UnkgmNLASADcmQYGUkR1INlzMdiadGH0myQTOYeYDSQJBG4B00tNo7+FHxC+GykrOULr7NZdnUm4NrNuSzwWaGaho7zNZHo6e3Na6qnVYVqn9orKmpqmPVHUFneKONWcvi/FIAfd03kTBMh0jZrRDQAJj8RJhdDh4woqB9MwHAjUaC8iJzOJkwDEGMpiVKrcW97vsbbHh72DSrXbS33um5JvLc9ngiluVPX0vs1NTUtdSVa5zRU4jp1COuOinMoLKdYK7peS64aCAdLkkmZuCZO4IBA1C7FAhkhsFzoGUmSA0WDYtE66ySdtfRfjzf+z7zcaXiC18a2zkK5V9jenrrNT08U1uIqJiTLJNUytLAiJ7Ikqz/jjCKFbK6xtzkl+fKARzdCL6AQbzEXlXYxoYwVHkk6gSZI0ibbT0AXiXyP4d6/hrlvjSLe+4rzetmw74tGy937otxmnqNrVEd3kiigq5YVE8lJUolOsMXmEQuz9b9cdIT2WVRUOcSRBcBpPLt3G56aC7lxMVTJpNcQROlwYlwImxtERa9geUBexewqDm/j/jre23t88mbV5Z2JS3oXuwVF33BNFdLBY5KCeWRHqDTSrUUiEo0Mucx5PUSUZlxvp4ckOYC10EaEgmQBvIMkj07a9BniisTlsYvyjQ7+UbaC51JWo3fkjmBt/1PDvK/GWxPELapbM9XVtad7U9LS29CsKVArY5DEprEXzlChQSssrKg8pi1dGm0A1cO4Ng6lp6kiLO1tcbAbFTFVIA/lOg6AZbiIvmLYF+t5Cwv/azzBsywbOod9cScxbmskPIqXy4181PDuEUlolmy8slbRM61EaQz1CRwezK6p5ZZj5bE6hhA6plpuEhpbYxeDs68kxJmBe2izVMYxlE1XNLZiAW6XH9PKAL3Bup07Q5b2i162zT8V70423nZ62znb1vpbBcZDJFVUrKKd6nK+7LmWSHyikZwVYgojFefXpOcHNqAhwOYyIiZmL9BM9upvBSBcHk8hncHuYi0aTcmSBrZdg5BsWx9y7Ordnb8hbem17nSSwV9I8vlzTVq/tVqKdh/czxzBminQjyZY0kVl6ATjw1Z1OpnpcsaHoNL9iNeo2ukrYXxmFrhv8AL7+awPhu5ZuW8Nqbs4d33uU7i5R2RWSbN3DcZpR59466ZKm2XSTsMtXUEsc7Mo6PPSqUfgwL8fSY2o3EUxDH3A2BBhzfQHTeCFzcEwsc6kTLm3H/AGnT4jQ6QVFLx/cIw+Oq9UHg3t0iW+ktG363kTddXTVU6R0lxSGrotsUjmJlBd7i01wKn/1dsGRhwdaeEvGHpux77wQ1o6kw53yYI9XD0TYxxytwgmKpvtyNjNeNC4tA2OVw1C8xKXdHiJ3tyZwP4dPB1XUmwts86cTVPJF4uMdIqtwJb5CtLuNLEq+4ZKupZjBDmNKa4POygrJ0R92pTp56pxd20iM1/ONWNM/Im5y+i5VPHeBToik0F7nEMm+R7QMznQLgTIboTEyCQvpg4W47444U4d4z4s4qtFNtjjHbtlorNZKON8rS0ccSrEGb/E7dmZj3Z3Zj3Y68dxLGVa+IdVrGXk3/AGHpoOwXRwWCGHpCi2THXUncnudSuTc77k2DtSXcO795bVtiR7foKSQXSWOANJHV1UcBjWQlSo8wwI6yOkfTIGY9IOrcFUquApMfZxiJtMGNbfQnpddbD4ZgLXjzGeuw7dp/svCXwUcM7F5Bo91Q7Wt19p5rvf8Aed43DcLtuq7S7Io61rzU0ltt9ktsNVTx1aR0dFMYwojgJUAyn3Ydesq1Qyk11QDytjlbncSAXE5py3IuRIk2JkrC7E1m16ngl0ZzYOOVgaYAJAm9yQwk2/DIK9fuMPClw5S7ZgsVLuup3RTxU8UNRS0CwWSzUtRT+ZEv/o+3CGJ5UZXV/OknkLd3Y9KjXGx/GHudnyW2LpcTppmsB/2tAGymGwz6Dsw5ZuQLGdZJMvMzqXdI3XNuTadfD/vKy3amtVgo+F75Xxw71oq69VkFLa6qupGpqeuFLMxh9neaJYKkB2DdcbDuJCUpvdVaRPMAcpyzMHMRPWJy2BntC6dB7dW3dNzaYFpBsZJIEnQSblcR3byfUcgbF3JZJN8bF4c4921E0e4XF5NsutQPYEqUttBR9EYp40V6EVD95c1FRBEsLx+cNTKDWPD6hLqjiYBBcJzAZnG9g6QALHLJdBgvTID/AAsM0hoAGYRYXuJkBxbzc1mgizjpJ7hHjmq2tsm3cTcL8kSXqqpqdK++XeKmpWsdtq5hK0j0xgjWWonaR3kRBM7BFHmzAuGejGV2PdnrNLWCwknMQALQeUCIkwBewOixYcsokvewF75JAtdxJlxuYmReXGL9VhbRyNsrjznfeVPJvDa8q2LastTva5VEEa+wiGYSpNPK4jhidYaqBHRyip5yAFih1INTCl34S4ZQNyQWwNSZPqSWm1wrMThHPxFNwiS0gA2MS10jo0QTPQiTdE2NbeZuYd67y5Hs15sHE3Ge6ZLXJZqbdO2JqrcFXb6OCRaerNI80UFvDvPUzxQsHlRRBJIOtmRLXsp4VgpVZL2lxIaRAJABBdBJMAB0WuWg2lZaeN8aH0mNcwDLJLocJJJAsSCTAJs6J8pCmpSbFu9dtqj28/INVT2JYzE7WGjjpJalcnqzUyPO46yW6mQhmJb3hnXJOMYKni5JNtTYRpYBsgbA27FPUc4g2hx3uSD1vafUFZE7borXWUlPeb/f7/ZZo0g9kuckUsCyRsDGelI0BJz09JDDKp2GO6nGFxLqbQ12siZvrqT6/NMZc2AAPS1vvvp1WzU1dFJfr3b/ACVjMENPI8nb3+sOST8e3SPnn9NZTAph07n6QkLIAWSpp46qmgqomV4pEDqQcgg/I6XeCg4ahGK+uQRqAypAQimATnUzXhFIxj1GNFRWKjHoNCUIQiuNFFIKg+ujNoUQyh+GNQOUCTg/I6gdCMbobKcADGoHQZUAQyCPUamZFDZfiPXRzHRQi0oZHroFxRaEMqMghRoh0JwIQiPpqAoyksAdHOlhCIwe41A47poQig747aIcpCGy/MDUzIkILL+o04KkIZXOT8dQuvCkIRB9fTRBQAQmX5eujmRQSoI9BoyohFfodHMohMvxAGmzGJUhBZc/Dvo5lEFh8MdtRrpRCCy/DGRo5kYMoLJ8tPmUyoTL279tDMoL6ILLjt3xogokpu6+ucY0c6aAgsB3xohyMJuy/HT5roG6GwyPTUJRhBIwdGVEBgPTGNMHXUm11NFlPc68e5c1rtlQXP1+egSiXJfSPlnUlJmSCuPlqApw5JwflqSmkK/T2yNBDMq6fnkaMqZlXTpsxUDlfoOM6EoZ1QUnBx20cxCheFp9/wB1UG2o6m43Od4qCmTrrgsbSNBGchJcL38vPYt3x9MHVrWF1hqVZTYXGBusJvbfG3dt0NNe6+80lFbaS7xUlXN5yhQe4ZSfmCV7evy9RkMBNhurcPhalR2UC5H7LT75zztC227bt2db1TU9VXtRzrJROJLevkPIJ54zgrACEDP6L1AHB1a2i6SD06jrGvXp1VzcA8kj00m8/DpdaraOYEvO8ptu2qKJLlO6NTOatIvbadI5nlKU75eWRDGqsF9FdT1eoBawFpJOn7genz7rQ/BgUxUOn0k6XtG53WT3tR3G411DLfr9x1Zb1LAtIkJtE1VVSxsTgGUVMeV6sgJ3VfMbJOTrZRqUgMsOcPUAfVp+dlyhQq5s9Gw3J39LiPrPZRv2lx/vHZ+5dybz2jdeKN2VNTLBLf6SSy1lDXikSl9mgQsKioWonhNF05SMOQuVDZCttdUovAYS5ovHlMmZtZpAvuY9Fuq1n54c2x0hx06uBFydrjovM37QjeHJ8u+Ni+JzgPZFxqPEDxwsd92xNsu8TbiO/rP1QxXCx1NI9JiAyU1YrxSftHVkiDqehfK6nDsE/wAN1CoDkdY8uWNbzN4jQd4Os4MbhWsb4zNR1LRmAuYAkgkT6kDsVLmxeKXYW7fD9tnxDcM8mbY55L0Md1qIZKCmorpdqNGKvFLUNPCaKro3d40jeIeSUMQAWQtrnPYRUNB7C0AxrYT6gzmiTe/wW7BUjVIqsIaxwMXMzcwABfuIvqbr50fGbd9q8LbguW++CdtbNsvBNxrqnf20p2qo7pcdlzVTzUm46EqoWeCip6ynFYRFLLTxzywwyfsappV6lCv4jhmcMwgOA30LXdL6CYJ1GkHDUo+A05mmNQTLQNnC0wIMnpcEAOtL7hng/jvm+r4suW89zpuinoNzX62b8C1E8u2am4pSVdVTJZvIqICKaRKljVx5dVzSxIqKVd2di2MYagE25ZiTBAMzMQdNM1ySdFUKVapUaxjsjuUHLIgETqIEnQC4ZaASpe8RcI0vHO16KtsW56Hc236TY0lPVbXsVA9pFFWTQxxz1gVJhFCivEHVqlvOkaKWUTxRyxnWbHYhpLnEXmQXCbagabzo2wBggmV6fA0qtHw6bYDQYMG5NgdbkgAa72BsQuX0HLvJHiC27DwONtbH3VS7jltMd6sFiremShWpoFc+XVSpT0lNX0lXZp6mJU6pTMsbrJIEfOg0nYdwxGYyJhzrD53JBBiwiNhZc3EVKdbPTczLJExd0SQSQNO+cg79Suh8A86eJvlifdlk3DYdp8T7jsUXk7ytFTUwxT2mptlXHJUzm3KqsPbjO9R7PJKIlSqdyWikHVmxVGi3nc6QTaLgyIAnTlG9zYWlX8Pc4htPw5IETIknWbXgjSB6kajsnhEsNl5ZTkqep5h3dZuNNqVdTaqX+xASzUFxu8LTdUFTcYkLVLwRTR+U9OYhMs7rKXeHoAr12sa2q5mZ7ojNMAWuGzoTa9hFheUmML21fAw5a0gmYAc68ESSIHUm52JEL0KuPDUPFZguGyL1aLfZaq8UldcLrcaOne5mRmkbNVWLEvtgZ5Io1WYq/VgGQgLjmOx3iwxwNrAA27QJt9RCTD1nVB/M5nQb6ToNNoHRQU8XGz7RYa3aXivvu0qiwbxod/WCXc9xs9M3UdqyTSUdRcLk9Liaeighq5pD5oLUhR5E8tWJbo4InMMLMgh2ptmiQADuSALa73sFe2nSBqUxBbGmpuAZibAEmdo1MKTNBytsLc9Fvy67I5ipNv11vhmo7jT1FVR3Skoh0pLSTzUvniNqYwVXmJLDJEJ4QjB3UkjmxDYqN5ZFxY9DeNexBg7BbG03Pe3LckSJkaidLG9jrJXmz4tfEhQcBcgbE8S1Je5KKi2ffIdt7kq025cUtm5rP7TC3TJV1XlU0jwlpKmiYMz9clTArdFQ/mdjC0i8ZCCGu7t5TcTAlwkkB1ha5uBGLEmnTa6oLVA2TqQR0kWkaiXWMCLqbvgH5Tg3RuzxW+IJ7jtG+7W31yfXWqy7ttU7T2+5WmyUkFto5ErcBWV6hLoUkICuS5UsCCcWOa/3ahRJ0bmjeXuMW18oB63E6rG6hTrYms5o8uVg9A0F3UWc4gwYkHWCoR+E3cg4m+3o8UXA24L/AEFZtNuLqy67BpxStFSWelud5hvVypaeXBBiNVNVzA91BZ4xjo6dWurvq8LfUfqCwH0aHNH0IHWLrBiqGTHU6TAeZpcBqczoDp/8ZAHVeqG2fE7S724/tq8HbEk5goUq6qjnvs08lk2rTvHPKrM10qYwKxF6R7lvjqWkAz1opDGgcOLYq4l4pggETdxsNGC/pmyt7ldbE1Gmu+nTJc8G4bci4Fz5W7zJJBtkKjxzrYNkQ8UeI3mPxj0d68SvH1tt1TUUlrWmlpbDM1ErdFJbLQhPRWNWddNBVVctRUO7wtEU9BrbWfTNOjgW5ajiIm7+YgCToARBIYBAnMSgMOKgyV35WBpztb5csEuLjq8gCSJDZEADRdZ8B3hf3RwD4aOFtjck3KrvHKd6rqzeG8Vq5faJKevuFbLcp6JZpQZZUh86KjaQnLeQH9XA0nFsXT8cso3ZTAaD1LRGa2knmA9Fy+EGo6g+pVblLySBuATyg6CQ3tqTEL0IrrPTWmO5VVrssU1LUvJVV9PToqGaTpyZVVfxSsQM47k+9kkYPA8YmMx0sPvot7ABZeZ32gPiH4g4Wt3GH/adunal8s1zq3++7FW+dVSVtigp5bhLOtLTxzTGNmpFpyzoqYnYF+2NdPhdBznuLBoDFh5tGiTAmXSL7fFdHDz4ZBORptJtAM5u5gA6epXjzyXyFbuN+EvDPPyxZ7ts3kq02yn33yfX7rSS0XK63KSop6+LatHc5l8qvq5faJK6WIeY7rkt1CUI3qq2GLsWRTu1kNaG80uFi4gSQ1hgToCbXlcfhWOp1sKarYirLpJiKZmCSQ0Fz8uWJktbEABeldbyvuBuOaLnze1pt3hP4yqpKhbnWw1jT3zfMlTORGtks8SiWKSaGHohllp2uLeaOinUKJdcqphmMeKTj4tQgQyOgnndeBeXAOygeZ7bhb8HjvEa4UWljWmS4iGt2kWEkm4LgATYNqGx2Xwq+GWh5Jtlg3hy1xDsvaVosTpX2Ljkmlq6OjrXIqhW32ZOsVtTH56eTTDrhpnBmeSqq+qoTRj+LnD/AO0+X6ZxMACxDBA1i77W5WBrPNzsTQOIgPltF0kg+d8/1m0A2cWyS43qaNYz16hn82CJ6ajjMh95WDKY/eOS3WPUEjOfU4+evHk3WnL1RKyant1DLLhKeGNGIKqAqdicnHYDOgXSoxhJgLA1tfS1llmZpxJVRMqlYuoFZwewA9cEgj6gnTEw626sZTIN1zWiuNdet01FfLLcbba54ZKZaR6V1kmSGQB0Eh93yuvzf2vu9ShVUn1GjKGN6mx/Yn4bddVqeAGANiRv3I/P5xcrtqZaNCyopwOynsB9PprMSueAksVDBGOG6S3c/DQTQrFcEjv+7RkpZSCM6AMJgkFO3YnOjKkJBGM6OYowkFR2wBqZkQ1D6SfQfD9+oSVISGGfTH66gemIlDKHUDkIQyue3pqZk0IZTHx02YoZSUIrnOpmRBSCp7n4amdQBDK50Q5OEMp+78tTMlAQyB37DUlEhCZcfXRBTEJBUH10ZUKCV+GM6JKOVDZc99TNspkKEy/PuNNmRIQ2X699EOJRyoDKO50S5DKEIgE57jUDkIuhMgAOiHI5UFlzj5amdRrUFlB0cyOVAZfUfu0xdKmVBKgHGdSUQEJx+7RDlIQWAwck40Q5SEAjvqZ0YQWXv9NNmUCAVxnt21M6iEVznv30wcogMudWFwRhAde3f+GpnMqBTPIzryhIXIBVYwMDtoTupKvqEoKtSVFWpKirRUVEZ1FFWooq1FEKWaOEBpGCgnGpKIC57cbnZ9xXi5bLuVJWRyyU8nRJ5TxjpBxlZlIPvAkjB/wtn5GxjoAd9/JaRScxoqtKiTvHZlfW025tvbVmtO4JrZdXr6vbVQ4C1srdDeY8jYg8uZMYil6AGCdMiAd99DENBDnmJETsNfjI7T3BXUFRwhxFjBne2wGvZecnIdw3PQXa/wDKCWfkOz8R0FZDdBtW6Weqq4KhWBL+TRwiaeh646h4ulRNBP2lEkTZLdSnQIAykZzaQQCY63AMRqII0IhM7iTXEUSCSBcwbXIkmLzeWkXJETZce8P1dYuMfFFyRyRuHZfJXFtXV5vW3rJWUjz5tNXSpTtSu4zTuXlENT5yuYGcuA6tISa69N5plpg9SCImQdR00uJ3hWCvTqAMa6RaAZGkjym4JOg6yB0XpON68q3Tm3b2xaC6bZNptG3I79uKZ6iUVdJa5x/skVQvS6TFpmlVZFdWMdJ1NhmGsxoUvDc+8gwO5+m1z6wgK1JjGtyznNriwGpE31EbyT2Ut+P7fBfbDSVO7rtUzXq5KzzmmuJkiozCqfgR4x5LGSUnBBbpEZJPYDNWcASGDTtBv8e3zlYMS5zakssBp3/cd1naug31DBe4du3y1brmhSmpaP7xLUFVTxt0lmjqY0ZfMUpE/U0WGZFDdIGdRjqZjMSAbncSNJEgxc7yO6yVC2RmZe8xpfsdfSQvAjxibf5t8AnI26PEFwb4cbPyj4U92XF63m/YlJafNS31wX9tuOzwvIq07SpIxqhG3s8z08UjOjmV19Bha5xDAzPD2jlMiSOh6xtN76G05cRSo0aorsZmaSZBEkTHMJECdxpFwoML4LuJfGVbPCpzptO6WCl29vCx7qlrKfbURtMzLT09tqYKB0pRIjVeZR7Y6BuhlljWNhB1S7BWhrvEBdGXW+riO1hEDQnUkSANjnsxRD6PIy9hAhpadROriJgyBpBkrzn5t8JXLvhE5q4t2NwzScw7+493ZvCams2y4aqejrpWgR2ktsNRVU0CymogWVAGQSjEXusSua2hlQh1QwRrMfOxdEHaYPzXOqtxOAAdROZrjYNOYgkX1DQZ62O69Y/Bb4v+VLxsqwb43rwvztvTwR2S011ugq7XZ6hXqam118scibuipUnZQ8lQka0jGWOSSmD1LLEVcGlhqhe4jKKh0ki0iBlkiTYmQBlnlBK0HidBzWtJc2XHnDTmLhd03JaA20zLoImJXrrcOYdjbn3HxRtzbnCV55L2HuPZNferbZ7ZZqK8UcVfTOlLAtBVUk0lFDEJLhUsZlmRKd+o9SAtjnMpYjnOcBwIBJdETM5s0HRuhBLhFittOrh2DKZbFwQCLDKQAADLrgQNBqVCPYFikj5R8XXJG2OPfJ3NZH2ttKGybqpaqOvsN3TatKa+tqIoVLTRoXVorgvmvUrEghleMBj0OIVMrGNpugPLjI0yl1gL2n+m0TLoWvhdcvrvfUvAE31MugOkGbQCbgCQAdFIDw4eK2Cw7q37w9W8PbzpaS7XOroKuhhjobhZLXdYrZbwsdXXGRhTvUxoalxNEmHDu/v9WufjPErhtUOgjQ3FszpgRfLpYkdNVaOGUc5DxEwTIMmw1iNZtMGLQF3e0ty3um8VUlw2zyBv3iukv9HW7et9Ikdvr6ieGHIuklRU1RFbbYJcCKCSJJZcR1HvqsUeoMlK8gVLiTsOkC4e4SNSGi1nSQ+Kc3yGAwCHQM03nKLAEaSethI1x28fF5xlt7ctqfm+t3XtpZ9w23aVvt+5Ns1NoFTU+3RNNOvWjRilaaeJGlaaQfsekg5IdKeDqwPCZIubEOjlIFx8SBAuR0shfRFMlr8siZkg3iBeCTFtALkqA/je8MtRxJxDcPFJ4X7htjcvGa3E3Xf+yLZaI7laY6Y1bvNW2aGIxRy0bvTJNV2iRjTyGJ5qdIZg6y9DCcWbXIoVXFpEQ4mLx+KZhwk5XASJgyNOT7g7DVy9lOWkGBcuAgSBu6dDpbSN5b3GLivmLhvk/b+4tkbQrPDvvrajmj3LTX6Or2vumskpnX2un6kf9vGqR1AecQlHiIRpTEGGF5ezmzXadIOYCbz0G03JnvftUTTq5GEklwkgwRBiADO/9ItEWGigD4K7nb/BjtDf3gE5e39ZZtv7BuVJv7al7v0sVopN1bLrkarp3xPIkSGCuSop5nVpFBnT1HTjfjqrXOZXYCDJb1IcLDSSbG0QTHdYvZ7C1KTamFzZoEiP6Sb30kHWbC211x7d+56TxefabeLzetPHyttzi+g4P29bI7HDZ5bVcuQLfJcW9jiYKfaqO3VLuJHj6EqaqFVgVF9oAeYCg6lhXNqAOeKgtIcAY1I0LmiYbMBxl1mmENWcfRbh35WimZdcSMxJyG1ibeJEZcxbs5e/3Btk46tPHvF3FVntO4ty7ModqUEdJX1ErwQQU8cYhSkqlHlxrI3SyhPwRtE4ypRBrjcQrVJq1DAdO+/cHW0TO891to03NZTDLA2gDQa6baxAE7HefN+n39yh4nrh9mlsK+S3+j2Fdt0UG7mtUrPF97rtyNK+43O5lnaSupZaye1UNN1ARNJ7RVHrzTMO9QoU8NVq1hGZjSf+0OGRgAtBMl53DQABJcsHEaoe19KiTzOyuN7w4ucAYiGNbBDfM90Ew2D9B1PvC3xVMtjr6inG46eCN5Ih6ydfmKpjHqwYxeg9Opc68bfLmHlH+Upw7iM40J+5+aiPdfF5Lve/b4438MW2rbzJyBbqgxVt8r6/2LZ+2pSD0w1l1RZDVVa9JZrfSJJMoPTK9P8AiHVo8KcaIr13eHTIsYlzv+xtpH/IwzudEmJ/lVBTIzPtLBZw08xginM2zS+IIpkEFeA32h20OZ9geHWz3XcPI/DNh3jNaawbgusm3a97lvjc94np6GkjZKyR4qeSWSAxqsPX7HSBuiIRque7hXsrYinRpZgJY1rbQIOYkxePxPNi42m4WjEUH0aFXEVAHPAcXEmwGUtDWiBaXZWNcTzHNrJU1Lfx9tvw1793ZYd+bu2t4pfF9utaSO5bTsNrqRuC83euCyVdJbPOqJILPYY4xSIaypijj6Ij50nWFTWili24lpo4NpZTYbkkBsAk5qhABkkkhgJP9Iddcyo6qyi3GcSa245QJe1sQwCmw+cgCCRFyC4tbcdeunhZuNdW2Pkjnm2Vke9FimWl2/aFaLbWwrVUq0MtksksPQXqXWGKGW6dpp1bDJTwdMesv8TYwkUDmG7neZxF/KZhgNwzsJLnLfgS+pyvgAeVo1bsHF1pfBNx5JIpxcmWlsuVDtrYdNu6y2mtt+2qid6fymrpYIRHJLKsDBWK+fPMFGBMgReuJRhQpPHrvJPhvPN1gHvH/EDci5v6LqUKYe/JOmka2sfgNAAfXqpXW6W81Nism5aGaqjiCq5pnj63npeggBu4w5OWDZxhh2A9MLyGvIcuYQ3yfXv+y1fcnI9hkv8At2lW6W+osElNFWVucMhhkmEUIZgcL+3Vsk9sRupGe+mw9N0kmxFh6wT+X5hX08MTTIA5r73ga/RNd/3OtsAod6q8dRtIXYLeEasSEQ04c9NQ7kH3FaPJAww6vUgFdJRLYibxI9Y0jqdtvzQogumnF9P33Hx7Cy5nxNyBSbuh2lUxXG9UlxltlLJWUlbEGW3VVbUSyrBIyAKkpSNm8tjkdS9h+HWutQDJsIsPWGyYnWJ1GiuxDTLiNDJ9QLT6fp2upAHf1htVNb4K+dKdvLnWRi46IvJdYypYnJY9QKr6sAcfDWBzCbi4t8Z6fqszMM57iAPvr/dIW/CoqJJpJAAVZI0Vj0O8rgRqTjBKp0scHJ6sgHGdPki2/wBk/fqpk2/zYfqV0JVcRqHcSPjuwGOo/PGqS/os4b1SSnYY/jo51AxJKkflqZ+qYN6JBGfTGjmQyoZXtkeupm6KZUjGoTGqgCQVH5aGZNCGRkeh0Q5SENlz6DUzIoZGDo5ggENlz6aOZFDKnt276k9FEgrnRlRCIx2OpKiGVBydEORQiPX1GjmRIQSpGNHOpEpBAIxoZk0dUJlIznTBwTyhOvx+OmBUF0Ij0BGoChCCVxjtnQzJkMjscabMogFQe2pmhRCYEds6gKkIDr+ZGoCogso7nvps2yMdUEj4Htoh6mVBK4PcEaJeoUNlyfX/AMNTMgE2ZPjnvpsyMIDLnJzoyiWoJBz3OmBKWENlPc47amZEoLj89EPUiEBlyNO110VMrXlJ6riqtTMoq0CVFWoCoq0cyirRzqKtDMoq0Q9RVpi6FFjbrbY7pSNTtUT0kgIeOaIgNC49GGexx8j2Px0ucbp2PymQoX8x8ZbvvDWK/bH39cNhV1srzWLWyMnsfkufNEbnpPTCzLHkyZUK7FR+LXRp4ikRD2z6Tt97brp0MS4jISbjaDOxsdx/lRZ3jScl2+dmt3O+3IjdbjU3WvnprdHDDUQzoUQQ1JdljghdpveTMiRnKu/QAIxtMmADAteddTYXk9NNrLuuqlzi1rAHACBqQB66zuTPoov8b8fx88Wem31uHkvek9n2b97UVsuO1t/1tfVzRKXgNaFZOilo36SiwlY5qrqhEq/s1RuzUqigPDawHNEgtjuATeXdrhtzrpie19QtHkdMgy2JvIbHmEyS6YtaASTyvjrw08/00dx2/Dy3yrxJxsm4XvUPIN3s9LXWxKaoZ2ntl0tNXDNT0rFoaeV4S5pBJTRSGZJD5I0UfDdztbmnYO5pGhBB5rSJAnYA6rnY93guays8Z4J05SJuADlI2tM6kGDBtvrZfjz8Gt92rum9bB2p4quCK6ul2vb71s66NDdobM9vimSrrIJI5JTCtTSSVS09LU1EeEnjhgQezhYwUK5JpOyu1LXDQzFjoTBgkgHc7rGzipY7JWYXaXb3uZaYygHpNjroFIjibxoW/eF6u/HXG/F3L9p5MpJTIl0o7zaLo9VTsoboloqmsp6iUBfPMjvEirGIZIyQ8esFTAmS15b6cwj45YHbWSYO66tWuKsv8zQNwCJ3jK5xnSR0kyu58f8AjkuWx9lRU3iV25eOGrzb5pkuFdvKgq7Vb9xqk7wq1Bcpo1plqmCjriaTo6ukQs6uGWmvwmpmmlzN2yw6JG4BJi+vzWem+lVguIDyNNI/8svwGvVTYsF8pNxU1+r7hb5aulaCqjmsW4YBTSGkZx58ohmUxVsTKY0LpmP3mVZH6yDl8NwjLra4uO0EafG/YKqpldlpdb29PgQvACLgyt+yS8T1n5WsdUm8vs9NyXi4WvatCblPSUXCG671UUazPUQ95GttX7AKRHiHTTPMgkHvl39KMacZh3MP+5bMIBJDZNh1kyZI6hcNmF92r5Yik6+1nRlEu/pvA13la94+7rvzdXhbbxUW7imv29VbG3zR8w1F6So+57nDcqSRKSrjmhYzzp00c3moJGgLGjOQQxzVg8rX+CXC4yRrY+gi51ubFd/ixApElp5YcBtyRpMEixvluRHVc/Xkk+AnfXJfNFJttr34SeQbhZN4W63W+8xqNl3KqanofvydHVfbKKujDTecqeZRzVUUzowmaVFdSFZjaYtUFtOt8oOxAgX2BAOxlKrUo1nVwZov1IveIzGDGVzrmDeNIUmfF1sPeNl8V3Hm6fCrynt/wpeKWagmmt71ElLUWLcgNuFU9Dd6aNWhrWlkbs4iNWzZYOIwCKaGKDsM73g52je9gCBynoL6nKN+isxOCzhjKTS2bA6B0k2Im1wLtudAvP3f29vFRHa99eMfifdm1ucueqSpsdZuizV0b2bcd2sQp/KktaWON2o7zZom8yahuEcYlEVRI8TSJJNBrfVbQpsZQJLWyYm8aGc0S1xGrSNgDFisWXFNq1K9OkCQIcGyAIJkQZk6uzBwMzrF54+CG6yeJDa1p3/tfcvKuxOB77uO6TzXe7WqC4XO910nn0dbb4vMVoaG1+UtNHNHLE0rzI5WOGN1aSkkUGBzmjMG6AxacwJNzOa4AIHUk2GltX3kF1B0HMDcQJADYaLTAkZjoRYauXsDab/Lxlbafb9lvu+eZ9u0lI9JQV9XQUntvtQgWpWoq69TGskcat5RKw9YwFIcjpPJxL2vJq5Qyds1oFjAuZJ6nW+8q/C4J5ptZUIzE3MHcwBAs22gECIUZvFtvDbNr4Q2fc7bdk3ZR7uudsFvpqKrM9uv1YGNT7QJoiJCnTQ18riIO0TwRe6oKsLcNSLcVliInUXaNNN4BGsAybqyg41aLgdWxPrIOWRYToDuJtaFA3nTw2Hb0VBwDuo2d7xdNy00dtvW38WOqu1kInr6iZ6aieDqqI4YrhElKxkGWSYNUBuhdTMW10FskAEkOvEWiTOstEiANIGq2YWmchqkEOmOUkNuY0kCGiS4kEm8wAsX4ZYN9+HrbfOOxOQLtt/k7w43C1U+5t0batLSuKawSJGKnclHFTsvQaOeWOmvtqhjTzQxrolLyyQzb30aWIaL/wAwGAT12aZvBv4bjYEBukEeXqVKuBr08zTlM6RvuBEAkai4vNpgx28SdVwduzmj7Mvd11ue09yWfaa8g7FoatLv7VUV1ZbbHDNSiKvmSfzZjV1tHLSlVmDOwYZMmVuw7HltU0pzVGhwAGknKbCOjg7QATMCU+JYx76FOsQclTmJgghzXPuDAIgMN5kwI0BX4TNj+Irjr7YxrVv3iyz8X8s714CpbzRWm3VUVPZZ6m3yQwe1+ZIsrtJBGJY+pVabzw7hgrK4pfVY3DVQ58tzC/QGZAAiAdNQMpvuDRisXSOPpOqyGuZlIN8zmmWgkGLSC7USIjLC9ceN6em5Km37cZbpyLY+DHt1yvN/3PUu4uG9LashlmS2QxuTQWjDApWnNVVpUS+zdCP7Q2HFPZh6ZzsBIiG9D1ed3dGCBAGe3KfSVsTWqVG06Lg05omwAOkMtDjrmceVhs0EgFvm5R+I3ZfH3jUruOdtcd8wcp7r2VxpsuybUtW2dv117FntU8dffamhUjpgociewwCOqmjEcNDGGLLH23ZK1WnUIAzFzsxJaAS1rWAkkx5s5kA3NhdcoVcJhsQykXkU8ssABJIe++gJILWtEyJEQRqpY2r/AM47xO+JnaVy542/suj4YlgjpKvjvau4amWz000TIy1G57lCkTXGeL2iQtQ0+KSQMGLTxxiR8VMUMK1zmODnC+Yt018jXa6QHOuNYaSAuo5tZ9EM56QOwLfEMkWLhPhzplHcFzrx6ZcLwW2xcb7G2VYv7GbYtkdmeWkoLba1tlq9jTLvFCIQRTI3UroYyOgOXGR2OXi+IFTEPc4uN9Tc9pH3pG65fD8I+lhWnwwH7gGYcT9e5Mkncr5s/GfdN3eNPxn1/HFTv+88OcI8QXRdpXHc9BEI7nu/c08NDILdRJNG8UFXSU9H1TVCK5p4mll/AzhOvw1pEYksM1CcoFpAcS50i+UGLWkgBV8XzVf+ga8BtMZ3nzAZ2wxoBsXHMYJkAEmV7X8C7C494TslVdeLKpbtyNuWme83LkDdVVU3O8bulpnhMtbdKt2kkmkMQcRqWAhRukJG2UGXHY11RpaeWmyBlaBAzdI3/q1JIiTBK3YDhgp5fFGZ7rEz0FgDAhg/CAA3cCLmUu6OWLNbeN75dq+8Rmj6WuFbU08LGAQvOZGFT1H9kHWKaIHJQZz290a4DcoguEAWv1g/vfddEYMmsGgenwAEj89p67qFj8l2bcI29w7Zdw7fvlDYqiz3mVKBBcLfLT+1wxwTm4F0hmSmT2hVJdj7RHEvSwAfXfoMzVRVMg3A2nlMwCJ5rRA0cTayjqWVriRzGZk8wAOhAmDPmmLDqV6Mxby3jLRbyuwti2ujiukcdM89WzFYmp4+lmVIwqF2cjpDEKcdJPVgccU2NDZMk6279Se2sXkrKMNTztZ22/ydOh6Sou8v36bZ28uVbjPVbRoNuGK2XS5Q1XnVlNV0ziog9kpKdEMkxaWT2l44lLhiMK3mYFuHcHU2ls2JiNZgGdfwgWJN+tlfhmDK3rBgm0QZudp8o/wtEtHJfI/KXH3GNDx6lRZoJ9u0k9LdLqYk/tAlbS1cjSPSlJegSrBI0bsPxv04AXzBfjMK1lR5qmALQDcAAWJkXuPTWdi+FewNFWzy4yYmLEC0gSBPabCJkCO3hY3RdLFxruPalo2HyDuy2Wfel3qaW5ewLWK70VTUNTVklZUzRF6pTDOAtO86SgzOGBDpHurSaVJ5cAMu5As4CYA2cIJJAgEaiSshcxuJqNfLnSWnLJ0IJBGgykhp3lsQLBKr+a7tyBy3dqm0bjlte17JPUWr2VrfU0s1IlwqBMKlDNGYjWO0zxRxzOo8pg4bD9S0soimAXbwJkRy3AsdIALjrsdweo2mS00hE6n4gCdJMCYAEE+gj1X2Bua03W6UT0cs+4w0JuFIKctOZ8MqPOAhIUKZCque8hkc56VXHNe05TFv0B9dzGmwF7lcrF0SAM9p+Gn5xv05QFvVt31VVe7UouimFqqonenAYNJ5cCkyTPgkKjFlRcE5ZT379s/hQx0m4/WAB66n0VFWlDQQD0+f7fqt3tt6WptFbWVR8poZp4GY9gegt0tkgDuAO47ZPrqh9ojdR9OHQO31WYo5fPpaZ3KGUxKzAEHuQPlqPIBsqiE4KDOe4/LS5kAhkEZ+miXIwkFc/loz0UjdDKkZ+OpMBHKhsuT39dDMpCQUPfRBUyoZXUJhCEMqRkj00cyMbofSMHAxoSgAhlCB+mmzJo2QyM49NQuKmUoRUD4jTZlIQ2XJPpo5rJoQSProh4Ri0JDL64A0cyh7oTLntjOiHKBBZSO/bGpKMILr8f6amYbooRUHGdGVAhFSO39NGVEMr1fEaAdCJEIDAHI0c26kITKB2ONHOpCAU79tHOmg7oTKSfQ6OaE1oQWX4HtpsyIQWX44GBoZlCgMvx0cykILJn6aMox0QGUZ79safMgBuEJl+YGoHqaoDJ+o0cykJuyEemma6CoBaFMY/nryxcuCq+eoXQoq1JJUVaUv6KKtNmUVaOZRVqZgoq0ZUVakqJjX1U1HD58MazsCAEDBWZj+EKT26icYBxn56k9EzWzY6KKG4N90thqLuzbNtbyUVWaWiqbfVqKoiXu49kCySlwRIvkBHLFCQFBB1qotc85A6ZvppGh2+c6arvtweZoJcYiTN2/A2HS9tQLqMPN/BOyt9G38h8m8fWjaFzgmiqqumrNxyWm3UcMEZElwdIJc1caJLKGaQUzlSe/uoD2MLiAx2WQ8kR5cxk6ASLEkWgu9CZCGHl4NOgSI0LTE7xbTobEa7cyipb/DZsbZfFnJ26+P/C3vzfXIzzC7bZ3DZautal3Nd5JGng9usdXXQSNCjTRw9Uqs1SJnnKq5wnXdi3tcKTHNZsQQ3MIEHmykdTE8oGX15NSo2pUnEOmk67occpFzFjM/1Frcs+Uwtd8OG6tkb6t9ypOGOVL1Z+QdrIslZtnija1PspqipjAnq6an+8Vlrq8GVpIJoSpx09XoBqnEV30+XEMJB0NQmCBYEBgaBa85tO6avg6VZgLIbeDl5yCZs7OXNABiOUGbQASmtRxDwt4p7PuS38Y+ILxU8MbNo6ikv7Xat3vXRyybjEsksc72oyezrSGalErGFaaWYUz+QESbzpK/eS1xdiKDHHQgDQdCdSYOhmxGbSFofgKjKLaVGoTUcSQQBBy//EAXF4AaDYSZhl4cfCtc9zbPufIPEu+r/wADeKnYG4btxxuraVbeG3Pte80L3COuoeuVzHchb2pp6GsoZ4p0aHrDBCyzBjisTRaRRcJa8Bwc3lcDBBlplszIcCOt9FzKLq7qxqEWaDyuG3TMBPcaxpGymzY+X+ZrXxZd+NfFp4eeW94UiXasstbu/im10m69v3dY52Q/7AwNziBwY5FnopUdw5DMpBOYcNDXCphqjSYBAccjr6bgDtD5iEK/EGmqW1qYaCLhwLgAROwvYyQWgDvqoveDnm3wl3jkfe/hI4/3fvPaK7Ur6DcW0bTT1+4tpVEdjkibzacW24NTSrNSzxShkiSSPyZ4kZiqDp1cXOIptbWrsEukGWtN9uYSCIIvOot3s4UKdXMzDPa5sSIIdv6G3Yn4KXvjl8O/JG7+L6zbXFu663e53Rcotv3vbO9o4rjabtaJ4JY7gKupCJVRR+yq6+YJHkVhF5eH6Nc7A4tjnZ4yFgkEE9bWMg8xEAR3srcI4DNSqgODtojpYRG0m9oHwXyv8l+I3kHw++BrxcfZ0+JzZF0bkGs2zchx7f6+4jz9x2OS+iiUp50onq7lRzJVxGPy5KiWGOMsiCMZ6zaM16eIY4ZCWzHWJ7xIg6wCTcqjFcQdSpVMPVzZ2teAdZblIEkwTE9JMCBde8925D4D5G4s8OnDlJabpy9s247bqtp2qltVmN5uFdt6SywQSwlaUmanB6kppZKiNfLmlGJFc9KcvPXdVqvZ5gZIkCIdYmY62jULucOw+GoYRjajgKbmtaC6YJDSNIMwBJ0jcLz58Hdelkr9qeGPxN2Tdk9w49v11vd8m3FfEq6xdqT2txZ6qSaNkkWCWmqLfbxEJGR6ujmTpy0iDqYkGPGpgXAEC/PmEgDrMns2+wScOqOc/wB3zONQGGk25IMGbmABBMC5ANzaX+9/C1a937w5C3b4Vt47S23yWFudpoaiqlq7rHXQ1kcU8Fpu5lZZqK2OZHi66Z4GoqgUs0bITMmswqBrTTxAIBubBvUF1/Md7zmEiDYrXi6jg6nWFy2I32mBl0FiYEkbRofG7weeIre3g48Re5eH9y7KbhviXebUe3rtZLnfoYLntrcD2KeWgvtNUxienklrIqdKCR+lBU1EVNM6QyVBOt+PpGraxcJywDBgglsWO8gbXGy83w6qaFdjSC1jozZjffnv1IILrSRO8L3/ANrcv+Jm08U0vIzcJ3nfO4WWO8VcFwulst1L7VUUsKR0tRRLVSmieQSrVZcqYnfocN5fWvJx2BaH+E17RAjUu6yQcsEDS3eNb+nwePZXbJpuAOggNJAvuQ6TpDtomDIELuXt0bI2zxtYL9zvx9uyi3nRU9ZaaO9LQ098j3JU3B4KetmN6tk58u5e0h5qUuKeWRykHTLTmQx9OnXeHuGHhzCAIbbKBJaC1wBIjWZGriQYnLmlrTiR4T5zHNABc1sHLGcCActogRF7rMbC5L8R/KW9uAd8Xq5JyLxlV7e/tEu2p7bBXXafbMNPTwVVRdK+J4Gp1qZpZAIjGrI9JUxqzr1MaRTZSFQi0a3IaHHygT5iBJ1MiDA0Re11UU/DIZfK10cx3JgAtBENAIEtJNyV1raW5uL/ABFcu7jqrlxPuCssu1LnLYV38m8K2wVVluUjyCShs8zCnq6qoKCMTU/mPB5UMJHUfcOOpUdRw2Z0BrtA5s5gBEkXAaP6rGSYHTTVpeLiG0WE5qYOYsjlcYkE2mRNoO2YlfPre9t7Y+z2+0q8Gtql5l3LuDwd0tdd907PkqZ1pKiywXCOenqaepmdFSTzJEpwJSSXp3hjZ06T0dbD1c/iOc3K8tAIvHURBncyOs67+Xr4I0MZQw1SoPCzkyQDDvKZMAdgYtoIXqj44juLlz7WL7Ma5znenEtq5D2pftpJuGuqIYamt2/UKGNNBHTPIYJzHPUIZ3UJ11ikdQiBWvhjGUWVQ+IbDiAZki8GYtIAImYB6q3ib3U34atSiZeNPKS0Am8y4zIiwtN5ClJ44vGDw1wVZ9yPx3c75v8AsdDTyPcajaNG1bZIOiGoFdapq2N2gi6reJZVp0LtEaNWVT5YzzMPTrkipVZYkQXQM1wQQDBMuIEjXMvT030KDW03nK9jTDQCSwQAJAEttOsEgabKG22vBdztZOL+IN73KzbD4/5Q5YudVvHd9YldNN7DV3VaipENyjpIgRQw00dLQ08PmdMPRI74JJXuYuM7qLTmbSEeWbiMxEkcxcZJiwygbTxeA13vonG0m5H1HHUkcujGgieVrI6EuPTSVV621beEaLgniGexQ3kV9PJY6ilNzqB93TQMqw18tbJMEhUSrVyjzEleHyicyrFG6cgVg57sQwhpF5iwt6GTEExEzaC6/q6ZLKfguzEExZ3MSZMC4MSQ0X2ANgQu8eILxJJ4XfCvuTmyuWj3DylatqQbYsbUVdldw7quM0UNEYlljVUpneoiqVhRBiGbLIfRaa1M4ysKFEFviuAEzIEcxNySR1JsQRYlczDsZgsMauLILaQLnC0QNGiIF3csnVaP4f8AjDbHh18PK8I3Pd8t5v3H9LW7hv25amVXe/b1r3qBX3y1VAlM8VRBV1DQiaMFY2icO3SWOuni8Uap8agIa4BjRN8g0JGkOiTJE7Bcbh3DWTkxnNVc7O8kEQ6xLSTYwCAAdnCI207ijm6p5E8RfIPAnItveE22726lWTbVNTtTXq/1Lf7PfIMRRx2+O4Ukc8zRuTG1RTzsWX3Q9TKLBTFU6gnUkZWi5aTvECIuAe9uox/gk0w2IF977GBOpJBn+kbLlPLOxN8c28+cgb52BR7Y/wDM3s9rgtVypr3cKqmTc0lc9QValmhE8T08c1Eq9c0CisWpRW66dxI1GGmk018ReoTygiSIEgmbiZECSRAJhwyjb4tQPZh6YOSDmuBJJyuiDHLcONhchpNyp0bbXbF/4Y473+914Vt/JFnv1uNztUl5o45LAWnpYqiywy0xWGgCBYad6fAVXgl7EMWFr6oFcsklpJBIl2YkO5iTd1zI2iB65MGwhmUUy1uWwjKAARFvQH4n0Uz6DkWo5J3XuHbuyLNSwbFjs7U91vBCR0y9HRHDTjzOr9shSTqEaSRJgAsesAc1zIpmriDF7Dcm5J9L7lvQaEpadEUxTygucSd5jWd9zpqdzFphJU7hvW6ObJajbFutO6eOqG8xDZ1tC+y113qYaWmlrr3bEOUe2L5qpGaljJM71jIxUw9XSw7XsZnPK53xhpMNzGwDnGIaBZoE3JhnVGvbzg5QLumxdeWi/NlEy4EDNAA5ebmvj45gtVitG+NiNy1xpt17NFb7luPdxs0FNBx/PNVey3GjIknD1spoq6V4rbAskySTGSR6fMeRw9rHFrzmyZojUvHYAHVzQ0uMNAESSCFhmqymTSZzZSQc3K0AAhziSA0QSWzzOMQMpkB4T2dwjuTaO2L1ufjTmbe1W1bJU7dsN027V0ltskDVlXS0MFsttNTw0VJD5PVM5WDzy0/Qsg6+o769fEOfmaLkDM6Q50wC6XEkwIhoGVu5AAtXw/BMp0YbVimHEgDlAAcTmixLnTJc5zz+Igk37TxrsbZe9PFBzFZ7iKev4X2dabJerosFoipae33Q22QS0VXUR4cMKZaJlDSPIAjeYw90NgxGPjBnEOu4ucGkmZ0mLX5pkARtc6anUjSc3D0Ya5wbLRrq7KSN7QRproApj8d7H2VbNu0N625AvH23KmhcpHbZXMtXNNFHO/tFUxWdshuzBwFCL0yBe2sGMxj3yysc2W0WAEGLD166k3BJThpY8lgkkySbk6gdRpYAA20Cdcd3u41m59ybkltQXYEFfDSWy4MscNNV08MMbSSR9zLKodjGHkUK8ilVPYFqsSC2mHZpe7MY1I1A7Cdt4uRCerldFFsyAJ9Tf8rkDT5rauGY3rNiWYVFZXxx1cgv9VTRJHIaypmVJDFFIAfMhEj5aZiAzDC+4CxtxzMj4F8oyjt3PS2g13NyAsuJqZnudaXEidYA17TFoEgC2ukirJZjbRPLUP51wlLM5yThOosAfgTljlvj8OwGuW+oDZun39/msznZvv7/ALLNlkUOzMoVfxE/4e2e+q5spGyt2K5XuCMjUKYAIZUj56IKGXok4/Q6kyE2VCK5+epMKBqQe/w0ZKkIZGTgAdtQORCGe/w0Q6FIQmHfPfRDtkUjRDt0IQ2Ge+P3amaCjEIRHr8DolyACEw+ef10cyMIZX5akqQhEEeoxpiZUQ2Uk5GpmKMITD5jTZlIQSD27EDUDlEJgB8BnULrqQhMB3B7jRzIjW6Cy4PyGpmUjqhMO+dEO6poQWBI7Y1M6OVBYYz2A/XRzogbIDDHfRzJpQmGiHIEILD1+ejKhCCy/PI0cyLR1TdhgkfDUlQ9kJl+OmLkcpQmGR8dHNshlTdgMHP6aMpiEBh69tTN0U2UwWXtn1GvMrzqtqKK/wDHUlRXwfU5zqSoqI9fTUCiTohRXxnQlRXx2yR21JUVuk/no5iosNdaAVcc4ajoZo3h8p2kZgenPdSFGSvx+h/fohx6q2m+CDuuXrsPYUF1S8Wmx2u7b3ESQG4wJ0V0ESkFUFUMOkQKZ6Gchsdw3prX73ULfDnk1jb/ACtD3PJzVLet/W28/cLH0/FtBVX+Lcu7Vk39fqapWWmkrYEljo6hVPSYCwHQIw7Krdh1O5Izgh24xzG5adu+nr8/yFtUcRXa9gpBoa36x+51PURss5vJrNTx7YtNaKm93Ce9UkbxQSEzec0juZHAK9SgeZ2b1AAAY9tVUiXElo0B+AiEMOHQ545QBI6bQP8AHdct5Z4m465WtVfszmTaPGe8Nm09KtXTVVXbR5tD0sCJRIPeglVo27xFSyuQO5I1qwfEKtJ80XGTaNj2jQ/EItwrX5ajQcwNr3nsdRrrNuq8Tubts83eH/kYb42BS8r7blqdySVy7KvLx35L05pYoKaNKyAm4LTYFbJmomqZKSKTqMMAjDJ16DWPAYYLiIlsgC8uN4aDGuWMxtJkz0atfK17qTs1MAS4gSQJAFpcRmIAJGXXYKOu1d4bh2Fz14dOZdz3vdvhx5M5C3WmwbnQ2a9W1LdvWx1NdUCyvJWyCao9toZzSCWCthpJlpa5ooeoKWO88O/kuYW5wwZpOblMc0gAQHCYMuBcJJ6c7G4xrqpd/ts8lgCXiwEGMpIOzQC0EyLL3hu/C3L11pLjLs/xAcsDbcVXJUfdtIbbC91uLVEkzFKmejmmo0MjxtLGC3qwVF6SNcZmOokjxaYmwEl0AAAXAc2e36qzIxjiJyl1yYBLdLNmREAgSLWIIlR65C+zfuXPuwKTbfL3iB5Su3KVovE9/wBqbpoL9TyTbYmSNoUeNZbaGlidCIJ6YsIZ40UFE6zjTR43RpctKkPDOo5xO+mcidwdvguVieGudiBiXVHAiI5acyb6hoMGbi4O8rnnEUvio4b5t2l4d/Gr4kL+t+3HLU2Ph3fFn2daZNr7u/YpPPbJ4DCJ7TeClMzrSSzNFNDGwp53YPGNL6eFdh3VaDMwmXAuOZvSbQWydQNYkC00Hi9dtRzHNaDbqAYGouepsZ3MnbyT+2W4Ds1Nsfa+y/Ehbtv2ao2jui7br2pumyW2e2We/bdujRLW22hri7+x3O31Ukty9gl83zo4A0bv1zFL8DVY/wDmUXEghrbwSHzAJA2ItmEDaBAVnFSMUwjENh4MzJnKAcxnqYm5mwK3/wCzU5PvG0+R/EHsrlba+2dteNDaVHNW7w6Y4Tddw1Fshp6a91MbHBmSso6fb9/j6epJJmrChcyvqvHn+QKTPJsPWS35OzMPQEAxCt4bXa6u11ZwJPLOgJ0DtrOaQRG9ypH+Lyg35tO78Ffal7dvFt3DxPb9mbatnK20rdZJqaq3DtZpluNPcS4eUmrtUzpWqixmXoWdeogCJq6FbK52EBIdmJbJEBwBbBiLG4nQfMjoV6QzNxVECAHZjcksJBMToBAMWJEx1Mt131y940t032TjHaHF0VJa7TT2S77nuF1pjc6Oq9nnmZKWpo3lannZKqhlHUVXHS3SB0suI0GUqIbVqWcfLcjYbgSBcSJ6A9epSfh8M3xWMJ1iCNDoYGmgs65m9tPE7x4+H7xKU9HwVbtubV5LvfM/E13mrdh74p9rWKrkavgip1pbfc445p3vFOKe3wpFUQjzMRIstK0gQN1ximh/ih8tdrzGbkzls2JJMg9bOiY5OJ4f4+FENIcCHDlJiAIDxO+pLR3Mb+xP2cniz2V4t/DRb+dq3dvIFpv1ZE+yd37Ou1ZDV021b9TSZSCokjhhkjRgJTCarHuPEjF/LI1zeJUjSJohgAs4ETMaWkn4xOkiJR4ZjjizTq/ikzYA9SAO0i4v6KV3NvE+3927WvFtS4bbist1WSS/RUbU60d0R6X/APD69S6rUU9WrOJD1nyi5kiaFnVtctmM3JktmNdZ1HTLrpewM3XaoYdrpbk80XieUE7R8G6HebLwp8HtRybxJzj/AOZvyNuu/bGt27qzcW2eN99X65Uho6+zPHbZai1080yxr96BpaiSmnIJlaeeo6JKhJEk9I9zTRL3gAiC4Cdi4CRsDEHSAMogGRyqtXwKzg+S0HksTNg43aeY7wScxu6GghS/2RzpwDbuP77tmapquWuSa/aUFhodlbaEm564V9BUVdopZEigMlvtsrw0sVSZq6WJYhGkzMuHZan4evWJrMEiZzeVoBhzgXnppDQTcgTad5xVGkWUapLQHGQYvlNiGed+ZxAEAAu1iCvM37aaxbq2hR+CTxP820G0uOeO/vG/bGqbZY6Q7kvlPbqugirBLcqqsKQVcszwyhhTQJGizOySSlwNJTZRcX0AS5xANuQSHWDdTF9XGSRBAuuRxHE3bXqDkpuAJcA7zNIPK2wjLoC4jYwoL8i+EnmUeM37OnjbnrlDcF98Mt6vVs2nsW2XLcMNbcuPLLWFqyktFdURxezpVdBiBaLzYh5XkqzLAo11sBiKbK732LmgudqAXNbNjYkDraTeIcvP8WoVwyjMsoEw3lGcAmJyiYJjlkuLRHQr2c+1U4Y3N4nty+APwe8fbsssG5uRd13S5UV/uUytTWzZttosT3CSiiWnp4qfy27RwxxmaSQiORUJ6svCajn4p+JqgtFNoc7UumQQJJcSSYABMDVw6dz2oxDcHws4agBLntZAgCcpzGwAJg8x1EwLkr1I5GoXk4/u122tcd2c4ckWqG47fqtsVF2pqWK+SVM9IsiVUtIoNA0iJFDHLKHpzBKsTAph15XjudDcgaCQZMmIJImbG93RDiROoXew9OajX5gWsFoEAmPwzNxeADymSTJkwC3tcNxcpWk8abn2DtPjvkWq3Maq21d7Srs9NtmneNaOP74iCyR19FItXHQU8rNJTSA1Kly3TILKbKrMribazY635ejiRJ0cABa0HXVqUagLKbiTERN7G4MXhsnMBOYmx0UIOR+Sd6+MHlOwbD5U3fScQcYcDCTcW+7ja7pTU9xbeFRVVVNS0Lmqp0gars6LW1K+UjNJGkbxmNpImW7Btp0ScRmzF0MYLiZaC51iXQ6zTpcwTqFz8dWOLqMwdBmVo56ggEAAwxkEZQfxcxMgTBtM56jk7wweGbwsch33fvJdXeL1JPcaXYsFfWQT3i99FNGklPRzGITzeVVTzRg07u7vFH70pYEjFNxNTw6FJhLnXIAIPmAEjpAtIAv8uhh6bGVDiqz4pMBBc4t1guIEE85tN5N7dYTtwJzbztUcseIK0eGrxI8e73obdaWsk1JcoNk26ittKtPM1Pc6isqDdJqh1MtOZ6OCJYleTyU8qZ3fcyjTw7C17mGXXBObcggNaCCP+48xAzREDg4nHe9VKVbD57thoAgkESCXvIAI2DfKCYLzdSs4x29zh4xuEd1cY8f7+4j4Rt+9baJ75a6a31V8ulu2zb6uK2QW64XCsaKGJporbNFEIaLzHUVEpfy4mD56jcM0CpXJfBBMQ0Fz5dbzOJiCbgNAAILoC1Oq1m1A2nTyDyNmXRk5XOgBrRckS4uBdGURLhgLb4dbDxP4dub9vbc585wntO3Jai07XorHu1NvWujrqWmNdHNW+zUdK81Q0UMx6peuWUQ5bv0pqr+JU6j2VqtIXN82YkNBggDOQNrCwnXdX0uE1Kdb3elWyCDIApkuLhaXBkzJEkmCOoKn/Z+DuFr5tyjq+Orlz3vrYVVaaSGZr9undVZTbkgqpYJ0SjgSeFZvM9qkTzCRC3XjD5JF+KpVQ5zKtNrSXQBlZIgEAuzTFoNxNthKycJ4i3K0OrlxILjDrCbk5miJtbKcwGuwXF/EDxHuXw/+HHnCe27j5hroNm7TqauitW2d3XS2JaWlijp6OnmnqKlsdFQqyRCnMeQ/SFIyFyMJxDg2mG87gyXARJIuANSJBvPeNT0sViKTKYrOeWkZiIILiGtMgS0wCLdo8ywu1/AvxrcuO+GOB7U1XuyS+3fbdZufdKXu4TXW63CnaOtuNUtdPUKS4e21MpMaqiSVqhUaR+odB+Jiq5+WKTM0NgAQBAka/iaL3ImIauEMPkwZFZ5OIe0ZnEgkkuDj+EiLOOUERlzOmAvRzhO7cO+HngOyw7O4+uFNcLdcpLTZNtJLIJai4fe0lupqeLzXIwZig9obqYoWkPUQRrjVG4itUZTJEuAkxYAtzSYFgBMgdIWvHUQc40ptJ13i+pkuc4xGxJEwNMVZuFuP+E9u22k33FS888r1t5l3FuOz2my1VYlQap+urlo7NAsigKWidWqV65hAMkMwRdVTHPqf/igimwZQ4wDbSXGA0kjRpESdbk82jUcGuq1iKfiGDBgbw0nzO5eUkSLCwEKH9tvtw3DuTet+414Y3vxJthLZU1tXuO93KHbdmtFupR7THIKVmklkZelewhKTdIeQKUj8tMTXysy1qjSbG/M8nQQB1zDU22Mkz6rC1A4s8PNUBOUZRLRNiJMGOU3G5jyhSm2PXbj3vZuP7Lt2O53LYltlW2PW2un9istrkjpvOqLhVyTmN53BlLLGC5aaQdYiHmJqzFFtOq6o+wIJBJEwOUNYBIvEA6AaFxAXOo4inSpltNwNW0i5MuvBOwi7ov2uCpQ7X3fEthW18a7c3fuSigXyIHxFFTALjOJpGVZ5CuSz9TL1SdyD1Y5GIZUfD6kNJvc/QDYCwFrxaU76VMPmq8TvFz8YFusaxsLLeLJByjuKgs9+vFqsGwbxLbYIqihqJjXS08pw0oYwMIsgl1XpdwDgkkDBVzKFN5aXFwna31In6LMa1MCGAm51t6WufvZdDks8tVL13CtFRRnJkpViCxyMQoHXkksB0j3T2z6/LWRtUAyBf8lU15gDfqswTkkn10gdCcCFbHcHRzKQhFcZ1JGpRSCMjGpmCiQV7ep1M1lEPH79TOohsvqe+gHbohDI9NNnUQyn79NmUQ8amZGEhlznHrqB0KIWmlHKhMv5nQkpghkA6bMoWoRXHp3GhmupCEUHw7aYvULUIj4aJemDUFlwe3fSh53UhDKD8tMXoZUEj6A6gejAQWUZxps0aqQglfXGiHKBqCyj5aIdvKMdEEj56IeoEAjH00Q5SEFgfX11MwhHKZhAYDHy0cxTNEoLDt6afOEYlBK+vbvoF3RABBYepxpg9GEFwMevfUlNkQHHyzpsyMKXp9B8deZLl5hJ1A5RVo5lEvOf8WhmUVZ+B/hoT0UVZGPX+GnzXUVAjGc4GoXhRKBGMA9wNKDeVFXYd8/TTFyiSzIq5cqq5xnUzbqLHxBVjEVHBT0SM7AlABhsnPugd27E5P8AHTZiTdEti5usZer/AGPbtm+8bjURw21JUgLM3cMX6cD4ls98epwdLmJsrqOHfUeWt11UVOQuR4ZZ6rdGwrTyZuBKC4U8Sy2qiMtFWdSRl5THjrqRH1Ih8vPUGlX8Sgrsw9FzxBAE9TBH6Cdp7db9+nhhRblxJGhkau7AQD6wNLHQEJruHeL02+rRe95bR37Z9k7dn++qu41lpdre8widI64eRK5jWAdbuJQxVWWVujC6uoUXgfyyJdbVvxF4ubAR3F7rFXqUm0jSzS50DlDiYJiJy6E66D81vPI3GVJvw099u0lXW3aJSlv6J4J1pWlKx5gYr0RmUdKN5fvtE0gL4bSYetByAwDrr6wesfLsphca1jYaIGuhm2/W14J3iB0ze+fDtsXl/jjdvFHLNLf937GvFL7DXUdXdpJRUdLB46mL4U0sUgSWExgGB0Rk6Si4dnE3sqNqU4aW6R+R6zvOt5XKqvDgYDZN/KLeh1+Myb7kqB/CHL/MHC3NFf4T/EnuncXIXNVvt9RWbE3KVMX/AGx7NjZDJcOgDyP7TW8MsdZEnQ0sQWZFKzZj6WPoUn0xXw7YpuN/+Do8pMzkdqPlqFm4a45fBrEAj0AOnQTA/p6mekT+3PuCAtYLFa2qrbXVMUj0opGWIzU7JiQqxP8AeN1iVSQT1LnByTrgB5cZIn70t8tl38JhiAahIIGsif2FtCtC594PsPiT4r3fxByLSbnpLbWUsMsM1tenWusNxhZZaK70M3WWgr6aeOOeGQYwVKnILa24DH1MNWFWnBI1E2IOrTbQixXNxOFo1WAmN4Jn9oj5rzX4i3PaPHHwpyp4b/HNxVtTfHO/HW76DjrlLbFyVFortPPIpS/UqxEJSR11JURVEEkTs0Enm9LADv167hg6zauFs14Jae0HlJOsGxEXtKsoD3nD1MO93KB01gDIYkm9ztExqF80XiV4i3J9nl4+vC9R1W7t13m9HdibVtW8JaiMyb/4wr5I7fHHU1TMipdrbE9Va5vM6P2TW+bJC511GVqWJpGWw0ySNmuHNG/KbEHsRquRVFfCYmlVJ52kNEiZabdpyaa3BF19ePHEnF27+MtlcbXuhsF6sN529JBbKOhuNbc7ZVozTwPRVxiIE1O8aJKjSNH5vXMyEnGfL1Xl7nVReIJJAEWBtNgeg2svYvoPoT4ZIaHFp0BO0jW+zoDo0O6hj9lfxtbePOd+ffD5ujalvse5ONNu2So2pW14hnuG6NnV7VbWWpnjj6mZ6GnUWmR+pi3scI91u+u/xnFPfh21wfMSDGxAGa/cwQO5XBZVGCc7h7LAmRBgEX9Lgk3I7r0b8Rm1rxd6/jjb42lS1+y6y/tVV1TFGeu3QtR1geZqZWWZ1WadOkp0P1yg5yhbXBwTywve7QNPck2I7XjvYHqu3gajCyQTnBA1gRb8Wk27jQr5dPtd6O6eGfkKXx4eCzeF+4m5dvFLSW3mKybf9sRaKqWSJ7fuWGBlWmBcpFFJTVSkxyTUztGGczH0WAf4tHwq2jTykxf+ps6yJ1b3GwC85xTBYjA1DimXBF+kGwOW8xBuRlPWZUvPCZ4uOf8AmDZFJtg8V8W8+cb0Vkt183/urivctvFz3RFXzM0UlLQ3JIIae6SPB0XGCKSQwp1wAI5gcZalFtNzqhqWBhocHNEgaSJLmiZBMSYuRmXawuLqVG0w1hzkSHDmaGiwJbIDTrDSTlidYUNfGR4iN1x2j7Q+g2n4WN926JNmWS/Gwck0FvNXYqoy1lFcb2tlqJJKie0tTV5xPSvPHDUxLK3k+YEXVgsE9jaWZ4a4uIlp1aQLAgZc0jQwSDAkocU4m2tTe5jDUaxocA5pEOabAgkOiBJIG0WFz6QeFSXYnBG1uDuL+Jdy7Z23w7aeIrtXVc93tVTS0S3CK80kcVwnwlOayrlhheSRZCzRqxeQs0hUaMeDUe7xA6S5gHYEGQJmANzpNhuVz/ZnBMbh6fgMAeQ+TLZdpqRsTO4Ji8ABRP8A/KMIp968HeGLa22K2DmDkm68szRUltt3VUUdXM9okVUjgWFVfzW8ohAxCYZR1kyPrh8JLXPLWyAGm5sdQTvtcz6aABbeP0agwIFRkS5gDbGfNvMxED1NzoF4seO6l5B4f8Pnhe2/tncm/t57PornapdsX3cVOKWu2bfrdTSmoslQzp5lRAhuNJNTtMweFY6qEh0VGHVwuID6/iNbDr7zLSQARtsQ7WbEbrkcbZXwmAZSe4uaMsGLhwH4rAgEeUW0M6BfUf8AZt77qvHX4iebPHFyHs+wxbU2HsKz8G7Otq2vEiXCKOCu3RWRxYKhRWNHRqYhgxQDo7EBs+JxXu+Cy03EurPLp3yAkN/8jc311WV2EGLxVGmWjw6IvN2+K8DMADaGANAPqdyvSTkO8cZWfhPdnKtlvVZs+groJDG9DBIiX6SWqhip6SrpwqPLUPJJFGie5J1tKgYKX1xhUfVqNp+Z5IAk7mZgyRGsm4sCdF7PBYU0MQKTWgNYDNgAABdwj9Ooi8Ly1+0x3DxPxh4eOV6HdW2bRuDeNgta37fN8iqVr7dx/PNUQz0e3VeSbzKhqysUD7qDqs586rqPLgZNdijXfmFSkZphwDLXqPFpFvwi5dcMbA5nmDzWYljmObUJaXNcdxlpgXqGIADuUDd55GwGlw8BvAjVeJfd995r2xRca7I21y1uW4Q7xqbjY9m0st6pqO5wmX2H76rpvYbFTLErLCnl1NdGaeRIaZ5EyevSw7TTaC8lrTB5oBIvctBe506taIgyXNC4uAxlY1atR1MCpVh4BaXOA0bDXEMaAAeao4CbkPmF7ieFLwib2rt1bhh57vtHsm4VRtd0jrNoh9z7s3ZXW+uSWGju29rskhDU1WqSywU1LTxuYwQY0hMQzu4pRZTy0OYbAfy2NkEF2VpzutMOc8/1XkFdPF8IxFd7H1mtBEy6oTVeAbwAQ2m3NblaywOUXJJ7r4ja+Dw1ffXHnHvNvJVb4l77dRZNrUF23xPc5q+nrvMZLjerbLGYloAsczSsfKjCwsY3EiqdchtX3nKynTApgcxDTyht4DpN4mNSSdIldKlhXtPvleo5ztWtlpaXeUZWgNIAOv8ASAb7KCvC3iT314b/ABGc02as4bo+RYrDebhuDcdfx5Q0Vn23tl6ehoLfTXWWuljkEdvih86mmIapmSriqZI4nkSfq6JqCvhmudU5LgOcTfO5xMACZdAyhoEtBuAQqajvArGiaZD3gDKAXEhjA6DmeP6iXkmOZsxBC3zw/wBbuTxE3Pdl54t3Bt/kvY92qjXyzwUPte3KSsSoWKR6OjaKOomTzKo+Zcrj/tFUQz+wNEsYJLadJmR0ggAc1nXG4uGAAcrG5iN3tcSRe3FOrnO5rQxxkBsObykyJBBqO6uHh0xIa3MAZ9guAeC3o9jcZ7efxC+Im8V+1oKeGppGqfcppqcS08MheWgEs4j65SgY9OMOqgop1zquNYx7iKQEjU5twJ/HYxrve5uq8YxzWBrg3KJ/puNSLbTFhFxG0KPm8tibe8QfiJbblHzLva+eG/jq/ne3KVXetyGps943FS08M1utFenQiSwUNPQi5TxFxHGZLehUM7DWvB8RZSw7eIhjWkAtpxMzJzvEk3GYMaYJzF0HkXOx+Gr5v4a8czgMwDWg5DZrCdR4jiXECCWtJdIqBcGuXiq5N5Y8TO9PEZwpszb29drbd2tcNuT3653Fts7atdTLUwvS1d5q6tZHFxaLpmNPFHPNR0slOk6o9VIsZw/D8mGNKo7L4hbBPMbE5gxrZzR+JwgF4yNJLObUx1DxKdKiwuLATlETBaNXQ0Ma6Tkb5iMz8uV7CGezdp8n+Lu+bn4U37z3zjZFpN02/ctM+2LNPZZ+l5UnirYLermroaMVMVTLHcLtUDqieN6WkRnDJsp0qNBpeKXlkQ4gwINnHyB2UwabA+oTZzhBWDiNepWa2o8huYjmaDEg3DJBe+C3ztDKRNyXiFK7kvw97R44gsPh72Fx5svlvmDclTUbg+76O7XS0+x00k/l1d7ubS1NVBHGhlcLLKJJJqkxrEjt1dHNwmLdWfIIbTpxmLmtgA6NEAGXaBrRMSSQBK6n8TNKkar3PzOkDKZL3ACNTMCxcXOytEA6taes2/wYcS3KW3U/Onh14KrWoV9tjtO2rbRz2v8AZnphevWojjrbgEUKAkrGE4J8klAwsqcfeweJh6hLhuREE65AJa31u4bELC6i7EgsdIa4xdziXADRztIOpaABoCSF2XjHYvDl+usO3rDw/sjbFnjSequVt+6YaVkYSD2elkpMDMSqzS4ZMEGPsARnnVcdiGjNUeS4WBmb7meo0sfit9ZmSjyOMOtFwIiCbxEkR6KS1t4823ZJrcbRRfdVvpB009DB7lNG2fxCIYAOMDt27A4yNc12LcZkyTus/juyZNvv6LdldX6ukg4YqfoR6jWfOqlcjPb4ahcEWobY79jqZlaEjRzbplY9hn92hmlRBP0Gjm6qKxGdDOjCCfj2AGhmCgakH0+emzdE+WEMj8/nqZghllDIzjRlEidElgMdvXUDuiOSyFqSFNkJx3GjJUDUgjII02ZMQgH1Px0JUASGHb6aIdsjCCT8TokwiAhsDk5B0S5SLwgt8fhohyMdUHUzXUDd0Nx/189TMiQZQiM/lppTCdUA+upmUyILDB+WpKLWwgsPjjOmJCJBQWH79EFDLKAwzkamaEYKCR3I0c0oEIDDHr30+ZGEJgew9dQvULUEjP56ObooAgMMg+mmzowm7AHPp+mmY68qBS415tzl5dVpc4UVaJd0UVaBcFFWpnUVabMoq0Q5RXBI9DoSohSytFGzInmSYJVAcFzjOBn49tQuUAWqw3T2qSpoqinlqI2VjChp2xUqW97qyOkFfTpz39dMCdlqfTyw7T46frdco3xdN3bTVLnxxQ017qTOJJKO61ISlLO4V5WmHVKr9PWixqD1uUXA7ur0wHnKTl7/AKR+ZkQJK30aLHtPijsIseu9o3Jg/W/BbfNz1yzvK/07fcfGOy6ftVVUjF7rR18kRIjoqeN6qmZ0VVZ5JMriQGPr8xvL1soUWsz1HS46AXBiJk8pA6RJ6xF9VTGU8Pkp0qZeYuSQAGz6STO3LFpXQ9u+Fi3NbqNNy8j89XHcShxVVdDuyttdNVsZxUM5pqSQRxkPjpTJ6AXCNhmza/ibAbUmR3EnSNbT99AuPicdUL8wcBroAdbfina1hfUgErZajw8bMqeg0HJnP0tajSwySx8i3Or8rqiYN1QzSywA+8v44yBkDGDgg8YY7lNOn/4gH5gg/X6qhr8QzmJjTVjYN7fhEj47LnFNx54gdp2nbNJs7mbb3Ju2dqVdLU01o3paloa28wU9O8SJJeqDAUjqVjJJQye/EQR/j1pZicK8lz2lhcDcHMBP/F1//tv8Ej21KTHMawOe4RqRGhPUXjaLeq7rsHnCxbtvw2HuGyX3jXk4Uz1QsV4CkXGBApkntlbGTT3GBepSzwMXjDKZY4sgaxYnAuptztIc3qOvQjUHsQO0rO2sN/yj5g3H1G0zZc/8WPhq2/4nONn2ncLtuDYG8rRXQ7j2ZvWyRxvd9jbgpj1U9zt/Vnqce9FJAfcnhd4nDK2Bbw3iTsO8nVrrObsQdv1B2N0a+FZVAMw4afsZtHr3BsSoMeHLxV71ve5dz+FTxIbc2xtHxebXudBU3SosMLwWvcNDPI7Uu4LWe8n3fXSIIzB+Omq5Z6UgHyi+vH4IQKtAl1MgkTrb8JH9Q+RAmYXU4VWhxZXJDgIg7jSQSdIm+0DVTe413/yTurdO8Lbc9qLsWnpbgop2nmWrp7lQtTKyVPnELK4MgnXp7eWVKEno78qrTDQ0k6z8IOkdYhdPEUsO1m7iBHS8zaLdtJOsBQE+0F8BvI3M01bzt4Z910Vm8VVuaioZ4pap7ZY+QrPTVcdZFZrw8PvJLDInVTXAlpKaQ9Oeh2C9jhXEqbA2nWuwXBN8puCQNMp0cN9dQuRiw9rDUwwyOIgiTLhve8HdsC2twSDCXxV8ObW+138BPLexuLOPNy8feMTiy7z1440v12c7g2JuVOky0FU0zOTDWUomSmeNhTTlKV1YMpCbWF+FxIbVIyPEZh5SNiIiSDEnUXHrlxlehicKX3DrG4vJvHoJmdxewUyvspuTNp8leDXw4brt9q6tqXexU+z9w2eqpup9v7qtEsVHUW2dZWJzI4nqowy9QZmycuDrJxui6lXeDrqPQjbsBb5LXw3GOxFENjK9kySbxfm9S7W87x01Xxu/9ofE8XD/ANol4W6Jd/7x4op7jaL/ALYNT7PW7u2L7aUutpkndStSY3ghraXzCksM0LdLTB2QXYWvTdmwVU2fBB2zZeUjpMxuCOiOM4VXJdUAlwvYzOki+lgZgagdTMo+PPExZvElbuFOS9m119O3tzUVq3/Ty0lMtwpYbe1HIKW11DDEaPI9Q7PIpGZY5lBI8snGaBoGowxLJbrEkxcTcgaCQLQbGQutg6IqYWnWpEBrwYkXieYyJANhYkwLbEroHJfhK4n5t46ve2/EH/au5WO4W28UF+slFcpVp77BcDGstRU02DmrVwTFIrDyyE7kL7udmNbTdNIAm0E7RNgZi+8jWYhU4itVq1HUaQHhusB1GWACYkADYa95hfIJ4TPDrz/4V7nzXt228ybvg2zxTve42Tl/bMtqaoi2/s+5Uapb9429opB7TSy+z0k1WI0Lxfdq1KeYsDK3q8TQo4ljHNkZxLbxJBnJ1B6SYMkbhcThtWvw3EuY2CxrhY6wQRm3GnmnQ21Unftpdl7g3TsbmO40XFl23zNt3iza24bjvGi3NSXFbDO811qZXS5NIKipp6qmm8+Smp0EU6FJCuFTHOwNSoC1ocGjxCADImAyLdW2Ac426r0HEzQr4F9QBznBhhwAECSCNoBykOABMCCJXoJ9lvy7fuWWl4e5SXdfC3KOzttbd2vU2Ovvy3WKssFXb6iWS+UdSpEU1NXV0rxxxdMgjeNQ7sysNTiGHp0mGqwSHSZjplDW3vYSSRFpjqufguJVKlI0qtJudsWMS4k3JF+UAATmvABiQE6+0i2zxbZuWvskqW3VVlj4/HiSpc2Wk90UapQziokQxMW6DJGvShwFIKplW6Rl4VVLq1R1W58J221o+99StnFKdYUW0mNObxKdyTqc0CNBA1jQa7Lj326Gx+FLV9lxyzuLcNitz3SDf1DadizxOsklNcIK5YlcTBQVL0Ud08yPCnp/GS2NU8PqvFank3aS6xAAuY+ENg6SbKe0JFfD1m1rZWhw6lxiIE9XRNzE6BSr+y9p9veCD7NLhbcm+aSi2HQycfW/dcU8UTSTX/cN1eWuISNQ01RUyJW0NKkKqzOUCxKzYGtHH3mpjPBYMxBDAB0AAPzdmJPTWAsPs5w5rsAw5rOLnvJNmtMASdgA0fEgGUw3zx3yb4nOUuPtk79tm5/C74aJZq3dP3Q13kpN3XmGgdPJrbh7OfLsq1NTcB000XVWBIpWkmpyoQCrUw1AOr1i172jyi7G5uWC78ZDQZg5Ba7l16eLxNdraGGa8BxH8yBzEQ4ta112gENhzgXOvDGEAnyK8ZXJ21PGDetueGTwz8kcIcT+CXgncsN93buXpiprNuXc887eVS0kc8nk1zUdNTVdS1TLKYGxNIxfoRJOhgMUTGMxZdneMrB+IDVxAAOUXAENnQBsm3N4ngX1K9TA4NoLhlNVzjmHLZjHExncXXc3MJjmcMrlrfhC35DwT4hN/cj+GHirxWcp8ZpseHf+7dzx2Kjpp7zU01VVg3o3a5TU89DR1tJV3aN6nyhKxSnEVPCIsrtdTr+BUpVWhgaQMpMC4jK4AOJu1pyyTMlzuuapXwJxLKdI+Ka03jPmIcIcyS1pgGNAwNs2QZM0fEL4kN9cTQcO7svm1K/bXNF5qVSw7XsW7bXWbcoJayAxG0UNj2xU1V5qHkp3dmramB1dsBhAkgQZMPghWLmUC2q6OYgFziRcnma2m1gIgCbWJLtuhi+JilRDsXTeykCC0ODmASYbmqyXOeZkZW5fNAEZlHbhrmDmLxcxV+zuFuUKXwIpbrzHJuzkHlt7Z951V0WnqKaeksNreATRT0TNVQ9U1YRSqxDhJKllXTW4e3whUr5zSIIDWZiXTEku8oa7QkDm8okNJOXE8frVqzvdGNfWESXgNDADOTKXFznN8waQLy9wALVIXw8fZ52TYG4uV7dfuQeMfEXxLsK1UkFXW3O+vd6mqtcME8scVDboZobfQxPU1k5aZWkqI5Z5URwzzSyYa3EQGZ6QLHuNgG3mzQC5wJMAABoyggXEQ1dHA4Oox9OnXcXNeIBcS0GSXPORoALtXZn5zJDrky3r5binhHb2y9/eJXe1zq+a5rov9gLZxdTSUW59/BqiQU9tFDTqxrayOSnWGpSqSRKc9fXJCQ4GY1H1K/u2Hb4j4uHaC3mLjAa3eZgnQGy34msyjRficwo0y4jNfQwAMkuLyR5QBm0NhJXZ6bbv2h3ivkp6XnvxHXf7NXZFwxRW7bXHdFBe9219XNiMx3u7zh4bZUukKCKCjDrl3AnJIQwYbh1FpbUnEO7HLTG5i0v3zGwgaQuDiMXxCsPF4fTbSYd3gOfFyDkuxgEg3zOkgzooK+Ezwq0W86jk3wy8dcicv+J/wabIuVw25VRbj31HYtl7juNTJ7XPFXpZKZa28SUwWJ6oBgk81SI550FMsL9lmMpik3GV6YY4xkzBzyGtNixriGgScrJgSHEBxPLhxGAxFOo/A06rnPsapaGMcS4HldVgvzwS4wXOghpyiSvdLZPggoLDQbCvfLvJ9v8A7JbOoo02vsvZ9ii2ps7b05dmNRFQxvJUVFV1SdCVM83mA++iJIxY8nF8bBqmrRa51U2zPOZxERADQGtEbAG1ictkMBgy1rsLTY1tJxktbJnS73OkuIiTowHmgmCM1y7y3Q8HXTYG99gbYo7XcNx1osc2yhRRW+8bpgDSSNcYJ6mRKeCOmlm656ypBVIZG8xg7RI2fDU313e7PIJiRflZa0kA2OkNEkwGgmQtmJp06TXVXy4g3cJdJsIixccozASBALrNBeOOcT8rbY2Xup95cz7T5PvHiKvUtXNeH29T124bbIWqEjpaWjutDijkoqeARwxrKsDoFqJZY0eWQ63YmhWFMYXDAFmkkBt9XOdn5hJ6TDQ1o0uuHcKtJ1WoQwG4G8CYAAkk7kScz3EhS0r93WWe3GlQ2Sm3TXLJIbbLd6WijMSrjpnlDipaPqPQGwO7/hIHVrlPpPp6XYN4kT2EZZPf6aLdgarq1zIIGhBzjXbbSZ+p0W77bmt1+ulvtdVtqK3Lb2d45mo0E01wbtJ5TAMsSJjo6kdg3SVbsnfI6sXAkEme826nrJm0bzuE9ejkGcG517CLDYkm2oHbUxuFPtKwU9yrBT3jdc08LB54YrnUmOnwmellMhVeoHOAFyfl30lTEZ2CWiBbQD8gJ+MqhlSo0TYZjN76+s26DQbBbtb2t9KkVvtMQanVj1GNupYsjqyzE5JPUPme+qHOJN0tTMeZ5uVl9KlakkH1BI0JhOQhnse+Doyik/rqTsohNg9++pJUSNRXABWx66EogILLj49tSVIScD499QlGENhoyhCEwzjUlQhDI9f66OZEBDYY7/TUz3shCDps6KE2AT8dQORAQz/HTZkQ1BbsfTB0S5ENKGRk/L9NQvTEHUIRyO2cHUDkQEFgc99TNuiAhsOx1JCMIJ7Hsfho5kR3QW9TjRzKQguPj2H9dQuKICC3x9dGeqkIBx8RnRLiUwCCfU+o009FHNQX9fTRDkcqA+fn2+WpmhENQm7j0ydHMECxAJzj5aYFTKgN2zntogpg1Ab1zo5lMqltrzjn9V5BVoByirTZlFWhKivoqKsHRlRW1JKivg6koStdvlTIf/Rhsd3uUU0ZYSwBehCCMhm6gUbByDj4H9WAJuVfQgODswEffxUc77uGTake4rpuTfNys+xbNEzZqamnp/Y5yjdfmzhGdowrqFVjn3izM3ugWMcCIY2T8T8gOvy2AXeo4MPLS0Aud2OloFyBNrnUzC0i3cs3+2WWvnuGw+XuSLiahXpLjabC8tBU00/ZSJpvJjmmEQImbqC5GV8tX6dbhgnmA0BgOuZwBkdpJA6WvvKyVatIXDwYEgN5nGDaMoIEnQbbzqtp2VT+Iiqhp4KCy7V41a9RVFdcrve2jrqygnMnWkNNaqRvZyIklaBWmqvSFSY3HbVrm4UOzVHl0QIbvG5c4WnWzTqufjcQxwb4YLg0xfltFpNyTuYy+sldCTw48f3OpiunIVTvHmC9K/mNPum8T1dOGznEVuQpQwpknCpAMDtk6B4w5oig1rPQCf8AyMuPzXPb4nLLoifLyi8axcm2pJQbr4W/DzXLWzQcL8ZWmrnYPPPbbFTUlRLgKpImgWOQN0ooDBgR0rg9tK3jeKPmqEjoTI+RkK+o8uEPJ/8AJwPa4Oy0K1+EuzbbqJ5+NOUvEBw9SyRPEaG1bzqaykjYyF/OSluQq4lcnGVwFIJOM50zuKhxmrTY4/8Abl+HIWotdkpNog5gNC4Bx+bpJj1XNOVfCFzRyHtU2CyeL7e9j3RSV9PcrPfrrs2w19TYK6LBjrKNqSChkhkADKUDFHSWSKQSRuyHTg+K4amTNKA6xh5uOnMHf21EFJiHVC5rjlLQDAhwEm14dcevyumM+8ftHuMjHDubhrw0+JS3RMzTXDYm7Z9sXmpGAQy2e7xvSF3I/ulrgoPYMB30vueCqE+FXLDsHt//AMmz88iTDYyGA16LgdOU5x63DSB6uJ9V5tfaLcqVO4dkW/xB03h18dHh28V/HNPVV1iutfxpNPa9yWeUqbnte4XSxNXxex1saFknZgKapSCoRkZGOu3wrh1do935atN39NRpII0cGktNtCALtkGVjq8Rwzj7xTqtZk/qD59CC3LOlp1iNFMfwk+LLZXil4G8NPi729vK3xrfunZ9+gpqlZ6vbV1qpsSWq5QRjyfaGkpaciRkUrLKXHVHLri4vAmlVfRg25oNtOhsQBJ9QOq7eA4g2rT8MMkC4ncD8RvaNCATqAIC9EK2zW/YlOKqjqJqnYK079dB1q0dPIzl/ONQxMjJIWKnLEBnU/hJA5VSqDLo5vp8tFoo16lZ4a6zydd/ltGw7RsoT+Kbwm7r5A3xsrxWeEbdO1eC/Grt23intVyqgXtO9rf2eTbe4o4e1RQMclZgDLSysksTAZU9bh/EmNacNiuakemrT/U2dPTQ7rl47BHI6q0EvFrzBbO4ud7biPVfK39mb48uYeH/ALQ3xccH8s8XS8J7I5k5TnoLlYrnXyx0XE+/qqqnloGmk6Op43YT05AEftHTTsGAXOvRY3h2ei1lR0ljZBF8zYvA7iCJ0Mz0XMw3Ew3FmsWkgnSxOnWwExciYmQCvqx2cm6nv21bRfBV3+1bWp3tN7o1Trllrq2dVp6qNQVp0RkhqvMilyscjOFx0515PEFrZe2wMQSbAASQSbzoBGy+iMqMNNzW5Q52Z1hGm0QSZJmdTqZXlf8AZl23bXgW8VXjV8FF22huHdGyblc6PmTYFwttB7VBJtmolakkphLkySiiqQIBGrOFJYhDIz47HFalTEYalWbrcETFyAdwLuAn03i54tCg5mLq0M8WkEk6HVupAAMmwEz8F7L3jdFFuOwUt/uNs3PYt0tX1kG0oI5aimaruCK6qKyKIPGICqMcuroiqznLlAeBSadIBtcxOVpOu1/Q7gBd51E06hpscC22a4uImGzf9Z7Ax4M/aG1/KHgs5Y4W+0qsE143pscU8vG3MNhubUtN9+WCpnd7dJWpSsTLSwVMj0sRdA4jSNSCpdm9HgqgqU3YbYAObbNBHqPMRzG5H0C4/FWmjWGMI5QS12UQA07gkC4JuY3J1K86fGHyzcvDj4IvEBxg/CO79s+FXne2X7dvA9TWmqWs2xQinp4aW010rSdLwGgiiqqSnV2EUM5hMf7II2yvSq1K9Go6M1NzfE0iXOkne82cYFx1uMGH4hTpYetLpa5jmtIn8LbC92tkkt6tME9foH5x4UPLHCPDHi98P279lbc5b4qtthrtnXCOpkS0X/b8NHA9dabpLTszzWeonCsswDCnaBZo48Rv14quLa2vUo12kh5dbe5IaQDo6Cd7g3OkLg2VWU6Qp5Q+LkWbOpaTYaDmtZwkmV57+NjxX7f5Ztf2YPL7W3cNt3PtvxUUVj5D2xV2yJ7psi/ezz07WasELRQTTIrqY5YyiVEbLOCFI0vDOHOOLfSY6Q6m4AzZ0xcEzbrrHrZauMcQDMEMQWZclSmcu4iTpc3JtMzIi10y/wDKRtoV/G/go8EXht9tiuF1vvJ0a3C6Oyj7xrY6GVZamoUY6mae4u7OOxGPQnU4NFbGOFMQzLA7CWgD5BcnjfE3VsDVrPu4uZba+YxtblECJELE+Fa7PtPwE8Z86+M3k2Dc8nB3KJ4dtFJcFagsWwFttwSkS6TKmWevmpo4ylwkDyLE6QxRgOxmuxuMayo11Ec1YZnO1MEGWtA2tcC7jcmAAOjwSm8iphcVyijsIAcWOaGucXawSIEtY0HNGYkqGn2mfi68YPip5x4x4E8E3HXIUHH3LFjKbbocGnvfI9jjlkIqVow6SWjb0q4KrM6STQ0nmTuiAx6fh/Bed1KrAc2HPmCGTeXkyC4TOW7WkgAFyT2j9r6uFwtN+Gu1xLQ8auIiQzRxnQ1IaXScuVtz7LfZb/ZCcB+FPZdt5B5c2FBv7kiZ6CttkG96WWW3bcuMMAp56iChmzTxV086yOkrRdS0/s6xMnv9Q4j7QPpktwhym8uF3QdBMyBF3QbuJmwC4dD2XpupilUcXg6smAXAnmLYExMNMWAJvmJXFuN1359oT4xPGNfKvdt84y+z8NQvFN2h21EtJeOTKawTVHtlPJdAvmUVkFReZYpjD0SSRCGMyIqyZz4au3C4SlXxAz1HnxGtPlEgNa527jy8rTbMSTNgfU4ylVrYp+HwJa1tBopufq7OeZzKYmGmDGYXsckEyO+7ms/GXDO891eFD7PHw58IcZ3G3Vltr9+bu2m9BZbpZdvVkbM9opbyivKl+qOkpHGBK1NSH2lkVjEdXYXiGJxjG18fUJw4JAaSYe4bBo1YNXm39EybZW+z+Ewbmtw9M+8OGpaXim3/APY7NOsRTBPM85rsac2xcS8w3jwk7G3jxPJtvZ3Llle5V26dg2PY96Wpq6+yXVah4rfbaSthgikgo6qkrYZqiWUeWgMrqPMDNix7HVQx7HkO8pkFtwQQ4kE5QQ4AADYNF4C7eCwFJ76nisMeaDDzMwd5c9xGb/lJLnWK574o+Z+D5bTsGk2R4eK28+NTccITj3jegL7b3Laq+SBWa57geDylgtFKRG8tRWiWnnw5VGHQxtw7MWazqAeOXzPdzMY217zzTZobzdbkgV4qrRo0BiQXFp8rWeao68saBsRdx8rBFzYHm/E/GP8A5ru+du+IjxX123ec/FJuuet3Du7flmee4Ns+SKsHtFDb7cYmjo7J0iRfOpl8yYQSvIvSC6rWxlNlI4bBAikImQAXzo5zpudS1tgLWkwnwHCa1R3vfEBNQCGiTkptyizW2giGh7rkkySuh+IDe188bW9dh3Lw9x8lWfwTyK1prtzbFgnbcHIsMUzms+7Hjlikt1jdi9K1ylbqlKyvEkcYSWYUcHkaa+LAe4gEMOUACOU1CesgimLxGbUNVmHx9YsdRpVMpDoNS5uSOWllkOe2IdUuGO5WEua5zZIbB8T/AIPvCrW2jgDeXLPG3HtlsWz7fV7bsLSLT1lJA84po7TT2imQS1FyEqhumOAzMhXqXMgd8jKeIx7n1KAdVqZgDALibSL6NaALiQAYEwLW43C0sBSZTDRSZDjchogXLnOcRIM6ySTJudZJScseKfm2njtnAHAO6eONvvHKkW9OaRLYo7d1Dp8yk2/SObpWyhW6gak0I6sYlXvq8cLp0v8A8uqGi3KyKjj8f9to2u5x6tIsvM1eMUW5hh2eK/aJbTO93Pbm/wDi1kEfiBiOt8U+DbYexN1zcu78vN1548Q1ZDFR3De+6II2lhoUdnW32qgT/ZbVQIzArT06gllV5ZJpB5mpieOnJ4GFb4dPWAeZxiJe6xcfk0CzWgLCxlZ7vFxTszoIAEhjQSCYEkmYGZzi57oGYmBErbzbEu9LHC8ksVRDKlRTSo5VqeVTkMjd+k92U/RmHfOuKysQZWtlCmNWgjpCxlXtyC7IBdi1WFbqjWoWKoCnHqQ8eD8fh8fnpm4hzfKSPif3VoA1yifSP7rV63iba1XBHHCLlaJUYyB7XVy24uxcs3WKVogwYsQw+Pzz307cWQQTeOoB2jeVpGKeCT1+P5z81m4duUNPSJbWtlRNSAg+W1dLJEx7d26m6mPbPvZz8SdDxjM2+X396KvMScxdf6rZYaanpQ6U0SQRluoqgwufmB6D9NVmpOqUknVG1MwTtKsxwPXGkLlZCGxPx0AeqiRpsyiQ3z7Z1MyIEoWoXK9VpcyiExzj5agKiRqSiAkMPXOBqB10wZ1Qz6nProl6IZ1QXxn66IcmypB757nUzoBgQWGD8NEPRyobDPyxqFwRDUHTEqAJDj5YzoZkYQiAcj4ambdQBBYeoxjUlGEM49MZ1J3UDUE9tMSiWobj1x66Ad1RAQHA9fjo5tk2VAYAjRzlEAhBOPz0cymVCYfTto5pRAQWX5YydN4iMIDAYPbRDlIQGAPbvjUzJoQT3+H6aIqdEcqAykfX46OcC6ICE/p3A0c90Q0Ju47ZHroh97oBllLPXnSV4tVqEqKtTMoq02cqK+pm6qK+ewGBqZiorHUzlRV1YBzjH8tNnUhaXurc1s23Z6y/XO+2qwWeNcy1dbULDDA34QWd/cAyV7EjvjHrpM82GpW3CYR1R+QNJOsDpquX7Nt9dvp6ur3rQ0UlDS1krVcq03k091qQemNFjbLNBCixsTJhjN0jpxCc9Btbw6Yc03OnYdbaE6CNpOpV2PcaZFKmYsLAzAjQyNSelsu5zLcKyzVW4LtY7TVPUNaKB3kqx5yziSRVHkqwcZHcM+fewVUYGcjLTeBJ32/VDxhSYXASX9RB7mx+G1l06GlpoBCIoY18tOhO3dV+X8BpfEK5ziSSSdU4/do5glIQpJUjGZHVB65J7aMotaTomNdW+zASAxqkcqrP1HHShHr9fn+h0peFZSp5vlZc+u/JWzNli93LeW9tu2a3UwLTPPOqpTp1Aq7kZx7r9/ng49NMwEkNaCSdLG/ot44fVqNBp0z9Ol9Y6I2zOQdtcgW19y7fnpaqlChYJutHWVeru0bgnKsrIfgcMMgahc5pLXWIUxnDX0SKbrz09LSs/crxPT1DmFXgtiL786YCTN1YCdf+EnAGcge98dQOkyVno4ZpHN5unT4fX4Lxj8cHgPvMHJdL4xfAVVWvifxcUl2t+4d0bJcy0+1ec0op1nipLvDEREld5kCrFXYBLMokzkOvpsDxxtRooY67RIa6JLZEepEHTUahc9vCcRSLqmEPK7USB6+h77XBMWXWPD59orwb4sOKE3PaIL1x5d6e5T7K3/sTdaIlfx5cwD1wVkful4fMQpHKB74jLKq4kUcrGYKrhqpDpMDMCJOYbRE6/T4hej4LQOKa4Dzj0BzaEGbSPkZ16Z3ijxe2zlPiazc02qmuCW2xVQtm445atZKqppRJ5UdV9104lqlZ5uiRYceeEdcqw6gM9XDFtXwhYnQXm9wATANj6SF1aeEyE06pkGYIAiRZxJmALHUCx00K8Sft8/AnuPmHa25vH/4adu7rG9oNvw2nlayU1J5cl5sNOyyU14ip1HmpWUD06GR298RxxuhzTuD6bgONzxhatngy0zod29L7bEkjcR43j/CHUWmrQIcCCDfW8zfUgwRFxGikH9i14oL79oJxjvLcHJ3Kl0oeYLfdKfb28LdROqU9/SW0p93XeQyhwatqm0TSiWPCxvLJGVfOdV8Yw7aDZyyDJB6QZI9IcZm+kRCPCPaGWM0zMEbzqAelo0A7zKw3i88Qx4b5k4H8aFVe6qa28Vblq9ub5SipnNTLx9uSc0UstSyMFkkoLhR09fmMBGEkTqFDHOfh7w5tTCOsXgf+bRmEb3Bi916fjmDNClTx0QGuGhnlgNdJuBe/YCNQvYTjK/0+9dvWbdtPf9w7Sg3VZqS6baSqpIxSUdsKRyQDBJzFN0U9TKMh0kmCq2IlXXHxDwx3huEO1Inf/wD5nKOtzEmVqY4PaKlICo1u9wTM36zBOW3lAmJKccwcKbW8UHE3KPhU5YprZDtXkbbVaBJOrIi1jYL+yCQdTey1SQ1cRz1e9KT2Rxq6hin03Csw+T8jpN9xb0hcviNKkKRLpdeCBf5x1BvqJAiLL5iOZOXKnnr7AeXwsckUi7q8VPF/JO3+HZrBJP8A7XHeqK9rQUJUsoWFqijnMSOSAVSXucHXqTTycVp1qZmnU5t7jKSRPwn4hefbgyeH4hlTz0wWzbUuaG23Gnz11X0Z+FznDYPib4F4isex7BufbIrrdcLRuGhktgVrAbXUewS22silHU08UqNFIoLEtHIcFJe/Ax7arKz6rzcXknc3BEWjcfCdF6ThDDRpeMIytgNGhzbg9CNOkm2gXzufboeH/cvAm2eLfFrwJSbP2rw1uDcW1blyHS7dASjr90UVVU1Npv6RKAkc7oa6jkljALdMStnII9F7PY59Su2nXuWG3oYDgeux+a8rx+hQbQdUws5XSHA7BpbBG+v0I7Jt/wCVZT7kk3l4Ct9bZ3ffpbHd6C83aisERDU9PdFmoXir6eMjqE0scsETKTg+QnYEuWw+z7hnqUxZ4IEztJt2giZ+qycfzNwDHAjIHxpcw0RJiSBJgaXMC6idwHxfs/kPfPir5b8cPLu0N6+HThGksHKu9duWOSuisu5d41FILa1op4fMNHWn2m3mGqr1BaqqoRCkkcZmJ6nvhw1FtbDNLqjjkpkgSQbh43DQJLBuOd0wAtzqdfG4s4LGPyMID60GMuVpJa8HV+hfchh5GtDpj6JPsivDJyHufanJP2gPixqYp/FFyzb46Onoa2l8io2ZtKFAKG0QKOn2ZZlWGplWIL1o0IJB8zq5fHcZTwlAYCkZg5qh/qfO53y97ZvQJsIHYvFsx1RkAANpNFg2n1A0l2smeu67z40vH1Q+GPgq01exLBLyN4jd/TVe1dh7GoZQ1dc7yY3ijqhC3SVpYD5NRPLJ0xxx4DHqK685g+HuxdQ0GEARLiTAa06knQbxeSdNCvX4tlPBj3vEzkYRlgSajpkMaNydLaCXaa+OG3rb4qPCP4VvDX4WNp+H7hqj8U427dNxJel3ybrU7bg9rimuG9LxTxUYjlpBXuvlUvmSxVDSU8SCoZZAPX4pjMZiHCnXiiwMB5SMoMNa1skHO4TeARzGzRJ4XD8Y/CYB1TFUnHEPc4RLYc4y505SeVgjOJnQSC4NHp3w74YuauMvDbS8V7T8QlhvG9NqU1Rcn3ZtrZ1EtgvN8nqJJ6qrmqK5aqouFfUSSOJpYCvW7eWGh7Qrhx2NwzqjXFjvDgNaC6DlAAAaxsQ3pJvOY5rldbhDarGl1drRWqkufOYkuOhcSeWw0iwFmiy8nfGJf93V/jD4H8NXgQ5IHil8dUC3On3lV36hg/s9xesns0pMtTRCGmiMFTRz1bU7xS4Mz+Z5srJFrXg6TcYx+JaPCoNiXm+hMRmBJJBgRv5BqRh4tx6vgSym9rXV3eWmJBIc0SXNDrN0IzGS0GYbGb0K8O/Bm9+DOTt47g3LXXHkTxL1e1mrOTeeN9X9au33CZMPBaKSipoy8VqQK7LS4p1RoEaTqclRixlag+h4VI+FhxGVoBLnH+p0lsn/AMgJIbOq08Po1GP94xTHVsQeWAGtaxtjlZcwJJNgHO1MSoneJTxB7w2/xDtvibkflri/ircO/wC81x+9aWmq4vunju2xzpXS0Kwu00s1wkna30UdND5kz3IHs8PmK2AwbHVms5nloBLQJL3Oy5KcTqbF0uAAa4mAV0ONcRc2k99EASS1ri4AU4JNWqSWxFMAnMc0EsaJJgzW4c8B+7/EzZrbvjnK2XrwscbxWWGzbV4mslyqrLWXCyoEWCffMlBJHLUTvHTQeVbaeZI6OBI4pJJXjIGriXE2UnRVIrViSXEw5jDeQyRD3SSXVDIzHkaAvLcNquDGsweenhWiGxyvqCIn/wD1MiwAAqOkue4l0D0J4F8KPCvhusdyuXhr4a2DxduWaVvvW5fcqdVylicKGluIBq6pWK9QlcuTk9MkbZGuXjuO4jENax74Z/S2wgz+AQN+07yFoo8GwbaznV25i6Lklz9BqXzpsJtuCphbYTc1ViK7XAwVUKsk6RhGClvVkHSOlMjCdRZgM9XcHXHygDKPv/Pb5rTiX0fMwTPr8u8bm0roCuvmGEHLKgLH+Az+46SQsEWlL0ZQBhVoSrQVWimCSw+Q1JUQj9ABoyokkgdzoJmoZb5ZHy1CVckaTMoq0Q5RIJGfTvohyYShk6AdZWgJJOPnoF6KCcjsdDOoramZWMViPoNMHqxBIwTqFyiGxzkaXOjCFoh4RylBb1+GdTME2WyQ3ppg5DKgkEE/PUDk+VCbPr8dGVMqHoZkS2UFs5zjTEqZQkEZ+GhmUyoB/LvolyICE5B9PXUDlIQn9NEOTEQUE6hcUCIQCAPjpsykIT4+nrqByJCCwyARol6bLKA3ocdtTMny9EFsfLUzKESUFvh66IcFIQG0SUYQWxjvol+yIagNjHcgaYFMGqV59O3p8NcEuXhQrA+mO5/npcyJalZGpmSqs/qdEP6owr6Yvugq0cyirUzhRBqGKwSsG6SBkdie/wBQO+pKZuq4pftoHct1p2rbfDNbFeF4pK+JKge09ZaMwo6AgRuqSnrLLmNcKcEh6FQtObQ9tfWdrSOvou4MSwUnUzzSDIFhG8wbzpaNbldLoYKKl6tvx0KR22ipl6CWXpfJI/D6huxYk+pfOTk6DqpcSSuUSSfEnmcfu/3os1BTUsCieKlp4ZvLCkqoHYf4c/L10DVOiqJJME/ZTtW61BOM/HHz0MyQhX0QUECpjgkhf2hVaJQWJP8Ah7HuD8O2dSbJmEyMuqx4slnkkpqmSgp6qaIfsZJx5rRev4S2cep7jv3OnZULQQ20qx9d5BE2PS35JleaaZJqGqpVfoDCKQIgbyxnKtgYbpVu+FPYnPbBOgXbk/VWYdwgtd/n9PuOih9yVzBw3xRv/ZnJG4dz8f7Lp70tSu4b9WV9NJQC3UBSJFdg2UqPPrYoY2HcebJ1h+kKNuHFR7CyCTsBOYk7AakQJMAxFomVtpUs2fDNccwEhtxrcuJMCAOpE7LXr541Zqm4XuxcceG/nfeFJRW2O5terjJbdrW2qppvNMc0IutRHVy07ezzEMtMSQvuqwIze3hhBy1ajGGYAJJM9IYHCb6E+sJGYRxYKtM+JJFmtzRpuSxsibw4jeVx/dHiT8VNRdb7tuz+HLherttLbmuQrpeVqt0pVIZYaZZYrP0STiWORlMOVCxkdRIxrNUw2GN/Ht/2G57S8WAOpiV1sDhXhzPEpOkmIlgtE5iJdExBBJImV4gcobU8c24uf5fGd4N7d4Sqznylt1xt+77Ftvc1wrn5rp4ZGaGknpqqlpaasrqaKFp6aePpcMkaZZ0VG9FhTRNFuHxT3ASMpLC0CdYJJyggxfrYRdYvaLB1cJV97wtMCBDx4jTYcoENAIPcHqCYkLsNu8anhF5O25wtzDxRT7mvPH0UdPY5tu3KoqZ7htC609umC2tLbRhq2a4wyNThmiiKLE000Mo/bgYK2CxfvFRj2c1zYSSJF7nKGgbkgEgA7Lt8H4thvcmONTLEAnS83mxlxM8t3GZykBeiWwfGJwVZd0cXXCs8SFiuG2txWa2bfbZO7rjJYr9Q3Ko6DDLJT10VIvS3VLTsio0YZoT1dBbNHEcDVY5znUyHC4MGIHV0m+hmR+S5OELK9JzW6ZnEuOV0k6BrRLo2gifQyF8Wn2iHDnI/gR8Su/uUPCPv3efH3At+u7TW+6bJuNwgoLHO0s00VpeuVY0nC+TNLD3KlFfpHSgLd/B4pmOoBuKGZ0aGLzHMGzO4k9YJ1hea9qOGYjhGLGJwbi1pvI/CehMQL3Am3lvBXudwHwLWeJ37MSPf3PUHI+6+Vtw7aPt1T91VIramiXptnsyMv+z1Sin9lnSeQYjn8qUe4jA8fE1BRxAbQaCAZBMG55pFyQLQdyJ3Ij2vDKtXFYFjaroJaQ4eXYi4gAkySBppbUqYP2UXKe2uVPA34RpLpVvunkDb1BfOLr5b6yJZrlQ1dppaloDRR46o43jgpnKSDsWGG6yQ04zTyV6j6dpAfbqSAfrOn5LB7PYl78M2gQAGnJe0xYz1t1vGoheuO3bpUXDZVJW3jbouFDJF94biq4Fkie3IaOKrEsJYl/2RlkVVhxJkEN0EsDzajMjy1lhp3deNtZ3vHqupLXkEul1so23EbaxvIvN4XyPfaZ8c8qeBTx18Och7tvFNN4eOct+bH5D3Tcau2vPM9/sV2innllooY1aln8qsV2pYA4dJHCgMOlfccKqNcA1vmpZmgD/k0tFybyZvYTGwXguOYpjKrn0z/JqQDOnK4ERvAaAJdJPMTdeunB3iMn4x+1l5T49mhXj3Z3Nu5KmqjsU7Cnj2lvSGgpJoapRE5RJ7pboZgWmCmaqopT0KrOG89mdiMFLrmkPNryyQWzoMrosJhsE7Aeix2CoYAsaCXNe0Ty+ZwEg3BJaQTpaRAlwlbb9pLt+38k/ZF/aD2Cx0ENNtPbFNcEtEbSN7LXU9vvkVaLhSB1VxJ/tVQM90cplWKkEph6j6WLoveYecvrcZQCO8fW90/FchZUZlklriTazizMb9BA7yIsvnt8UPMW1ftTOSPsS+DqjlLbl23fX7Rt+3+Qns8jo22LjUVVPDUpLJJ1eXUmmtzTFRnod+sf3gGvUYOkKWIxNV3k82kAw1ziNNJMWt8ivD4yvn4dhcM3WbCQTHK0E3JnWA6CY6QTIPxA8bcUeKL7WPgD7PzgStoePeJdpbXsm3tx7WasnpbVeZ7LWT18FsMMUZy9NHX1MhL9QkZ5yXLyZGHgmMruZUx+JBzZiQYnYNJiQALQAIgCAIXo+NYWhQq0eGYc/y8hLw2BInPBJBJLjzOnzSM1wF9Gfi+8S/CXhZj31a/EzyZVbcsNu2vNc4vLdI6S4qi+TbqWltiSZnmlM7wdEnmmX2Riwjiw2vKVH+Ly0my6bbuk63IgQOb/jIkmV6nhNLw6bccSKbJh2waJBcS7XUQA2NYaMwK+bbi+qi5m5K3L4jrpQUu/PE7yXbKvbvG/GsxkZNkbJolNG9duFaaR1t8EpiWoqkUCR+0EMUk0+I/SPoeHRNCkYjnq1BcA6tA/rIAho3dqWtaSsTMU6pihxCo0kSWUKZOVzh+N8HyZy67tGs1zEtafcrw6eFHii1WLjne/PXIlx8Q/JHKO2P7S3Xd92igtlJHQU9HRyRUfkHIjoKOJpBHSVMjU8UaSySIZWZytfiYwtR1HDtytonNzHMS4m7ibCToXAT5WtMLPh8PUxOHfXqukvmmQ1paC0l0Ma3zxP4RzPc5znX04rvzfHiC+1/3Zf+JfBnv68cCfZvWKplp9y8o22mSgvXKtXB0F7PtwMFMdDHlUaqwIy6kkuFSJqKOBp4el71xYZqjrspk3O2aodgbxN+gmS3FiOJupVBg+EkBzTFSq27ac6tpjRzzo534fKIEl3pt4bOA+AfALx7HsPw7cawbUoEtK3C7Whuh7vuKsNSitNcq+QM9VVIruVMgK9iEwrdIw8Q41iMdUyvMBsAASGt10He0kyT1WzhfsxQY0hty4kmobuMDUm1j0BETosD4uuYtmbO2nvmXeHKVt4qs9so7fPumuraiBKSw0gZnpRWRurdS1FRVIDAcOyRzdJLFQMOGqAvFs0G0TJIAs2NSACekwN5Xp8DhYZ4gAEgwT0NiSTECBEmJm2hUWvCP4Zrt47fEdx/9op4i+Oa7Z/Em0rKlr8Pey62l9jqoaBmJO6rpAWMkVZVMvmU8OeqGNYpGPWVJ9NXqu4bSqUHf/k1P9y8hg2pjbNFnn1HWPnHEMTR4jWZVoGaFInK4i9V277i1MQPDaRfzRovYmsvm2RcU2jQ3Wqrd2LE1RRUnt37cw9ClnUt3SPMiq0uQAT6lvd15NkvEaDc9Ok/oNTFgvVtpVGA1nCGntv6b6aQfgDKzw2XcIaoy0G41tJUo1PaXj8yiRh6sMgOc4D4B6QwHYZINrKrQeb7+/vRZffbXZmF5O+/31jdbPuHctktKQy36rpLKqKZZ3qqgRNHECFysgI6gWZV7epIGMkA0ufcN/usuDwz3Tkv0j9Z7f5TKn3Ba5Wd7ZUK1xlqEYRlSjSRAhet1PoG97BIB9B2Jxp4IMH/AArnYdxjMLR9dbenyW8U6yJBEsxBlC+92x30JiwXPcQTbRLWRH6yjq4UlWwc4I9R+egHWsmgjVXPcE9iNTMU4KET66bOiraBcokMB8idQuTtdshnHw0CVYFbSzZFJJ9MaAcNVEInPfRBTNF1bRVyQ3c4z31FEIjQzBRW9NLmVgNkhj3IzkaherEPUJuohtjB7HJ0perGoepnTwEJvXTZ1AkHRD+qKG2O50S5HL0QzjHxI1A7ZNklBbvk4xqZ4TBsaoTY9T2OjKOVCPx1A+QpllBf8R9NQORDUJsdhjUzEaqQgkdifj8NN4nRGEFgPiNQv2UhCK/L10c6YNQWGfXTBymVAYeoPbQzqBqCRjGmLlCE3bsSB20cymVBYDPY99TPKbKgt+eBo59kQEBh2OmzIlqAwH+moHiUSFKssceoA1wy5eFyq2e2NGUYulAj46EpS1V1/HudFTIlBh8hnUJQyK/UD8RooZSr5HrntoSlhClkdU6oo/OfP4eoKSPzOinDL3ssfBRzvVNVVU0jICTFCzBhGSMEk/PGQPkCfXOjMKx7xlytHxWs7jtsscyXS1SVEtfAwaSnapIjqIvjEUbK4OAy4H4lAyOo6mYeivoVTEO09Pr6/oSn1huhvFleoild5iz+U8g6fMB7qcf4eoMPdOCO+QNJsjiqYZV7W0WSsteJ7fTPNJG05jDzdJyFcjJAPxx3/IY0Q+yrxVEteQBbb0WaVg6q49CM6IKykLH3CshpaeeaYF6RARUYBJRCO7YHcjGew+H5aOdW0aZc4AanT1XN9tbvpqV7hTU73G97WikeKlrIYjL7OyBR7KcEvI+GUqQvpkEk4yjX8oI3+/l6/JdbG4AyA6Gvi4n6nYKPfJHLsu9dxXviDju33jce7BaKe4XWjq6OVLOKCeaWFaipmAD+UfLlxFG3mVJWMKBGJJR0MNROQ1nWaDraZgGADq4giAfLOZ2wXRw2GZhi19UiZIbB5rRN9BHU+W4HMQFgLNtDgfYm9dybor9u0G69908FvDX++UFK9ZaIZ3ZPYLcjoqW+nYx+bHDS+4xyzeYwyb8VxqsaeRpLWONwHamNXGSXGDHbQAaLnD2efWcyq9rZBcWgAwI3EXN9S7mJvKitdq3c1dzXu2npNtVEFBZrTaEpaIW2atmnkkmuMwanqaqRaajk8k07PSP15DFsRK5dctDD0zTBBy3N5a0WDSZNzqdQB0kkQvcTlZLSCXZjcnSzRZovcGDPpOqiFDtTeG5vEPuXb2x7/wAzHdlu+7qGlrbrSUstVstJemeCtgsy00MdTA8grWWoSJ4E6/2lQsasJd7qEtzOblBnc36jMXWtEjMD0aTAVT8QynT5qgJEyAIAmReLkzAFnGJ2zESg3l4bPFLS8KcWcIbtudg3LaEq5bJQRW2appaG30ywForxf6akQy1NQOjzWWCtVBMsUaA9Zdb8+GdULmkkRJJEwP6WSYPQFzJMyYAg+WpY4PNSqGc2xBylx2Mm7BrIbEC8kmB5C+LjwC86fZzXWyfaA+Ad+VrndbXao4OYaeW7PdI99Wz3PPmwnlyxMoCtJSoiLGoDo6+VID1cJiaeMb7rVADTOUCRe+skzqYN/wAl57E4M4WqMXRvVF3NIGlvKIiRAvLSRsZJXr7xdv7gfxc+Hzgzdtvp7furjPc1kpDSQbztS3CrnQExyxRyVPmxVTrIkmUhkPs8kbB4yWjUefxNTEYWqblhJ0YYH0Mi3WCRMRdezwGIw+Ma6GirF5IbEmPwwAOhgEHTNAKijyR9lb4VPFHs/lDbmzOFOFOIK2qo7nbKS7wsaMzVFN0w0N2pKKkWNKRzM4PmuVDxDyjBKjhl2UPaCqCH16hcbSInU6Ek9LxczuIhDifCMOWOomm7K6NJsYJMC4OWIECDzGRMnxh+zP8AG14z/DFzPR/Zv7z4ftXJO5Nnpf7JYLEl7O3tx0FShFU8Fpr58U9SCtOamnhmVPPjwiSYaNT3uL8IpVCcUKmUODZJEtI2JAuOh6HUC68NwfjVXCk8LxDczQdrk6iInKRBJFwR1Oh7z4T+bNrcD/agc27Q2KNkbas3JFuqd67foYbdJZ32tfIKB1qbXdrVWBam1SzlGlUMCYnKVMcjwO7PRjW1BgCMUbtsSTYgmxDgC1wGhynTlsdO2x9F/E/5QOWocwAM3Ah2ZoIJJBmHASZkQvae2+IWg2JPxTWWt913vi64WKwXTcF0t9lmG3LHt6KU1dZMszA5WF66NmdXkaRZZAO7e7xjScKlRzm5Q02JIzTGVsCxgkcoiB1tf0uJa19MOY7+Y/NDRBcTY3MxJbMk5doEgBRc/wDKWNu7e5E+zq21zDTtSz7q2Rva0X201DnraeKrSWmnOGwTG3XTSDGQ4iBXspOr/ZLHupY0MNpGnpBH5b9bryPtHwgHA1pAhon0hwbAjWzjpoV2XlTwu1viU8LHPm+uMbBsSx8u0lj2FzNs6RaUVr3XdlDbTd2NcOny5DULUNSEL1AR1DxsGQINdKljW4WvSaTLWue06RlJDbGBcRJPUTqq6mMfiaAaWkFwABuCDJyRcnKLAT3I7xj+078Qr8rfZB8peJLh5rhT8a8obc2hK9rmqJCbNQ3aamp6lJVVWLNBUWqogUOwRfNcZJ6BrGcIWY5lF+rXOnvALh01m5gm3qVtpcQZ/DKtVglxa6LRBMMPpDXCQIkidJXyt7i5F4+8Nm5/s7+RuLdl1Ut52/x5T7v3HX1VPPQNui91dZXvOySnDyQU69FEkqARt7LIE6gSx9NWZUquq0m2BAa3f8IuR1cST1iOy8TSqYXCMwleMzgXPdto6A0Hs1vwJPdellqsu6vs09ueEPxgb7rLJvjxepuOm5n3NaPu+R7s1gu8NXQXWmuNQrukRp0mtzr56QdD1RKPIOtY8VSu2pUqYKh5GAsJEQHQDM63II1MxMXk959EnCt4li2y+o4Pm4zNMAgDQhrSCNACS3ss340PGdtDxkeKzgjffPG16/l/wzcdWVt/7q2bS2+a21lVLXyJBQUKzGQNWVFWDbpgURIxFMIlidE6ZOfwug7DFzqLZrOhjZgjNc7TAadZvmBkCwG/2idQxjaWGzZcOwGo8gOs0Q0WMZgbwGnmFw85i5fR79mLxVf+MrHv3mXlDaO2tveIfe9FbbpU7fhtptS7ZtMqu9FYaag6Io0pLfG6wow8paiaWpncFpQVwcfxnhtGGLi5rTzONy4wMzi6SBOgb+FrQABzLdgMDTxIGJFMMDiYAjkaHGGAxmzE89RwkveZkgNXkDzkdw/ayeJG78HcP8u2TZX2dPE97qqy+bmu0c9uh3lU1M9Klx29RJE9OaqmgPWrqJlULJ19QzT9W7gmFp4WmziOOaS50BjTcmCSHGbDTWNoiS6M/tBjMTXru4Rw05XCTVewuhpDSCyQNTJzf90SQ2Hew9x5V2De7xw3sPwObeua0G25aGz7kjsFRHa7JBsqGeNqmOmrOhkjWJ4gkUsjxKJGmWNqiSQAZKPjV6z8RjxANzmBEughkgdSbNAJjRobJXZPD/4dhRhaBaQLMaOe5HMR+EkASSDc+Yg8pl/U2zctLyHuDmzcu4bLQLSWySmqKg1y00O3reKOatlSu8yMM/T+yZpnaFkC4VUUssnGNZlGm6nMiTPeIFo7k2vJ3NsuugXOZTpZRJiALiS4AR1mLWgC/Ur5zuI+auBPtGvE9vbxLeK7lnjG1+ESh3dVvtDjG2zT11133crYvRTXa60NLG9WLcnutDTSDDyZLKyrlvZYDh+IwFBlalTc/EkEg5Dlpgm5mMucydzlHqvOcQxruIF+ApuazC04a4l7QapB0kkSwamBzGNtPfW5eN+uuO4dsSeHbgLxT830dRDU0tyq6TjWstNNRKTEY6ySe8PRCVIsyL0ISGLrll6TrzA4LiC53iltMATLqjAddgC4knb9Vecdw6mxtPEPN3NADWvd1tIZlaNJMkjpoU22F4prJs6hqb/yB4d/FfsyiuEqx3K+XDaUN5mmrMlQ1T91VFXNCEJiWNDGEUOvSOk5JOEqOAbRc0ibNa8T/wDbLJO5v0toN3EX0/EAdIIn8Dw0N6CxGU3NzfWZupRbb8W2wb9dLpQxbS8RVbX05c+V/wBku5oCkK9PVK3nUKL3ZsdIJb3cBTov4RiWMzvaI/7mfLz6rzVXF4YlrKbxJE3m/wD9enWJQrBvTZ/iG2JtzxBUG4Y6biujqqu52eshtnlVdHFTNLDJNXmuj66RiY3LQGKN4QF8xiQQtGLp+6mKoIfF7wBIkC2vrMEmw3PT4fiJccPRhxdAvNzP4QImNLzJBiNFhNw8n3zjCh23f6O40+8RdKhXkjuNBJRivEhTpNLWxxJCqoCD1OpVlaR8knJqe0tZkaDPr6ySNf1FhC6tPh4xVQtJDWtta5HaJPyEbXAELql05Iv96t9us1i2vvW336veH9tDRJPDDCV6pMVSyeXGcBgshyw9RGT7ukpg5huAeoH9/hFxuNVlZw+lTcXVXNgA9ddrRf8ALv17Daqq3rSRwU09PhD0N0oY8ue591u+fX17nSuqSZK5tWm6czgfzt8Flj2J76UP6pEnTZlFWlDyorE+upmRAQSdDOr4SG9M6WVEIkk/HUlRW0wKtaIVaYuToTHOf56TNZRI0M2yiG/r89DNKsaCh6ElWKs40CSohMQfz1C8KxgQ2OB8NDNNlYgnTZlEn66OZWtCE3r651C5NlCQfr6amayIQiTk6mdQoLn4ZGjmTBsoROB641M0KZUJj3+P7tEO6KBpQn/MaGZMGoR+h02dQNQW+Pz0cyYNQHOiXQmhDY4x89TMoAgH0OdNmUhAPqdDOiQgPjJ9Roh40RDUB+3YYxolwF0csoTA4PpqB/RANTdvj8tMHolqC3x740Q/ujkUpiwxntrjucV4NXBB+OgVFWQPU40FFWRqKK+e/r30cx0UV8nGPho5t0IEyraJeirEgep1A9AlM6ytiolE0rERorSOACSEA7tgeuMjSvf1VtKkXmBvb4rVqivF1nakno7ZU0EtPBKpnJB6ZHKjp90huxHoQc9j89KKl4JWynRLAHtJkE6dQJ+9VrFVXS7Le6VS2O83SzrI9ZcYaalLozsD1VEABIxhQXh9e5Zct2e1gkwNvRCozxAH5gCbCSZA2Hz0PToFslqqLfRbbtz0U9HWrPSRyQVNNUmpSpgYK3mRyerphwQw7EFTnvoPeBOVLBqVS4kwDva/7rbLm0aUFWZJzSxhGJkDEGIAfiBHpj1z8Maj4IhZKXmBifvuuNLuHd9bV19jo0cXCnXoSqkgWSKWAoh89pRIgYBiyhQASQc9I6jqumSQSTb7++y9C7B4ZjWvdo7aTr0iDHc/KTChfy9uLlLw/i63Qco7c4/sd1qqiuulzqbK1XHaZehjFJSxTzNTxzSuqRLAC0R6mmIynQ+zDUqLhDQXEahsS7tMT3LstgI1MroPazFlpa2WAES5xAbprEEgaXLTJgQJjNeHLe3GWyds3TZlNUCTdF0utRSRtRVMl2uF4qjlSa6PPmpII4JVSRnEPk07eSyIoiW/EVn4gtEwIt+FoE31tc3OpJN5Ky8ZpVRVOKLZy3JjSBIAOh1s0CxNxcldjks1duGRtp7i2FdayqJklSVnMEr07MwETyMeh2iRR0shZhkEdwSec6qRyuIgd/n1/T8ldRr0wPe6T4BEGRp3iNz1/VcVh2/drTyHuXaqXGw7msVwpZbrSJW1uKuKYdMa00/7MrGEg6ZI526iFZl6UMaFrGFjWTTMOB0vpqSDPWAQLknW9u7708ta57CNBI0t0GrpJ7abyVt1k403DFebc10iqxR1sdVeapS3RWRVY8oKtPXiQvTxxSTSiNAERSB6AkNaa75Ja6WiwFo6SRFyRvc/Jcmq+hUpkG77Cbi1zAHeJIm9zdMLhy3vzjarppeS7bd5NlvU1Brb2kaQfdypGDHT1x7RLEzRgLPSlYyzJ5kcXX5pR7JBLNW7bb3Gsx3i3VRuGpPGoEi36mNet3SfyUoW3HtG5WGxUNWlnMFdRwvFDTTlzLC8ZBAp4SXKYZkPSCG6iAT30tOq596fN3F/r+645wlVr3OJO9nCPq606G9xvsvj+l2pxH4DPHjH4aV5U3Dx34IeQ9xDdXFl2qoqmGk4i3yJUV6SrgqvLWa2lWnhbzWCPE3vspjlkPsapOLp+9uZ/MaIfYczeo1AO4AmOhBAWXCnEcMIw5INJ5lsHNDtQ0kf1639QQZI9uuO+YuIt97deycMX3j+77021uGvTeKLevbqB6CJWqbjC1RDkS00/mxyRSOPLiT3yRJTNFrz2J8TDnPVBY0gEcsG1hGYyP8AkR6CZC9TQL65OZ4c7QtDrtc4wJABvFgLEkgaErx2+3P4PTedu4++0/8ADpVb223zps+42L7zrIqdkq7jYfZ2qrZfgEwYxTyQSxeZIqebD05yFTPo/Z3GOZmweIGs2JmDYFp7mdBMHoZXhuPcFOVtfCASwEktmPMQY6xrItBN9FAr7S3xbeHX7RfwieFHxK0m17bsPxGbZvX9nuXmtDLBVWqmmaNWejif/eaSZ6kVEAXPlDzYm/C51fw2jUw2KfhTemQS2dCdpO0RB06hZcU9uJ4b74XEOY9gkHmaMsHeTNsskz11Akt4PfENvStk48u/jJ5W5ouPhbs227lxXbuT9t08tPtDc1HSzQJS012Cwedb4V9ro42rJkeCQiHzJIT1A5sTwgAur0qeZ7znyuPMDLgSACJFiQAZEGxhej4H7QGlRp4Qua3w7BwDXMuBrMw/KI0AdoDe+2eKbem9eQfBb4z+BuQNn7l3bd9u7Olvm2t4XTf810ium3Irt5i1NHUIjQXFaf2KjomK9AVkHW3Ueps2FrAVaVeiWtY5wEBomTPXmGaSQZ2sIXRx2CbVo1sO7MXNa8gEwCACQYENzNBzEEEklepf2Q/i0s0vgs8NlBaotjm/T2i3UcdDPUJSCGupLbTU09VMIUbpXqpV65ZOkAyAvgyAsPaJr3Yx0G1zoTAJmBYCTNhOphcT2ewdPE8OD8QSMrQC6RzCXQBeYA6CwHQLxc8dF15G2/4V/tbPDHZqimuHh/445I25ebVPbqillht63+8RXmK3CSJX64oJa27e6rJ5ZaEd8so30Sa1TDYt1i6Wb6sY5pOg1GUT6xol4mwUqGLwgEHJnuCDlcadgCeoJ0kiDuvLzwt2DbvjB+0I8EfGFx3ZE+wdvbN2va45rftQ3JoUs1mNdNRi2O2KuU1q1MTFi0crMXKMhMR9DReaIrYgZiSXEQQDchrYJEAARBIkATrdeGxDjjX4bC0w3lY0XJDSbudmIIOpMxoLBfUz49NhcR7N8MXKm8rvxBvG42yC170s26Nzbg6Km67sulTY66F7ldrgcSVEazU9NTrF1JDHNTQ+XF0wwQjxLOK4nlptho5cjR5QM4IIBvLrnMZcQZJkkj61Q4FhXOe+o/OfMSLQA0zTAFgwAzlAAAMWEk/KD9mLszlO58jSb/puLLVyptS3VENbQwX2719vprjuek8gUTddBTz11caQ1McopYF6UkmpZJGREzr1vEsjKPmyEggGAYBs4wS1okcuZxAEuiSvmPsg3EVqxzNL6fKXXyyWiWMzEOJFs2RrXE5RaIXspxhvz7Rb7UblTlDhba3JS+D7w37bqpNp8mbh25eXulDUjyxF93UFdPNI1XXygVbdEDwUyRN5j9+78NnDeH4bDtxeM55uwAZcx2ho/CBEudm6AXhetxvtJxOvjnYPAU/CqgcxdzFjRqc0WdJ0ADyYzHMLT+vvgq4T8JHhp2Pt7gKu8QfMc22jT2+yX247jqJbJY6y5tLC9XR0JEtreVpKh3ZYqR3jCTqWHmAil/F61ev4mRtNrrTcPyjmjNIfFp2BJGq6/B/ZunQpeCXh7oc7LIIcdMzmwQIt5ibXHlXqDx+lZbod0XrePiR5NhorbXw0i0NdV2eoEMkKGZlqlNBE9Rk1UJVWRcFwgz5agcDE4+mxpqZLmSDL9LiRLj35iTMEzqV2m8MqBrcNQa2MsGGBuoERlIDbDQbHoV4veLbfG5PtFOc67wu8Ocz78vPgs27uWy3HxA77Fwihsk0EvskI27SvBTw+0z9Pmswz0xkBW7gdfovZ7B4eixvE8W0BgzeGDmJe65kAu0sBMbiNQvO+02MxNuEcPH/UuEVC2BkZJ5SbkOfcmHaA5oGYD3Q4/wCMePOINj1G2+JLNuvbdrtUYs+3NuWu9Tx2mhpj0JTNMlcTFHWeX0oVEjdXuKeti+ORjeJVcWQaxDnTcm3qGi4IjoAOkABa+F8Lp4RzWU2hjALw0F5A3zNAcRO776km6kyvGFPVXLbN93bbnul+UGngmnrWdqJC5JXyoylLKoCRnpCYHSD72MjI6p4ctYRBvMXkXsTJH0Cp/iAcHBhIDbxoCdL/AIrzuTfon+3KSwX0We7pSypJT07xMk7xxxzzzYY/s2bpPQDjPSfeJ75XSuaWG4ubTPz+e3aUa9SpldTmxMxBmBIva0669Oqbbtpdzbks287Rt7dtq2qLfVsXuSUsk8tEYitQWeOVjEyhGXqkZXAALBSVxqphaweJUHLra3Uai49BB7hIKjaZZUiXOGhIgzaLXmxgTqbyF5qLHxrzVW1Fj2hxnaGpL7BFT3qa7XCtro90p7RB51TVUMRb7yZ4o6QC7Vvks0MrBepUaHXXc+sXtLrZYIAAlovEO0YJk5Zc5xF7mR2MDhhhmB+aQAQTmgGWk2EXIGjWjKA4XAhT4puMwd6W611e7d0UFDSUcyUlusNQ1poKiHrjSNHpwXWocLE465MAguCoXpBynGNLCC0OcbydZMkkREaiZm+8yuIHvZFRgAbAEEZogbk6XNg0D1MLLceUW5uPtvSbQrLvFuhkq6qe1rMkVFVx0zVUrY6FHs5eAt0YQIpiEfu5JLZ31hUggxoOu3zvv3steMptq1fEIsdY00EDrGwvMyV1+y3utuEgkrIIKhkVCjCk8ueok79gjHqjPp+JRgA/pXLhYn77rmVaLAOWR1vYfGL/AAW6U9T1pBHUtTx1rIHeJH6un54PxAORn6aOcbGVicw6gWTvP79NugGykFwPTB0C4BMGIeT8z+/Qzp4SSR8xpc6KEWyPrqSmDZSdNmThgSGfB7YOoXXTpBYnHwOlL7Qok6XMmAlIY4HqRqAqwNhC/PQlMklh8xoyjCGzEnQThnVJPx0MysCGSfmf9dSVEFnPfuDpgU4akFjnRzFWAJBPz0uZFIYnB+GgHBOAhHvpsyYNQm1J2RyoZ/LOmDkYQSRn4aGa6MITj0xohykITenwOoHKBBPqfjqAwiAgse5Az8tEvRA2QXJHbUL1IjVAbONTOSmyILZB7A/lqZ+iaEBvU6OdEBAb19QdQO6JoQ29Ce/7tHOdVAEA5wcDRzI5U3P56YOuplUoCQNckvXgmthX0ofdQsCvk6Jch4at1fI9tHOp4av1HPr3xoh6GRY64XBbcaeomMaUrOsLuzhfLLEBT39Rk4/dpXOi6tpUS+WjXX5K9TcYYY6OWZikbzLGpx8SelR+pI0HVLAqUqBJcBqAmlfeIoGCI8TuJTFnPuo/lkgOR+Ek4Hz76Dqqto4RzhJG0/CVpG9KuC509DFT1O5KG4B+g+wMEmiDAhx7w+AXv8Pj8QdV1KgJuNO/+F0uG4dzM05S3uJFtOq5zaJrrcLs9HLUWCe/2xaeoRZw0E1db38yINE4HT1Ll1YqnT5igdgwwKQBEkwD+fTr0j5rbi6gYAGtJDpnoDYzHfWCZyrrNi3NRlaq2XZ5qS9RzSQtSTqOtiPeTHSSJGdSp90+uRgYOrDXDbE3P3C4tbBvdFRg5ev0nsB3XC44ZNm7s2VteBpoeO9110tbb1owqy0FfFDJVyUM3USVppwhZfLIVJI5kICzINaGHOwuJkjb4xPeJ37G910n1wHPJbzttJ0vaRpeJ2vaLhSSu8939nVaNV9r61dJUHUD8wV/M47Z7aofUMWXJw1OnPPpeyjF51iivN8pL3uGuguFbWw0poYIZKOgiIWVkp28klnD4aTuwJV+691RjQrtYc4aZG9j8Y0t3m/e49e/DVH0gGtBbGurjoCZMAdLAaWO4c7c2rxbbLL99Q2uy026b5TQ1Mtc1NFULWzqhJhVcOAIwjr5IOAkS5yyk6ur8Rh5p03GBPx9f1kam0LAG4qoGioORtst7C0GT1tB1kzoVFbeW2th8Ic2cYVFPs28763pSXS4VFVtva/VdrvU0NbbZKVSlKxQ+y0U8cbr55jWNatyhHknq6eCqPfSfTAEG0mzQQQTc2BI2mTHdZ+JYqrUpDEtqFrSAbgCYd/xlzpJAOUFoIE3K1Plbd3iE52tlTPtPifi7jm6/cdTdbVbLzVVVwrqejeRqf2q6PBLTW+keVoJRHTxtXTHy5gMdDHVtPCUKUvdVvYGGiNjALg5z+8MaB/VBE24Oq+lUaxzXGnOpMOzRoGtJLQA4S91RouDE2HKrn4SvHqtDS7ru32gqXHcMlLUywWu1caWgUcLMDGlCtTM0s01LMG6GMillKRN5YA8o5q9Th2bK2m/1NQ+ugbaNYB+JNxdgsbjnEk+GGg6ZCbDckuFwPxQBMxA12jw28K+Ofh+7b62RavGRR7+3ozw3SGy8l7JirnekkjYSVEVXS1VPNT0bVMdQypTtOqdS9f7Qui6HPwXhimKTmNJsQ4H4czbmIm7d4783iNWrUb49Z7XkSNC29rQwkdgXBxgBdqq/ED4huL6uaxeKjwo7i3Xsi4UE8O5tz8NxzbrsVGqGNOq42poYbpCXiaUEQx1OUHfqA6tDD8M8W+EqB8RZ3I7ewk5Xf8Al8lkxWNo02Mc8ZHfhzcw0kw6JidJYBrda9wr4g/C5xulJs7wjb8405e4rWSWah4/sF6obfubbkpyq0Fto6+WmlnphI0rikqDHNEzCOJpExFG3EHPLoxjTSeTq4FrSdzpAMbgZTqSIvVhaOJq0PFBzta2JBzkAQb5cwEgGTIOsgmE98W/FvDX2lvhvu/F62G/764nvdtlunt9utUaXO33dOuKI00kxSFJqaojqFqlZgFkjWFi4eZNJw7EVMNV8VroIiJMAjrOsEeUgGfMNBN5wLHUizFtABka6HYRBOboCQQJDgJEfPHw/wAk8kb85IrvsnvHrY7q/ik21HS0O2N+2OqjFfWWmniSSOpjuFM6VM6tbjMTDExepEahl8wS47GPw+T/AK6iQ7Dul2U3Gb0NvNEEwGkm8Qr+CY6mP+irAsrjyuEtLmySDtl7m/LMCV6Dbq4J8SHOMlLtLws7/t281t1ra01M+/qisnjpZlCJX0hqkjiklhIK08lBcEugD5A8ry2bXNpuw9SXVx4YN5F5N9nGQSd6ZYNzO/puIVX4Sl4oeKgJPKYgDQXaHSAATLhcQJk2+KDxCcPc5eD3kTmXw7bpr4dtXa5WelgulNa6sVNuu9ufyrjSCOYoqzxpIkBEigASQt0nGc+/D6WIy1GmQ0mDcXEtNtRqddrwvh/EsNisDUfRIjONLGWm4i3b1GnUL61vs+rDyluTwV23kzgep4+2Vx3UXWWzbBsu46Casp6GOc2633ieslkdneirLibqxo8BXMKABgwOvM8ZFN2LbTqEte6JywMsF/hxH48t57yYgz9N9mqlMYItpNzsbcl087srS/4AgibQNDpGO8U3gP5S8C20L7fvD/Z9ybi4Spdi3y1b14nudZ/aKLbj11skparcO0pmEXUE8+aaS2FYQU9pkjVCxRcn8WpYouY8inVJEOEgOgghr5mCYgOk7STvMFhn4djcThyalAzLYjLIN2tGw1c2wMiBaUx/8mx3nJ/5tqbQp9p128HhvF5r2kSCGf2WqppKONlhMk0ZZnpbxSn3AzHpz0nB1r9p8LUc/wAUOygDSdZJkCASPL6d9lw/ZLH024EUi0klxaSNAIDgXHpJJ+aid9vRy1eOGORefNq7U25cV4j8S20tpXAmtqEpqqhu21riIPbPZlBkME1MyU3lz+W5kQuVHlgGcDLnsYyqRnouLo1tUaRBOmYG9pgbyUfaGqzBte9vN4zHMkaBwc11juIN43gAxdedn2LmxN02z7VDwn2ba+9n2deq+wVt6hu8tvSRqKKq27UzuY4XLrIwSR1RmKgkBj0DIHpeIOacLXzgwBBA3Ac35TbrA6ryPB6XhYumXDNmExpqDAPabGLnQL6M/wDyhLxVW6zcKcdfZv2a02jfHPvKFysk8NbT1bxR2W2pckjglmiDMySVU6rGkeSnlCof3sL1eK9lsF7xixWLgGMNyY1INvgDJNosLTb3XGeI+BhajmyHVQWNb8sxJ1IHl0MuME8pCgduvwv0O9Nubd+xa+zVls++d+2Gd7r4iecfPNJbaWtcqlVbIp1VmkfzIkQU4aRf9mjiRQwqJF7xxTMY7+JYg5MKz/babl8aOy6E3me8zlDZ5VBtfhOFOBpicZWAzkD/AGmk3JdMgloAjlcGiXcx5fYHh37IHbHh4sXh7tce667bFrirGud4sGzYpJaakvUNM3k1iS1BeSrgIPVUwzoYpW6VSONSVbhY3jTKtUvILzFiQABMaAXEXDbk7k7D1HAajqVGph8O3w2tiTmcS4SfMbAF28QALX1U690WKK/8Y27i/cfOe3LhPS3G32qsFPa46SGulku1IqrDF5rS00qKhhCL1HpqCQv4SOFTxlE4kOgm9gTcwCTMATMfIar0FLC4iizx6VLJIJzDaGn1FyZkmJ7rxZ+2I8Ve+OMtr3TwreH/AHdbJOdN5U94t9dbVhpI6nYeyImcVNbXVclQIKGQAvHG8jRMIpWfqBUZ6HBMAzFVvExDppNgvMiHOJszS5vcCb2i6r4xxOphcG33OnOIqAZPMb5eapFpa0DzGxN/wmI/8N7npbR4TeBuI+MqDw38J+H/AG1uS3XWC3XmePe1w3BcKSpjebcd7p6WamtyU00sUUqtPJLGhhV1jYLD09+rin1cb7w9zjUAMZGkCk0gw0OeCc8EkxTzSdiXTxOGcCp4fhhw4phrHkB7qjodVIcCcradyyRE+KBl1MBe5dTxmd42zam8N0eMXnvcd4q6lblQRW17Ptmpm6jGklTTRU9oaVHkJpu0kq95UUsGwTxqFWi0uNPCzAvmdUdl1gEtLWjQzY6Hur6lPFhgois1rdJFOmWuBvll7nEgSYiTvoVrd43nx/ta47y49snil8fVl5SqKOG7VW1auuorlc6hJFlHtMElwoJaeGn8umUpIsyRL3wA7ENBiG1GBnurS0HUF4A3MkPmTOhBd0EAIUOF4htRuIfWYAM0clPQGLCJNyZLRH9RW+bRs/jUgqYY+N+Vaa/8TS1sFVUz7s2/a7xuOCCWV53loHoTSUglQCePyqlJSh8tgsgVkIpuwJIFSWOb+FrjcjYl4Jv1bbuNUeM0KtJpkhz3SMxDmNAgCAGm8SDMt3m5C3Ta204Nybtss9/5GquVaq4UdVd49i72emouurR1WomqYaKGnJqVilZHhroJ44S0OEVnZ9U0cTTpvc2mzKQBJBL4noXExJ3Bk3AMC44hh8R4MipytcAHNAbIEmLAZhGgbExLtl3298b8WQ0tBvDZNJd+Cr/a6WO1VMNopPu9fIidGWhlhjX2SboYKqKA6sHPlnLKwrrYmq+Q/nkzPXvOqwcO8Rj25oLTpJBAm03Mi2u430Ty47pvlgvFBVy7Z3BuSzNUGVtwxFYaeGnaMMsQDESecrJleseWWkwzZPTrIQQ2LCJEE3n8gNr+saldtlBlVuTMGuI8sTodT6g6C9raBdJsVp3JDtyjiNvtFpv9VJ94PNJIJpYnlPU0bjuCw6ihKkrgAqMjRqSIZNha338evoue+vRdXNRxLmi0aaCPhpp8ytunqYLjSWxKmhWG8sQCEhYuiq5VmRuxKZHx7dxkarc7MANlkbSdTe5wPL69pE94+K2Cliq6WV09jt/k9lEkR6C31ZSPy7Anv37acOKzOIcJkz3usnk/PUzJFWpmUVaGdRCLZ+egSrQ3qkH0ONHMnQix74OiSokaBciAq0A8JwxIZsfPShyshDJ7k5A0cyiGxI9DoZkQELRz9FdCrSl6KQzfD46mZEBBJ74Axog7qxrEIn886maE6TqZ1EksBj00MyYNQ2OT29NQOVoCESAMg51CUUInPc6JenDChsWGc40cyORD0uYqBs3QWJPY/u0cymW6Qcd/y1MxTwgE/PA1M5UAQWOST20cybKUFtTMgBugscDQzpsuyAx+efro50Q1AJPzzouenIQGAz2BxohyaEFgRj0zqZwoAhN6H01M4UhN37D89HPdEBSWMhPpnXGzrwQYrCRhnUzhHIEoSY+Y0M9kCxV5nYjBxo+Jsp4arzO3fOdEPU8NCmMjhRG6IQe/WnUCPljtpsxRDI1/ZaPfaPcdvtk9RapoL0sZVhbmcUwZQynEUvfBADEK3YnADKNVv9VvoVqZfzNid9diL6fE/mtNk31Z6+r29tyOpig3DUubhNRVigVao4OHjCZEhU+6HQsD5Z7nSPqGOy30MC4B73WAEdrbGTbuD1WNv9+tvsf9pjcrxFHTwpFU1NBRMXhj6yredAR+0AJwT8FycD1FbnONwCfzW7D4Ut/lQLkkSdbbHbsOvUKNFbzQu2dxVNnqbxWcj3+jlbcPlW+gRKt7Mzye10sNMxjZ1ijj8/3etlZYi34siyjUJFvKetrjqTb632FlrxnD2hviCGHSJtJgNMiTfQW1nss3zNyFZeMNi1ty5FoLrVWTpN8t16stonNRRTtKqnyBIuG6UnhVGHdghBByoKuL3RTYM06CwJ+u5Wjh9HxK3jUnQW8pBIIjS8T0JM/DdbxvvdwuGwdt1Oz7fdp99Um9doUVXaaima3XG3wPc4cxywShTGWg89j/AIHAfpZguddjAU3EuzDVrzfrlMXFtdF42tXw7qwZWePDvcGRJi9uhPr2ut0uO6Kr2fcctI9C0lTJRw09mlfEsMh6ulc+kUrOjgEsEHT3I7nXEZVLzlba/wAP10Xpm4ANDHOk5Q45hF/3Gndc15Y3su2rDRrPeNpcd1lVVLFVRVLNT+2TSTCBYjNEsy5PXESyOJCyIAR1BtW+KJ5iXR009dR9YHVbuE4Rr6hLml7YESRa07wOoAgjX0Ufa3jeonFdaNy7W3E3JMUtRVJctkVNckCrMA4p6mWmSGczOsskXROH75J7KzHoNqOqNGjmaAuA+IAJiBra30CY4igyr7xRhmaCQSJIbYOMyNvwjt6JqLjZb3X7T8O9PxpyHwBVLbzX2mSvL2x9xT9cSsKFiJXqqsdMvnRysGdAW62Vm1ZXoV35qlbK6DAgyBrBhsNaIAibf8SsGCxOHouD6NbMDdxiSNy0ufc3My0EydWkgqQ/De3LJxTaJKnd9tuddyHdZqKkv1ZfaoVdVcKuCGOlE9PVZxJThjLKkSojLFK5RB3XVOKxbJyMAa0SQBpe/rJgTJ+NlgxTcTXd4lOSB/SALSSAW6CJ66i8mCtR5w8WPBPDm4v+zXmDlTYdgrjLDc4rAlStRfI4vMBjL0FN5lRFASPxtECfdK9Q6iDgeGYrFAuw7HPAP4WuIB7kNIB7TPWFX49PDN94kN5YzOcGtPXKXluY9wSNplcT5N8Z/HG5LPuTdz7e5q3Lse2W6nkX2Xjje0NVHWq7Sq1LVQ2dRDJ0SJ5csbh+rALKGLa61L2b4iBmFOHG0EsuN5BqX/8AGyz4fjPCKZFJ9ZoubyLTa4vIgEm8HYGyd8B/aieC+42y67I3N4hNpcUrbq6OgskO/qefbNfWUjU6uep6+KnjqJ4pBURtJEWV1ETdTOz5biPB8e0eLUoPE6w0uAvsWzaIgGDraAuZTNKu8eE9tRxuSHt16QTN9bSBfQQpScucW+Fjxg7ajqbxx7wZ4j6iMOlur5KK33+Ond0DdDVCiXpiYLH1FWyMKVKuqMOfhvaDEYcmnQqFs6iY+lp9PgkPs9TltTFsygaFwLTr+GYINrER8l5/8beEzmHwyLb5PApzDtzbvHUUklW/DHI1ZPeNpW6oeodKmntN0iU3C19E6TsvV7VB1SFjFnqxufxHD4txq4oZXx52DURbMwnKbaFuUwLHr1H4WpQoZaEvaXGxgHY2cBmudQ6byIEiPKz7YXd0u86bjTxAXzindvgb+0k4opk3Bs+vu11pqvb/ACPZoZXert1lv9MRS18saStUxU0qwVJSSoiMOJca7nDmmmx1Gq4VsLUtmbJgnTM08zAdJuNDNlwajRVIrYaW4inLsrgGkRc6kh1gZAJO+USV7PeADn+0+Lfw+7Y584wtNptFLumuqrt9wwVkUtVa6mFKamqKaRUmXomFRTSTBpGRmjqIg3diR5Li+HNGp7s90lguexJImR0MWkTpovYYLH0q1D31xOV0TOgMXEwZv27mF89P28HC+wOQfCR4avGjtSrpareVvu0m27jK1O0NTU2S4zV0tJBUowDCSjkgjhHUOrE7A4wAPWezOKfTrOwtTcA9eYAZr95O+y4/t9gPEonFU22puidAQTlt2Jvtud5XjN4G/E74ovDFvHY2ydjXCq3Dx7vC77e3vSbHrHiel3m9ru4qkgoJpcihuLS0UyKEAadsQMrNNFn0+OoUXvzuMFs3/plsSRuACPTqACvBcFxuJptFBs5agMCSMwzQ4NM2LoIvYxoSWr9AW/cqcGeKLwq3nmjafIOz+auIN02KartlvukcMNPLV06mRrfVL0AwVCSoYpqdwJUYSLkAZPyvEUquGrCjdtSQNzE7/K4OhHwX1PgWKbXjwqZAaCSQTOUg9yY1E3jcTZfDv9nb4heevAX44OVttW+W+WzgjZF7v1RyXa7bQJcP7N2Oaogts95o6F3LzmlBtkpAMiiCEPIsiodfTcVw5mLw4NTzkAC8SfMBpAkg3I1MCCQvm9PF1cHjq2GpNmiHFxBtygcpnzRzDS+9tR2f/wApdpePm8S3hnvnG9XS7ooLvxLHe23KlaKs7rae41LxVz1PUfN6ovKIICqqMiKAqBV5vsrUztql7Q2HAQBEWuD/AHJMgyrvbkP8HDvqOLpL40gAZBAgAATJtrMyZUdeJfFRt7wPfag8B+I/dtsu3I2zNs8dbWjp6KyUaw1k9DU7Cpaakj8pnVfOXz4etiVzhn6c+4ejiaVarhK9Old7y8X0nPOomwj1HqubTr4ajisM6q6KYp07gEmMtzBiSTPTta6id7XzZ9pt4z9sPaKlrpz5ybuEUxpvfjt+3EErLFFTtkuKOjoofNZhhsRyEAue+3hWDpYamadQ5abBJMSSIlxjubAeg0Wf2h47U4hihiKU53GGtmzQDDAD/wDZxtzEnsvu6+zJ4V448GlJuLwwWriq3wpsJ7rS3XkyKeMjf10neiqfvCqojI1RSO1JPb4w0mY1dJIof2ah38Rx3i7sZS95YRksGtjmaBmBvYczpJiSbEgWC9pwzgNbCgUiXeJVOZxMQ6QIAMkvcOhAygnmJJiaHiG8TnEnh62DYOWec920XGlhcw1dpWvqnFxv1eqHyqC30IHn1r9Mr/s4VLM3rgAHXmqFDEVangYdhfU/paJPQk9AOpgDWV7GhQoDOH1A2m0kOcbNaCbydA50WFydACV86X2m3jO5+qPCBvPnXfVlo/CRNubcFtfYW1rhQwHke7mSoFZBO8nV5dgpI4qV53kCzV7yLErimiaNT6vh/B6bKowNWoKlW+YNP8to/FmcLvPNAa3K0SS5zjIHExHHW08H7/g2Obh2thr3WLnWADGGfMROapYAOysBGY8C8DGzvDdsnj63w8Ibd319on40a27Uu4+QL3Y6TqsdFU08kcxS6bruNO8cFFA8f7OCITS1TEzyBuunjg7nGsTW8ICgPd8MzR75YCbiWsEPe69gIDBacxcTxuBUsOHk44txOMrNjK0iq9swQwEnw2Njzue4FxGVrSxonr/F/KPiV4F5d33vG7+GPiax7On27NuLc1tkutcu3937cjrEp6GSiucVniVPYPvOdBLOZDVx1MS9DLCpHDr0RVw3PVc8MIaHFtw5w3BqGMwaIG1yYleywrXtxeSjTZSfUkkB7ZIGoBbTgkHzHSBAduvSHjfiPxubc8N++6fanI+0fDTso2Gd6GwRGfddxnhkQziRNxzywyB3Lx0sNNHDHFSqVCA4j6eZxKtgjaq4vJIFsrGW5YygPJJPM5xdJ0AF1roU3txLG02AkExOZ7wSSbgljWhoMNEG4u6Nc9wf4gr9tranEHG3Ifhq3fYtzNdn2vWTcZWoJQ7ungpJJJpqh6mWG50xbyIizSq2EZmErxkNrTXD69Vz2PD2gEgPIAaARsAWESdAY2InlVTKRwrDzZXOIBdd9zMBsg9DJcJzDlJBLl6QXrdfhyk3PZtqXLa1puG/L7OJqeils1UldPUwpI6R9Tqkrt0RyBCzdDBJDkDOuWcXiAA0TGo0jYHt0+ELFSwFR7nVc8eHDScwsNdLgDUkASCd1qVm2tQ0E9s5N2xZLrs7ccG7aozvcIvPqKOkcGGoo6moqOqSRJRAMRwO6RyGPyzhez0sa8U20qp5MugsNZGWNeuYgTe91uxWGa95aYccoi+pgXgeUNmwMWFwZhTxtlyo6ih/ZeYlB1NBEZuxnUZGTn1B7/x1jZVBEryWIwzg+Dd2pjZalvBbfbKegvNVeo7LZ3rKSOtMvTidPMBSMs3c9TdKdIyz9QUdyAS2pDgQJ/eDB+Go26rThy580gOa8frbS4m+2q1bbO5Lrua9y2VqKeiMUU80lXUNGzeV57JHIkcfUqyOFVgshUoAfdOcF2UgLza3z1ifqYn4LfjaTaTA7c6DTQX1uQJi2s6rr9LRUlEZXp0cSSEtK5YlpW/4mPxP/QwNLntC4r6jnAB2ydlxoByRW8z6aMpwxJLn541JTBiQZM/HtqTsmgIZc/pqByYBDLfMnUL4UDSklxjtnSeIrGsVi/yGNTOnASC5GMnGjnRAQy4+HfQzJgwpDP279hqZ4KcMhC8wfI6hqJknzPpoZ0waUgydj72iXI5Cklx8ydLnVsIbPjPfGj4myICCZPpoConDEksTnRD04aEgtj11C/dFIZsduxGiH9UwYUIsO/fJ0M5VgaEMv2x6HUzdUwEpGc6BqJwxCLk9uw1A7qmDOqGz49Tk6mdMKaAzg9+2NQv6KZAhM/y9NDOmy7oLPj66meyhYhFvXJ/fo59wiGIDMT66mdEM6oDOfqdTOiGIDuTnJyNMHJsiCznPz1PECPhoLP3750c6YMlBd89zoh10AwoDP6+mNDPe6bIVI0y5+OdcUuJXgsgVeZ8zoB5ULArmU/8AENTMUMiV5hPoRqZ1Mirze3qNMH9FPDVmnWMdTsqr8z2Gm8SynhnZa/dLwqwSLCldH7vciHvg5GVJ9SPX49vzGs760iy2UMJBl0fP8wFDrlnd227mlXZ7bZrVuffNtiivFvpXvFDE9G4Vo1qnWR1NGwL4EvVE7dR6WIzqUHgtLs8NNiYMDseW/pfqvUUsFUY3xCwmDpF3bw0zffqNlHLi7xX7p42sG0U5G2/VQbOvFVDPaN13uokgW+gxRmsmqXhgkhhfraWUNI6h0RmzHh0Gt2AqhuamZibCTl6Tfp211TY2lh6tZ1JxgtECMsaS0Dy3GmkEQRJTrl3ePEl9qeRqvkXbPG1Hte42yeAvernVGmvdHHEZRdqKejgmURRLOiM8bBkMZ6gAU1VhW1czcglx2Dc28XEAz0mR0XWZRc7DNptqEBu8tblJHlhzxrB6Eg67nR+HrbZNwbv2hwf4peE9uXfcrU9Va9v7nrL1PfLTe6ekpoJp4RO/QaS5TQ/t3pmWJngilfDh3VejTrPoZ6+EcMk3tBBJMAg6gWvcTA1uuBiMc52HZQeXMdAIaIvbKHSNhJAJueoDSut8ycQjjTjiv5Z4Ktkth5H2y8e6rVQUVTNDZ92PaWneO1VkZkdJYzC9akeQrxyy+aj+6YzVgeLHMG1YyvtMC2aASIA7azIt3WTiuA98cQ9xJaIMmXRqBeSJdEkdgQVm6Hnbijclp2/4jtpSX6u2tcrIldS0EUsgmpoqtIKoTS0wIjQDpXzADIGQlk/EQ2GpRqAuZk5pg26SLHf4fFd/BYJ9Skym90SAc23pOswbTBGmmnWaP+zHKVtmul7v/Hv9hJld6q2WuCmqvvcBQvTcnqF6Io+ojChI2Zo0LPhektSxrWwCSXxG4j4am3wAJsseJwVSk4sbTJEgy6Ykf0xqRFzLiNo1XH9oXy2+Ha67IsVXdb3a+BamhqbNaGqKSH2K2VWBNGaOkhiFVSUMywTxtPN1Dzhg+WHiZ+i+lUrSRzVAJIEkxO+1pFmxAiRrGbEuFRxLWbgkzodIJJ5nCc1yQQYBJBCVyFy5SeIRN58FeGio2nc9xU5pEreR6yN57Zx9XyeXNTNNCGSatvChIpUpU8tYwYHqJoRJGstmBolh8TFyxkkARD3RqGg6N2LzaZADiDGHF0alJgd53EE5JBbaYJIMBs3DRLyAYDWnMmM3hz5e5wtG/bT4u/EjfN3WK3tWwLtHjajqdpbeqYsyCM3KohmludW5Ur1xLVxQofMTocKGNrMXg6LQ6jS8R39VSHQezBDIHVwcd7aLPlxU0zTijniS0nORpZ7pLJF+QNMEAkm67ZwF4fNoeGOx3TYHFe1dq7IsVTWyXSporFQpb56kSxsIoZalG824So0ZzUVT9cinv3AUUY/ilfFECs8uyjQmwveAIDR2A/dMcJgyfeGMGZxALjcnLHM4ukzfbSbd5eVNwo6qjp2FdOaWbpgjAmIV+rHbIPyJHY/Md9YTUEjqubSwrmvNriSetputW5ApLVdqF6XcNPar7YnjZqmnucUdVT9LkAu8cwZSnpnA7Zz6ZGrKWMqUnipReWkbgkH6XVdLhWGxNJ1CvSD2mLEWMbftPooYckfZ/wDg35Fevv1T4cOCts31QTFdbHtiOzV8c7sMYq7e1PMHJ8spKj9SsfU9111G+02OIyvqucDs6HCOkODrLVw3hlDClootymb5XFp9ZG+szqOmq4DYfs59x8J2i3WnwleOzxa8A26lq5XoLRuprfvWwWyMVDytHBT19OJzEJKmdw3tSsS2SWx20v4rg6z/ABMRhgD/AFU3OYTaBYEtFhpkAjQBVChjWU3U21BUzXh7Q6S65zGW1Mx65ifhYxf8WE3IFk2HuzhX7STiTjfxb+F27NSVFw35xdDUpX7VKKyx1tdtjqasp2WTLJW0U9StMz94egdJbAilTqCtwusfEEjLUgEz+EP8jraghpjS62VqjsVSNLHYcsZFy2XDUcxF3NAI1uCdSIJXjB4O+e9n/ZX+MXeXhbs/M/H24fCXykKPcGwuV3uUdbabNBURFBU1U8aAVESNAtLMqrF1z0sDOYoy/R2OI0RxOgKxkFkh7ACDI2DTJBM8s6AzeIPK4Vi2cJxJw4YXMqQ6mXQL9zIF4EkEkWi5Xsp9qlatqVX2THPXh/2zYJbvDszaFvu61vtEDNJJba+kaSvlkXtLJLI1QSV96R5ZG7AONcHg3EXV+K06jPITA7AgtAgTsB2A+E+k4l7ONpcNrVKji5z2v6kyZqamOxJjaAJNvIrwVfZ38c/aEfY7WQWmeybI8UGx9/7rGx93JX+yvSyF6arWhuDBS/sksj5Rky8UoilT0ZW9rxjj/uuPaypem9okRJ3FhuY166GNV894LwB2OwcUpzMJykaTMzO0W6AASLrgfEniw8RG27ly/ads2C98b+POw+0JzNxpXBae2c126ji6JL7RUUhCQbvgj95mgUiujY1CpJ1SJrJxDhtNzKbHn+URyPky2dGHcsdpe7dJEX7PBOKV2Yh9TLNdtnssc4/EWkCAQACbw7eREOtseMDhzjj7bXg3xsUe8diWjw8cqW2CHfArKrzYrTS1lta13akvsUkS+RLFVUsck0ZQr0p1L1BgNNwzD1Rw6pg6s+LTkaHWczS3UukG0dYXP9qRRq8Qo4nDEeFWa2Lt1FoIkBpaYFyIIkkBQt+2k4Jt/AHN2xdq7J3Pdo+Grptq47g2BsetqGll45slXXzypRIT/c008jSVkNLktTxTrGxLAk9P2bxQrVHmo0eKHNFQjQuA01N2izjYE6dVyfbLBGhSoupuJpEOygxNozEEDyk2bf8ACYAFlH3xVX3au7/tE+YpdlS0HEOz6rdy2emnpKpKVbDTpSw0lRPBIHCK6rHVOoVgjMwUdmA1fw8tfhRUqTUBlxAvmGZzo63ED8+qxcQYaXEWUaJ8NzRTbJMBjsjROoAykmPSy93v/J7/AA+WDmPxk+Ifxy2zjg7f4l2eG21x/SyyrBFQ1FTEIgoPq9TBa4Yg7AdpK5nPc5HK9pMc7C8NDarhnqk5tdBzOjtmIaNLAjquvwPh9DE8Sc6gT4VIANt5jAa0kWEmC4jqR6H1IvfiT5T5p8WfiM4T8EV349rdj1cSvvnlK90puG39kVVTDRWuS1UFGgSK91kTWv3IjJ7LE89QJZCIsHyuD4bSfhWY3HFzGaNy2fUGYvls2aDJ5yNAMrZIX0bEcRr0sSMHhmirVaJOY8rCAY8Qg5s0GTTaQ8zDi3yiYW2eF/D/AOBmPkjxIb+ve/vEFzbQ2Ses3Pyzvmpp7hcqKnijXroxO6ilslIArstLSiJgo6GWVgoZMbx6s6j4GFZ4OHcYhsnMSdXOu6oZ9ROwWbBezIxlSnUxbw+q2S2eRrYBJNNghrR1MXmS83K8I/D14Tt2/bYeJu6+MHmTc3I1J4BNvbzvFm2hYRdJkvd5qH6JZpIJET/ZaZ5RCskikS9MENLGFaMuPSYZ9HguCaarA/EVGzB8oEmM17/isLOdmcTET5rj+MPH8TlwrhTw9CADaXENuQdDFoJ0ZeMxK989m8I8K8Y7IsvC3Dmz7zxl4YrBbKivgoKYPdqHcqLO7SGOqkdy1KsxYyIX86qaCNVXyghfy/EuI1a1Y16wBqnLlAgZehy//wBQBDZDjzQB7r2ZwLcFhm4fDuEgwZkOuNCYu50gEmS0Ejqtf2/Zrly7W8wrVw7blgr6kWLfdJWxSX7asFTF7PU0oq7VMzeZXUsDxKY4hHGnURO+QvVQ2qKcPa4iDZzRDnRIeWmLyZGY9OUHRdTitLDFtNop5xlgNcQCAYgGIhrtS27iDcAQRpUvG/FF1s1j4p3PWch8kcR01miuMVg3DKbHarHT0MwKmKy0iwEGZYXlhjkWoDrD1ZCyK2qa2PLaj64aA8df5jiSNJMtDr3jLEjoY24fAPcyGnLJykMGUQDoXQHFs2MmD6RPX+A4L9aOPOLt20OwFpL9bIhFBTUFNSW970zq6zSsDGhjjjWsOeoonTCesBlRRdjMVWdULHOkC13WEWJsSLkE7mTa6wV8Dgxn0h0SYJIGrGjfQNAi42sTPbd+W+yb+25Ytw2rz7zeYKqKo29XzuAJa1ZeiGojZSAj+8yLJGAWUOTkSrnnGm5ri13KXWPodZte14Olt5V1AhvmgsAkjpaTE/WbXjYrdto7FksewRsLc12XdD2q3xtQ13nMI5qcSEOIWLOQwjY9XUuWwGKn3jpnFlQmbAx922+wsGJxxFUYik3KXOMiJg6jNMTewv8AGLLctsXK27K4stuyK67x1tfQ0UdBH5XvtUxtIYUlAOetyBg49W9/sHyBWxHibXOwt3Pp+gWOpgn1MYawFjeTOwm++sX+HZK2fZYOQb/953inq02xtur8ihts1X7VTyXQAsZmOWV3pllRUZDhZmlYEmONhrwxFKmXjV0gG9m6GJ/qMjTyg7OK53GXZSKQ8xhxMAE6ZRESLjMQdRlncLtckNbRVNRLS1hrVCKRDM4VYckjqAUAO2BgFiDgYzqnxbarnsaxwEiNdN/2+HyWQjuKB/KkDRyAIArsvWxb5gE49NAVRMbpThz5hpf0sm8V3VoKgzRyRPG7oQ646gvYN+R+fpoPqQ2VZ7tzANvp9/BHtVRPNbaCWpjEFQ0KmROrPQxHpn6aszdElemA8hukp55gI9ToGok8MpBc4GPXUNRMGJBk9fe/dpS8pw1IMn6/nqAlMKaQZCPU6IdCfIEkyfXQDwiGBIMvz0fETQhmT66BqIhpSDLn56GdNkKR1n6aGcpw2EkufnjQzp8qQXGiaibIUkvj8tLnRDEIuPnnUL1YAkGQD8tEuTZCkM/rkgaOYp8iEZPU/wA9QP6JwENpO5741BUnRMGlIL47fHUzJwwJBc9u+NTOE8IbSAn10DUTBhQ2f5HGlNROGdUJnA9PXUD5ThvRCZ+/c/8AhoF9kwYhM+fTtqeIiGFBZ/kc6IqI5EIuCe/y0M6YsQGcH6aJqAlTL1QWk+GcDU8RNk2QGfGR3B1M+yIpoDMO4GiX9U2RBZxnTZ0MpQWbt30c6PhoDyfu1A+6ORSGM3yOuP4q8GKSrztAVFDRV/OGiagAQ8JX80euRjUFRDwlQmHc6gqXU8JNqp53iIpmpQ/xEykqw+XbQdUkcqenTbPNPw1UfuQJWlr7bYbaXp7vK5WI2+GXy6TAAPnuT0lCScAKCvckjBzjqjxLD5r2PCA5rHVnXbGjiL+lp+N+wWHoePto7StF5t19o9qxbeuUr1t7tVLH5zXqsZ8u1bIoZ5l90ghlY490MqL0HY7GloHNOXTYDuBoOuwm5krOHOxNbxcO0ioYGc6gaCJiIGl7a63UALzzVtzcfHNfwXwzS7evd3iMNFbrmJJKKWnqYYZDFLTrIqx0opYklDTVBipSsXQi1Rn8g9PC0nNeatc5Wm8HeTqTJmTERmcTEBvmGzG4EgtquBsSBEW3sA2TmvYCwnM5sKJvJ3hn2Dx1VUd5rOWfFlUc71sEpuF0485OktQo7a0kRraK2baoIZaGho6nyV6Y4I5gkiJJO6gFj06fFqeJ5BQY4DUuaS5xvlLqktzG97tAGgcYWCr7NYg0/EbVLGAQ1gbyCwAIa4uJiASS0k7RMrlm09k/bYXOg2LRcLzcV3qHbm4nvcR5bjttBe6I08MlIi3entkk3TUz09QyOw6nlDF/MwwIuPD+FsqPFSsWS24YS8Cb8pLBIBuIJHquBiOKV3YZvhUxVbIALmuplwEGDzm400EHUNK3/eA+202xR7Ysr7I8Nl3sl1VVr/8As+sFvu1NHNIHklf2O53Ckj6WwqZdUJVnOTJ05ys4bwhxzNxDjHUhh6ASKTr+k9NLrq0OL41x/m0MrgYJ53RfYio0kCNSR10Wh8R+KDmXwhwbJ4T8UfBW6N0bH2Vt5Ns0d2jtFTtO/VFPFEiiL7prZ5rTe0MUiqUt1f5k5EixwuVXq6PFeEioH16D8uYl1y1zZO+dk5b/AP7Gt7kLDw7ixcwNbDxIEgEGN4pua10gjVhqRHeF6teFbefDvOtNs7lPjuz8Scs2ESy1kO47EiIKQw08cKI9FUKslNXRgxeYr9MiN1kDIJPlq2KxVF5ZUeQRMg2MHadI9DBHZejxj6FbCk0y7I+AASTJzEkntawix80Lslx5etGxN1XLacFp3LW8h3u6TixTyUFTLHNK6RtmtmVXSKihEjeaD+zC9KjEjKNZMHNSwIyDUgiRfWJknp1PaYHEsJ4lJhJs0DlggGJs0wBmMSDII8xtqFKbam2FnltNTbNx0Rijpdx1YRZKy7VcwMr3YTg+Y83WApkBzGjqhwIQAcXxDxCYEAWA2AG1x13tJnqtHDeGPYwNeC1xJdYEAGzcsaRA0vMAhdN2Lv6jTbu0dmXCit+3Llc6cPR25KsPijRwaly7Ae0GNCXklXqD+bCwZjJk2ueXGXm3WCNrAD6D9IXNxfDXNqurNlxaTJ3J235bxY6Q6dF1qG41EiNfxA1wgpw8EaAHokjGRKQvchgwxg/8LYxkjVLK0c33CwPwrZ8CcpMHvO3rb8wuT7s38dqX24VNHcbNNBBc6OWqp7rV+yJRmWFoozGhXCCXocfIv0tgkkGt2INyDBHbWf7LtYThAq0mBzTzAiRewM/GDFrWm61l+TZ54bpueSmrtp7XNM9HDV3KAxU5SNmJkyiyFjKskZSHCt7p9CcEjMBmNidhc+lj8zp8luPCWtcMMYe9tyB3gbwIBFySddFy6r5b5LpNw12xtw3ri7ate1JHeLBLtygq7lWC1pUrHHFVwzuoSYmUKiIJgJCgOCQTrb4TgAC4nQ+VoDjtJJmPhaToFmPDGBprFhLASOYzmhsuIa1oOo66ddF1vZu+N7y8XVW8rHvHcW971bqycSUt7oYYXuUdNUBZonWOngaknkQMI1YdpHQnqQ6DatNpBqjKOxmJ0uSZBtptcLm8R4ex9bwaTG8wGkiCRMAEmY36QRqFy7nDmHg29WKXc9ZerFvex09It0lSx22S73GECISoYhBFMYZlBVzEelusIcqcMLMmIILWAkGw2aSbb2M6arocE4S5pFR7cjhaXWgAztDiJ0MG0+h+OjxK/ZE2Kr+z/wBkeLvw87Xv9FyC1srd+7gts9VLJ95bdqqiWeKNaZx0pXUVPJE7ohzPGJB0hox1fTcJ7UNbjPccTAiGz/zAEydIJsDFl84477H06uDdxDBg3JOXq0ucZ+UbCIINyuxeCLxHWK4+A7xKeGvdT3e5bA5F4j3hHxzf6yeasqbbuW32hZ7hs2pqsAMUSmiuNH2zLSz9J95TrFxPA+Fi24sQ003tzDQEF9n69y1w0Dhay3cB4r4uGpYQk1A8GJM5YY4OafTVpuS0ncKeH/kwW9aG+eDjxM7HlEEl3tvI1Nc6GRKcNJTtVWmF0YSKpYAvROPoM49dL7ftLDReNw4fI7/PquD/AKfYh7iWXytgnpDrdYMR8LLuH2wf2cd/8c1o27z94Yds3C3eOPaLF4rrZ7qaMV1PSmST7sat6wDcYGUimkQh0cGJjGrjp43sxxp1N3u+JjwHTqN7XA1LT+K0bySF6r2n9n6LcN7zRdlrMjLEAmSJJgW1JBPfUElfHp4kN27Q584uu/N+8pqHZHjTt+7TYuRLNJTCgl3VFLTPGl1ioQix089PNSGnqkwHMs3mOGLEj3+CovwtVuGu6nBLTcxBBgu7zybQIC+e8XrUMbhjigAyuyBUFgDsC1syTu87GdBCkh9qNu/afMW3fs4OUdr23bdvq79xQlHcUguHtVVV1dPdpaZprhVN+0edyCGMxaROhgztgdOH2ba5lbEUHnyubtDRIJgAWje3buT1fbqoytg8HiQScwIuZJyhgvc/DYGRAhefB37fuBOQ/EDZNi/2NWS5UF/2BNWUTfeMNHbqiqWKdrbVSDqJeGBoFqvxmGaQggyZ12qf83DskmDkdplJi4BGwJglvaNF5DHP90x1UhgzNzAAnNlJGWc34i0EgO632X1FfZOcP+JTxF+Brjng+O6bi8MHgdS71tdvi7W6oEG4eZbhV3ICeioZY+ma32qOD2aCSpJEkxQRRHpLMvmPaR+FpYsYjGHxKjQPDpGS1sAuz1BoSTOVl9czrL6H7DeOcK2jg6ZYSXF9aYOkNbSmYMWfUAkXDYN1662fZG0uNecL3wZwRf7dw7sX7lrNs3K1WGhdLXs2ww01LWJO0XtHlRGedLvTxxExFZJKicNJJGQPFHiTcVRficZzGQ4k5RmgkBg5b2gnUZRlGWZXv6fBhgmYanhqYgA5AQ4mXHmcfhBDjd7iM2YC/mp4hud+bvtWuU7j9m34Wqqh2d4Kdo1EU/M3IO04ZZqWeJJ3f2KnnmKo6eagjVCze0TxtNI0kVO7P6DgOCbQp/xniflEeGyzZMW9J2AAyNuG5i0DyvtXiaZxh4Rw1wOIeIqVHGS0WDgIF3R5zqZNNpaM5XsDeL9sXi/g7gzwmeDzYUm5NkLX0e0LlZ9t09XUNbdsOZI6+c18aAmriMhqJJoy9Q5lMgTJ615OevxDGuxOJMDXmAAMDlaGuI5dGgWBFidl2cFwejwTDRzACIMiQ4nzkyQJ/wCQIkERuui84bz2tw1ypt5d4cp8SbYt1ptCU1n++rrR217fUzsqU1JLJO3mikWSGCpmBPSQsLBSyHPBp4plRz2eITUedhMakut0BIA6k6L0XDMOypgjkw8URr0cGxYAak6Bw0gi8rz/APs77tNxDfOX+D9vc07E5q5zvW6pN1Xi8Hf1FdaLdNfPIDW3qiSnkLW6jYPSwLSy9U7zBjkxwNI3b4yaVanTdQAp0aYyiWuBAAsHF0BziZMNkNAzG5AOXAUTTL6mPDs1TmgRE6ZWtFw1oi7gBowEm655zh4iNh7L5W8RfCldV74pueRYaS3Q2pLZ98oxZ3Mt1pa2NfMr54mqKiFKVEgRZZIoWjcTOYq+HYCrUoMdSZNMv1BgW/Dc2c7L5nE2kiA2/oMRj2OxAbVqAEszAEZbGRmiILWy0mJNiJktmd/hZ5N2RNtK77X5Bt+1ePhYKC2Q3e0CpS5Ku4HkllqTU1sbolbPn2JPLCqPPldT1lT058bVbTfna7M7MQ0gQIAiWA31mHHRom2qy1MJXqUmmk13ML5jDg0iwIvkkcxHQgDopabtqK3kCmue37dPLLYkplepKTwIkdb1RACJZCfLnQPO+SEJwvc9gcPvByGo10XEdTe+2lo1udd4oZg6eHLWvbzmwEHywdY/+MAyI23XIORfFlw7xxx/uravL/LXHXGW8JaOms9ZS1letFUW6vq5WgSaQzENBDGqzTRYXqEUQYBUKkjD1KdWqGGS2QDABsLnQmTFjGhIBMwFXiOH1GPbiKDcwBJ80AgbAmLk6zEmYkgpvdfFJxhurb+4t38UU/HXK1o2tNSWna9WL7FUfeE1Q1PQR0qCEEo9SagK8g6jEOjzEUDA2kVqpMENNQmZEAfi1MCGxmN9vll/hzcKxlTE1C1xBLrTBBJ2nu1trk21ujw4+ImgqtjUkD72J3A1yraqpsrUcldXNcJH/wBpqmWlULJQCpkqZBLCZovLMb9QGcHGMqMYHvBiOUmQA3YkuiSW7GDJsE9Xh2HfVIawSYmCNZjKBcggw0yAYmSFLCk39fEt833hcIN3XnzRVS0dHbJIA3XjyVYPMfLQdSBRJ0s5BYDPujEHEjk9LxE/ewmBvuqG8LZnEjKNJm4AmdtYmSLbLeNt2FrA0N73BuO8723e0TSskqJGsLE9TrFEoATGeletmOP8TZJNzqtNtqY+Jufn8du1lz8RWfWHhNaGU5i2nb17/ojwXVK65V1NUzma0irE3m1LLD1xdCyABiBkBSFx3PvnJ0oc2QSdPz+4UqYc06QdEOiLSY2/OTPYQtw2vdXuVH51PF/6POZIpulVWbrJYdIBycBlBJ+OR30zZAg7WWDH4cMdBMn8tv8AELaDJ6+8Bo5gsQYEkuM9znUzoin2SDJ9NQVOicMKGZfUZ0A9N4aGZO5x66BedEwYkGTBPfGoDNinFNJMn1J1AU3hpBf1wNAPRDEkykE+g0A9OKaCZs57jOpKcU1bzR9O+hmTZEMy+vc99HMERTQzJgdwBoZxMhOKaSZMDGQNHP0TCmUNpB886AqFMGJBlAJyc6AeUwpoZl/PRzpxTSDIAD21C9MGJBl+udTPsmDAkGYehOpmThiEZvroFyfIUMyZ7476mYJgwJBf5kDU8TorA3ohNJ39fz0uadU2RDaX9RoByYMCC0nbvjGjmujlQGkHzwNHMmyWQWlz37Y0Q68KBqC0v10ZRyoLSD0ONRrk2VAMvc4IOjmKYsQmkAz37aIcgGJu0g7nvnRzFOGbBBaTP+mhmKgZZSAabA9dcV1ReFFO6T54+BONIaiPhJXnd/XUzhDw1fzvrj9NHxEPDV/M/wCYaYVFPDQaiRzE3lAPIMFRnGe/z0xfIsmpsAN1od1u9iskVYbneX23C2HlDwrDGwyF63+DDJAJDY9M/DWc4lrCDU0XVp4HEV48FuY7GZI7CdO1vRef/NF1uPJG7Ytm2DfNPtbiLbsdLe+RaxnWKkrKCSdvIt6U8BDs05Tz2j93zo1CHzBOqyb8M5sjFZdbMHmJd1giLSLXgkWtb0+Fo1aDfBfzVnTGzmiN3TI3AcPLBuIJGI2DwZFFvyPc+9jyBNva82efb+36/wBggi/s/YGqvagtRb5+ukSSV+gyRGLppxFSRiNelm1pxHEC0eC0SGmXHMZJ0gPEG0m8nMS4iQAsVdrXg12ZWgQA0TBMXMC5AIABsSBc3hSd2nxTZNoWawbgs01528plFT7PUTC8Xi8MqOsRWsqlaRZiGRxDEEiXGAigltZqmIe85AA3sOUfH0GrnEnqVkqVAXvp1D4rhPMZDWzBMNFgyREfLYLnvJln5UsMcvK9um48p6O32iahv9gqtx3O3SX2CN0NPI/sUEgirEUywrBiaL/aQiv0hRq+k2g4BheZm3IHAEyCLuEg25iBpMLmYWviRW8KnQDw4iHyBAiSbtIF5OocQLkOuOY76qPFVc+OKmjs/CmwOIN03mrprLaquTlBrrUWP2qaNWrEpIaBKeompF86UQRVKySPTKOtuonWinw/AB7c9fNFzlYbxchrnH8UQCWwJlbcNxerUeS1pcA0+ZoaZi2YZiQ2SJ80iRAla/vn7Pzj7f8Ax1Hxhy5unxP7s20zQztua58t7hlW51SMHjkuNBNM8UTNJHTkZhkhMgGVXAQ2U+NGnVFZtCkInSmARPQjm32cCsL8M1zXNbVcS4AZARBjoQA2xkxFhoCvMZ/BlyL9nDyFu7lfwheNam4Vp913arudTsHmi2W6TZ27axHCSRwR21Y6hagRyEJJR0paMFY2CD3ddapxzC8RLKGJw7g9os6mXPcB1LXAyOpc4CZg7rDhfZDF4cVK2ErteCRLSMjZdcQ4EBkxa/NEkELvvh38bFl4+Xa+xvGB4Q+VPDX4p973KuFBf5ngs2296VHUzRzWe+XJ41ik8tkjioplEpVB0R9JC6y8S4HVp0szXNfQZEmbt/72MDi0k6nTq5b6PtKcTinUc/hvkgNIL22As10gOEX1aSdGnVdL5n8Te8Np7vsWzuNuLqbcHiBuNYae0x7d3Xt+43PcVOZ4vb4LjRPUxKZRT9U71KMqgRdB8rsBiw/Dn4h13gMN5PiNaAAY5iyCJsNSSR5rruOrMo0i6oHPDNW5ROaw5Wh8i1yIsJcbQuhbh8etr2Jtq8UXOPDHN/h2G3Zo2sNVujZFRPRUUUUMYqbSbtb5aqlE/kPKI5/OjWVOhiUKd4eCYyqSKMVQ43yOa6T1y2dHq2y5WExWCLxWc7JIJcXywf8AcS5uWCRoCbyACpM/9pkdl4+2Vdtvb2oN/wBBfBItllooKSrprxHEGkV5a1Gy0EscaqXUNh5cEs2WPIqYmmWua2nzDzXNtiCI19YXcp8IrYqvnD8rQZ+DtABpIO8yQJjQLmF43w3KfhVt+9OHdmXvkeTcFLPQW377eS3w0lC9XLTGqrnh6qtI6WP3swRvU/sh0oXA0vu5Fbw3PDIuT5tpgNBvm0AsL3MLcKgpuf4kGIs0kEutbMQA0EiXE6C4Gy4NY/EpcqDaWwNv3G+1lH58NNZRFuKknqfui400Mq+2090kaliejnngqIY5pmRz0I/qpiW3FYdxe/LMC+05ToIuQYgkCdxvK7mHwVIDxKpGczmLTIJJBcDHmyi8wATrElRfqfFdyPuTlyLbG0Wh8T+8LJVTbju1faLRUfc20vLR2o7VWyB1ovNqaeRFNa9SAHSmPSr9PV0eH8KPuxxTSWUiIDqhAk6Ogz5QZsAXXIk3A4nFOI0aFT3MiKpjlpy52V1xygZszosOVtiSMsE9V422Hybzxtix8w7l5L4y8O20dxVNrqKDaO3qiq3VBC6TvD0XCaqq4Kaohk64USDyp4UdXETK5zq5uIwNBxbeu+4JaGsAO2XledBqQ0kaxdZTX4nVLhTZ4eWSHPJLjqXTlDAO7Wut/wAhZRG8TPiZ5Z+yp5e4+s/M/iN2t4i+PLjcqu/0eytu2WKxX631kj+b7dBaqZ1hqKOJ4j0UlQ/QPPaRZpGHlptwvD6XFnOGAY/xWtjM45xvq4jlcZ1AMARlb5jxanExw+gMRxEMbQqHLDeR0WByXJc0Xz+Vxdq4iGr0E8C+9LHv7wq8BWGkNZ4k9yNx9aq+Gu23K9JaqVpqZVqKNXUinYpNCsMnmF5FYt1iJSFODj7HHE1mUKQDA6JdqYvOlhvaARFyV0+BycNRxtWuKQdzZRcQZibyTBMA6GY6r5SftEfBtvn7OrmXe2yd1UO8KDwY8ryzXC3yfdHW237tDG00S04SQQCtopqh40lhlImoJpkIILxj6dwvGjGUG1Gia1MQbjmBMQdbOi8gQ8A2sV8W4o1mExL3sMYeqTpmlh2dFiCLkf1NkGbqev8A5LByjbrfyl4u+GLtcqS3zX/aVn3FSwyzkK8tDVSwTrHGSFZui4Re8e4ABGsP+oFEHCseb5XEfMW/K6r9gcS5tc02AkmDpsJ31ESPVfZFTXmTam6jbKa3W1LbcIWlpRFTsFopkUSVSPL/AMMgMc2Rks6zMfidfKRiHEFwv92gdB8gvq38PZVZcmRP/wApJg+uwmLQF8i32+/2fG1uU73vvxx+FraFbLdbNSdXK9PbaENb7qY5PJa508kWUarjGPaVGA8aiXJkjkDfQ/Y/2me5owmIFtGE/OOsf0nQG2hC8Z7X+wD2UBjGEeIZJbfMW9YIkEdNSNrSvkgvW5L1dbVt7btxulXV2q1w1EduhkbqSijmmM0ojHwDOxcgfEk/HX0JtBjXl7RDnRPeBA+QXyXE46o6k3DvMtbMW0zRP5BY++C2Rmaos3mtRm3U8kisrDy6j2dfOQdXdgJBJg+h7Y7Y0aRe6zheT8pt9PuSq69NgcDT0yidbGBIv3Hp0X6cPgu3BtnYnhF4P2dyekWzqu27W2ek8bQSxSQSLZqZTG0TBXBcUo7dIU5OMjqbXw/2lqzjapcJl7/z+O5vfppZfpfgWCq1MLh/dCDFJpibX0M+s95B3svm88YvI27eUd82fwReFmolu3iV5Ov0+891SUlzcW3jy1vJUyU6S1XWZImioKyaoqA3u0sdZNgNLLH0+k9neEU6g8XFWw1AQSRq6wdDRaAQ1gOr3NDRbNI9tvairQd7rggXYysYZBJIZNnE7ZiCQIgAl5EBk+0PhS8Nvgu+zH4b3bwzvzcPHzXOOxf2o3TuS9UiGDcVOlM+LuzTF/JpgjLTJCoCwydSg9UuRzPaD2pq4t4fSloFmgay46WElziBN77CAs/sZ7KOwlA+DMkgVCSWyRMyJyhrAXGby0S4nc1Bt7xE/arX+3c47U5c5G8EvgWs1oltu2Ku2UslFuvlOjeSnqKivlzJHJa7O60kSxNG6VVQisx6EcY0nAYfh9N44m3xcQ4z4ciKYAMB5vmfecl2ttNwuHX41Vc9tDg3+1MmpA5zMAUgW2aLgVNTJygNgnitV9kpb9lWjh/cFkt/F2/bzer99811ku/Ey3Suq3NE4NPWbleeonpI0pGZ1mkHSamIDu8uddF/H6kmjSe9oY0glrmtYDIl2QMbN7AAzl6CV1sNhsNXc+pi2MdcXqF7qjmyQGgucYMiSbgDW1kypvsxPCVxfbN38cc5WrlGxMaKqr6i6cfKljse64wF/bigiMy09dDJUxUyMxjlKSU5YSe904j7U4lzYpN8W4aA5xc4TAAtkBDiJNiBBjRdDC+ztKW1cI5lFzpkAZdZvzZiMjfxNImJkLkfF3EPIXhB5eu/H/iD33uHlaGngqb9tCk3JRTUdbWVNV0wLXVG5KaJlmqba9RPRy108LrTyVLVAKxTB6XVisTRr0ctAFoPKQLtaBckMmQHxYAy5oLQJJzY+G0q9GqOcPHmBMZ3c0NDjckCQ6JF3Mc4w0Acir/FTx1xNzly0bNtaw86bsuO3ZLhBeKXyLJTV9JFJKlYtdHIqw0UCTQTyT1EJlmquiVF9sDpIMQY+pQD2O8NrXNGZ1zoC3S7reRggAxOUB0+r94pU62WrzVHgkNaZggkOm8CN6jtL2kNa2QW1udvFd43bPV2HwR8nS3WgXyl3RuaPbkO29obYeSpkroloHYTXu9TvG0paeFKdZBIOmeF8eXG8Cw1BrKnEQ5gGgcc1R0DQUmgNYBP/uPN9Q4TPmsT7R1Klaq3h5p1HOFi2S0EhrTmrPOWRAAbTpmBJ5CAu8cSfYiWG1HeHJfJfL1y3Vylum6G9Xm61PF+0o1EToqpTxw19JXyU9MFMf8AsoZTkL1Et31rd7XMpU2YaixzWMn/AN5wJPU5AwOM+rRPKFwa3DHVcVUxFapTqPfAk0i7yjytD3HlEQH+c3JOqyfKn2K2xd70lt2c/OfNlj2jJdVr73b9vx2TbkVdUhg6FKWlt1PDK6sHkA8vOGX3lGerJhvaik2t4xoBxFhmc9x7m7nGw6wAtT+DPq0crMQaZMkljGgG8ictmgmATJMi0rdLnsTem5N40Ph38QvG+6uZxtBIIK/cLWq3QWC42ieSb7muUSTVkaGqKU08M0ccXRFJ7VC4khdfMxFgZ/1lJwGbq7mzbtAyuMXacx7Ecwt6nhHEqTqRw2WHiSIa4WESSQGwP+LSSRGgMqZu3NpcjcW2fZdPtra9Zunju3yimpKOS6R3K7WacKYxUO5eDzFEatEyyyOySdByynXLjxHudmGYz2AB1AkQD3AEgdSrX42lJa4kEjm5TLoMgfiJEEnr0NjEgbRyVY7ju217eusG5L21XQzVEAe2COO3wRmEES9A6YijMASWJLN27DIyOqcxJiBuSL326/Abd1S7h1RuGFWnyOJFrzJB69RsY+azOya23X7c+975czaUs9VXrabUi+WWuMcEMZqHfpJBX2gyRlQB70B6s9hq2li2Cm3nBzEutFgDA7ydb2uN1i4hQqtDaLWEFgub2LiSIm1mxB6G1l2mS8UNLQirRlNGqqQVXC4PZcfAA/DQq4poEk/Vcengnl/hxf8Ab9lq9m35b7xJXSUlRTV1JFOaWM08gkaomDEMEUfAY/F6Zz37HC0qxdfY6d/09Pmt+M4Q6jAMgxJkRA7n46enVbZSTVzRM9b5KSkkhEJIRcnAJ+JxjOO2dXZoXOexs8qcGU49QBo50BTSTLj1YaBfKbw+ySZsd8nOoHHRMKaH5w9DjUzFN4aQZj8B30PVMKaGZSSe41A6E/hoZk+uTqZ04YkGQfPJ0M6bwwkGUfTQzp/D7JBlP1OpmTCmhmX5ldAvTZEgy9vxE6hqJgwJBl+BP8dDOmFNIM3y/ho+In8NCMx+fbUzJvCSTL9RqZk3hIZl+pOoHpxTSDKM/A99AOTCmkGY/nqZkwpIbTHHcgHUD04pwhNMTnvqF6YU0Nph89DOm8NBacZPf+OoHp/BQ2m+uiH9URRQmmBPrnUL0fCQTNn01MyBplBacYI9TqZ90xp9UBpR3GQBo5+qYUrIbTD17amdN4abtN699MHqCmgPOg9XUfrqZ+iPhpu86EfiBOoH3T+Gu/GUfE/n31wTUXhQxI834+6dAPRyJQlHxI0c8IFqV5w+f8dAuQDFfzfq2iHqeGsDfK2qEBSgqoKWrj6Z19oysE6g90eQAlQfTIGR64Olc6TGi14Oi2Ze2QbW1HcDdR934N13ikp7CtnoaK01UwgmkuZnrTKznCLSwI0aEEv0t5jKegHCnsyrSJaZNjtEfEknS3QSvUYSnhwc4dJAkxDbDqYJNwDa06nY47Y/BO1tqz7WqNvWmsprLYKprxDE9b1pdbiF6RWGAFwmA1QIkR1RAVPSSEZdjsa5zi9oA2HWPWwkiJMT6SQsOMxeZhpVXXfYwDyj+mScxAtMzJld+vlrpty0C0S0FbTMJkmieQGLy3U5z27gEDpOPUE4+B1RrYrl4aqaLsznAgggxex+/gVerq7dZaRKyWmrLrfJFYxqpHnZCnKqx7RRgKcn0wCT1H1ZtS0D79fv0CDaFSs4izWD5X7fiJn19AuS712xue/bhs63bc9LUbSCwXO9WaC0pLDXNH2p1jq3JdQsyLM2UAcQoBgnT+KxgcWZidBeNbGQB0ka7rdgyC1oYwCCQCSZG5tIHQbxJ2QN9bSstbYbTet10O99xWzbMjVdNa6W6LQlmkp5IBIqiRGeXy5nCdUqYY5QK5BD4aodDEutzSehjQ9O/Q2UDyXkUIDnzcCZjadPp3JgBFotm8l122knsO8rhsuluVPPLV2rc1K16jt8UzDojCPOJ1mji911NQYzIz5VgANXVX0QSHiI3aQJPYQWxO4EwO5WDxaJeHluYiAAOWdJJIgdYhthFxqo77Y4WvO26mnuForW3xydVU8Vlp9zbvMlyrI7f0BZA0iFY6WAdMgSmpgquABP5kkjSaqr8VdWaKVIhjDchunYkky8xubN0aAF6WjgaVIOq4k5iy40bzG8NGUxqJcZLtc1gue+Inhe/wDiK4k35wHzhNRc37earpY7xZ7VQx01LURRtG7z1MzuZqeVIlVlCFJlZl6S+SzX8JxzsNXFeiSC2bk29MoF5NryOsKrivDMHXwwApANqWAMF2tspJgX5sw6W2C8vNtx+Jn7JLkIb23+m+vG39nvY7JDtyg3DHSRRby4h277TLLHJJSyL1V1KplCLLG/WIYx7sHuqfVPp0OJCMMfCrvMljictR0aMvDTuWxrqV4pzMVw9h94aKlOTDgJc2JnxCBLwAYnbo64Xr5sjxoeHjl+27H5G4L5LtPJfGG6bdV0DVu34GnqLVW0cC1MDT0o/b008fXKGWSMsGkjHcYB8bXp1qJfTqtLXNixtqY+XcGOi9Vw7hoxzG1WEOv5pkOB1E6GR+Gx6gLzuWzbP4lpt7734a5J2T4e+aqa71tk3PaKNOjaW+JoX8+kN2sjuFC1dME6a+ieCpWUn3px7h2O40cRlpYkGo0gQ4WqDrDrBwH9L5tEZdV2m+yFVpNTBktLTMOuwF2tr5COrRB/Fm8qhX4bvFjuHj7a/NPGnNfMmz6zdEc1buWw2DbFGs0tDQTTTzV0m17rHKKW5RRtUxErNHHWRSdYCgBS/W4nw6m5rXYNpeDDS4xBsAAQRmYTGglpGhO1Hs/jqrsY5vEYaWy9rRrYzNrVAASbERPOwSCN18P2wvGdzht+W77R2Dx1tE7gukH3be6/dtfb5ZrVmq9tt1nho4JI4rdPFR5Ssn63jnmqnpgB5bx3VMJgqT2ivUk6kZZM2ILzmbF/wNALmhuciTLYnirxndQaAxunMIEnRoIeXkAg5iQ1rnEAOyAL0p8OXA2wd101Hwxyxwztfjfj3jKKifb3HdlrJqjb01rq5ZZIrrWFo4xXPNVUc8ApKtAKWSCQusspWfWbiHFnMJxufO99vEdALYtlbchpgglwOhhuUTPGo0mMYcFhBkaSTlmcxixmxIaMx0JJEkxlAiLuLl+427de8vBD4ArTsrgO97YWReQd8QtSmi41tlXUPCY0jYmOS9zsJWpoeookc/UwMiQoHwdB2Jpt4jxJxdTJIaBM1SB5QYu3+pwE2yt3K6PFMmHqjA4IZqrgHQRLaYJnOW2N5BbTMAxnfFMQ7ddl+FXhjw3VnC1/2BxXyFvPdF+u1urr1y5uGuir9x1VP58dSlVcofMatnt7vArBHwUUBQgU9QbEcZxeIaaLMrKbQYpsBgSCDZoyh8GdfyScN4Zh2PrYmsXVKh5S83mIsHvcAGg2OQZRNrG8Ntsb25V+zK+0Rr+N15EtG0/B9zVuSs3VxvOjQUmzrHdatSKm3V6tGrUEMssdKB7O6MoWGbpk/aDXTcafEsCMS4F9akAHmTmibGJIJiZzDqARZeLxGHdw/HHDPhlGrdoygw8C7Z1AvLcphziQd49zPGn4XuOftQPC/vPgXd9BU7T3dSzvW2wvcVeo2juWKldaSWUQnpnhIqgQcmOeCfzB8AvE4RxipgcSKzIc0i++Zs7aRpY7EKviHDadXCPo1yYPaIOs3m4/ENvKdZXxQ/YO8m3Xw8/av8R7S3dAlmnvv37xveqaaTpEFTJE2EOT7zJVUESBfjkjGca+re1VLxeH1HMuBDgewvPyMr5ZwCi6hxDwatnAub8f7kR8V+ghyJs+i3PbbhZ7NbLlT3cmGporjSVslM9tfzOoS5jdQ6qwLeS3aQEqQUY4+H06kOhoEdwDE/fwX3vBPIAqVXwNxrmIFvj3H564u332wPty8be3XYbHS32pnFg3Lb5oBLQV0k8TIEZQcezTQ++mcfsGxglWUXVM7SHU56yPmT6j7gLP7u/EtuZAEtvcQY0O8m+vMb6r8uZfDpu7fHim3f4ceP7dTDdsN/3HarVQTuUEgt61s4gVioJdoqExoCB1OUHbPb78ziLPcxjKpgZQ4n1An6nZfCuJ8Aqfxarw+mIeHuaB6Ex9LBOfBDx/sLmLxfeFjjTkyvitXG+4N7WWhvTyBh10T1CNJF7vcGUDygfgZB8tX4zEuw7H1iJLGuIi9wDH1XF4ZgjXxFOgLFzgINtxb46L6f8A7YDxg37gvk9PDp4fZb3cubNwW+x2K2UUitVVlHTVBqnidDIuUqDLUCmEQcKfUqUAY/IfZXgw4gM1S1NhdmMwLBsgn/7F20bEr9Me1ntK7hNEPpx49YDK0D/k4ZgBYttlDdTIGkhSq+zo+zm3V4I/CtvDxJc38nbN2LzZeLZU7w3TeGRLhVm3hBLBbqy7VDkLAwHmzeSnvyThnmcIqjR7acfw9TLhcOSaLIgAZQXE/wBIEuiwaDEXhsmVwPYLhFajiTVxVLPiqhLXFxBIA1jRo05jP4QAQGrlXGfHlf8AahcxbK8ZfO+0ZuLPB1aoI5ds7Mpqp5IORqOOrkb7zvwn6YjbPbqWAQ0SxqZUjaUpgl2NJ38DpFgh+LdeY/25BDcupNWCSZs2QOgXWxFN/H6nhUHuGCYS0XvWPLmEDSkACLmXGZJEAfQFd57e+wpOMqy8buq66/Xql20qeaIAaercTSeVIiqej2WOrYg5Zelo8gJgeSwT/wCc1zm+SSZJM5Zde+ug7kyZldTG0cn89ha1obILQJBAyAAGRZxbEWiCBKkq9+pxVUjxNFQ0da7yRweV5TzuoJCENj1UKfdyT0YGq/EJufj6riNwBDMpuWwJmbdo6d+sqJvJW2J+QOXLDY7ReodqR2Cgj3g8/wB2pVMt4jkljt9PKjYJQh6yZ4kKsRBTnqXqzrdg6zWNdUO/KAO45j6hsAHQF+8Lo1iXUxTc3PJgySBlsZBFozAXM6EBfPx9ob9pHU+H3mzZ8u9uPavbnP2y6umism2o69Xte4bTW9aXcPdEjCy089PFRRJJMkbU09Of2TOjMe1wTgb6gqCm4OY6QXROXLOUZZmc0kxq3QgEK/jXHMHhaVN9UuzyCBBBfJAJaSYa0CTe2YtzTEDye4fo6fxF8xb25kruCtt8x3PkLddFuHa9hpqsWTijbl1Efe23WK40scNfJRrUrFIsAkId/MjWTrlx7muKuCZTpNqBj2gzVeP5hB1cxjS4gOPlLgLNjM0AE/OeF0KfES6vUpvr03wfApmWWBDRVqnKA8eYhriObyE8o9orB4COYjv66XHlrxK3Tj7fFbG9M1t4PvFbtrb+xUkeELRVUJIrqmORouhWlljp1jVniSRiq68NU43gmAUcPS8YHzPqiS4yTZohovqedxsLar6dw/g/E8SG4qvU8BrTyU6cQQABOdwcXQACAGsAMzlGvovsf7NPwyXeM0e9eRfFNvi7Wlwtxhv3M25+qkqWIlMhjirEEbEqWDDAKsfTtjM7jt8woUg28fymntqR+uq5+NwdZnN4tQl4m1Q3E9iNNBrHeV2Gn8I3hy40oJtx8ReIvxI+Hm2UMDvUXa3cr1tZbqSJcly8V8aupO5X3vdHbPf00tXj7A4NxOHpmRblLCZ0A8MsJ6jVYn8I4pUHhtc515ykCoSbXIcHEQPiOy5NzvxD4ytoWBufeIfGfsrk2/bTs10qvYOS+PLZS0m47I0Cz1VNNX2o0zMpEMM8TmEqsqRt7oZi17Mdw97HUHU3081rPzQ4GAcrmk9tZuey5lHCYynUa9wa64sC/rFodDT1i0CNF54bj8Q/jB4dsNm3lzDyd4muG7lFaprxcN2LtCe47RrzDCktHQChp46mljR4A9M9XUVEnn9ccv7FlMQ6ruC0A7JhqfiZdg7nJ0JMubABg5QwECZ6nqU+JU8Q01MYabPEPLyw1gJk83MS4gnR0SCGmYaOr7T8RvL+5Nt7X5G5k8P20d0bpu9tgrdt32l3HTrZLBLXwNUrB7APaaa33QnolMHnzCrdkjheRkECcWrhaNN1SlRrDlMPMEmxGjgBLQDl5Q2HSXADmXpcA+q5lNz2OAdlcwaFwAyEOl2YnrmJaGwWuJJCnbtLavDu1LDWzLtywbUs5t9JRyVu26BpLbcROAUkFc8SvT1oV1VwzRtIrK2JGIVMGIxT6k/iuBe0QdIBPLtqeg3nVh6VY5KdQgF2YwXde1pnWYN9YClHs3jfav8AZWCy122aG+7WjkMtuoo6GTCQoEeET+c7kFcABThiAOpQCRpa2KrTncZcJvAAnTYD9Y6yuK+lTo1yaByOMAkuJ6zF/jOnSdV2zb1PQLJTBKW1U9dHFHPNFTIFjpAVKoiKFAX1fPxPTn4jGfxcxkmT16n7/NYMUHAECcpkCd73J67fktzWpWTr6CCVYofoR66gqLB4UKjMfQHvomoUfDVjLkZ+H56gej4YSDKPnqBxTimkmUd+57/DQc/qmDCkGVcZznQzo5CkGUY/FqZwmyIZkyPU6XOnDUlpPl20fETZSkGX5nGoXphT6pBk/M6XPdHwwhmX17jQLlZkSGlORgnRNRMGIbSH4nGhnThgSS/zbt+elzkpgxCMoB+A1YXbKzIhmXsfjoZkRTSGl9e/79TxAE/h9kIzfXUL0/hobTZz31C9OKSGZvhqZ7JxSQmqPgWUaQ1N1YKSA9Snp1jUFTdMKSxDX2iF4Wxf7abgaU1gIpZfK8oOE/vuny+vqI9zq68ZOMDOrBmLS7YR8zP7fD5IwMwbuf0j9/u6eNUEk+6366QVQVYKPRCaZviuP10PEU8LqhNM+fVFH6nRFTqp4IQWlbJPUP0GjnT+EEBpTg5dif00M6PhWQDL82Ofz0zqiPglD60HwGNQVNkRSQmlUfAafxEDSQWqPkdTNdHwl3czj6k64JevEikrif17/wAdDNChoqvPGDg4/XUzlA0ksTj56heUPCV/O7+p0Qd0PBCAVjeYTyFpHX8HUBiP54/P4n6aYPhMGENyhYqqtslddIKyqrZpKGNSPZM/s5CR+Jx8SPlnGgQJzLTSrZKZY1ok77/Dp+aytFTUtvhkgpIliiaR5WHUT1OxyxJJJPr+QHYYAA02dZKuZ5DnmY/TRImm9ngWKEVaqi4URjqZh8gTnB/PQLkWUZMmPjZYwVNLaglXUUVdGsuYwI4Wm8hPU+aV6jk47t3HYDPbUBIsArKjTUBGYWv0n0002Hx3Wvy8hbDpZo513Lt6KerQQxLNWRwswiBbpWJyHPT5mSOntkHsMaFaq5ktcDbsr6HDK1Rghpy66Hfvpt1T+P7tqZ1rtwV9HNW0zskPnlYvZcYYv0E4Vj0qeo98AdxkjQp4hsHm1RxDSwZaTYaRJ3nbXcCY9Z9VzrmDljaGz6BYblu/YkdXNDK0VsrpJJZKxVADdEUAeRh+0XICnORjQBqPM0JJHQTfudvit/BOG+I6XtcG65hAAA7ugfVQkuvjg2BRCTaj8S86vy9PbVqW2ltLbsEl5vtN70KyQwzvHKsWAArGOMYGerCnXS4fwnFYk5AW2kEl0MB/5OEgH1Pz0XS4myjgwa76gNGeUvzGd+RsSZvr8rysMvKXi021Q7Yv3FXgRvtrpL3Vtb7g3IPIlpilo6JRiGolttJNM7OxjI8sVAZfMBIbuda28JoME1cUwEf0h75naS1rRHUSOi5mI4x74802MqGNCGsZl3JkucSLxAZNrwopbj8VHi7Pio2/4VdzX7cdNveS03K+vRcbce2LcNZQQU6RKgZ7hcp46FpVkqGV6lQWHkKhJZ1HV4ZwWiWVMUyXMaQJLywXJ1/ljS05Sd72VHFsbSpsosDAwPBPNnuGxux8m+xYAYNlDLkD7L3iK0xb25V8HniP8V3hm8TE13q5L/T7r2TeLLt/cKSTRvLQVVHaLfTJSQsI1DGj60cMT3XpK+nZxJ9doo8Swmels4ObUdN4Muc7NroRrrdfPKGFbhsSa3C8U1tU8xaCGtsIIghsSZ5pBF4K4R4L93eBvnTmTe3CHiW8OfFfhy8QtPHRUFq2zuKSrrrXu+9RTSxSz22pvLHyoOyuIZX65OqIRl1hKtm49R4lgKXvDXyx2jgxrcrY1dlFj6SNZgwF6HgHE8Bj64wuLZzAy4OqOfmg6Nuc46RBjSZLl6HXL7K3wc8l7V3HsG48TWbYW5aWdTV8oWGOO2XqxVsgDUM1rhihhkmWZJGC04hEeYyjM5CufP4H2xx7HhznhzDHIZdm66zHUkkayBFh67iXsXwoU/8ApqWSqcxaW8uUjUl0wMp/7iRrutHtHiv5x4J8RmzfDF4qduUu7+VKO1TybE3RtyantlNzcad/YrclDG6lLbdFkqpFnVv9mWOCokGQU6q6vBKNdjsdhKkUnESHTLC4y4vcAZYACQ4czuURKpwftBUwjWcKxdL+ZBhzcpa4AB0NYSDnJyjw5sTMgC00qbwu8Jct2bkrmHxH0G3+fudrjRrTVdtnvNf/AGRs6hnioaGgpaaZaarRJahnWskRp5pah6jog6xGldD2gNBraPDwAySC8ta55J8xkjlECA1phrQAXOMk6H8BxNeuHYpzqLHxDGOLYaOY5puTfmLhH4WgCAtl294ReI+DeT9g2PhaHZPDG0bDZLdXpt+kvcixzVslZUq1fNH1BhLIr1JMsnnEeZNIhgceY2XG+0JxYdUxDwXGWgjZuXyjoDaQA20B2YGE/BeEMwtEspsc5pLieUczgWmSSJfB1LiQbcpKkbZ977Z4R5C4q4H27YK627DuctRW2ujtNMGbaTQxNKLfVushOKlop5ackli0dRGoI6OnEKrsTTfiTzZNY0l1hECJFpA7E92r4XKYqO56gLQXXDiLuIkWABg7TF0DxFcBcBc47e3bt6+bG2lyNBuCjNFuXal0k9nF/plJdVhaYKtHcVZuuCrXywzgq74w8d+E4xVwlVpD8h1Dunqd2ncGfTZcmtw92LoOpVW52NJAAuJ3IAOxHWRqIXgNcuZPGH9kltfanL2yNxT+MDwM224rZZ2ulR7Nvjj+0I+Dt269ZaOZaeSYNTzEMKeTqAKQ1B6/WspYHizslJ3g13Sco/23O/qadgY5huNBIXn+I4LHcLa99eka2HaAcxPO0aS4WzAbHlJgBx6fPry74gePNq/an3jxZ8NXWC68ex8q2vku3SqOgJHNPS3GphZf8LI8tXCy/BkYfDX0TgmFqPwDcPWEOylh/wDs0H4iDPRfKeP43D/xc4miZYSx30aTpv16Gy/SfO+bNc3qUsxq6+hV6KngqIEYwVdNMTPT5ckf+pdST9G7ga/P9cPYcrhvF+o1+X5r9B8OwRcxtRzhLgXRuLQSBfV2nwWD5Crai0V9t5WoXlorVaf9m3HGk/lvLbHOXnCKPfkonYy4b3TG9WnfK600AKoyHfTrP99PWFkbR8KWRJdpOltLnTMBrroV+bj9pZZd2cC/aW+KtbBf7ltvd9r5Mr7/AGu6W2doJ6OSolWugmikXDI6ipQhhjBB19x9mQyvwmixwzAtykHtyn5wviHt0+pS4u/FUuUkteOt2gj5f5ULuKeRd08Vcrcf8ubNgt1bvnb19pL7a1r6JayCSvgnWSLzadu0y+YFPQfxHA+OvR1KLn0zSaSMwLba3Bba2sGxXjqGJisMQ8SQ4OMkiSDmuQQQDvEbwV7W+BG2T7ovG+vEdyk3IXKvP27bvX7c3Buuf2aT+xUNZA8UwiaqYZvVQzmi8soBSxErGyOyKfn3tPVfhMOMBgminSaBa4L4M5RF8lsznfjOttf0B7CcNbxLGfxjijzUruJgCMtKIymNnfhYweTopy7r3t4mftDt7WTwO7f39d9l+FvaO3LHduZ4bPXPXT25YuiF7fH5ojkM8hheZ6LLrCzSqzsy+VrzmCw2CwRdxjFDM7MRSboC7+oA2hswHQAToLhy9JxvFYjFPZwnhsML2A1qn4g06MLmmxeBcXcWQTaQvdLj9G2BsG77U2vtkbm43prfNFRrbaeejp6K2UpWakeOVjFTQHHkyeXAoQiUdweot4jGYt1Zxrk8xMkmCS4mLXLiZ6iPQQB9Ew/CqFBtLCgBgZAa0RFxBERpFgXGbEmV2Pi/kjc3L3LPEj7wsVNarNHQVW4KOnqZF86oleip6VJZ4FdmWR3qrn0I49xYWLf4c7cNSNJtR4cJ8pAvEuza+jQSe8C+nmuN4DDMoRSnODmnSIkEAkRAzAWMk6dV6F3Ojiu8T0clRGFfpBDqHGQ3ZhnBUg4PUD2I1R4gF5heMpO8PmjT1C+XP7Rz7VLfvhD/ALLbR8Odz2zvHxF8k3C6Xqirp6H7xlsNhdIrZZ2hooh0T1dX7GssMcgK/tPM8vDhT7L2c9nn453u5JbTaBmgiXPcc5bJ8uVpAcdQI3uLPa3jVPh1MeOwOeTlY3mgBslzjAzOBeS2GkBzpBMNIWS+zm+xF2/fqqbxLfaTNdef/ErdvKudXte/10lXb7EZBlI6+QZFZXoFHVF1NBB2jCEgtrscW9qqOCb7jwUBtNts4Fid8nYf16uN5heOwnAMXjnjinHSXVHzDXRYDQlugB/C2zQDoTde426+AuMuPtpJLtzj/Z9v2dQ0YpmoIKOkgis8KxvFFNGZv2TQwpLJE0bgkxSZ7tEmPB1MfWcXVHOJcbySZJ6SL3gAdLd19J4fX8R7cO0QLAACx+AiDaQRv2JWocd7E29ty1QbdsV13tQcd3Kkp6CkpYKVJLhbnSmZVhqrjURvU1FOIlUxvKxljkiK9bqVxXWxra5Ic3mkmxhuouAOvQTOsSukcPVogRlLm7uJMi+05Zk7AWI0uF1+m27uiy16V1kvdz3m9Ev3a/tH7NGhGJfPkCoUlm7IvbvkyHC5KnG5pnM0R96fp6AXKDcRRewMrgMkT8dOsgak6DRW504X4p8TGy7PsLlvZtq3ztiKriuVJC9wmj8ip6GjSYPEVYYE0n4wV74KE624LGVqFYVKMBze0xvvvb126lcakw0g8BxaHWNokDbv9mYRdo8LHYuwN0WDeO89y82V11N0e83K+RwrVVEVV1IsNNHGBFTRQwt5KQRKqnuwAZiNWY3GtLf+nZlgDeSXbuJNy4n5CB3WbCvfUqNbUOWCMsWDWj8JAiRaXE6mSbFYHh/etNFxNxvt7cG09ybWv8VmhtsCV9MjHzaOMUitNPG3SJHSJJOh+lsFx0noI1RxDGGrUdWMGbm4gZrkddbfUbLoUeEmlUIpHlBNpMkTIgRHy7aSYhLyf4GfDPs+1XXfHHXhynh2nfEP9prVsGaa0VUMMwkkqKu3R0rxxzqGZmeGVJVOFkgUSL0SdlnH8TWe1tRwcW3BeAdIgTq2exHQ2uKcLwdlIPpNqeEYIt1mxcDYkTIGoMzsuM8G3raux93b04+8Q+8+LN78fU81PTbVlVJdvQTWud5JaeeqpI5IoorgjSvR1VM8UJjaKlnEax1C9Ax9YUw2rTaS9xOaQHZSBcAwbEXBvaW5iQZ6+Ap4iu3KxzmZRykRLxMSZk/Iw7WJsvXXbls4lqKajotsbneqtVZF5EUNt3TPVU86FMD345nHvJ8274BySe/FLw55zNBI1tpf0C59Sti8oqPbpBksAP1E2XU4bLBSAR0NdcKSnHR+yUoVAX8IGVJA9Pj6DUNUEzvr/lc/xXOMuAP36rMQeXTxeVG0jLknLMWJJOSST9ToZgqSwkyUszjto5xNlPCSfPx8M6AqdEfDSDPnOp4lkwpJBm9e40mdN4KSZvqdHxAm8JJMwHqx0ufomFIoZnHwJ0RUTCkk+f276BeU3hIZqB8SMagf3TeEhtUqe/UuPz0M6dtEoZq1Pbq0MyYUUk1I9PeP6aId0TiihmpPybUFQphSQ/aCfp+uhnlP4SGZyD2KY/PUzphRQjUt/wASg/LUzq1tJDM5+LAfpqZynFJCM3fu7Y+p1M6cUkMyjuMn9+gXp8iG0qjtjvqB6cUkNpfoo0udOKaG0w9OrGoHhWCkhNOB26iRoF6YUkEzD4nTF6YU0Jp8D56GcommgNUep+GoXJvBQWn9e/8AHTNeVPBQGn+TfTUzJhRKA0/fsQP10c6fwkFp/TuRotqICkgNUYz3P+moHFHwuibtUYx30Q4yp4S7x7SME51wi8SvFiire0DHwxpc4lHwUoVIx+LTF6XwUsVPYdxo5+iU0bq4qR2PVjRD95Q8FK9oHzxps6Boq/tHzONN4hSmgiCowPXUzpfBSvPH/FoZ0PCSTUgdOWAJ7Dv6nR8RTwSmNZFbbmKmluFJR3FZqd4JknjWQSwsCGjbIOUIJBU9u+mFdws0ojDkAOFo/Nc1n4g4nLUC0XF/GCCFlZD9y0oki6E8tTG3lkjC+79B2GtZ4vidG1CPQx+SJwrHgiuC4RF7jrBBPxXIuUtjSVd72/tTZm4odl7lv5nNUbXaaWaems1NETUSwmVegTdUlJBFJIDGjzA+W5B0cM4OBfWlzRcjMQC4+UH13PmIaYI1XQwVQYZgGGY1uTK2TIIk6NDdALui40m0Bds2JxVx1xytfPtPatutVyrgGuNaxaesuDlutmqKmQtLMxc9RLscnB7YAErY57xlNmjQCwHoNB+dzNyVgqh9RwdUdmcNyBP0jaB2FlvUlBa5ZIppKGmaZGZ0crlo2ZSpZT/hJBIyMdidZW1IkDdTn6/Y0UebFtPZM/ib513RbI46TfNRtDaFFdamknC1EkCS3h6eKXufcwxYKcBux7410auIccE2kfLncR65WSqaYDKrDAMA63HmMx0uTou+R1EqSOlNW1ED+WY5+gsszuCpXoDdiMdY+XcYPY65cg3IutT6APmaCJt07zHwUCvGl4ZfDf4wdnwcc+IDiGXfNPaKeWG3VU1HJHU2uWdO0tLXRftICFTzDhgpYRh1Zex6/B+P47BO8TDExuCRlIHUGQegtI2Wyt7LYXGMPvWV2cyCPOI/pNiCTA6QOq8Ua+2+Ov7I6n3Hvaeq394tvABU0JWriu1xoU33x5RlU/bU9VIGjqpoUCxggyKqR5EdLkkesdQ4dxUto0AKOIP4ebI+9wIuJNyQJ7uXBrVuJcKOeu/3nDU97F7YFswN3MHQuAN9tWWxuTPDP9rDW8hNumW98uimpKam2xt9aiC23jY1lkSOR7rLUxoRT3GkrVSJpYinmpCz9LpUkScupUxXBSJGXNmLy6XMdAIDdOYOEntygwRb1GEPD+P4YMpwWtDSMpioHuIzOAzS0jytBJGuUHVaBwr4h95fZ1VuwfC7z1yZdN2eFiybniit3K2z4pqG0VdZVVLPUW7db1AdqIpFLJLDLA/lsZDLlwwC9LEYSjxMO4jw+nmMf7b7EAA8zA088mB1GkSSVwXtxfCgMFxR2TOSBVs83IGV8/7Zi5kw6B5QIXvZxD/YWlj3jyDXeHXdlq2fu02+ntcD0tM9e9t8mVoaqqhM5qEmq5qysl6GzKizU2fecqnk+IGowNwxgubMgEWNhlmA3lAEwYknWCV6Sn4mInE0cTYEiTOV0EmW8vlFgDaYJgQFg7htzZHH2xt38c7UG9LNvCslpL/typ3DDNLLS3eNpaiihjdVkWFYnp4VCsVXyXky6lnzVRrPDwQ0Bgs6IuCBmuNZHTsNl1cfSrYwtrVnBxOYW8ov0MazfcuGhWGufjQ4q3HZdo7P29su6795S3HaPvC328RyPbbfSTQTVNOaquC1CR07rSVqAKrSOaaT3OrGa8PhKwLgIDW+YnsRo2QSRIttIkhIMC11RrxVhtoA8zjBBiAMpMeYkDUCYhR1q/D9c62z1vJ1qiqt9V1wFe9+4taihr7JuaylpIaqCGKNWla5Q07TNAZpCxVnpwAs0Yj6WDxtNxFEy18Ah4JBadRvlAJiYJvBmxnR7R0i1zqoANKzXTu0gXMwXWAjKIO4sCPhP8X/AAjbPD14huWuItr3Oe9bLoK4Ntu4moSd66z1MCzUkruqqGbyplVvdVg6MGVGDKv3fg3EzisOzEugOMyBoHAwRfv69iRdfkf2v4EcBj6lCnOQwWzu1wkfT+6+/wD8FPKV95W8NXAe8LJJY7k104t2+yV1Jdgv3bXU8UULwIGIPnRrGgDHK+bUzKx6V6V/PvtHSYzGVwTBzmZBBjeOgOnoJBuv1V7LUmVOG4d8HKWg6A5pG5A0mZ3gARIlTD2Hz/tqXZt2a1Wi/wDJOyKK61Vgq6ymtwjKLA/kTRzQORJMOrzeqcArIeor1ggnnNq1GiCIMAwTeDpYTFogGCrOIezgr1M3iBrjNpJGYXMGIsREbfBfnffapb3rd++PTxL3Kqq4rg9svce2qWoWneB6mkoKWKkgeVW7mURQRoz9g5UsAAwGv0D7G83C6VQ2zS70zEkj9Rvdfmv/AFNHh8Yq4fU0w1vqcoJJi2pOluib/Zcbdod0eOngm31lPV1MMFdV3BZ4YaaR6Fqeklm9rC1YaD9iI2mBlHSpQMSCoOtvtXjPd+G1qxMAC8HLYkAgEdRbrdZP9N8C3EcZpUnND7kgOEiQDlkakB0H4L1j8UPizrNg8ec7ci2it39t/g7kXetfuDiuSlraNqu77iooKemraq7U7Jg0VasNNVCWBmhjemTpUSTqyfO8Dwh2LqUcPVg12NGYHMMjHuJGUz5hMGbmYENa6fvPGOM/wpmIxBbloPdDSAHCpUYLiDEU3ESDrDS4k5mg7f4SLDR+Byg2Fe+Um3bX7t5LgaXdxqWjqp79cZJfaovZYVKSx08Sw1PmMxcVEsQIwFCuvtJivfXOwmFgNpABo2AHKS6ZGpGWPKLmTpo9h+FnhmHGPxpLq1dxL3AXlwzBogSDlBzzHRvVe2m1tg2rb216S0cdjc9Rue13GS/XG3Um35ztzbtxw0kMcSM1MKg1IkQSrJ1mPMUixRIsUB8ZVr03DO/QAgOLmS7Y5fNAG8Ak3lxcSR7zC16/iGIa2oAQDnzQTJkwNLhoJaJ7ST2Tw5WG23zk/wARHPNFv+Lb0FfLt7a0VLULJPVT1VHQLUS1M0kpjJZnubQ9Cwr7kA6QofpD499NuEp0oh5c42iIkNFuYk8skkm5griPq1vevd3087GtiSeuZxAi0DNA9CSTErm/2nX2mNn8H1g2/wCHbhyz3bnLxt7tt8NJtLaFut5qPutZlMSVddHF+0JYh3iphh5SvUeiJWfW/gHs1W4rVcxpy0m+dxgADcCbTGpNmgybw0+M4x7Q0OGM98qtkuJyNBJc8g69mA2LhcnkZzSW8C+yz+xrt/BsNN4kvGTDbOT/ABg1simneqqku1DtCnWKFIBD1II3uCpH5TzqXSJVVICAC59V7Te2NPIcDws5aX4nAQXEmSATcMJMnQv1NrLyXs/7P13YhvFOLAuri4BPliwkDQgCwmG+pJP0FpT3iCPy4Ki2MCwBx1xjo9Oy+9ggemDgfL4a+dzrey9v/LcQXg/Q/t+/dVV26ruscMN1q4RTK0cjQ0+QkrL3w/VklCT6dvwr699QnrdRjm0zmpAz1P8Ab7utJqLE1p8i02hI6GbyEel8rKpCsRQCBMEHAKp0gYIDduyaUy67vj3XTpYhpaS7QSLgHXc/Mz1jutysdSkvmVEddXzxMSER5GMcf0UP72fXOf550Q8TA+/gufiqJENLQD6CfjFlsXndySSSe5+unzzqsXhLB1PXTTpX1NcKmGN1kWGZB0o2fdKY7lvQDOfpj10jqhaCQbrU2mHjI1sTuP17dY+q0TjygRNlWzb16tRr456SWW4NWRRlJTNK8ghcDImAWTp6u69Kr8TgaKtWYi0QPkBdPVwbqVRx8TMQ4xE9de3p67LK0+16HbUE39mWuMMeI0ipDUGWGnVBgCNGOVXHSpGTlQB8NZapn1WtmIdVIFeCOuh+Y339b7qMe5OH9tVV02LRb0tFsq7xcbe+2JJ6umgkpbrNSwippJpkwQ0wjhljR2HWrxnpHSFz0/eKrnPqsfDgJsSIvBjoDMm+iubiKVPNTZTLqZcCbTANjJPS0et91hrNYq/bG3aCuqN2QbR5GoEgspqaK0l1kq1l7J5LALUU7KGcwyhxGZA8brhW1S/FOe6IJaTvtOpm5HY/BdZ+CpPORjRldexAsBpaLxblgm4hSGpd3V1to1qNyNcrldqbERgZUhFW/oKimRQnmwsyt2I8xB2KkgZyVHxGXUm0/dlzaXDvEcabIbuSLwOhMmCLaGD1XUrfeFr6aOYPC7svViNsgfD1+Pof+u+iHLmV8Hkdl/NPhVM3f+R1MxSeAkGoft3XH56hfdOKISDUP69SAfroZ0fBCQag/wDGMamaU4pKxn/5z+7QzFEUeyGZj69bfv0A9MKSQZfTJbH56mZMKSGZl+mNTMm8NJ89Rnso0cybwkj2gdu/8NKSm8FDNSTnsdTMmFFJ9oYfIfrqZ03gyhmoJPqM6GdWCikmoPzOdTOiKKE1QPnnRzqxtFCM/wBe2hnVgopBqBnGfpoymFFDapGSMnQzEJhRKQaj0Oc6mZOKKE1Sc5ycaGYJm0UJqggHv20c3RWCigtU/MgHQLk4ooTVIHxxqBxVgooDVQ+B9NEm6fwUJqn66GZEUEBqrtgnUzKGim7VXb1JGmlN4CA1SM9iDoF26IoTdBapx3IOPqNFz4TCimcl0pFLKaqmDAZI8wZH5jOpn+SIoGYTF71RDsKgSHPois/8gdO0OlH3eNUF7oPRaetf8oyP540JITGgIXfzVZ/xa4Tnrxow/ZV7Vn4nSgqeAle1f8w0SUDQSvalye41M5Q8BX9pAzkjTNd0Smgle05xg9vz0Q5DwEtar5EZ02dKaCuKoEnBA1GvKU0ET2nAwD30S5A0ECoMNVC8EwZ4mGCAxU/oR3GlJnVMxjmnM3Va8bK8kBgrb1dakAk9aFY5CSQc9YGc9lwexzk/HQhp6/NbfeYMsYB8z9NPouQchXKSz277m21ufe68gzMUt9PDUCp6ZnjdlaoVgEWIrHIzO7IBhyCWCqzBgecsR1Mm31+kH0XV4Zhb+JUa00rTI1voN5np2BtJDbYe3r/xdfEvG8tz7i5Iue5IaKhqrtMIY1t9WnmeTRwQKqeVRN5hCAZPm5aUs83UN9Ws00wykIDdpubXceptpoBYWXGxeWs8y0MjMRrEE36839ROoAiAIUiaevSpgiqImPQ6hhn5ayhx3WR2HgkFYnce67dtWzXO+3Yymgo6aarm6VJykcbOwyB2JCkD6kaBcZtqVZRwD6pyU9fgombDXdVm2ns/mi02GgvvK1+pI6zdtFDUdKVUUpE1QJpeklJKNsRwoVJCoafChnkTpYnENl1DMMjLD4drTmNz3M6ATvfg6dV0XaBpMzOjWidome8u1IClHNu2y3uxUNdZq5btBXIslFJBE0mMgsJGUYKBekk9RXBBUkE65xfIIB+x9Flw+Ae2p/MGWNZt8Pj2B6xZaG68svS0NNBduPNn2MmVq4yJNca2YOxKiN3MdPGSpBPUsuD7oDAAm6iaLW/zHEnaIAn1Mn5AE6yrcQ1lSrNNpJkR0gdhDvQ5hGpkqLG+avbty33s3i2Obe1Xc91Q10FZuirJr79tyg9mmVzFKYCtpSZxJGJgEVfKeNV8wgJuw1V4a6o1sU2gSAYBM2DjOZ3UgGTPSSvQVuGNFEPrFpc10taG8pJvIFw4tERmGUzJJkZvPHxc/Y3eE/di2nkXwwb6vfg25icQ2eK7bQrjHT3CnkgWmippLdFLH5jMWh65YmR5Ecl+vqBHosD7emq33fiNMYimTMO1mZkEgiBsDYdQvDO9g6orHF8PecLWY2MzAQIEyXaCTpOsjchQ5sXi63D4X+LaTwb/AGtPhKsVD4XtzUFHaByVsWwF9vbjoREIad6+njVGhrQabzfOj6KpWj6hAekMey7gdfEVBxLg1cvc0k5CQHt6joWibjQ6ZjK8/W4uMK1/DvaCiA6MviAucwnq43cCdI0Bgw3Vdq8IPjWp/D1y3S/Z/wB051tXiS4Vulle/eHXkunuC1pu1CgaSLbV5lVSz1cDwmKMhRJGURXUCSJV5PHOGMxVA8RwzfDqNMVWG2U7uAP4T37wdV1PZfiDsPi6fD8aM1OoJpumS5otAdMFwHTzNgG+vrFujxAbP465QsN95Krbtsyz3iFbb5dxmejtVLcaSB6jy4mMaCaV0mnJYM0Z8hWByrAeN93q+ETTZnOpgZjGmgmACImJvG6+n0MMK7BRpujoSIJzHq7sJjWAbRdQss9Vsrjvna8W7YlHsravIN637T8iWKgpkRDSJe9rVcRo6kE9Uze12+SToVcx+cQip0t1d7HYmpWwzPEJMNcwkCRIe1xy22a65JvludI53C+FNp4lzQCWkguvBIaHNE3gNJBj/u3mV6EUu5ts2e9zbIuNPb9pJS0sFZC1loKmjlkDQhAz1ULYhaWQhSGyXB9erufP1K9SrNSpzHSTB9BpeNbWAXXfwseEDTM5pkEiPNJMW020vbRfI/8Ab8eDG38Lbi4M8Rm29xVV7t27oKmw32CSsimWmvMCe1PLTBI0KwymapZlbq6ZAScGQg/Yf9NuNU6wqYRgjLzDUkt8t53FvsL4F/rLwp5qMx5kXylobAEy5sETre1haQIKm39kt4kOU7n4AOL9l7S2ttHd1q2xuC/cc3KKp3YlurzT17rc4mgiZB5xiiWUR04fqlLHo6WAzxfbnCsbj3OqODW1A1wBaTOSx06m3QTdet/0kr0XcMpmmHOrUnRaLAuMG5ME5gZy/h3C9kuF9uVNLTeKPluzwbPpONN73C2X/bt8daYTXeBKQR1NHcT5UDxRQ1EbxRQTSPPGpAPQeoDwvFKmTDUaNYkFhdLekkEHUglwuYAH6/ScI8VceGsAeQAJBM6G9hMgWJuDf0XxH/a6bclsnjw5pqGg29TrdorZe1W1xutK6z0UeGTrd+o4jAZlYqzhyuB2H27/AE9rh3CqYaSYLhcAaG+m1zG8ar82/wCtlFzOOPc4Rnaw3JJ0i56223UTvDVvWxcd703JvPcZ82kptsXCmjiVlzMaryqOVEVuzSiCqqXQf8cafLI7/GqRfSFMCZe35A5vhMATsCV472Gx7cHjnYqo6A1j49SMvx1mN4C9YeKtx3zxeeJifmbmfizcVssN8ENg4Vor3Zki2jtLbcU7+Y8fnI0NXUw0kAipqYq6T1E7yydaQquvI18OeGYJ1IPmoTmrPDjnLiJAG7cxPmMZKYMDM5fWuDPfxzijaop/yGAswzHt/lwLFzzIaSAJc3V78rZDWyPRHaXh33JtnkzamxuSdtV6ccw2iqqNvXqSqS8bki2nGzPAtopKiniKSUM0alg0CCSGoowIWzJLryNTiLDTe6m4F5jM0WGf/m4OdGYWEvmQ6SIyr6pgeHOpnwKjZFLNke8yA3SGyAOU6wxwLS3zG69J+KNhcS8c1Vj4msVma+1MqVcMcd/sM0TXQGoinqaCKcqpmm9nw6zROxaMqJARkjy+PxlSpOJAhojQggROvQB1oNunf1eFY4Usr6kkzzSWuuIDok3Nz3iRFgoTcu/a07H8LPHXN22dk0sG8vFTV8objgsOxJIprjDavapI3oqmpkyYmjjSeJVip8NLLH5QOFLjv4D2UxPEa2HZSJFNzBmfEbmQJu5xgwSIAOY2gL5/7Qe1+B4TRr++AOrU3BrWA8zzlETl5msuMxJ6tZzSpF/ZUeDuu4Ou24fF54o6TcnNPjb33TPdbnc54Fq5doUlRgPRRo7L/tDBQsk0IZPLRYIcRoxfd7Te0dEUxwfhYAwzYBII5zr35Qb7FzjmdtHm+A+x+KrPdxvjLi3EumGlrgGACwbAIBi2W2UWEmZ97Nr7hoL3LPXUsdTa4lYE008RilLBVwzRMAVUdYAHfJ7+76HwpMGHa37/ABtb5L1eKwrm02g3kC/Y3j13MgRpdb/7T6Au2R9NEO6LliggzVyQxPK8pVVGWJIAA/PULgE7cKSQAFjLmlFUyW6orJnVaeV5FzKVQkxspDYOCMEnB+IGp4gaCSraNN4BFPePzV6VbfVyx3f2CFashjHK0YEnQwHfP1x+Z7aOchNVpvaPCzW6TZZP2hdEEhU+CmFTTUtYZTP5jFonhBD48sOvSxX5HHx/d8dAkXTtDmjl2v8AK4nqg2asT7so4QoSSGJYZEIAKMgC4P7tQ1STPVPXwsPPQ3+ayJqgc9xoZlWKC55yXBHedu01pFY9HXS3KjlpZE7lZIplmJwO/SEikLf8nV88aBJJBG37b/P5ro8Mp5apdtBn0NvmTEd1j4KykvkPmVVE9ku09M8E6kExibp7Dr+OQW6WBzgDB+GlDrET0Wo4V1My05g0yOsb+nfbYpxcts3HcNJt43yrohcqHrlimh6i8M7R9HmrIcN8wVXpyDnqyBiw2BAPb7+/gq6danTe51NuvWNJmI0+cotLPTW+mFsV7rDeWYCWCmygdjj9oGwQEx36wc/P3tKXAmI+/p8k5pOqHxCBl6m/w9e2nwW8rMsaqiDpQdgAfQaYuXM8Im6o1JxjP8dAulEUEg1P1GpmTigrGpxkgrjQlMKKGarPbqzqZuib3dJapz8e+hnsiKCQaoZ9Sf10AUwoJBqR8Pz1A5P4KQanvqZkfBSTUn56kphRQzUevfQzJ/BSDUj4tjQDk4oIRqB8xoymFApBqOxJI1A7omFBCNQDjv31JOysFBIapHzJ1JunFBCNT39RnQzJhRSGqs9sgaJcnFBDNST8SdDMnFFBerVO7uqD6nGh4gCsFCdEwe60a+tXTgf5xqEq1mGPRNnvFJ36ZGlP/wCXGzfyGjdEYc7oRufUMpT1jD6x4/njRMjVOKKbvcKk56KJz/nlVf5Z1LlHwghmrrSuTHSRH6yM38gNEnoVPCEaJu0tcxyaqmRfj0wk/wAS2jIGqbwx0QHM5/FXT4/5VQf01AUwZ0CbmNMgtUVsx+TTNj9wwNTNspkOqbvFRsQXgic/N/e/nnVjXRonDCRdUpgiJMMNPESO5RAuR+g0DUdFylFASkvVH/j7fHTSj4aatUYxg/w1A66bwt1281ykd5jn89edLtl5oYYzorCuXI/bAn/NoyicMeiX7aCP7xj+uokOGPRX9rP/ABvqZgh7v1CX7X/zuf11AUpwyuKv5s/79PKU4dEFYMdnY/roylOG7JYqxj8Tfq2oSp4CUKtfQsf/AIjokJDh+yX7Whz7zH9ToFyX3ZWauhUFpZPLjHdmZuyj4k6IKIwzjoLrlltu0CSRVcdivLV01TJWsi0kis9Q4KrJMzADCowRQThV+OQACS/QjT0gf5Oq7NXAgiC8QABqNBsI6m56n1ksrsb5u6seyNT09FY7dUUdZXxPK7y1MqOtRHTxsmB0hkikJznCpH/jYq1J+UF03uBa3c/Xfe+10OGpUodqXAwdI/DMEa6j5mNF0ex1UiUccNTcKa5SP1TRPFGUBjJyAASc4zjP8B6aDXAaLBi6MvJDYA19Vx3lXf8Atu6yWfi2G4U9Sb1WGC7VCTskNtt1M0U9b5s6gosjRmOJYiyljP3IA76sI/K7xSLNvfcmzYnWTvcW6q5vBsSaZq05Dh5epJsLXMakmNrdRsm1qK03O3UVfdduWGnvKUSnDIrFQzFy3Vj3mUeWGOD7yn5g6z1XwCAfsBbMU2rSflY85S4m3y+t/gmfG9fTS8f7QWktUVOaq3rV11uMarJFJIWkYnp6ek9XWSMY7nAHoZWJBLZmP2Ux2ELa9R1xDjBv1037LVrRT8h0BmkqK6grdqVKLL7XcaUIbCqjBPSG/bABgwlAjI6D1YA6tWCmwCSfWIM+nSd5n0Oi14yrSL4Df5gMQD5pvex+V59Suk01Lt3a1RFe3oY5LnLTikmqPID1NVCC7xRDpH4QQxVAOletsYLEmOxLv9vYXjv/AI1PYbQuW7C1MS4xr8gNJ76nrJK5nuvaW2bztXdtrulhiuVlraWrbFHHJFURJIvVinkRhIwBGUz0jq6Qv4VXVba7mu69iB+Ufn3XfoF4ewteWkQDf4X6HrEkD5pd3sWx7jtOzWzcNi2xvLalfSDbtbRXOm+8Ka6W3sYI54qkssj/ALQDLZYl8DOca0UsfUpPFSg4tfOotffTYf3XJrcHGLD6FcS2A6/WLmAN4k2Xyi/aY/YzbS2Pc77zV4BU35tu+01U90k42SnmMlMI/feexTDM8ToY/NEM/YqP2UgISI/XPZr/AFGbiSMPxFoBNs9oP/eNPiPiNSvjntN/o3iqFD33hDvJzZQTM2uw/wBWlp10jRb34VPtAb14wuK7lyZ4gfETxhwbv7iKSHcE73Jak0l3kWAwLcqi3w+WxjczVEJihZ2NTOWcY8qN/Pcb9mmcOxHhUmvqCvLRlALhN8oMwXWFyByjqSR7z2G9tf4tw54c1jKmHAL5dAIb+JxPkp7G5IMNFgAcTw79qHUbp+0R4P5c8SnFG59l7Fo9tV2zbJdJdvSwytea9UenmqIYlYiXpatjiwgmWOtJMSZkY9F/stXw/C6zKNTxHkiRmBhoPMAdP6cwFgWxJsF57Fe1OCxfF8PR8M0aRuHOBAe4+QkG+Wxyl3mDpyjb6Or/ALq2Jubbts5xoqWC1bPt9NUTQbkqBJ7JRTRh1hmYA9DxwMXzI6qFlZwW6YiG+aNpVGjKG8zhEADNfpuJ0HUc0XC+w0HQ52HfVBuJE6jUzsJ3ubACASSPLf7Tr7OnaviD8IG9eVeN6mYcvUNsTdVDPHd53g3YsKmZoTT+YYCGElYYWVFw8nw6iNer9lPaNmCxjadXKKZJGgzCbXIvaBMk2Xi/bn2fqcWwlWhSL3VQAQA45JbcDKZFxuIMxchfNX9jdzFszjLxwcT0/Idwttv2dfKyCkSqrXVaemuMciVFE7F+0YeaGOIvlTiQL1YYg/WvbXCVTgKj6I52T8jIPrE5o6j4j8//AOlfF8nERgqziGVoFj+KZba9zdt9A4r7AeTPE7tLjrnnb3DNniblzeXJW3L3WXKOgt6TUdFWUJppYbtNTd4xB5dTLDKw6mlMEAdwUB18PwOE95wtSq05RSLeYm8OkEAwJMjlFok9V+pcXTbhcXQZ5M+YNYJJOUSQSDI1AmIE6L42vtXrttit8ZO6rdtinucFNa7JaqCs9ttfsE0s/lNK0jR9TF1YTqVkP40MZxr7D/p8x7cBNS0vdAkGAIG2hkXHWZX5w/12x1OpxhgZctptDtdZcRqBNiNLRoSo1eEbh2484c2WXb1Jtpt32i2wNfa+2sshjukEEkSimlaN0aOOeWWGFnDAqJTjJIB9TxbiHu1A1ZDTYAmNToYOsXMdukr557G8CPE+JMwrWy27jciWtEm4Bj1iBqSF9fNn4qtvHtjq9ueIGybe2Jxfdlmq6KjsqzVvHO3KQRdRkpa0oZ7dXxRgIp8mKCDzFliaJ165fhL8a2q41sM81KgF3wBUd1BYPM02kyS4cpkco/Z9HCNohuFxFHwqbdKZeS1twAcxgCDmcJyjMBlBu5avx3yxw5eand9k3hZbBvm+bQuKyW/fN1o66KmulIlL0pcJaRabHkNR1BjmSZo4JnErxd5gsYdhcRTANNpYKgkMABIM6EF1pcBlIBcBAMRJ6mIea38p7gXUyJJJbILZBzAdzmg5XdSIXM/EV9ofxnwhRCy7ssdk5SraqneHbPFm3vPa3X+4sTHHV1MXlJJHbuuR4YHheT2h4HkWNmMXl7uEezuKxtb/AKUHOYBe4DlFrRJBeQJykAsBFxJK837T+1mB4Xhs2PcG3OVtN0vcb6OLZa0OsXEQSS2+XK7N/Zy/ZxXvbnJ7eNPxvwU0fiDutOm5tr2OOv8AYU2AgZUieoVkdDWeVJTJBCWPkoTkySiUx9n2o9qsPh8OeE8NII0c65zEzIaQbgmczhY6DlifC+yfsXjOKYv/ANQ8XZ/Me4ZGZZAAEAuFoLQIuCbZncxEerG+7ZVbDdOU+MuXa2zR2tZfOopEjuFtrbTgxNiCPoD9EnU8bkgdUjYx2182ZWY4+HUaZda0yDNozTrYaE/VfcqWFfWDadVvKL3tfzXIvpqB8VL/AI+uN/8AuSyVt9SM7kryK63oytCkCssKdMqYzEcf3mFILuVXBwAXsYyoWAyBqdd/sDruvO42m14cW+UWPUiCRrvvE23ld7o7tTT0oq1qo54Sx98Ht64wPy9NAPkSvOVMG5rssQVpdbvm20lY8NWxqFqKmS1wxCMlampUEtEp9CehGYkkKAGyex1WysToNf039Pu5XSZwhxaMtiAHegOn1sBrMLK2mOaGSChutXDcauINUBVz00zFz0jucswBx1H4KcAA41YxwmBt9/e6z12Zmmo0ZQbetvoO3feFtftQx650wMLCKKSapfn21JKIoKxqgO2RnTZkTQQfOAkaUN0lvxD/AIj8/wA9KSiKVoSjVAfHvozdHwCtA3HNdvvSybhoZFekoZ5qeSmZ8JMsqBDK2FJ9xgpGO+A3r1ajHxPf95/T8l0MNg6bmmk4cxgzHS8Ceo+7LYZKK010TyU48suOlZoXKsvfPYj0HocemlAHRVtfVaRm22Ky4qQqhQ3Ydu5zqGN1QKCY1sNNcEjSpVm6G6kZXKsh+hBz+nofiNGeqsp0y0y3dEp2FNBHAJp5Qv8Ajkfqdvjkn4nUtsi+kXGYRfa+w97I0UPdkg1XfsdLmTDDoftXUDhtSU/u/VJNYR6N20JR92QzWAZ75/XQJEJxh0NqzB9RnUB6Jhhkn2wkZBJGl0Kf3fZDNaPiyqNQvCcYZNmu1MvZ6qnU/LzBnUlOMI7ohNeaM+lTGx/5ct/LUMphg3dEBrzFnCpVSH4dMLH+mjBmyf3TqkfersPdpavuP8Shf5nUAhM3ChIa5VB7rSH/AL0qj+WdCCU4wo+whe31zHLRUcY/94zH+Q0wgJxhkM1VcxfNRSxjPbEZOP3toeqsbhh0Q/NqSPfrnJ/5Y1X+h0XFM3D9kJ2LDDVla2fgJOkfwA1BG6YYdBApgckSyf55Xb+Z0YEQE4oQUPFGDn2am/VAf56AcU3gndE9qjjGEVEH0GNQuJ1QGHHRCauJPd8/rqT0T+AgmtLfhJYakJhSEoEleqAl26QPn21M19Uww5Kx73yjOR7bSlvkJFJ/cNM0HUJvdzMQmz3umGelppz8kiZv5DUyklDwOqH97FwStLWf99Qv8zokEaotoCU2e41eT5dLGPq8wH8gdQjumNEaITVtay/ipI3+PZmA/lowA6yLaI3CCampyS9YD29FjAH7znRm0IeF0CC03UCWqak/k/T/ACA1Oybw+ibM9Pggr1jPfqct/M6YOuiGG8LtpuPb1OuC4LjDBpP3gCPUHQATe5lV7dH8VH07aJQ9zKWtbH2OBoQlOEKr22M+mP36MWhA4QpQrVGAC36MdGBCnuqIKxf/AGkn/wAWhKrOG7K/t2B2kkx+emlD3XeEoV5+Er/w0EDhB0VGvbA/asR9QNMO6AwY2CDUVuYzJI/mIgL9PT2Yj+f+uoAZsnZhLwBErA1W5KutK0tpgr3qDIUNQUKR065UM5LdmYBiQmDkr8B30W0ydbfeg/fRXt4c1gzPg9uvy09eidU9BRUdrktdH/ssTuZZHABeWQt1M7nGGZmyT6euBgYAd7gTf7+/8pMjvE8Q3P3YdOy0W7UzrUXCtu9/pYKVQS3kSMkjOF7dMC5BLZIxk5wvY+mg2i0nqT9/dl1cO4gNZTZ89Pmenw3Wp2rbcc+6RQ1lugraemthhq/bXSR6hzJDL/dheiMCRQBEpVB0kkHJzqmBIMXtHx339fSE9ap/LzzdxtFhEEdZNtSQSZ7Lqj1y23biLXeXDXPEkb9cglkMhURjv2y/cZI+OT6az1GA8o36LnU8MX1gWzAPpaZ+/ktWt9gsNLtGmW71NfVPTJJDUVktX+0g/aEP+0j6MBe4X4KM4+szNAhot8/ufqtbqlZ+IJZuZAj5W+yd05oYd1muMtXVUu4NoxyQ+y2+sRYpyqqQ8plxh1Oe0cgOR3LKcDVws3o6/wDj177aLHiqFKIpiHEXIk/L9SN+q5htfdkF22FdUpLbuex7vpUC3O23JY1rYZEwUR+mRyqtEI+h0JQKwYA47DHUgx2W0a2Nj3HaZnfULr4TD56rXEy3QbEa6gWDpkxutbr+Ttw3yY1dpt24aq34jgp7nb1hneoiELM0kkSv0xxpMAnmMQjFfdYHPSr8I4DO4gDoTEbCZETvAk9lqw+Ap0m+G4X+MT0B1mNRFpXDOP7xyBu3aW5bbyLdXskdr3BWQ1VxtVwWlD1TCGVZqeSSPEUZkRJFhZSVVnjZn6jq84ai3KWy61gZ76xeY1NhNxotlSm4P5Whr3Bo6iB0uLGYvJ6wq5n8QW1vDJx1uDdvIu19w0W1UanpYKuks8lXFVOyB5Kgy08krO8S9UjAEv0JIwVwrY0YbhmIxdVtLDw9xmwItG0QI01gDS4XKxeMwuGYcTiKmQMu4mdHOgfAk7X6DQL5Y/GBtit3RyFxb9or4TeI9n7Fv8v3rv297PpYUrXpYbNWUcrXu6WtoxT0wlW4UEj0i+Z1oUqCVZmx9r4Ji3tou4bjqvM2GhwkQXgtDWv1cRDgHAACC26/MHt77PMdXHG+BUyWOkua7VwbDnOcwGQNCWuOYy10CFybw/csbs8f/ij8MPAvKlPTQceS73rN2Xe22WBvOus0aVFdNE6x9LSO5E8UUhJlSKdwzuUU6vq8Lp8Jw1bGU5c5lMNaDsOVo7ASAXDSRYCVnpe1+I9qOIUOG1A2kx9Q1HEO3ALoJ1gSQwnreYBH2Y1+4Noy7IpaPZVyt+06C7U8tLTXG2TLFSU8fX01EciuPKUxqZyyPGGVozkD3mPwEh7nkVJOhOs/vew6X9F+uqPDhnz5ZyyMsTc6R1v36rkK7Nu0e7/7NcZ3il4Z5NqoRcBZqm0wCy3+lRe1a9KySwO6LFmUUrQspkVGLghx03ViQTXGYaZgeYdRIuZJtnB3iAFifg6FGmfCcRcSASROmUAkQI/pIO5IJAPxAePHw98ieGDxR782xvlNlU12uFU+7rTXbRWSntMlLVTPNG1vjYK8AifqTyz3iZAASOlj+hPZnidHF4NjqLi4N5Tm80gCc33foNF+G/8AUr2cxPDOKvFZgp5yXsDZiCTpN7EXuYO5XodsH7VG6pf+AfEXU7Q2pcuUthbXXbO70uV+prXHvapnqqyWqrGVllqa2SopYaUM/SVgqMdmLxDXk63smWsrYdrsrKhlkNc4tAaAIAhrYc4mSZcBaLkfSuF/6lNrU6WNrSatIEPOZjBzEaFxJILGGzGwHHm2B8Y+WOUd381cocg8vb9rprxvvdF4q75dJzheueaQuQoHYKMhFA7BVHy17rh/D6WDoMw1EQ1gAv23Pcm57r4d7RcbqcRxtTGvEOeZAGjWiwaOzWgAeklejf2aPh0oubX3Tehsaq3tNb75QS1QFa1KKOhhxI0EDxTiX2iqeYRkeU48mnn6OpmYLwfanHuotbli4OoDpJsLEEQ0AuNxJLQba/Wf9GPZ2ljPFr1Q6xaJDi0Na27jLXNJLpazSAC4gzC+iDeXhy25feN6+88L2CzeHa+2mxTnb1x23cQKXc8roYEtlXSe0NSV1O8RMbhYOstU4UqygD5IeJVXPa3GAVSSJBbDgdcwcG5mkWi4FidDK/UR9lqbWn3Fz6ZDbS4uZAnzNcYIO8kwIIOYQvN2yfaGL4W/Chujj3nmy7uvvi7iq622UlFV1irXR1cMSwQz11Ug64qCnYOUjjZ2qJaciUhuoD0GL9mHcQxoZgSPdyAc1yBOsA6vI00DAQRsV86p+39Pg3C/H4xPvg5chjM6LjSwZYAvdJMOaBJyrlHgb8KV62VyhwB4hOZ7lvW7cu1ss+7aSjiroo6o0CQxRU8lJJ0SvJWiWsikIC9KYjhTMjlk7ntFx2k2jWwODaMjRkJv5naiGwQ2AQSTLjP4RfgewX+neJxFehxvjTi7EVCXBrgIaxu5GhPNIaCAwXIzFe/1/wB1703tT8IXKxWe38xXa00tEbzXPUlJbZTxoxn+6an2dFkrGeNOikmbzkwWHQzKuvmVOnTaXy7w23iZudgbyBe5bbQdSPvVImjTzUm5g8zAgQ02Lujo7gTfYQezWjesm/6DavHu7Kg2G8tNJdrNa6ikhoa680SFXoHWPqfojSoemaSMhECRftP7whs4oGnUzM5iB1kB2hJIGoExrc8ugV9SmAHVKPKDrrIaPNa0zpNzfbbI7B8Qu06nd+4bDuRt0WrkSS6x2iC1qHcRh4ozM0UYXzFpTMJV82RQesYHSAo1VVwDiM1JuYEEz22nYWiADebztY/COfTD55REyBM7ettdhB9TKqg5Tg2nx/uW8VdPW1dutNSacu9UjtWVLTxoIoyC3SqNIIiWwQyN2PbNdGg52RrYlxgfPU/nbZef4hw0PxEnUibDQQfSSdel1heR5toWCggr99XSlu24zdIVpaKCVEjo6qWpQRiixiVIhIQHcHqcM7SDpARbaQ8QinQbM/UXJnYCJIG3c3U4fQqGavlbGpmbD8R0JPcRsLTPQdu71ghutXbrY123JMWTqlMHSIV8sgJ1tjI6o/XLMe+e4Oq2sJm0ev399YVeI4bnphzyG/Gd9fl6BdZp7x54diksSg9IDrhjj44+A+WdSJuuI7AwYR/vFT6M37tAaoDCFV94YP8A6w/poxuiMGkm5YGSHB/LQlH3NBa7Rr+J+n8yBqSnGBJWOku1F0ezCoZet+zJKoMZJz1Zz2AOlDQVd7k8HNGnb4LDbZ3pb73Zrdc6asq6qCeMvG8tOUZgGK91BODlSfXV9Sg5pLSOn1EoHAkyQ2Oyzxv1OBkGdu3wib/TVQJ2CP8AD3fZSPvxTkrT1bf9zH8zowUx4eeyT98ys5UUVSoxnqZkA/L1z/DTZSRKAwQmJVfelSR2plB+HVMP6A6UhOcE3r9EFrjXMcqtGg+rsf6agZ1T+5tCsa+rwczUqH6IT/XRI6IjCCdENqyqOB7bgf8ALEO/7ydKKcapxhB0QjUy/wCKtqXz/lH8hqZNwnGE7JDTKezVFWRnP96R/LGly7KwYbsgsaRjlkZz/wA0jH+Z00wj7sdFfzKT/wBhTn81Ggm93KUKyJPwrGv5KNG6gwnVWNx6e3X7ulI3Te6BINxXuSw1Mqf3SyGbgM9jkaIaiMMhvcAO7Ej66AAGqcYbomM18pKdWeespYUUZJeRRgfqdECdE/ux6JuNxULhvLq4pMdj0Et/LOmLD0TDDXQ5L9GM9CVs3+WFv5kY0PDJCgw1kA3uVi3TRVij4dZRc/8A6x0Sy0mERQuhPdq05CU0K9v8c/8AHAU6kTaUfACCLnXkHzJKCNvgFDt/MjULB1RbR6hN5KyrfPVchEP+SBf/AKs6gYAev36JvA2ASDUsAA9fWN+TKuf3AajgDeFBSMQmztRv3mM85x/jmcj92caZtjICBoE22QzPRD/1FKfllAf56YJvAJEJQrlT+7CoP+Vcfy0S611Bh0CW7RqCZJkUf8zAfz0hAhOMK5YxtyW9W6PvCkLfIOCf4aZrC7QKHDEaoL7hpv8AAaqY/JIHP9NEsJ2TNw6bff0jnK0Nfj5v0L/Ns6ZtL0SmheE3e83AswSjgVcDDSVI7n5YVT9NEsMTP5phh2oX3lcCCZJrdGPh0B2/mRolo7oih1CavV1bNhrpIo+IjhRf55OixoBmPr+0JzQsu2feWQcsB+uvPlhSe5KhcvT3tQtkKe5Ja3Ij/ED+ugWIe5pf3j/zD56bJZIcGVcXLJwG76bIh7kri4gDOdEMQOCSvvMkfi76GVQYJL+8j8G7aIYl9yV/vMdgWOpk3Q9ySvvMD499HJ1Se4lULn8m/jpQFPclb7yzjLk/rqwsATe5dlRuXf8AEf36OSEPcugWpX2vkSSeW4VEUtud4lhiRljdWGcszkEkZwcAHuB+Wo1p0F5WuhgwRDRBEydfpYfFY7aUs1Ndat7hH0XCShhYYUKsSGWVvLGfez7yser5jsMEavcLZRpP1/JDFYVroLRb+wutouVVSxPBdvZ6GS4QgpHLL6qhPvAEehIBA/d6E6TKYICqp4VxBpyYK5rPcLHW2y8TddFYq6W5xv5NSYyJPfRFkVC4XDpGSDnpOMkeumbSMgO+n+P8Le2k9jgAJEd+9p11/sm9NyrsBqS7Xam5Mgmgp/MEMUVzhSOpKnpzHGvdiXDIApOSOw76Z+HcAA5hE6Eh39gqX8LqF7G5R0Ngb9z2/sVC7xY8o1HENqsF947uu5tx87VhprLtvb9ZUQlN0QyzrJLTSrKimlgQdcy3CchaZkBHUGMEnX4XhRinmg5oawXc6/JG5gnUwMoEu0EGHDn46jUw1L3unzEnlZAGZ0RlBtqASTOVuruUEKCO64/tCbI90ptl8i8VWBIoKi42jiqs21V3SxvRZaZoae/s0ktTN1eafNZY4kZshApK66ww3CXx4niFxsagLRfT/b/CNLElx7FYMQ32gl1eh4IsD4bg7MdyHVRlBcRbkbkFpkQVjbB4895QWvaO2uLL5uPcPK1zrI7bV7YucEVvuttv8MUUNRHehIQkfXNIQlSsjo6qFVW6g4rqeyjnVXB/Kxt80ktymYLSNbXIgEbwLLfhvavCYjDNqtph1V0tLIAcHCMzXNJloGx8ptGaQugXPlXmfim51sm/9ibWm8UN0tnsFfVUUXt8PG+2JGdqutpYpU8iqqaqV5YY43cLVTLFCitDBMDZQwVIhzKDyaAILnaGo4eRgdMtEDMZHKJe6DlAy48vrig6tTHjOBy0wQRTFs9R+k5BAgG5ysYZLnKJ21OO/D7sPnXalLxDT3TdFVX7IWypYbnWrckK1dejrTmmrJlgpTGaZhJGMRujBY4nIAXqVuIYrE4d4rQw+JOYCCC1pMyGknUQfNqS6JKx4L2ewWB4hT8Aue3wnNyFxLcrntB5SWhu+YCGxADbALxdo7Pub7Nj7RvZ43/FFRttG/0d2qFtFeswFqraZiBHP5Z6gIKoq3uZ9xh0+mvo9Z7eJcLf4JDs7SLggFwPSZ1HVfk3EYZns37XMFYllJrw6RctY+eoiwJGkWt1X0b8p+PLwrVV22vcqXxVcfb/AOPqVKiC47es9K010uXmIG6l9ngWOujheAYp+mKR4ZXy7BFTXyrDezePeHVDhajah8pLXZR/5aEzqSQCBEL9cO9sOEUYLcbSc0+bnaXHawBJJiZDRJvqVg7J47/DbzVRG5XjnDbddYrZba3pq9w32Gir5JIekxyRySPTzUc4jlkKE9ZkMaLiTrYDHV9nsVhjkdTIcSLZXEb62dIJ6C0zIAXocB7W8JxdA18HimOptmYcGm0aAx8S7KNeyhP4xvCvyH4ouFdw8w3nclVed6WeCovdooqY0NRT2lZSJFttVVUjEVE9TTiHFUw/3lRB7qIXk9X7P8Zw+CxQoMcCHQ1xk3PVodcNaZEalvMdgPln+oHsTiuPcKNUyKlOXUmwJywLOLRBc8AG1muho3LvmTKvIzSsQuFwB6fpjX1u+hK/DFSmc19R9E6mUhPNBAlbAHwKL+Xz+mjlmwTGzZH33X0EfYb8pcpbBn5d2rtajv8AV7I3PW0tuq6qhiUPYa9FiX2vrYgN109XJF5eck4KjIzr5x/qHg2VRSc6MzJMExIvIAnqB8JX6i//AI5UnFuIa4SwloIyyARcOJiwgk66gWXpv9oJ9pBtDw40lksG7thT33f8bTVO2NoNOlMsVOIx5FfcJ6eoaWkeGZpBFH0A4jjdCSpMfh+AezeIxtQii8To53miTdoEcznDW+5Bib/avbv234d7O4cHEAuLrsaLF5bG5HKwRdxkk6A3jxA408KXjc8TW96vxkckbIulqorjLHcbVebnaArVJjVRFNarb1IHFLFCrwiVfKfy1IExBz9SxdfBcMoDh9J/P0DuaTrmdfKXEwSOYA2y2j87+z3s9xr2k4k7j+NpNbTEFuYHKADAyMkZgzzcxhxEuzSQZNbE8L97t25LtQc0x8k3Tfq3KmtL3Wl3/UWR2r6qsCLHVrGR5ccTU9LU4poVTy1jd2DGPXm6/FKDGAYZtMMgmCzNYNJJ6uMEjmcLmACJX2DAexmMdUc/iFWs+oRAe2pkF3ABsCGsBLQeVrrCTEKbVq8LmxKDbPF+7rJtvmqG0zxT0t/qKDlC+UsTTVExiW4SPLLEbclR3mld0kWWSVTmMgBuJisZneWOpUs1taTdInKQGkuy2aA0yLz1XqcDwDwx4jcRXIJMFtZ13XaXSXxmJGYlwaLAA9emHYt+8Kk1PScdco7k48o7HtKjqoto8htV7ip4K2orJZ5KK21qeVckfzVDZhqHj6o361dT5Yrr4mljXOD6YzOdGakAJDRAJYS5kCTqGkA2O6bhns5iMBSaMPiC+m0F3885ozETNQAPvERzawGhN+MpPGVYN57k5T3Kvhy3jftwV9orbpUUe+q+ywWOKIsU89HopepJWUzsIJW/aMcsfXTYnA4BtNtBlZwDc3mpl2YkaDK4TAsJAtotmFqcZFZz6+DY8OgDJUADWiZMPaTfWAXGbHtNu58rc9U9048tO9uJdsWbhT7xn3Jfa3bt+e91EccRaaFnp0p6epEHmPHLLKkcjYpVIyWdl5VHhVLmyVczw2A0tLdbG5JExMCd+gg9DF1agq5nUSxu7w5pFogQJJki5iGgmdRHZZ920dl3Ja46Lc1ppLHZrE96t8dDEJbOkEiv7HK9cF6RHFCJ38yRslj+zQgK2ueMOXNc9wOobMaG2YR8hlAm9yJXYbTY5rWCIdJN+Yj+5vaBAEkrt3HPKdg3XuG70m3uQLbue20rLUVlypkh8lpWUp5ET+qopBC56mK/H1Jy1KLmeYFo0ANie8QNe37LNicBNIS0ZjsCTA77T10XY73vCisFsS7V9ZXvTe0x0zLHlnLO4QBUAyx94HA74yfhqtjC4hrRJK57OH5nFsAWnsnFHuGK5zslElympFOGmkaSNVPSDjBwSe/y7fHSCnuQi/BZReJ+BWY66U4DIz/m7H+uiGz0VfgOVCSjGT7PCR9VBzonqh7s6NdUoVMCggQwD/ujS7ojCFYq+34Wqz3Cujid5I4/cVFyxYkKMAepyw7adrCeUIswfMAVxvgzkq1XjZW3rfPV3eCvYMKYXOMxS1aH3wY2PaTHVjt3wB210eJYVzahsO8QY9dfqlbh83NsfvoOnyXeDcc9ve+uTrlqz3NDNwUkj3dGEwwaH7cmPQZ9flokJvdCkmvODlnXt89DSyPuaCboBkmdf1xoZU/uaDJeokBzUwA/no5URg0IX2Nvwv1/5Qx/pqGm6JIRGEEwhG9r2xDWP/lQ99BzTsn90Td79Jk9FDXMfqFX+baYMMwVBhrKxvkrAYgVT8mlAx/A6UsgwSmbhbIbXWubsgt6fV5Gb+QGg1oG6nuvRWNwrSB/tFMh+OIif/q0cgkkIjDjogNV1TH3rjIn+SJB/E50DT6pvAjZDFQygh66um+pkA/+UDTuaDt+ajMPugvNTuB5j1Eo+TTuR/PQDJOibwTogobfGxeKkplf/i6cn+OnAMZdkPAvKJ7XChykUKj6IBpZPVN7vKFJdgv45gg/5mxotYNEwwxCYybhoo8+ZW0qn5GQZ/nqClZEYUhN/wC0dG393O0v+SNmz+4af3d3RA4cHVCa/wDr0U1xl+WISM/q2NDwSicOEH76qXyBQVAIP+KRF/qdOKEHVEUQgvdLgfwQ0idvV5if5LoCkOqLaIQWr7gSOuooo/8ALGzfzI1Axqgp7QgPVVbZ6rnKoP8AwRIP550fDHT6phT7IJmB/HXXBx8cy9P/AMoGmygnRQUt01kFE5Jmjac//mSM38CcaIEXChYUMTUMQISmplH0Qf6aaHHVHwdlZrmqD3GCfQaJpybqCimsl2ycF/3nU8GUfDTZrr8OrvphTsEfCTdrqe/v99E0VDT6Js929R1H9TphTsh4XVNZLqMfj0W04Oinhrpo3fRsO1/tp+HcKP8A6tcmpgzrB+/gu4cENgiLuiAkf+nbYfrlP/2tIME7oVHYQDUJ3HfhIB5d1pJM/wDCqn/6tKcNqEPcuyObnVt5ZS4qAGyf9nB6hj09e3w76ngbJDgh0RBc6j/+N/Tyh/rphh0PdB0SxcpSP9//AP8Amui7DJDhB0V/vGXP/wCIf/qLoNoQNEPdB0SvvGY9hcmA/wAi6goSUDhBrCuK+Y+lykH/AHE/00ww/ZA4QdEta6Ygf+kpiP8AKn+ml8ATolOFAMEKvbJvjcqj9Anb+Go2gOinuw6K4qpcf/iFWfy6f9NN4Qmygww6JPtT+nt9WP8AvD/TR8EawocMOiT5w6xIaqqeUDAYuMqPocas8K1kRhQtdtj3E11yvdymuiF3aGClV1JjhUqA5K+rN0FsZ9CMDOmdQaABunNARlAHy3SKu4Xu4mGKmqLpt2FSWleSRZJKlBnqSNAfdbABEh9Or8JPpYyg0Xdf0/U9O35JRhRsAfgrzUdLBQSf2fnpaWdwJTLKGmeft6tL1dRJGB1kkj4emhlLrO07KNw4mXifl92UW+XJ6+Xatbxwty2va7bWVMSJR3mlq7jLb2aXqLjEigp7jyhirJGOrqyuBrfg6DM2d8/CADbqZ9Os6BMcNALmAEnc2ntAEn5jTood8obz2r4YqtabZm1au+8s39KaHbe0rDVm73/d1vg6UEs1XL1yClRlDzTTyJTQrGqh1aNF12MJgq+OBptIyN5iYy02TuYsD0sXOJsDMjz/ABriGB4VTFWs0vqmWtbGaq8j8LAbkCxOjWC7iJvEDmXkHx5U1HeeS5trcD8BR09TSxy0NPVy11xElVVqkRDzGnhnqi5VS0chi6gxGAXz0MPwnhwilUquqG/4Q1tgSb8xAibloMfBcPH8X9oBRdVp4anRaDbNUNR8EgCzcjM1wA0PIk2USuNNibx2un/bJvjxV8x7Cuu67lBFe7hT01ne31nU0kFaJVn9ojlhj8yKIVCs0ILqrqnuDXWr1sIGe7UsMHBkkc7gRoRoGkEnbzbibryHDfZ/iTXu4jjOIOpvrOAfyU8s3bHMXjlmMwJbtaFidtbZ2NvifkGs394mfEvco9xV1vtkd7pr9FT2uGsMjRxNXiCFG8mkoJqF1jjURLK0iRFkfr1eA2kKYp4VkCSQQ4kCAXZZNy50iTJIALgIhUYTg9WsMRUfxGqQ+Gy11NrTBcGAkCzWtIcQIaC43JdKXzjQx+D7n7atr8EPMG/ecN9VNH94zWLcVrp90P7Srw+Utd7VTwzQmcTVcgZXyCFVRjVnC44hRca1IUWAxLXFgHmmLlrogAi0ySVwfazh2J9n8XTbgMQ7E4iownw3sFZxu3LJbD6YcZLXSYgAWJUJvtF18SvJF9sXPXiG4qvFgvFzZrZ9/wBmkp5dpSUgX/YqK2eSnXC0ax1Qb2mR5JGDYwIyo9B7O4Sjh2OoYeoHhsG8+JP4i4GIGkBoAAudZXyP/WNvEq7qWK4lhnUnXbLcppZTBaGvElzpJLs5mbNAAgewXgH8Tr+K7jnj/a3JN/sFyvO17XHbJaeRI0NrWBYqQ10sbqTVTyx1StHPhlgjNQh/aYc+J9oOH+513Ppk8/WdCZyg7C0O0JMRDbL9G/6Re1FHi3DaQsKtIQ8DXM0RnOnmBkAWu7NJUmJfDr4U92cqbkvlw4T473Rs2pv7o12jstLWT1FZRVDU4tVP58ZEdEjQwRPhiJpKeSJR0iUGmlx3H0sMzLUc0xMSR5hOc9SZJaNAIcZ5V6Ov/p7wXF13uqYanUvE5WmMsDII6AAOPctsSY55yv8AZ/eGm7b/ALzceM9t0PhVo7NDbZjdLLe1tU8ZmNUB0xRk0rs8fQ5iZHBwil8nBvw/tNiqlMe9EVc0iMszAadRzWmJBA1gHVU1v9L+F+JOCa7DVGgGabi0C5glplhFp5gTYaL5jvGP4c7n4T/EHunh57rVX+3wQ01wtdfU0/kzT0k6dSGRAAokQh0YqOnK5AGcD6RwrHjF0BWaMpuCNYI6dtPu6/EH+pXsVU4BxZ2CL/EaQHNdABId1gkSCCDFvTRRmPUjTdJLkYOSAScDvrqOEBeBaSTJupeeF3xf7p8LFq5JuG0YXfdlZDTy7bmnippaO016yxiarqElRmf/AGaMxqEZD1EEkr1K3A43wMY0MY4wPxQSDEGwi0l0XOw6wvqX+nP+pVTgDMRlbmc8AtBALc4OrrgwGzpMmPUenHgK8Nu0987gHi28T183RzJzZdatNw2iguEksVNRT+Yp+9rzXTx+VUuqmOVIIvMEQEbOje7GvJ45i3YKl/DsBT8NoBBdBET+GmBzEnQujUmDq5fXP9NP9P8A+MYge0XH6vjVCQ9lO3NHlLzZjWiAWskNDRJEEBe21Jc+Vtw7P2pW7q3Luy52OSmjpKKqsrR08FiDkpKCDl5WkjlCiaVH6lQGIR+71/OKmCotceW++bUgXAA2EiSAST+Kdv1dSzZi6YN/KLTMXJmSPRrQZI6rkVfPsvY1y8TvMKjYE23KK92qnoZb3e6mKo82Gw+dOBD5MheR18tWORnyQhQKrFtzxUdhqOHbZ7s9mtm2eBoRAB7bzOkecyZMdicTV5qYFO5cA2zJdJcCAMpHw2F5ecLbk8Wd5424/sVVsPa21bfTbchp60XiaZrhO8KeWI0gWF4KeBUqWRqdmmkwS7lOyCcV4ZhaVZ7/ABZM/h03vmmSbWLQAOpklD2exmLq4ZjThw1uURJImQCBlgwP+92Y/wBIGuW463BszZfJl3vfMVC+zNmVm1RdNoVtaamsT2qikkhqJpLhBL1ICt0iEazJEUiKRgEMuZXwbxhnMp8zgeYADRwsMhEzLb6yfQqNxjm41nicjXAxN7tMk5hLSIIA09NF2zdXIXD/ACxX0W1drb7sVwp7va6OxW280bChq6SqaRJSkhwMwosQiKuo6GlZcgudc+jhatNxfUYYaSSDcQBf5npYwNgu4KlJ1MFrxJGxkmfLb4z1vpK7BsrkyzUO7LtueLcK1dmprQ9eVjV0r5qaCJSiMO6pMemMEIqAtIgXuSdZ3YNzmZY5idNpNhfWDaJ6dAtdTD/yYtl066TNu1+ul+i43vPiLfW0aap3lsG+UV12nc5TuHcXHM9zWOz1FQ0css0lDGPKWIwhI1NPKzU87xBmSN3eU9R1ai8htR0PZYPgk+pmbm8EAOaCLkABcHC8LqMqePRaS12tO1wdgbkE/iaTkdLrAlbpxt4rtmb73dfqq0X7ZN7uQ8m2owo1hvQlAURQPSSgGlgBkkPtBLxMenDEsOrFV4XVbTHiZgCZubX3Lrg2iGgTray3Yethn8lGCRqATY6kEaz3JjvcKVG2bhfl3vcqm/PNf7c1O1TS3GNlaOil84xSxQNkFOgge+VBkLsOygIvNbh2hnJb8zvJ7dAD3NzK2YiiHMDY02jtv369Nl2Gx316ie7zKaypgEsUccjhFMgESkt2Pfu2M/HH5aqOHMA73WR2H0CzpvE3fFOcj5yqM/z0Pd7wUhw3RKN1mxlVjzj0L/8AhpThjKb3YQhG6VLdl9nBI7d2P9BpjQR93EKOnNXK+3E2jujb33jYKxG8qlrJKqoNPRwdUyBkknLdzgkEJ+H4kHXSwHDqhcHgHeLTNthv+Xqs7wxs5jYRN4iep27772XCfCzZNjVHh6rqyO3bbrqhKJpJHDrO3nGjDESksQJc5JHYd8gDOu57SVagxYbMbaAWtpb6rjez+CpvwzT5utybyZ3Py2U2tpV88m0trySVtYztbKXqbC5J8lc5OD315jGUAKzwNifzXawuHHhtMbLOisUElqqpf4d5D/TWfwTlsFoNGLpBrIgD77t3z3kY/wBdH3e9k3g3STV05zmONvj3Gf56ng7JfBVCuRPwRxqPkFxomkTui2gNghtdkjyGkRPj3IGoKQTeB2TeTcFMh/aVlMn+aUf66jcPN0TRsmj7noVIzWwN9Acn+GoMKTaCj4CF/aelbJR5n/ywuf6ab3R24QFIdUltxZ7rT1zn/wB3jP7yND3M6kImiOqbG/zN2FvlI/5pIx/U6cYSLylNJqQbzVNnppaaP6tP/wDsroHCjqj4Q0QHu1wJz5lBEPnl2/00fdhCJpiLBCNyrTnqucSA/wDDCD/EnTe6NjTREUx0TdrhUH1u9SP8saL/AE0vu46fVMGCNkL28jHVX1kn5ykfy05w41hAMQWraVv7yNZT8mmdv5nR93jZQtKBHV22nBWG20UYJLnpVO5JyT+edOaLkDTBmUU31Fx0KV/yqP6aX3YxdTwwEN9xL3y8mPqDoe6dERTugNuKIdjKgyfj204wpGihp7oDbijPfzox+uj7qgWBAfcUZ/8AWr+/RGFhHIm7X8fB/wD7aPuvVTIm7X/OSXz8+/ro+7KEBNmv47ftAdEYZAhNzfx2Jkxphh4mEC1Nn3APUyd/z0Thp2ULU1e/DsTJn9dDwCoWiE0a+gZw2R+enGGtZQthAa+jI97A04w5AlKRsm7X4A5Mgxpvdt1MqbvfBge+M6UYa6JaE0N9TOQ4/fqz3c6FAtkLJNvemKgfedM4H/5wOP463Hhw1XezlUd3W6Qe/UUEgB/xFT/PQGAKQvaTeEj+0tjbHULM2Pmkf+mi7BOndHO0pf8AaOwR9ybVGMZOHVcfuOqzw8kQR9EoqJwu57MoHTVUyEf8NSw/k2lHDSdW/RMKtoBRzuy1kYFzdfqtY4/k2mbw3t9FHvnU/VUu5qAM8i365AkYwLg5H6Ak6V3DpMFv0SiqNj9QnS7tgUe7uG4AfWpDfzU6UcMH9P5qeJOh/JHG8UA//qKq/Xyz/wDRo/wyNB+aBqDqjpvQkYF/lb84kP8A9OqzwzQwgHiNQjje0o9L2WH1pgf5DQPCR/SUC8RtKsd8VpHuXiNh8jQuf5HTHhTf6T9/BAPncffxVLvi4g5+8YX/AP8AXyj+TaLuFjQA/RWeIBYx9UVN83LPeankA/8A5OYf10P4S2P8Ite3b9f2ThN9XI4zFCf/ANBMND+EC9/y/dIagnT8/wBk0uu9rgKGWQTU1ulQho5/LdjG3z6SPe7Z7fEZ0v8ACdhv99VY1w1Ud7rzrJthaGpuO7bVEK6s9hMU9E00VYPeLRxwKY5Y5Mk+mQxPzKjVw4QDLcptfp85kR3QOIYCJIE6X/I9VG/dfNu6rpT7r3VS0e05+O7Fb5Wl3NJUNXxMoMcfsVqoenqqrl7wp1qHMgjaRUKSMTHrp0uCgNbJOZ9g2IJ6XNms3tci4gCRwMZxl4e4U2gU2DM55MtbGogCXPieWQAfMZOUx24u4y3twlx/S36fcN+2byzuymgqrhVXKrW8wSZqZHgomd+lhDSRyRxeQhWFgsz9JZjrpcQFGo8UWx4bTbLyyYEu3u4izjJiBMLh+znDK9CkcZWk4iqD5znLQSS2mDALQ0EZmtgF0kglco5X3/y/vLdm4958h7a3dvvbk1W1TLQ7epp6WzVaUkeWniqatTKpdGZAYwwIYN0tIUBelwRlFgFKzti8wb2gtbr8T2BiYzcT4viC4txDC5sAFtMZhLbky4W3sB3OgUc79U0fIXFEO5rZxRaOOtmXOre2VO8624/sJJJ66Gmf2eCnpmWaOFJIXVVCTVEsQfr9IpOrhsM6nVaKr5OuUA5iACb3BBMQAeVoNxNx4rH4ulj8Aa2Fw4bTkjOXNDAXODJAghwEglwALi2xEXd2Db+2tvbEvc/HHFfKnCdjsl6rLVdeUbNSVCwSWmDyo4oq2kpnmRauWnWVKqpqKZUpJXl6j5irEllSnWqRVxOWoCJDZGaTrDhlOQGIyudni1iXLnYTD4HCUnYfAtq4fK7Ka0O8MtbEF7CHs8RwnNnY3wrFxGVrTu9NyVxnYt8X/Z/h54g2rylaqSxXtIE2deJLk8000NPV/et03DUMInnp5qGhkeA+dOFdjgEmPWQYXFVqYqVn5Wy2MzcjGgGMrGQXXDiJENOknVd7+I8PweKFDhtI1qkOnw3eLUeS3NNSpIaILQeYuc0GQyBlMmeVtweITmKh3ZuTefBXg3uXHW5qCO3Xay3jkKrmo6yqRx/t8s0NvCUdWJJQhLFSSgUgsEfXOw+Bo4Z7cuJcKgOopGQOl3SR8D10XZ4q7ieNomk/h9N+HcIc12JaAT1EU3BpHWR8188yt4kvs5+eBfKfb8ew9w1VvuFDRfeVIlxgrrVNIYpAvmIvmSIYkPUVV1dFYqOrB91icNRx+H8MulpgnLaCL9TE+vod1+PKjuL+xvGPefCyu5g0OlzSwmDcZZIgTYXF2wYXsltHeXii492rsCPj2r8M/N/G25KWPddns1HRXGym5ROI1ljpZmeczyL5UayGVGcyyyM+GV8ePr8OwteqSXva9nKZDXAaxZsZR/TBsANl+r+EcY47h8LTrYVtCvSqgOADqjCZF4e8uDnbukN5idDIUlfDz41eNd4XTemy+Ttr2Tww843WpNVbNt73ppKSGspKdBDCKaoCR01c7ftixToyWHSrdA1h4lwLE4emx7iXU787biTr1ItAvO86rt+zH+oeAx+Idhq7Th8S6wpVbOIbYEEw11ybNPaNSvJr7cKJR4iuJJbhVxV+8/7BUyXaVaoSmRVq5xTkoIo/KHQG6UwcqAcnOvSeyJYKFRtMy3N9SBN99l+ev/5N0GsxuEc61Q03SNLB9rSd819/gvF2Firr5vcE9Pc9yD8tetncr8vsEC6mz4Btt8dX3xDW6u5ShtlVta0WO7XqOmqR2q62GHFMiKY5Q0gkdXVCjAlBkdtYeL4l9PCudSkOJaBGtzfQiLbyIX1P/RvguGxvtBSp45odTa17yDEEtFrGxvsQZ7r6sLhzpdLhdNr2C87Z3bx7TpAtDXirrS9dU0rKhjKOwIowfMCuVLOoWZEVQCdfL/4Y0BxJDpO2k9zPNpMXmxJ2X9AKWOBa2ixuUDQEAECNmgQ21rxGkEgFYrf3Ic20OPKKu2JZtv3qWpIoaOKS8VU0NV5IiT2h4REBFHT/ALILFCAWXpiAyUC2MwQfUu7LuTlAInvNy7vbU6Ao4vFOoUnOpszHQCZB+AFg3UxJO1yJ8sN0cwVm2OOv7ccmb2tNNadzcnR3m619VG1TW1VDTs9U1R7mGcssVL10sYw4kAHu+5ruUsIxlanTpAlzWWA/qNgLxoXGHHcTMiV8r4px3weHOxOOeBTqVhmJMfyxM2AMAsYJYCTlMAQV2m7eNrxFcqborYdncU7U2Hx9DSiWCp3rRXH2u+QSll6+mmD9KumMxtKCqu4ZicgU0vZJtFs16hDv6WBrg0i95IuD2IMCJ36TP9S8fjKxbwzDAUoBD6znsLwd2Na11txN4MmLRvtLu3xB765U4/5J3FvXwuXW4WOGWC0237su60u4qi4U2AJoonWSNY16eosrKFjyVPk9Omp8Jw9Gm9k1Mzty1pyhpkm5idYi/Q8y6FXE8VxL6NaKIYyTDXv5y9oa1ulu4IO3QxrG4l5U3LUDclx3Hw5xftGooR5Vxt+3Kuoe+VFRKyM9KlXOip58qtIahkhYRovUDFldL7vQZyPc9zpECWgwBIzEB3lESJNyd0MRR4lUIfRFKiy8uDXu5iYOQfy5k2DhAgbgkrNcSbT5p4u3rFQ3rmva99uVRFHfYqC72uuho90EVnmJTUMiSkOGnek6f2RKezqCFjJLWYjDYRzP5LHCOUHlJHKRLhaIEm53nUQtGBocXpPy4iuypm5iIc0RmktB57aNttIDbyuscm763jviCusXKNkHGtLuCjuVNPDct2tFbb1VMrxT0lFV02I4G6RK00c4heZ3yiyKr5wt4bTpjPTIfEGzZjcEg3jQNjMOsGF18VxKtWIwuIYaQeCDL8oJNsrXN1cQSTOUj8I1KDwlFwjwxR0fGXJ9mtNj5EesopXmuiveaapWGGJ4IaarCmLz1icxezsVZAnWUTPSbMa7EPIdQMsv5bXJgmDeJuSB2k6qjgmEweEaMNW5ahDQA83gDlAcLWAsJBm8DVTx3Hy5a5q2Tb9ovNffNv09rFRKlrWGLzvMYhKRZB7iFpA3mA/hVkX1bXEZgM3MW3mLm0i8neAPmewXrm1A2IOt7dNJHcwYupCbN5BgrqianW8NU1LxiaoSiYSQ00zEnyI26B1KihV6gACB2A9NZ6mAjaR8p7/H5pAZAtH6fHddCbc6E+9PfcgfFwgP8tUe4TeB8/7oEdPy/shjdcK5ANU5+T1q4/8An1b7mdwEoa2dUBt60sUlOJ2o4euQKvXXDu3yAz3P00p4eSLa+iaRIlRmve7qOx8JWmlvEdopa1ZoVljkRqqaNPaZH7whC5XC+uMDOddt2Fc/FHw502t+HrYBcSi6mzDB1aNbzf8AF8SVxfwt8pVNu4+29TU+0Rua3rQ2/Bp9vVAmpVamIJV2Xy5h7uMllLDvk+muv7RcJc6u50kGTqRtHe36Lg+yuPpHBsgA2GjXA3nqIPrupz2O+Wu60S3izNboIpiVZkoGp5AyEoVdCVKspUrgjtjXk62BeDldP0P1/VewoPYWyzT4jTtaFljW1IIZdwXWA57hCvSfphw3bVZwgP4VcAeqE9fcgzMm5bi/YDpeOPp+Pf3Qpz+vw1Bg2bt+pUv1+iT961oUrLVe0/8A+TKmf56PubfsIShfffbpqLbK2PitSJf/AJiDqHB7iPv4JgbRdCO4LdEQZLe8fb1alLD9SM6IwZ2SamCiJuy1jtHPQxN9VCfwIGocE6LyoQJR13QkgBiqY5B/yPn+WlGEnVNZIbcbH/1jZ+p1DgeyBgIJ3FnJ68/ronCCJUkbof8AaA9h5hzqe6SoT0Qmvzf+0/efXU907IaIJv3x8zt+eh7qpmCA19yDmTB/lpvdDuoTCE18HciXAxnTe7dAoEI3wH/1q/qdD3YhAuQDexnAmGdF2EtogUFr565lBH56ZuFRDigNfGz3mXH56Iw28IlNmvZ7gSjP56b3YdFJ2QmvZyR1/X10vu6Eymz3vPrIP36cYRKT0TWS7oc5MZOfiB30Bh+qndNmuqd/eXPr20xw6BMJs92X4SN+jHtpxhroTdN3uxyf275+jnU92HRTN0QGu0gbtUPj19dEYcAaIC6bvd5M/wC8MT+mp7ueihcZTWS8S98T9vqNMKAS55TV7zN3/bofl2/8dE4bdDMQm5vVQMgSRn886Y4UahRxQWvU/wA0P/eOp7sEA9N3vcxyepG+ProjDQlL00kvc/yT/wCP/wANOcI0FQPMWWMa/wBgIPVBTJn4mlYf/Tr0b8M83Kt94ZKWm49u4IE1FGPT0K/6aT3UnUINxLYkFGO49vH8dyo0+PasKf8A1DR91dsPp/ZK+sw6n6oi7ksWF8u/wrk9IK3I9z8u76q91FyR9E1PFg6O+qfpuCjGOm+yKfl7apx+/OlGGb0+/mrBXMaynS39APcvc5Pr/fxn+mmbhGnZAYiBcpwm4sHAvMh/78Z/ppfcp2SuxUbo39opTjovTBvTOEOoMEBqFPerWKpdxVQB/wDTqj84k/107sG3p9/JFuIcNXIy7oqV7G90Z/OMD/69UOwINo+/koMX1j6/uiru6UD3rvbD6f4D/wDt6Q8PnYoHFbmFcbxP+K52k/o3/wC1pv4feyIxfdKG81+NwtXrj1b/AF0f4a6xAMeib35up/NFXeKEdqq3sfp16n8NcNQmbjGnf6pX9sJP8MlC/wCfm9v/ANXQGAEXn5IOxkDlj5/2XON0b73jR3BXstw2xTU6DzohXwVRUkI3UFmjTIB6gMFT0+ucdtW/wtm8/IH6SqqmNqCzQ0nuSP8A/H7Kgzzvy83KlDe9imnsu2bvdZqa3VtxidhU0NLNIkR8iokjUN19QAkUqydPV0du23DcMyQ58lguQRAMCbi5iLkEfnK89xzjDatI0WENe6wM3E2tpcmwIMgx0hbttm5W/lKybJ3W16oducF7Fq1o9i0A6IYbuabFPFd5RIgVolj6RSwgAN1vMfeeHoUUC0uc69apM9Wg3LRH4j+LoOX+pZMHXZXps8HlwmHMA2h5bbMSYhjTdv8AW7n0DZ53unfez7zvTascl8tm6qyn8ub2NqyoqY6kCeObNRRMwhEcQJfpVcMAAcN2JGDdSbmHKesAdrONyT8IJst1bi9GtUFMOzdg7NuNWgWHXW11y/xE8wXje9fY9uXa53uzW01Hnw26zeZMKC2jpeZ40ijyMMYwJGljjhYkBi0eBZguGAOc7LmI1O07AyQL+hLul1zvab2gLWCkwlk2AEk5fxEBoJO0GwaYuCFDfdvJe5Id/wC16DcWzN6PviK5NaNr7TippIVelmpGp473VUJleCmr3DqIUc9CeUpcN1M430MCSHRlJI5nSDF5LMwG8HMRcTA0APzLiHtSaeIoiqx4LXZaVEBwz2IFYsOkEjICYJGZxl0t9GuP6m0Xzj2y7H5Tavu3E9LCLXZdg7Xq6lLB5JVmWlrbjCqy3ib9p76SvDGGWUtAc9Wsdag7xPeGNDqhM53DQ9WsNmARZxzGIhw0X0bheHbVwwwuJd4dGI8NjrunXxKrYc8unma3ICSZDtU5vY42tVdsjb0m3Nm2azQ7t8uajhpFoh5T2+anpQUESqsaSLGhHSyOUXq6iygo44h+Z7nEujUyYMgkz13FwRstRo4HDeHRo02sYHgQ2BbKREW9DqDodYWX5KoL5ZducfVtdtXb+9KG3L5kkMtc8tXI0il5C1YADV06MxkaGaPrQgAFhoUsKHud4TuwtYDSw1adrGCt3EMU6nSDnszdeaJnraHDe4kAdF5/+Ke1bk8U/AVPabxtW20XIe3aVGsa113MdRapaWWSKqooROiyVEdQrRrHGnUXlTr6kSIKejwygaFU5XSHawDewINpAjUyQA3Ykr5T/qLw93HuD+G+jlrU7slwBaQSHC4BcHCBIBzOywQAVDD7O/xBVvGvJVDw7u7cDbIstyrZY6evqZRTvb6kKfMoXLxlkWodAg7qI5TnDFzq/jGCa5pqET1HXvYwY7zbSF8p/wBEfbl2CxY4Tijla4kNLoGR27bgkZjoARDusr2Q8WNXYN4cPxbY3JZONeUuNaKT2Zqqshdp7aT0oFjaQN5HS7xddUhUlmI6Q7hjy+HMcyp4tJxaTtFj69R0ET3gL9Ke3GDw+LwRpYykyqwbuN2+nQ6cwIA6TAXzWeJTYFVx3ybLZKq83m8001rorhS/eNU1RUUkEkWUpmlZmLCMDpByMr0nAzr0OHNPKfDAFyLQBO5svxB/qNwivheIBlWo57SxpbmJcQ28Nk65e0CFHsoI2icks5wcEY7jV5cLgLwRp3B6qVPhZpHu125Wtn3XQ1YrNmVtG1dUKWSyrLLDH7YPh1p1YHV2JbuR6it9Nzg0gwMzZ6kdB6/kvo/+mhz4muzLJdSeAb8pMDMTI09b6L2N3DV7R4+29YrheH3OKGxrUvGZbiK5pXKiFa2elgnkCFmEY82JP2ZfpVlbXn/AJDhSa2T0+cTF+8kTrov1tVrUcLh6b8Y97W093k3gAZi0EwDaIByzsVpVy5z5btHG9fvveFLbt98ibqpaez2WGmlllk24J1WGPyqeNfLeUrKWDMwZ5PNADAljd/BGMcKTbCZcSNQLkSYgQI00Guy4lT26x9LAnHV2hz3gBjWnyudytloBzG4cbgzYDdcI4y2DtLxCb8vm+73deT7nxFt28UFg2jQtQRM8/skQZ5J290JCsqqTDGVMnTh2HRrpYbPSb4gaBVfLiZsBNvU9CbDUTK8Fw/hOH49i3nE1nOweGLGMbkgvc0S6f6WzrAzOgAkCy9Ebly5eIr3yFZZd+1FduapoqKgxHGkk8srO4jcSF5AWHWjSFX6lY9lAGuMzhjeUZYBOugt8Bp9YX3L/ANRc9Sn4gzBotuJJggSfj0tbUrVbjy9vKr5iptmvdoLxyTaLAn3vGLhLTRUKyyMk0sUTKscVO8EyFJZZYlSNyAAelTGYKjkdswkXIF9wCZ1nUAEk2g7Y6/tDXGOZhHHPWY2S1uoJtIbEkRoS4AXJPXrdl4r41hqtvVO973T8iVNzmlWkpLRUSQUlvkkhUQQpJMFjCiOJQsy98qEjjRXCvoIIJ8NvMBJLhBMGSbX1Okd3GwA6dDBsexpxLpYTYNMtAiAL20GshoJIaLlx2enuVwnuO3d6zUFtv7s72aGCSll6kaeMq0wSRMBhJTxSdbMDgM2Ex06qGDhpY2RNzpEC+oPQ9/UroVMXmcx9RoIbbUzJtoR1A6CLgLbdz32w1lFfONd0TUW4fuuCpSWdmC2+41FaskMccNPgIxRjJPLJ0uEeMBCxUgJh6Ba4VG2mANc0CCTOzYsNC6ekK7FYpjw7D1gHRcyBlm8AzMmbkXDYvdc73jxvxDsWDdb263XS7WurgpmnoquGaU7aEM6P960cUgkMEa+8r9KtiLpaNXYurXsc6Za2IuTa4/pMRr6iTawErk4vhWHosdmJc0xaS7K4fjbm0ib7AX7LN8abug21JVczLs27ck7Nq56hKWO3xmR62IOY1uFQsh8ozL0qi9R8zyEZ5OpwGWvEYN7milYPP9UDLP4et9TsCQ0ECybBcRptzYthLqZ/pl2a8ZomIGg0LruIlT04qFYKSpv+4Z4o7hPO8iW9Io1S1J0hFpndRh3QKx6QSqtI+CxPVrBWwjRAFzue/beNp3AXpqGILhmjK3Ybx36HePmbLsB3BRRnJe3A/wDc1n9y2CvOIgXSxueADMc1Pj/lx/TROCO6RuIHZXO7MD/egfj2J0owBnREYkFcp5Y3Sai1WuLzZnXzppWxE5yFgcAk4PuguCfpkeuAdWF4dBcY2/ULDj8YcoM73+RXJ/DTuCC2bG21E1uqpQ237M4FJTsVP7Nh1JjBCdx+RDfPJ6/H8DnrvJGjjrH1+S897GYwNwNEj/8AWzSfp812XZV4nsVpNorRuCgqzVVlT2jlMfQ9TI6+9765wynGc65mNwAc4OaAbDpsPgvQYHEloIeSCXON50m3X81t8m8CgBW/xRAevnonf9/SdYxw0QTlW4YyDMhOF3TcugNFPbqn5YLKD+7q0owDCYTOxJ21Vv7XXBcCajI+ZSZWH7m6TojhwhAYyEJt5yK2Hgr0/wCYRdQP/wAJOoeGwLIHFhI/trAP/wC7ER/5wy/zA0h4bGoU99b1V13dDOD5VZDOvb8MgYaY8P6hEYkG6bSXelfLvS07fXy1/njR9xtql8cJu93gJyrTRH4eXM6/wBxo+4bQicQJsk/fcwJKXCtB+RdWz+8anuAjREYm2qGL/XocrckkX4B4R/NSNQYEbC6VuJI1QW3NcgcBqGQY+JZf9dQcPFyo7FHZJ/tXXD+8pA3+SdT/ADA0v8OlT3sITbvkXBelrv8AuqG/kdH+HHdA4qEL+2MGf2jzxf54XX+mlPDnbBN742NUht5UfYGugX/M/T/PRHDzGigxjeqWN0QyANHUxSf5XB1Dgwm943VjuEkEhyTnQ9xQ94QG3AQenzPj6Z1BgZvCAxAmyA24R3w+R6+uiMJdAV0M30nt5jHt89T3IzdT3i0hN3vxz/e4P56YYNDx0B783/tGx+elGDnVDxt0Br9nv1nR9z6BQ10Br6Tj9of36Hul5hB1c7FBa+en7Qn9dM7Czsl8aUB74TgeawH56Iwo1hTxwm7349/fPf66Iwd1PHk6ptJfTj+9P79E4W8wp4ybvfWPbzSR+eiMJdKa8IDX1hgmQk/no+6DUhB9e90Fr8xBJk7Z+eg7CiLJTXEJs9+JXHmHHz04wkFKa8JrJfycftNEYPsgMSdJWO++4gpASId/+Ea9r/D2leTHG7XS1viYB6IQfh2HbS/w4KHjPdHF8iIIKQk4+Kg6T+Hbqz+MBKN2o5ABLSUcnSQw6oVbB+Y7evfRGBI3SHi7OyoXG2N+K32xvnmnQ/00XYJyb+KsmIHyRkuNtyuKG3DB7DyEGP4aBwPVOOLtmLIntdpbDNb7bn5+UoxpfcXBE8WYVcVNmOT7BSA/TIx+46jcG4CNkg4gz7lFWqtajCQBBjt0yuP/AKtL/DzN/wAlc3ig2/NOkuFKoDK04H0qJP8AXSOwG0I/xWLSnC3WJfSpr17entDH+ugeGpTxZvVHF19CK64D/wDT/wDhpf4de4/NM3iY6pa3lvQV9eP/ANKD/TR/h8nRXt4r3S1vc2MfeVd2+br/APs6n8PA0RbxWBYq0l7rVjdobnWvIBkJ+z9/6d17HQ9wHT80v8Td1/JR85Q5fkpbHFVW/cFwpOmojikaOkiq3ctL5bQNAyKoz73vlgVK+mNKOHjXKY7SNp1P1gFZMdxstpyH79Ad40F/jZebO8+cd7bgt6bb2fa7ze9+3utmsslZFKppnqK2P2VUleRGeoMcQl6WQFUbDKxKsutNPhkkBoho6/M2HXvEi3Qr5vxn21qeGWUgXVHnLaIlwygEmLjXlBg37KQvCXHu8du0tq2vf5C7rLJAK2hxC1FTxP0GKgYIGghHXEobpMnSY1PUACGdgAOYaamd/X84Bhd3gHjYek2hV1bYRENA2aLCNBJE2XSfEVvzadws1p40v22tvTu1YKShSriRoKApTtIjyNHiWNvcYoilJGkjXJAydVUsO9pzhxvM777CIJ+YAM7QupxziWGawUKjAS4wJteJBJBkaep0CjttXd+0ePrc+6KmW73qiio+tq+6N5knIG4JQFZA0cR8whUVI4/2Uaxq0gwhdjKlE+Vrco0aB+Eakm9idSXSdBqAFxcHxTD4UGrWeXmLucB/McbBrYmQNA1ogmTeS5adsPbFZd987X3A1RbJuZbjLJuq/wAd0pnhjuBERpKKFlbqJmT2mb9o2QuAo93pZbhhw1ppXDWCAfW509PX8lwuHOdVxNPGENFeqc7xcSGjKwCZ0zW2gaXBUx6PkGo2ftQ33bEcN8235+bnZTa5pXsN2HaYLGWPQGYl5ISViIZZ093zM5XYPO85RDvgJG2vbe/TWF7yjxltCkXsjJNxDuV29u51H/yFiVxrk6rr7/Twb2uVyprU10r7VSVNCY+uioVgqY5I1hWNn63QVVRK5BKe8TiMIp1bTwQa4NAnUyNTIjQgWsB19ZXO4nxB72Gu90DlGU6CHAgzJvckjTpZsrb9t80T8a26m29DfLTYeP1tVVc6KuNCJjTmWSQVMUzzy++Fl/CzAv0P/i1lxGEhxc6bRaw9NAdegW7h/HRRApvLcsF0nMbyZBJI07kW9FheHNwUe/xbNz0G87dbuQ62I3GjaCjg9jpYpv2EqsEEfTKwQZIyCGyO3WBbVYxrHNIMaEzBteL7T3HfZZOE4/3lwxAeC43aIEDUTbePXfLqV4yeL7hf2CjtXOll9hqbfeKiWK8rRU7xx0lxDt1hzlkLhupSUPSVEberMda2sgZRtpppt+/02X5z/wBTvZsBw4tSjnJzhs2cDvrBm3yJ1K2XjPxB7535xguxKnflyNfQW6pgrLQ6wedc4SyFJaMuQ0koWNupcZVjlQes5yMwlKc8XtF+nwMbb/QLr+z3t5jMZw/3Q1eZrXBwIGZwtBbJGY6yI16yuLeMvdVHu7fGyr1blqpqJ7BGYamrkjNTXKZpG86dEJ6HJZlIYkt0A+hGpQptbOnoNrafqvI/6q8RZisRh6zBILDc6m5uRcjprtayh6CS6qrA5B7/AAJOtO8FfKxUP4V2ngzkP/ss37QbruFyusW34nhp7tQ0FYaepudE8qmSKNh2JHQr9yACFOlc0O/DMaeq9X7HcZfw/Ge8OeWsEB4BALmkiQBoevwXpq3iSs3LAve2uN/D/wAq8j241UVTSU9soYraslL0jzZ5ZVBeeolmRIupmcBRJ0gvJkNTweLJDy1o/wC42HQAWA6ki5sJiZ+6VP8AUDAYzNQwVGrUba1NgBI1c5ziSTewBsJLomIye6K/nnm6+2Dj7eW8NjcK7Skp5ty19os1yF2vtr9hBgihkV1VIahpK2Xy6VekhgzdikeEpcOpAucXGplEQ0ECXWIkzNhd2kepVmP4txrib6ODeW4Wm7nMua+o0U7g5RDW8zhlbqTB/CF0Ox8e8bcTWXbOyNqcgcrLTWm2tcLhSx3qoovZJpG/3mpK+UKcHqcmPI7HIYDuBiadN7y59IDaTf4XNz6R0ibL0nA+HUOGYeng8NiqhgF5AIFz+Iw2Wi95JO65dUWp94XC31NJu3krfzzPUUlHWXm8VtJQz1Id1aKgcFJJFRzFKWGCY1dmkGMFzhGUgS6mGW3EmNZIJgQJsYEwIMrjvruxVQFmIfVJJAIcWsmYhrgOYzFwHGJOYALtXFvGnFdmo6PdNvudPfN13Ohlulcbo9LW+UnTAIE83pYFpJDLjo6ViDdwfLDM7qwAyU+UN6SJMmY00Aud9omF3fZzgOFpH3lxz1Hi5dDjAAibmxceUDQRMkSpDpzFYL7b7nV+z22hvVDbqukkWermihjgPvLPLUoEjjiBji/CWy3bp7HWR+GeGmbabb9IJJJ6D+y9tS47ReIbZzJETtGsgQ0dTNlm9vb8q/8AsmqKnelNv+e4pCzUVA1ulp6WaR3bpVvP8lApMsS+WGJZXQEYJj1bXweV4a0DNpJIn5SSTY7GO5EhcD7Qk4U1apd1gA3mYuQBEEXJEjpN4z793tuqSosX3nbNubJp6uopbVbGa9MKm4mnMiszvMwjigNR1NLKmVjUBR1llVozBtzCTJMuiDAFoJgSbC1pcT8R5niftBiA0ZW5RIaDmBc4yZABIaBNiZ5QDOsGa+2325WRWekrGt+4K2ot7C82221j1JLMehPvS4yEyTRZMWVIjjVAV8tgekMaLnCKYlo0JENB6hu51MkuJPTVetpVQ4h1eznAy0HM4joXWgdmhrb6wuqWLZiUcsF6t95Fup4qVLNW0FrjWvppohG0LSxLLGWd0DHLdPUyBlyQq4X3drpMZid/L362Hx1uuhS5IDOUNsW2I6drj00st52Zcqjadztu16qhn3HEKWSekv8AJNHHTVNEoVYkOT2njAEbDBJUB8nJArfhZBeLfnJ+GnyV2HxuSKbpPQjSP3Gn10XbKC7KKcS+ZA7yM0pKLhQW74Hxx6evc+vx1V7rBgbLYMY3VPPvrGPfB/I6HuiPvgVffR/9r2H/ADaT3S0wm97XJOT7400dNTIxkdaKrkVAC3msVCqnYjswVxj44I7eo00MJqT9/f30PMx+NmG7369rfH7vcaVwFdJKfbG04mXyf/3ZoBJEBgQuIoW6V+hVw+P+fP8AjAXo8YoTXeT/AFH9fv8AvK4PsZiyMDhwP/1t+Fh/n66REhPvk9/eYH89cj3NetGL6Kz3lmDB2DA/A99T3SNETi5TF6ykYZanpyT/AMgH8tM3DEKv3kbIAq4I/wC5aph/yTOB+7ONT3USj713SWuE2T0XCsTBz3Ctn94zqDCCNNVDizEyhm7169va4ZPl1REfyb+mlGDGiBxhhNHudQxPnUVrqB884P8A+sp/np/duhQOK6hN5LjGPfa1zI/wMMoB/gy6X3ORFo++yHvY80H7+KR99ooOZL1T4+DdTD/6tKMEdAEW4xvX5oL7gVGz99tEpP4ZYlx+/AOrPc5uAgcfB8339EpdwSsD5Vfb5j+Xr+eGOoMIJkqHGEiWxKoXyvGcxU0vwJSQj+a6HuYUdjzoUNr/AD5JankGP+F1P9Ro+4oP4gAEE7jJwGgq4/h3TP8AInUOBUGPCGdyRZ7zOp+qMP6aAwJ6JTjxOqE25aZ+xrImb5F/X9+m9zjZBuPaTqgNdaR+5FI7Zz+FT/HTe62sicW1N5aulkzmJCfgVyuP3aDMJCDsUN0M1yL2SerjHqMTv/U6UYMaAIOxo2P1QDc5QMLcK3t295w38xp/chEwoccRaUA3arBPTc5SPk0aH+QGicGI0Se/ERdI++q4E5rYXH1iI/k2lOBERCDceeqbyXy4jHRLQMfXuHH8s6gwLQLpXcQfMjT4oDX6vxl0pX+qzMP5rqHAwieIu1Q/7RVWCDT5/KZdN7jdAcRdJlCfck4z/s07Af8AC6H+uiMBJQPEkA7ncgg0teoH/KD/ACY6X3Eg9Uo4kO4QDuhcsCtag9O8Tf00W4Ao/wASGhP5oT7nhznrnUntgxt/pqNwNohE8UGkpu+5oB6zsB69w3+mp7keiA4ownVN23TSZJasjH5k6YYAqr+LM/qQG3VRH0r6b9ZB21HYI7phxQGwIQ23PSkDFbTZ/wDerqHBEKDiI6ps+46fA/2uA5//ADB/rqDCCZQPERunDXNlX8ZOvaOoAL5aOKEWVC5HB6WJ/LSDD3lMzihN90Zbkcdmzqe7WuoOKOKULk57dXfGcaU4YJXcSOoKKtzb16+31Op7uNITjijouiC6MAMMRpxhoKI4o4HVFF0xkdQxpBhQlHFDOqKtyOBl9RuHumHEzqlrc2wMsB6fH00fdhKtHEzqSiJdCf8AFn9dB2Gsk/ihN0Vbo3bDd/z0BhxMKfxM6IouhyD1HHr66X3UaQmbxU6Sri5kAYbA+uj7sFc3ihQqm+ikhaeTzWjBUMEUswBOMhR3P5DTe6TaLpv4tAJJXO9w78rqj/ZtryJcK2UMlM8TOhhlGQCXaNkAHS2QxwQD+lTsIcsmw7qqrxzZhk9lHG97gk33R1ke57nuCWhgrXpqeO2iVKS6zvGyyylowmKaQuY1XPXIoHorEvG4YOE5Z9fpINp3iIG86Dh1+MGqXNe8tAOxiTvcCYvEzJi0alhafb5N1bMp5aLbFp27ap0esp6aFlqaeRopY/28oKRMgZWVSB0qI2C+vVoNwjz5yT2i3qN766Xt6JW44h1NjGhrRE3va0Eael7XvNx3HeV5egsbjb8u4aikWp8hK41coqJ5yMtFEzlSYWwpaVCfwqq5P4a/cwTGUen5E9u25K7NbjBaCWuJvr0PT49bx1lRl3tU+VsOprb1tekoZKCplofbqiaSWeCaR2FRVdUbMMssjIoVmIVZGZupgQ7qRDbReNgbC4/c2GwC4tfiU081QGWk3J0cbT8jAN++gUf9rttq8bovqb6sdNfdsW+0z0lL5KO0NxmlhZo6l4yQRGAEcLgOOkdWSCBmZSIBqATHbSNZ1uPkDovP08VTq4g06w5GjqYcSLHYx3ubXMWXVKa87e3Pv7kyfjSCk3BR0W3bQkNYJeqlEymWpHm1QOfLPtDIWOXAjjKt27PTZnGoAm0j4WGvwFuq6/8AE2uxDvBOYhjd++YSZ0vE6iJCe7i3rdOP7hSci7ipLBdIVtMdpv1JDNUMlZam6lNSMoeuSJXAZ85ljadD/gAj8Kf/AG+aO3Tb06DYx1VtfjTqLxi6trQ4BxuD+LuQDc7gkDZdK4/3BBTbY5JsdNa6yvv8FD5tuulK5uENttpUvT06svSUWF4jG4C9R6VDAnGmfRLWkAW1O0nfWJ7bLTgOJthzDJMct5AadNJjS51Ij0XErxu1t7cdCj3K+2KGvgpqI0lLUUJeWrknlRwCyFSjd4yD74GHOcsNV1Q0OhxNzbTQev3t1WCrxhuIw/M1sASQQZJJ7fe/RRvflqn40vlwtsG27Z92UVW0EtfX1QUVk0SGWUTQsWd5gOpom95BLIUy5VU1krMeLkADYRfoI2vpOsSR1Xnh7RNw1QsiQNXE2JgkgjW1yANzB6INnvPJnMe0abi608a2u124Uc9lqKqGAXRhHJOWEj1kjLSUohUrGTEJpwvVhQT214fhtWpeYB3EAH43c4HoAAesLn1eP1sdQ9ybQsJBnnIkmDEtYwtBu5xJE+WQvM3kTY+6OEeTLxs3ckET3u01RVnQypDWoPRkb3X8pwSPgcFh2Odc6tSNN2UifX9rhfH8XgqnDsZ4dTzMOoJ+hsbzrY6rbfEBurjTdV72VV8X7bs+27YLDSG4xUPmqjV7r+2VkkJw6lekkdm7N8RqivWNSoSfTSPyXV9qMVgarqTsEzLygugkjMdjO43XAeo+dKhZsnPx7fTQIvovKNJuApW8QcVWS+8X/wBs4bpcbbyQL7LFaI5qL2ijqqWOJA/nIRhU6nlJm9E6D3yNbmYd2RoAIJvI2vb1HbfZet9nuDUq2Edic0VWuhoIkG15EdTroFJTafLSQ7d3vaN53S+bN55o5aahpbbDUm2QVVOsbHDv2WNOqRJOvqPSAH6MgEpVaP8AZqXM6n5ba72AnaV77g/tGG03mo8067AAGN5Q706TIvIG8brLcLWze+6pd6XTaNfumLc8opbQu4aK9BI6MQBmlmkkR+upZ5C4C+4j+SZC5GcXMw1N7MtgJJ1MwBYBu25km06KcDxGLq1qlamXeKQG5wRAMy4udebwCADmI1G1XvelPxRcLNBPet38sbvqqiSpShvK+ciO6kzztR5AkqI5TKy1Tydm6h+HJFIaxr/DoNhwETNwOx0aD2AJmZO9+O4z7qWuxFR1dznDlIsTuS3VxB05iBoANtI3LuLmnm7ct0rNy3w2K30hevM1Xb6iSsq0McUMSVcdLmPqMaeV1Fu6M2SwwdOzgzwc9SflMXnU5d76bWC5mL9pcdxCtlzCm1pmTIJtlHKwuvBI10Nyu47PG99lbg2tLuO5cScbbMqI6uy0u4rVs2SeaGSMdaxwwzO0UdRPl1VnQ4CYIGVGtApOPne5wOwygm9hIk9zHz1XfwWIxWEfTa9tKmxstD4e4NMTOUkCToJjTSCJ6pbOPuVK6Ghh3FcbNf7PDc801lvUdTabrMomBWa5TUcE6SOOrJiIXy+xGXUEXUsG1sE3PpmaPQgtk7T6xbXquqY+o0NqODmSYmab3aEF3K8RaQ20WkTAWSbiXnCdZN3WmSWw1EclStmG26yCpmoU8zCyzCthSWd+8jhY/KIypADE6V/DmlhY4666stuABO27idVsxJ4m93iN5Q0nJEVI7nNG+zWg7rcuIeKqKrad6DkybfW45aKehulbX2yKJ7H73lrTuzL5oSPyz0wBVUFmLDsTq2lhqYBaAWixN9fkB6STAFgtPBqbgfEqVRVqGRceX/jqYAN4yyTrKmXs610dtSr2tsq5UjezSn7zuVKC9PDMUwYIFT8Pu4BI7p6Z6iSGNBtQ5zOX6n57f40XsMJiRRmnTIzbxoPv+5upB0N1p7TBRW+neAOqRxRKmB7oHoo7YH4fQDHf5aV+Hl111W8QyiAgW6liPtld7ZVR1dRVyTuysGUYdsKqOGCgHqbsB7zsfjqNw7YAiLfenayUY45iZ/b5LZ4K/wBmhEKzzTdyS8jdTOfiSe2TpThRqFa3iJ3KKLseg/tPjoe6qfxLqUlrs4wesn4ZzoDCSdE54lO64byncJauouMa3ettxFmmjHllehCRI3mPlSen3FTsQSzxj4nV1LDgMdZcbieOJcA10GD6Xm5nb07dVgOFrhPb6TZNI95qrgx27DGVdkwf2UMgKhUU4XqZDnJ6xIPQDW7iOGaTUht579SNz8lxPZfiD2UcO0umWDp/SCNADa43vZSKN2YDtJjt8/XXLdgwvZ/xIm0qxuz9/wBp+udRuFBR/iTihtd3A7yEH89EYXYJhxEyk/e0np5nf4fTQOFBvCh4idUhrs4ziQfv0Dhh0RPEd0gXdh38zB+PfQODEwoeImdUg3aQ5/bEfrqHDDomPETrKQbu5zmUfv1X7oANEv8AEr6obXaTOBJgfPTDDdEW8QItKGbvJgjzTj89BuFEwj/ECBqm71yOepkhYfVRnTHDlB2NCZu9EWEns8AcdsgdJH6jGgaJSjFiZCQapQfdmqk+glb+p0PdrQQj72SLlBNXMScXCsT44JVh/EaY4cdFX74R+JJa4VoxivDf5oh/QjQGGCY4tw3CBJcrgPSaiYHt7ysM/wATpxhwk98deD+abm4VR/FT0LH5h8fzXR92uiMaRdN3r2XL/d6s34vckUHP7xpfdxoh71HlCQLm4JDU9xT6Bif5MdQ4bomGMPdCN37Z67gnwOUb/TTDD30S+/GNfv5Jq18jU+9cJkHx6k/1XUOG7JRj9sySL2hBxcaY/mV/8NJ7uAbqHGE7hJN2ZgcVlK3+n79TwGpTjnbFIa51PbplpmH6/wBNAUGlA415Nv1QWuVXg5WJh/mP+mnbhwN1BjnRogNc6gesUfp/x+v7xoeFNkhxbpgoLXSf/wBmfy6xo+7tJQGOPRNnu0w9aeb/AONf9dT3ZKMaYiEJrxKPWGo+X+H/AF0PdtkRjnRCbPeHxgx1A+Xu/wDjqw4foo7HnUIJvDEnCVWf8p0ooQl9+KE12z26an/4DjTGjCAxibNdo+/Ukx+ODGf9NMaBOiR2PEWCayXSBu3kuP8A9Ef9NFtB0qv30dFzGo5+tfl4pbfI7dTA9cmOw9P5/wANesHC3E3K+ID2yoxygn73WW25zRbrk6U9yhWimaXoDIcpgnsTn09dV1uHFtxcLTgvamlUhr7FZem5ftE94ktIjI6WKl+sY7MR/ID9+kfgHBuZaB7S0jU8MJ7T8ubenqkpF9rQkkB2AA7aR2Ae0ZjCdntFRcYaVstZvzb9BQC5S3FHpy3SvR7xZsZwANVU8M5xygLY/jFJjM7nWWUsm6rbuGB6m2VPnKpw6kYZfX1H6aapQdTs4K6jxJlUTTdMLPCobvk4+es4VxxSX7YEGWdUA/4iBpi3cItxe4S0rOoKysHQjsQex0XMEJ/eSiLVEYPY4+OgGDbVA4kwlrVHsD6amSSJSuxUlMbjfqS1RLPWS+XCSFJ+CnBIz8vQ6LKZNhqkfjQzmJWBfkjaiIsn33SHK9WFOSBnGPp3Px07cOehS/xijF3BaveOcdm2ieenluUiyxdLdSxl42B+BI7gd85+mn9yeRYLLW9psNTeWuddaFuTfFv389zig3PbV29b4vPmiDiQVEh/BAWHS2G7MQrA46VOc6zNwxJk6nT1++3fZM7jDKstY4ADX7ka/ksdsTcW3LBS19hv+47dUXAOtQtPRKVPW2SYw491WyWTqwCFBwR3JtGFiwBPr96ffZZsJxim0EPeB6f512CyVLzHZ7NuPcq0jUtTE8NM5Kjyox0I2IUU+nSrIuT8dPTwjySD3Qf7R0WPiR97LQrn4hrjRzVl2ktFpqKmoCxKwjEjIgYYiDMcdxklvTIB+GNX1eGOa2xK5H/rHMbgEba6W2XKK7ckG4Lfte+32xQUlDSwGoWi6zJUzyFCied5bAHpBkOAoB6x3wMazs4c+SX66dfz1+euyz4n2iY5jXxA1j9wDH3qtB2Xv0Wahu1tt9PTw2KoT2i6xLTR+XKYIunolIOGLBGkY+hDFD2LasPDwRm6X2/b021uuZhfac08zaYADtddBOt/sLm9de7dS7dF0j2luii31PT1dbNR20CkiCM/4zL1kRxRBoowuGUgOqD1xlq4Fxtllw3JG+/WSZ0glY6XHKTKWdktLpsJEjp/TDRFjIEwLmFz+67x8SF3srSWy5XnbWzrVT1FFX2xqjpqKunlRQ6kTRuHwv8AiESLgDGTk6xN4DWBL3mCNpI+Mgn5kyslX2pxrqQbRJDQIOhtpEEDboIWuy82eI+K1mTbc1hv9rpLdNaqW4mdFrpqdx0EOYWCTSK6ArJgAydRIJOqXcOrPbLXAt6HX00B7dYVbPbLHsEASWiJ0+dyDpPr8ltk/N28Ztujb1x4Vt1C1JRYlqqW9UrSxPg9PUZhiJiR3iXuV+HcHUrUsSJc/KPiQJ32ufQroU/asupiiaLpjsT2MTYdio4XC+8n75mo6ep2per9bo5Z6ilt1RdEbqkLe+ZJWcvKqqCFJwAwUgEADWWjwyu54LQ0m1psN7Dv/decxnH6tfzhzhJPc9idbdNtF6LcbeLduLrrK29+L+WtmWw2VaKhpYLTHW0FD0yF2liWlYmNWLAHtgBU7YGus6hiGGalMmdS0g/Sy9twz26oYcBjmuptAgAtIaD1BE+ijX4obvxZ4na3d/IG2+QbVU7zt1JB9309QwppZKeKESS000UgVzlnl8tgCVaNg2Q645OLbQdIcS11zeR+fXfpaFy/aKvR4nOJpvDi0CI+oPzseuuy8vEb3oio91znpx6fXXm2HoV85DxmiPglvG0c5kYMy5JAA+H+h1bbZM4EQNl6ycPbstWy+MNj2+l21V101Ba5S9RJH1/7RIoZmjJ7ADqkIU5X32yO+R7NuFd4eZggWH9/y7r6FwLjtHC0aVOJIn6g/uex62UWuQrrba69cqclRvV7T3dbNw0NVZYJZ/eiqgImfEIVkcsYzIxZu3u+ozrhVmZWkmzpje3xsPp/fjcUxjK9apigYcC0gGNbbGSZj0FutnHGZuvINqhs/n2fjG11NVU1103mbNPNVVdW8jSPBB5GB0Dp6VBwE97GO40+FwbqrGl0+GNIAJJ3ubiT+msKcP4m+oDSpFtN7yS6oS4C5mAG2MDQbSdlIDZuxOMdpbjt09kuF63Xf4I56u5X26256sPAYliCD9mxhIeVy3ZgoVT7xBA6dDDlkiiwhrRtqb7m2kagwuzhMHgqVZr31PFq7kgkAZdtQLnfRdurfEDbbJBd6mpkue7qi+llNqulc8U0S0waKN5mCgrGYlKux6wfMAUAkAZW1XH+VSHProTE+k9ogSfqvV/+p6bWGoSXB1okNJyjuBbWZMfQLk25LtT7ptm5KOW4bJ27XVVPGaKAJNUNBUJULkUFMI80bEAN1yjzJFRiCsbhTpbh3F282nkM/wDyMQBvDZ2zSVyMXxI4im4crQQYl4sf+DQZmLZnRvlAapvbE3fdN2bdtc+39p3fck9HL7VcrdQ9FHS01bFgu6R1CwrFC+A/QpLBXBznAOunQdOY2Ikcxj979gP7enwXHzVphlJpdpIbpI6TAg9yuwVI5Tv5jtl6v22NlbXDlHCRy18tYjjqVJKtHiEalR+AKqsB3dwcCMwbSIqOnsBb1M6/l2ldipxTFvhoDWN3kku9AW2Hwk9CFltz8HWKks8l5te49209wiSMvTW+rNNFeI426vZGjXC9DgEKuAFfpbH4s2VsPTMS2ek9UtSk4TUp1C07xGg29P19Sq2BVJQWihrqSu3IlfUxmYUa1KJ+0iZh7JM0fYOyZK+91K/uk6bwmyBA+ZI6W9PkrsNjoacpImbb/rHQb7LtFBe9u0VTWVftM1FWAiPyXcvUk5/9YvvEN3AwDgDvkZ0GshuUD5D7C6beIicxPz/bX70W6Ulayx9ZFRCrEuIpMZjyckds98k9snHfUNG8FM3iBi6eG4YIOT6agoSE38QSDcDkHrIH0Pro+CieIQhm4H/i7fDUNHsj/EL6riG/blJUxb7hSJZS9tmhib49UNKXkU9x2VZRIMf4wvy0woHIZ9f0n6R8SuRjeJEl8XtH0Jj5GfUBA48qpqWk4+glh8qSG3wxySH1Pm0fVGvqfxKnmH5P1fPWrFU5qPnv+f6WCx8ExsUaAOzW/Vtvnr6rt/3mpGfMTpI/4uxGsJpbBej9/wC6aS7hoYGdJq2CJgPQuP8Ar46Pgzog7iQBuUI7hovLaUV1OYwAxPmDAHz/AC1HUdjqiOIjUFJ/tFQftP8AbqbA9T1jAOcfz0PCsieJAGJQH3NbF6gblRgjJI81e2NHwVDxRseZNZt4WSmVnqLtRRoACSZBgZ9D/HSGltCV/F2gyXQmMm/NtooZ79bhHjqDGUYOPXRbQPRA8aYBOb6p4u5rbKEeO40sis3QpEgPUe/b10vgQm/iYMQ7VE++qYAn2qEDOfxjtoiiCiOJDQlIkvVNDH50tXBDFnHUzgDP5nQFFEcUjmmyut0EgLRyiVfQFTkaYURsmHET1TSrvSUkZllc9OcDv8T6anhHZK/iYF5XAtw8oVX3q1RT1s1vSOGopZIWJAWXAdD8O/usM/XWylw9pF9/3XmMX7TnOHMdAEgjvEhPaflK5U9ehrbnQTUppomdUXPS5YjC49cjBz8jonh7SCAN1aPaaoHDM4RC6VNvi108UTy1sAmZVJj6sEA47/pkayHDXhdr+N04mdVrT8v7aSrgo5ap0ZoWlkfHuw49VJ+eiMG4zb+6y/8AqqlIaXX/AChbjDuShqnRKe4QTswDAKwPYjI9PppHYaNl0W8XaRYysAOQLMbgtunrYqepaXyUVnGXbOPT/r4aZuFMyFV/6hptdDnQdFnGvUJcxCphM3r09Y6vUj0/MEarFEarR/EyTEq5uTY7SY+OdHwBqmPFSEj71cntKcfHB1DhwVX/ABK1ygtciQep8nHpoeDeFDxQnVNJK9G7OkTD45UHR8CN0juJSYKaST0zEj2el7/ERj/TUNLdB2PAMhBMtPjKwqv1BI/lpfAaLqN4jukGoQdw8oH0kbt/HUNERop/FDGv5oRrPlNVZ+Ylb/XRGHAMEIfxHom7VMmTisrx3+MucfvGicO2LhQcQPUoBq5h3FbUn5ZKn/6dL7uCi3iTtQgvWzf/AMZL+qp/ppjhglPFHdUI19R1d6w/X9mugcKIQ/ijiY2QWr6n0FSDn5xj/XRGFtBSt4i7qgtcKn/+IjJ/93/46PgBH+JO0TZ7hV9z59Pj6xH/AF0PAASnijtioNMZcZPUfmde8yBfm3MYVo55Y/dSZlHoe+keRqrGPcd7J1HUVEbCWOV1lBzkMfXOi6PgiKrgZGqBJXVzlWapmJA6RkntpQGmwsgcQ6JlZOi3Fc6WJYfMMyAhiGyert6HQ8IAyr6eOeBB0W/bT5Xr9rT1TQ0ccyTx9DqWxj5fuyf36oxOF8SJsutw7jhw5JiZW103O17V45KmN2YAj3W+BPoc+usjuGN0XQHtVUm4TK5813+6JUeZDFGWhMS9BIwfg35/z07eGtBiUtT2nqOm0arDU/Mu+KWoimjub5VQvQfwAAg/hPzxpv4XTcLLKz2nxLSCNvvRbfP4iN0yRPEKG2xsc++gII/LWdvCBrMrdV9r6pEZQsdaued324yrI8NerennDPSf9NXVOFUzBbZUUvays0w4T6rR7/yFujcksstbWEK+CyxgqGwcjI+mtFHBsZEjRczFccr1iZstRSrqwzsZZASMHJ/XWksaCAsIxLuqa1AkqW6plWR/X3j8fz1YWtulNVxdJTWhjqopBJMaaMocxJApUJ2xn5k4x9NUmkDc3QZVIEaIyVAoK2aukkMRkVvMmlk7D0wMk5HofT56SGMM9Uxquzcyw1qqqh66eeYy+bVGedCzE9UYdOlsH07MBj6aFGne4iVScQSeYrYsF16Wwx/5gDg/rrVoIUa4ututc3FT3CWigp6SB5uhlCuGUMvwz3+Azk9jnHw9dZcRSLhliyUvIXBd6xVskw2vRo4UxwtXzRPII6CFWABZwQzghsYyMtJnA6dcPHNJfkAsIkn9N/2WWs4gBgJk9P1P309dhlutHYaGutEKJFDUy9VXMPeqKyXv09WT/d98BB2A7dskl3VBT/ltsPu5V9GpA1kmxP6enb9bpCbhmvcVRTXKuiYqUiqIEZlkuC4HREfXOVClguB2OSS2dClVa8w4zB06+vb19FacSctjH5x27n5rWtwWyxSU1wqaZqfb0sUrFKenLPLUyZA6VAJC9OY17HOABgHGqcWxjhpBOgG/qdPvVZ/KIHL99NQterrFfa2nt+057dQz22CYSyrUyqscRZep4ox/xEHDSMMksqggd9VDDvLgzYfcdhtG+psISPJNiLm/9z1Mb7WG8rpVBU0VVeuigFLBcGSJvYZCYmiQB0zGy9j7pQjBC9sZAHbpMqMLy13mOxV0gRk0/L+3ZJvN3mjNtNFNVxVKhpKRJPM60bPYh1H4T6Hqz6dJx3Iz1SXEBg/t+ytOJDQAXR8Vpl52Zt7fRvEu6be1fX3NW96emU3CilT3euEtjHYowAYL0DOD31W/CiowtqCZ2P7/AK/BY61NjnF7xc9Bf4D46fFecc1NLbqyrpKhXWWCWSKQMuMMpxnv6enpr5nVaWvLdIXPFSOWdJSZ1LZy7r2/Fk9u2e+i61wo4yLn6qa9i3parDs6335nlt1iSZY5KVagtLC5jziOEkZUluk+uOn1AJx7KnxKlSpioY9Br/hdKg8tp3JgfJR+3XX7k5Hrb7drdS10e3PvVqhmIykMs7JEgZvR5SFUYGcDq+HrwTSq4pwqEQ0mB6k7fdlixuIzuIYe59NL/oFKyDbdfsKOn29PUz27ZEjxxVFMK0wgVETdQMobqEqMVbCnAWRhk4YDXq62Hp0ag8SIG3T5D87LTQFSnTyUyY3/ADvJt6D8k/G+9ywXbcFp2ndhFcbw3QtO8KRQLbxGcyPjpKBssQgwJuods5OsL3io4sa6JuTOg/eNvnC6DOK1qJ/lamwHXr6Dr12W48eJRbZEVxtt8gnvM1MDU3eF5PbJ1LARoQCyxxqFChMAKPj666uGwNMsAbcW9SepI+/RNgca+i81HXfpPYaAAiw+7ldo3JzFuGSlpKNbxU1tVJUwvXQyTGZphC5dJi46ffBXHUCPgrHV1bCMaQ0besfW3911q3tFVLSZlxttP0vK0Wm5Y3jTbmuUK7uqvuqolSpnrZ2LNPUEBf71cnLARZbI6gOk9idVMw9MugWaPz/ssY9oMVTqSXai86/ZC7ztvnHdFEHuF1r7XcKqfqHSUHTED1K0QUH0YufdA7g474GurSwFIAAG66tL2rxElziIP5D9F1nbHOE1vmke6WnzJQhFGVld1pO3cqjlhkkjJ+Hw7aZ/CoktNyulhva5wJFQW9Tr6Ll24OY7rbpbhR0xlt9JWVDXFViQBYpeotM0bBcr1MUlKZIJMnbuMUO4cWOEXCw1fad5aQLEmV2ja/iEWGkskVwpay4UqJGJkaRQwwAFBAHfAAYE9/nqw8Oc4lwXQw3tY1oa11wNSt6uHiRo4Y7g9DSSVMjMBTIw6fLGPVj8T39PpqtvC322W2p7X0wDF+i1+DxNXGKEmos9NJL5gJIcgBcDIx+YP79XHhRmAbLJS9s7QW3QoPEtWQNO9Rblqesr0L1ACMZJPw7n0Gldwo7FOPbSDca6LZZ/E3ZBDH5FnrmqD+PqYYX/AK7apHDasnRbHe2VHUTK43uznmO52veIp7b7PVVUc6EknKHyyqBe/YEFwxHqO3w0/uDssFcqt7TsIcQIJ/b9d+3otdtvNd2t1HttLeQtVTLHH1MMlgIwpDHP+HAC/Qn561VcEHOM7z+v5rnYf2mfSpsa3VsfQC3w2Wwnmevehlh8+pWZkVe7ZAYY7/z0zeHtWk+07yyJuVpd/wCSrzcKueSnq6mGJ5BKPe7hgAP3dvTV1PCNaLhczFcequMtcRMLVTu29u2XudYyZHu+acdI9Bq7wWdFz3cVrnR5hZIbyuzRLEaqoWLJb8Z75Of6DR93ZOiuHFaxtmP+UKbdNbKVY1dR5gyGPUfj/wBHRbh2bBI/ilU3zXWMrr/XVaqr1UzdIA7sfTQbTaDoq6uPqOEFxWMe71RVVklkKDsAG0wYNlUcU/LMp7Hue4ReQUralPLcSIA5wrD46qNJusJm8SqD8R6rLtvy8CGSNLhWq7hRkOc4GlOEZotTeOVgIc4yUzj3teCGp6mvqauDocKskhIBPfq/PsDonC0wJ0KRnGqxGVzpF/qteq+Z967cFWsF2moaSRHQHzeoPn/EFH4T2/XGuZiqLM3NH6rQz2kxVPRyxNH4kt8Mr2y63aW6UkSNGGOD1A594/UBu2sVOiwOPVWu9sMSR4bjIH3P32WSm3lW3Zae4VVSPMZFJHmBmIHYZI9T8P4a71JjANpXKq8TqVYcTH9lsNs3BJA0UjsylAWTLZHUSCMj6YH7tO6nstdDGwRJ9P0+Sztdu2suVsnq5a0e1NUBcM2WCH3j+g7fu+mszcO1rgFuqcWdUYXk7wtVrb1MsaO0x885J6Se6HOQT8j8vrq2nSB2/wArn1Mc4DW/6bratvcpV9qjcSSTed0jodW9FC9IX6fn+ekxGBzaLo8P9o3UxzH7H3qtVr92Sm6xXKCSdpU95W6sHrznORq2lh4BbCwYjis1Q8FNZ987iqZkme51Ucih1Lo5UnqYscn49ydIMHTAgBLV49iS4OzQeo7rpO2Oar1b7FdLVcaiWtYxkU8jH34yc+h+X01mxPDmkgtXb4Z7VvYxzaxnolWblG4wSRVMlTUtEgR3jDEKxCgNn5ZPx1KuEaLAXS4T2jeLk7fpdbXtjlm6XXdtZLXTiloJmwIh38lekYA/I4/edUOwIZTuZK6GE9pqlTEmbNP0TPc/OtRSXFKWmqo4qVHDllOepOoAH54x1A+uNZ6eGbqdSmxftU5rw1mn6WWHh8QEiXdleoZqEtGHUEM4OO4A+v0/8NVtpNIlQ+1MO7LpFw5z2/RTqPOSeCbHs656WORnJz6fEfnjVLWSYGq6dX2ipsvMgrnd150uy1FUaSSBYB/d9OGGCvwP0bW6ngQW3P3K5GJ9rnhxy6fNLtfiDqJKcLXQQvVo2SV7CQfX5aepw+8BJhvbC380XH1WcoOe6Scyirt7hVZj7j+i57fwOqHYJ7QtTPbFjjzA/NNDz/DJVSRrb4ooApZWeTHw+OmPDzqT9E3/AKvYTlA+q2yg5b2/XWwV88slJJjBRvi4HdVP7tVVsIWmy20PaOi5mfNC1qTnjbqYIhqW7EdPxz+fy0wwTyVnd7XYeRc3WtXDn0TJMLZTezyeXkeb397PfuP104wDtSVhq+2Ivk1/Va8OdruGklZkZfdAjwMA47nOPmPTVz+HjZZme2L4n77rLWDnsz1awX6Onp6foJ81FOeofTSVMAADF1bhvbLM7LVsFqMMZMUg6zgJ6/Dq12XXErxrRKwEryoTkEDJGqS6DKAtor0VTKBLkkj09NEWPdPnJF9EWSqZVHTgHS5jCrMxKEalyqqTg/HGnJMwowwLIfU5ck9QbA0GtUeDMrKUxeX3cHOMn6auYQgDeE/WOQA9m6fU6BbIVjWjcKjE4A7Y0ewUDTureXIAMgg5+GnbM2SjSClKkuS2Ce+NJAKEEiSiBZcjA+GnywnuDISuiQ9gp+J9NEtMpr67q/RIf8Lfu0blTMd1cJJ3PRgY0gTB5TeaijqjF50byBG6gOogEjv3Hx7/AD0xaNQkcJEFAqYZfb6GZeoyZZCMeqYy3x+YXv8A66Q07iErmE3BWJvlwqLakERWNgxyreYVkLKchQMHuRkZ9M+vrqis4thQOO61K/7wv9PTRR2+1wxVwkLtJNKMdAOCEjXu7+8vYduxJ+WubiMRVAAEW+vpt8UrXzcj52XLbWntNlu9Zd5dwVVTcYOuOplJVamXLFxGe/8AwIekYAy2Ow1jpx4ZL266LO0kuc4n6QsXXrStSe/NVzFyB1tJ1MSRgYPwPf4HSuazLAGqQSRdMlhoIaVqWkSsjmwFIgchzj0LN+IDPxzpfDaRDR8EGOgzP3+i6LtyxrfUqrhc6eJEpvLEKl+oQhkKlyenAYD3sjH4h6Y10MLREF7/APH3+6vDQ8+n5/fxW07G+6aKOVjM1bJ7RIIOleoShjgSAYHcqoOfiCT89acAQ0Q3WFbADuY7/VW3TTx3Guoq2Ww09FTxO/VcHnMDoWwqujIDIpDEDPYHuCCNGux9Q84EfGfkP3QqEA2Bn5D5/wBlowg3HaEu8MFPDUxwzs5radGl6zkF2kjXuFPUwwA6Ag9l1zzTqNkA2B2F/wDPog5zhdwvv97BYe7z1KV9uvdjqqWsqlygVATTISOyMoPQykFvVgy5b9ctZxzCpTN/v77JXOcAMwv0HRQO5XnaXf256sW5bU8tQJWgUhlRyilsEdiM9wR2OdeC4iT45J1nZc3FuyvkCB9/fqtDWVXAhPmRp09+/df1/U6wvMaFVA2hb7QUg3zu6gt0c89HRyRwmp7gNlUQSCIemS3UR8gSddDDUW160mw1Ue6SGabf4XV67blBabPsWgo7zuKmp57jLPPEJy4hSKMSM4i9AynOGyPQnHx11auHpU3Ma3W512Hxi/otQY4MAB1P3tJj1hbTdXu9LTUkldeKe53auDMtLV0iTOIM9TO8nctjCKQvd5GEY+OttemWuytccx2t8Nr3sNJNzYIl78niG42nXvvAgXJvAsLlbhtTZFZZIVr9w2WhvNNWIkjzRhjUQOF6h1YI6jnIcA+7jpXOMHfhsA6kJdBB7fv+e/0TNE87xrv9f2tt3XVtp05padpbbSUd3tsaGCeoM5pz1ozEKYFICtkkFsDJwDrqUAWXbEd9Sr2U4MCelrBbm8NHcbnWSCKaScUphkcv5k02TlmYMOhUAAUYz3z6+utzcriXEffqrBGYHf727fFaq9utdlStvaWanksdV1RCKD9onQV6FyPicgeox7xznHauo0UxnA1VZpti/lC2uzCC2TPVNTRzwufMjnjPWrvhRlc9ycd8gYHfuda6FQtMi8/r+icMynmGi6VLTiogCNhZPxK2TlG+Yxrc5oPmVmcn4rCXSKaBlq45Xmakj80LI3ukZwR0gY7r1An5aqewahBxdE7BKt9PWWypqYJqmpqaDI9mxH1CJAMBCw7nHzI7jHftoUmFouSR+SAJBgrNRVBnUsiTLH3wXBUk/QHvq1riRMJ56JWTk57D5Y08DRBsKicg/P4fTUeYSHWUL4DJLZI9NSSDZM5t7rVbgcW6tqx3JglwB8UIOSfrn+Gs73Qy6ryzJHdETqEVLOgTGIQ+PgvYKR/X6flq4mCkYw5RHZZoAjIYknv6/D89RwiE9zrqkgZyRnv8NRx6qA6JHST6Z04MGTogJBkK56h+Z0Q4Qqieqsw7dOB9e+laZunIhIIOQRnSuEWTB15STCzD1AH102hQifRNzGVZhj0+uki0lUOtZJYZbPqT8dEmBKZhKwd6eSKkkmhfD9OMAnJHzGPiO/prJiYySE7uX4KPlzrJ37SVSVtMGCkkkFcnsO57/mPidcCo+9zKyOeSJTOjeWmlgWKGR55IlX3CMhiSc4Pb0/noMkPhok2VbXTE63W+22W4Fo56iJqZGdQgcnqfse4GPTPy/frpUARDnalMXE6aff3uuo2+rNQiM1RG8re90g/hHp+uulSeDotJe7RZA9Y/C3odWC9lYHE6bJLF3x1OT2x305aAla6UAqw6hk6BIKl4ukOrepPf1H00CQEeYpBDjtkH9ex0N5QI3QSzp1EnAx8/XRgBVtkGFQnlCYWQ4I740jssyVA4gqo62elczrK0ZAwWzoVMsXVjKjmmy55uOtt8nmzPWypUsOtShJP/AHf+vmNcjFVKYkDVK4ucZJ++y5ib7NFXw1LOA0ZRutsDrAJGO35/r21zRWi/3os76hhZNdyVE1VFNKQkeC6s6jGSe7Nn6/lnV1F+UybD8kxxBddZ5d4VEZiFUyr6qG6uoYHrjHYD/XWgYyDc6qwVXEXFk9odyEUpqk8hHZuoL5uG6c+g7flqxuLIAEiUtOruFsEG4IJOnolJYjv0nOD/AK62Cu0+VDNe6LLdYYjG5k6g56Rj4nVjnicvVHMfMU7ivzTQx0yyHyUbrCn0BI7/AK+mlY4OdJTuxJyho0TYVUZdlyAA2Cv1+Wm8TdVuPMqWQ47Me/y1adJKVpIEJBLY7ep+Pz0ROqbZNz1An0OhE6KuoTEFSkSkmhomSNfMYjLgKSD9Mn46BbOi9JTaW6haTXwyxTANnJY9sevqNVmQLrORuU+tFI1RJKwAZx7qjHocD4f9euo3oNU7AbwntVQeYyRrGI5cElcAdOO+dNMGCo6naALLFNTHrnToGAe59MfPU3sqsuyUacdYLIWc+v1GpJTBkD1W32SytMpldOhf8I+J+urmOVjMPN1sa2OMEHo/XRD9Vc2hbqEo2RM56f3nR3smdRvEKvuVcN+zHp8dQuEwFPBaLBXFlQEHyxgabMEooC1koWNScdGPjnQNS6IobEJvWWr2enllRAGAOMn00HxEoOoxosDC6GSR3AK9IYA/H8v36TxBNkKbTvYLYqe2JPGHCrn44+B1aH20TignQsqgfgU9u3bULwSoaN7oYsECuZRDEJSMdQXvj/oDTBwSHDg3IumlVYZ3IMUNsdCpVlmQ5J/MfDGe2NCehS+ANwCuM8m7VqqG2tVUEyRQpEyOBEvQkJH4VOQwPb1JJPpkDtrkcTw5NMuBNlW6mWw77/yuLWmjrLjsfZtLVUT9Bp1w4kLdK98Nj0De9nHbA9flrl0qRNMDaFjL+QSNVgrjaaqkZUf9tDHhS47+YDg9QGMKO+Poe3y1Z7sWkhZ3TmundltFVXeXDB1r1noZhkszfIH1J741fQoOIyhVsBNwpD7K2xHT22qWuSRlkkDTRdukQIQpLZGce5jA9Rn1wddOmMrdL6rqYehEytts/sAoa2qiSlSUu4iETJ2RZGZQhOM+6w7dvT00aWIA5SbraKMEmNFhNw2sXB6dKSTcVjmkm/bVTUb+VKO5AYDI6QcMCCO4HqM6pq84BAIHUKurTvDTJP3C0Lce37fS0VFVV++Ku2VM7FxOsCoXwM91IxglE+I+IyO+sGIYxoAeXT99lPCdNnCfvvuuTbj2+s9TLUU1wo4LoJQ7exNI4qywDpJNCepiOonLABssQp+XJfTDyYNx0+/z+QVVRhZzCwPyP7eo+ZUKuY+g7ohljohb5moqcyjqyJJUDI7AHuoPQPdYBlxgjtk+R4sSKpJEH7+RXIxZjKP2XH0yS5GC5U9QI9B8v5a5eljcLIDNzqupcd1FwpIt511uq1paiKgjcP1KGXEykBervgkAHAOQT+eutw3yvkxp9/qmpm5LRMD8vvutu3bcKS37ksSVErVphkmLJAQvmnqChR6jBKgZ9CD8vS3EYhoqgi8D7/daahIIDrX/ACif2W77f6iLjuy8xVFZdpULUMEBY+0FB2EBf1hiXsrZwD1vknpOulhmloLyJcb9NdT2HTtYaqM53Eu0HS+mw6xqep1sFJDY8N2vFvo/vi6LIVgeeWKNVMU8UoJZEGQCUOcv1AHv0jvjXosNSJZLnT+X+PqVsw+beP7X+M9dguuHbVBcqGmqY5qOsmSLMdXT5TyAV74KgdR7EfzA+PefSY8Qb/eytZQG2v3r1WLpdkpQzWyK1XW70UaKG8mVvOjIDD3ZFb1PvDPf4DOdVswbM3LYhVmk6JB+ff6rI3LYt9uLGpmudA6lw/RFTtEH7EZbue+GIx9frq2pgc3mcT8v0U8GqdYA7T/dPLNs+ms80i01A8MvRGrftupBgZGB64GTgegOrqdJrRygBM2jGmv3Zbi1NIEGVOCBj66uc4BO5p3SZ6B5oHjPYMpXt8M6jmiCmDCBdaTHV3BAtHVzUsUgUqpGWaRASA3VgAHtg9vr8dZg8xB1VJcQYP3+SzVvqfbSR0FT/LVtM3gqNM2WQkidSMA9s98fDTv7pssJSQM2O2Tn4j102VQtg3QpYDGjuRkKCe+o6YVZaQ4brRa6UrTXCnCRiL2dpFwx/Hgg9sfQ/wAdZXOM3SkgS0WT/LZaJUBRURweo95D6gjH/Kf11ZN4OyE7ffotoalds4X9flq5ojVPknVC9nk7kqc/HRIjRAiNUkwP2yGB+OpkR1uQkGnfP4fy1A0pXMkwFXs7+uCTnUIKbLAlW9nYY7H5Z0IKj2DoreS3ftpiTCA7qxhYAAgHvnVGYapW0iRCbSxMASA2PkBnTkyLI7zstLr5bhRqDTPNFT9R6jMFzj+Y9DrFXLgOgVMGeqj/AH1fPFyeFGJX3XdAcOO59MYGO3x+uvOVwSJjT76rPU1IAv8Aeiw1tq5J6gSI8kUgjVZCrAFh8QM+np66Wi8lxJ/ZVadj9/VdGoaK6ys71YqmmPSyHzQytEfkwzn9NdTD0DqIn1VjiZkrp1kp1g/YGCqp1znpePIb6574/hrsYYHorCLLaBGyqWYD49tWPd0VrBuVjhVhixVOkAdu/r66rbVJunkGUaJi6dRUfu9dWEXgIt0ugzE9RXvjHrqsEg2UDSDP36pnLI2XGWBwcarLiAowXusTXNKWjHWAD2x/ro1CZmbKoHpumkNR+07ZGD6ZzjVYq5gltKfTv5lO0Rcr1np6gPno1HtiDqiTC4/ebWRUOsMlTK6g5JOAPn39AuuJXpRp9/fRUPpkGBqtEMzUFVCZFikiDAyKigHo6hkd/qFPf5fXWRlTK4T8fvsqKjQJBVXK4moV2dBEQf2cncYHf1A9c/XVT6xcJKsyiZWtvUZWNlkKrjIxjC/nqrxbyTZUOBygBZWhmikkPnt5XT+DucjPpj941ookCxsmZrIWxw1FQlLdpmqTDLCBIjKwZJjgYz8Ph2+PfWjNyZgfT6Ji4zJWdqaipqYjQK/tFRGyvI6kqIsjII+vfIH/AEdThmMTYWVpcctvvujx3D2OGDDPPHBKYnf4qT2QN27YBH7xqw1riDO3xSAFoknRZWrb2CuRJ6yKRZEMgY4VUK4zkD5jsPrnVheKb4n7/uUwpuJBO6PSbgjjM8cqqelxllbOcqCO3r8fz9dWUsWAOyI1gLKyX+2COaQzAKgy3UMZ+gz8dWHHgNJTubOiDNd446aGqjiZom9VJ7qPgTj56sqYiItKqAtKlrbuUrRJ5qT2qpMMkhKooB6e+MfqQdYBjl7SnWZBEFYq93i2XFPMjpKmlSIuRIUJbHqAxx6g/v04xYgrNUa1wkCIWT23uCxWM1R9iudQzBRnoOQe+c/oRouxYPlVuFDG+afkncN82Y90r7lNS3h2kZTEmO0a9I9QfXJBP7tQY0RIAS+FSzOmVUl52S1TWVAhuhd2QgFMYwMN+WT/AC07caJmEHUqM5pPyS4Lxx+9zklxcDEsGBG0ZOX6j3x6DsNO3HDpdOKFEvubLZ4d47JpgsEUtcnfABhwNT32dlo/laA/ROf7b7LAGaypDntgxEd9IMZuQpmpdUld67TZv2k0qJ8ynb8/XTjFEDRQmnMk3Tpt5bIUsHuMiDvgmP8Afoe+jQBIPD/qhX/tpsYKri69St6YjJz+miMWBoEWilE5kSDeGyZUMjXYRDJ7MProjGC0hT+UbhybVe7tkzpJTLdisnYf3RIPz9e3bTe+73hK/wAIWDgtRW47RS5BjcoEo1QuQgL5PbBCntnuf0GgMUJsqTTpz5ltkO+NhxslItyqBIRnvD6/X17aAx3b8leH0tnfRKHIPHHnR053DCKhvRSBn+f8NIOJsTkUv6k//thsfqEf3tICQWA9nfuBjP8AMasGNHT8kXeHeXfmsLfdx7YuFC1LQ35qSoMgZW8h8lVGcY+p7fTU97bPMPyVFVjS2GuglahvjeGzq2wpRQ7npYTKpWYLTyeY+OxRVx6nuO/YdyTqivjWubAn5ffxS1Aws8wH36Lk3Hdw2jbrdX2bdE1LbooJGWldFLMYXJkVgQMZUuVz8lXWbD1wxuR1/gsOHFMEgmP73TDddy2neLRd5orqk1zilf2aOnBViAwAZlIAMbKuex6gSO2mNZjxBF+6qxAplpv6R+3RbHxJSWW1xVW5dxXe20s5hEdJRSEhyAPVjjC9Xw+hydaKdRrBM8xQ4fQB/mPsPv77qQkE+xp7PTUNduWxM6qgneNygaUDLEHHzJ/frW7FUwObQdl2G0mlpEj5rkO5a7blqqVq6Gu2/faLq8qQMwLBScBhkHAXsPyJydZKuKaILVjxFFgMmHD4fBVRwWK7WFzFfKbbSKvdTdmjkK4I9yIEhsAnucDvgA9tJW8E+aPkb/lCvplzmSwkfEf3XP8Ac234/OSd95y1U00YnZGq4SyxkkeXIzDJyD6KAScnOufiBTuJv8f7z8SqzhqkXdPymP0+AWj0+06LbyyDdNTbFpZqUPE9vqqcSk+nQoIIDe8ASenGARkEYqaadIZXHNPr9/CFko4PKS88vy+/rZRP8SKUVRcLZXQ1lZUVcUs0IiqHLypAyo69Ryyj3i+Ok98nsANeU42QSMoP3t8Fj4i0RmmY+emsd/z7KKmFHmK5Bz+E/EflrzxO65TQCCQEaCrqIjJHTTSRiZfLkVWwHX5EfHVhLgJ6JC6SY31WRp3aWqgknpZLiqxMzRsOxQe78PUAsOw9fTV1EPJ0lDxBI6D7/wAqWnBtLW3uWVb0ldc62OJPIAdlCU64VveYdPuZChAQE7/H09XwWmSIcL9/v7Gi20OfzHTQdvl9OuqnBatqW63LbEtlBC9InuvT1WVjyACsyspHQ4Kg4VTnAb4En1ocJsAPv812KeCaACBP399Vs9LQNBb1SrrqWjjjVkRfbDKUPUTlwelMMT6jI+gzq1haACSPrb5/stTKOo/Mj7+qz0FkpmNBVy1EMEETEM5mAV2Y4zkHJ7BvXGSew+WzxWEg9EGYYwCQthmqrNCZKeKqhkZQucOAO/1zonFNKu8AAW1Q4KOkqJZT5qqpIAOfXsPQ/mdWiq2JGirNA5oCu9upBUpD7bSxyNnpTzB1EYzkDP0OlOIpki90jsIdAsgtk7AAg5Pr89O2o0XlHwSBdc/vu2fKnRqYlGVsAFAwwSM/pk6qeW2IKzVcOQZRLDYJj5UjIoJBbpI7sufxfro0y0KunQMytjnsUpAwMnOAP0zq7MD6rQKLokpC2ryFHmKVP+In4fnpXVAAkGHMrSdyXK3wUtZRwVlE9dhlMTPgr2x9PnrFWxrNAUtSmbxdccqLoj0VVNJG1TK8QiZgThSAMZ+A9Dj8/prIK26x1A0tghZGh3lZInlerpamlV4TT9IBcdI/CfX1yCT+erG42DIbH3omZl36brudtpzcKaCtiR/Z5UV0yO5BHy/hrqtJPMQtTAHbWWQa1EZPluvz7acOj1UdShNpbY6qXWNm+IGPXUcbaKeFNwhU1CZ06zH0kjOPiula6PVRtKRbdENrZCxKMqjuTjTZxElN4V7Jt7EhXzV6WTvkj00ucapBTjRDFArIGRcg9h29dAPE3TeHIkBYO6RCCLzo1DgNhgPX5Z1Q6pOiqq0iGk9E3uHnwULyRqnUPUjB6M/DUc87JXMgTC57uupd7bJb6lFhqB73WFwenGR9BrLi6kiHHRUuECIhcKvtXAtBMTIwiZQi9K/DuMnH5/rj4a4eLcYmFie4BYvY6UU5rY6mNC46QS/p0f8ACPgT8f00+BcMv39/NZBTBd92XbbZte2pFBNQ1T01RGWPQG6Uf5ggHsMYPbXZbRaIdELd4MCxW+WuipKfrla40jsTjCydsfLuSdbKeUWVzaZPwWUrFojAeiqpST2IEgzpqjwQrgzc/otKlenjMiGeLPcD5EEjv9PU6z5/msrzYxqs1SVFB5KgVUGST2BJyP3avD2q1lhr9UOR6RpURZusZ7kI3b+Gg1/NKgAN5WKrZYlmRULuXGMhW/01W4iYKre4DVNaxIOumJZgC46j5ben07flpKj9gnBEgLX4nAd5GD9JOfwnWcGLKi030Rq2qEdMDTF3lJAPu+h/X5aeo8uEBMYAkBajUQRvN5M7yVDhzIzEenxPyGe38dYS5oMnZV5XEQue1lLHV1JjRGkjOcg+729cdXrn8tc8sBEFVVGkrn1aBRPJA5cKMhVc9RUEdiMfmRrA8ahUOACeQ27ogR6kNHG69QY46WwM+vz+mtNRmXVI1hcL7pFNRSLHDM0bKje8pPx+A/TRbSIGUjuka0EDus9b6kxzC11kkCU8sweRmXGQADjI9PQA/l9dWsePK42ElWAGfW33+SyVjqfJepnjpZzA7mRTkABfQDJ9ewz8u+tNAmJIj+6uY0TIvP6Id6qaiOSqnoY1hDr0VAB/vxj4qPiPXOs9UmTsEa8i7QrrWRpbq1UEVZWSSIkc5kLNIpUEKM+hGTn9c6dz+TIwXJP36AKum4Xe4yQB/gfFYKKaWllMDhFAUgqT+FwME/n3H79Z85E/RKI++ycNdpKxko2CEIwYFEJZiB6H9f5ac1C4+ieZELJSXqeShSJXgiVlPf3ursc+vz05xDoElNnABDVucdbLAA0N2oIu/YCZu3/XfWQlh1P0K6rXubvb1To7guhEim/wMp7kee2CfXQmn1+n6K9uKq7n1ujw7jusYcpf6aHPw9oZc/w0XOpxr9EfeqomHfVWS+XBQCL/AEwbs3+8sD9D6aBLCNfoUjK1QA81/VOF3BdC7dO4YPTJIqz30/JP9irBVqkWd9R+6NFuG7hy8e4acOwCk+1kdvhpszIk/kU4xFWbHbqE5+/ryW8w7ggZwPhXn93rpQ+nP9ioK1YjzfUK73q7GML9/wALL1Yw1ZnH5ZOiHMiAl8WrHm+v91f73u7sQb/AQRjq9sz2/f8AloFzNZ+hQNWqfxR8f7oXtt0EhdL5GZOwJatHYfq2oHU4/wAoF1edfr/dOxeL1lT/AGgpSQuB/tgGPp+L6DUNWmDE/fyUFWuSId9/NWFZeQCJL9Svn/8Anl9P/i1Y19MwZ/NPNYGC76j904WurpQ3m3iFu5z/AOkVBz+/Vni0htr6o5qs+b6hAaS5ZZhd6EnHfNcpJX8gdQvp6gx80GseNT9UyqUuEx9+vtwLKPw1YywPzOdL4rSdZ+BSeG+J39VjnsFSrZNTah9PaUwf46drmTBd+f7KirhXnQfULO0ElZRYjeS11qgYHm12OkfIEMNTxGCwIj0VradQWIn4/wB1sEdwjdBJU0tliQdQBFeSQfmPf0hqDXMPktIY52rPr/dNkhoq+dZ6yagmpg2RFFcPLWbB7EhmJxnPx7/LVTnUyZLvp+iHhA3P5/un4NhlnDLb6CRY1KEi4qASSMYy3cDpPftq04qXSCPkrDh6cxlt6/eiyAi230tmht4Y/A3GP1/fqe97SPqj7rTJktPzCSg26Zik1BbkHwIuaen17/TROJncfI/sgaFM+ZpHxH7p9G20TlW9iQepBrgw/wDm0TiImD9P7K9uGpGx/wD7f3V3Ox3ZDI1Ew9QRKWGc+vY6Y4k6qe70C6+nqh1L7FCkkU1RKo6wqu3Vn889j+Z1W+uYkBWOw9DQmVrFTUbcedZ4qWnqJSuAH6gI++Ookn3vln4n6DWYVHF1lnfTojS/zWn3iLbMk0UoaWukUjy5FmB9nlPxXrOD2GD275/dU4g3ET9+qqc1h1n4XXEOUpFuu3qu1Udvt0LRE1RanjypEXmE9y5KN0soOOofDtnXK4k1zmkTIWKsGZMgEH4/S6iHJIxVOsIqA9OMd/z15wNXGgRH39+qIgBikdmjJXsO/r30oB0+/v8AylFEGZ2We2tfIbBdDXVFpobxB5MkJhqPRSw7Op79LKRkH8/z1oo1XNktRo1Ghwc8SPkp0cSjb1x29DcZa00VCpJo0mjUED1fqxnOX6vjgjGvWYBssDr+n5ffdd/BeE5sz9nVSGhu+2HgAEtqVGUdWO2f1+Hprp+8O0JXRY2jAiEj7w22hUNXULqcDp7Y/Ptoe8OmQSnNOlaYKyH35YQqqau3dA7qC/b92rPenExN0zWU8o0hMXve1pJc+fQtIyeqlvTPocarbiXpPDo6GJSIb/tVY38qqpkjjOcdTjB+Y/8ADTtxLxr+SIZSvf8ANFa97YkZap6mkDg9QZncEH5/z0rsWQ2ED4Rgk/VP4N0WieJXgukJQEqM1BUjHb0JB1DiXG6Zj6ZFj9UtrzbZHjleuhkbuATUk9j/AN7U97dEzdDwWG5P1/ulG5UJIYVqhunoBWrPp8h72g3GGdbKCk2JH5/3RVukSqojrZSAe3+1H19PnphjCN1BSAuT9UCoroqgAS19YASThatgO/66Hvc3N0SALAn5rX5LDtud2d43kkPxapJ1DiRGyxnBMJJJ+qsLBtxB0Is6r64FQe/6acY0AjROeHU41KT/AGb23gkwzE/WfOk98tsg7hlPWT81sdFVmhhiipblcI4EXCp55wB8hpvfiTCvbh8rcrSYRnudS8gc3W5dQx+GdgMY1BjDEqClJ1MlJe51DxNCbncGB7ZEhyPyOndjj1TimRYEpkJ2QuIq+4xhvXEnc4+GdRuNAsVUaDW7lGe5zGMxGvrCvzMhzojHk6QgaX/Ipl7RIUKrX1PT64J7A4+mp/EHE3CTwehKv7Sy9Q9ulVT6goGx+/RPEjoEPdrarGVTRnM71x6vn0j+WlbxIjVVOwYI1SkcOZmNapYucExL/DTt4q7QFRuBBOt1iblT+bHJNLVo5ABI8kfD0zjSP4kd1U7BdSuN7rp3eqiijlEtHNGxVgAAzAdRxj64/edYqmIzGTosNfDAHKNPspjtF5GppqaKoSB+s9Q6QfXHcn5diO3p+ur24nIICy4WmHT69F2ihlm9lREukYjyMq57dXz9e3r/AE1YeJtK6owsNsVlhV1ixp03AN0/hCSkd/39tWfxMba+qu91Kv7bXFmjaudU9e0xwTnv8f46J4iDdwQ92qA6plOjSv3rUfHqWc9xqe/jYJThCd0IRSovRFVRxjBH96cD8vlqw8RB2Q9yeBAP10+qGwqFRitREx+fnElvppRjmgQGqPwzv6kMx1HukFDntgynIH7tMMa2Lj6JXYSobbJm8U3SzMqOo74V/wAR/dpvfGnQXS+7VAYOiQfMDKPZl7j59h+fbUOMB2S+6OECEOSXoEoaJGA91gMH+n5emmdjxEAIOw7gZOoWFujx+R0ogT/i6Rkn8saz1sWCdCg6k5q0GrruppGngcOTkEeoOfTJ9NZBibWEkrI4RcrSrwlPVR07Rl/aVdo36u2Qe4z/AB1SxzMwOizVKQIWw3NOq1TFY0RGCIo7fT4Z7emratSRGifwIZI0WHq7pJDFBT08iiPoHUCo7H46Dq5J7Ks08oAWNnuElW0MczKjAgda/I9jn9CdK0ZvMdlXmBIXVrWtGtvgIVhmNS34e/7z+Q/TXS99aLLZSoENCKRCKoBIpSGiIYBc5GRj0OPidI/EsJPdO6kcwlantigpRLdkkaSSRJTDFhe6L8x9Tgfu0mHrMbTl2pWWjQBeR0VXii82tiUP0TmWA+aF6cAlhgr8T8fl/LS1arSdfuFKmHdtrb8/16LH26mpaaKD2uZY1kiMmcdzlz8cfIDTtfTA5tbff3qgKRH1/NImt1EK+np4axFo3Rn6s5MeMZGfrkfx0gNMuM6D7hJVoukAan7KxRupKksRn0AxrhNrkmVvLuqTHdV6sNj1Pb66YVDsmDhMlKW6HsQCwJ+B9ToOqO2SgCISxdQRj38fDA9Pz0PGOqBIGgRFuYHcFmPy07a51TEAx0RBdsqAY8H1+Wn8burC8dEsXIAk5Zjn0z20njlKDJtqjC54Vh5nxwAdBtS99U7SIVLdVLZ62UDPoe2nNbYpRrCL96BskN8/jjGh47tFHgCQrLcyWOGYHv8AH4fu0zqpSMjbVL+8+4PmfQaY1yPRORzKluhZinX3xnuP09dAVpOsJwbSri6lPdLqSPkNMa3QotN7q4ugGR5gA/I6Bryqh0KuLsrBT5gUn4kaBrEaJ3EEIn3ngL7ydJ750W1r6oF8RKX95MPQjOP+s6hxEmSpHNCItycjCuhPx7+nf66nj9EwCFDcpctI7Rgk9/pj56jaoF5SmfNCP96liSDH0fAjRFcgySrGKvvVveHcDPbv/I6tbW6pASJ7IgucmAACT6g57fv0DXlFzoMq63ORQAG6CfmdQ173UdmFgrNcH6ivUwAGPX1Oga0ptJHRAF2IIVTIX75wMtkaXxSFA+RZYm4XFe0gRDPnIU46i3r3+A/mc6qfiCfKUTGqxLFHC0hRyX60llZsk9R94En/ADE49NZtRGiRrTF7/cqK9xt0tDJVW+Yq1RTu8bEHIJUkfx15iqyCQViqUy0EbrCIzBJABgAd8nVRcAJKw0zYyntIplKhnWMMQCxGfX44+Or2NBIBFlax2kKZG0bzB9y0UFIfKpoEEKp04/CAOojv6+vc9s69fh8QHCNIXRoQGQ1bZ97KVJ6wAe4yNaRWOyuFQXS1uZIB6we+iK/RMwghKFy+HXH8wDompGqIcALqvvNCvZlx+fpovqKB0CdArC4gAqHXqHoc6DqpmyJuCBqqa4A9XvKV+p0xqj4oPM2hL9vBHwC5z2OMnVZq9EriJ0sqeu6my2B29T2xqxtW2UoF20IYrQMZCAfnpBXugIBslCt6mYjqBHyJGnc9twUWiST0ShcJUUKkjxpjAAY9tKXgm6jifRE+85B1KJpuwx6n+eiHjWEomUP2+THSZpcfLr7emoXCYKBdAuqS4SgqUlctjAOfT8tCWzdWeIbE3KprhO5JaplDZJyCf6aAINygXu+ISlulTEcLWVHf/nP+unzCJAQDyDqrtdas4X2uoA9cBsaSGnVWl5kd1YXOsHQBX1R/Jz/PTBrbiFW+q/cpQvFYo9yqk+Weo+v10sCUG1NwUQ7guTABKt0GO3/WdMQJmLKzx3RASfv64uAwqpAw+THJ+v10crSj4joMoE14rqmNo3qmAb45xqotaDBVZrOIsgLc66FWRKycLnOGlJwdTKxAF40KWbtWkEGsqe3c+/6nSmm3oi574sSmDSRzL0zNVOAxYKJMAN9O3b104aBdVuYCZJshRLSQt1rTOjeh/aHuNMXKvwWh03WQiq6VfWkZsdu8rY0CRrAVoyzcW9U5S9SR46YX6QMAec2P5/TQaLK3xpsnibpnUJmkiIHfvK3+uo2ofwwrBiNzt3TyPe9RHgm2Up/75ydMXPPLKIxwnyo39vajCYtsDfP3zpS5++6uOPt5fqlf29JDB7Wqr2wQ/rpvEfOt1PfxplSv7fxKc/dcvoQT1/DSGq+TpKs9+aNkob+hC5FBKO//ABaYvcdErce0GYQf7eRE/wC4OSfkx9P3aGdwGqqGObuEKPfcPSA1E4cfEOTnVbqryLRZRuMbNwgS75p5kZJKGZlPb3j66DXvgWCr9/aRAC16su9BUFituBUn0Mpwf66gc+ZtZU1HsI0+q1apjhqaqOoiSmpI1wfL98gkfPt+WmzScxMn0WF9NpIIsPitka8CSNIpBQrEo90BWOP3j+Gmc4m0rWasi4ED76Ko7lbR0CemtcuFwS0Hcn88as8Rw0NiqgGEgPATwVm3CQZKG0Kfn5f/AIagrO2VoZS2ATmC7WYe4RbadA3ulWPp88Y9fpqOxLtSforQWDQJ01zsknutUUDD5Z9f01WcRInf0THIbEW9VZqu19RKTW/p/wA+D/LTmsIglTKJkKhPaZFys9IT9HGmGISBrTohlrPIuBNRsfT8YzqOrkiUxoNPqm5obSclVpwD3H7Qajq3VUuwzIC4K1Y6pgkZPfJbBx9fl664MyTdYQ4zCuayGMN1OAwPxHYf+Gg2oMsFWUyDYokVUWieTz/3Edh9NTxRo5WC4JBRFqi3ZHZx6sAx/npfFAElLPLBRDXFGDuXMZyD64/MacPRYTN1b2spgmQL2B6cnH7z20wqSICa4vKKayQdIBdXb/myB/1/DSmpN1DVdaVda5znrl6D1EZB9fy1A4ItfaTa/wCiLFNIclZZnOPzHp8dQVAiGm8JYrC6NlvLbGfUHPcaHifRR1UESrmpdcEsc9+3SNTOEhqGQdv1VGpk8vIl6TnHYafN3Vuebj6Ia1cgMh6ijY7Er2P6/HSmp11TTcwngqpCiu58sn0HpnTZxoEQ2RJSRXBc5mBI7AAHTCFUDHmVNVsD+LJwMlWz+mhIFig87dFSVnV36kjb1PU2CR+WgHgRGqg6I61pynvg57DDd21BVumJhI9uI8wtIowcYI9NAOkQESTBhL9tLEYwwxn4d+389OXjdExp0VxVjDHA7jsCACP11PFt3SsymeiW9aqoC7RhM9znB0wrWEJhEJQqgCGwue2P+s6tfVtCaBPZXNR1HBdBnv3PppDURLZcIKG1cgR8OcfHv2H1P/hoiqRcCyhI6rG1FXLKUZZFIGB1qx6sfp+f66zVXSZ1ARbAICxMtY1OXZKhql1TI6VPu9/nk4yMjVBqRpsoCFlZqhnjgmDxKWQqMP8AQMD2/L11c+qCA5Fplt9Fx/eiIboKyL0qYUZ8f8QGCf4DXI4gBmBFrLHiHRcaFaEPx1EYCg9Of11jMBsrA03IGhWSsMqU9yt8shAjWeN/XGAGB9f01dhn5X8yjNYOikfRxJSy1FRAvls0pZwFA6gQMjA9SMnv+evQNLRzBdRrYWZ+8cdMjShYyezE4GrnVYGZxVjRJsrtcJA7qZmGO5B7dvnnUNVp1KIJ+CIax1CnzOsD6en0OrW1BdBw3nVKNxlySpGcfI40HVepSuMRCULg/RklXIPy7frpRV2CsdBHdJe4OQw6kJxjKnRzmRKVzwLHVWFeVYs7jpB7ZGc/lpBUaNEhOpN/v6q4r8krkfU+vf8A6Oia24UhX+8CuCsnVn5j+WnbiANSl3kK63LHbsGzk5bJ/LQFXronmPVLFylAGcsPT176BqoAFJNxJALAkY9M/HTGrsdVW514VxcD2/8AVqMZHfJ0W1RqpmBSjclOeoS5xgY/h31A8wU7iJhWFwQRkidyB64OdQ1BIaELE66K63MkfjbP0x3+ugKp0TskWSVuPvZVyzE/E/xOmFYyoDJ1S3uTlgEdh2740zqu6DySYGySbm6k5YkgEjt39NTPAlK597KvvHIHVL29D29dJ4k6pi6SkG5sMjJKd++n8UlVgqjdGGSJQRn5fPQdXtZMDElqD96Ov4u4yPjgjOo6pN0rDuifeZPvEhj8e49dBtXqjNsxSvvFj6MB82zqwVjPZDNJACt95SFeoDIHbOqnVT11RJvIVLcuoyYkAI+Xw0XVdEAdVRunfCMjH0zkaGe+qhqTok/ekmMsiFfzHbTsqX1Uz2iEQ3M9Ks3ujt3z/DQ8WZG6afokPdVUJ1FkGR+umdWvATNeI11VNcwAch37dsf/AH0grwiTNyg/eo6SxDj6AZxp2OBSZxKt96DHUeon8jnRc+8aqAndX+8wqlnjkXHr1aTOYVYd1VC5IAcrIRjv640XVWmxCgeNEM3aHuvUQ3r6E6UVb3TmoFb7ziJHvH5n3cabxIuVUQ0a6+ir7xh6Sxcfr20DUAEotcFYXKJgckkn5EaY15TlwSPvCAdmkUD6nAH0/PSmsZhVsFo6pLV8OceaCc4HfTeKD8FHEAhUa2FgAHBHpnOgaqaQYAQzWRAD9ooz8c6PiglKdOVWasQNkugOe3fOoKk3KUXKpamNgWEg/XtjTF4iEwLTdYLc97qLXYLrX0TolbFGDH1qCOrqHqPj2ydc3imNNOjmabyraLZcQQuf7a5Zpa2For9CKGVf/XR945PzXOQfyyNYsPx5pE1FW9toA+/8rXl3VdXbrBtT4yMdBB/P17a5bMWZku+iJJLrAFOId01ypgx2xhnOQzYP8dWtxZAIJv6ItEbfVEbdNWyswpLcyA/+0cZH7v66jsYS4wQUzSPKltvFVDdVLREZOeiqwSfzI0BjiZJ/VRzWhpAQv7Y1je+aC3NGB6CYnHz+Gi3iBOpH1+apc4R2RhvRSgc0YV8DqxOvb6dxkaZvELR1TtLTcBO494hUzUUlQkg7gpKrdQ+WO2PTRGOvpJRzp2N5wM/lNRVKIcAEuuVOOwxnTN4jBhWN7K77wp40kVKKqncdlHWg6hj/ADZHx+egccNtUpcItqEun3lQtGBNT10MmMt7gIU/IEHJ+WmbxC3Mqi5p8qdDd9rkfoQVajHoYSf3d9BuPbrCYubmEfqqj3fbnBlZK2Efh6TEWx+oP66I4gybi/wVromxhUd02snImqCuMAeQ37z207sbT+CLnwInTsntNuC2zx9cNUAowG6wV/mNOMcwDmMJqQzCQnMd4pC7t7dCwY4BV/UfAjOg3Fs+CbKSZKcG60nRkVtOp7gEsCfXVjcS2IzJC0i6ELxBC/XLVUYQL2HUCD/0dT3ll76JSxwMlXW/WuUyH2ulQ4Vg3UO4/IfDUGKbBcTZQDeEWnulLUM70k1NMmMAK+er9+oyu29wma7XcJx7TlehVDMO+VHYH6D9dWGpaQg+NAENayQ9JeIKD7w8xh1D8sd9AVCfKUc3UIy1jlmaOKUAAnv6N+enbUMyULRIGicotVJ5kfsNVLMo80oqlisYGSx7dlA75+vrp21IsVY1peYaJ/xf5C6EayMxECGqVO+QWx2+mRk6jy2ZSu5ohDWtpFcQ9cka/Nz2UfzOiXgiSo54HKCryVAYOGRekfhGB74+fr6/l6aqNaAYRMlYaqgWYJFUIkR6WyQxwG7YBx8vr9dISCYVkg6fJN6gyU1MfZ8NSrnqjBJ8rI/wk/4c9/ppXgNEN0VAlvoFq13jeutUdQEzPT4Oc/AnuPyGRrFUGZt1KrS5lrlaK6+XVMzqRkY+h1ne20BcwHnObdIXrSTp/Fg/Xt6aVpAv9+qRjXTddr2rdWrKAROJBVwnpft/eL8CPie3r9QddfD4gFsArpYd2ZsbhZzzVdZVeRH6sg5X3f5/I6vdUJsFpETI+wrPIBE0cpUJkqucnsBj/wAdDOIjdWNFjKcJKUjLq7pLgAEnPYaYOAEDdRxJuNk2F0aSrFOoV4wCGYMPcbHxHy/rqqjiTMDRCoGwJsU7FT0uUDyspXGcjA/PtrUauxSOmbnVCmrZYovM6/eGB7o9Bkd+/wAdU1K0OEFBjRkvqh1FzmCylkESAYV1YnqPr39Menp30j6hBmUbG6x1Pc5zJlWVo1OO7flnStrGLpbAQsytx6oy4UNIBggDPfJyNXU69uqDInRY6i3DBW1FRTL5mVXOCnSox6/6apo4oueRBuq87cuUlZb2o5GHywx6N2Gfz1pNSdETpHREkqFeMTOGV/wgHJHr/wBemh4gJ1UIDgZQmrFifywZVGACcn/r6abPugIiyulbh+lnb9c9j8tQEosdDrqz1PuoTLKg7nPr1DQzdUXkFDauiQ9PWDlcjJxkfT5/DQzjVKICuK9HAAdzJ8fd7H/r+mj4gn0TZhoAqNWvd/OP4u4PYD/w0wqCJQIBAjVUaiXrDK46O5yT2/8ADQ8aUA+STskrWMwXssjeg79+39dKahKIdEJIqpAMMwDdRGA3fRc8dUSIBlW9rcrjqAA7EdXY6HiiLJHCBfVWFWB0iSJ0dsjJGcj6dxp/FKjIGiS9ZMvZgqj1HqTj4fHSipO6UzEEXQ3rJH6fcLZx8xgfDvqeLdQmYslm4SYUdchQnKhRgaPikiDqmkxlCs9czKY/eI9B3OP36jnpXuJtskmumHTlSQe/ZfT+GdA1QDCVzuX+yu1e6Bi0pDE9lxoZ5TkkJJq6kd1kLIfkfT92mbUsg0uMz9/ZVva5ApKvNF8feHc/L6anjAamyYm1pSGrpSCwkkJz6ken7tMKsIg81yrpcXYMQXYk57jtn/Ttpc++6Vzp0ukJdHyGDF+5B+GPy0xePKAgXbuSfvIkL1jLkdvePvD56U1TMBAuGh/yqNycquSAxB90/P8Ar+eoaqBd2SGucrL2KqSckYxn56IrXSh03CQLhOyqRCjAd+oHAA/fotrSNVBpEJIuJI7LEQcnscn66Q1CTqoKgIkpP3iPdVgox2+ffTBwBKBIKubgAisYgPd9Wzkn/r+eg6tF0GOOWTr3SRXAsV8kBzqGvN/vZLImN0Nq4dHT5Z7nvgDA/TRNUbpnwBACAa1QQEQemSB3yfhn/wANMHlCQLBXSviV8Dr6sn4+v6aXxtiq26wPv9lY1/4pF8wH0z9f+u2la+2VWEgGZuubb+vcrpHYzEWjdVmeQN3HqPTXn+L4pzj4ewWqnAB7rjjRKxRo+ox5AwBnHw1zWkarJV8vKt/HsvvmRJIvX8z29ca05m7KxzHSbIgFNkiOT9pk5HYkjTU8uidrRMtRVWMsqGX0OPyz9NQ5SblFweG2CGaanJHSy+g7sRgd/lpXEQq3slpGpQwlOEXEkQGcD3sBj9PpoBzRqrKbTlkKno0byyKpFk/4RjB7fvzq7l2TeCQMyN7M+UYTOFXt2Ix+8jJ1XEIGiTdFVGUxiJ2j9cLjvoANm6gBGiMAUBVg34SeoHLHHw/PQc5okJzE2GiSqsYmAiLh1wrgElT8wMj+OqyQR0lVmR3Q2hyFcrU4HY9h3x8PX89PN7aqttMm+yCUU9LGjq2I7YOP550zpkFHLJvKA1YlOzdUbKVJGC6jP6Z0znXywo0luoQXucbZZup2Px8z07fLUc6bDRMKgF0WK6xgAeZJGSMtkjA9P36rGsqoVL3MSsnHVQzlZIah0XOAzOPd/jp3OGpstHoVRkdVk6KtHc9wAwHV+/VYItKrfJuCnCOFVuqoXHSOx6Tkfv05qA2CdjSArRyxYy9XF1/LABA0+YabpqeYyJ1Tvrkb0quoD0Ck5zoGHG11YQ6URKipSUMlbIkYC56pCM9vh31Gug+bqpTa4eieffNwQlluPfGCTMcDv2yDqzxMvlKtBcdYWQp943y3iu9hvkkTVED08wBB82NvxKc57H44x2Gm8TMNVfRxb6WZzTqIO9j6pjFuC4pLk1cEkZYYBwTj+WrDiN5WN74dpZOhf6vzYyKiIr691X3T9OwH5aIxDpGUq0gTYIMt/rFaZWemkRj268DpUfwz8fjo+8OJMFVuj7+/1QRuCrIUGelRk/EMj3hj49u+iKz7EHRBrgLQPmm4vlxMnUtXBI3SVCnsO49SR3+Oq2vdm7JMx1CHBcHhWriZIjE6FOkS9OAf0+mj4ux/VFsxG3qFjjCzLGsnlLIPQ9eQf4aqIWQYZWamPUx6whJx69l0sCEDhTmlPaSaoo5oqiKZSUXpIY5Vx8tWisWmQnZRc0gytoG5ocBxAoUYLAH/AK7atdjhedVsY1pv+6bNuynSSU+VUAnJBDeox6ev6anvfZK1zc0gpf8Aa+jXCrBWdPcEiQFh+mT+edOcX2TCqAZansG67QsQQPVKwPpglRj9e/z1Z72yIARkE66q6butsjtIaqZPeHu9Jwx+fYY+uiMa3RwSZwTrH36K1XuW3ytTiOryoYBwQQOnOT/IarfimuMgK1z7a6pUu5KWWBlFbSGToZgpViQfgASMaY4hsdFRUfa8IFNfKN6dcVUKOHz0tnuPqRqCuI5kGEZZBhZCC8Uy9nqIgvfARj/M/HU94YeXr2TgGdUWO608SoQV6+4Xpf8AF3+OrGYpsXStpG53+Cc/f9Fl2aqMbeignGP4emo7EsjKQnpUybn9EgXqjwS9wEKYwCW9R+746AxLALqvKZtaEX75gcCOO5qy5z7wA7f9fu07MQ3VNkfFt+32Uo3WAqPMqYHb8OM+v5k+vpp/HEwCjkM8wV1ucMKmRpYHkb0OV90Z+h9dQV2gwTZLlcDni/33RDdKfDAVUI+IzIBkY7ntqv3lkASrGsMSAkC50zrGPaqSM4OSSM/QatbiGySSl8O4yhDa7UpOHqo2wewUg/x0PeGbKOYYgpbXWkYgiVAe+QJAM/louxDYAJULTFldbkEYqgMrHuffB6fpk9vTOlNYTEhQOM6fqhe3HzAjlgSMkH5ad1W6Qg7orTSSIkohRkBA6gcFh+vxz8dQPGpKD9FTTsGPYKD3wp9B+elbUi5TBpAuEI1SMxIfpTGCSDn1+Pz07KohK61gqkaHu4lVWABLAYx+p9NK6o3qgWjrdZOGjr3szXclnoEqFpWYnJMhHUB+WCP3jSuxLM4YTc3A7dVuZgMQcO/FBvI0gE9C7T42/dYv2qSJmAzGpzhz8fn9P003iCAufUMEti90qSd/eBkBUnq9CT9M5zotc0BOCYkf3SpalyAI5I3PqThv/sNHNIsoTohNWKP2Jk6SV/F8WI+v5ajKhCBJBVzVgSDDJ5QH4SckfXRzblO8yLaKy1hcsyj3B2HVkFj+XbRDzvoplGaUJqzMnQoz09yDkYb45x8dAujRBxvEIa1MowMKoH0IwfX8/TVhdBgpWkmwCR7WikgmNpH74x2J/wCvloOdKSzbEXVnq4wGMvXE+cdPTj+Q1WbFVuaJkqzVIbrIDMgXPUwHy+ug5ycNBdCEapB1BVVWI74A6Qf+u+pmMomAIhUKnr90EEEHBA7Afp/XQzSZCRpBOXVIExYDsVU5PSAOnOOxOmNfcouY0kQrGfyiPNB6SfQ/AY9P3aQuOiQkC5H7obTKcFfd+YCnufh9PnpnPsgQBtZX9pIJYqqNjPu9v4HTNqHcq6ICG9RCOmQMQD3IIIznvqp1YbKuqGxITVrhB1hJGCsR8SOpv66XxWg5UuaSCBZAqrvbqQSNNVqpiIU4PUy/IY76pq42m0K4UQVzTclyhuFUtbGRJAy+WgwepwPU4/U+uuLiaoe8kfduq0RDfitXZw6AxsoYjJ/LI7Y+Z1S8GbaLK/SAsrJWU8jtA1T5kmM5bsB8f+vy1U2q6ZKte0Ax1RoZE95w8LEYAZR6n45Px+PbV7KqenTE2CqSrpkZhHNOJiMlVzjP+vf46rqVDuE2thZDhqYGYs0juWJ7sfT4fDQzuAiLLPktBRumFleJXZO+GAAIx8O37tWNxEAwrBSJBARVqY6dsvKZukdvcBI/M6IrmNFd4ZB7o4rQ0sTdQp5SQ3R09/17nRbVsbWCmUT0KybVMrASExTRehK4H659RpfGvCsczfohe0pIQ3s0brk5yQAPqdQ17iEhEnRJBXrAX2QgHPbHv9vmD8DpWvVdSmiS1kKuFiSEVB7lkfqGP1+GkbXM6p5/pF02jucHV5C+Q5UnK9IIP5/PVxxLgQTogNwfkjrXRRqzmmpIx1YH7IZ/TTjFuAVkAbaqoL5QsoMppoGZu48kP7vzyPQ6IrkmHJGlh2Hx+/qjx3u2M03VCAg9G6Bhh+WmpYtxbcpSKesIi1luqo3khoqc9xgOoJzoHEECWxdMWMNwElZaIMont8B9M4T0/XVXvDg66RtKnEZUGaS2hJGe3RqAO2Pho+9uBgCyIpU7mLIkNRaGTqa3osjA9I7Yz+unbidoTCjTva6MWty9LezqpJwe4GO3p20oxQiCETRbHIFYPbAzKY6ZjjJJPbTU8RIvuixgm2vqgtUW330SGjZx+FR8fy0WVjMqFjQCk+1WgBCsMLDOCVAHScfP5503jE+qVwaJDQqkrrfI7qtCvun8Rx736eup7xJ0TOczNDQiedbIwsjUxUjB+Jx8sDUdWtEWUhsSdFTXaCInoKupJIw7evzPbS+IbyPooXRfZWNzYkKz0jIThffYfDsM+mo2tHKPyQD7QY+aP5tWEZacIIyvf9qWAIHzzoir0Nk5D26K0cld0ESdBc4wFlOBo55sNkrXOvI+qdeZUeWvmxOpJySZQSR9PloCpluU/hOIiEjzEHSJIQEGe4mGCNQ19ZGqV1MyLXSh5LMP2LBMAAeaMnv21GVdJUcAdBZDNLBMCFo5sj4dXZfqProuefmkY0QYCIsETYxTVBJ7DvjPbRqVTEqBpO0q5hjWP3aKfOcdXb1+Pw03iHdHwBsEiKA4OKZinpl/X0+miax9PqgKciw+iuY/fOaYhMZzk6QVHaI+GJsEPpnDu7QSCMLnJUALol5+aDg6Yj6JyuVPvRu6DvkBSD3/APvpfFhF7SdQkxTo3ZVAJ7gEj1/TTOxCDDFgLJ1HI7J1MMOCQFII/X0xpPEvqiwEROip552DMyJ2z2KjH8vlp21nDUokuva3wS0q5epVjSFO47MAP17j19dF1czqgDJkN/JIatqXIjkRHZexAw3SM/DtphUcBrdB7jm0+/REFbInmMKdS3p2ZcE/D10BXJIEpswuYVfebszItPgKe4yO5x/130HVyoHQ6C1HarMaU5R4Jw6EsqnLRd8AHt+vbOrDVIIv9/FQOIERZCeplKgiKoUFs5BXI/eNVvrxyouNoAgICzurszGtYEd+txgH6DAxoGrN0suLocEtq5elCpU5+PUNP4siAo5xgEIPtUOemWKMygYHvD+Glz8sIyAZISS4AGDSqq/iXv3/AI6jqhlRxIIAKGKsEqsdTTwAjIHXkkfDB/poF5AkpHTYj81ZKpm8zNX1kD16hhfz0prEaoNLiSJunKzIwZHkduoZ7HsfT66njAG2itY4kXlNpKqdGCwGB0IwC8n9NTxJB/ZVl2yH7fMB1NJTwqceshIP8NAOGhS5nDm0SZa+coyCqTp9WPmHAI9O2f46UOAEnX7+4ROJqRkBt6/om5mqWfIuQ8vsSMEDTlwgEyqgXk3KOkyh8x1dSrMfeIncZ03ikAACyJIm5VJUiMkR11RF8cGY+o/M6niggQmMzIKcSV0wZiLlNkjuxl7nH09Pj66BrGPVCqXH0SHrKjpVIrhNLF2PvSd8j07j+WmFQ5YOisdnDZVCvuMIZEmbHqcuTg/l30adUjRKWkkgoslyup6WjqlVz+HJLEfl27HVrsU4GxlNDjzR6Ski53pgh9qp8Z9Xzn9SRpjXcIvHwU8N3RIF6vBkLBqeT4EL2U/p/wBfDVXvTyTJVLpBnLurter10khaSM+oIA7HSuxFQCJSlpB0Q4Lte6UK0hiqQGLDze/fHw/00aWIcND+qDS4aj7+9k6N/uqAYW3Kx931OT/H1+umGOfAko5TGiGl/uCdAFHRMAe58wnq/ec6Pvr5kEIMEWj6/qjJf6jo/a0CMufVHGSPoD8NX++ODgCFCw7BLe/r1OzULgjvjrB/L8tK3HOgff6JCIP39Fb+0kChEjp5x/jOR1dz9Qe2rKmNgXCVsgxKptxxIoZ45mJOO5AJ+Pz0j8dGyvYHESFgpt3xtKBFTTiDpIZmIBB+BA+P5azux5JtZIAZAAn9lp09dU1ldHULI7sF7Mzehz+LXPbmiTqrTUl4aNEgor1Lu0rPIx6pX9c9+5Hwz/rphUOWYslvmsUeumado1VFWPpACA4AUen5/wDR1CDJJV1WpaAsXMy+8QwjUdgioc5/PQOknZZqzidNPmryW/CjLSuMHKlT20obKIo7Kxop16GiYoB3GBkfLQbRtY/f6p203bfqjo0+GVgMkYY9OMnOf36V8zmIVjQd/olLJP0N+xkbq7dwB/LvpC0DRVNdYn90OHrKNGywg59SD73+umDSJI2UZpYJ7CXeIklCQe2M5H1+utAZlN1ewXVLI594Rq4z7xHbtn6fHVBYRZAZinaTskjhIoWBHYZ9P+vlotYTLldltpZNJnmqZRTo4giP4unI7/njQfTET0VF5hXFKsatCKhlJb06znOg2BaElWmRN7+qs4YtC5rWjYj3VcHH5d/hoODZsFWcx+H380ZIZ+y9ZZT2wqj3f1GtFitIZclIEbsroyzEkZICdQP6/AaGToo4bH7+/sq6RdMRVFcYAJyR6/LOPr/DQcALpWjlkCDZJEayMiydRJ7v73YflgY0WkFs6IFsJ4IKdsyxMY2H4W7gY+Pb1I0C0XEKFjZt96p6AOhMTM7du3UQTn9M6Tw7yES20f2VkM0CDpjAABAAb+mgAJhEHKd1U007KnmiJm6veDN6DPx0zWaEImoDqgS0ntccJkmZEDYwrZz2/jomBPdWGkfRFpsYUpUq6KMEuFbq+GD8vjoUw0gQq2tA0SXfymkD1EasxK4b1P6AemmDwWwLhWTrKtApToj84sAwwrx4Bz8ifz1Cw6oeHr2TpFVSzPNCqA9wCM5z8e319dMQM06myc07iEeIUkrSipnqpqft0CKVVOfmcggj+Oo1o1Iv8bJntmxKZKIQwVJnAH4ABnP6fnoCnPmSAbJTQLEgkYiVi2CCPT8hp3DREUGxI1RAsBifqLOpGezEDP8ADQDoMBI2mG2/VXp4/wAEqVEiKi4GXJ6R8c98aj9ZAVjGxYJwXjjifNWGRc9i+f1GhsCrA0i86K4iMhilhfzM+8MLkEfHTiRbSFU6mDcf5S81URcCjeaMHPV7qj69gMnQzECSdeqaQBpCGlbUdTxGJoeoe7gdh+QxoAOkkFQ1mi0QCni1lUzYDsyEjKlcenw08ZocEA+TISnnqGUIjRhur/AQSv56AJ23+7Jg46Qm2KqEuOurjQ9RZiw6h+XrqNYSOZSo4jS0pXVLIhImqJIv8QLnIH7v5aam0RCDTImVTxkmSEicp2wrMcN9CP8AXSEaHZB2m6L5IMEcMcghTB/ZghVUevfvp3SD3Q8MFsbLHJTUqS5Z0THY9x7vb17d9KDLZIsqW0G6HqjyVMcYDRV8jkZJAOQo+AzqrxDOWEzGXgFEF7WFlE80T59Rg4B+f89M0EnKArGuymSnCVtK7LIrSrLj4MT2/Mj8tMXQYKUNBMkojyReWzSTtGoxgeZ6/qdLmkxr99EHUgdd02jw8yoBO3oc9WOn65zq4XCBYCAESeI9IZjOp6uwY5wfpjtpCCD2TGmJF0TzH8rMkaEAerDv+v8ADRL7iblQNGVNWrI0JABQkEH9mcIMfLRgCCbIANmxSFeUskUSyOpOcmL3R8cahfukY0k5QkzTimMcvtLRSMewAxn6YIxpRBaAEr6ZF56fd0RKsuSq1L5QZYugAb/LqxzhGYiAnY0E3P5ontClRL1SoqkDBT8YPxGqyZFt0wY3YqxnWQoYqkdfUQVMOMjVgqblHKCBlQZESeN3EqSAd8eWQW+nrql5uVU9gg5UAwBMd5CpPr0sfh8840C+bD9EgokapMMZbqdKmMMoGV984+vf0OmLhqUrqZKS7U8MiGWpV5G7EOhP65OjTqNBgJzSIvqgVMKq69AlYsVDdK5B+Py9NKXy66StR26/FOI2JU5jhjH+EtGTkZ/++mDgbn9FDTAum1REzz9EbVBRD7xRQFUD5fPUZbmKL6QiCkgSsCYytSevPS/ugfE/rpQSAICDaAmxS1pWmyZVpYQuD70ncD9P66fMI5lW2g4mG6IfkMUJjMZjwOnpPfVmYTZaTR5eybPJUwydCxMhzjOcd/z0hc6dEpZsLd06zOoEirKH7AYIDY0c3LcJS0i4KE8lYQXVpn6T6lj7p/19NOJ6JgCYk/f6pa11YARHHVzgdsJ8T9Sew/LVDg6dPv73QgxBTb70rkVvMp5VfPyPY/LUeCke8kEFGM88sYkIdAT3Bdl6c/z1YIlQtLhE/VXqqqFXLeyzw9OOktIz9Qx3/P4/LVTiY0CD6YBubpmtWEkB9m6ox6guTjP5fTTBpBkWMeqJc2TEwrrcUjfLhQx9GUsQo+g0zZN2qQyZmE2lr5Jw0YqPZ1ByP+Jvl2Hw/wBdLlIuVWHAiJTlLlUdwGlkf06urscD4jSlhjKAnAAN1j3ZpQgmqKmQA5xg4H+n6aBpybDVQAlouhoIlAUdXyP/AF8NHKZQewC0q6Zl6goKKO3bPc6LafySNj8KdQBkRo2KuWA6cn0OfXQLZ2RptcDlN/7pC0k7q7KiyyjJwR6HHz+OrKnRXeE75JtPSVzAHysnPUTnGe3qdUvablVVKRLOpQxcZ0GJqZmmIz7wx2/4jqoMIuRAVucEkEXTyKpjIUSRU6dRz14yB+n+mmYXExrZWwNwkS1fQ0hjUmIfEHGPyGo5pJ7ousZGiua+kChV86OQ9+ojuDoCne/qqi9kSUwWqpyR5kr+XjJ7HI0cpAmElPLNjKdLNE5LSVQjjyAOkEZHyzpgSTBErU2C7VOhPTRHpEnWB72e47/mP10csnRIco0SFkWSRY0LrHnPce6Tj56RogkKNLTBB3V1boqkhSnYDuvWcjP6/HTXMiPv0S5uaEaaTo8uDqK5bu3T+L9RqoERCrcIsfvqiRrG/XPF0PgEAkFjn/TVjoFmhFtIZkiOSTCMkrLk9wBgfvGnFOSLWVzWt2N1T1E4h6FmjXqOApGD+uqxYqXDYKvDFNIW84SySgZXp90AH4404F4F/u32FKTbXRZSYQCIqgxg57N2z+f00oeJj7+ylNLVJyHZHSGXzWJUdzk/E57+mmDTOkIVGtj6Jy3UhHT0u57FlQnv8s50oEXnRO9g6fmmQeaaVpZixhK9RC47H5HHz0AANdlU1hI6J6yyFBMKiGEd1GTgD6kflqeIIsrRS3H33V0hZ4RVGd6hFJ6RgJk/NQe/66gZrCjqZFyZCaLUBR1RUykggt1DGB9dM0v2sEGRqEuSSKTpVJIY5Bg4LaamQXadVYGj0ThV6gTL+0XqPb/iP+mmdb1UewFyEIpkbtFTgMM9u7Hv3Omc/mCjmgOBI1RXkqJpVj6YEjYd1I9fr6aUgNv0TVB+FquHqYmBQIob1IYHA1MxiAiKZ2RRUy9AjiMCkepUAlfy0WuAUAMc26N55QH2yCOpkIwfy1AeijWgeb7+/qrt5LRSgLDTH1OAMkfl6EaBf+LVWMpyDlsgNUwNEkipArKMZAGGI+mg6QAR97KttISkxXSGoljBimjkAKplMYz8z9dAzeR8UoqNJsjPVTqAViiAz+Hv1dv6ajXG0o5yBGwVzJVnNYZgsSnPUo7Z9MeugCNIugCScw0QzJV1EjSJIzMABgR59f66lQiJGisuNUSNKhWMTSTL2Jz0HKn4flq0AOExCRrCNVdGrQAklRJLJnHmMO2PX9RoOcBDtkZI1MlEhqp1n6llhnPQRlR8Pl8tEuluYKOGX1KvUVk/SQsqKVBJQDv+oOi65lGuYEK00lwNPHMjUwj6cnCfuAz/APfS+pVbwcokJYH7MZTOO/Y4BOjrZBzLAHVM5iZHHdEYgjLjOfj2x8NI0QR0++qRw5pi4R/aIhExSIyn1U9eM/Xvpi689VGtEGyJEIZ27PMoV/RvRfy+emLbghOACbI8tNGV8sSkN+I5HT7v1/hoNIzSE1YGYKS8ApjLIlZNEwHSxck5/L4AaNODcd1DTmBKMI0YovmU5Ocgtlst/rpSLSJULCYhWdQpdqiTpPbrwxKk/l8vy0zSDBiUAw6u3STMxEk0ckI6BnJjZs9vQD46QmddP7oFgjVNp/aZ0RGqJynTjqUdIQD65znUJk6IZZIbNkOI+VHEorUIDZDthj+WjDYtZKWEW19UJqoJN0GrkkGCSTGB1fke+mLhlgBETMJSNHM3uO8zjLt5nrj5A/6fLQgbdkDSaTOu6BVwVKSRESCKNmIEi5yMn6Z9NQA6k26I1GkaJVTS1VQIEjnKxrnse3V+eq8sSXKstdEBNlhlpzFClezkMCy4IVT+ei1jSC4C6LGuBAJVjT1TdTB1MZYqMev1OSe2hlEEpyBcO1VewmVvOURyOSFVu/UT9NFjQDF+6qNM5pKyEFAUjRpJZoh+HIfOP640agAcQRqnDI1smwpp6ch4GR0Ukgl8BTn8tKGtgA2SgCbSUta+OOQwl5ugA9TRnK9X56jKh1ama62VOKq4RQqwdZSWGOknv3+fbS+IdBcJpa0xoD9E2kuVI4jDK3X2GQcgD9R6jOmJN50Smo3TdIirKCNmAkJY+pAOWP6jvjTdgrDliAUeSsto81fa3LP09RPct/DtqQSlc5swVaCso3U4rSMdiCgB7fE6LyA6AE7D0ShVRzef5dargAZTyzjHz1cxzdpTlwzSFY0/WyOsrBfxqQSMflpDGioLCVTsoTojlEgABORhh+ZxqkifKCmDW2i5TXMnSVJjRSQwAbuBnUDTaNQkcCQRCSwNOrJPCJWBGMgHt+n56hdAm6hoyboUFTFPIkVPRqz5ywT/ABDHfP8A4ajbnNMC6rDADEXS1rKSJR0vEznOehSf351YDuncG2lV7ergJGWdW93pYher9R3GlZMJS5v4QlechMaToVhJz8wB+fxGoHEDv+qDQ2Q0W++qIZ0yi+YYARjCgHtj17ab1CsyENAQHWMkJF1tE56c9OD6/wAfTUc4l8bpazJOt0mQwqS7yztn3er/AIvhkDSujQBQsykHojoqgRBLjB0HGA698fLTuANwEKdMxIIVOABhXQOQMdKrgj5/TQc4SmqMEaffzTCSnDBmkLTkA+67YP6nRBiFW+i46zbZba18jq5EM9rtUmfiade+uc3FO6rWXMmS0JyK2xvIq1O2rXUMPwkBl/kdOzGvAk/oi0U92/mhTSbNklME23FQYJLrO47/ACHfTDGuJmEfDoElgn5pBXaNPEHSwidQ3brkLHTjGZQMsKjwKOXmBSKip2th4jZREGH4kIDfxGldxI9EXMpAQVhmg2+wIjkucUZPcFUOf5aQYoG5EJ2hhkIiU9nLpi5VaqDkK9OMEZ9PXTisJ5QgWtI1RordbxMJI7mY174DRHC/z1Uyo34/f5IMDfKDaU4eyvO/VFfaFIm9RhwcfljTzTIgzP3oncw7II22gZPMuVslIyciUqw/hjTl7C2AVldROpKB9zXFJehGo5Kc4IPtYyD/AKarMZrFEB05bo8lku4JNNTRyv2/DIhx+mdWgiIBC0Oplp0TGa27nMbRi1mPqzhlAZv1xosp7ZtEHOcRBCxr0G4oo1WWmqyuRklT3z+Wl8CbqZnARKfU1RV06JEKZpWC4LPEW7Z9fTGhTpua6RICZrxl6pgbrUxTSyvSovc+8Yj7v1Go5jgAFQ+s0XgIK7kdSRLDBJkjv09JP0yNIxzidFW2vHM5GpbpSTSSFURCynC5+OlzTqradQOJA0TsSxsq+0OmOokhmHb8hprG2339/oiDsUmV0Sb/AGSlSVOnA6ZMjH5fPUDupTPgHSQncUrlcSUojjIx09Weo/lpmmIG6am68aK59mVA6U6wt/w49NOHmb6pgGZb2VMFlXJIR8j0Oe2nsRBTPMyTqliqpFk6PNcuOxI9R+/VQfsrQeYCZQUqafOZKmUHPSq5PvZ+eo10jv8AklO4KtKI5sPKxbp90HBABx8O+iHgiECCd0Q01PHib2mRZVUdlIIz9dXeNIjVECNUNI0TLEyOX9AWLAd+2NIXWt9/f3KUQTE3VhTk9BkZYxnOVQsf1+miST9j79FGsk33V1SMI8bFJHOcEqQfh8BpBsoxglKj63kZHQRwnvgsR/1+WpmgyUPNZycwiBGzHSMGbv3bOB66niHykoBoEEaIfUwmaM9MaMDkN73UPl9NAa5lJId2RYBTeSSJokjLYVVBzn66arUCsFKBPdWmeHJT2p+5HujOf1OiXSbahKW90SXpRYooqieUtg9fUCf10CZMK17Rlumxd/LHQs6v3Hde7D5dv5nUJm0KoiPREglmPWs8rv19vdXsO2oY1n6ouLh8URyViZkkKxg57gZ1BU0m6j35dNEATSAPKvllVIPceh+ZOg5wiSq3ESb2+9VaF5O7tVxVFP8AIxev6nUaRElLnc50kiU5LFpIZUiWT4dPYBfr3/XRbY6qWgkBOEGelPIjdj+HLjsNTxOp0TFoFwLpazPBl0plDZwSnfH5/PUdUIuSoLG6x0NX5tQ7sOtT7rOO4J/6+H00S8tgyq2lpdKyMdWXwQy5B9AuB/H9NQVJuFcNUKZVqWileUrj3T0E/uwO2hI1SHWZhVKWTDIzp8QB2P8AD0+GoHbgpBDZMpRcyQmV5irE9gV7t+vrqARIF04YM102cxxxuGpo19wZwuO/zxq8VNgZTFt5CHGYZ5GMUflL9UHy+egHEC1/v9VVkBMNjojLG/uqsPvdQ9SMMD6/l8NVgxZMaVwSkAmKYwxZdWbIUEYP0z8tEFsySi8OktG6eSV0IeRXp8yJge93z2zpBUzaFAgNEwmMlbKyrIlIqxE4VCoHf/i/nohu86pM5dtZNJJa7pjESogY4BC+p/oNQmTdR7osNU9ijrYVwJIfJJ97HYt9c507GtBuq+cFClgq5SxBiiQerBuw+n56rzQTe6Lru5gkQRiUsal6eOBV79CFj+g9M6sa4WJlQhxMBN6hIppVWlWrjg7hTIAP3DQyZrgBJKV92ygyO7QvJjCsx740CAjBJJ6pmtBK0qxGGEr/AIgreo/M6sAJEqsAkybfsjCgI92aljC5OOlu+nJLjKIpgiIsiNRR4cxUk7OCABkY1QGmYG5Vnh3IIuFUdHGg/a0s7ysCGwwxn541bUO1lG0xMBNRb4QSppp0Q989Y7aLXCbqGlqRKf01OkKFIvbyoOSBjv6/DSuIlAU8upKqaZ4w3kQzIrDpYEjJB+WdI5+YX7KDMHCNVUMUJRZSK4OoycoAR9c6cATeJS02g8pKZrLcBKGCiSA9vX1Gqg2RZQuAbCP+yRumOCojRsgsqjtn17acmbINAG8FMjTM7lC1XGvop8tR1D8x6DQMzP6oFsXJRJE6ECQxMAe3U/8AhA9fzOoMxN0pygWSUaXDJ7O5JHc+uBn+WpJhNSA6aojSyTSBURelcAhjog7myscQUKORy2GhheYDswcnHfUaDqDZAuOYQrIlRK7T+TGue+QB/LStaL82qBe6QQE3liuAZfLWDsSTkd2GnLNpSHOTLRBSlpLkIpVRThiMnzO5xoAtI1srHuKVDFXoqiRI3Qk+8SGx3+Oi+DulJcTzaJzF6U/+Ztcqrv6furaOvyWTp/8Aez+R1hb5B6hNv99QmlV/fS/5NdB+rfUfkFditR6Ikv8Aur/mNLR29f0CyVvxfeyYVHq35D+WqP8A3PmqDqgx/wB1+g1rHmb8F0afmd97IsP4x+Wi/wAv33VFTy/AfmspF+JvyH8hrNT8p+CodofT9EVf75P8w/lpqfmP/cF0DqfQfkjP/dH8tUYjyD1/RKfM74IU34R/l/prVS8wWOt+yLR+h/yHTu87fvquhhtH+h/VE+K/mNW1fN8P1T09KfwWYp/SD9f56R2/x/VLX1C2ak/C3+VdXO29f1SnzP8AU/kg1n9yv66B8xWHG/7Xy/Rc4uXqv5auZofvdVO3WvQf303+XWvF/wC78vyQ3P30Vq7/AHg/5NZ6vlH31V7NT99Eim/HT/8AvBoVPMVpZqfVbDU/7zSfn/Q6rwP+y74/mEh8nyTWs/vF/wAi/wBdHD+b5/krTqExX1b/ADf66qr/AH9Fnq6FOov7z/uDS4zzD4fqnb/ulAT8cX+U6uP+031Cu6fBJP8AfL/mP8tXVvKPRDD6H0/dOl/u/wBf6aowWrfvdIPL8P0WZp/90h/znUraOVr/ACJrB/fS/wCf/XVZ87lsq+cfe6M391N/mT+Z1r/9j4Lku/H99UiD/wBX/mP8tc6p/uH0/VXU/wAPqfyCaJ/+If8AfH9NaWa/Na9x97J43+8Sf5f6arw/+yPgq8P5x6/umq+sX+T+utNbyffRPS1d6ptTf/ic/wCf9dU/hPx/Mqv/AN9voni/3kH+Z9Sh/sfJY2+dvx/VEj9F/wAp/nq/8JW3Yfe5WOj/ALif8z/LUxX+4fiqqPk+P6LMQ/3NR/lXVLvI30CFby/BNaj/AHN/8yaQ6hI3R/p+oTVPwQfmuqm+ZvqU2C8rvQfms2n903+Ua0t1b6n8wlo/7abN/fxf5R/8o1a7zPVjtFak/uqX/Mf5axVfP990jdR6ptV/7qP/AH4/rrW7zN9D+iR+rv8Au/RP5f8Ad4Pzb+epT86vdqfvqsZS/wB/+raLUlfyffULPL+Of/MP66qHk+f5hXV/P8vyKVTf7xJ+WrWJx5mpunqfyP8AXQZ5vvsrHeb4funUf92n5H/5dHEJXeY/FKm/DH/l/poDUpcP/uhYKn/C3+dv56vP+18D+RVTND6rBt+Jf/e/10mzfT9FSPK71/RbkPSn/wAp/nqmn5B6pho30CEP6D+Wqa/k++qrZv6H9Fj7l6Sf+8GtNHVWcQ8quvrJ+Q/rrVT8330CoxG3wS4f9x/7zf11lZ/tj4fotJ8zvT9UqX+8of8ALrThfP8AFZW/7fwCVF+Nvz1gdqP+4/qtQ1Pono/vE/yf11tp+f4qpu/oEqn/AN3l/wAzf11S7yN9VK2/30SIfUf5dA6H1P5K3C7eiDWf70P8ui7b0CNL/dC1mX8E/wDlH/zarf5x8fyV9bzj0KzkH92P/dp/PVlXZZBqfQ/mlP8Ajpvy1XW/3B6/ukq6u9T+idVfpX/5f6atZ/tt9VWNvU/ksVRf3zf5W/kNNT8jkKerlkIvwU/+cf001HzLLU1CG3+8Sf5W1XW85+H5K6n5viiD+5H6/wAtIzylNV8v31Rj+Nv/AHmq8Tr99lH6n4LDTf3I/PRf/uffRb6ug9CndH+FvzH8tO7y/FYmaKy/jk/zf6aXEaO9SrmaBNX/AN6b/MdbKfkPo1V4f/cP3siy/wC7H/N/XSv8wVlLytTBPx/97TjT76pKvlX/2Q==</binary><binary id="image1" content-type="image/png">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</binary></FictionBook>
2+<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><genre>unrecognised</genre></title-info><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><section><p>This example test if Pandoc correctly embeds images into FictionBook.</p><p>Small inline image: <image l:href="#image1" l:type="inlineImageType" alt="alt text a small PNG image" />.</p><p>Paragraph image:</p><image l:href="#image2" l:type="imageType" alt="alt text of a big JPEG image" title="image title text" /><p>alt text of a big missing image</p><p>A missing image inline: alt text of missing image.</p></section></body><binary id="image2" content-type="image/jpeg">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</binary><binary id="image1" content-type="image/png">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</binary></FictionBook>
test/fb2/test.jpg

Binary file not shown.

test/html-reader.native+2−1
@@ -1,5 +1,6 @@
1Pandoc (Meta {unMeta = fromList [("generator",MetaInlines [Str "pandoc"]),("title",MetaInlines [Str "Pandoc",Space,Str "Test",Space,Str "Suite"])]})
1Pandoc (Meta {unMeta = fromList [("generator",MetaInlines [Str "pandoc"]),("title",MetaInlines [Str "Pandoc",Space,Str "Test",Space,Str "Suite"])]})
2−[Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",Space,Str "John",Space,Str "Gruber's",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
2+[Header 1 ("pandoc-test-suite",["title"],[]) [Str "Pandoc",Space,Str "Test",Space,Str "Suite"]
3+,Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",Space,Str "John",Space,Str "Gruber's",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
3,HorizontalRule
4,HorizontalRule
4,Header 1 ("headers",[],[]) [Str "Headers"]
5,Header 1 ("headers",[],[]) [Str "Headers"]
5,Header 2 ("level-2-with-an-embedded-link",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link ("",[],[]) [Str "embedded",Space,Str "link"] ("/url","")]
6,Header 2 ("level-2-with-an-embedded-link",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link ("",[],[]) [Str "embedded",Space,Str "link"] ("/url","")]
test/lhs-test.html+2−1
@@ -21,7 +21,7 @@
21 padding-top: 50px;
21 padding-top: 50px;
22 padding-bottom: 50px;
22 padding-bottom: 50px;
23 hyphens: auto;
23 hyphens: auto;
24− word-wrap: break-word;
24+ overflow-wrap: break-word;
25 text-rendering: optimizeLegibility;
25 text-rendering: optimizeLegibility;
26 font-kerning: normal;
26 font-kerning: normal;
27 }
27 }
@@ -92,6 +92,7 @@
92 pre code {
92 pre code {
93 padding: 0;
93 padding: 0;
94 overflow: visible;
94 overflow: visible;
95+ overflow-wrap: normal;
95 }
96 }
96 .sourceCode {
97 .sourceCode {
97 background-color: transparent;
98 background-color: transparent;
test/lhs-test.html+lhs+2−1
@@ -21,7 +21,7 @@
21 padding-top: 50px;
21 padding-top: 50px;
22 padding-bottom: 50px;
22 padding-bottom: 50px;
23 hyphens: auto;
23 hyphens: auto;
24− word-wrap: break-word;
24+ overflow-wrap: break-word;
25 text-rendering: optimizeLegibility;
25 text-rendering: optimizeLegibility;
26 font-kerning: normal;
26 font-kerning: normal;
27 }
27 }
@@ -92,6 +92,7 @@
92 pre code {
92 pre code {
93 padding: 0;
93 padding: 0;
94 overflow: visible;
94 overflow: visible;
95+ overflow-wrap: normal;
95 }
96 }
96 .sourceCode {
97 .sourceCode {
97 background-color: transparent;
98 background-color: transparent;
test/odt/native/tab.nativenew file+1
@@ -0,0 +1 @@
1+[Para [Str "Three",Space,Str "tabs",Space,Str "between",Space,Str "A",Space,Str "and",Space,Str "B",Space,Str "will",Space,Str "be",Space,Str "converted",Space,Str "to",Space,Str "one",Space,Str "Space:",Space,Str "A",Space,Str "B."]]
test/odt/odt/tab.odtnew file

Binary file not shown.

test/pipe-tables.native+2−10
@@ -131,13 +131,7 @@
131 ,(AlignLeft,ColWidthDefault)
131 ,(AlignLeft,ColWidthDefault)
132 ,(AlignCenter,ColWidthDefault)]
132 ,(AlignCenter,ColWidthDefault)]
133 (TableHead ("",[],[])
133 (TableHead ("",[],[])
134− [Row ("",[],[])
134+ [])
135− [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
136− []
137− ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
138− []
139− ,Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
140− []]])
141 [(TableBody ("",[],[]) (RowHeadColumns 0)
135 [(TableBody ("",[],[]) (RowHeadColumns 0)
142 []
136 []
143 [Row ("",[],[])
137 [Row ("",[],[])
@@ -213,9 +207,7 @@
213 [])
207 [])
214 [(AlignCenter,ColWidthDefault)]
208 [(AlignCenter,ColWidthDefault)]
215 (TableHead ("",[],[])
209 (TableHead ("",[],[])
216− [Row ("",[],[])
210+ [])
217− [Cell ("",[],[]) AlignDefault (RowSpan 1) (ColSpan 1)
218− []]])
219 [(TableBody ("",[],[]) (RowHeadColumns 0)
211 [(TableBody ("",[],[]) (RowHeadColumns 0)
220 []
212 []
221 [Row ("",[],[])
213 [Row ("",[],[])
test/pptx/code-custom_templated.pptx

Binary file not shown.

test/pptx/code_templated.pptx

Binary file not shown.

test/pptx/document-properties-short-desc_templated.pptx

Binary file not shown.

test/pptx/document-properties_templated.pptx

Binary file not shown.

test/pptx/endnotes_templated.pptx

Binary file not shown.

test/pptx/endnotes_toc_templated.pptx

Binary file not shown.

test/pptx/images_templated.pptx

Binary file not shown.

test/pptx/inline_formatting_templated.pptx

Binary file not shown.

test/pptx/lists_templated.pptx

Binary file not shown.

test/pptx/raw_ooxml_templated.pptx

Binary file not shown.

test/pptx/reference_depth.pptx

Binary file not shown.

test/pptx/remove_empty_slides_templated.pptx

Binary file not shown.

test/pptx/slide_breaks_slide_level_1_templated.pptx

Binary file not shown.

test/pptx/slide_breaks_templated.pptx

Binary file not shown.

test/pptx/slide_breaks_toc_templated.pptx

Binary file not shown.

test/pptx/speaker_notes_after_metadata_templated.pptx

Binary file not shown.

test/pptx/speaker_notes_afterheader_templated.pptx

Binary file not shown.

test/pptx/speaker_notes_afterseps_templated.pptx

Binary file not shown.

test/pptx/speaker_notes_templated.pptx

Binary file not shown.

test/pptx/start_numbering_at_templated.pptx

Binary file not shown.

test/pptx/tables_templated.pptx

Binary file not shown.

test/pptx/two_column_templated.pptx

Binary file not shown.

test/tables.latex+27−3
@@ -56,11 +56,27 @@ Multiline table with caption:
56 >{\raggedright\arraybackslash}p{(\columnwidth - 6\tabcolsep) * \real{0.35}}@{}}
56 >{\raggedright\arraybackslash}p{(\columnwidth - 6\tabcolsep) * \real{0.35}}@{}}
57\caption{Here's the caption. It may span multiple lines.}\tabularnewline
57\caption{Here's the caption. It may span multiple lines.}\tabularnewline
58\toprule
58\toprule
59−Centered Header & Left Aligned & Right Aligned & Default aligned \\
59+\begin{minipage}[b]{\linewidth}\centering
60+Centered Header
61+\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
62+Left Aligned
63+\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedleft
64+Right Aligned
65+\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
66+Default aligned
67+\end{minipage} \\
60\midrule
68\midrule
61\endfirsthead
69\endfirsthead
62\toprule
70\toprule
63−Centered Header & Left Aligned & Right Aligned & Default aligned \\
71+\begin{minipage}[b]{\linewidth}\centering
72+Centered Header
73+\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
74+Left Aligned
75+\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedleft
76+Right Aligned
77+\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
78+Default aligned
79+\end{minipage} \\
64\midrule
80\midrule
65\endhead
81\endhead
66First & row & 12.0 & Example of a row that spans multiple lines. \\
82First & row & 12.0 & Example of a row that spans multiple lines. \\
@@ -76,7 +92,15 @@ Multiline table without caption:
76 >{\raggedleft\arraybackslash}p{(\columnwidth - 6\tabcolsep) * \real{0.16}}
92 >{\raggedleft\arraybackslash}p{(\columnwidth - 6\tabcolsep) * \real{0.16}}
77 >{\raggedright\arraybackslash}p{(\columnwidth - 6\tabcolsep) * \real{0.35}}@{}}
93 >{\raggedright\arraybackslash}p{(\columnwidth - 6\tabcolsep) * \real{0.35}}@{}}
78\toprule
94\toprule
79−Centered Header & Left Aligned & Right Aligned & Default aligned \\
95+\begin{minipage}[b]{\linewidth}\centering
96+Centered Header
97+\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
98+Left Aligned
99+\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedleft
100+Right Aligned
101+\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
102+Default aligned
103+\end{minipage} \\
80\midrule
104\midrule
81\endhead
105\endhead
82First & row & 12.0 & Example of a row that spans multiple lines. \\
106First & row & 12.0 & Example of a row that spans multiple lines. \\
test/tables.ms+30
@@ -143,6 +143,7 @@ Multiline table with caption:
143.PP
143.PP
144Here\[cq]s the caption. It may span multiple lines.
144Here\[cq]s the caption. It may span multiple lines.
145.na
145.na
146+.nr LLold \n[LL]
146.TS
147.TS
147delim(@@) tab( );
148delim(@@) tab( );
148cw(10.5n) lw(9.6n) rw(11.4n) lw(24.5n).
149cw(10.5n) lw(9.6n) rw(11.4n) lw(24.5n).
@@ -157,30 +158,40 @@ Default aligned
157T}
158T}
158_
159_
159T{
160T{
161+.nr LL 10.5n
160First
162First
161T} T{
163T} T{
164+.nr LL 9.6n
162row
165row
163T} T{
166T} T{
167+.nr LL 11.4n
16412.0
16812.0
165T} T{
169T} T{
170+.nr LL 24.5n
166Example of a row that spans multiple lines.
171Example of a row that spans multiple lines.
167T}
172T}
168T{
173T{
174+.nr LL 10.5n
169Second
175Second
170T} T{
176T} T{
177+.nr LL 9.6n
171row
178row
172T} T{
179T} T{
180+.nr LL 11.4n
1735.0
1815.0
174T} T{
182T} T{
183+.nr LL 24.5n
175Here\[cq]s another one.
184Here\[cq]s another one.
176Note the blank line between rows.
185Note the blank line between rows.
177T}
186T}
178.TE
187.TE
188+.nr LL \n[LLold]
179.ad
189.ad
180.LP
190.LP
181Multiline table without caption:
191Multiline table without caption:
182.PP
192.PP
183.na
193.na
194+.nr LLold \n[LL]
184.TS
195.TS
185delim(@@) tab( );
196delim(@@) tab( );
186cw(10.5n) lw(9.6n) rw(11.4n) lw(24.5n).
197cw(10.5n) lw(9.6n) rw(11.4n) lw(24.5n).
@@ -195,25 +206,34 @@ Default aligned
195T}
206T}
196_
207_
197T{
208T{
209+.nr LL 10.5n
198First
210First
199T} T{
211T} T{
212+.nr LL 9.6n
200row
213row
201T} T{
214T} T{
215+.nr LL 11.4n
20212.0
21612.0
203T} T{
217T} T{
218+.nr LL 24.5n
204Example of a row that spans multiple lines.
219Example of a row that spans multiple lines.
205T}
220T}
206T{
221T{
222+.nr LL 10.5n
207Second
223Second
208T} T{
224T} T{
225+.nr LL 9.6n
209row
226row
210T} T{
227T} T{
228+.nr LL 11.4n
2115.0
2295.0
212T} T{
230T} T{
231+.nr LL 24.5n
213Here\[cq]s another one.
232Here\[cq]s another one.
214Note the blank line between rows.
233Note the blank line between rows.
215T}
234T}
216.TE
235.TE
236+.nr LL \n[LLold]
217.ad
237.ad
218.LP
238.LP
219Table without column headers:
239Table without column headers:
@@ -255,27 +275,37 @@ T}
255Multiline table without column headers:
275Multiline table without column headers:
256.PP
276.PP
257.na
277.na
278+.nr LLold \n[LL]
258.TS
279.TS
259delim(@@) tab( );
280delim(@@) tab( );
260cw(10.5n) lw(9.6n) rw(11.4n) lw(24.5n).
281cw(10.5n) lw(9.6n) rw(11.4n) lw(24.5n).
261T{
282T{
283+.nr LL 10.5n
262First
284First
263T} T{
285T} T{
286+.nr LL 9.6n
264row
287row
265T} T{
288T} T{
289+.nr LL 11.4n
26612.0
29012.0
267T} T{
291T} T{
292+.nr LL 24.5n
268Example of a row that spans multiple lines.
293Example of a row that spans multiple lines.
269T}
294T}
270T{
295T{
296+.nr LL 10.5n
271Second
297Second
272T} T{
298T} T{
299+.nr LL 9.6n
273row
300row
274T} T{
301T} T{
302+.nr LL 11.4n
2755.0
3035.0
276T} T{
304T} T{
305+.nr LL 24.5n
277Here\[cq]s another one.
306Here\[cq]s another one.
278Note the blank line between rows.
307Note the blank line between rows.
279T}
308T}
280.TE
309.TE
310+.nr LL \n[LLold]
281.ad
311.ad
test/tables/nordics.latex+22−4
@@ -5,13 +5,31 @@
5 >{\raggedright\arraybackslash}p{(\columnwidth - 6\tabcolsep) * \real{0.20}}@{}}
5 >{\raggedright\arraybackslash}p{(\columnwidth - 6\tabcolsep) * \real{0.20}}@{}}
6\caption{States belonging to the \emph{Nordics.}}\tabularnewline
6\caption{States belonging to the \emph{Nordics.}}\tabularnewline
7\toprule
7\toprule
8−Name & Capital & \vtop{\hbox{\strut Population}\hbox{\strut (in 2018)}} &
8+\begin{minipage}[b]{\linewidth}\centering
9−\vtop{\hbox{\strut Area}\hbox{\strut (in km\textsuperscript{2})}} \\
9+Name
10+\end{minipage} & \begin{minipage}[b]{\linewidth}\centering
11+Capital
12+\end{minipage} & \begin{minipage}[b]{\linewidth}\centering
13+Population\\
14+(in 2018)\strut
15+\end{minipage} & \begin{minipage}[b]{\linewidth}\centering
16+Area\\
17+(in km\textsuperscript{2})\strut
18+\end{minipage} \\
10\midrule
19\midrule
11\endfirsthead
20\endfirsthead
12\toprule
21\toprule
13−Name & Capital & \vtop{\hbox{\strut Population}\hbox{\strut (in 2018)}} &
22+\begin{minipage}[b]{\linewidth}\centering
14−\vtop{\hbox{\strut Area}\hbox{\strut (in km\textsuperscript{2})}} \\
23+Name
24+\end{minipage} & \begin{minipage}[b]{\linewidth}\centering
25+Capital
26+\end{minipage} & \begin{minipage}[b]{\linewidth}\centering
27+Population\\
28+(in 2018)\strut
29+\end{minipage} & \begin{minipage}[b]{\linewidth}\centering
30+Area\\
31+(in km\textsuperscript{2})\strut
32+\end{minipage} \\
15\midrule
33\midrule
16\endhead
34\endhead
17Denmark & Copenhagen & 5,809,502 & 43,094 \\
35Denmark & Copenhagen & 5,809,502 & 43,094 \\
test/tables/planets.latex+4−4
@@ -1,18 +1,18 @@
1\begin{longtable}[]{@{}cclrrrrrrrrl@{}}
1\begin{longtable}[]{@{}cclrrrrrrrrl@{}}
2\caption{Data about the planets of our solar system.}\tabularnewline
2\caption{Data about the planets of our solar system.}\tabularnewline
3\toprule
3\toprule
4−\multicolumn{2}{l}{} & Name & Mass (10\^{}24kg) & Diameter (km) & Density
4+\multicolumn{2}{c}{} & Name & Mass (10\^{}24kg) & Diameter (km) & Density
5(kg/m\^{}3) & Gravity (m/s\^{}2) & Length of day (hours) & Distance from Sun
5(kg/m\^{}3) & Gravity (m/s\^{}2) & Length of day (hours) & Distance from Sun
6(10\^{}6km) & Mean temperature (C) & Number of moons & Notes \\
6(10\^{}6km) & Mean temperature (C) & Number of moons & Notes \\
7\midrule
7\midrule
8\endfirsthead
8\endfirsthead
9\toprule
9\toprule
10−\multicolumn{2}{l}{} & Name & Mass (10\^{}24kg) & Diameter (km) & Density
10+\multicolumn{2}{c}{} & Name & Mass (10\^{}24kg) & Diameter (km) & Density
11(kg/m\^{}3) & Gravity (m/s\^{}2) & Length of day (hours) & Distance from Sun
11(kg/m\^{}3) & Gravity (m/s\^{}2) & Length of day (hours) & Distance from Sun
12(10\^{}6km) & Mean temperature (C) & Number of moons & Notes \\
12(10\^{}6km) & Mean temperature (C) & Number of moons & Notes \\
13\midrule
13\midrule
14\endhead
14\endhead
15−\multicolumn{2}{l}{\multirow{4}{*}{Terrestrial planets}} & Mercury & 0.330 &
15+\multicolumn{2}{c}{\multirow{4}{*}{Terrestrial planets}} & Mercury & 0.330 &
164,879 & 5427 & 3.7 & 4222.6 & 57.9 & 167 & 0 & Closest to the Sun \\
164,879 & 5427 & 3.7 & 4222.6 & 57.9 & 167 & 0 & Closest to the Sun \\
17& & Venus & 4.87 & 12,104 & 5243 & 8.9 & 2802.0 & 108.2 & 464 & 0 & \\
17& & Venus & 4.87 & 12,104 & 5243 & 8.9 & 2802.0 & 108.2 & 464 & 0 & \\
18& & Earth & 5.97 & 12,756 & 5514 & 9.8 & 24.0 & 149.6 & 15 & 1 & Our world \\
18& & Earth & 5.97 & 12,756 & 5514 & 9.8 & 24.0 & 149.6 & 15 & 1 & Our world \\
@@ -24,7 +24,7 @@ planet \\
24& \multirow{2}{*}{Ice giants} & Uranus & 86.8 & 51,118 & 1271 & 8.7 & 17.2 &
24& \multirow{2}{*}{Ice giants} & Uranus & 86.8 & 51,118 & 1271 & 8.7 & 17.2 &
252872.5 & -195 & 27 & \\
252872.5 & -195 & 27 & \\
26& & Neptune & 102 & 49,528 & 1638 & 11.0 & 16.1 & 4495.1 & -200 & 14 & \\
26& & Neptune & 102 & 49,528 & 1638 & 11.0 & 16.1 & 4495.1 & -200 & 14 & \\
27−\multicolumn{2}{l}{Dwarf planets} & Pluto & 0.0146 & 2,370 & 2095 & 0.7 &
27+\multicolumn{2}{c}{Dwarf planets} & Pluto & 0.0146 & 2,370 & 2095 & 0.7 &
28153.3 & 5906.4 & -225 & 5 & Declassified as a planet in 2006. \\
28153.3 & 5906.4 & -225 & 5 & Declassified as a planet in 2006. \\
29\bottomrule
29\bottomrule
30\end{longtable}
30\end{longtable}
test/tables/students.latex+10−2
@@ -3,11 +3,19 @@
3 >{\raggedright\arraybackslash}p{(\columnwidth - 2\tabcolsep) * \real{0.50}}@{}}
3 >{\raggedright\arraybackslash}p{(\columnwidth - 2\tabcolsep) * \real{0.50}}@{}}
4\caption{List of Students}\tabularnewline
4\caption{List of Students}\tabularnewline
5\toprule
5\toprule
6−Student ID & Name \\
6+\begin{minipage}[b]{\linewidth}\centering
7+Student ID
8+\end{minipage} & \begin{minipage}[b]{\linewidth}\centering
9+Name
10+\end{minipage} \\
7\midrule
11\midrule
8\endfirsthead
12\endfirsthead
9\toprule
13\toprule
10−Student ID & Name \\
14+\begin{minipage}[b]{\linewidth}\centering
15+Student ID
16+\end{minipage} & \begin{minipage}[b]{\linewidth}\centering
17+Name
18+\end{minipage} \\
11\midrule
19\midrule
12\endhead
20\endhead
13\multicolumn{2}{l}{Computer Science} \\
21\multicolumn{2}{l}{Computer Science} \\
test/test-pandoc.hs+1−2
@@ -2,12 +2,11 @@
2
2
3module Main where
3module Main where
4
4
5−import System.Environment (getArgs)
5+import System.Environment (getArgs, getExecutablePath)
6import qualified Control.Exception as E
6import qualified Control.Exception as E
7import Text.Pandoc.App (convertWithOpts, defaultOpts, options,
7import Text.Pandoc.App (convertWithOpts, defaultOpts, options,
8 parseOptionsFromArgs)
8 parseOptionsFromArgs)
9import Text.Pandoc.Error (handleError)
9import Text.Pandoc.Error (handleError)
10−import System.Environment.Executable (getExecutablePath)
11import GHC.IO.Encoding
10import GHC.IO.Encoding
12import Test.Tasty
11import Test.Tasty
13import qualified Tests.Command
12import qualified Tests.Command
test/writer.context+42−38
@@ -17,6 +17,7 @@
17
17
18% use microtypography
18% use microtypography
19\definefontfeature[default][default][script=latn, protrusion=quality, expansion=quality, itlc=yes, textitalics=yes, onum=yes, pnum=yes]
19\definefontfeature[default][default][script=latn, protrusion=quality, expansion=quality, itlc=yes, textitalics=yes, onum=yes, pnum=yes]
20+\definefontfeature[default:tnum][default][tnum=yes, pnum=no]
20\definefontfeature[smallcaps][script=latn, protrusion=quality, expansion=quality, smcp=yes, onum=yes, pnum=yes]
21\definefontfeature[smallcaps][script=latn, protrusion=quality, expansion=quality, smcp=yes, onum=yes, pnum=yes]
21\setupalign[hz,hanging]
22\setupalign[hz,hanging]
22\setupitaliccorrection[global, always]
23\setupitaliccorrection[global, always]
@@ -48,6 +49,9 @@
48\setupitemize[autointro] % prevent orphan list intro
49\setupitemize[autointro] % prevent orphan list intro
49\setupitemize[indentnext=no]
50\setupitemize[indentnext=no]
50
51
52+\defineitemgroup[enumerate]
53+\setupenumerate[each][fit][itemalign=left,distance=.5em,style={\feature[+][default:tnum]}]
54+
51\setupfloat[figure][default={here,nonumber}]
55\setupfloat[figure][default={here,nonumber}]
52\setupfloat[table][default={here,nonumber}]
56\setupfloat[table][default={here,nonumber}]
53
57
@@ -133,12 +137,12 @@ sub status {
133
137
134A list:
138A list:
135
139
136−\startitemize[n,packed][stopper=.]
140+\startenumerate[n,packed][stopper=.]
137\item
141\item
138 item one
142 item one
139\item
143\item
140 item two
144 item two
141−\stopitemize
145+\stopenumerate
142
146
143Nested block quotes:
147Nested block quotes:
144
148
@@ -255,51 +259,51 @@ Minuses loose:
255
259
256Tight:
260Tight:
257
261
258−\startitemize[n,packed][stopper=.]
262+\startenumerate[n,packed][stopper=.]
259\item
263\item
260 First
264 First
261\item
265\item
262 Second
266 Second
263\item
267\item
264 Third
268 Third
265−\stopitemize
269+\stopenumerate
266
270
267and:
271and:
268
272
269−\startitemize[n,packed][stopper=.]
273+\startenumerate[n,packed][stopper=.]
270\item
274\item
271 One
275 One
272\item
276\item
273 Two
277 Two
274\item
278\item
275 Three
279 Three
276−\stopitemize
280+\stopenumerate
277
281
278Loose using tabs:
282Loose using tabs:
279
283
280−\startitemize[n][stopper=.]
284+\startenumerate[n][stopper=.]
281\item
285\item
282 First
286 First
283\item
287\item
284 Second
288 Second
285\item
289\item
286 Third
290 Third
287−\stopitemize
291+\stopenumerate
288
292
289and using spaces:
293and using spaces:
290
294
291−\startitemize[n][stopper=.]
295+\startenumerate[n][stopper=.]
292\item
296\item
293 One
297 One
294\item
298\item
295 Two
299 Two
296\item
300\item
297 Three
301 Three
298−\stopitemize
302+\stopenumerate
299
303
300Multiple paragraphs:
304Multiple paragraphs:
301
305
302−\startitemize[n][stopper=.]
306+\startenumerate[n][stopper=.]
303\item
307\item
304 Item 1, graf one.
308 Item 1, graf one.
305
309
@@ -308,7 +312,7 @@ Multiple paragraphs:
308 Item 2.
312 Item 2.
309\item
313\item
310 Item 3.
314 Item 3.
311−\stopitemize
315+\stopenumerate
312
316
313\subsection[title={Nested},reference={nested}]
317\subsection[title={Nested},reference={nested}]
314
318
@@ -327,7 +331,7 @@ Multiple paragraphs:
327
331
328Here's another:
332Here's another:
329
333
330−\startitemize[n,packed][stopper=.]
334+\startenumerate[n,packed][stopper=.]
331\item
335\item
332 First
336 First
333\item
337\item
@@ -342,11 +346,11 @@ Here's another:
342 \stopitemize
346 \stopitemize
343\item
347\item
344 Third
348 Third
345−\stopitemize
349+\stopenumerate
346
350
347Same thing but with paragraphs:
351Same thing but with paragraphs:
348
352
349−\startitemize[n][stopper=.]
353+\startenumerate[n][stopper=.]
350\item
354\item
351 First
355 First
352\item
356\item
@@ -362,7 +366,7 @@ Same thing but with paragraphs:
362 \stopitemize
366 \stopitemize
363\item
367\item
364 Third
368 Third
365−\stopitemize
369+\stopenumerate
366
370
367\subsection[title={Tabs and spaces},reference={tabs-and-spaces}]
371\subsection[title={Tabs and spaces},reference={tabs-and-spaces}]
368
372
@@ -382,7 +386,7 @@ Same thing but with paragraphs:
382
386
383\subsection[title={Fancy list markers},reference={fancy-list-markers}]
387\subsection[title={Fancy list markers},reference={fancy-list-markers}]
384
388
385−\startitemize[n][start=2,left=(,stopper=),width=2.0em]
389+\startenumerate[n][start=2,left=(,stopper=)]
386\item
390\item
387 begins with 2
391 begins with 2
388\item
392\item
@@ -390,51 +394,51 @@ Same thing but with paragraphs:
390
394
391 with a continuation
395 with a continuation
392
396
393− \startitemize[r,packed][start=4,stopper=.,width=2.0em]
397+ \startenumerate[r,packed][start=4,stopper=.]
394 \item
398 \item
395 sublist with roman numerals, starting with 4
399 sublist with roman numerals, starting with 4
396 \item
400 \item
397 more items
401 more items
398− \startitemize[A,packed][left=(,stopper=),width=2.0em]
402+ \startenumerate[A,packed][left=(,stopper=)]
399 \item
403 \item
400 a subsublist
404 a subsublist
401 \item
405 \item
402 a subsublist
406 a subsublist
403− \stopitemize
407+ \stopenumerate
404− \stopitemize
408+ \stopenumerate
405−\stopitemize
409+\stopenumerate
406
410
407Nesting:
411Nesting:
408
412
409−\startitemize[A,packed][stopper=.]
413+\startenumerate[A,packed][stopper=.]
410\item
414\item
411 Upper Alpha
415 Upper Alpha
412− \startitemize[R,packed][stopper=.]
416+ \startenumerate[R,packed][stopper=.]
413 \item
417 \item
414 Upper Roman.
418 Upper Roman.
415− \startitemize[n,packed][start=6,left=(,stopper=),width=2.0em]
419+ \startenumerate[n,packed][start=6,left=(,stopper=)]
416 \item
420 \item
417 Decimal start with 6
421 Decimal start with 6
418− \startitemize[a,packed][start=3,stopper=)]
422+ \startenumerate[a,packed][start=3,stopper=)]
419 \item
423 \item
420 Lower alpha with paren
424 Lower alpha with paren
421− \stopitemize
425+ \stopenumerate
422− \stopitemize
426+ \stopenumerate
423− \stopitemize
427+ \stopenumerate
424−\stopitemize
428+\stopenumerate
425
429
426Autonumbering:
430Autonumbering:
427
431
428−\startitemize[n,packed]
432+\startenumerate[n,packed]
429\item
433\item
430 Autonumber.
434 Autonumber.
431\item
435\item
432 More.
436 More.
433− \startitemize[a,packed]
437+ \startenumerate[a,packed]
434 \item
438 \item
435 Nested.
439 Nested.
436− \stopitemize
440+ \stopenumerate
437−\stopitemize
441+\stopenumerate
438
442
439Should not be a list item:
443Should not be a list item:
440
444
@@ -547,12 +551,12 @@ Blank line after term, indented marker, alternate markers:
547\startdescription{orange}
551\startdescription{orange}
548 orange fruit
552 orange fruit
549
553
550− \startitemize[n,packed][stopper=.]
554+ \startenumerate[n,packed][stopper=.]
551 \item
555 \item
552 sublist
556 sublist
553 \item
557 \item
554 sublist
558 sublist
555− \stopitemize
559+ \stopenumerate
556\stopdescription
560\stopdescription
557
561
558\section[title={HTML Blocks},reference={html-blocks}]
562\section[title={HTML Blocks},reference={html-blocks}]
@@ -897,10 +901,10 @@ note{]} Here is an inline note.\footnote{This is {\em easier} to type. Inline
897Notes can go in quotes.\footnote{In quote.}
901Notes can go in quotes.\footnote{In quote.}
898\stopblockquote
902\stopblockquote
899
903
900−\startitemize[n,packed][stopper=.]
904+\startenumerate[n,packed][stopper=.]
901\item
905\item
902 And in list items.\footnote{In list.}
906 And in list items.\footnote{In list.}
903−\stopitemize
907+\stopenumerate
904
908
905This paragraph should not be part of the note, as it is not indented.
909This paragraph should not be part of the note, as it is not indented.
906
910
test/writer.html4+2−1
@@ -24,7 +24,7 @@
24 padding-top: 50px;
24 padding-top: 50px;
25 padding-bottom: 50px;
25 padding-bottom: 50px;
26 hyphens: auto;
26 hyphens: auto;
27− word-wrap: break-word;
27+ overflow-wrap: break-word;
28 text-rendering: optimizeLegibility;
28 text-rendering: optimizeLegibility;
29 font-kerning: normal;
29 font-kerning: normal;
30 }
30 }
@@ -95,6 +95,7 @@
95 pre code {
95 pre code {
96 padding: 0;
96 padding: 0;
97 overflow: visible;
97 overflow: visible;
98+ overflow-wrap: normal;
98 }
99 }
99 .sourceCode {
100 .sourceCode {
100 background-color: transparent;
101 background-color: transparent;
test/writer.html5+2−1
@@ -24,7 +24,7 @@
24 padding-top: 50px;
24 padding-top: 50px;
25 padding-bottom: 50px;
25 padding-bottom: 50px;
26 hyphens: auto;
26 hyphens: auto;
27− word-wrap: break-word;
27+ overflow-wrap: break-word;
28 text-rendering: optimizeLegibility;
28 text-rendering: optimizeLegibility;
29 font-kerning: normal;
29 font-kerning: normal;
30 }
30 }
@@ -95,6 +95,7 @@
95 pre code {
95 pre code {
96 padding: 0;
96 padding: 0;
97 overflow: visible;
97 overflow: visible;
98+ overflow-wrap: normal;
98 }
99 }
99 .sourceCode {
100 .sourceCode {
100 background-color: transparent;
101 background-color: transparent;
test/writer.jats_archiving+36−46
@@ -78,39 +78,31 @@ Gruber’s markdown test suite.</p>
78<sec id="block-quotes">
78<sec id="block-quotes">
79 <title>Block Quotes</title>
79 <title>Block Quotes</title>
80 <p>E-mail style:</p>
80 <p>E-mail style:</p>
81− <p specific-use="wrapper">
81+ <disp-quote>
82+ <p>This is a block quote. It is pretty short.</p>
83+ </disp-quote>
84+ <disp-quote>
85+ <p>Code in a block quote:</p>
86+ <preformat>sub status {
87+ print &quot;working&quot;;
88+}</preformat>
89+ <p>A list:</p>
90+ <list list-type="order">
91+ <list-item>
92+ <p>item one</p>
93+ </list-item>
94+ <list-item>
95+ <p>item two</p>
96+ </list-item>
97+ </list>
98+ <p>Nested block quotes:</p>
82 <disp-quote>
99 <disp-quote>
83− <p>This is a block quote. It is pretty short.</p>
100+ <p>nested</p>
84 </disp-quote>
101 </disp-quote>
85− </p>
86− <p specific-use="wrapper">
87 <disp-quote>
102 <disp-quote>
88− <p>Code in a block quote:</p>
103+ <p>nested</p>
89− <preformat>sub status {
90− print &quot;working&quot;;
91−}</preformat>
92− <p>A list:</p>
93− <list list-type="order">
94− <list-item>
95− <p>item one</p>
96− </list-item>
97− <list-item>
98− <p>item two</p>
99− </list-item>
100− </list>
101− <p>Nested block quotes:</p>
102− <p specific-use="wrapper">
103− <disp-quote>
104− <p>nested</p>
105− </disp-quote>
106− </p>
107− <p specific-use="wrapper">
108− <disp-quote>
109− <p>nested</p>
110− </disp-quote>
111− </p>
112 </disp-quote>
104 </disp-quote>
113− </p>
105+ </disp-quote>
114 <p>This should not be a block quote: 2 &gt; 1.</p>
106 <p>This should not be a block quote: 2 &gt; 1.</p>
115 <p>And a following paragraph.</p>
107 <p>And a following paragraph.</p>
116</sec>
108</sec>
@@ -837,12 +829,10 @@ These should not be escaped: \$ \\ \&gt; \[ \{</preformat>
837 </list-item>
829 </list-item>
838 </list>
830 </list>
839 <p>An e-mail address: <email>nobody@nowhere.net</email></p>
831 <p>An e-mail address: <email>nobody@nowhere.net</email></p>
840− <p specific-use="wrapper">
832+ <disp-quote>
841− <disp-quote>
833+ <p>Blockquoted:
842− <p>Blockquoted:
834+ <ext-link ext-link-type="uri" xlink:href="http://example.com/">http://example.com/</ext-link></p>
843− <ext-link ext-link-type="uri" xlink:href="http://example.com/">http://example.com/</ext-link></p>
835+ </disp-quote>
844− </disp-quote>
845− </p>
846 <p>Auto-links should not occur here:
836 <p>Auto-links should not occur here:
847 <monospace>&lt;http://example.com/&gt;</monospace></p>
837 <monospace>&lt;http://example.com/&gt;</monospace></p>
848 <preformat>or here: &lt;http://example.com/&gt;</preformat>
838 <preformat>or here: &lt;http://example.com/&gt;</preformat>
@@ -866,11 +856,9 @@ These should not be escaped: \$ \\ \&gt; \[ \{</preformat>
866 <italic>not</italic> be a footnote reference, because it contains a
856 <italic>not</italic> be a footnote reference, because it contains a
867 space.[^my note] Here is an inline
857 space.[^my note] Here is an inline
868 note.<xref ref-type="fn" rid="fn3">3</xref></p>
858 note.<xref ref-type="fn" rid="fn3">3</xref></p>
869− <p specific-use="wrapper">
859+ <disp-quote>
870− <disp-quote>
860+ <p>Notes can go in quotes.<xref ref-type="fn" rid="fn4">4</xref></p>
871− <p>Notes can go in quotes.<xref ref-type="fn" rid="fn4">4</xref></p>
861+ </disp-quote>
872− </disp-quote>
873− </p>
874 <list list-type="order">
862 <list list-type="order">
875 <list-item>
863 <list-item>
876 <p>And in list items.<xref ref-type="fn" rid="fn5">5</xref></p>
864 <p>And in list items.<xref ref-type="fn" rid="fn5">5</xref></p>
@@ -882,11 +870,12 @@ These should not be escaped: \$ \\ \&gt; \[ \{</preformat>
882<back>
870<back>
883<fn-group>
871<fn-group>
884 <fn id="fn1">
872 <fn id="fn1">
885− <p>Here is the footnote. It can go anywhere after the footnote reference.
873+ <label>1</label><p>Here is the footnote. It can go anywhere after the
886− It need not be placed at the end of the document.</p>
874+ footnote reference. It need not be placed at the end of the document.</p>
887 </fn>
875 </fn>
888 <fn id="fn2">
876 <fn id="fn2">
889− <p>Here’s the long note. This one contains multiple blocks.</p>
877+ <label>2</label><p>Here’s the long note. This one contains multiple
878+ blocks.</p>
890 <p>Subsequent blocks are indented to show that they belong to the footnote
879 <p>Subsequent blocks are indented to show that they belong to the footnote
891 (as with list items).</p>
880 (as with list items).</p>
892 <p specific-use="wrapper">
881 <p specific-use="wrapper">
@@ -896,16 +885,17 @@ These should not be escaped: \$ \\ \&gt; \[ \{</preformat>
896 just indent the first line of each block.</p>
885 just indent the first line of each block.</p>
897 </fn>
886 </fn>
898 <fn id="fn3">
887 <fn id="fn3">
899− <p>This is <italic>easier</italic> to type. Inline notes may contain
888+ <label>3</label><p>This is <italic>easier</italic> to type. Inline notes
889+ may contain
900 <ext-link ext-link-type="uri" xlink:href="http://google.com">links</ext-link>
890 <ext-link ext-link-type="uri" xlink:href="http://google.com">links</ext-link>
901 and <monospace>]</monospace> verbatim characters, as well as [bracketed
891 and <monospace>]</monospace> verbatim characters, as well as [bracketed
902 text].</p>
892 text].</p>
903 </fn>
893 </fn>
904 <fn id="fn4">
894 <fn id="fn4">
905− <p>In quote.</p>
895+ <label>4</label><p>In quote.</p>
906 </fn>
896 </fn>
907 <fn id="fn5">
897 <fn id="fn5">
908− <p>In list.</p>
898+ <label>5</label><p>In list.</p>
909 </fn>
899 </fn>
910</fn-group>
900</fn-group>
911</back>
901</back>
test/writer.jats_articleauthoring+40−48
@@ -67,43 +67,39 @@ Gruber’s markdown test suite.</p>
67<sec id="block-quotes">
67<sec id="block-quotes">
68 <title>Block Quotes</title>
68 <title>Block Quotes</title>
69 <p>E-mail style:</p>
69 <p>E-mail style:</p>
70− <p specific-use="wrapper">
70+ <disp-quote>
71− <disp-quote>
71+ <p>This is a block quote. It is pretty short.</p>
72− <p>This is a block quote. It is pretty short.</p>
72+ </disp-quote>
73− </disp-quote>
73+ <disp-quote>
74− </p>
74+ <p>Code in a block quote:</p>
75− <p specific-use="wrapper">
75+ <p specific-use="wrapper">
76− <disp-quote>
76+ <preformat>sub status {
77− <p>Code in a block quote:</p>
78− <p specific-use="wrapper">
79− <preformat>sub status {
80 print &quot;working&quot;;
77 print &quot;working&quot;;
81}</preformat>
78}</preformat>
82− </p>
79+ </p>
83− <p>A list:</p>
80+ <p>A list:</p>
84− <p specific-use="wrapper">
81+ <p specific-use="wrapper">
85− <list list-type="order">
82+ <list list-type="order">
86− <list-item>
83+ <list-item>
87− <p>item one</p>
84+ <p>item one</p>
88− </list-item>
85+ </list-item>
89− <list-item>
86+ <list-item>
90− <p>item two</p>
87+ <p>item two</p>
91− </list-item>
88+ </list-item>
92− </list>
89+ </list>
93− </p>
90+ </p>
94− <p>Nested block quotes:</p>
91+ <p>Nested block quotes:</p>
95− <p specific-use="wrapper">
92+ <p specific-use="wrapper">
96− <disp-quote>
93+ <disp-quote>
97− <p>nested</p>
94+ <p>nested</p>
98− </disp-quote>
95+ </disp-quote>
99− </p>
96+ </p>
100− <p specific-use="wrapper">
97+ <p specific-use="wrapper">
101− <disp-quote>
98+ <disp-quote>
102− <p>nested</p>
99+ <p>nested</p>
103− </disp-quote>
100+ </disp-quote>
104− </p>
101+ </p>
105− </disp-quote>
102+ </disp-quote>
106− </p>
107 <p>This should not be a block quote: 2 &gt; 1.</p>
103 <p>This should not be a block quote: 2 &gt; 1.</p>
108 <p>And a following paragraph.</p>
104 <p>And a following paragraph.</p>
109</sec>
105</sec>
@@ -817,12 +813,10 @@ These should not be escaped: \$ \\ \&gt; \[ \{</preformat>
817 </list-item>
813 </list-item>
818 </list>
814 </list>
819 <p>An e-mail address: <email>nobody@nowhere.net</email></p>
815 <p>An e-mail address: <email>nobody@nowhere.net</email></p>
820− <p specific-use="wrapper">
816+ <disp-quote>
821− <disp-quote>
817+ <p>Blockquoted:
822− <p>Blockquoted:
818+ <ext-link ext-link-type="uri" xlink:href="http://example.com/">http://example.com/</ext-link></p>
823− <ext-link ext-link-type="uri" xlink:href="http://example.com/">http://example.com/</ext-link></p>
819+ </disp-quote>
824− </disp-quote>
825− </p>
826 <p>Auto-links should not occur here:
820 <p>Auto-links should not occur here:
827 <monospace>&lt;http://example.com/&gt;</monospace></p>
821 <monospace>&lt;http://example.com/&gt;</monospace></p>
828 <preformat>or here: &lt;http://example.com/&gt;</preformat>
822 <preformat>or here: &lt;http://example.com/&gt;</preformat>
@@ -860,13 +854,11 @@ These should not be escaped: \$ \\ \&gt; \[ \{</preformat>
860 and <monospace>]</monospace> verbatim characters, as well as [bracketed
854 and <monospace>]</monospace> verbatim characters, as well as [bracketed
861 text].</p>
855 text].</p>
862 </fn></p>
856 </fn></p>
863− <p specific-use="wrapper">
857+ <disp-quote>
864− <disp-quote>
858+ <p>Notes can go in quotes.<fn>
865− <p>Notes can go in quotes.<fn>
859+ <p>In quote.</p>
866− <p>In quote.</p>
860+ </fn></p>
867− </fn></p>
861+ </disp-quote>
868− </disp-quote>
869− </p>
870 <list list-type="order">
862 <list list-type="order">
871 <list-item>
863 <list-item>
872 <p>And in list items.<fn>
864 <p>And in list items.<fn>
test/writer.jats_publishing+36−46
@@ -78,39 +78,31 @@ Gruber’s markdown test suite.</p>
78<sec id="block-quotes">
78<sec id="block-quotes">
79 <title>Block Quotes</title>
79 <title>Block Quotes</title>
80 <p>E-mail style:</p>
80 <p>E-mail style:</p>
81− <p specific-use="wrapper">
81+ <disp-quote>
82+ <p>This is a block quote. It is pretty short.</p>
83+ </disp-quote>
84+ <disp-quote>
85+ <p>Code in a block quote:</p>
86+ <preformat>sub status {
87+ print &quot;working&quot;;
88+}</preformat>
89+ <p>A list:</p>
90+ <list list-type="order">
91+ <list-item>
92+ <p>item one</p>
93+ </list-item>
94+ <list-item>
95+ <p>item two</p>
96+ </list-item>
97+ </list>
98+ <p>Nested block quotes:</p>
82 <disp-quote>
99 <disp-quote>
83− <p>This is a block quote. It is pretty short.</p>
100+ <p>nested</p>
84 </disp-quote>
101 </disp-quote>
85− </p>
86− <p specific-use="wrapper">
87 <disp-quote>
102 <disp-quote>
88− <p>Code in a block quote:</p>
103+ <p>nested</p>
89− <preformat>sub status {
90− print &quot;working&quot;;
91−}</preformat>
92− <p>A list:</p>
93− <list list-type="order">
94− <list-item>
95− <p>item one</p>
96− </list-item>
97− <list-item>
98− <p>item two</p>
99− </list-item>
100− </list>
101− <p>Nested block quotes:</p>
102− <p specific-use="wrapper">
103− <disp-quote>
104− <p>nested</p>
105− </disp-quote>
106− </p>
107− <p specific-use="wrapper">
108− <disp-quote>
109− <p>nested</p>
110− </disp-quote>
111− </p>
112 </disp-quote>
104 </disp-quote>
113− </p>
105+ </disp-quote>
114 <p>This should not be a block quote: 2 &gt; 1.</p>
106 <p>This should not be a block quote: 2 &gt; 1.</p>
115 <p>And a following paragraph.</p>
107 <p>And a following paragraph.</p>
116</sec>
108</sec>
@@ -837,12 +829,10 @@ These should not be escaped: \$ \\ \&gt; \[ \{</preformat>
837 </list-item>
829 </list-item>
838 </list>
830 </list>
839 <p>An e-mail address: <email>nobody@nowhere.net</email></p>
831 <p>An e-mail address: <email>nobody@nowhere.net</email></p>
840− <p specific-use="wrapper">
832+ <disp-quote>
841− <disp-quote>
833+ <p>Blockquoted:
842− <p>Blockquoted:
834+ <ext-link ext-link-type="uri" xlink:href="http://example.com/">http://example.com/</ext-link></p>
843− <ext-link ext-link-type="uri" xlink:href="http://example.com/">http://example.com/</ext-link></p>
835+ </disp-quote>
844− </disp-quote>
845− </p>
846 <p>Auto-links should not occur here:
836 <p>Auto-links should not occur here:
847 <monospace>&lt;http://example.com/&gt;</monospace></p>
837 <monospace>&lt;http://example.com/&gt;</monospace></p>
848 <preformat>or here: &lt;http://example.com/&gt;</preformat>
838 <preformat>or here: &lt;http://example.com/&gt;</preformat>
@@ -866,11 +856,9 @@ These should not be escaped: \$ \\ \&gt; \[ \{</preformat>
866 <italic>not</italic> be a footnote reference, because it contains a
856 <italic>not</italic> be a footnote reference, because it contains a
867 space.[^my note] Here is an inline
857 space.[^my note] Here is an inline
868 note.<xref ref-type="fn" rid="fn3">3</xref></p>
858 note.<xref ref-type="fn" rid="fn3">3</xref></p>
869− <p specific-use="wrapper">
859+ <disp-quote>
870− <disp-quote>
860+ <p>Notes can go in quotes.<xref ref-type="fn" rid="fn4">4</xref></p>
871− <p>Notes can go in quotes.<xref ref-type="fn" rid="fn4">4</xref></p>
861+ </disp-quote>
872− </disp-quote>
873− </p>
874 <list list-type="order">
862 <list list-type="order">
875 <list-item>
863 <list-item>
876 <p>And in list items.<xref ref-type="fn" rid="fn5">5</xref></p>
864 <p>And in list items.<xref ref-type="fn" rid="fn5">5</xref></p>
@@ -882,11 +870,12 @@ These should not be escaped: \$ \\ \&gt; \[ \{</preformat>
882<back>
870<back>
883<fn-group>
871<fn-group>
884 <fn id="fn1">
872 <fn id="fn1">
885− <p>Here is the footnote. It can go anywhere after the footnote reference.
873+ <label>1</label><p>Here is the footnote. It can go anywhere after the
886− It need not be placed at the end of the document.</p>
874+ footnote reference. It need not be placed at the end of the document.</p>
887 </fn>
875 </fn>
888 <fn id="fn2">
876 <fn id="fn2">
889− <p>Here’s the long note. This one contains multiple blocks.</p>
877+ <label>2</label><p>Here’s the long note. This one contains multiple
878+ blocks.</p>
890 <p>Subsequent blocks are indented to show that they belong to the footnote
879 <p>Subsequent blocks are indented to show that they belong to the footnote
891 (as with list items).</p>
880 (as with list items).</p>
892 <p specific-use="wrapper">
881 <p specific-use="wrapper">
@@ -896,16 +885,17 @@ These should not be escaped: \$ \\ \&gt; \[ \{</preformat>
896 just indent the first line of each block.</p>
885 just indent the first line of each block.</p>
897 </fn>
886 </fn>
898 <fn id="fn3">
887 <fn id="fn3">
899− <p>This is <italic>easier</italic> to type. Inline notes may contain
888+ <label>3</label><p>This is <italic>easier</italic> to type. Inline notes
889+ may contain
900 <ext-link ext-link-type="uri" xlink:href="http://google.com">links</ext-link>
890 <ext-link ext-link-type="uri" xlink:href="http://google.com">links</ext-link>
901 and <monospace>]</monospace> verbatim characters, as well as [bracketed
891 and <monospace>]</monospace> verbatim characters, as well as [bracketed
902 text].</p>
892 text].</p>
903 </fn>
893 </fn>
904 <fn id="fn4">
894 <fn id="fn4">
905− <p>In quote.</p>
895+ <label>4</label><p>In quote.</p>
906 </fn>
896 </fn>
907 <fn id="fn5">
897 <fn id="fn5">
908− <p>In list.</p>
898+ <label>5</label><p>In list.</p>
909 </fn>
899 </fn>
910</fn-group>
900</fn-group>
911</back>
901</back>
test/writer.opml+1−1
@@ -52,7 +52,7 @@
52</outline>
52</outline>
53<outline text="LaTeX" _note="- &#10;- 2 + 2 = 4&#10;- *x* ∈ *y*&#10;- *α* ∧ *ω*&#10;- 223&#10;- *p*-Tree&#10;- Here’s some display math:&#10; $$\\frac{d}{dx}f(x)=\\lim\_{h\\to 0}\\frac{f(x+h)-f(x)}{h}$$&#10;- Here’s one that has a line break in it: *α* + *ω* × *x*².&#10;&#10;These shouldn’t be math:&#10;&#10;- To get the famous equation, write `$e = mc^2$`.&#10;- $22,000 is a *lot* of money. So is $34,000. (It worked if “lot” is&#10; emphasized.)&#10;- Shoes ($20) and socks ($5).&#10;- Escaped `$`: $73 *this should be emphasized* 23$.&#10;&#10;Here’s a LaTeX table:&#10;&#10;------------------------------------------------------------------------">
53<outline text="LaTeX" _note="- &#10;- 2 + 2 = 4&#10;- *x* ∈ *y*&#10;- *α* ∧ *ω*&#10;- 223&#10;- *p*-Tree&#10;- Here’s some display math:&#10; $$\\frac{d}{dx}f(x)=\\lim\_{h\\to 0}\\frac{f(x+h)-f(x)}{h}$$&#10;- Here’s one that has a line break in it: *α* + *ω* × *x*².&#10;&#10;These shouldn’t be math:&#10;&#10;- To get the famous equation, write `$e = mc^2$`.&#10;- $22,000 is a *lot* of money. So is $34,000. (It worked if “lot” is&#10; emphasized.)&#10;- Shoes ($20) and socks ($5).&#10;- Escaped `$`: $73 *this should be emphasized* 23$.&#10;&#10;Here’s a LaTeX table:&#10;&#10;------------------------------------------------------------------------">
54</outline>
54</outline>
55−<outline text="Special Characters" _note="Here is some unicode:&#10;&#10;- I hat: Î&#10;- o umlaut: ö&#10;- section: §&#10;- set membership: ∈&#10;- copyright: ©&#10;&#10;AT&amp;T has an ampersand in their name.&#10;&#10;AT&amp;T is another way to write it.&#10;&#10;This &amp; that.&#10;&#10;4 &amp;lt; 5.&#10;&#10;6 &amp;gt; 5.&#10;&#10;Backslash: \\&#10;&#10;Backtick: \`&#10;&#10;Asterisk: \*&#10;&#10;Underscore: \_&#10;&#10;Left brace: {&#10;&#10;Right brace: }&#10;&#10;Left bracket: \[&#10;&#10;Right bracket: \]&#10;&#10;Left paren: (&#10;&#10;Right paren: )&#10;&#10;Greater-than: &amp;gt;&#10;&#10;Hash: \#&#10;&#10;Period: .&#10;&#10;Bang: !&#10;&#10;Plus: +&#10;&#10;Minus: -&#10;&#10;------------------------------------------------------------------------">
55+<outline text="Special Characters" _note="Here is some unicode:&#10;&#10;- I hat: Î&#10;- o umlaut: ö&#10;- section: §&#10;- set membership: ∈&#10;- copyright: ©&#10;&#10;AT&amp;T has an ampersand in their name.&#10;&#10;AT&amp;T is another way to write it.&#10;&#10;This &amp; that.&#10;&#10;4 &amp;lt; 5.&#10;&#10;6 &amp;gt; 5.&#10;&#10;Backslash: \\&#10;&#10;Backtick: \`&#10;&#10;Asterisk: \*&#10;&#10;Underscore: \_&#10;&#10;Left brace: {&#10;&#10;Right brace: }&#10;&#10;Left bracket: \[&#10;&#10;Right bracket: \]&#10;&#10;Left paren: (&#10;&#10;Right paren: )&#10;&#10;Greater-than: &amp;gt;&#10;&#10;Hash: #&#10;&#10;Period: .&#10;&#10;Bang: !&#10;&#10;Plus: +&#10;&#10;Minus: -&#10;&#10;------------------------------------------------------------------------">
56</outline>
56</outline>
57<outline text="Links">
57<outline text="Links">
58 <outline text="Explicit" _note="Just a [URL](/url/).&#10;&#10;[URL and title](/url/ &quot;title&quot;).&#10;&#10;[URL and title](/url/ &quot;title preceded by two spaces&quot;).&#10;&#10;[URL and title](/url/ &quot;title preceded by a tab&quot;).&#10;&#10;[URL and title](/url/ &quot;title with &quot;quotes&quot; in it&quot;)&#10;&#10;[URL and title](/url/ &quot;title with single quotes&quot;)&#10;&#10;[with\_underscore](/url/with_underscore)&#10;&#10;[Email link](mailto:nobody@nowhere.net)&#10;&#10;[Empty]().">
58 <outline text="Explicit" _note="Just a [URL](/url/).&#10;&#10;[URL and title](/url/ &quot;title&quot;).&#10;&#10;[URL and title](/url/ &quot;title preceded by two spaces&quot;).&#10;&#10;[URL and title](/url/ &quot;title preceded by a tab&quot;).&#10;&#10;[URL and title](/url/ &quot;title with &quot;quotes&quot; in it&quot;)&#10;&#10;[URL and title](/url/ &quot;title with single quotes&quot;)&#10;&#10;[with\_underscore](/url/with_underscore)&#10;&#10;[Email link](mailto:nobody@nowhere.net)&#10;&#10;[Empty]().">
test/writer.org+7−7
@@ -600,14 +600,14 @@ Ellipses...and...and....
600 :END:
600 :END:
601
601
602- \cite[22-23]{smith.1899}
602- \cite[22-23]{smith.1899}
603−- $2+2=4$
603+- \(2+2=4\)
604−- $x \in y$
604+- \(x \in y\)
605−- $\alpha \wedge \omega$
605+- \(\alpha \wedge \omega\)
606−- $223$
606+- \(223\)
607−- $p$-Tree
607+- \(p\)-Tree
608- Here's some display math:
608- Here's some display math:
609− $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
609+ \[\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}\]
610−- Here's one that has a line break in it: $\alpha + \omega \times x^2$.
610+- Here's one that has a line break in it: \(\alpha + \omega \times x^2\).
611
611
612These shouldn't be math:
612These shouldn't be math:
613
613
test/writer.zimwiki+3−3
@@ -8,9 +8,9 @@ This is a set of tests for pandoc. Most of them are adapted from John Gruber’s
8
8
9====== Headers ======
9====== Headers ======
10
10
11−===== Level 2 with an embedded link =====
11+===== Level 2 with an [[url|embedded link]] =====
12
12
13−==== Level 3 with emphasis ====
13+==== Level 3 with //emphasis// ====
14
14
15=== Level 4 ===
15=== Level 4 ===
16
16
@@ -18,7 +18,7 @@ This is a set of tests for pandoc. Most of them are adapted from John Gruber’s
18
18
19====== Level 1 ======
19====== Level 1 ======
20
20
21−===== Level 2 with emphasis =====
21+===== Level 2 with //emphasis// =====
22
22
23==== Level 3 ====
23==== Level 3 ====
24
24
test/writers-lang-and-dir.context+4
@@ -15,6 +15,7 @@
15
15
16% use microtypography
16% use microtypography
17\definefontfeature[default][default][script=latn, protrusion=quality, expansion=quality, itlc=yes, textitalics=yes, onum=yes, pnum=yes]
17\definefontfeature[default][default][script=latn, protrusion=quality, expansion=quality, itlc=yes, textitalics=yes, onum=yes, pnum=yes]
18+\definefontfeature[default:tnum][default][tnum=yes, pnum=no]
18\definefontfeature[smallcaps][script=latn, protrusion=quality, expansion=quality, smcp=yes, onum=yes, pnum=yes]
19\definefontfeature[smallcaps][script=latn, protrusion=quality, expansion=quality, smcp=yes, onum=yes, pnum=yes]
19\setupalign[hz,hanging]
20\setupalign[hz,hanging]
20\setupitaliccorrection[global, always]
21\setupitaliccorrection[global, always]
@@ -46,6 +47,9 @@
46\setupitemize[autointro] % prevent orphan list intro
47\setupitemize[autointro] % prevent orphan list intro
47\setupitemize[indentnext=no]
48\setupitemize[indentnext=no]
48
49
50+\defineitemgroup[enumerate]
51+\setupenumerate[each][fit][itemalign=left,distance=.5em,style={\feature[+][default:tnum]}]
52+
49\setupfloat[figure][default={here,nonumber}]
53\setupfloat[figure][default={here,nonumber}]
50\setupfloat[table][default={here,nonumber}]
54\setupfloat[table][default={here,nonumber}]
51
55
tools/build-arm.sh+3−1
@@ -1,6 +1,8 @@
1#!/bin/sh
1#!/bin/sh
2
2
3−IMAGE_ID=ami-0fa8979d18f69948b
3+#old version:
4+#IMAGE_ID=ami-0fa8979d18f69948b
5+IMAGE_ID=ami-0cd6b53a434812702
4INSTANCE_TYPE=t4g.2xlarge
6INSTANCE_TYPE=t4g.2xlarge
5KEY_NAME=debian-arm-us-east-2
7KEY_NAME=debian-arm-us-east-2
6SECURITY_GROUP_ID=sg-086ffbadc286c5c00
8SECURITY_GROUP_ID=sg-086ffbadc286c5c00