summaryrefslogtreecommitdiff
path: root/macros/luatex
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2021-06-10 03:01:49 +0000
committerNorbert Preining <norbert@preining.info>2021-06-10 03:01:49 +0000
commit2bd77f5a4d02b0d1649589aa7a548e79b198f6af (patch)
tree04786bcca2c349d0cb1373335978e03bb117df7b /macros/luatex
parentf7fc4ad3995d7f6ebbed20c20bf06e3a9176ea04 (diff)
CTAN sync 202106100301
Diffstat (limited to 'macros/luatex')
-rw-r--r--macros/luatex/generic/minim-math/EUPL-1.2-EN.txt287
-rw-r--r--macros/luatex/generic/minim-math/README27
-rw-r--r--macros/luatex/generic/minim-math/minim-math-table.lua2507
-rw-r--r--macros/luatex/generic/minim-math/minim-math.doc244
-rw-r--r--macros/luatex/generic/minim-math/minim-math.lua482
-rw-r--r--macros/luatex/generic/minim-math/minim-math.pdfbin0 -> 106915 bytes
-rw-r--r--macros/luatex/generic/minim-math/minim-math.tex517
-rw-r--r--macros/luatex/generic/minim-mp/EUPL-1.2-EN.txt287
-rw-r--r--macros/luatex/generic/minim-mp/README28
-rw-r--r--macros/luatex/generic/minim-mp/minim-mp.doc329
-rw-r--r--macros/luatex/generic/minim-mp/minim-mp.ini17
-rw-r--r--macros/luatex/generic/minim-mp/minim-mp.lua1282
-rw-r--r--macros/luatex/generic/minim-mp/minim-mp.pdfbin0 -> 82287 bytes
-rw-r--r--macros/luatex/generic/minim-mp/minim-mp.tex61
-rw-r--r--macros/luatex/generic/minim-mp/minim.mp73
-rw-r--r--macros/luatex/generic/minim-pdf/EUPL-1.2-EN.txt287
-rw-r--r--macros/luatex/generic/minim-pdf/README36
-rw-r--r--macros/luatex/generic/minim-pdf/minim-languagecodes.lua146
-rw-r--r--macros/luatex/generic/minim-pdf/minim-pdf.doc425
-rw-r--r--macros/luatex/generic/minim-pdf/minim-pdf.lua1114
-rw-r--r--macros/luatex/generic/minim-pdf/minim-pdf.pdfbin0 -> 108362 bytes
-rw-r--r--macros/luatex/generic/minim-pdf/minim-pdf.tex351
-rw-r--r--macros/luatex/generic/minim/EUPL-1.2-EN.txt287
-rw-r--r--macros/luatex/generic/minim/README40
-rw-r--r--macros/luatex/generic/minim/minim-alloc.doc216
-rw-r--r--macros/luatex/generic/minim/minim-alloc.lua196
-rw-r--r--macros/luatex/generic/minim/minim-alloc.tex184
-rw-r--r--macros/luatex/generic/minim/minim-callbacks.lua265
-rw-r--r--macros/luatex/generic/minim/minim-doc.sty215
-rw-r--r--macros/luatex/generic/minim/minim-etex.tex413
-rw-r--r--macros/luatex/generic/minim/minim-hooks.lua30
-rw-r--r--macros/luatex/generic/minim/minim-hooks.tex56
-rw-r--r--macros/luatex/generic/minim/minim-lmodern.tex28
-rw-r--r--macros/luatex/generic/minim/minim-plain.tex786
-rw-r--r--macros/luatex/generic/minim/minim.doc81
-rw-r--r--macros/luatex/generic/minim/minim.ini25
-rw-r--r--macros/luatex/generic/minim/minim.pdfbin0 -> 285949 bytes
-rw-r--r--macros/luatex/generic/minim/minim.tex8
38 files changed, 11330 insertions, 0 deletions
diff --git a/macros/luatex/generic/minim-math/EUPL-1.2-EN.txt b/macros/luatex/generic/minim-math/EUPL-1.2-EN.txt
new file mode 100644
index 0000000000..4153cd3775
--- /dev/null
+++ b/macros/luatex/generic/minim-math/EUPL-1.2-EN.txt
@@ -0,0 +1,287 @@
+ EUROPEAN UNION PUBLIC LICENCE v. 1.2
+ EUPL © the European Union 2007, 2016
+
+This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined
+below) which is provided under the terms of this Licence. Any use of the Work,
+other than as authorised under this Licence is prohibited (to the extent such
+use is covered by a right of the copyright holder of the Work).
+
+The Work is provided under the terms of this Licence when the Licensor (as
+defined below) has placed the following notice immediately following the
+copyright notice for the Work:
+
+ Licensed under the EUPL
+
+or has expressed by any other means his willingness to license under the EUPL.
+
+1. Definitions
+
+In this Licence, the following terms have the following meaning:
+
+- ‘The Licence’: this Licence.
+
+- ‘The Original Work’: the work or software distributed or communicated by the
+ Licensor under this Licence, available as Source Code and also as Executable
+ Code as the case may be.
+
+- ‘Derivative Works’: the works or software that could be created by the
+ Licensee, based upon the Original Work or modifications thereof. This Licence
+ does not define the extent of modification or dependence on the Original Work
+ required in order to classify a work as a Derivative Work; this extent is
+ determined by copyright law applicable in the country mentioned in Article 15.
+
+- ‘The Work’: the Original Work or its Derivative Works.
+
+- ‘The Source Code’: the human-readable form of the Work which is the most
+ convenient for people to study and modify.
+
+- ‘The Executable Code’: any code which has generally been compiled and which is
+ meant to be interpreted by a computer as a program.
+
+- ‘The Licensor’: the natural or legal person that distributes or communicates
+ the Work under the Licence.
+
+- ‘Contributor(s)’: any natural or legal person who modifies the Work under the
+ Licence, or otherwise contributes to the creation of a Derivative Work.
+
+- ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of
+ the Work under the terms of the Licence.
+
+- ‘Distribution’ or ‘Communication’: any act of selling, giving, lending,
+ renting, distributing, communicating, transmitting, or otherwise making
+ available, online or offline, copies of the Work or providing access to its
+ essential functionalities at the disposal of any other natural or legal
+ person.
+
+2. Scope of the rights granted by the Licence
+
+The Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
+sublicensable licence to do the following, for the duration of copyright vested
+in the Original Work:
+
+- use the Work in any circumstance and for all usage,
+- reproduce the Work,
+- modify the Work, and make Derivative Works based upon the Work,
+- communicate to the public, including the right to make available or display
+ the Work or copies thereof to the public and perform publicly, as the case may
+ be, the Work,
+- distribute the Work or copies thereof,
+- lend and rent the Work or copies thereof,
+- sublicense rights in the Work or copies thereof.
+
+Those rights can be exercised on any media, supports and formats, whether now
+known or later invented, as far as the applicable law permits so.
+
+In the countries where moral rights apply, the Licensor waives his right to
+exercise his moral right to the extent allowed by law in order to make effective
+the licence of the economic rights here above listed.
+
+The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to
+any patents held by the Licensor, to the extent necessary to make use of the
+rights granted on the Work under this Licence.
+
+3. Communication of the Source Code
+
+The Licensor may provide the Work either in its Source Code form, or as
+Executable Code. If the Work is provided as Executable Code, the Licensor
+provides in addition a machine-readable copy of the Source Code of the Work
+along with each copy of the Work that the Licensor distributes or indicates, in
+a notice following the copyright notice attached to the Work, a repository where
+the Source Code is easily and freely accessible for as long as the Licensor
+continues to distribute or communicate the Work.
+
+4. Limitations on copyright
+
+Nothing in this Licence is intended to deprive the Licensee of the benefits from
+any exception or limitation to the exclusive rights of the rights owners in the
+Work, of the exhaustion of those rights or of other applicable limitations
+thereto.
+
+5. Obligations of the Licensee
+
+The grant of the rights mentioned above is subject to some restrictions and
+obligations imposed on the Licensee. Those obligations are the following:
+
+Attribution right: The Licensee shall keep intact all copyright, patent or
+trademarks notices and all notices that refer to the Licence and to the
+disclaimer of warranties. The Licensee must include a copy of such notices and a
+copy of the Licence with every copy of the Work he/she distributes or
+communicates. The Licensee must cause any Derivative Work to carry prominent
+notices stating that the Work has been modified and the date of modification.
+
+Copyleft clause: If the Licensee distributes or communicates copies of the
+Original Works or Derivative Works, this Distribution or Communication will be
+done under the terms of this Licence or of a later version of this Licence
+unless the Original Work is expressly distributed only under this version of the
+Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee
+(becoming Licensor) cannot offer or impose any additional terms or conditions on
+the Work or Derivative Work that alter or restrict the terms of the Licence.
+
+Compatibility clause: If the Licensee Distributes or Communicates Derivative
+Works or copies thereof based upon both the Work and another work licensed under
+a Compatible Licence, this Distribution or Communication can be done under the
+terms of this Compatible Licence. For the sake of this clause, ‘Compatible
+Licence’ refers to the licences listed in the appendix attached to this Licence.
+Should the Licensee's obligations under the Compatible Licence conflict with
+his/her obligations under this Licence, the obligations of the Compatible
+Licence shall prevail.
+
+Provision of Source Code: When distributing or communicating copies of the Work,
+the Licensee will provide a machine-readable copy of the Source Code or indicate
+a repository where this Source will be easily and freely available for as long
+as the Licensee continues to distribute or communicate the Work.
+
+Legal Protection: This Licence does not grant permission to use the trade names,
+trademarks, service marks, or names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the copyright notice.
+
+6. Chain of Authorship
+
+The original Licensor warrants that the copyright in the Original Work granted
+hereunder is owned by him/her or licensed to him/her and that he/she has the
+power and authority to grant the Licence.
+
+Each Contributor warrants that the copyright in the modifications he/she brings
+to the Work are owned by him/her or licensed to him/her and that he/she has the
+power and authority to grant the Licence.
+
+Each time You accept the Licence, the original Licensor and subsequent
+Contributors grant You a licence to their contributions to the Work, under the
+terms of this Licence.
+
+7. Disclaimer of Warranty
+
+The Work is a work in progress, which is continuously improved by numerous
+Contributors. It is not a finished work and may therefore contain defects or
+‘bugs’ inherent to this type of development.
+
+For the above reason, the Work is provided under the Licence on an ‘as is’ basis
+and without warranties of any kind concerning the Work, including without
+limitation merchantability, fitness for a particular purpose, absence of defects
+or errors, accuracy, non-infringement of intellectual property rights other than
+copyright as stated in Article 6 of this Licence.
+
+This disclaimer of warranty is an essential part of the Licence and a condition
+for the grant of any rights to the Work.
+
+8. Disclaimer of Liability
+
+Except in the cases of wilful misconduct or damages directly caused to natural
+persons, the Licensor will in no event be liable for any direct or indirect,
+material or moral, damages of any kind, arising out of the Licence or of the use
+of the Work, including without limitation, damages for loss of goodwill, work
+stoppage, computer failure or malfunction, loss of data or any commercial
+damage, even if the Licensor has been advised of the possibility of such damage.
+However, the Licensor will be liable under statutory product liability laws as
+far such laws apply to the Work.
+
+9. Additional agreements
+
+While distributing the Work, You may choose to conclude an additional agreement,
+defining obligations or services consistent with this Licence. However, if
+accepting obligations, You may act only on your own behalf and on your sole
+responsibility, not on behalf of the original Licensor or any other Contributor,
+and only if You agree to indemnify, defend, and hold each Contributor harmless
+for any liability incurred by, or claims asserted against such Contributor by
+the fact You have accepted any warranty or additional liability.
+
+10. Acceptance of the Licence
+
+The provisions of this Licence can be accepted by clicking on an icon ‘I agree’
+placed under the bottom of a window displaying the text of this Licence or by
+affirming consent in any other similar way, in accordance with the rules of
+applicable law. Clicking on that icon indicates your clear and irrevocable
+acceptance of this Licence and all of its terms and conditions.
+
+Similarly, you irrevocably accept this Licence and all of its terms and
+conditions by exercising any rights granted to You by Article 2 of this Licence,
+such as the use of the Work, the creation by You of a Derivative Work or the
+Distribution or Communication by You of the Work or copies thereof.
+
+11. Information to the public
+
+In case of any Distribution or Communication of the Work by means of electronic
+communication by You (for example, by offering to download the Work from a
+remote location) the distribution channel or media (for example, a website) must
+at least provide to the public the information requested by the applicable law
+regarding the Licensor, the Licence and the way it may be accessible, concluded,
+stored and reproduced by the Licensee.
+
+12. Termination of the Licence
+
+The Licence and the rights granted hereunder will terminate automatically upon
+any breach by the Licensee of the terms of the Licence.
+
+Such a termination will not terminate the licences of any person who has
+received the Work from the Licensee under the Licence, provided such persons
+remain in full compliance with the Licence.
+
+13. Miscellaneous
+
+Without prejudice of Article 9 above, the Licence represents the complete
+agreement between the Parties as to the Work.
+
+If any provision of the Licence is invalid or unenforceable under applicable
+law, this will not affect the validity or enforceability of the Licence as a
+whole. Such provision will be construed or reformed so as necessary to make it
+valid and enforceable.
+
+The European Commission may publish other linguistic versions or new versions of
+this Licence or updated versions of the Appendix, so far this is required and
+reasonable, without reducing the scope of the rights granted by the Licence. New
+versions of the Licence will be published with a unique version number.
+
+All linguistic versions of this Licence, approved by the European Commission,
+have identical value. Parties can take advantage of the linguistic version of
+their choice.
+
+14. Jurisdiction
+
+Without prejudice to specific agreement between parties,
+
+- any litigation resulting from the interpretation of this License, arising
+ between the European Union institutions, bodies, offices or agencies, as a
+ Licensor, and any Licensee, will be subject to the jurisdiction of the Court
+ of Justice of the European Union, as laid down in article 272 of the Treaty on
+ the Functioning of the European Union,
+
+- any litigation arising between other parties and resulting from the
+ interpretation of this License, will be subject to the exclusive jurisdiction
+ of the competent court where the Licensor resides or conducts its primary
+ business.
+
+15. Applicable Law
+
+Without prejudice to specific agreement between parties,
+
+- this Licence shall be governed by the law of the European Union Member State
+ where the Licensor has his seat, resides or has his registered office,
+
+- this licence shall be governed by Belgian law if the Licensor has no seat,
+ residence or registered office inside a European Union Member State.
+
+Appendix
+
+‘Compatible Licences’ according to Article 5 EUPL are:
+
+- GNU General Public License (GPL) v. 2, v. 3
+- GNU Affero General Public License (AGPL) v. 3
+- Open Software License (OSL) v. 2.1, v. 3.0
+- Eclipse Public License (EPL) v. 1.0
+- CeCILL v. 2.0, v. 2.1
+- Mozilla Public Licence (MPL) v. 2
+- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
+- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for
+ works other than software
+- European Union Public Licence (EUPL) v. 1.1, v. 1.2
+- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong
+ Reciprocity (LiLiQ-R+).
+
+The European Commission may update this Appendix to later versions of the above
+licences without producing a new version of the EUPL, as long as they provide
+the rights granted in Article 2 of this Licence and protect the covered Source
+Code from exclusive appropriation.
+
+All other changes or additions to this Appendix require the production of a new
+EUPL version.
diff --git a/macros/luatex/generic/minim-math/README b/macros/luatex/generic/minim-math/README
new file mode 100644
index 0000000000..b463a8bad3
--- /dev/null
+++ b/macros/luatex/generic/minim-math/README
@@ -0,0 +1,27 @@
+Version: 2021/1.0
+
+SUMMARY
+
+This package gives a simple and higly-configurable way of using unicode and
+OpenType mathematics with plain LuaTeX, making use of most of the latter
+engine’s new capabilities in mathematical typesetting. Also included are
+proper settings and definitions for nearly all unicode mathematical
+characters.
+
+
+DOCUMENTATION
+
+In order to obtain the typeset manual of this package, simply say:
+
+ luatex minim-math.doc
+
+
+COPYING
+
+(c) 2021 Esger Renkema
+
+These files may be distributed under the terms of the European Union Public
+Licence (EUPL) version 1.2 or later. A copy can be obtained at:
+
+https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+
diff --git a/macros/luatex/generic/minim-math/minim-math-table.lua b/macros/luatex/generic/minim-math/minim-math-table.lua
new file mode 100644
index 0000000000..3a12d1da99
--- /dev/null
+++ b/macros/luatex/generic/minim-math/minim-math-table.lua
@@ -0,0 +1,2507 @@
+-- vim: nowrap fo-=a
+return
+ { { code = 0x00021, char = '!', class = 'punct', cs = 'exclam' } -- exclamation mark
+ , { code = 0x00023, char = '#', class = 'ord', cs = 'octothorpe' } -- number sign
+ , { code = 0x00024, char = '$', class = 'ord', cs = 'mathdollar' } -- dollar sign
+ , { code = 0x00025, char = '%', class = 'ord', cs = 'percent' } -- percent sign
+ , { code = 0x00026, char = '&', class = 'ord', cs = 'ampersand' } -- ampersand
+ , { code = 0x00028, char = '(', class = 'open', cs = 'lparen' } -- left parenthesis
+ , { code = 0x00029, char = ')', class = 'close', cs = 'rparen' } -- right parenthesis
+ , { code = 0x0002B, char = '+', class = 'bin', cs = 'plus' } -- plus sign
+ , { code = 0x0002C, char = ',', class = 'punct', cs = 'comma' } -- comma
+ , { code = 0x0002E, char = '.', class = 'ord', cs = 'ldot' } -- full stop
+ , { code = 0x0002F, char = '/', class = 'ord', cs = 'mathslash' } -- solidus
+ , { code = 0x00030, char = '0', class = 'var', alphabet = 'digits' } -- digit zero
+ , { code = 0x00031, char = '1', class = 'var', alphabet = 'digits' } -- digit one
+ , { code = 0x00032, char = '2', class = 'var', alphabet = 'digits' } -- digit two
+ , { code = 0x00033, char = '3', class = 'var', alphabet = 'digits' } -- digit three
+ , { code = 0x00034, char = '4', class = 'var', alphabet = 'digits' } -- digit four
+ , { code = 0x00035, char = '5', class = 'var', alphabet = 'digits' } -- digit five
+ , { code = 0x00036, char = '6', class = 'var', alphabet = 'digits' } -- digit six
+ , { code = 0x00037, char = '7', class = 'var', alphabet = 'digits' } -- digit seven
+ , { code = 0x00038, char = '8', class = 'var', alphabet = 'digits' } -- digit eight
+ , { code = 0x00039, char = '9', class = 'var', alphabet = 'digits' } -- digit nine
+ , { code = 0x0003A, char = ':', class = 'punct', cs = 'colon' } -- colon
+ , { code = 0x0003B, char = ';', class = 'punct', cs = 'semicolon' } -- semicolon
+ , { code = 0x0003C, char = '<', class = 'rel', cs = 'less' } -- less-than sign
+ , { code = 0x0003D, char = '=', class = 'rel', cs = 'equal' } -- equals sign
+ , { code = 0x0003E, char = '>', class = 'rel', cs = 'greater' } -- greater-than sign
+ , { code = 0x0003F, char = '?', class = 'ord', cs = 'question' } -- question mark
+ , { code = 0x00040, char = '@', class = 'ord', cs = 'atsign' } -- commercial at
+ , { code = 0x00041, char = 'A', class = 'var', alphabet = 'Latin' } -- latin capital letter a
+ , { code = 0x00042, char = 'B', class = 'var', alphabet = 'Latin' } -- latin capital letter b
+ , { code = 0x00043, char = 'C', class = 'var', alphabet = 'Latin' } -- latin capital letter c
+ , { code = 0x00044, char = 'D', class = 'var', alphabet = 'Latin' } -- latin capital letter d
+ , { code = 0x00045, char = 'E', class = 'var', alphabet = 'Latin' } -- latin capital letter e
+ , { code = 0x00046, char = 'F', class = 'var', alphabet = 'Latin' } -- latin capital letter f
+ , { code = 0x00047, char = 'G', class = 'var', alphabet = 'Latin' } -- latin capital letter g
+ , { code = 0x00048, char = 'H', class = 'var', alphabet = 'Latin' } -- latin capital letter h
+ , { code = 0x00049, char = 'I', class = 'var', alphabet = 'Latin' } -- latin capital letter i
+ , { code = 0x0004A, char = 'J', class = 'var', alphabet = 'Latin' } -- latin capital letter j
+ , { code = 0x0004B, char = 'K', class = 'var', alphabet = 'Latin' } -- latin capital letter k
+ , { code = 0x0004C, char = 'L', class = 'var', alphabet = 'Latin' } -- latin capital letter l
+ , { code = 0x0004D, char = 'M', class = 'var', alphabet = 'Latin' } -- latin capital letter m
+ , { code = 0x0004E, char = 'N', class = 'var', alphabet = 'Latin' } -- latin capital letter n
+ , { code = 0x0004F, char = 'O', class = 'var', alphabet = 'Latin' } -- latin capital letter o
+ , { code = 0x00050, char = 'P', class = 'var', alphabet = 'Latin' } -- latin capital letter p
+ , { code = 0x00051, char = 'Q', class = 'var', alphabet = 'Latin' } -- latin capital letter q
+ , { code = 0x00052, char = 'R', class = 'var', alphabet = 'Latin' } -- latin capital letter r
+ , { code = 0x00053, char = 'S', class = 'var', alphabet = 'Latin' } -- latin capital letter s
+ , { code = 0x00054, char = 'T', class = 'var', alphabet = 'Latin' } -- latin capital letter t
+ , { code = 0x00055, char = 'U', class = 'var', alphabet = 'Latin' } -- latin capital letter u
+ , { code = 0x00056, char = 'V', class = 'var', alphabet = 'Latin' } -- latin capital letter v
+ , { code = 0x00057, char = 'W', class = 'var', alphabet = 'Latin' } -- latin capital letter w
+ , { code = 0x00058, char = 'X', class = 'var', alphabet = 'Latin' } -- latin capital letter x
+ , { code = 0x00059, char = 'Y', class = 'var', alphabet = 'Latin' } -- latin capital letter y
+ , { code = 0x0005A, char = 'Z', class = 'var', alphabet = 'Latin' } -- latin capital letter z
+ , { code = 0x00061, char = 'a', class = 'var', alphabet = 'latin' } -- latin small letter a
+ , { code = 0x00062, char = 'b', class = 'var', alphabet = 'latin' } -- latin small letter b
+ , { code = 0x00063, char = 'c', class = 'var', alphabet = 'latin' } -- latin small letter c
+ , { code = 0x00064, char = 'd', class = 'var', alphabet = 'latin' } -- latin small letter d
+ , { code = 0x00065, char = 'e', class = 'var', alphabet = 'latin' } -- latin small letter e
+ , { code = 0x00066, char = 'f', class = 'var', alphabet = 'latin' } -- latin small letter f
+ , { code = 0x00067, char = 'g', class = 'var', alphabet = 'latin' } -- latin small letter g
+ , { code = 0x00068, char = 'h', class = 'var', alphabet = 'latin' } -- latin small letter h
+ , { code = 0x00069, char = 'i', class = 'var', alphabet = 'latin' } -- latin small letter i
+ , { code = 0x0006A, char = 'j', class = 'var', alphabet = 'latin' } -- latin small letter j
+ , { code = 0x0006B, char = 'k', class = 'var', alphabet = 'latin' } -- latin small letter k
+ , { code = 0x0006C, char = 'l', class = 'var', alphabet = 'latin' } -- latin small letter l
+ , { code = 0x0006D, char = 'm', class = 'var', alphabet = 'latin' } -- latin small letter m
+ , { code = 0x0006E, char = 'n', class = 'var', alphabet = 'latin' } -- latin small letter n
+ , { code = 0x0006F, char = 'o', class = 'var', alphabet = 'latin' } -- latin small letter o
+ , { code = 0x00070, char = 'p', class = 'var', alphabet = 'latin' } -- latin small letter p
+ , { code = 0x00071, char = 'q', class = 'var', alphabet = 'latin' } -- latin small letter q
+ , { code = 0x00072, char = 'r', class = 'var', alphabet = 'latin' } -- latin small letter r
+ , { code = 0x00073, char = 's', class = 'var', alphabet = 'latin' } -- latin small letter s
+ , { code = 0x00074, char = 't', class = 'var', alphabet = 'latin' } -- latin small letter t
+ , { code = 0x00075, char = 'u', class = 'var', alphabet = 'latin' } -- latin small letter u
+ , { code = 0x00076, char = 'v', class = 'var', alphabet = 'latin' } -- latin small letter v
+ , { code = 0x00077, char = 'w', class = 'var', alphabet = 'latin' } -- latin small letter w
+ , { code = 0x00078, char = 'x', class = 'var', alphabet = 'latin' } -- latin small letter x
+ , { code = 0x00079, char = 'y', class = 'var', alphabet = 'latin' } -- latin small letter y
+ , { code = 0x0007A, char = 'z', class = 'var', alphabet = 'latin' } -- latin small letter z
+ , { code = 0x0005B, char = '[', class = 'open', cs = 'lbrack' } -- left square bracket
+ , { code = 0x0005C, char = '\\', class = 'ord', cs = 'mathbackslash' } -- reverse solidus
+ , { code = 0x0005D, char = ']', class = 'close', cs = 'rbrack' } -- right square bracket
+ , { code = 0x0007B, char = '{', class = 'open', cs = 'lbrace' } -- left curly bracket
+ , { code = 0x0007C, char = '|', class = 'fence', cs = 'vert' } -- vertical line
+ , { code = 0x0007D, char = '}', class = 'close', cs = 'rbrace' } -- right curly bracket
+ , { code = 0x000A3, char = '£', class = 'ord', cs = 'sterling' } -- pound sign
+ , { code = 0x000A5, char = '¥', class = 'ord', cs = 'yen' } -- yen sign
+ , { code = 0x000AC, char = '¬', class = 'ord', cs = 'neg' } -- not sign
+ , { code = 0x000B1, char = '±', class = 'bin', cs = 'pm' } -- plus-minus sign
+ , { code = 0x000B7, char = '·', class = 'punct', cs = 'cdotp' } -- middle dot
+ , { code = 0x000D7, char = '×', class = 'bin', cs = 'times' } -- multiplication sign
+ , { code = 0x000F0, char = 'ð', class = 'ord', cs = 'matheth' } -- latin small letter eth
+ , { code = 0x000F7, char = '÷', class = 'bin', cs = 'div' } -- division sign
+ , { code = 0x001B5, char = 'Ƶ', class = 'ord', cs = 'Zbar' } -- latin capital letter z with stroke
+ , { code = 0x00300, char = ' ̀', class = 'accent', cs = 'grave' } -- combining grave accent
+ , { code = 0x00301, char = ' ́', class = 'accent', cs = 'acute' } -- combining acute accent
+ , { code = 0x00302, char = ' ̂', class = 'accent', cs = 'hat' } -- combining circumflex accent
+ , { code = 0x00303, char = ' ̃', class = 'accent', cs = 'tilde' } -- combining tilde
+ , { code = 0x00304, char = ' ̄', class = 'accent', cs = 'bar' } -- combining macron
+ , { code = 0x00305, char = ' ̅', class = 'accent', cs = 'overbar' } -- combining overline
+ , { code = 0x00306, char = ' ̆', class = 'accent', cs = 'breve' } -- combining breve
+ , { code = 0x00307, char = ' ̇', class = 'accent', cs = 'dot' } -- combining dot above
+ , { code = 0x00308, char = ' ̈', class = 'accent', cs = 'ddot' } -- combining diaeresis
+ , { code = 0x00309, char = ' ̉', class = 'accent', cs = 'ovhook' } -- combining hook above
+ , { code = 0x0030A, char = ' ̊', class = 'accent', cs = 'ocirc' } -- combining ring above
+ , { code = 0x0030C, char = ' ̌', class = 'accent', cs = 'check' } -- combining caron
+ , { code = 0x00310, char = ' ̐', class = 'accent', cs = 'candra' } -- combining candrabindu
+ , { code = 0x00312, char = ' ̒', class = 'accent', cs = 'oturnedcomma' } -- combining turned comma above
+ , { code = 0x00315, char = ' ̕', class = 'accent', cs = 'ocommatopright' } -- combining comma above right
+ , { code = 0x0031A, char = ' ̚', class = 'accent', cs = 'droang' } -- combining left angle above
+ , { code = 0x00330, char = ' ̰', class = 'botaccent', cs = 'wideutilde' } -- combining tilde below
+ , { code = 0x00331, char = ' ̱', class = 'botaccent', cs = 'underbar' } -- combining macron below
+ , { code = 0x00338, char = ' ̸', class = 'overlay', cs = 'not' } -- combining long solidus overlay
+ , { code = 0x00391, char = 'Α', class = 'var', cs = 'Alpha', alphabet = 'Greek' } -- greek capital letter alpha
+ , { code = 0x00392, char = 'Β', class = 'var', cs = 'Beta', alphabet = 'Greek' } -- greek capital letter beta
+ , { code = 0x00393, char = 'Γ', class = 'var', cs = 'Gamma', alphabet = 'Greek' } -- greek capital letter gamma
+ , { code = 0x00394, char = 'Δ', class = 'var', cs = 'Delta', alphabet = 'Greek' } -- greek capital letter delta
+ , { code = 0x00395, char = 'Ε', class = 'var', cs = 'Epsilon', alphabet = 'Greek' } -- greek capital letter epsilon
+ , { code = 0x00396, char = 'Ζ', class = 'var', cs = 'Zeta', alphabet = 'Greek' } -- greek capital letter zeta
+ , { code = 0x00397, char = 'Η', class = 'var', cs = 'Eta', alphabet = 'Greek' } -- greek capital letter eta
+ , { code = 0x00398, char = 'Θ', class = 'var', cs = 'Theta', alphabet = 'Greek' } -- greek capital letter theta
+ , { code = 0x00399, char = 'Ι', class = 'var', cs = 'Iota', alphabet = 'Greek' } -- greek capital letter iota
+ , { code = 0x0039A, char = 'Κ', class = 'var', cs = 'Kappa', alphabet = 'Greek' } -- greek capital letter kappa
+ , { code = 0x0039B, char = 'Λ', class = 'var', cs = 'Lambda', alphabet = 'Greek' } -- greek capital letter lamda
+ , { code = 0x0039C, char = 'Μ', class = 'var', cs = 'Mu', alphabet = 'Greek' } -- greek capital letter mu
+ , { code = 0x0039D, char = 'Ν', class = 'var', cs = 'Nu', alphabet = 'Greek' } -- greek capital letter nu
+ , { code = 0x0039E, char = 'Ξ', class = 'var', cs = 'Xi', alphabet = 'Greek' } -- greek capital letter xi
+ , { code = 0x0039F, char = 'Ο', class = 'var', cs = 'Omicron', alphabet = 'Greek' } -- greek capital letter omicron
+ , { code = 0x003A0, char = 'Π', class = 'var', cs = 'Pi', alphabet = 'Greek' } -- greek capital letter pi
+ , { code = 0x003A1, char = 'Ρ', class = 'var', cs = 'Rho', alphabet = 'Greek' } -- greek capital letter rho
+ , { code = 0x003A3, char = 'Σ', class = 'var', cs = 'Sigma', alphabet = 'Greek' } -- greek capital letter sigma
+ , { code = 0x003A4, char = 'Τ', class = 'var', cs = 'Tau', alphabet = 'Greek' } -- greek capital letter tau
+ , { code = 0x003A5, char = 'Υ', class = 'var', cs = 'Upsilon', alphabet = 'Greek' } -- greek capital letter upsilon
+ , { code = 0x003A6, char = 'Φ', class = 'var', cs = 'Phi', alphabet = 'Greek' } -- greek capital letter phi
+ , { code = 0x003A7, char = 'Χ', class = 'var', cs = 'Chi', alphabet = 'Greek' } -- greek capital letter chi
+ , { code = 0x003A8, char = 'Ψ', class = 'var', cs = 'Psi', alphabet = 'Greek' } -- greek capital letter psi
+ , { code = 0x003A9, char = 'Ω', class = 'var', cs = 'Omega', alphabet = 'Greek' } -- greek capital letter omega
+ , { code = 0x003B1, char = 'α', class = 'var', cs = 'alpha', alphabet = 'greek' } -- greek small letter alpha
+ , { code = 0x003B2, char = 'β', class = 'var', cs = 'beta', alphabet = 'greek' } -- greek small letter beta
+ , { code = 0x003B3, char = 'γ', class = 'var', cs = 'gamma', alphabet = 'greek' } -- greek small letter gamma
+ , { code = 0x003B4, char = 'δ', class = 'var', cs = 'delta', alphabet = 'greek' } -- greek small letter delta
+ , { code = 0x003B5, char = 'ε', class = 'var', cs = 'epsilon', alphabet = 'greek' } -- greek small letter epsilon
+ , { code = 0x003B6, char = 'ζ', class = 'var', cs = 'zeta', alphabet = 'greek' } -- greek small letter zeta
+ , { code = 0x003B7, char = 'η', class = 'var', cs = 'eta', alphabet = 'greek' } -- greek small letter eta
+ , { code = 0x003B8, char = 'θ', class = 'var', cs = 'theta', alphabet = 'greek' } -- greek small letter theta
+ , { code = 0x003B9, char = 'ι', class = 'var', cs = 'iota', alphabet = 'greek' } -- greek small letter iota
+ , { code = 0x003BA, char = 'κ', class = 'var', cs = 'kappa', alphabet = 'greek' } -- greek small letter kappa
+ , { code = 0x003BB, char = 'λ', class = 'var', cs = 'lambda', alphabet = 'greek' } -- greek small letter lamda
+ , { code = 0x003BC, char = 'μ', class = 'var', cs = 'mu', alphabet = 'greek' } -- greek small letter mu
+ , { code = 0x003BD, char = 'ν', class = 'var', cs = 'nu', alphabet = 'greek' } -- greek small letter nu
+ , { code = 0x003BE, char = 'ξ', class = 'var', cs = 'xi', alphabet = 'greek' } -- greek small letter xi
+ , { code = 0x003BF, char = 'ο', class = 'var', cs = 'omicron', alphabet = 'greek' } -- greek small letter omicron
+ , { code = 0x003C0, char = 'π', class = 'var', cs = 'pi', alphabet = 'greek' } -- greek small letter pi
+ , { code = 0x003C1, char = 'ρ', class = 'var', cs = 'rho', alphabet = 'greek' } -- greek small letter rho
+ , { code = 0x003C2, char = 'ς', class = 'var', cs = 'varsigma', alphabet = 'greek' } -- greek small letter final sigma
+ , { code = 0x003C3, char = 'σ', class = 'var', cs = 'sigma', alphabet = 'greek' } -- greek small letter sigma
+ , { code = 0x003C4, char = 'τ', class = 'var', cs = 'tau', alphabet = 'greek' } -- greek small letter tau
+ , { code = 0x003C5, char = 'υ', class = 'var', cs = 'upsilon', alphabet = 'greek' } -- greek small letter upsilon
+ , { code = 0x003C6, char = 'φ', class = 'var', cs = 'phi', alphabet = 'greek' } -- greek small letter phi
+ , { code = 0x003C7, char = 'χ', class = 'var', cs = 'chi', alphabet = 'greek' } -- greek small letter chi
+ , { code = 0x003C8, char = 'ψ', class = 'var', cs = 'psi', alphabet = 'greek' } -- greek small letter psi
+ , { code = 0x003C9, char = 'ω', class = 'var', cs = 'omega', alphabet = 'greek' } -- greek small letter omega
+ , { code = 0x003D0, char = 'ϐ', class = 'ord', cs = 'varbeta' } -- greek beta symbol
+ , { code = 0x003D1, char = 'ϑ', class = 'var', cs = 'vartheta', alphabet = 'greek' } -- greek theta symbol
+ , { code = 0x003D5, char = 'ϕ', class = 'var', cs = 'varphi', alphabet = 'greek' } -- greek phi symbol
+ , { code = 0x003D6, char = 'ϖ', class = 'var', cs = 'varpi', alphabet = 'greek' } -- greek pi symbol
+ , { code = 0x003D8, char = 'Ϙ', class = 'ord', cs = 'oldKoppa' } -- greek letter archaic koppa
+ , { code = 0x003D9, char = 'ϙ', class = 'ord', cs = 'oldkoppa' } -- greek small letter archaic koppa
+ , { code = 0x003DA, char = 'Ϛ', class = 'ord', cs = 'Stigma' } -- greek letter stigma
+ , { code = 0x003DB, char = 'ϛ', class = 'ord', cs = 'stigma' } -- greek small letter stigma
+ , { code = 0x003DC, char = 'Ϝ', class = 'ord', cs = 'Digamma' } -- greek letter digamma
+ , { code = 0x003DD, char = 'ϝ', class = 'ord', cs = 'digamma' } -- greek small letter digamma
+ , { code = 0x003DE, char = 'Ϟ', class = 'ord', cs = 'Koppa' } -- greek letter koppa
+ , { code = 0x003DF, char = 'ϟ', class = 'ord', cs = 'koppa' } -- greek small letter koppa
+ , { code = 0x003E0, char = 'Ϡ', class = 'ord', cs = 'Sampi' } -- greek letter sampi
+ , { code = 0x003E1, char = 'ϡ', class = 'ord', cs = 'sampi' } -- greek small letter sampi
+ , { code = 0x003F0, char = 'ϰ', class = 'var', cs = 'varkappa', alphabet = 'greek' } -- greek kappa symbol
+ , { code = 0x003F1, char = 'ϱ', class = 'var', cs = 'varrho', alphabet = 'greek' } -- greek rho symbol
+ , { code = 0x003F4, char = 'ϴ', class = 'var', cs = 'varTheta', alphabet = 'Greek' } -- greek capital theta symbol
+ , { code = 0x003F5, char = 'ϵ', class = 'var', cs = 'varepsilon', alphabet = 'greek' } -- greek lunate epsilon symbol
+ , { code = 0x003F6, char = '϶', class = 'ord', cs = 'backepsilon' } -- greek reversed lunate epsilon symbol
+ , { code = 0x02015, char = '―', class = 'ord', cs = 'horizbar' } -- horizontal bar
+ , { code = 0x02016, char = '‖', class = 'fence', cs = 'Vert' } -- double vertical line
+ , { code = 0x02017, char = '‗', class = 'ord', cs = 'twolowline' } -- double low line
+ , { code = 0x02020, char = '†', class = 'bin', cs = 'dagger' } -- dagger
+ , { code = 0x02021, char = '‡', class = 'bin', cs = 'ddagger' } -- double dagger
+ , { code = 0x02022, char = '•', class = 'bin', cs = 'smblkcircle' } -- bullet
+ , { code = 0x02025, char = '‥', class = 'ord', cs = 'enleadertwodots' } -- two dot leader
+ , { code = 0x02026, char = '…', class = 'ord', cs = 'unicodeellipsis' } -- horizontal ellipsis
+ , { code = 0x02032, char = '′', class = 'ord', cs = 'prime' } -- prime
+ , { code = 0x02033, char = '″', class = 'ord', cs = 'dprime' } -- double prime
+ , { code = 0x02034, char = '‴', class = 'ord', cs = 'trprime' } -- triple prime
+ , { code = 0x02035, char = '‵', class = 'ord', cs = 'backprime' } -- reversed prime
+ , { code = 0x02036, char = '‶', class = 'ord', cs = 'backdprime' } -- reversed double prime
+ , { code = 0x02037, char = '‷', class = 'ord', cs = 'backtrprime' } -- reversed triple prime
+ , { code = 0x02038, char = '‸', class = 'ord', cs = 'caretinsert' } -- caret
+ , { code = 0x0203C, char = '‼', class = 'ord', cs = 'Exclam' } -- double exclamation mark
+ , { code = 0x02040, char = '⁀', class = 'bin', cs = 'tieconcat' } -- char acter tie
+ , { code = 0x02043, char = '⁃', class = 'ord', cs = 'hyphenbullet' } -- hyphen bullet
+ , { code = 0x02044, char = '⁄', class = 'bin', cs = 'fracslash' } -- fraction slash
+ , { code = 0x02047, char = '⁇', class = 'ord', cs = 'Question' } -- double question mark
+ , { code = 0x02050, char = '⁐', class = 'rel', cs = 'closure' } -- close up
+ , { code = 0x02057, char = '⁗', class = 'ord', cs = 'qprime' } -- quadruple prime
+ , { code = 0x020AC, char = '€', class = 'ord', cs = 'euro' } -- euro sign
+ , { code = 0x020D0, char = ' ⃐', class = 'accent', cs = 'leftharpoonaccent' } -- combining left harpoon above
+ , { code = 0x020D1, char = ' ⃑', class = 'accent', cs = 'rightharpoonaccent' } -- combining right harpoon above
+ , { code = 0x020D2, char = ' ⃒', class = 'overlay', cs = 'vertoverlay' } -- combining long vertical line overlay
+ , { code = 0x020D6, char = ' ⃖', class = 'accent', cs = 'overleftarrow' } -- combining left arrow above
+ , { code = 0x020D7, char = ' ⃗', class = 'accent', cs = 'vec' } -- combining right arrow above
+ , { code = 0x020DB, char = ' ⃛', class = 'accent', cs = 'dddot' } -- combining three dots above
+ , { code = 0x020DC, char = ' ⃜', class = 'accent', cs = 'ddddot' } -- combining four dots above
+ , { code = 0x020DD, char = '⃝', class = 'ord', cs = 'enclosecircle' } -- combining enclosing circle
+ , { code = 0x020DE, char = '⃞', class = 'ord', cs = 'enclosesquare' } -- combining enclosing square
+ , { code = 0x020DF, char = '⃟', class = 'ord', cs = 'enclosediamond' } -- combining enclosing iamond
+ , { code = 0x020E1, char = ' ⃡', class = 'accent', cs = 'overleftrightarrow' } -- combining left right arrow above
+ , { code = 0x020E4, char = '⃤', class = 'ord', cs = 'enclosetriangle' } -- combining enclosing upward pointing triangle
+ , { code = 0x020E7, char = ' ⃧', class = 'accent', cs = 'annuity' } -- combining annuity symbol
+ , { code = 0x020E8, char = ' ⃨', class = 'botaccent', cs = 'threeunderdot' } -- combining triple underdot
+ , { code = 0x020E9, char = ' ⃩', class = 'accent', cs = 'widebridgeabove' } -- combining wide bridge above
+ , { code = 0x020EC, char = ' ⃬', class = 'botaccent', cs = 'underrightharpoondown' } -- combining rightwards harpoon with barb downwards
+ , { code = 0x020ED, char = ' ⃭', class = 'botaccent', cs = 'underleftharpoondown' } -- combining leftwards harpoon with barb downwards
+ , { code = 0x020EE, char = ' ⃮', class = 'botaccent', cs = 'underleftarrow' } -- combining left arrow below
+ , { code = 0x020EF, char = ' ⃯', class = 'botaccent', cs = 'underrightarrow' } -- combining right arrow below
+ , { code = 0x020F0, char = ' ⃰', class = 'accent', cs = 'asteraccent' } -- combining asterisk above
+ , { code = 0x02102, char = 'ℂ', class = 'ord', cs = 'BbbC', alphabet = 'blackboard' } -- double-struck capital c
+ , { code = 0x02107, char = 'ℇ', class = 'ord', cs = 'Eulerconst' } -- euler constant
+ , { code = 0x0210A, char = 'ℊ', class = 'ord', cs = 'mscrg', alphabet = 'script' } -- script small g
+ , { code = 0x0210B, char = 'ℋ', class = 'ord', cs = 'mscrH', alphabet = 'script' } -- script capital h
+ , { code = 0x0210C, char = 'ℌ', class = 'ord', cs = 'mfrakH' } -- black-letter capital h
+ , { code = 0x0210D, char = 'ℍ', class = 'ord', cs = 'BbbH', alphabet = 'blackboard' } -- double-struck capital h
+ , { code = 0x0210E, char = 'ℎ', class = 'ord', cs = 'mith' } -- planck constant
+ , { code = 0x0210F, char = 'ℏ', class = 'ord', cs = 'hbar' } -- planck constant over two pi
+ , { code = 0x02110, char = 'ℐ', class = 'ord', cs = 'mscrI', alphabet = 'script' } -- script capital i
+ , { code = 0x02111, char = 'ℑ', class = 'ord', cs = 'Im' } -- black-letter capital i
+ , { code = 0x02112, char = 'ℒ', class = 'ord', cs = 'mscrL', alphabet = 'script' } -- script capital l
+ , { code = 0x02113, char = 'ℓ', class = 'ord', cs = 'ell', alphabet = 'script' } -- script small l
+ , { code = 0x02115, char = 'ℕ', class = 'ord', cs = 'BbbN', alphabet = 'blackboard' } -- double-struck capital n
+ , { code = 0x02118, char = '℘', class = 'ord', cs = 'wp', } -- weierstrass elliptic function
+ , { code = 0x02119, char = 'ℙ', class = 'ord', cs = 'BbbP', alphabet = 'blackboard' } -- double-struck capital p
+ , { code = 0x0211A, char = 'ℚ', class = 'ord', cs = 'BbbQ', alphabet = 'blackboard' } -- double-struck capital q
+ , { code = 0x0211B, char = 'ℛ', class = 'ord', cs = 'mscrR', alphabet = 'script' } -- script capital r
+ , { code = 0x0211C, char = 'ℜ', class = 'ord', cs = 'Re' } -- black-letter capital r
+ , { code = 0x0211D, char = 'ℝ', class = 'ord', cs = 'BbbR', alphabet = 'blackboard' } -- double-struck capital r
+ , { code = 0x02124, char = 'ℤ', class = 'ord', cs = 'BbbZ', alphabet = 'blackboard' } -- double-struck capital z
+ , { code = 0x02127, char = '℧', class = 'ord', cs = 'mho' } -- inverted ohm sign
+ , { code = 0x02128, char = 'ℨ', class = 'ord', cs = 'mfrakZ' } -- black-letter capital z
+ , { code = 0x02129, char = '℩', class = 'ord', cs = 'turnediota' } -- turned greek small letter iota
+ , { code = 0x0212B, char = 'Å', class = 'ord', cs = 'Angstrom' } -- angstrom sign
+ , { code = 0x0212C, char = 'ℬ', class = 'ord', cs = 'mscrB', alphabet = 'script' } -- script capital b
+ , { code = 0x0212D, char = 'ℭ', class = 'ord', cs = 'mfrakC' } -- black-letter capital c
+ , { code = 0x0212F, char = 'ℯ', class = 'ord', cs = 'mscre', alphabet = 'script' } -- script small e
+ , { code = 0x02130, char = 'ℰ', class = 'ord', cs = 'mscrE', alphabet = 'script' } -- script capital e
+ , { code = 0x02131, char = 'ℱ', class = 'ord', cs = 'mscrF', alphabet = 'script' } -- script capital f
+ , { code = 0x02132, char = 'Ⅎ', class = 'ord', cs = 'Finv' } -- turned capital f
+ , { code = 0x02133, char = 'ℳ', class = 'ord', cs = 'mscrM', alphabet = 'script' } -- script capital m
+ , { code = 0x02134, char = 'ℴ', class = 'ord', cs = 'mscro', alphabet = 'script' } -- script small o
+ , { code = 0x02135, char = 'ℵ', class = 'ord', cs = 'aleph' } -- alef symbol
+ , { code = 0x02136, char = 'ℶ', class = 'ord', cs = 'beth' } -- bet symbol
+ , { code = 0x02137, char = 'ℷ', class = 'ord', cs = 'gimel' } -- gimel symbol
+ , { code = 0x02138, char = 'ℸ', class = 'ord', cs = 'daleth' } -- dalet symbol
+ , { code = 0x0213C, char = 'ℼ', class = 'ord', cs = 'Bbbpi', alphabet = 'blackboard' } -- double-struck small pi
+ , { code = 0x0213D, char = 'ℽ', class = 'ord', cs = 'Bbbgamma', alphabet = 'blackboard' } -- double-struck small gamma
+ , { code = 0x0213E, char = 'ℾ', class = 'ord', cs = 'BbbGamma', alphabet = 'blackboard' } -- double-struck capital gamma
+ , { code = 0x0213F, char = 'ℿ', class = 'ord', cs = 'BbbPi', alphabet = 'blackboard' } -- double-struck capital pi
+ , { code = 0x02140, char = '⅀', class = 'op', cs = 'Bbbsum', alphabet = 'blackboard' } -- double-struck n-ary summation
+ , { code = 0x02141, char = '⅁', class = 'ord', cs = 'Game' } -- turned sans-serif capital g
+ , { code = 0x02142, char = '⅂', class = 'ord', cs = 'sansLturned' } -- turned sans-serif capital l
+ , { code = 0x02143, char = '⅃', class = 'ord', cs = 'sansLmirrored' } -- reversed sans-serif capital l
+ , { code = 0x02144, char = '⅄', class = 'ord', cs = 'Yup' } -- turned sans-serif capital y
+ , { code = 0x02145, char = 'ⅅ', class = 'ord', cs = 'mitBbbD', alphabet = 'blackboard' } -- double-struck italic capital d
+ , { code = 0x02146, char = 'ⅆ', class = 'ord', cs = 'mitBbbd', alphabet = 'blackboard' } -- double-struck italic small d
+ , { code = 0x02147, char = 'ⅇ', class = 'ord', cs = 'mitBbbe', alphabet = 'blackboard' } -- double-struck italic small e
+ , { code = 0x02148, char = 'ⅈ', class = 'ord', cs = 'mitBbbi', alphabet = 'blackboard' } -- double-struck italic small i
+ , { code = 0x02149, char = 'ⅉ', class = 'ord', cs = 'mitBbbj', alphabet = 'blackboard' } -- double-struck italic small j
+ , { code = 0x0214A, char = '⅊', class = 'ord', cs = 'PropertyLine' } -- property line
+ , { code = 0x0214B, char = '⅋', class = 'bin', cs = 'upand' } -- turned ampersand
+ , { code = 0x02190, char = '←', class = 'rel', cs = 'leftarrow' } -- leftwards arrow
+ , { code = 0x02191, char = '↑', class = 'rel', cs = 'uparrow' } -- upwards arrow
+ , { code = 0x02192, char = '→', class = 'rel', cs = 'rightarrow' } -- rightwards arrow
+ , { code = 0x02193, char = '↓', class = 'rel', cs = 'downarrow' } -- downwards arrow
+ , { code = 0x02194, char = '↔', class = 'rel', cs = 'leftrightarrow' } -- left right arrow
+ , { code = 0x02195, char = '↕', class = 'rel', cs = 'updownarrow' } -- up down arrow
+ , { code = 0x02196, char = '↖', class = 'rel', cs = 'nwarrow' } -- north west arrow
+ , { code = 0x02197, char = '↗', class = 'rel', cs = 'nearrow' } -- north east arrow
+ , { code = 0x02198, char = '↘', class = 'rel', cs = 'searrow' } -- south east arrow
+ , { code = 0x02199, char = '↙', class = 'rel', cs = 'swarrow' } -- south west arrow
+ , { code = 0x0219A, char = '↚', class = 'rel', cs = 'nleftarrow' } -- leftwards arrow with stroke
+ , { code = 0x0219B, char = '↛', class = 'rel', cs = 'nrightarrow' } -- rightwards arrow with stroke
+ , { code = 0x0219C, char = '↜', class = 'rel', cs = 'leftwavearrow' } -- leftwards wave arrow
+ , { code = 0x0219D, char = '↝', class = 'rel', cs = 'rightwavearrow' } -- rightwards wave arrow
+ , { code = 0x0219E, char = '↞', class = 'rel', cs = 'twoheadleftarrow' } -- leftwards two headed arrow
+ , { code = 0x0219F, char = '↟', class = 'rel', cs = 'twoheaduparrow' } -- upwards two headed arrow
+ , { code = 0x021A0, char = '↠', class = 'rel', cs = 'twoheadrightarrow' } -- rightwards two headed arrow
+ , { code = 0x021A1, char = '↡', class = 'rel', cs = 'twoheaddownarrow' } -- downwards two headed arrow
+ , { code = 0x021A2, char = '↢', class = 'rel', cs = 'leftarrowtail' } -- leftwards arrow with tail
+ , { code = 0x021A3, char = '↣', class = 'rel', cs = 'rightarrowtail' } -- rightwards arrow with tail
+ , { code = 0x021A4, char = '↤', class = 'rel', cs = 'mapsfrom' } -- leftwards arrow from bar
+ , { code = 0x021A5, char = '↥', class = 'rel', cs = 'mapsup' } -- upwards arrow from bar
+ , { code = 0x021A6, char = '↦', class = 'rel', cs = 'mapsto' } -- rightwards arrow from bar
+ , { code = 0x021A7, char = '↧', class = 'rel', cs = 'mapsdown' } -- downwards arrow from bar
+ , { code = 0x021A8, char = '↨', class = 'ord', cs = 'updownarrowbar' } -- up down arrow with base
+ , { code = 0x021A9, char = '↩', class = 'rel', cs = 'hookleftarrow' } -- leftwards arrow with hook
+ , { code = 0x021AA, char = '↪', class = 'rel', cs = 'hookrightarrow' } -- rightwards arrow with hook
+ , { code = 0x021AB, char = '↫', class = 'rel', cs = 'looparrowleft' } -- leftwards arrow with loop
+ , { code = 0x021AC, char = '↬', class = 'rel', cs = 'looparrowright' } -- rightwards arrow with loop
+ , { code = 0x021AD, char = '↭', class = 'rel', cs = 'leftrightsquigarrow' } -- left right wave arrow
+ , { code = 0x021AE, char = '↮', class = 'rel', cs = 'nleftrightarrow' } -- left right arrow with stroke
+ , { code = 0x021AF, char = '↯', class = 'rel', cs = 'downzigzagarrow' } -- downwards zigzag arrow
+ , { code = 0x021B0, char = '↰', class = 'rel', cs = 'Lsh' } -- upwards arrow with tip leftwards
+ , { code = 0x021B1, char = '↱', class = 'rel', cs = 'Rsh' } -- upwards arrow with tip rightwards
+ , { code = 0x021B2, char = '↲', class = 'rel', cs = 'Ldsh' } -- downwards arrow with tip leftwards
+ , { code = 0x021B3, char = '↳', class = 'rel', cs = 'Rdsh' } -- downwards arrow with tip rightwards
+ , { code = 0x021B4, char = '↴', class = 'ord', cs = 'linefeed' } -- rightwards arrow with corner downwards
+ , { code = 0x021B5, char = '↵', class = 'ord', cs = 'carriagereturn' } -- downwards arrow with corner leftwards
+ , { code = 0x021B6, char = '↶', class = 'rel', cs = 'curvearrowleft' } -- anticlockwise top semicircle arrow
+ , { code = 0x021B7, char = '↷', class = 'rel', cs = 'curvearrowright' } -- clockwise top semicircle arrow
+ , { code = 0x021B8, char = '↸', class = 'ord', cs = 'barovernorthwestarrow' } -- north west arrow to long bar
+ , { code = 0x021B9, char = '↹', class = 'ord', cs = 'barleftarrowrightarrowbar' } -- leftwards arrow to bar over rightwards arrow to bar
+ , { code = 0x021BA, char = '↺', class = 'ord', cs = 'acwopencirclearrow' } -- anticlockwise open circle arrow
+ , { code = 0x021BB, char = '↻', class = 'ord', cs = 'cwopencirclearrow' } -- clockwise open circle arrow
+ , { code = 0x021BC, char = '↼', class = 'rel', cs = 'leftharpoonup' } -- leftwards harpoon with barb upwards
+ , { code = 0x021BD, char = '↽', class = 'rel', cs = 'leftharpoondown' } -- leftwards harpoon with barb downwards
+ , { code = 0x021BE, char = '↾', class = 'rel', cs = 'upharpoonright' } -- upwards harpoon with barb rightwards
+ , { code = 0x021BF, char = '↿', class = 'rel', cs = 'upharpoonleft' } -- upwards harpoon with barb leftwards
+ , { code = 0x021C0, char = '⇀', class = 'rel', cs = 'rightharpoonup' } -- rightwards harpoon with barb upwards
+ , { code = 0x021C1, char = '⇁', class = 'rel', cs = 'rightharpoondown' } -- rightwards harpoon with barb downwards
+ , { code = 0x021C2, char = '⇂', class = 'rel', cs = 'downharpoonright' } -- downwards harpoon with barb rightwards
+ , { code = 0x021C3, char = '⇃', class = 'rel', cs = 'downharpoonleft' } -- downwards harpoon with barb leftwards
+ , { code = 0x021C4, char = '⇄', class = 'rel', cs = 'rightleftarrows' } -- rightwards arrow over leftwards arrow
+ , { code = 0x021C5, char = '⇅', class = 'rel', cs = 'updownarrows' } -- upwards arrow leftwards of downwards arrow
+ , { code = 0x021C6, char = '⇆', class = 'rel', cs = 'leftrightarrows' } -- leftwards arrow over rightwards arrow
+ , { code = 0x021C7, char = '⇇', class = 'rel', cs = 'leftleftarrows' } -- leftwards paired arrows
+ , { code = 0x021C8, char = '⇈', class = 'rel', cs = 'upuparrows' } -- upwards paired arrows
+ , { code = 0x021C9, char = '⇉', class = 'rel', cs = 'rightrightarrows' } -- rightwards paired arrows
+ , { code = 0x021CA, char = '⇊', class = 'rel', cs = 'downdownarrows' } -- downwards paired arrows
+ , { code = 0x021CB, char = '⇋', class = 'rel', cs = 'leftrightharpoons' } -- leftwards harpoon over rightwards harpoon
+ , { code = 0x021CC, char = '⇌', class = 'rel', cs = 'rightleftharpoons' } -- rightwards harpoon over leftwards harpoon
+ , { code = 0x021CD, char = '⇍', class = 'rel', cs = 'nLeftarrow' } -- leftwards double arrow with stroke
+ , { code = 0x021CE, char = '⇎', class = 'rel', cs = 'nLeftrightarrow' } -- left right double arrow with stroke
+ , { code = 0x021CF, char = '⇏', class = 'rel', cs = 'nRightarrow' } -- rightwards double arrow with stroke
+ , { code = 0x021D0, char = '⇐', class = 'rel', cs = 'Leftarrow' } -- leftwards double arrow
+ , { code = 0x021D1, char = '⇑', class = 'rel', cs = 'Uparrow' } -- upwards double arrow
+ , { code = 0x021D2, char = '⇒', class = 'rel', cs = 'Rightarrow' } -- rightwards double arrow
+ , { code = 0x021D3, char = '⇓', class = 'rel', cs = 'Downarrow' } -- downwards double arrow
+ , { code = 0x021D4, char = '⇔', class = 'rel', cs = 'Leftrightarrow' } -- left right double arrow
+ , { code = 0x021D5, char = '⇕', class = 'rel', cs = 'Updownarrow' } -- up down double arrow
+ , { code = 0x021D6, char = '⇖', class = 'rel', cs = 'Nwarrow' } -- north west double arrow
+ , { code = 0x021D7, char = '⇗', class = 'rel', cs = 'Nearrow' } -- north east double arrow
+ , { code = 0x021D8, char = '⇘', class = 'rel', cs = 'Searrow' } -- south east double arrow
+ , { code = 0x021D9, char = '⇙', class = 'rel', cs = 'Swarrow' } -- south west double arrow
+ , { code = 0x021DA, char = '⇚', class = 'rel', cs = 'Lleftarrow' } -- leftwards triple arrow
+ , { code = 0x021DB, char = '⇛', class = 'rel', cs = 'Rrightarrow' } -- rightwards triple arrow
+ , { code = 0x021DC, char = '⇜', class = 'rel', cs = 'leftsquigarrow' } -- leftwards squiggle arrow
+ , { code = 0x021DD, char = '⇝', class = 'rel', cs = 'rightsquigarrow' } -- rightwards squiggle arrow
+ , { code = 0x021DE, char = '⇞', class = 'ord', cs = 'nHuparrow' } -- upwards arrow with double stroke
+ , { code = 0x021DF, char = '⇟', class = 'ord', cs = 'nHdownarrow' } -- downwards arrow with double stroke
+ , { code = 0x021E0, char = '⇠', class = 'ord', cs = 'leftdasharrow' } -- leftwards dashed arrow
+ , { code = 0x021E1, char = '⇡', class = 'ord', cs = 'updasharrow' } -- upwards dashed arrow
+ , { code = 0x021E2, char = '⇢', class = 'ord', cs = 'rightdasharrow' } -- rightwards dashed arrow
+ , { code = 0x021E3, char = '⇣', class = 'ord', cs = 'downdasharrow' } -- downwards dashed arrow
+ , { code = 0x021E4, char = '⇤', class = 'rel', cs = 'barleftarrow' } -- leftwards arrow to bar
+ , { code = 0x021E5, char = '⇥', class = 'rel', cs = 'rightarrowbar' } -- rightwards arrow to bar
+ , { code = 0x021E6, char = '⇦', class = 'ord', cs = 'leftwhitearrow' } -- leftwards white arrow
+ , { code = 0x021E7, char = '⇧', class = 'ord', cs = 'upwhitearrow' } -- upwards white arrow
+ , { code = 0x021E8, char = '⇨', class = 'ord', cs = 'rightwhitearrow' } -- rightwards white arrow
+ , { code = 0x021E9, char = '⇩', class = 'ord', cs = 'downwhitearrow' } -- downwards white arrow
+ , { code = 0x021EA, char = '⇪', class = 'ord', cs = 'whitearrowupfrombar' } -- upwards white arrow from bar
+ , { code = 0x021F4, char = '⇴', class = 'rel', cs = 'circleonrightarrow' } -- right arrow with small circle
+ , { code = 0x021F5, char = '⇵', class = 'rel', cs = 'downuparrows' } -- downwards arrow leftwards of upwards arrow
+ , { code = 0x021F6, char = '⇶', class = 'rel', cs = 'rightthreearrows' } -- three rightwards arrows
+ , { code = 0x021F7, char = '⇷', class = 'rel', cs = 'nvleftarrow' } -- leftwards arrow with vertical stroke
+ , { code = 0x021F8, char = '⇸', class = 'rel', cs = 'nvrightarrow' } -- rightwards arrow with vertical stroke
+ , { code = 0x021F9, char = '⇹', class = 'rel', cs = 'nvleftrightarrow' } -- left right arrow with vertical stroke
+ , { code = 0x021FA, char = '⇺', class = 'rel', cs = 'nVleftarrow' } -- leftwards arrow with double vertical stroke
+ , { code = 0x021FB, char = '⇻', class = 'rel', cs = 'nVrightarrow' } -- rightwards arrow with double vertical stroke
+ , { code = 0x021FC, char = '⇼', class = 'rel', cs = 'nVleftrightarrow' } -- left right arrow with double vertical stroke
+ , { code = 0x021FD, char = '⇽', class = 'rel', cs = 'leftarrowtriangle' } -- leftwards open-headed arrow
+ , { code = 0x021FE, char = '⇾', class = 'rel', cs = 'rightarrowtriangle' } -- rightwards open-headed arrow
+ , { code = 0x021FF, char = '⇿', class = 'rel', cs = 'leftrightarrowtriangle' } -- left right open-headed arrow
+ , { code = 0x02200, char = '∀', class = 'ord', cs = 'forall' } -- for all
+ , { code = 0x02201, char = '∁', class = 'ord', cs = 'complement' } -- complement
+ , { code = 0x02202, char = '∂', class = 'var', cs = 'partial' } -- partial differential
+ , { code = 0x02203, char = '∃', class = 'ord', cs = 'exists' } -- there exists
+ , { code = 0x02204, char = '∄', class = 'ord', cs = 'nexists' } -- there does not exist
+ , { code = 0x02205, char = '∅', class = 'ord', cs = 'varnothing' } -- empty set
+ , { code = 0x02206, char = '∆', class = 'ord', cs = 'increment' } -- increment
+ , { code = 0x02207, char = '∇', class = 'var', cs = 'nabla' } -- nabla
+ , { code = 0x02208, char = '∈', class = 'rel', cs = 'in' } -- element of
+ , { code = 0x02209, char = '∉', class = 'rel', cs = 'notin' } -- not an element of
+ , { code = 0x0220A, char = '∊', class = 'rel', cs = 'smallin' } -- small element of
+ , { code = 0x0220B, char = '∋', class = 'rel', cs = 'ni' } -- contains as member
+ , { code = 0x0220C, char = '∌', class = 'rel', cs = 'nni' } -- does not contain as member
+ , { code = 0x0220D, char = '∍', class = 'rel', cs = 'smallni' } -- small contains as member
+ , { code = 0x0220E, char = '∎', class = 'ord', cs = 'QED' } -- end of proof
+ , { code = 0x0220F, char = '∏', class = 'op', cs = 'prod' } -- n-ary product
+ , { code = 0x02210, char = '∐', class = 'op', cs = 'coprod' } -- n-ary coproduct
+ , { code = 0x02211, char = '∑', class = 'op', cs = 'sum' } -- n-ary summation
+ , { code = 0x02212, char = '−', class = 'bin', cs = 'minus' } -- minus sign
+ , { code = 0x02213, char = '∓', class = 'bin', cs = 'mp' } -- minus-or-plus sign
+ , { code = 0x02214, char = '∔', class = 'bin', cs = 'dotplus' } -- dot plus
+ , { code = 0x02215, char = '∕', class = 'bin', cs = 'divslash' } -- division slash
+ , { code = 0x02216, char = '∖', class = 'bin', cs = 'smallsetminus' } -- set minus
+ , { code = 0x02217, char = '∗', class = 'bin', cs = 'ast' } -- asterisk operator
+ , { code = 0x02218, char = '∘', class = 'bin', cs = 'vysmwhtcircle' } -- ring operator
+ , { code = 0x02219, char = '∙', class = 'bin', cs = 'vysmblkcircle' } -- bullet operator
+ , { code = 0x0221A, char = '√', class = 'radical', cs = 'sqrt' } -- square root
+ , { code = 0x0221B, char = '∛', class = 'radical', cs = 'cuberoot' } -- cube root
+ , { code = 0x0221C, char = '∜', class = 'radical', cs = 'fourthroot' } -- fourth root
+ , { code = 0x0221D, char = '∝', class = 'rel', cs = 'propto' } -- proportional to
+ , { code = 0x0221E, char = '∞', class = 'ord', cs = 'infty' } -- infinity
+ , { code = 0x0221F, char = '∟', class = 'ord', cs = 'rightangle' } -- right angle
+ , { code = 0x02220, char = '∠', class = 'ord', cs = 'angle' } -- angle
+ , { code = 0x02221, char = '∡', class = 'ord', cs = 'measuredangle' } -- measured angle
+ , { code = 0x02222, char = '∢', class = 'ord', cs = 'sphericalangle' } -- spherical angle
+ , { code = 0x02223, char = '∣', class = 'rel', cs = 'mid' } -- divides
+ , { code = 0x02224, char = '∤', class = 'rel', cs = 'nmid' } -- does not divide
+ , { code = 0x02225, char = '∥', class = 'rel', cs = 'parallel' } -- parallel to
+ , { code = 0x02226, char = '∦', class = 'rel', cs = 'nparallel' } -- not parallel to
+ , { code = 0x02227, char = '∧', class = 'bin', cs = 'wedge' } -- logical and
+ , { code = 0x02228, char = '∨', class = 'bin', cs = 'vee' } -- logical or
+ , { code = 0x02229, char = '∩', class = 'bin', cs = 'cap' } -- intersection
+ , { code = 0x0222A, char = '∪', class = 'bin', cs = 'cup' } -- union
+ , { code = 0x0222B, char = '∫', class = 'op', cs = 'intop' } -- integral
+ , { code = 0x0222C, char = '∬', class = 'op', cs = 'iintop' } -- double integral
+ , { code = 0x0222D, char = '∭', class = 'op', cs = 'iiintop' } -- triple integral
+ , { code = 0x0222E, char = '∮', class = 'op', cs = 'ointop' } -- contour integral
+ , { code = 0x0222F, char = '∯', class = 'op', cs = 'oiintop' } -- surface integral
+ , { code = 0x02230, char = '∰', class = 'op', cs = 'oiiintop' } -- volume integral
+ , { code = 0x02231, char = '∱', class = 'op', cs = 'intclockwiseop' } -- clockwise integral
+ , { code = 0x02232, char = '∲', class = 'op', cs = 'varointclockwiseop' } -- clockwise contour integral
+ , { code = 0x02233, char = '∳', class = 'op', cs = 'ointctrclockwiseop' } -- anticlockwise contour integral
+ , { code = 0x02234, char = '∴', class = 'ord', cs = 'therefore' } -- therefore
+ , { code = 0x02235, char = '∵', class = 'ord', cs = 'because' } -- because
+ , { code = 0x02236, char = '∶', class = 'rel', cs = 'ratio' } -- ratio
+ , { code = 0x02237, char = '∷', class = 'rel', cs = 'Colon' } -- proportion
+ , { code = 0x02238, char = '∸', class = 'bin', cs = 'dotminus' } -- dot minus
+ , { code = 0x02239, char = '∹', class = 'rel', cs = 'dashcolon' } -- excess
+ , { code = 0x0223A, char = '∺', class = 'rel', cs = 'dotsminusdots' } -- geometric proportion
+ , { code = 0x0223B, char = '∻', class = 'rel', cs = 'kernelcontraction' } -- homothetic
+ , { code = 0x0223C, char = '∼', class = 'rel', cs = 'sim' } -- tilde operator
+ , { code = 0x0223D, char = '∽', class = 'rel', cs = 'backsim' } -- reversed tilde
+ , { code = 0x0223E, char = '∾', class = 'bin', cs = 'invlazys' } -- inverted lazy s
+ , { code = 0x0223F, char = '∿', class = 'ord', cs = 'sinewave' } -- sine wave
+ , { code = 0x02240, char = '≀', class = 'bin', cs = 'wr' } -- wreath product
+ , { code = 0x02241, char = '≁', class = 'rel', cs = 'nsim' } -- not tilde
+ , { code = 0x02242, char = '≂', class = 'rel', cs = 'eqsim' } -- minus tilde
+ , { code = 0x02243, char = '≃', class = 'rel', cs = 'simeq' } -- asymptotically equal to
+ , { code = 0x02244, char = '≄', class = 'rel', cs = 'nsimeq' } -- not asymptotically equal to
+ , { code = 0x02245, char = '≅', class = 'rel', cs = 'cong' } -- approximately equal to
+ , { code = 0x02246, char = '≆', class = 'rel', cs = 'simneqq' } -- approximately but not actually equal to
+ , { code = 0x02247, char = '≇', class = 'rel', cs = 'ncong' } -- neither approximately nor actually equal to
+ , { code = 0x02248, char = '≈', class = 'rel', cs = 'approx' } -- almost equal to
+ , { code = 0x02249, char = '≉', class = 'rel', cs = 'napprox' } -- not almost equal to
+ , { code = 0x0224A, char = '≊', class = 'rel', cs = 'approxeq' } -- almost equal or equal to
+ , { code = 0x0224B, char = '≋', class = 'rel', cs = 'approxident' } -- triple tilde
+ , { code = 0x0224C, char = '≌', class = 'rel', cs = 'backcong' } -- all equal to
+ , { code = 0x0224D, char = '≍', class = 'rel', cs = 'asymp' } -- equivalent to
+ , { code = 0x0224E, char = '≎', class = 'rel', cs = 'Bumpeq' } -- geometrically equivalent to
+ , { code = 0x0224F, char = '≏', class = 'rel', cs = 'bumpeq' } -- difference between
+ , { code = 0x02250, char = '≐', class = 'rel', cs = 'doteq' } -- approaches the limit
+ , { code = 0x02251, char = '≑', class = 'rel', cs = 'Doteq' } -- geometrically equal to
+ , { code = 0x02252, char = '≒', class = 'rel', cs = 'fallingdotseq' } -- approximately equal to or the image of
+ , { code = 0x02253, char = '≓', class = 'rel', cs = 'risingdotseq' } -- image of or approximately equal to
+ , { code = 0x02254, char = '≔', class = 'rel', cs = 'coloneq' } -- colon equals
+ , { code = 0x02255, char = '≕', class = 'rel', cs = 'eqcolon' } -- equals colon
+ , { code = 0x02256, char = '≖', class = 'rel', cs = 'eqcirc' } -- ring in equal to
+ , { code = 0x02257, char = '≗', class = 'rel', cs = 'circeq' } -- ring equal to
+ , { code = 0x02258, char = '≘', class = 'rel', cs = 'arceq' } -- corresponds to
+ , { code = 0x02259, char = '≙', class = 'rel', cs = 'wedgeq' } -- estimates
+ , { code = 0x0225A, char = '≚', class = 'rel', cs = 'veeeq' } -- equiangular to
+ , { code = 0x0225B, char = '≛', class = 'rel', cs = 'stareq' } -- star equals
+ , { code = 0x0225C, char = '≜', class = 'rel', cs = 'triangleq' } -- delta equal to
+ , { code = 0x0225D, char = '≝', class = 'rel', cs = 'eqdef' } -- equal to by definition
+ , { code = 0x0225E, char = '≞', class = 'rel', cs = 'measeq' } -- measured by
+ , { code = 0x0225F, char = '≟', class = 'rel', cs = 'questeq' } -- questioned equal to
+ , { code = 0x02260, char = '≠', class = 'rel', cs = 'ne' } -- not equal to
+ , { code = 0x02261, char = '≡', class = 'rel', cs = 'equiv' } -- identical to
+ , { code = 0x02262, char = '≢', class = 'rel', cs = 'nequiv' } -- not identical to
+ , { code = 0x02263, char = '≣', class = 'rel', cs = 'Equiv' } -- strictly equivalent to
+ , { code = 0x02264, char = '≤', class = 'rel', cs = 'leq' } -- less-than or equal to
+ , { code = 0x02265, char = '≥', class = 'rel', cs = 'geq' } -- greater-than or equal to
+ , { code = 0x02266, char = '≦', class = 'rel', cs = 'leqq' } -- less-than over equal to
+ , { code = 0x02267, char = '≧', class = 'rel', cs = 'geqq' } -- greater-than over equal to
+ , { code = 0x02268, char = '≨', class = 'rel', cs = 'lneqq' } -- less-than but not equal to
+ , { code = 0x02269, char = '≩', class = 'rel', cs = 'gneqq' } -- greater-than but not equal to
+ , { code = 0x0226A, char = '≪', class = 'rel', cs = 'll' } -- much less-than
+ , { code = 0x0226B, char = '≫', class = 'rel', cs = 'gg' } -- much greater-than
+ , { code = 0x0226C, char = '≬', class = 'rel', cs = 'between' } -- between
+ , { code = 0x0226D, char = '≭', class = 'rel', cs = 'nasymp' } -- not equivalent to
+ , { code = 0x0226E, char = '≮', class = 'rel', cs = 'nless' } -- not less-than
+ , { code = 0x0226F, char = '≯', class = 'rel', cs = 'ngtr' } -- not greater-than
+ , { code = 0x02270, char = '≰', class = 'rel', cs = 'nleq' } -- neither less-than nor equal to
+ , { code = 0x02271, char = '≱', class = 'rel', cs = 'ngeq' } -- neither greater-than nor equal to
+ , { code = 0x02272, char = '≲', class = 'rel', cs = 'lesssim' } -- less-than or equivalent to
+ , { code = 0x02273, char = '≳', class = 'rel', cs = 'gtrsim' } -- greater-than or equivalent to
+ , { code = 0x02274, char = '≴', class = 'rel', cs = 'nlesssim' } -- neither less-than nor equivalent to
+ , { code = 0x02275, char = '≵', class = 'rel', cs = 'ngtrsim' } -- neither greater-than nor equivalent to
+ , { code = 0x02276, char = '≶', class = 'rel', cs = 'lessgtr' } -- less-than or greater-than
+ , { code = 0x02277, char = '≷', class = 'rel', cs = 'gtrless' } -- greater-than or less-than
+ , { code = 0x02278, char = '≸', class = 'rel', cs = 'nlessgtr' } -- neither less-than nor greater-than
+ , { code = 0x02279, char = '≹', class = 'rel', cs = 'ngtrless' } -- neither greater-than nor less-than
+ , { code = 0x0227A, char = '≺', class = 'rel', cs = 'prec' } -- precedes
+ , { code = 0x0227B, char = '≻', class = 'rel', cs = 'succ' } -- succeeds
+ , { code = 0x0227C, char = '≼', class = 'rel', cs = 'preccurlyeq' } -- precedes or equal to
+ , { code = 0x0227D, char = '≽', class = 'rel', cs = 'succcurlyeq' } -- succeeds or equal to
+ , { code = 0x0227E, char = '≾', class = 'rel', cs = 'precsim' } -- precedes or equivalent to
+ , { code = 0x0227F, char = '≿', class = 'rel', cs = 'succsim' } -- succeeds or equivalent to
+ , { code = 0x02280, char = '⊀', class = 'rel', cs = 'nprec' } -- does not precede
+ , { code = 0x02281, char = '⊁', class = 'rel', cs = 'nsucc' } -- does not succeed
+ , { code = 0x02282, char = '⊂', class = 'rel', cs = 'subset' } -- subset of
+ , { code = 0x02283, char = '⊃', class = 'rel', cs = 'supset' } -- superset of
+ , { code = 0x02284, char = '⊄', class = 'rel', cs = 'nsubset' } -- not a subset of
+ , { code = 0x02285, char = '⊅', class = 'rel', cs = 'nsupset' } -- not a superset of
+ , { code = 0x02286, char = '⊆', class = 'rel', cs = 'subseteq' } -- subset of or equal to
+ , { code = 0x02287, char = '⊇', class = 'rel', cs = 'supseteq' } -- superset of or equal to
+ , { code = 0x02288, char = '⊈', class = 'rel', cs = 'nsubseteq' } -- neither a subset of nor equal to
+ , { code = 0x02289, char = '⊉', class = 'rel', cs = 'nsupseteq' } -- neither a superset of nor equal to
+ , { code = 0x0228A, char = '⊊', class = 'rel', cs = 'subsetneq' } -- subset of with not equal to
+ , { code = 0x0228B, char = '⊋', class = 'rel', cs = 'supsetneq' } -- superset of with not equal to
+ , { code = 0x0228C, char = '⊌', class = 'bin', cs = 'cupleftarrow' } -- multiset
+ , { code = 0x0228D, char = '⊍', class = 'bin', cs = 'cupdot' } -- multiset multiplication
+ , { code = 0x0228E, char = '⊎', class = 'bin', cs = 'uplus' } -- multiset union
+ , { code = 0x0228F, char = '⊏', class = 'rel', cs = 'sqsubset' } -- square image of
+ , { code = 0x02290, char = '⊐', class = 'rel', cs = 'sqsupset' } -- square original of
+ , { code = 0x02291, char = '⊑', class = 'rel', cs = 'sqsubseteq' } -- square image of or equal to
+ , { code = 0x02292, char = '⊒', class = 'rel', cs = 'sqsupseteq' } -- square original of or equal to
+ , { code = 0x02293, char = '⊓', class = 'bin', cs = 'sqcap' } -- square cap
+ , { code = 0x02294, char = '⊔', class = 'bin', cs = 'sqcup' } -- square cup
+ , { code = 0x02295, char = '⊕', class = 'bin', cs = 'oplus' } -- circled plus
+ , { code = 0x02296, char = '⊖', class = 'bin', cs = 'ominus' } -- circled minus
+ , { code = 0x02297, char = '⊗', class = 'bin', cs = 'otimes' } -- circled times
+ , { code = 0x02298, char = '⊘', class = 'bin', cs = 'oslash' } -- circled division slash
+ , { code = 0x02299, char = '⊙', class = 'bin', cs = 'odot' } -- circled dot operator
+ , { code = 0x0229A, char = '⊚', class = 'bin', cs = 'circledcirc' } -- circled ring operator
+ , { code = 0x0229B, char = '⊛', class = 'bin', cs = 'circledast' } -- circled asterisk operator
+ , { code = 0x0229C, char = '⊜', class = 'bin', cs = 'circledequal' } -- circled equals
+ , { code = 0x0229D, char = '⊝', class = 'bin', cs = 'circleddash' } -- circled dash
+ , { code = 0x0229E, char = '⊞', class = 'bin', cs = 'boxplus' } -- squared plus
+ , { code = 0x0229F, char = '⊟', class = 'bin', cs = 'boxminus' } -- squared minus
+ , { code = 0x022A0, char = '⊠', class = 'bin', cs = 'boxtimes' } -- squared times
+ , { code = 0x022A1, char = '⊡', class = 'bin', cs = 'boxdot' } -- squared dot operator
+ , { code = 0x022A2, char = '⊢', class = 'rel', cs = 'vdash' } -- right tack
+ , { code = 0x022A3, char = '⊣', class = 'rel', cs = 'dashv' } -- left tack
+ , { code = 0x022A4, char = '⊤', class = 'ord', cs = 'top' } -- down tack
+ , { code = 0x022A5, char = '⊥', class = 'ord', cs = 'bot' } -- up tack
+ , { code = 0x022A6, char = '⊦', class = 'rel', cs = 'assert' } -- assertion
+ , { code = 0x022A7, char = '⊧', class = 'rel', cs = 'models' } -- models
+ , { code = 0x022A8, char = '⊨', class = 'rel', cs = 'vDash' } -- true
+ , { code = 0x022A9, char = '⊩', class = 'rel', cs = 'Vdash' } -- forces
+ , { code = 0x022AA, char = '⊪', class = 'rel', cs = 'Vvdash' } -- triple vertical bar right turnstile
+ , { code = 0x022AB, char = '⊫', class = 'rel', cs = 'VDash' } -- double vertical bar double right turnstile
+ , { code = 0x022AC, char = '⊬', class = 'rel', cs = 'nvdash' } -- does not prove
+ , { code = 0x022AD, char = '⊭', class = 'rel', cs = 'nvDash' } -- not true
+ , { code = 0x022AE, char = '⊮', class = 'rel', cs = 'nVdash' } -- does not force
+ , { code = 0x022AF, char = '⊯', class = 'rel', cs = 'nVDash' } -- negated double vertical bar double right turnstile
+ , { code = 0x022B0, char = '⊰', class = 'rel', cs = 'prurel' } -- precedes under relation
+ , { code = 0x022B1, char = '⊱', class = 'rel', cs = 'scurel' } -- succeeds under relation
+ , { code = 0x022B2, char = '⊲', class = 'rel', cs = 'vartriangleleft' } -- normal subgroup of
+ , { code = 0x022B3, char = '⊳', class = 'rel', cs = 'vartriangleright' } -- contains as normal subgroup
+ , { code = 0x022B4, char = '⊴', class = 'rel', cs = 'trianglelefteq' } -- normal subgroup of or equal to
+ , { code = 0x022B5, char = '⊵', class = 'rel', cs = 'trianglerighteq' } -- contains as normal subgroup or equal to
+ , { code = 0x022B6, char = '⊶', class = 'rel', cs = 'origof' } -- original of
+ , { code = 0x022B7, char = '⊷', class = 'rel', cs = 'imageof' } -- image of
+ , { code = 0x022B8, char = '⊸', class = 'rel', cs = 'multimap' } -- multimap
+ , { code = 0x022B9, char = '⊹', class = 'ord', cs = 'hermitmatrix' } -- hermitian conjugate matrix
+ , { code = 0x022BA, char = '⊺', class = 'bin', cs = 'intercal' } -- intercalate
+ , { code = 0x022BB, char = '⊻', class = 'bin', cs = 'veebar' } -- xor
+ , { code = 0x022BC, char = '⊼', class = 'bin', cs = 'barwedge' } -- nand
+ , { code = 0x022BD, char = '⊽', class = 'bin', cs = 'barvee' } -- nor
+ , { code = 0x022BE, char = '⊾', class = 'ord', cs = 'measuredrightangle' } -- right angle with arc
+ , { code = 0x022BF, char = '⊿', class = 'ord', cs = 'varlrtriangle' } -- right triangle
+ , { code = 0x022C0, char = '⋀', class = 'op', cs = 'bigwedge' } -- n-ary logical and
+ , { code = 0x022C1, char = '⋁', class = 'op', cs = 'bigvee' } -- n-ary logical or
+ , { code = 0x022C2, char = '⋂', class = 'op', cs = 'bigcap' } -- n-ary intersection
+ , { code = 0x022C3, char = '⋃', class = 'op', cs = 'bigcup' } -- n-ary union
+ , { code = 0x022C4, char = '⋄', class = 'bin', cs = 'smwhtdiamond' } -- diamond operator
+ , { code = 0x022C5, char = '⋅', class = 'bin', cs = 'cdot' } -- dot operator
+ , { code = 0x022C6, char = '⋆', class = 'bin', cs = 'star' } -- star operator
+ , { code = 0x022C7, char = '⋇', class = 'bin', cs = 'divideontimes' } -- division times
+ , { code = 0x022C8, char = '⋈', class = 'rel', cs = 'bowtie' } -- bowtie
+ , { code = 0x022C9, char = '⋉', class = 'bin', cs = 'ltimes' } -- left normal factor semidirect product
+ , { code = 0x022CA, char = '⋊', class = 'bin', cs = 'rtimes' } -- right normal factor semidirect product
+ , { code = 0x022CB, char = '⋋', class = 'bin', cs = 'leftthreetimes' } -- left semidirect product
+ , { code = 0x022CC, char = '⋌', class = 'bin', cs = 'rightthreetimes' } -- right semidirect product
+ , { code = 0x022CD, char = '⋍', class = 'rel', cs = 'backsimeq' } -- reversed tilde equals
+ , { code = 0x022CE, char = '⋎', class = 'bin', cs = 'curlyvee' } -- curly logical or
+ , { code = 0x022CF, char = '⋏', class = 'bin', cs = 'curlywedge' } -- curly logical and
+ , { code = 0x022D0, char = '⋐', class = 'rel', cs = 'Subset' } -- double subset
+ , { code = 0x022D1, char = '⋑', class = 'rel', cs = 'Supset' } -- double superset
+ , { code = 0x022D2, char = '⋒', class = 'bin', cs = 'Cap' } -- double intersection
+ , { code = 0x022D3, char = '⋓', class = 'bin', cs = 'Cup' } -- double union
+ , { code = 0x022D4, char = '⋔', class = 'rel', cs = 'pitchfork' } -- pitchfork
+ , { code = 0x022D5, char = '⋕', class = 'rel', cs = 'equalparallel' } -- equal and parallel to
+ , { code = 0x022D6, char = '⋖', class = 'rel', cs = 'lessdot' } -- less-than with dot
+ , { code = 0x022D7, char = '⋗', class = 'rel', cs = 'gtrdot' } -- greater-than with dot
+ , { code = 0x022D8, char = '⋘', class = 'rel', cs = 'lll' } -- very much less-than
+ , { code = 0x022D9, char = '⋙', class = 'rel', cs = 'ggg' } -- very much greater-than
+ , { code = 0x022DA, char = '⋚', class = 'rel', cs = 'lesseqgtr' } -- less-than equal to or greater-than
+ , { code = 0x022DB, char = '⋛', class = 'rel', cs = 'gtreqless' } -- greater-than equal to or less-than
+ , { code = 0x022DC, char = '⋜', class = 'rel', cs = 'eqless' } -- equal to or less-than
+ , { code = 0x022DD, char = '⋝', class = 'rel', cs = 'eqgtr' } -- equal to or greater-than
+ , { code = 0x022DE, char = '⋞', class = 'rel', cs = 'curlyeqprec' } -- equal to or precedes
+ , { code = 0x022DF, char = '⋟', class = 'rel', cs = 'curlyeqsucc' } -- equal to or succeeds
+ , { code = 0x022E0, char = '⋠', class = 'rel', cs = 'npreccurlyeq' } -- does not precede or equal
+ , { code = 0x022E1, char = '⋡', class = 'rel', cs = 'nsucccurlyeq' } -- does not succeed or equal
+ , { code = 0x022E2, char = '⋢', class = 'rel', cs = 'nsqsubseteq' } -- not square image of or equal to
+ , { code = 0x022E3, char = '⋣', class = 'rel', cs = 'nsqsupseteq' } -- not square original of or equal to
+ , { code = 0x022E4, char = '⋤', class = 'rel', cs = 'sqsubsetneq' } -- square image of or not equal to
+ , { code = 0x022E5, char = '⋥', class = 'rel', cs = 'sqsupsetneq' } -- square original of or not equal to
+ , { code = 0x022E6, char = '⋦', class = 'rel', cs = 'lnsim' } -- less-than but not equivalent to
+ , { code = 0x022E7, char = '⋧', class = 'rel', cs = 'gnsim' } -- greater-than but not equivalent to
+ , { code = 0x022E8, char = '⋨', class = 'rel', cs = 'precnsim' } -- precedes but not equivalent to
+ , { code = 0x022E9, char = '⋩', class = 'rel', cs = 'succnsim' } -- succeeds but not equivalent to
+ , { code = 0x022EA, char = '⋪', class = 'rel', cs = 'nvartriangleleft' } -- not normal subgroup of
+ , { code = 0x022EB, char = '⋫', class = 'rel', cs = 'nvartriangleright' } -- does not contain as normal subgroup
+ , { code = 0x022EC, char = '⋬', class = 'rel', cs = 'ntrianglelefteq' } -- not normal subgroup of or equal to
+ , { code = 0x022ED, char = '⋭', class = 'rel', cs = 'ntrianglerighteq' } -- does not contain as normal subgroup or equal
+ , { code = 0x022EE, char = '⋮', class = 'rel', cs = 'unicodevdots' } -- vertical ellipsis
+ , { code = 0x022EF, char = '⋯', class = 'ord', cs = 'unicodecdots' } -- midline horizontal ellipsis
+ , { code = 0x022F0, char = '⋰', class = 'rel', cs = 'unicodeadots' } -- up right diagonal ellipsis
+ , { code = 0x022F1, char = '⋱', class = 'rel', cs = 'unicodeddots' } -- down right diagonal ellipsis
+ , { code = 0x022F2, char = '⋲', class = 'rel', cs = 'disin' } -- element of with long horizontal stroke
+ , { code = 0x022F3, char = '⋳', class = 'rel', cs = 'varisins' } -- element of with vertical bar at end of horizontal stroke
+ , { code = 0x022F4, char = '⋴', class = 'rel', cs = 'isins' } -- small element of with vertical bar at end of horizontal stroke
+ , { code = 0x022F5, char = '⋵', class = 'rel', cs = 'isindot' } -- element of with dot above
+ , { code = 0x022F6, char = '⋶', class = 'rel', cs = 'varisinobar' } -- element of with overbar
+ , { code = 0x022F7, char = '⋷', class = 'rel', cs = 'isinobar' } -- small element of with overbar
+ , { code = 0x022F8, char = '⋸', class = 'rel', cs = 'isinvb' } -- element of with underbar
+ , { code = 0x022F9, char = '⋹', class = 'rel', cs = 'isinE' } -- element of with two horizontal strokes
+ , { code = 0x022FA, char = '⋺', class = 'rel', cs = 'nisd' } -- contains with long horizontal stroke
+ , { code = 0x022FB, char = '⋻', class = 'rel', cs = 'varnis' } -- contains with vertical bar at end of horizontal stroke
+ , { code = 0x022FC, char = '⋼', class = 'rel', cs = 'nis' } -- small contains with vertical bar at end of horizontal stroke
+ , { code = 0x022FD, char = '⋽', class = 'rel', cs = 'varniobar' } -- contains with overbar
+ , { code = 0x022FE, char = '⋾', class = 'rel', cs = 'niobar' } -- small contains with overbar
+ , { code = 0x022FF, char = '⋿', class = 'rel', cs = 'bagmember' } -- z notation bag membership
+ , { code = 0x02300, char = '⌀', class = 'ord', cs = 'diameter' } -- diameter sign
+ , { code = 0x02302, char = '⌂', class = 'ord', cs = 'house' } -- house
+ , { code = 0x02305, char = '⌅', class = 'bin', cs = 'varbarwedge' } -- projective
+ , { code = 0x02306, char = '⌆', class = 'bin', cs = 'vardoublebarwedge' } -- perspective
+ , { code = 0x02308, char = '⌈', class = 'open', cs = 'lceil' } -- left ceiling
+ , { code = 0x02309, char = '⌉', class = 'close', cs = 'rceil' } -- right ceiling
+ , { code = 0x0230A, char = '⌊', class = 'open', cs = 'lfloor' } -- left floor
+ , { code = 0x0230B, char = '⌋', class = 'close', cs = 'rfloor' } -- right floor
+ , { code = 0x02310, char = '⌐', class = 'ord', cs = 'invnot' } -- reversed not sign
+ , { code = 0x02311, char = '⌑', class = 'ord', cs = 'sqlozenge' } -- square lozenge
+ , { code = 0x02312, char = '⌒', class = 'ord', cs = 'profline' } -- arc
+ , { code = 0x02313, char = '⌓', class = 'ord', cs = 'profsurf' } -- segment
+ , { code = 0x02317, char = '⌗', class = 'ord', cs = 'viewdata' } -- viewdata square
+ , { code = 0x02319, char = '⌙', class = 'ord', cs = 'turnednot' } -- turned not sign
+ , { code = 0x0231C, char = '⌜', class = 'open', cs = 'ulcorner' } -- top left corner
+ , { code = 0x0231D, char = '⌝', class = 'close', cs = 'urcorner' } -- top right corner
+ , { code = 0x0231E, char = '⌞', class = 'open', cs = 'llcorner' } -- bottom left corner
+ , { code = 0x0231F, char = '⌟', class = 'close', cs = 'lrcorner' } -- bottom right corner
+ , { code = 0x02320, char = '⌠', class = 'ord', cs = 'inttop' } -- top half integral
+ , { code = 0x02321, char = '⌡', class = 'ord', cs = 'intbottom' } -- bottom half integral
+ , { code = 0x02322, char = '⌢', class = 'rel', cs = 'frown' } -- frown
+ , { code = 0x02323, char = '⌣', class = 'rel', cs = 'smile' } -- smile
+ , { code = 0x0232C, char = '⌬', class = 'ord', cs = 'varhexagonlrbonds' } -- benzene ring
+ , { code = 0x02332, char = '⌲', class = 'ord', cs = 'conictaper' } -- conical taper
+ , { code = 0x02336, char = '⌶', class = 'ord', cs = 'topbot' } -- apl functional symbol i-beam
+ , { code = 0x0233D, char = '⌽', class = 'bin', cs = 'obar' } -- apl functional symbol circle stile
+ , { code = 0x0233F, char = '⌿', class = 'rel', cs = 'APLnotslash' } -- apl functional symbol slash bar
+ , { code = 0x02340, char = '⍀', class = 'ord', cs = 'APLnotbackslash' } -- apl functional symbol backslash bar
+ , { code = 0x02353, char = '⍓', class = 'ord', cs = 'APLboxupcaret' } -- apl functional symbol quad up caret
+ , { code = 0x02370, char = '⍰', class = 'ord', cs = 'APLboxquestion' } -- apl functional symbol quad question
+ , { code = 0x0237C, char = '⍼', class = 'ord', cs = 'rangledownzigzagarrow' } -- right angle with downwards zigzag arrow
+ , { code = 0x02394, char = '⎔', class = 'ord', cs = 'hexagon' } -- software-function symbol
+ , { code = 0x0239B, char = '⎛', class = 'ord', cs = 'lparenuend' } -- left parenthesis upper hook
+ , { code = 0x0239C, char = '⎜', class = 'ord', cs = 'lparenextender' } -- left parenthesis extension
+ , { code = 0x0239D, char = '⎝', class = 'ord', cs = 'lparenlend' } -- left parenthesis lower hook
+ , { code = 0x0239E, char = '⎞', class = 'ord', cs = 'rparenuend' } -- right parenthesis upper hook
+ , { code = 0x0239F, char = '⎟', class = 'ord', cs = 'rparenextender' } -- right parenthesis extension
+ , { code = 0x023A0, char = '⎠', class = 'ord', cs = 'rparenlend' } -- right parenthesis lower hook
+ , { code = 0x023A1, char = '⎡', class = 'ord', cs = 'lbrackuend' } -- left square bracket upper corner
+ , { code = 0x023A2, char = '⎢', class = 'ord', cs = 'lbrackextender' } -- left square bracket extension
+ , { code = 0x023A3, char = '⎣', class = 'ord', cs = 'lbracklend' } -- left square bracket lower corner
+ , { code = 0x023A4, char = '⎤', class = 'ord', cs = 'rbrackuend' } -- right square bracket upper corner
+ , { code = 0x023A5, char = '⎥', class = 'ord', cs = 'rbrackextender' } -- right square bracket extension
+ , { code = 0x023A6, char = '⎦', class = 'ord', cs = 'rbracklend' } -- right square bracket lower corner
+ , { code = 0x023A7, char = '⎧', class = 'ord', cs = 'lbraceuend' } -- left curly bracket upper hook
+ , { code = 0x023A8, char = '⎨', class = 'ord', cs = 'lbracemid' } -- left curly bracket middle piece
+ , { code = 0x023A9, char = '⎩', class = 'ord', cs = 'lbracelend' } -- left curly bracket lower hook
+ , { code = 0x023AA, char = '⎪', class = 'ord', cs = 'vbraceextender' } -- curly bracket extension
+ , { code = 0x023AB, char = '⎫', class = 'ord', cs = 'rbraceuend' } -- right curly bracket upper hook
+ , { code = 0x023AC, char = '⎬', class = 'ord', cs = 'rbracemid' } -- right curly bracket middle piece
+ , { code = 0x023AD, char = '⎭', class = 'ord', cs = 'rbracelend' } -- right curly bracket lower hook
+ , { code = 0x023AE, char = '⎮', class = 'ord', cs = 'intextender' } -- integral extension
+ , { code = 0x023AF, char = '⎯', class = 'ord', cs = 'harrowextender' } -- horizontal line extension
+ , { code = 0x023B0, char = '⎰', class = 'open', cs = 'lmoustache' } -- upper left or lower right curly bracket section
+ , { code = 0x023B1, char = '⎱', class = 'close', cs = 'rmoustache' } -- upper right or lower left curly bracket section
+ , { code = 0x023B2, char = '⎲', class = 'ord', cs = 'sumtop' } -- summation top
+ , { code = 0x023B3, char = '⎳', class = 'ord', cs = 'sumbottom' } -- summation bottom
+ , { code = 0x023B4, char = '⎴', class = 'over', cs = 'overbracket' } -- top square bracket
+ , { code = 0x023B5, char = '⎵', class = 'under', cs = 'underbracket' } -- bottom square bracket
+ , { code = 0x023B6, char = '⎶', class = 'ord', cs = 'bbrktbrk' } -- bottom square bracket over top square bracket
+ , { code = 0x023B7, char = '⎷', class = 'ord', cs = 'sqrtbottom' } -- radical symbol bottom
+ , { code = 0x023B8, char = '⎸', class = 'ord', cs = 'lvboxline' } -- left vertical box line
+ , { code = 0x023B9, char = '⎹', class = 'ord', cs = 'rvboxline' } -- right vertical box line
+ , { code = 0x023CE, char = '⏎', class = 'ord', cs = 'varcarriagereturn' } -- return symbol
+ , { code = 0x023DC, char = '⏜', class = 'over', cs = 'overparen' } -- top parenthesis
+ , { code = 0x023DD, char = '⏝', class = 'under', cs = 'underparen' } -- bottom parenthesis
+ , { code = 0x023DE, char = '⏞', class = 'over', cs = 'overbrace' } -- top curly bracket
+ , { code = 0x023DF, char = '⏟', class = 'under', cs = 'underbrace' } -- bottom curly bracket
+ , { code = 0x023E0, char = '⏠', class = 'ord', cs = 'obrbrak' } -- top tortoise shell bracket
+ , { code = 0x023E1, char = '⏡', class = 'ord', cs = 'ubrbrak' } -- bottom tortoise shell bracket
+ , { code = 0x023E2, char = '⏢', class = 'ord', cs = 'trapezium' } -- white trapezium
+ , { code = 0x023E3, char = '⏣', class = 'ord', cs = 'benzenr' } -- benzene ring with circle
+ , { code = 0x023E4, char = '⏤', class = 'ord', cs = 'strns' } -- straightness
+ , { code = 0x023E5, char = '⏥', class = 'ord', cs = 'fltns' } -- flatness
+ , { code = 0x023E6, char = '⏦', class = 'ord', cs = 'accurrent' } -- ac current
+ , { code = 0x023E7, char = '⏧', class = 'ord', cs = 'elinters' } -- electrical intersection
+ , { code = 0x02422, char = '␢', class = 'ord', cs = 'blanksymbol' } -- blank symbol
+ , { code = 0x02423, char = '␣', class = 'ord', cs = 'mathvisiblespace' } -- open box
+ , { code = 0x02506, char = '┆', class = 'ord', cs = 'bdtriplevdash' } -- box drawings light triple dash vertical
+ , { code = 0x02580, char = '▀', class = 'ord', cs = 'blockuphalf' } -- upper half block
+ , { code = 0x02584, char = '▄', class = 'ord', cs = 'blocklowhalf' } -- lower half block
+ , { code = 0x02588, char = '█', class = 'ord', cs = 'blockfull' } -- full block
+ , { code = 0x0258C, char = '▌', class = 'ord', cs = 'blocklefthalf' } -- left half block
+ , { code = 0x02590, char = '▐', class = 'ord', cs = 'blockrighthalf' } -- right half block
+ , { code = 0x02591, char = '░', class = 'ord', cs = 'blockqtrshaded' } -- light shade
+ , { code = 0x02592, char = '▒', class = 'ord', cs = 'blockhalfshaded' } -- medium shade
+ , { code = 0x02593, char = '▓', class = 'ord', cs = 'blockthreeqtrshaded' } -- dark shade
+ , { code = 0x025A0, char = '■', class = 'ord', cs = 'mdlgblksquare' } -- black square
+ , { code = 0x025A1, char = '□', class = 'ord', cs = 'mdlgwhtsquare' } -- white square
+ , { code = 0x025A2, char = '▢', class = 'ord', cs = 'squoval' } -- white square with rounded corners
+ , { code = 0x025A3, char = '▣', class = 'ord', cs = 'blackinwhitesquare' } -- white square containing black small square
+ , { code = 0x025A4, char = '▤', class = 'ord', cs = 'squarehfill' } -- square with horizontal fill
+ , { code = 0x025A5, char = '▥', class = 'ord', cs = 'squarevfill' } -- square with vertical fill
+ , { code = 0x025A6, char = '▦', class = 'ord', cs = 'squarehvfill' } -- square with orthogonal crosshatch fill
+ , { code = 0x025A7, char = '▧', class = 'ord', cs = 'squarenwsefill' } -- square with upper left to lower right fill
+ , { code = 0x025A8, char = '▨', class = 'ord', cs = 'squareneswfill' } -- square with upper right to lower left fill
+ , { code = 0x025A9, char = '▩', class = 'ord', cs = 'squarecrossfill' } -- square with diagonal crosshatch fill
+ , { code = 0x025AA, char = '▪', class = 'ord', cs = 'smblksquare' } -- black small square
+ , { code = 0x025AB, char = '▫', class = 'ord', cs = 'smwhtsquare' } -- white small square
+ , { code = 0x025AC, char = '▬', class = 'ord', cs = 'hrectangleblack' } -- black rectangle
+ , { code = 0x025AD, char = '▭', class = 'ord', cs = 'hrectangle' } -- white rectangle
+ , { code = 0x025AE, char = '▮', class = 'ord', cs = 'vrectangleblack' } -- black vertical rectangle
+ , { code = 0x025AF, char = '▯', class = 'ord', cs = 'vrectangle' } -- white vertical rectangle
+ , { code = 0x025B0, char = '▰', class = 'ord', cs = 'parallelogramblack' } -- black parallelogram
+ , { code = 0x025B1, char = '▱', class = 'ord', cs = 'parallelogram' } -- white parallelogram
+ , { code = 0x025B2, char = '▲', class = 'ord', cs = 'bigblacktriangleup' } -- black up-pointing triangle
+ , { code = 0x025B3, char = '△', class = 'bin', cs = 'bigtriangleup' } -- white up-pointing triangle
+ , { code = 0x025B4, char = '▴', class = 'ord', cs = 'blacktriangle' } -- black up-pointing small triangle
+ , { code = 0x025B5, char = '▵', class = 'rel', cs = 'vartriangle' } -- white up-pointing small triangle
+ , { code = 0x025B6, char = '▶', class = 'ord', cs = 'blacktriangleright' } -- black right-pointing triangle
+ , { code = 0x025B7, char = '▷', class = 'bin', cs = 'triangleright' } -- white right-pointing triangle
+ , { code = 0x025B8, char = '▸', class = 'ord', cs = 'smallblacktriangleright' } -- black right-pointing small triangle
+ , { code = 0x025B9, char = '▹', class = 'ord', cs = 'smalltriangleright' } -- white right-pointing small triangle
+ , { code = 0x025BA, char = '►', class = 'ord', cs = 'blackpointerright' } -- black right-pointing pointer
+ , { code = 0x025BB, char = '▻', class = 'ord', cs = 'whitepointerright' } -- white right-pointing pointer
+ , { code = 0x025BC, char = '▼', class = 'ord', cs = 'bigblacktriangledown' } -- black down-pointing triangle
+ , { code = 0x025BD, char = '▽', class = 'ord', cs = 'bigtriangledown' } -- white down-pointing triangle
+ , { code = 0x025BE, char = '▾', class = 'ord', cs = 'blacktriangledown' } -- black down-pointing small triangle
+ , { code = 0x025BF, char = '▿', class = 'ord', cs = 'triangledown' } -- white down-pointing small triangle
+ , { code = 0x025C0, char = '◀', class = 'ord', cs = 'blacktriangleleft' } -- black left-pointing triangle
+ , { code = 0x025C1, char = '◁', class = 'bin', cs = 'triangleleft' } -- white left-pointing triangle
+ , { code = 0x025C2, char = '◂', class = 'ord', cs = 'smallblacktriangleleft' } -- black left-pointing small triangle
+ , { code = 0x025C3, char = '◃', class = 'ord', cs = 'smalltriangleleft' } -- white left-pointing small triangle
+ , { code = 0x025C4, char = '◄', class = 'ord', cs = 'blackpointerleft' } -- black left-pointing pointer
+ , { code = 0x025C5, char = '◅', class = 'ord', cs = 'whitepointerleft' } -- white left-pointing pointer
+ , { code = 0x025C6, char = '◆', class = 'ord', cs = 'mdlgblkdiamond' } -- black diamond
+ , { code = 0x025C7, char = '◇', class = 'ord', cs = 'mdlgwhtdiamond' } -- white diamond
+ , { code = 0x025C8, char = '◈', class = 'ord', cs = 'blackinwhitediamond' } -- white diamond containing black small diamond
+ , { code = 0x025C9, char = '◉', class = 'ord', cs = 'fisheye' } -- fisheye
+ , { code = 0x025CA, char = '◊', class = 'ord', cs = 'mdlgwhtlozenge' } -- lozenge
+ , { code = 0x025CB, char = '○', class = 'bin', cs = 'mdlgwhtcircle' } -- white circle
+ , { code = 0x025CC, char = '◌', class = 'ord', cs = 'dottedcircle' } -- dotted circle
+ , { code = 0x025CD, char = '◍', class = 'ord', cs = 'circlevertfill' } -- circle with vertical fill
+ , { code = 0x025CE, char = '◎', class = 'ord', cs = 'bullseye' } -- bullseye
+ , { code = 0x025CF, char = '●', class = 'ord', cs = 'mdlgblkcircle' } -- black circle
+ , { code = 0x025D0, char = '◐', class = 'ord', cs = 'circlelefthalfblack' } -- circle with left half black
+ , { code = 0x025D1, char = '◑', class = 'ord', cs = 'circlerighthalfblack' } -- circle with right half black
+ , { code = 0x025D2, char = '◒', class = 'ord', cs = 'circlebottomhalfblack' } -- circle with lower half black
+ , { code = 0x025D3, char = '◓', class = 'ord', cs = 'circletophalfblack' } -- circle with upper half black
+ , { code = 0x025D4, char = '◔', class = 'ord', cs = 'circleurquadblack' } -- circle with upper right quadrant black
+ , { code = 0x025D5, char = '◕', class = 'ord', cs = 'blackcircleulquadwhite' } -- circle with all but upper left quadrant black
+ , { code = 0x025D6, char = '◖', class = 'ord', cs = 'blacklefthalfcircle' } -- left half black circle
+ , { code = 0x025D7, char = '◗', class = 'ord', cs = 'blackrighthalfcircle' } -- right half black circle
+ , { code = 0x025D8, char = '◘', class = 'ord', cs = 'inversebullet' } -- inverse bullet
+ , { code = 0x025D9, char = '◙', class = 'ord', cs = 'inversewhitecircle' } -- inverse white circle
+ , { code = 0x025DA, char = '◚', class = 'ord', cs = 'invwhiteupperhalfcircle' } -- upper half inverse white circle
+ , { code = 0x025DB, char = '◛', class = 'ord', cs = 'invwhitelowerhalfcircle' } -- lower half inverse white circle
+ , { code = 0x025DC, char = '◜', class = 'ord', cs = 'ularc' } -- upper left quadrant circular arc
+ , { code = 0x025DD, char = '◝', class = 'ord', cs = 'urarc' } -- upper right quadrant circular arc
+ , { code = 0x025DE, char = '◞', class = 'ord', cs = 'lrarc' } -- lower right quadrant circular arc
+ , { code = 0x025DF, char = '◟', class = 'ord', cs = 'llarc' } -- lower left quadrant circular arc
+ , { code = 0x025E0, char = '◠', class = 'ord', cs = 'topsemicircle' } -- upper half circle
+ , { code = 0x025E1, char = '◡', class = 'ord', cs = 'botsemicircle' } -- lower half circle
+ , { code = 0x025E2, char = '◢', class = 'ord', cs = 'lrblacktriangle' } -- black lower right triangle
+ , { code = 0x025E3, char = '◣', class = 'ord', cs = 'llblacktriangle' } -- black lower left triangle
+ , { code = 0x025E4, char = '◤', class = 'ord', cs = 'ulblacktriangle' } -- black upper left triangle
+ , { code = 0x025E5, char = '◥', class = 'ord', cs = 'urblacktriangle' } -- black upper right triangle
+ , { code = 0x025E6, char = '◦', class = 'ord', cs = 'smwhtcircle' } -- white bullet
+ , { code = 0x025E7, char = '◧', class = 'ord', cs = 'squareleftblack' } -- square with left half black
+ , { code = 0x025E8, char = '◨', class = 'ord', cs = 'squarerightblack' } -- square with right half black
+ , { code = 0x025E9, char = '◩', class = 'ord', cs = 'squareulblack' } -- square with upper left diagonal half black
+ , { code = 0x025EA, char = '◪', class = 'ord', cs = 'squarelrblack' } -- square with lower right diagonal half black
+ , { code = 0x025EB, char = '◫', class = 'bin', cs = 'boxbar' } -- white square with vertical bisecting line
+ , { code = 0x025EC, char = '◬', class = 'ord', cs = 'trianglecdot' } -- white up-pointing triangle with dot
+ , { code = 0x025ED, char = '◭', class = 'ord', cs = 'triangleleftblack' } -- up-pointing triangle with left half black
+ , { code = 0x025EE, char = '◮', class = 'ord', cs = 'trianglerightblack' } -- up-pointing triangle with right half black
+ , { code = 0x025EF, char = '◯', class = 'ord', cs = 'lgwhtcircle' } -- large circle
+ , { code = 0x025F0, char = '◰', class = 'ord', cs = 'squareulquad' } -- white square with upper left quadrant
+ , { code = 0x025F1, char = '◱', class = 'ord', cs = 'squarellquad' } -- white square with lower left quadrant
+ , { code = 0x025F2, char = '◲', class = 'ord', cs = 'squarelrquad' } -- white square with lower right quadrant
+ , { code = 0x025F3, char = '◳', class = 'ord', cs = 'squareurquad' } -- white square with upper right quadrant
+ , { code = 0x025F4, char = '◴', class = 'ord', cs = 'circleulquad' } -- white circle with upper left quadrant
+ , { code = 0x025F5, char = '◵', class = 'ord', cs = 'circlellquad' } -- white circle with lower left quadrant
+ , { code = 0x025F6, char = '◶', class = 'ord', cs = 'circlelrquad' } -- white circle with lower right quadrant
+ , { code = 0x025F7, char = '◷', class = 'ord', cs = 'circleurquad' } -- white circle with upper right quadrant
+ , { code = 0x025F8, char = '◸', class = 'ord', cs = 'ultriangle' } -- upper left triangle
+ , { code = 0x025F9, char = '◹', class = 'ord', cs = 'urtriangle' } -- upper right triangle
+ , { code = 0x025FA, char = '◺', class = 'ord', cs = 'lltriangle' } -- lower left triangle
+ , { code = 0x025FB, char = '◻', class = 'ord', cs = 'mdwhtsquare' } -- white medium square
+ , { code = 0x025FC, char = '◼', class = 'ord', cs = 'mdblksquare' } -- black medium square
+ , { code = 0x025FD, char = '◽', class = 'ord', cs = 'mdsmwhtsquare' } -- white medium small square
+ , { code = 0x025FE, char = '◾', class = 'ord', cs = 'mdsmblksquare' } -- black medium small square
+ , { code = 0x025FF, char = '◿', class = 'ord', cs = 'lrtriangle' } -- lower right triangle
+ , { code = 0x02605, char = '★', class = 'ord', cs = 'bigstar' } -- black star
+ , { code = 0x02606, char = '☆', class = 'ord', cs = 'bigwhitestar' } -- white star
+ , { code = 0x02609, char = '☉', class = 'ord', cs = 'astrosun' } -- sun
+ , { code = 0x02621, char = '☡', class = 'ord', cs = 'danger' } -- caution sign
+ , { code = 0x0263B, char = '☻', class = 'ord', cs = 'blacksmiley' } -- black smiling face
+ , { code = 0x0263C, char = '☼', class = 'ord', cs = 'sun' } -- white sun with rays
+ , { code = 0x0263D, char = '☽', class = 'ord', cs = 'rightmoon' } -- first quarter moon
+ , { code = 0x0263E, char = '☾', class = 'ord', cs = 'leftmoon' } -- last quarter moon
+ , { code = 0x02640, char = '♀', class = 'ord', cs = 'female' } -- female sign
+ , { code = 0x02642, char = '♂', class = 'ord', cs = 'male' } -- male sign
+ , { code = 0x02660, char = '♠', class = 'ord', cs = 'spadesuit' } -- black spade suit
+ , { code = 0x02661, char = '♡', class = 'ord', cs = 'heartsuit' } -- white heart suit
+ , { code = 0x02662, char = '♢', class = 'ord', cs = 'diamondsuit' } -- white diamond suit
+ , { code = 0x02663, char = '♣', class = 'ord', cs = 'clubsuit' } -- black club suit
+ , { code = 0x02664, char = '♤', class = 'ord', cs = 'varspadesuit' } -- white spade suit
+ , { code = 0x02665, char = '♥', class = 'ord', cs = 'varheartsuit' } -- black heart suit
+ , { code = 0x02666, char = '♦', class = 'ord', cs = 'vardiamondsuit' } -- black diamond suit
+ , { code = 0x02667, char = '♧', class = 'ord', cs = 'varclubsuit' } -- white club suit
+ , { code = 0x02669, char = '♩', class = 'ord', cs = 'quarternote' } -- quarter note
+ , { code = 0x0266A, char = '♪', class = 'ord', cs = 'eighthnote' } -- eighth note
+ , { code = 0x0266B, char = '♫', class = 'ord', cs = 'twonotes' } -- beamed eighth notes
+ , { code = 0x0266D, char = '♭', class = 'ord', cs = 'flat' } -- music flat sign
+ , { code = 0x0266E, char = '♮', class = 'ord', cs = 'natural' } -- music natural sign
+ , { code = 0x0266F, char = '♯', class = 'ord', cs = 'sharp' } -- music sharp sign
+ , { code = 0x0267E, char = '♾', class = 'ord', cs = 'acidfree' } -- permanent paper sign
+ , { code = 0x02680, char = '⚀', class = 'ord', cs = 'dicei' } -- die face-1
+ , { code = 0x02681, char = '⚁', class = 'ord', cs = 'diceii' } -- die face-2
+ , { code = 0x02682, char = '⚂', class = 'ord', cs = 'diceiii' } -- die face-3
+ , { code = 0x02683, char = '⚃', class = 'ord', cs = 'diceiv' } -- die face-4
+ , { code = 0x02684, char = '⚄', class = 'ord', cs = 'dicev' } -- die face-5
+ , { code = 0x02685, char = '⚅', class = 'ord', cs = 'dicevi' } -- die face-6
+ , { code = 0x02686, char = '⚆', class = 'ord', cs = 'circledrightdot' } -- white circle with dot right
+ , { code = 0x02687, char = '⚇', class = 'ord', cs = 'circledtwodots' } -- white circle with two dots
+ , { code = 0x02688, char = '⚈', class = 'ord', cs = 'blackcircledrightdot' } -- black circle with white dot right
+ , { code = 0x02689, char = '⚉', class = 'ord', cs = 'blackcircledtwodots' } -- black circle with two white dots
+ , { code = 0x026A5, char = '⚥', class = 'ord', cs = 'Hermaphrodite' } -- male and female sign
+ , { code = 0x026AA, char = '⚪', class = 'ord', cs = 'mdwhtcircle' } -- medium white circle
+ , { code = 0x026AB, char = '⚫', class = 'ord', cs = 'mdblkcircle' } -- medium black circle
+ , { code = 0x026AC, char = '⚬', class = 'ord', cs = 'mdsmwhtcircle' } -- medium small white circle
+ , { code = 0x026B2, char = '⚲', class = 'ord', cs = 'neuter' } -- neuter
+ , { code = 0x02713, char = '✓', class = 'ord', cs = 'checkmark' } -- check mark
+ , { code = 0x02720, char = '✠', class = 'ord', cs = 'maltese' } -- maltese cross
+ , { code = 0x0272A, char = '✪', class = 'ord', cs = 'circledstar' } -- circled white star
+ , { code = 0x02736, char = '✶', class = 'ord', cs = 'varstar' } -- six pointed black star
+ , { code = 0x0273D, char = '✽', class = 'ord', cs = 'dingasterisk' } -- heavy teardrop-spoked asterisk
+ , { code = 0x02772, char = '❲', class = 'open', cs = 'lbrbrak' } -- light left tortoise shell bracket ornament
+ , { code = 0x02773, char = '❳', class = 'close', cs = 'rbrbrak' } -- light right tortoise shell bracket ornament
+ , { code = 0x0279B, char = '➛', class = 'ord', cs = 'draftingarrow' } -- drafting point rightwards arrow
+ , { code = 0x027C0, char = '⟀', class = 'ord', cs = 'threedangle' } -- three dimensional angle
+ , { code = 0x027C1, char = '⟁', class = 'ord', cs = 'whiteinwhitetriangle' } -- white triangle containing small white triangle
+ , { code = 0x027C2, char = '⟂', class = 'rel', cs = 'perp' } -- perpendicular
+ , { code = 0x027C3, char = '⟃', class = 'ord', cs = 'subsetcirc' } -- open subset
+ , { code = 0x027C4, char = '⟄', class = 'ord', cs = 'supsetcirc' } -- open superset
+ , { code = 0x027C5, char = '⟅', class = 'open', cs = 'lbag' } -- left s-shaped bag delimiter
+ , { code = 0x027C6, char = '⟆', class = 'close', cs = 'rbag' } -- right s-shaped bag delimiter
+ , { code = 0x027C7, char = '⟇', class = 'bin', cs = 'veedot' } -- or with dot inside
+ , { code = 0x027C8, char = '⟈', class = 'rel', cs = 'bsolhsub' } -- reverse solidus preceding subset
+ , { code = 0x027C9, char = '⟉', class = 'rel', cs = 'suphsol' } -- superset preceding solidus
+ , { code = 0x027CC, char = '⟌', class = 'radical', cs = 'longdivision' } -- long division
+ , { code = 0x027D0, char = '⟐', class = 'ord', cs = 'diamondcdot' } -- white diamond with centred dot
+ , { code = 0x027D1, char = '⟑', class = 'bin', cs = 'wedgedot' } -- and with dot
+ , { code = 0x027D2, char = '⟒', class = 'rel', cs = 'upin' } -- element of opening upwards
+ , { code = 0x027D3, char = '⟓', class = 'rel', cs = 'pullback' } -- lower right corner with dot
+ , { code = 0x027D4, char = '⟔', class = 'rel', cs = 'pushout' } -- upper left corner with dot
+ , { code = 0x027D5, char = '⟕', class = 'op', cs = 'leftouterjoin' } -- left outer join
+ , { code = 0x027D6, char = '⟖', class = 'op', cs = 'rightouterjoin' } -- right outer join
+ , { code = 0x027D7, char = '⟗', class = 'op', cs = 'fullouterjoin' } -- full outer join
+ , { code = 0x027D8, char = '⟘', class = 'op', cs = 'bigbot' } -- large up tack
+ , { code = 0x027D9, char = '⟙', class = 'op', cs = 'bigtop' } -- large down tack
+ , { code = 0x027DA, char = '⟚', class = 'rel', cs = 'DashVDash' } -- left and right double turnstile
+ , { code = 0x027DB, char = '⟛', class = 'rel', cs = 'dashVdash' } -- left and right tack
+ , { code = 0x027DC, char = '⟜', class = 'rel', cs = 'multimapinv' } -- left multimap
+ , { code = 0x027DD, char = '⟝', class = 'rel', cs = 'vlongdash' } -- long right tack
+ , { code = 0x027DE, char = '⟞', class = 'rel', cs = 'longdashv' } -- long left tack
+ , { code = 0x027DF, char = '⟟', class = 'rel', cs = 'cirbot' } -- up tack with circle above
+ , { code = 0x027E0, char = '⟠', class = 'bin', cs = 'lozengeminus' } -- lozenge divided by horizontal rule
+ , { code = 0x027E1, char = '⟡', class = 'bin', cs = 'concavediamond' } -- white concave-sided diamond
+ , { code = 0x027E2, char = '⟢', class = 'bin', cs = 'concavediamondtickleft' } -- white concave-sided diamond with leftwards tick
+ , { code = 0x027E3, char = '⟣', class = 'bin', cs = 'concavediamondtickright' } -- white concave-sided diamond with rightwards tick
+ , { code = 0x027E4, char = '⟤', class = 'bin', cs = 'whitesquaretickleft' } -- white square with leftwards tick
+ , { code = 0x027E5, char = '⟥', class = 'bin', cs = 'whitesquaretickright' } -- white square with rightwards tick
+ , { code = 0x027E6, char = '⟦', class = 'open', cs = 'lBrack' } -- mathematical left white square bracket
+ , { code = 0x027E7, char = '⟧', class = 'close', cs = 'rBrack' } -- mathematical right white square bracket
+ , { code = 0x027E8, char = '⟨', class = 'open', cs = 'langle' } -- mathematical left angle bracket
+ , { code = 0x027E9, char = '⟩', class = 'close', cs = 'rangle' } -- mathematical right angle bracket
+ , { code = 0x027EA, char = '⟪', class = 'open', cs = 'lAngle' } -- mathematical left double angle bracket
+ , { code = 0x027EB, char = '⟫', class = 'close', cs = 'rAngle' } -- mathematical right double angle bracket
+ , { code = 0x027EC, char = '⟬', class = 'open', cs = 'Lbrbrak' } -- mathematical left white tortoise shell bracket
+ , { code = 0x027ED, char = '⟭', class = 'close', cs = 'Rbrbrak' } -- mathematical right white tortoise shell bracket
+ , { code = 0x027EE, char = '⟮', class = 'open', cs = 'lgroup' } -- mathematical left flattened parenthesis
+ , { code = 0x027EF, char = '⟯', class = 'close', cs = 'rgroup' } -- mathematical right flattened parenthesis
+ , { code = 0x027F0, char = '⟰', class = 'rel', cs = 'UUparrow' } -- upwards quadruple arrow
+ , { code = 0x027F1, char = '⟱', class = 'rel', cs = 'DDownarrow' } -- downwards quadruple arrow
+ , { code = 0x027F2, char = '⟲', class = 'rel', cs = 'acwgapcirclearrow' } -- anticlockwise gapped circle arrow
+ , { code = 0x027F3, char = '⟳', class = 'rel', cs = 'cwgapcirclearrow' } -- clockwise gapped circle arrow
+ , { code = 0x027F4, char = '⟴', class = 'rel', cs = 'rightarrowonoplus' } -- right arrow with circled plus
+ , { code = 0x027F5, char = '⟵', class = 'rel', cs = 'longleftarrow' } -- long leftwards arrow
+ , { code = 0x027F6, char = '⟶', class = 'rel', cs = 'longrightarrow' } -- long rightwards arrow
+ , { code = 0x027F7, char = '⟷', class = 'rel', cs = 'longleftrightarrow' } -- long left right arrow
+ , { code = 0x027F8, char = '⟸', class = 'rel', cs = 'Longleftarrow' } -- long leftwards double arrow
+ , { code = 0x027F9, char = '⟹', class = 'rel', cs = 'Longrightarrow' } -- long rightwards double arrow
+ , { code = 0x027FA, char = '⟺', class = 'rel', cs = 'Longleftrightarrow' } -- long left right double arrow
+ , { code = 0x027FB, char = '⟻', class = 'rel', cs = 'longmapsfrom' } -- long leftwards arrow from bar
+ , { code = 0x027FC, char = '⟼', class = 'rel', cs = 'longmapsto' } -- long rightwards arrow from bar
+ , { code = 0x027FD, char = '⟽', class = 'rel', cs = 'Longmapsfrom' } -- long leftwards double arrow from bar
+ , { code = 0x027FE, char = '⟾', class = 'rel', cs = 'Longmapsto' } -- long rightwards double arrow from bar
+ , { code = 0x027FF, char = '⟿', class = 'rel', cs = 'longrightsquigarrow' } -- long rightwards squiggle arrow
+ , { code = 0x02900, char = '⤀', class = 'rel', cs = 'nvtwoheadrightarrow' } -- rightwards two-headed arrow with vertical stroke
+ , { code = 0x02901, char = '⤁', class = 'rel', cs = 'nVtwoheadrightarrow' } -- rightwards two-headed arrow with double vertical stroke
+ , { code = 0x02902, char = '⤂', class = 'rel', cs = 'nvLeftarrow' } -- leftwards double arrow with vertical stroke
+ , { code = 0x02903, char = '⤃', class = 'rel', cs = 'nvRightarrow' } -- rightwards double arrow with vertical stroke
+ , { code = 0x02904, char = '⤄', class = 'rel', cs = 'nvLeftrightarrow' } -- left right double arrow with vertical stroke
+ , { code = 0x02905, char = '⤅', class = 'rel', cs = 'twoheadmapsto' } -- rightwards two-headed arrow from bar
+ , { code = 0x02906, char = '⤆', class = 'rel', cs = 'Mapsfrom' } -- leftwards double arrow from bar
+ , { code = 0x02907, char = '⤇', class = 'rel', cs = 'Mapsto' } -- rightwards double arrow from bar
+ , { code = 0x02908, char = '⤈', class = 'rel', cs = 'downarrowbarred' } -- downwards arrow with horizontal stroke
+ , { code = 0x02909, char = '⤉', class = 'rel', cs = 'uparrowbarred' } -- upwards arrow with horizontal stroke
+ , { code = 0x0290A, char = '⤊', class = 'rel', cs = 'Uuparrow' } -- upwards triple arrow
+ , { code = 0x0290B, char = '⤋', class = 'rel', cs = 'Ddownarrow' } -- downwards triple arrow
+ , { code = 0x0290C, char = '⤌', class = 'rel', cs = 'leftbkarrow' } -- leftwards double dash arrow
+ , { code = 0x0290D, char = '⤍', class = 'rel', cs = 'rightbkarrow' } -- rightwards double dash arrow
+ , { code = 0x0290E, char = '⤎', class = 'rel', cs = 'leftdbkarrow' } -- leftwards triple dash arrow
+ , { code = 0x0290F, char = '⤏', class = 'rel', cs = 'dbkarow' } -- rightwards triple dash arrow
+ , { code = 0x02910, char = '⤐', class = 'rel', cs = 'drbkarow' } -- rightwards two-headed triple dash arrow
+ , { code = 0x02911, char = '⤑', class = 'rel', cs = 'rightdotarrow' } -- rightwards arrow with dotted stem
+ , { code = 0x02912, char = '⤒', class = 'rel', cs = 'baruparrow' } -- upwards arrow to bar
+ , { code = 0x02913, char = '⤓', class = 'rel', cs = 'downarrowbar' } -- downwards arrow to bar
+ , { code = 0x02914, char = '⤔', class = 'rel', cs = 'nvrightarrowtail' } -- rightwards arrow with tail with vertical stroke
+ , { code = 0x02915, char = '⤕', class = 'rel', cs = 'nVrightarrowtail' } -- rightwards arrow with tail with double vertical stroke
+ , { code = 0x02916, char = '⤖', class = 'rel', cs = 'twoheadrightarrowtail' } -- rightwards two-headed arrow with tail
+ , { code = 0x02917, char = '⤗', class = 'rel', cs = 'nvtwoheadrightarrowtail' } -- rightwards two-headed arrow with tail with vertical stroke
+ , { code = 0x02918, char = '⤘', class = 'rel', cs = 'nVtwoheadrightarrowtail' } -- rightwards two-headed arrow with tail with double vertical stroke
+ , { code = 0x02919, char = '⤙', class = 'rel', cs = 'lefttail' } -- leftwards arrow-tail
+ , { code = 0x0291A, char = '⤚', class = 'rel', cs = 'righttail' } -- rightwards arrow-tail
+ , { code = 0x0291B, char = '⤛', class = 'rel', cs = 'leftdbltail' } -- leftwards double arrow-tail
+ , { code = 0x0291C, char = '⤜', class = 'rel', cs = 'rightdbltail' } -- rightwards double arrow-tail
+ , { code = 0x0291D, char = '⤝', class = 'rel', cs = 'diamondleftarrow' } -- leftwards arrow to black diamond
+ , { code = 0x0291E, char = '⤞', class = 'rel', cs = 'rightarrowdiamond' } -- rightwards arrow to black diamond
+ , { code = 0x0291F, char = '⤟', class = 'rel', cs = 'diamondleftarrowbar' } -- leftwards arrow from bar to black diamond
+ , { code = 0x02920, char = '⤠', class = 'rel', cs = 'barrightarrowdiamond' } -- rightwards arrow from bar to black diamond
+ , { code = 0x02921, char = '⤡', class = 'rel', cs = 'nwsearrow' } -- north west and south east arrow
+ , { code = 0x02922, char = '⤢', class = 'rel', cs = 'neswarrow' } -- north east and south west arrow
+ , { code = 0x02923, char = '⤣', class = 'rel', cs = 'hknwarrow' } -- north west arrow with hook
+ , { code = 0x02924, char = '⤤', class = 'rel', cs = 'hknearrow' } -- north east arrow with hook
+ , { code = 0x02925, char = '⤥', class = 'rel', cs = 'hksearrow' } -- south east arrow with hook
+ , { code = 0x02926, char = '⤦', class = 'rel', cs = 'hkswarrow' } -- south west arrow with hook
+ , { code = 0x02927, char = '⤧', class = 'rel', cs = 'tona' } -- north west arrow and north east arrow
+ , { code = 0x02928, char = '⤨', class = 'rel', cs = 'toea' } -- north east arrow and south east arrow
+ , { code = 0x02929, char = '⤩', class = 'rel', cs = 'tosa' } -- south east arrow and south west arrow
+ , { code = 0x0292A, char = '⤪', class = 'rel', cs = 'towa' } -- south west arrow and north west arrow
+ , { code = 0x0292B, char = '⤫', class = 'ord', cs = 'rdiagovfdiag' } -- rising diagonal crossing falling diagonal
+ , { code = 0x0292C, char = '⤬', class = 'ord', cs = 'fdiagovrdiag' } -- falling diagonal crossing rising diagonal
+ , { code = 0x0292D, char = '⤭', class = 'ord', cs = 'seovnearrow' } -- south east arrow crossing north east arrow
+ , { code = 0x0292E, char = '⤮', class = 'ord', cs = 'neovsearrow' } -- north east arrow crossing south east arrow
+ , { code = 0x0292F, char = '⤯', class = 'ord', cs = 'fdiagovnearrow' } -- falling diagonal crossing north east arrow
+ , { code = 0x02930, char = '⤰', class = 'ord', cs = 'rdiagovsearrow' } -- rising diagonal crossing south east arrow
+ , { code = 0x02931, char = '⤱', class = 'ord', cs = 'neovnwarrow' } -- north east arrow crossing north west arrow
+ , { code = 0x02932, char = '⤲', class = 'ord', cs = 'nwovnearrow' } -- north west arrow crossing north east arrow
+ , { code = 0x02933, char = '⤳', class = 'rel', cs = 'rightcurvedarrow' } -- wave arrow pointing directly right
+ , { code = 0x02934, char = '⤴', class = 'ord', cs = 'uprightcurvearrow' } -- arrow pointing rightwards then curving upwards
+ , { code = 0x02935, char = '⤵', class = 'ord', cs = 'downrightcurvedarrow' } -- arrow pointing rightwards then curving downwards
+ , { code = 0x02936, char = '⤶', class = 'rel', cs = 'leftdowncurvedarrow' } -- arrow pointing downwards then curving leftwards
+ , { code = 0x02937, char = '⤷', class = 'rel', cs = 'rightdowncurvedarrow' } -- arrow pointing downwards then curving rightwards
+ , { code = 0x02938, char = '⤸', class = 'rel', cs = 'cwrightarcarrow' } -- right-side arc clockwise arrow
+ , { code = 0x02939, char = '⤹', class = 'rel', cs = 'acwleftarcarrow' } -- left-side arc anticlockwise arrow
+ , { code = 0x0293A, char = '⤺', class = 'rel', cs = 'acwoverarcarrow' } -- top arc anticlockwise arrow
+ , { code = 0x0293B, char = '⤻', class = 'rel', cs = 'acwunderarcarrow' } -- bottom arc anticlockwise arrow
+ , { code = 0x0293C, char = '⤼', class = 'rel', cs = 'curvearrowrightminus' } -- top arc clockwise arrow with minus
+ , { code = 0x0293D, char = '⤽', class = 'rel', cs = 'curvearrowleftplus' } -- top arc anticlockwise arrow with plus
+ , { code = 0x0293E, char = '⤾', class = 'rel', cs = 'cwundercurvearrow' } -- lower right semicircular clockwise arrow
+ , { code = 0x0293F, char = '⤿', class = 'rel', cs = 'ccwundercurvearrow' } -- lower left semicircular anticlockwise arrow
+ , { code = 0x02940, char = '⥀', class = 'rel', cs = 'acwcirclearrow' } -- anticlockwise closed circle arrow
+ , { code = 0x02941, char = '⥁', class = 'rel', cs = 'cwcirclearrow' } -- clockwise closed circle arrow
+ , { code = 0x02942, char = '⥂', class = 'rel', cs = 'rightarrowshortleftarrow' } -- rightwards arrow above short leftwards arrow
+ , { code = 0x02943, char = '⥃', class = 'rel', cs = 'leftarrowshortrightarrow' } -- leftwards arrow above short rightwards arrow
+ , { code = 0x02944, char = '⥄', class = 'rel', cs = 'shortrightarrowleftarrow' } -- short rightwards arrow above leftwards arrow
+ , { code = 0x02945, char = '⥅', class = 'rel', cs = 'rightarrowplus' } -- rightwards arrow with plus below
+ , { code = 0x02946, char = '⥆', class = 'rel', cs = 'leftarrowplus' } -- leftwards arrow with plus below
+ , { code = 0x02947, char = '⥇', class = 'rel', cs = 'rightarrowx' } -- rightwards arrow through x
+ , { code = 0x02948, char = '⥈', class = 'rel', cs = 'leftrightarrowcircle' } -- left right arrow through small circle
+ , { code = 0x02949, char = '⥉', class = 'rel', cs = 'twoheaduparrowcircle' } -- upwards two-headed arrow from small circle
+ , { code = 0x0294A, char = '⥊', class = 'rel', cs = 'leftrightharpoonupdown' } -- left barb up right barb down harpoon
+ , { code = 0x0294B, char = '⥋', class = 'rel', cs = 'leftrightharpoondownup' } -- left barb down right barb up harpoon
+ , { code = 0x0294C, char = '⥌', class = 'rel', cs = 'updownharpoonrightleft' } -- up barb right down barb left harpoon
+ , { code = 0x0294D, char = '⥍', class = 'rel', cs = 'updownharpoonleftright' } -- up barb left down barb right harpoon
+ , { code = 0x0294E, char = '⥎', class = 'rel', cs = 'leftrightharpoonupup' } -- left barb up right barb up harpoon
+ , { code = 0x0294F, char = '⥏', class = 'rel', cs = 'updownharpoonrightright' } -- up barb right down barb right harpoon
+ , { code = 0x02950, char = '⥐', class = 'rel', cs = 'leftrightharpoondowndown' } -- left barb down right barb down harpoon
+ , { code = 0x02951, char = '⥑', class = 'rel', cs = 'updownharpoonleftleft' } -- up barb left down barb left harpoon
+ , { code = 0x02952, char = '⥒', class = 'rel', cs = 'barleftharpoonup' } -- leftwards harpoon with barb up to bar
+ , { code = 0x02953, char = '⥓', class = 'rel', cs = 'rightharpoonupbar' } -- rightwards harpoon with barb up to bar
+ , { code = 0x02954, char = '⥔', class = 'rel', cs = 'barupharpoonright' } -- upwards harpoon with barb right to bar
+ , { code = 0x02955, char = '⥕', class = 'rel', cs = 'downharpoonrightbar' } -- downwards harpoon with barb right to bar
+ , { code = 0x02956, char = '⥖', class = 'rel', cs = 'barleftharpoondown' } -- leftwards harpoon with barb down to bar
+ , { code = 0x02957, char = '⥗', class = 'rel', cs = 'rightharpoondownbar' } -- rightwards harpoon with barb down to bar
+ , { code = 0x02958, char = '⥘', class = 'rel', cs = 'barupharpoonleft' } -- upwards harpoon with barb left to bar
+ , { code = 0x02959, char = '⥙', class = 'rel', cs = 'downharpoonleftbar' } -- downwards harpoon with barb left to bar
+ , { code = 0x0295A, char = '⥚', class = 'rel', cs = 'leftharpoonupbar' } -- leftwards harpoon with barb up from bar
+ , { code = 0x0295B, char = '⥛', class = 'rel', cs = 'barrightharpoonup' } -- rightwards harpoon with barb up from bar
+ , { code = 0x0295C, char = '⥜', class = 'rel', cs = 'upharpoonrightbar' } -- upwards harpoon with barb right from bar
+ , { code = 0x0295D, char = '⥝', class = 'rel', cs = 'bardownharpoonright' } -- downwards harpoon with barb right from bar
+ , { code = 0x0295E, char = '⥞', class = 'rel', cs = 'leftharpoondownbar' } -- leftwards harpoon with barb down from bar
+ , { code = 0x0295F, char = '⥟', class = 'rel', cs = 'barrightharpoondown' } -- rightwards harpoon with barb down from bar
+ , { code = 0x02960, char = '⥠', class = 'rel', cs = 'upharpoonleftbar' } -- upwards harpoon with barb left from bar
+ , { code = 0x02961, char = '⥡', class = 'rel', cs = 'bardownharpoonleft' } -- downwards harpoon with barb left from bar
+ , { code = 0x02962, char = '⥢', class = 'rel', cs = 'leftharpoonsupdown' } -- leftwards harpoon with barb up above leftwards harpoon with barb down
+ , { code = 0x02963, char = '⥣', class = 'rel', cs = 'upharpoonsleftright' } -- upwards harpoon with barb left beside upwards harpoon with barb right
+ , { code = 0x02964, char = '⥤', class = 'rel', cs = 'rightharpoonsupdown' } -- rightwards harpoon with barb up above rightwards harpoon with barb down
+ , { code = 0x02965, char = '⥥', class = 'rel', cs = 'downharpoonsleftright' } -- downwards harpoon with barb left beside downwards harpoon with barb right
+ , { code = 0x02966, char = '⥦', class = 'rel', cs = 'leftrightharpoonsup' } -- leftwards harpoon with barb up above rightwards harpoon with barb up
+ , { code = 0x02967, char = '⥧', class = 'rel', cs = 'leftrightharpoonsdown' } -- leftwards harpoon with barb down above rightwards harpoon with barb down
+ , { code = 0x02968, char = '⥨', class = 'rel', cs = 'rightleftharpoonsup' } -- rightwards harpoon with barb up above leftwards harpoon with barb up
+ , { code = 0x02969, char = '⥩', class = 'rel', cs = 'rightleftharpoonsdown' } -- rightwards harpoon with barb down above leftwards harpoon with barb down
+ , { code = 0x0296A, char = '⥪', class = 'rel', cs = 'leftharpoonupdash' } -- leftwards harpoon with barb up above long dash
+ , { code = 0x0296B, char = '⥫', class = 'rel', cs = 'dashleftharpoondown' } -- leftwards harpoon with barb down below long dash
+ , { code = 0x0296C, char = '⥬', class = 'rel', cs = 'rightharpoonupdash' } -- rightwards harpoon with barb up above long dash
+ , { code = 0x0296D, char = '⥭', class = 'rel', cs = 'dashrightharpoondown' } -- rightwards harpoon with barb down below long dash
+ , { code = 0x0296E, char = '⥮', class = 'rel', cs = 'updownharpoonsleftright' } -- upwards harpoon with barb left beside downwards harpoon with barb right
+ , { code = 0x0296F, char = '⥯', class = 'rel', cs = 'downupharpoonsleftright' } -- downwards harpoon with barb left beside upwards harpoon with barb right
+ , { code = 0x02970, char = '⥰', class = 'rel', cs = 'rightimply' } -- right double arrow with rounded head
+ , { code = 0x02971, char = '⥱', class = 'rel', cs = 'equalrightarrow' } -- equals sign above rightwards arrow
+ , { code = 0x02972, char = '⥲', class = 'rel', cs = 'similarrightarrow' } -- tilde operator above rightwards arrow
+ , { code = 0x02973, char = '⥳', class = 'rel', cs = 'leftarrowsimilar' } -- leftwards arrow above tilde operator
+ , { code = 0x02974, char = '⥴', class = 'rel', cs = 'rightarrowsimilar' } -- rightwards arrow above tilde operator
+ , { code = 0x02975, char = '⥵', class = 'rel', cs = 'rightarrowapprox' } -- rightwards arrow above almost equal to
+ , { code = 0x02976, char = '⥶', class = 'rel', cs = 'ltlarr' } -- less-than above leftwards arrow
+ , { code = 0x02977, char = '⥷', class = 'rel', cs = 'leftarrowless' } -- leftwards arrow through less-than
+ , { code = 0x02978, char = '⥸', class = 'rel', cs = 'gtrarr' } -- greater-than above rightwards arrow
+ , { code = 0x02979, char = '⥹', class = 'rel', cs = 'subrarr' } -- subset above rightwards arrow
+ , { code = 0x0297A, char = '⥺', class = 'rel', cs = 'leftarrowsubset' } -- leftwards arrow through subset
+ , { code = 0x0297B, char = '⥻', class = 'rel', cs = 'suplarr' } -- superset above leftwards arrow
+ , { code = 0x0297C, char = '⥼', class = 'rel', cs = 'leftfishtail' } -- left fish tail
+ , { code = 0x0297D, char = '⥽', class = 'rel', cs = 'rightfishtail' } -- right fish tail
+ , { code = 0x0297E, char = '⥾', class = 'rel', cs = 'upfishtail' } -- up fish tail
+ , { code = 0x0297F, char = '⥿', class = 'rel', cs = 'downfishtail' } -- down fish tail
+ , { code = 0x02980, char = '⦀', class = 'fence', cs = 'Vvert' } -- triple vertical bar delimiter
+ , { code = 0x02981, char = '⦁', class = 'ord', cs = 'mdsmblkcircle' } -- z notation spot
+ , { code = 0x02982, char = '⦂', class = 'bin', cs = 'typecolon' } -- z notation type colon
+ , { code = 0x02983, char = '⦃', class = 'open', cs = 'lBrace' } -- left white curly bracket
+ , { code = 0x02984, char = '⦄', class = 'close', cs = 'rBrace' } -- right white curly bracket
+ , { code = 0x02985, char = '⦅', class = 'open', cs = 'lParen' } -- left white parenthesis
+ , { code = 0x02986, char = '⦆', class = 'close', cs = 'rParen' } -- right white parenthesis
+ , { code = 0x02987, char = '⦇', class = 'open', cs = 'llparenthesis' } -- z notation left image bracket
+ , { code = 0x02988, char = '⦈', class = 'close', cs = 'rrparenthesis' } -- z notation right image bracket
+ , { code = 0x02989, char = '⦉', class = 'open', cs = 'llangle' } -- z notation left binding bracket
+ , { code = 0x0298A, char = '⦊', class = 'close', cs = 'rrangle' } -- z notation right binding bracket
+ , { code = 0x0298B, char = '⦋', class = 'open', cs = 'lbrackubar' } -- left square bracket with underbar
+ , { code = 0x0298C, char = '⦌', class = 'close', cs = 'rbrackubar' } -- right square bracket with underbar
+ , { code = 0x0298D, char = '⦍', class = 'open', cs = 'lbrackultick' } -- left square bracket with tick in top corner
+ , { code = 0x0298E, char = '⦎', class = 'close', cs = 'rbracklrtick' } -- right square bracket with tick in bottom corner
+ , { code = 0x0298F, char = '⦏', class = 'open', cs = 'lbracklltick' } -- left square bracket with tick in bottom corner
+ , { code = 0x02990, char = '⦐', class = 'close', cs = 'rbrackurtick' } -- right square bracket with tick in top corner
+ , { code = 0x02991, char = '⦑', class = 'open', cs = 'langledot' } -- left angle bracket with dot
+ , { code = 0x02992, char = '⦒', class = 'close', cs = 'rangledot' } -- right angle bracket with dot
+ , { code = 0x02993, char = '⦓', class = 'open', cs = 'lparenless' } -- left arc less-than bracket
+ , { code = 0x02994, char = '⦔', class = 'close', cs = 'rparengtr' } -- right arc greater-than bracket
+ , { code = 0x02995, char = '⦕', class = 'open', cs = 'Lparengtr' } -- double left arc greater-than bracket
+ , { code = 0x02996, char = '⦖', class = 'close', cs = 'Rparenless' } -- double right arc less-than bracket
+ , { code = 0x02997, char = '⦗', class = 'open', cs = 'lblkbrbrak' } -- left black tortoise shell bracket
+ , { code = 0x02998, char = '⦘', class = 'close', cs = 'rblkbrbrak' } -- right black tortoise shell bracket
+ , { code = 0x02999, char = '⦙', class = 'ord', cs = 'fourvdots' } -- dotted fence
+ , { code = 0x0299A, char = '⦚', class = 'ord', cs = 'vzigzag' } -- vertical zigzag line
+ , { code = 0x0299B, char = '⦛', class = 'ord', cs = 'measuredangleleft' } -- measured angle opening left
+ , { code = 0x0299C, char = '⦜', class = 'ord', cs = 'rightanglesqr' } -- right angle variant with square
+ , { code = 0x0299D, char = '⦝', class = 'ord', cs = 'rightanglemdot' } -- measured right angle with dot
+ , { code = 0x0299E, char = '⦞', class = 'ord', cs = 'angles' } -- angle with s inside
+ , { code = 0x0299F, char = '⦟', class = 'ord', cs = 'angdnr' } -- acute angle
+ , { code = 0x029A0, char = '⦠', class = 'ord', cs = 'gtlpar' } -- spherical angle opening left
+ , { code = 0x029A1, char = '⦡', class = 'ord', cs = 'sphericalangleup' } -- spherical angle opening up
+ , { code = 0x029A2, char = '⦢', class = 'ord', cs = 'turnangle' } -- turned angle
+ , { code = 0x029A3, char = '⦣', class = 'ord', cs = 'revangle' } -- reversed angle
+ , { code = 0x029A4, char = '⦤', class = 'ord', cs = 'angleubar' } -- angle with underbar
+ , { code = 0x029A5, char = '⦥', class = 'ord', cs = 'revangleubar' } -- reversed angle with underbar
+ , { code = 0x029A6, char = '⦦', class = 'ord', cs = 'wideangledown' } -- oblique angle opening up
+ , { code = 0x029A7, char = '⦧', class = 'ord', cs = 'wideangleup' } -- oblique angle opening down
+ , { code = 0x029A8, char = '⦨', class = 'ord', cs = 'measanglerutone' } -- measured angle with open arm ending in arrow pointing up and right
+ , { code = 0x029A9, char = '⦩', class = 'ord', cs = 'measanglelutonw' } -- measured angle with open arm ending in arrow pointing up and left
+ , { code = 0x029AA, char = '⦪', class = 'ord', cs = 'measanglerdtose' } -- measured angle with open arm ending in arrow pointing down and right
+ , { code = 0x029AB, char = '⦫', class = 'ord', cs = 'measangleldtosw' } -- measured angle with open arm ending in arrow pointing down and left
+ , { code = 0x029AC, char = '⦬', class = 'ord', cs = 'measangleurtone' } -- measured angle with open arm ending in arrow pointing right and up
+ , { code = 0x029AD, char = '⦭', class = 'ord', cs = 'measangleultonw' } -- measured angle with open arm ending in arrow pointing left and up
+ , { code = 0x029AE, char = '⦮', class = 'ord', cs = 'measangledrtose' } -- measured angle with open arm ending in arrow pointing right and down
+ , { code = 0x029AF, char = '⦯', class = 'ord', cs = 'measangledltosw' } -- measured angle with open arm ending in arrow pointing left and down
+ , { code = 0x029B0, char = '⦰', class = 'ord', cs = 'revemptyset' } -- reversed empty set
+ , { code = 0x029B1, char = '⦱', class = 'ord', cs = 'emptysetobar' } -- empty set with overbar
+ , { code = 0x029B2, char = '⦲', class = 'ord', cs = 'emptysetocirc' } -- empty set with small circle above
+ , { code = 0x029B3, char = '⦳', class = 'ord', cs = 'emptysetoarr' } -- empty set with right arrow above
+ , { code = 0x029B4, char = '⦴', class = 'ord', cs = 'emptysetoarrl' } -- empty set with left arrow above
+ , { code = 0x029B5, char = '⦵', class = 'bin', cs = 'circlehbar' } -- circle with horizontal bar
+ , { code = 0x029B6, char = '⦶', class = 'bin', cs = 'circledvert' } -- circled vertical bar
+ , { code = 0x029B7, char = '⦷', class = 'bin', cs = 'circledparallel' } -- circled parallel
+ , { code = 0x029B8, char = '⦸', class = 'bin', cs = 'obslash' } -- circled reverse solidus
+ , { code = 0x029B9, char = '⦹', class = 'bin', cs = 'operp' } -- circled perpendicular
+ , { code = 0x029BA, char = '⦺', class = 'ord', cs = 'obot' } -- circle divided by horizontal bar and top half divided by vertical bar
+ , { code = 0x029BB, char = '⦻', class = 'ord', cs = 'olcross' } -- circle with superimposed x
+ , { code = 0x029BC, char = '⦼', class = 'ord', cs = 'odotslashdot' } -- circled anticlockwise-rotated division sign
+ , { code = 0x029BD, char = '⦽', class = 'ord', cs = 'uparrowoncircle' } -- up arrow through circle
+ , { code = 0x029BE, char = '⦾', class = 'ord', cs = 'circledwhitebullet' } -- circled white bullet
+ , { code = 0x029BF, char = '⦿', class = 'ord', cs = 'circledbullet' } -- circled bullet
+ , { code = 0x029C0, char = '⧀', class = 'bin', cs = 'olessthan' } -- circled less-than
+ , { code = 0x029C1, char = '⧁', class = 'bin', cs = 'ogreaterthan' } -- circled greater-than
+ , { code = 0x029C2, char = '⧂', class = 'ord', cs = 'cirscir' } -- circle with small circle to the right
+ , { code = 0x029C3, char = '⧃', class = 'ord', cs = 'cirE' } -- circle with two horizontal strokes to the right
+ , { code = 0x029C4, char = '⧄', class = 'bin', cs = 'boxdiag' } -- squared rising diagonal slash
+ , { code = 0x029C5, char = '⧅', class = 'bin', cs = 'boxbslash' } -- squared falling diagonal slash
+ , { code = 0x029C6, char = '⧆', class = 'bin', cs = 'boxast' } -- squared asterisk
+ , { code = 0x029C7, char = '⧇', class = 'bin', cs = 'boxcircle' } -- squared small circle
+ , { code = 0x029C8, char = '⧈', class = 'bin', cs = 'boxbox' } -- squared square
+ , { code = 0x029C9, char = '⧉', class = 'ord', cs = 'boxonbox' } -- two joined squares
+ , { code = 0x029CA, char = '⧊', class = 'ord', cs = 'triangleodot' } -- triangle with dot above
+ , { code = 0x029CB, char = '⧋', class = 'ord', cs = 'triangleubar' } -- triangle with underbar
+ , { code = 0x029CC, char = '⧌', class = 'ord', cs = 'triangles' } -- s in triangle
+ , { code = 0x029CD, char = '⧍', class = 'bin', cs = 'triangleserifs' } -- triangle with serifs at bottom
+ , { code = 0x029CE, char = '⧎', class = 'rel', cs = 'rtriltri' } -- right triangle above left triangle
+ , { code = 0x029CF, char = '⧏', class = 'rel', cs = 'ltrivb' } -- left triangle beside vertical bar
+ , { code = 0x029D0, char = '⧐', class = 'rel', cs = 'vbrtri' } -- vertical bar beside right triangle
+ , { code = 0x029D1, char = '⧑', class = 'rel', cs = 'lfbowtie' } -- bowtie with left half black
+ , { code = 0x029D2, char = '⧒', class = 'rel', cs = 'rfbowtie' } -- bowtie with right half black
+ , { code = 0x029D3, char = '⧓', class = 'rel', cs = 'fbowtie' } -- black bowtie
+ , { code = 0x029D4, char = '⧔', class = 'rel', cs = 'lftimes' } -- times with left half black
+ , { code = 0x029D5, char = '⧕', class = 'rel', cs = 'rftimes' } -- times with right half black
+ , { code = 0x029D6, char = '⧖', class = 'bin', cs = 'hourglass' } -- white hourglass
+ , { code = 0x029D7, char = '⧗', class = 'bin', cs = 'blackhourglass' } -- black hourglass
+ , { code = 0x029D8, char = '⧘', class = 'open', cs = 'lvzigzag' } -- left wiggly fence
+ , { code = 0x029D9, char = '⧙', class = 'close', cs = 'rvzigzag' } -- right wiggly fence
+ , { code = 0x029DA, char = '⧚', class = 'open', cs = 'Lvzigzag' } -- left double wiggly fence
+ , { code = 0x029DB, char = '⧛', class = 'close', cs = 'Rvzigzag' } -- right double wiggly fence
+ , { code = 0x029DC, char = '⧜', class = 'ord', cs = 'iinfin' } -- incomplete infinity
+ , { code = 0x029DD, char = '⧝', class = 'ord', cs = 'tieinfty' } -- tie over infinity
+ , { code = 0x029DE, char = '⧞', class = 'ord', cs = 'nvinfty' } -- infinity negated with vertical bar
+ , { code = 0x029DF, char = '⧟', class = 'rel', cs = 'dualmap' } -- double-ended multimap
+ , { code = 0x029E0, char = '⧠', class = 'ord', cs = 'laplac' } -- square with contoured outline
+ , { code = 0x029E1, char = '⧡', class = 'rel', cs = 'lrtriangleeq' } -- increases as
+ , { code = 0x029E2, char = '⧢', class = 'bin', cs = 'shuffle' } -- shuffle product
+ , { code = 0x029E3, char = '⧣', class = 'rel', cs = 'eparsl' } -- equals sign and slanted parallel
+ , { code = 0x029E4, char = '⧤', class = 'rel', cs = 'smeparsl' } -- equals sign and slanted parallel with tilde above
+ , { code = 0x029E5, char = '⧥', class = 'rel', cs = 'eqvparsl' } -- identical to and slanted parallel
+ , { code = 0x029E6, char = '⧦', class = 'rel', cs = 'gleichstark' } -- gleich stark
+ , { code = 0x029E7, char = '⧧', class = 'ord', cs = 'thermod' } -- thermodynamic
+ , { code = 0x029E8, char = '⧨', class = 'ord', cs = 'downtriangleleftblack' } -- down-pointing triangle with left half black
+ , { code = 0x029E9, char = '⧩', class = 'ord', cs = 'downtrianglerightblack' } -- down-pointing triangle with right half black
+ , { code = 0x029EA, char = '⧪', class = 'ord', cs = 'blackdiamonddownarrow' } -- black diamond with down arrow
+ , { code = 0x029EB, char = '⧫', class = 'bin', cs = 'mdlgblklozenge' } -- black lozenge
+ , { code = 0x029EC, char = '⧬', class = 'ord', cs = 'circledownarrow' } -- white circle with down arrow
+ , { code = 0x029ED, char = '⧭', class = 'ord', cs = 'blackcircledownarrow' } -- black circle with down arrow
+ , { code = 0x029EE, char = '⧮', class = 'ord', cs = 'errbarsquare' } -- error-barred white square
+ , { code = 0x029EF, char = '⧯', class = 'ord', cs = 'errbarblacksquare' } -- error-barred black square
+ , { code = 0x029F0, char = '⧰', class = 'ord', cs = 'errbardiamond' } -- error-barred white diamond
+ , { code = 0x029F1, char = '⧱', class = 'ord', cs = 'errbarblackdiamond' } -- error-barred black diamond
+ , { code = 0x029F2, char = '⧲', class = 'ord', cs = 'errbarcircle' } -- error-barred white circle
+ , { code = 0x029F3, char = '⧳', class = 'ord', cs = 'errbarblackcircle' } -- error-barred black circle
+ , { code = 0x029F4, char = '⧴', class = 'rel', cs = 'ruledelayed' } -- rule-delayed
+ , { code = 0x029F5, char = '⧵', class = 'bin', cs = 'setminus' } -- reverse solidus operator
+ , { code = 0x029F6, char = '⧶', class = 'bin', cs = 'dsol' } -- solidus with overbar
+ , { code = 0x029F7, char = '⧷', class = 'bin', cs = 'rsolbar' } -- reverse solidus with horizontal stroke
+ , { code = 0x029F8, char = '⧸', class = 'op', cs = 'xsol' } -- big solidus
+ , { code = 0x029F9, char = '⧹', class = 'op', cs = 'xbsol' } -- big reverse solidus
+ , { code = 0x029FA, char = '⧺', class = 'bin', cs = 'doubleplus' } -- double plus
+ , { code = 0x029FB, char = '⧻', class = 'bin', cs = 'tripleplus' } -- triple plus
+ , { code = 0x029FC, char = '⧼', class = 'open', cs = 'lcurvyangle' } -- left-pointing curved angle bracket
+ , { code = 0x029FD, char = '⧽', class = 'close', cs = 'rcurvyangle' } -- right-pointing curved angle bracket
+ , { code = 0x029FE, char = '⧾', class = 'bin', cs = 'tplus' } -- tiny
+ , { code = 0x029FF, char = '⧿', class = 'bin', cs = 'tminus' } -- miny
+ , { code = 0x02A00, char = '⨀', class = 'op', cs = 'bigodot' } -- n-ary circled dot operator
+ , { code = 0x02A01, char = '⨁', class = 'op', cs = 'bigoplus' } -- n-ary circled plus operator
+ , { code = 0x02A02, char = '⨂', class = 'op', cs = 'bigotimes' } -- n-ary circled times operator
+ , { code = 0x02A03, char = '⨃', class = 'op', cs = 'bigcupdot' } -- n-ary union operator with dot
+ , { code = 0x02A04, char = '⨄', class = 'op', cs = 'biguplus' } -- n-ary union operator with plus
+ , { code = 0x02A05, char = '⨅', class = 'op', cs = 'bigsqcap' } -- n-ary square intersection operator
+ , { code = 0x02A06, char = '⨆', class = 'op', cs = 'bigsqcup' } -- n-ary square union operator
+ , { code = 0x02A07, char = '⨇', class = 'op', cs = 'conjquant' } -- two logical and operator
+ , { code = 0x02A08, char = '⨈', class = 'op', cs = 'disjquant' } -- two logical or operator
+ , { code = 0x02A09, char = '⨉', class = 'op', cs = 'bigtimes' } -- n-ary times operator
+ , { code = 0x02A0A, char = '⨊', class = 'op', cs = 'modtwosum' } -- modulo two sum
+ , { code = 0x02A0B, char = '⨋', class = 'op', cs = 'sumint' } -- summation with integral
+ , { code = 0x02A0C, char = '⨌', class = 'op', cs = 'iiiint' } -- quadruple integral operator
+ , { code = 0x02A0D, char = '⨍', class = 'op', cs = 'intbar' } -- finite part integral
+ , { code = 0x02A0E, char = '⨎', class = 'op', cs = 'intBar' } -- integral with double stroke
+ , { code = 0x02A0F, char = '⨏', class = 'op', cs = 'fint' } -- integral average with slash
+ , { code = 0x02A10, char = '⨐', class = 'op', cs = 'cirfnint' } -- circulation function
+ , { code = 0x02A11, char = '⨑', class = 'op', cs = 'awint' } -- anticlockwise integration
+ , { code = 0x02A12, char = '⨒', class = 'op', cs = 'rppolint' } -- line integration with rectangular path around pole
+ , { code = 0x02A13, char = '⨓', class = 'op', cs = 'scpolint' } -- line integration with semicircular path around pole
+ , { code = 0x02A14, char = '⨔', class = 'op', cs = 'npolint' } -- line integration not including the pole
+ , { code = 0x02A15, char = '⨕', class = 'op', cs = 'pointint' } -- integral around a point operator
+ , { code = 0x02A16, char = '⨖', class = 'op', cs = 'sqint' } -- quaternion integral operator
+ , { code = 0x02A17, char = '⨗', class = 'op', cs = 'intlarhk' } -- integral with leftwards arrow with hook
+ , { code = 0x02A18, char = '⨘', class = 'op', cs = 'intx' } -- integral with times sign
+ , { code = 0x02A19, char = '⨙', class = 'op', cs = 'intcap' } -- integral with intersection
+ , { code = 0x02A1A, char = '⨚', class = 'op', cs = 'intcup' } -- integral with union
+ , { code = 0x02A1B, char = '⨛', class = 'op', cs = 'upint' } -- integral with overbar
+ , { code = 0x02A1C, char = '⨜', class = 'op', cs = 'lowint' } -- integral with underbar
+ , { code = 0x02A1D, char = '⨝', class = 'op', cs = 'Join' } -- join
+ , { code = 0x02A1E, char = '⨞', class = 'op', cs = 'bigtriangleleft' } -- large left triangle operator
+ , { code = 0x02A1F, char = '⨟', class = 'op', cs = 'zcmp' } -- z notation schema composition
+ , { code = 0x02A20, char = '⨠', class = 'op', cs = 'zpipe' } -- z notation schema piping
+ , { code = 0x02A21, char = '⨡', class = 'op', cs = 'zproject' } -- z notation schema projection
+ , { code = 0x02A22, char = '⨢', class = 'bin', cs = 'ringplus' } -- plus sign with small circle above
+ , { code = 0x02A23, char = '⨣', class = 'bin', cs = 'plushat' } -- plus sign with circumflex accent above
+ , { code = 0x02A24, char = '⨤', class = 'bin', cs = 'simplus' } -- plus sign with tilde above
+ , { code = 0x02A25, char = '⨥', class = 'bin', cs = 'plusdot' } -- plus sign with dot below
+ , { code = 0x02A26, char = '⨦', class = 'bin', cs = 'plussim' } -- plus sign with tilde below
+ , { code = 0x02A27, char = '⨧', class = 'bin', cs = 'plussubtwo' } -- plus sign with subscript two
+ , { code = 0x02A28, char = '⨨', class = 'bin', cs = 'plustrif' } -- plus sign with black triangle
+ , { code = 0x02A29, char = '⨩', class = 'bin', cs = 'commaminus' } -- minus sign with comma above
+ , { code = 0x02A2A, char = '⨪', class = 'bin', cs = 'minusdot' } -- minus sign with dot below
+ , { code = 0x02A2B, char = '⨫', class = 'bin', cs = 'minusfdots' } -- minus sign with falling dots
+ , { code = 0x02A2C, char = '⨬', class = 'bin', cs = 'minusrdots' } -- minus sign with rising dots
+ , { code = 0x02A2D, char = '⨭', class = 'bin', cs = 'opluslhrim' } -- plus sign in left half circle
+ , { code = 0x02A2E, char = '⨮', class = 'bin', cs = 'oplusrhrim' } -- plus sign in right half circle
+ , { code = 0x02A2F, char = '⨯', class = 'bin', cs = 'vectimes' } -- vector or cross product
+ , { code = 0x02A30, char = '⨰', class = 'bin', cs = 'dottimes' } -- multiplication sign with dot above
+ , { code = 0x02A31, char = '⨱', class = 'bin', cs = 'timesbar' } -- multiplication sign with underbar
+ , { code = 0x02A32, char = '⨲', class = 'bin', cs = 'btimes' } -- semidirect product with bottom closed
+ , { code = 0x02A33, char = '⨳', class = 'bin', cs = 'smashtimes' } -- smash product
+ , { code = 0x02A34, char = '⨴', class = 'bin', cs = 'otimeslhrim' } -- multiplication sign in left half circle
+ , { code = 0x02A35, char = '⨵', class = 'bin', cs = 'otimesrhrim' } -- multiplication sign in right half circle
+ , { code = 0x02A36, char = '⨶', class = 'bin', cs = 'otimeshat' } -- circled multiplication sign with circumflex accent
+ , { code = 0x02A37, char = '⨷', class = 'bin', cs = 'Otimes' } -- multiplication sign in double circle
+ , { code = 0x02A38, char = '⨸', class = 'bin', cs = 'odiv' } -- circled division sign
+ , { code = 0x02A39, char = '⨹', class = 'bin', cs = 'triangleplus' } -- plus sign in triangle
+ , { code = 0x02A3A, char = '⨺', class = 'bin', cs = 'triangleminus' } -- minus sign in triangle
+ , { code = 0x02A3B, char = '⨻', class = 'bin', cs = 'triangletimes' } -- multiplication sign in triangle
+ , { code = 0x02A3C, char = '⨼', class = 'bin', cs = 'intprod' } -- interior product
+ , { code = 0x02A3D, char = '⨽', class = 'bin', cs = 'intprodr' } -- righthand interior product
+ , { code = 0x02A3E, char = '⨾', class = 'bin', cs = 'fcmp' } -- z notation relational composition
+ , { code = 0x02A3F, char = '⨿', class = 'bin', cs = 'amalg' } -- amalgamation or coproduct
+ , { code = 0x02A40, char = '⩀', class = 'bin', cs = 'capdot' } -- intersection with dot
+ , { code = 0x02A41, char = '⩁', class = 'bin', cs = 'uminus' } -- union with minus sign
+ , { code = 0x02A42, char = '⩂', class = 'bin', cs = 'barcup' } -- union with overbar
+ , { code = 0x02A43, char = '⩃', class = 'bin', cs = 'barcap' } -- intersection with overbar
+ , { code = 0x02A44, char = '⩄', class = 'bin', cs = 'capwedge' } -- intersection with logical and
+ , { code = 0x02A45, char = '⩅', class = 'bin', cs = 'cupvee' } -- union with logical or
+ , { code = 0x02A46, char = '⩆', class = 'bin', cs = 'cupovercap' } -- union above intersection
+ , { code = 0x02A47, char = '⩇', class = 'bin', cs = 'capovercup' } -- intersection above union
+ , { code = 0x02A48, char = '⩈', class = 'bin', cs = 'cupbarcap' } -- union above bar above intersection
+ , { code = 0x02A49, char = '⩉', class = 'bin', cs = 'capbarcup' } -- intersection above bar above union
+ , { code = 0x02A4A, char = '⩊', class = 'bin', cs = 'twocups' } -- union beside and joined with union
+ , { code = 0x02A4B, char = '⩋', class = 'bin', cs = 'twocaps' } -- intersection beside and joined with intersection
+ , { code = 0x02A4C, char = '⩌', class = 'bin', cs = 'closedvarcup' } -- closed union with serifs
+ , { code = 0x02A4D, char = '⩍', class = 'bin', cs = 'closedvarcap' } -- closed intersection with serifs
+ , { code = 0x02A4E, char = '⩎', class = 'bin', cs = 'Sqcap' } -- double square intersection
+ , { code = 0x02A4F, char = '⩏', class = 'bin', cs = 'Sqcup' } -- double square union
+ , { code = 0x02A50, char = '⩐', class = 'bin', cs = 'closedvarcupsmashprod' } -- closed union with serifs and smash product
+ , { code = 0x02A51, char = '⩑', class = 'bin', cs = 'wedgeodot' } -- logical and with dot above
+ , { code = 0x02A52, char = '⩒', class = 'bin', cs = 'veeodot' } -- logical or with dot above
+ , { code = 0x02A53, char = '⩓', class = 'bin', cs = 'Wedge' } -- double logical and
+ , { code = 0x02A54, char = '⩔', class = 'bin', cs = 'Vee' } -- double logical or
+ , { code = 0x02A55, char = '⩕', class = 'bin', cs = 'wedgeonwedge' } -- two intersecting logical and
+ , { code = 0x02A56, char = '⩖', class = 'bin', cs = 'veeonvee' } -- two intersecting logical or
+ , { code = 0x02A57, char = '⩗', class = 'bin', cs = 'bigslopedvee' } -- sloping large or
+ , { code = 0x02A58, char = '⩘', class = 'bin', cs = 'bigslopedwedge' } -- sloping large and
+ , { code = 0x02A59, char = '⩙', class = 'rel', cs = 'veeonwedge' } -- logical or overlapping logical and
+ , { code = 0x02A5A, char = '⩚', class = 'bin', cs = 'wedgemidvert' } -- logical and with middle stem
+ , { code = 0x02A5B, char = '⩛', class = 'bin', cs = 'veemidvert' } -- logical or with middle stem
+ , { code = 0x02A5C, char = '⩜', class = 'bin', cs = 'midbarwedge' } -- logical and with horizontal dash
+ , { code = 0x02A5D, char = '⩝', class = 'bin', cs = 'midbarvee' } -- logical or with horizontal dash
+ , { code = 0x02A5E, char = '⩞', class = 'bin', cs = 'doublebarwedge' } -- logical and with double overbar
+ , { code = 0x02A5F, char = '⩟', class = 'bin', cs = 'wedgebar' } -- logical and with underbar
+ , { code = 0x02A60, char = '⩠', class = 'bin', cs = 'wedgedoublebar' } -- logical and with double underbar
+ , { code = 0x02A61, char = '⩡', class = 'bin', cs = 'varveebar' } -- small vee with underbar
+ , { code = 0x02A62, char = '⩢', class = 'bin', cs = 'doublebarvee' } -- logical or with double overbar
+ , { code = 0x02A63, char = '⩣', class = 'bin', cs = 'veedoublebar' } -- logical or with double underbar
+ , { code = 0x02A64, char = '⩤', class = 'bin', cs = 'dsub' } -- z notation domain antirestriction
+ , { code = 0x02A65, char = '⩥', class = 'bin', cs = 'rsub' } -- z notation range antirestriction
+ , { code = 0x02A66, char = '⩦', class = 'rel', cs = 'eqdot' } -- equals sign with dot below
+ , { code = 0x02A67, char = '⩧', class = 'rel', cs = 'dotequiv' } -- identical with dot above
+ , { code = 0x02A68, char = '⩨', class = 'rel', cs = 'equivVert' } -- triple horizontal bar with double vertical stroke
+ , { code = 0x02A69, char = '⩩', class = 'rel', cs = 'equivVvert' } -- triple horizontal bar with triple vertical stroke
+ , { code = 0x02A6A, char = '⩪', class = 'rel', cs = 'dotsim' } -- tilde operator with dot above
+ , { code = 0x02A6B, char = '⩫', class = 'rel', cs = 'simrdots' } -- tilde operator with rising dots
+ , { code = 0x02A6C, char = '⩬', class = 'rel', cs = 'simminussim' } -- similar minus similar
+ , { code = 0x02A6D, char = '⩭', class = 'rel', cs = 'congdot' } -- congruent with dot above
+ , { code = 0x02A6E, char = '⩮', class = 'rel', cs = 'asteq' } -- equals with asterisk
+ , { code = 0x02A6F, char = '⩯', class = 'rel', cs = 'hatapprox' } -- almost equal to with circumflex accent
+ , { code = 0x02A70, char = '⩰', class = 'rel', cs = 'approxeqq' } -- approximately equal or equal to
+ , { code = 0x02A71, char = '⩱', class = 'bin', cs = 'eqqplus' } -- equals sign above plus sign
+ , { code = 0x02A72, char = '⩲', class = 'bin', cs = 'pluseqq' } -- plus sign above equals sign
+ , { code = 0x02A73, char = '⩳', class = 'rel', cs = 'eqqsim' } -- equals sign above tilde operator
+ , { code = 0x02A74, char = '⩴', class = 'rel', cs = 'Coloneq' } -- double colon equal
+ , { code = 0x02A75, char = '⩵', class = 'rel', cs = 'eqeq' } -- two consecutive equals signs
+ , { code = 0x02A76, char = '⩶', class = 'rel', cs = 'eqeqeq' } -- three consecutive equals signs
+ , { code = 0x02A77, char = '⩷', class = 'rel', cs = 'ddotseq' } -- equals sign with two dots above and two dots below
+ , { code = 0x02A78, char = '⩸', class = 'rel', cs = 'equivDD' } -- equivalent with four dots above
+ , { code = 0x02A79, char = '⩹', class = 'rel', cs = 'ltcir' } -- less-than with circle inside
+ , { code = 0x02A7A, char = '⩺', class = 'rel', cs = 'gtcir' } -- greater-than with circle inside
+ , { code = 0x02A7B, char = '⩻', class = 'rel', cs = 'ltquest' } -- less-than with question mark above
+ , { code = 0x02A7C, char = '⩼', class = 'rel', cs = 'gtquest' } -- greater-than with question mark above
+ , { code = 0x02A7D, char = '⩽', class = 'rel', cs = 'leqslant' } -- less-than or slanted equal to
+ , { code = 0x02A7E, char = '⩾', class = 'rel', cs = 'geqslant' } -- greater-than or slanted equal to
+ , { code = 0x02A7F, char = '⩿', class = 'rel', cs = 'lesdot' } -- less-than or slanted equal to with dot inside
+ , { code = 0x02A80, char = '⪀', class = 'rel', cs = 'gesdot' } -- greater-than or slanted equal to with dot inside
+ , { code = 0x02A81, char = '⪁', class = 'rel', cs = 'lesdoto' } -- less-than or slanted equal to with dot above
+ , { code = 0x02A82, char = '⪂', class = 'rel', cs = 'gesdoto' } -- greater-than or slanted equal to with dot above
+ , { code = 0x02A83, char = '⪃', class = 'rel', cs = 'lesdotor' } -- less-than or slanted equal to with dot above right
+ , { code = 0x02A84, char = '⪄', class = 'rel', cs = 'gesdotol' } -- greater-than or slanted equal to with dot above left
+ , { code = 0x02A85, char = '⪅', class = 'rel', cs = 'lessapprox' } -- less-than or approximate
+ , { code = 0x02A86, char = '⪆', class = 'rel', cs = 'gtrapprox' } -- greater-than or approximate
+ , { code = 0x02A87, char = '⪇', class = 'rel', cs = 'lneq' } -- less-than and single-line not equal to
+ , { code = 0x02A88, char = '⪈', class = 'rel', cs = 'gneq' } -- greater-than and single-line not equal to
+ , { code = 0x02A89, char = '⪉', class = 'rel', cs = 'lnapprox' } -- less-than and not approximate
+ , { code = 0x02A8A, char = '⪊', class = 'rel', cs = 'gnapprox' } -- greater-than and not approximate
+ , { code = 0x02A8B, char = '⪋', class = 'rel', cs = 'lesseqqgtr' } -- less-than above double-line equal above greater-than
+ , { code = 0x02A8C, char = '⪌', class = 'rel', cs = 'gtreqqless' } -- greater-than above double-line equal above less-than
+ , { code = 0x02A8D, char = '⪍', class = 'rel', cs = 'lsime' } -- less-than above similar or equal
+ , { code = 0x02A8E, char = '⪎', class = 'rel', cs = 'gsime' } -- greater-than above similar or equal
+ , { code = 0x02A8F, char = '⪏', class = 'rel', cs = 'lsimg' } -- less-than above similar above greater-than
+ , { code = 0x02A90, char = '⪐', class = 'rel', cs = 'gsiml' } -- greater-than above similar above less-than
+ , { code = 0x02A91, char = '⪑', class = 'rel', cs = 'lgE' } -- less-than above greater-than above double-line equal
+ , { code = 0x02A92, char = '⪒', class = 'rel', cs = 'glE' } -- greater-than above less-than above double-line equal
+ , { code = 0x02A93, char = '⪓', class = 'rel', cs = 'lesges' } -- less-than above slanted equal above greater-than above slanted equal
+ , { code = 0x02A94, char = '⪔', class = 'rel', cs = 'gesles' } -- greater-than above slanted equal above less-than above slanted equal
+ , { code = 0x02A95, char = '⪕', class = 'rel', cs = 'eqslantless' } -- slanted equal to or less-than
+ , { code = 0x02A96, char = '⪖', class = 'rel', cs = 'eqslantgtr' } -- slanted equal to or greater-than
+ , { code = 0x02A97, char = '⪗', class = 'rel', cs = 'elsdot' } -- slanted equal to or less-than with dot inside
+ , { code = 0x02A98, char = '⪘', class = 'rel', cs = 'egsdot' } -- slanted equal to or greater-than with dot inside
+ , { code = 0x02A99, char = '⪙', class = 'rel', cs = 'eqqless' } -- double-line equal to or less-than
+ , { code = 0x02A9A, char = '⪚', class = 'rel', cs = 'eqqgtr' } -- double-line equal to or greater-than
+ , { code = 0x02A9B, char = '⪛', class = 'rel', cs = 'eqqslantless' } -- double-line slanted equal to or less-than
+ , { code = 0x02A9C, char = '⪜', class = 'rel', cs = 'eqqslantgtr' } -- double-line slanted equal to or greater-than
+ , { code = 0x02A9D, char = '⪝', class = 'rel', cs = 'simless' } -- similar or less-than
+ , { code = 0x02A9E, char = '⪞', class = 'rel', cs = 'simgtr' } -- similar or greater-than
+ , { code = 0x02A9F, char = '⪟', class = 'rel', cs = 'simlE' } -- similar above less-than above equals sign
+ , { code = 0x02AA0, char = '⪠', class = 'rel', cs = 'simgE' } -- similar above greater-than above equals sign
+ , { code = 0x02AA1, char = '⪡', class = 'rel', cs = 'Lt' } -- double nested less-than
+ , { code = 0x02AA2, char = '⪢', class = 'rel', cs = 'Gt' } -- double nested greater-than
+ , { code = 0x02AA3, char = '⪣', class = 'rel', cs = 'partialmeetcontraction' } -- double nested less-than with underbar
+ , { code = 0x02AA4, char = '⪤', class = 'rel', cs = 'glj' } -- greater-than overlapping less-than
+ , { code = 0x02AA5, char = '⪥', class = 'rel', cs = 'gla' } -- greater-than beside less-than
+ , { code = 0x02AA6, char = '⪦', class = 'rel', cs = 'ltcc' } -- less-than closed by curve
+ , { code = 0x02AA7, char = '⪧', class = 'rel', cs = 'gtcc' } -- greater-than closed by curve
+ , { code = 0x02AA8, char = '⪨', class = 'rel', cs = 'lescc' } -- less-than closed by curve above slanted equal
+ , { code = 0x02AA9, char = '⪩', class = 'rel', cs = 'gescc' } -- greater-than closed by curve above slanted equal
+ , { code = 0x02AAA, char = '⪪', class = 'rel', cs = 'smt' } -- smaller than
+ , { code = 0x02AAB, char = '⪫', class = 'rel', cs = 'lat' } -- larger than
+ , { code = 0x02AAC, char = '⪬', class = 'rel', cs = 'smte' } -- smaller than or equal to
+ , { code = 0x02AAD, char = '⪭', class = 'rel', cs = 'late' } -- larger than or equal to
+ , { code = 0x02AAE, char = '⪮', class = 'rel', cs = 'bumpeqq' } -- equals sign with bumpy above
+ , { code = 0x02AAF, char = '⪯', class = 'rel', cs = 'preceq' } -- precedes above single-line equals sign
+ , { code = 0x02AB0, char = '⪰', class = 'rel', cs = 'succeq' } -- succeeds above single-line equals sign
+ , { code = 0x02AB1, char = '⪱', class = 'rel', cs = 'precneq' } -- precedes above single-line not equal to
+ , { code = 0x02AB2, char = '⪲', class = 'rel', cs = 'succneq' } -- succeeds above single-line not equal to
+ , { code = 0x02AB3, char = '⪳', class = 'rel', cs = 'preceqq' } -- precedes above equals sign
+ , { code = 0x02AB4, char = '⪴', class = 'rel', cs = 'succeqq' } -- succeeds above equals sign
+ , { code = 0x02AB5, char = '⪵', class = 'rel', cs = 'precneqq' } -- precedes above not equal to
+ , { code = 0x02AB6, char = '⪶', class = 'rel', cs = 'succneqq' } -- succeeds above not equal to
+ , { code = 0x02AB7, char = '⪷', class = 'rel', cs = 'precapprox' } -- precedes above almost equal to
+ , { code = 0x02AB8, char = '⪸', class = 'rel', cs = 'succapprox' } -- succeeds above almost equal to
+ , { code = 0x02AB9, char = '⪹', class = 'rel', cs = 'precnapprox' } -- precedes above not almost equal to
+ , { code = 0x02ABA, char = '⪺', class = 'rel', cs = 'succnapprox' } -- succeeds above not almost equal to
+ , { code = 0x02ABB, char = '⪻', class = 'rel', cs = 'Prec' } -- double precedes
+ , { code = 0x02ABC, char = '⪼', class = 'rel', cs = 'Succ' } -- double succeeds
+ , { code = 0x02ABD, char = '⪽', class = 'rel', cs = 'subsetdot' } -- subset with dot
+ , { code = 0x02ABE, char = '⪾', class = 'rel', cs = 'supsetdot' } -- superset with dot
+ , { code = 0x02ABF, char = '⪿', class = 'rel', cs = 'subsetplus' } -- subset with plus sign below
+ , { code = 0x02AC0, char = '⫀', class = 'rel', cs = 'supsetplus' } -- superset with plus sign below
+ , { code = 0x02AC1, char = '⫁', class = 'rel', cs = 'submult' } -- subset with multiplication sign below
+ , { code = 0x02AC2, char = '⫂', class = 'rel', cs = 'supmult' } -- superset with multiplication sign below
+ , { code = 0x02AC3, char = '⫃', class = 'rel', cs = 'subedot' } -- subset of or equal to with dot above
+ , { code = 0x02AC4, char = '⫄', class = 'rel', cs = 'supedot' } -- superset of or equal to with dot above
+ , { code = 0x02AC5, char = '⫅', class = 'rel', cs = 'subseteqq' } -- subset of above equals sign
+ , { code = 0x02AC6, char = '⫆', class = 'rel', cs = 'supseteqq' } -- superset of above equals sign
+ , { code = 0x02AC7, char = '⫇', class = 'rel', cs = 'subsim' } -- subset of above tilde operator
+ , { code = 0x02AC8, char = '⫈', class = 'rel', cs = 'supsim' } -- superset of above tilde operator
+ , { code = 0x02AC9, char = '⫉', class = 'rel', cs = 'subsetapprox' } -- subset of above almost equal to
+ , { code = 0x02ACA, char = '⫊', class = 'rel', cs = 'supsetapprox' } -- superset of above almost equal to
+ , { code = 0x02ACB, char = '⫋', class = 'rel', cs = 'subsetneqq' } -- subset of above not equal to
+ , { code = 0x02ACC, char = '⫌', class = 'rel', cs = 'supsetneqq' } -- superset of above not equal to
+ , { code = 0x02ACD, char = '⫍', class = 'rel', cs = 'lsqhook' } -- square left open box operator
+ , { code = 0x02ACE, char = '⫎', class = 'rel', cs = 'rsqhook' } -- square right open box operator
+ , { code = 0x02ACF, char = '⫏', class = 'rel', cs = 'csub' } -- closed subset
+ , { code = 0x02AD0, char = '⫐', class = 'rel', cs = 'csup' } -- closed superset
+ , { code = 0x02AD1, char = '⫑', class = 'rel', cs = 'csube' } -- closed subset or equal to
+ , { code = 0x02AD2, char = '⫒', class = 'rel', cs = 'csupe' } -- closed superset or equal to
+ , { code = 0x02AD3, char = '⫓', class = 'rel', cs = 'subsup' } -- subset above superset
+ , { code = 0x02AD4, char = '⫔', class = 'rel', cs = 'supsub' } -- superset above subset
+ , { code = 0x02AD5, char = '⫕', class = 'rel', cs = 'subsub' } -- subset above subset
+ , { code = 0x02AD6, char = '⫖', class = 'rel', cs = 'supsup' } -- superset above superset
+ , { code = 0x02AD7, char = '⫗', class = 'rel', cs = 'suphsub' } -- superset beside subset
+ , { code = 0x02AD8, char = '⫘', class = 'rel', cs = 'supdsub' } -- superset beside and joined by dash with subset
+ , { code = 0x02AD9, char = '⫙', class = 'rel', cs = 'forkv' } -- element of opening downwards
+ , { code = 0x02ADA, char = '⫚', class = 'rel', cs = 'topfork' } -- pitchfork with tee top
+ , { code = 0x02ADB, char = '⫛', class = 'rel', cs = 'mlcp' } -- transversal intersection
+ , { code = 0x02ADC, char = '⫝̸', class = 'rel', cs = 'forks' } -- forking
+ , { code = 0x02ADD, char = '⫝', class = 'rel', cs = 'forksnot' } -- nonforking
+ , { code = 0x02ADE, char = '⫞', class = 'rel', cs = 'shortlefttack' } -- short left tack
+ , { code = 0x02ADF, char = '⫟', class = 'rel', cs = 'shortdowntack' } -- short down tack
+ , { code = 0x02AE0, char = '⫠', class = 'rel', cs = 'shortuptack' } -- short up tack
+ , { code = 0x02AE1, char = '⫡', class = 'ord', cs = 'perps' } -- perpendicular with s
+ , { code = 0x02AE2, char = '⫢', class = 'rel', cs = 'vDdash' } -- vertical bar triple right turnstile
+ , { code = 0x02AE3, char = '⫣', class = 'rel', cs = 'dashV' } -- double vertical bar left turnstile
+ , { code = 0x02AE4, char = '⫤', class = 'rel', cs = 'Dashv' } -- vertical bar double left turnstile
+ , { code = 0x02AE5, char = '⫥', class = 'rel', cs = 'DashV' } -- double vertical bar double left turnstile
+ , { code = 0x02AE6, char = '⫦', class = 'rel', cs = 'varVdash' } -- long dash from left member of double vertical
+ , { code = 0x02AE7, char = '⫧', class = 'rel', cs = 'Barv' } -- short down tack with overbar
+ , { code = 0x02AE8, char = '⫨', class = 'rel', cs = 'vBar' } -- short up tack with underbar
+ , { code = 0x02AE9, char = '⫩', class = 'rel', cs = 'vBarv' } -- short up tack above short down tack
+ , { code = 0x02AEA, char = '⫪', class = 'rel', cs = 'barV' } -- double down tack
+ , { code = 0x02AEB, char = '⫫', class = 'rel', cs = 'Vbar' } -- double up tack
+ , { code = 0x02AEC, char = '⫬', class = 'rel', cs = 'Not' } -- double stroke not sign
+ , { code = 0x02AED, char = '⫭', class = 'rel', cs = 'bNot' } -- reversed double stroke not sign
+ , { code = 0x02AEE, char = '⫮', class = 'rel', cs = 'revnmid' } -- does not divide with reversed negation slash
+ , { code = 0x02AEF, char = '⫯', class = 'rel', cs = 'cirmid' } -- vertical line with circle above
+ , { code = 0x02AF0, char = '⫰', class = 'rel', cs = 'midcir' } -- vertical line with circle below
+ , { code = 0x02AF1, char = '⫱', class = 'ord', cs = 'topcir' } -- down tack with circle below
+ , { code = 0x02AF2, char = '⫲', class = 'rel', cs = 'nhpar' } -- parallel with horizontal stroke
+ , { code = 0x02AF3, char = '⫳', class = 'rel', cs = 'parsim' } -- parallel with tilde operator
+ , { code = 0x02AF4, char = '⫴', class = 'bin', cs = 'interleave' } -- triple vertical bar binary relation
+ , { code = 0x02AF5, char = '⫵', class = 'bin', cs = 'nhVvert' } -- triple vertical bar with horizontal stroke
+ , { code = 0x02AF6, char = '⫶', class = 'bin', cs = 'threedotcolon' } -- triple colon operator
+ , { code = 0x02AF7, char = '⫷', class = 'rel', cs = 'lllnest' } -- triple nested less-than
+ , { code = 0x02AF8, char = '⫸', class = 'rel', cs = 'gggnest' } -- triple nested greater-than
+ , { code = 0x02AF9, char = '⫹', class = 'rel', cs = 'leqqslant' } -- double-line slanted less-than or equal to
+ , { code = 0x02AFA, char = '⫺', class = 'rel', cs = 'geqqslant' } -- double-line slanted greater-than or equal to
+ , { code = 0x02AFB, char = '⫻', class = 'bin', cs = 'trslash' } -- triple solidus binary relation
+ , { code = 0x02AFC, char = '⫼', class = 'op', cs = 'biginterleave' } -- large triple vertical bar operator
+ , { code = 0x02AFD, char = '⫽', class = 'bin', cs = 'sslash' } -- double solidus operator
+ , { code = 0x02AFE, char = '⫾', class = 'bin', cs = 'talloblong' } -- white vertical bar
+ , { code = 0x02AFF, char = '⫿', class = 'op', cs = 'bigtalloblong' } -- n-ary white vertical bar
+ , { code = 0x02B12, char = '⬒', class = 'ord', cs = 'squaretopblack' } -- square with top half black
+ , { code = 0x02B13, char = '⬓', class = 'ord', cs = 'squarebotblack' } -- square with bottom half black
+ , { code = 0x02B14, char = '⬔', class = 'ord', cs = 'squareurblack' } -- square with upper right diagonal half black
+ , { code = 0x02B15, char = '⬕', class = 'ord', cs = 'squarellblack' } -- square with lower left diagonal half black
+ , { code = 0x02B16, char = '⬖', class = 'ord', cs = 'diamondleftblack' } -- diamond with left half black
+ , { code = 0x02B17, char = '⬗', class = 'ord', cs = 'diamondrightblack' } -- diamond with right half black
+ , { code = 0x02B18, char = '⬘', class = 'ord', cs = 'diamondtopblack' } -- diamond with top half black
+ , { code = 0x02B19, char = '⬙', class = 'ord', cs = 'diamondbotblack' } -- diamond with bottom half black
+ , { code = 0x02B1A, char = '⬚', class = 'ord', cs = 'dottedsquare' } -- dotted square
+ , { code = 0x02B1B, char = '⬛', class = 'ord', cs = 'lgblksquare' } -- black large square
+ , { code = 0x02B1C, char = '⬜', class = 'ord', cs = 'lgwhtsquare' } -- white large square
+ , { code = 0x02B1D, char = '⬝', class = 'ord', cs = 'vysmblksquare' } -- black very small square
+ , { code = 0x02B1E, char = '⬞', class = 'ord', cs = 'vysmwhtsquare' } -- white very small square
+ , { code = 0x02B1F, char = '⬟', class = 'ord', cs = 'pentagonblack' } -- black pentagon
+ , { code = 0x02B20, char = '⬠', class = 'ord', cs = 'pentagon' } -- white pentagon
+ , { code = 0x02B21, char = '⬡', class = 'ord', cs = 'varhexagon' } -- white hexagon
+ , { code = 0x02B22, char = '⬢', class = 'ord', cs = 'varhexagonblack' } -- black hexagon
+ , { code = 0x02B23, char = '⬣', class = 'ord', cs = 'hexagonblack' } -- horizontal black hexagon
+ , { code = 0x02B24, char = '⬤', class = 'ord', cs = 'lgblkcircle' } -- black large circle
+ , { code = 0x02B25, char = '⬥', class = 'ord', cs = 'mdblkdiamond' } -- black medium diamond
+ , { code = 0x02B26, char = '⬦', class = 'ord', cs = 'mdwhtdiamond' } -- white medium diamond
+ , { code = 0x02B27, char = '⬧', class = 'ord', cs = 'mdblklozenge' } -- black medium lozenge
+ , { code = 0x02B28, char = '⬨', class = 'ord', cs = 'mdwhtlozenge' } -- white medium lozenge
+ , { code = 0x02B29, char = '⬩', class = 'ord', cs = 'smblkdiamond' } -- black small diamond
+ , { code = 0x02B2A, char = '⬪', class = 'ord', cs = 'smblklozenge' } -- black small lozenge
+ , { code = 0x02B2B, char = '⬫', class = 'ord', cs = 'smwhtlozenge' } -- white small lozenge
+ , { code = 0x02B2C, char = '⬬', class = 'ord', cs = 'blkhorzoval' } -- black horizontal ellipse
+ , { code = 0x02B2D, char = '⬭', class = 'ord', cs = 'whthorzoval' } -- white horizontal ellipse
+ , { code = 0x02B2E, char = '⬮', class = 'ord', cs = 'blkvertoval' } -- black vertical ellipse
+ , { code = 0x02B2F, char = '⬯', class = 'ord', cs = 'whtvertoval' } -- white vertical ellipse
+ , { code = 0x02B30, char = '⬰', class = 'rel', cs = 'circleonleftarrow' } -- left arrow with small circle
+ , { code = 0x02B31, char = '⬱', class = 'rel', cs = 'leftthreearrows' } -- three leftwards arrows
+ , { code = 0x02B32, char = '⬲', class = 'rel', cs = 'leftarrowonoplus' } -- left arrow with circled plus
+ , { code = 0x02B33, char = '⬳', class = 'rel', cs = 'longleftsquigarrow' } -- long leftwards squiggle arrow
+ , { code = 0x02B34, char = '⬴', class = 'rel', cs = 'nvtwoheadleftarrow' } -- leftwards two-headed arrow with vertical stroke
+ , { code = 0x02B35, char = '⬵', class = 'rel', cs = 'nVtwoheadleftarrow' } -- leftwards two-headed arrow with double vertical stroke
+ , { code = 0x02B36, char = '⬶', class = 'rel', cs = 'twoheadmapsfrom' } -- leftwards two-headed arrow from bar
+ , { code = 0x02B37, char = '⬷', class = 'rel', cs = 'twoheadleftdbkarrow' } -- leftwards two-headed triple dash arrow
+ , { code = 0x02B38, char = '⬸', class = 'rel', cs = 'leftdotarrow' } -- leftwards arrow with dotted stem
+ , { code = 0x02B39, char = '⬹', class = 'rel', cs = 'nvleftarrowtail' } -- leftwards arrow with tail with vertical stroke
+ , { code = 0x02B3A, char = '⬺', class = 'rel', cs = 'nVleftarrowtail' } -- leftwards arrow with tail with double vertical stroke
+ , { code = 0x02B3B, char = '⬻', class = 'rel', cs = 'twoheadleftarrowtail' } -- leftwards two-headed arrow with tail
+ , { code = 0x02B3C, char = '⬼', class = 'rel', cs = 'nvtwoheadleftarrowtail' } -- leftwards two-headed arrow with tail with vertical stroke
+ , { code = 0x02B3D, char = '⬽', class = 'rel', cs = 'nVtwoheadleftarrowtail' } -- leftwards two-headed arrow with tail with double vertical stroke
+ , { code = 0x02B3E, char = '⬾', class = 'rel', cs = 'leftarrowx' } -- leftwards arrow through x
+ , { code = 0x02B3F, char = '⬿', class = 'rel', cs = 'leftcurvedarrow' } -- wave arrow pointing directly left
+ , { code = 0x02B40, char = '⭀', class = 'rel', cs = 'equalleftarrow' } -- equals sign above leftwards arrow
+ , { code = 0x02B41, char = '⭁', class = 'rel', cs = 'bsimilarleftarrow' } -- reverse tilde operator above leftwards arrow
+ , { code = 0x02B42, char = '⭂', class = 'rel', cs = 'leftarrowbackapprox' } -- leftwards arrow above reverse almost equal to
+ , { code = 0x02B43, char = '⭃', class = 'rel', cs = 'rightarrowgtr' } -- rightwards arrow through greater-than
+ , { code = 0x02B44, char = '⭄', class = 'rel', cs = 'rightarrowsupset' } -- rightwards arrow through superset
+ , { code = 0x02B45, char = '⭅', class = 'rel', cs = 'LLeftarrow' } -- leftwards quadruple arrow
+ , { code = 0x02B46, char = '⭆', class = 'rel', cs = 'RRightarrow' } -- rightwards quadruple arrow
+ , { code = 0x02B47, char = '⭇', class = 'rel', cs = 'bsimilarrightarrow' } -- reverse tilde operator above rightwards arrow
+ , { code = 0x02B48, char = '⭈', class = 'rel', cs = 'rightarrowbackapprox' } -- rightwards arrow above reverse almost equal to
+ , { code = 0x02B49, char = '⭉', class = 'rel', cs = 'similarleftarrow' } -- tilde operator above leftwards arrow
+ , { code = 0x02B4A, char = '⭊', class = 'rel', cs = 'leftarrowapprox' } -- leftwards arrow above almost equal to
+ , { code = 0x02B4B, char = '⭋', class = 'rel', cs = 'leftarrowbsimilar' } -- leftwards arrow above reverse tilde operator
+ , { code = 0x02B4C, char = '⭌', class = 'rel', cs = 'rightarrowbsimilar' } -- rightwards arrow above reverse tilde operator
+ , { code = 0x02B50, char = '⭐', class = 'ord', cs = 'medwhitestar' } -- white medium star
+ , { code = 0x02B51, char = '⭑', class = 'ord', cs = 'medblackstar' } -- black small star
+ , { code = 0x02B52, char = '⭒', class = 'ord', cs = 'smwhitestar' } -- white small star
+ , { code = 0x02B53, char = '⭓', class = 'ord', cs = 'rightpentagonblack' } -- black right-pointing pentagon
+ , { code = 0x02B54, char = '⭔', class = 'ord', cs = 'rightpentagon' } -- white right-pointing pentagon
+ , { code = 0x03012, char = '〒', class = 'ord', cs = 'postalmark' } -- postal mark
+ , { code = 0x03014, char = '〔', class = 'open', cs = 'lbrbrak' } -- left tortoise shell bracket
+ , { code = 0x03015, char = '〕', class = 'close', cs = 'rbrbrak' } -- right tortoise shell bracket
+ , { code = 0x03018, char = '〘', class = 'open', cs = 'Lbrbrak' } -- left white tortoise shell bracket
+ , { code = 0x03019, char = '〙', class = 'close', cs = 'Rbrbrak' } -- right white tortoise shell bracket
+ , { code = 0x03030, char = '〰', class = 'ord', cs = 'hzigzag' } -- wavy dash
+ , { code = 0x1D400, char = '𝐀', class = 'ord', cs = 'mbfA', alphabet = 'bold' } -- mathematical bold capital a
+ , { code = 0x1D401, char = '𝐁', class = 'ord', cs = 'mbfB', alphabet = 'bold' } -- mathematical bold capital b
+ , { code = 0x1D402, char = '𝐂', class = 'ord', cs = 'mbfC', alphabet = 'bold' } -- mathematical bold capital c
+ , { code = 0x1D403, char = '𝐃', class = 'ord', cs = 'mbfD', alphabet = 'bold' } -- mathematical bold capital d
+ , { code = 0x1D404, char = '𝐄', class = 'ord', cs = 'mbfE', alphabet = 'bold' } -- mathematical bold capital e
+ , { code = 0x1D405, char = '𝐅', class = 'ord', cs = 'mbfF', alphabet = 'bold' } -- mathematical bold capital f
+ , { code = 0x1D406, char = '𝐆', class = 'ord', cs = 'mbfG', alphabet = 'bold' } -- mathematical bold capital g
+ , { code = 0x1D407, char = '𝐇', class = 'ord', cs = 'mbfH', alphabet = 'bold' } -- mathematical bold capital h
+ , { code = 0x1D408, char = '𝐈', class = 'ord', cs = 'mbfI', alphabet = 'bold' } -- mathematical bold capital i
+ , { code = 0x1D409, char = '𝐉', class = 'ord', cs = 'mbfJ', alphabet = 'bold' } -- mathematical bold capital j
+ , { code = 0x1D40A, char = '𝐊', class = 'ord', cs = 'mbfK', alphabet = 'bold' } -- mathematical bold capital k
+ , { code = 0x1D40B, char = '𝐋', class = 'ord', cs = 'mbfL', alphabet = 'bold' } -- mathematical bold capital l
+ , { code = 0x1D40C, char = '𝐌', class = 'ord', cs = 'mbfM', alphabet = 'bold' } -- mathematical bold capital m
+ , { code = 0x1D40D, char = '𝐍', class = 'ord', cs = 'mbfN', alphabet = 'bold' } -- mathematical bold capital n
+ , { code = 0x1D40E, char = '𝐎', class = 'ord', cs = 'mbfO', alphabet = 'bold' } -- mathematical bold capital o
+ , { code = 0x1D40F, char = '𝐏', class = 'ord', cs = 'mbfP', alphabet = 'bold' } -- mathematical bold capital p
+ , { code = 0x1D410, char = '𝐐', class = 'ord', cs = 'mbfQ', alphabet = 'bold' } -- mathematical bold capital q
+ , { code = 0x1D411, char = '𝐑', class = 'ord', cs = 'mbfR', alphabet = 'bold' } -- mathematical bold capital r
+ , { code = 0x1D412, char = '𝐒', class = 'ord', cs = 'mbfS', alphabet = 'bold' } -- mathematical bold capital s
+ , { code = 0x1D413, char = '𝐓', class = 'ord', cs = 'mbfT', alphabet = 'bold' } -- mathematical bold capital t
+ , { code = 0x1D414, char = '𝐔', class = 'ord', cs = 'mbfU', alphabet = 'bold' } -- mathematical bold capital u
+ , { code = 0x1D415, char = '𝐕', class = 'ord', cs = 'mbfV', alphabet = 'bold' } -- mathematical bold capital v
+ , { code = 0x1D416, char = '𝐖', class = 'ord', cs = 'mbfW', alphabet = 'bold' } -- mathematical bold capital w
+ , { code = 0x1D417, char = '𝐗', class = 'ord', cs = 'mbfX', alphabet = 'bold' } -- mathematical bold capital x
+ , { code = 0x1D418, char = '𝐘', class = 'ord', cs = 'mbfY', alphabet = 'bold' } -- mathematical bold capital y
+ , { code = 0x1D419, char = '𝐙', class = 'ord', cs = 'mbfZ', alphabet = 'bold' } -- mathematical bold capital z
+ , { code = 0x1D41A, char = '𝐚', class = 'ord', cs = 'mbfa', alphabet = 'bold' } -- mathematical bold small a
+ , { code = 0x1D41B, char = '𝐛', class = 'ord', cs = 'mbfb', alphabet = 'bold' } -- mathematical bold small b
+ , { code = 0x1D41C, char = '𝐜', class = 'ord', cs = 'mbfc', alphabet = 'bold' } -- mathematical bold small c
+ , { code = 0x1D41D, char = '𝐝', class = 'ord', cs = 'mbfd', alphabet = 'bold' } -- mathematical bold small d
+ , { code = 0x1D41E, char = '𝐞', class = 'ord', cs = 'mbfe', alphabet = 'bold' } -- mathematical bold small e
+ , { code = 0x1D41F, char = '𝐟', class = 'ord', cs = 'mbff', alphabet = 'bold' } -- mathematical bold small f
+ , { code = 0x1D420, char = '𝐠', class = 'ord', cs = 'mbfg', alphabet = 'bold' } -- mathematical bold small g
+ , { code = 0x1D421, char = '𝐡', class = 'ord', cs = 'mbfh', alphabet = 'bold' } -- mathematical bold small h
+ , { code = 0x1D422, char = '𝐢', class = 'ord', cs = 'mbfi', alphabet = 'bold' } -- mathematical bold small i
+ , { code = 0x1D423, char = '𝐣', class = 'ord', cs = 'mbfj', alphabet = 'bold' } -- mathematical bold small j
+ , { code = 0x1D424, char = '𝐤', class = 'ord', cs = 'mbfk', alphabet = 'bold' } -- mathematical bold small k
+ , { code = 0x1D425, char = '𝐥', class = 'ord', cs = 'mbfl', alphabet = 'bold' } -- mathematical bold small l
+ , { code = 0x1D426, char = '𝐦', class = 'ord', cs = 'mbfm', alphabet = 'bold' } -- mathematical bold small m
+ , { code = 0x1D427, char = '𝐧', class = 'ord', cs = 'mbfn', alphabet = 'bold' } -- mathematical bold small n
+ , { code = 0x1D428, char = '𝐨', class = 'ord', cs = 'mbfo', alphabet = 'bold' } -- mathematical bold small o
+ , { code = 0x1D429, char = '𝐩', class = 'ord', cs = 'mbfp', alphabet = 'bold' } -- mathematical bold small p
+ , { code = 0x1D42A, char = '𝐪', class = 'ord', cs = 'mbfq', alphabet = 'bold' } -- mathematical bold small q
+ , { code = 0x1D42B, char = '𝐫', class = 'ord', cs = 'mbfr', alphabet = 'bold' } -- mathematical bold small r
+ , { code = 0x1D42C, char = '𝐬', class = 'ord', cs = 'mbfs', alphabet = 'bold' } -- mathematical bold small s
+ , { code = 0x1D42D, char = '𝐭', class = 'ord', cs = 'mbft', alphabet = 'bold' } -- mathematical bold small t
+ , { code = 0x1D42E, char = '𝐮', class = 'ord', cs = 'mbfu', alphabet = 'bold' } -- mathematical bold small u
+ , { code = 0x1D42F, char = '𝐯', class = 'ord', cs = 'mbfv', alphabet = 'bold' } -- mathematical bold small v
+ , { code = 0x1D430, char = '𝐰', class = 'ord', cs = 'mbfw', alphabet = 'bold' } -- mathematical bold small w
+ , { code = 0x1D431, char = '𝐱', class = 'ord', cs = 'mbfx', alphabet = 'bold' } -- mathematical bold small x
+ , { code = 0x1D432, char = '𝐲', class = 'ord', cs = 'mbfy', alphabet = 'bold' } -- mathematical bold small y
+ , { code = 0x1D433, char = '𝐳', class = 'ord', cs = 'mbfz', alphabet = 'bold' } -- mathematical bold small z
+ , { code = 0x1D434, char = '𝐴', class = 'ord', cs = 'mitA' } -- mathematical italic capital a
+ , { code = 0x1D435, char = '𝐵', class = 'ord', cs = 'mitB' } -- mathematical italic capital b
+ , { code = 0x1D436, char = '𝐶', class = 'ord', cs = 'mitC' } -- mathematical italic capital c
+ , { code = 0x1D437, char = '𝐷', class = 'ord', cs = 'mitD' } -- mathematical italic capital d
+ , { code = 0x1D438, char = '𝐸', class = 'ord', cs = 'mitE' } -- mathematical italic capital e
+ , { code = 0x1D439, char = '𝐹', class = 'ord', cs = 'mitF' } -- mathematical italic capital f
+ , { code = 0x1D43A, char = '𝐺', class = 'ord', cs = 'mitG' } -- mathematical italic capital g
+ , { code = 0x1D43B, char = '𝐻', class = 'ord', cs = 'mitH' } -- mathematical italic capital h
+ , { code = 0x1D43C, char = '𝐼', class = 'ord', cs = 'mitI' } -- mathematical italic capital i
+ , { code = 0x1D43D, char = '𝐽', class = 'ord', cs = 'mitJ' } -- mathematical italic capital j
+ , { code = 0x1D43E, char = '𝐾', class = 'ord', cs = 'mitK' } -- mathematical italic capital k
+ , { code = 0x1D43F, char = '𝐿', class = 'ord', cs = 'mitL' } -- mathematical italic capital l
+ , { code = 0x1D440, char = '𝑀', class = 'ord', cs = 'mitM' } -- mathematical italic capital m
+ , { code = 0x1D441, char = '𝑁', class = 'ord', cs = 'mitN' } -- mathematical italic capital n
+ , { code = 0x1D442, char = '𝑂', class = 'ord', cs = 'mitO' } -- mathematical italic capital o
+ , { code = 0x1D443, char = '𝑃', class = 'ord', cs = 'mitP' } -- mathematical italic capital p
+ , { code = 0x1D444, char = '𝑄', class = 'ord', cs = 'mitQ' } -- mathematical italic capital q
+ , { code = 0x1D445, char = '𝑅', class = 'ord', cs = 'mitR' } -- mathematical italic capital r
+ , { code = 0x1D446, char = '𝑆', class = 'ord', cs = 'mitS' } -- mathematical italic capital s
+ , { code = 0x1D447, char = '𝑇', class = 'ord', cs = 'mitT' } -- mathematical italic capital t
+ , { code = 0x1D448, char = '𝑈', class = 'ord', cs = 'mitU' } -- mathematical italic capital u
+ , { code = 0x1D449, char = '𝑉', class = 'ord', cs = 'mitV' } -- mathematical italic capital v
+ , { code = 0x1D44A, char = '𝑊', class = 'ord', cs = 'mitW' } -- mathematical italic capital w
+ , { code = 0x1D44B, char = '𝑋', class = 'ord', cs = 'mitX' } -- mathematical italic capital x
+ , { code = 0x1D44C, char = '𝑌', class = 'ord', cs = 'mitY' } -- mathematical italic capital y
+ , { code = 0x1D44D, char = '𝑍', class = 'ord', cs = 'mitZ' } -- mathematical italic capital z
+ , { code = 0x1D44E, char = '𝑎', class = 'ord', cs = 'mita' } -- mathematical italic small a
+ , { code = 0x1D44F, char = '𝑏', class = 'ord', cs = 'mitb' } -- mathematical italic small b
+ , { code = 0x1D450, char = '𝑐', class = 'ord', cs = 'mitc' } -- mathematical italic small c
+ , { code = 0x1D451, char = '𝑑', class = 'ord', cs = 'mitd' } -- mathematical italic small d
+ , { code = 0x1D452, char = '𝑒', class = 'ord', cs = 'mite' } -- mathematical italic small e
+ , { code = 0x1D453, char = '𝑓', class = 'ord', cs = 'mitf' } -- mathematical italic small f
+ , { code = 0x1D454, char = '𝑔', class = 'ord', cs = 'mitg' } -- mathematical italic small g
+ , { code = 0x1D456, char = '𝑖', class = 'ord', cs = 'miti' } -- mathematical italic small i
+ , { code = 0x1D457, char = '𝑗', class = 'ord', cs = 'mitj' } -- mathematical italic small j
+ , { code = 0x1D458, char = '𝑘', class = 'ord', cs = 'mitk' } -- mathematical italic small k
+ , { code = 0x1D459, char = '𝑙', class = 'ord', cs = 'mitl' } -- mathematical italic small l
+ , { code = 0x1D45A, char = '𝑚', class = 'ord', cs = 'mitm' } -- mathematical italic small m
+ , { code = 0x1D45B, char = '𝑛', class = 'ord', cs = 'mitn' } -- mathematical italic small n
+ , { code = 0x1D45C, char = '𝑜', class = 'ord', cs = 'mito' } -- mathematical italic small o
+ , { code = 0x1D45D, char = '𝑝', class = 'ord', cs = 'mitp' } -- mathematical italic small p
+ , { code = 0x1D45E, char = '𝑞', class = 'ord', cs = 'mitq' } -- mathematical italic small q
+ , { code = 0x1D45F, char = '𝑟', class = 'ord', cs = 'mitr' } -- mathematical italic small r
+ , { code = 0x1D460, char = '𝑠', class = 'ord', cs = 'mits' } -- mathematical italic small s
+ , { code = 0x1D461, char = '𝑡', class = 'ord', cs = 'mitt' } -- mathematical italic small t
+ , { code = 0x1D462, char = '𝑢', class = 'ord', cs = 'mitu' } -- mathematical italic small u
+ , { code = 0x1D463, char = '𝑣', class = 'ord', cs = 'mitv' } -- mathematical italic small v
+ , { code = 0x1D464, char = '𝑤', class = 'ord', cs = 'mitw' } -- mathematical italic small w
+ , { code = 0x1D465, char = '𝑥', class = 'ord', cs = 'mitx' } -- mathematical italic small x
+ , { code = 0x1D466, char = '𝑦', class = 'ord', cs = 'mity' } -- mathematical italic small y
+ , { code = 0x1D467, char = '𝑧', class = 'ord', cs = 'mitz' } -- mathematical italic small z
+ , { code = 0x1D468, char = '𝑨', class = 'ord', cs = 'mbfitA', alphabet = 'bold' } -- mathematical bold italic capital a
+ , { code = 0x1D469, char = '𝑩', class = 'ord', cs = 'mbfitB', alphabet = 'bold' } -- mathematical bold italic capital b
+ , { code = 0x1D46A, char = '𝑪', class = 'ord', cs = 'mbfitC', alphabet = 'bold' } -- mathematical bold italic capital c
+ , { code = 0x1D46B, char = '𝑫', class = 'ord', cs = 'mbfitD', alphabet = 'bold' } -- mathematical bold italic capital d
+ , { code = 0x1D46C, char = '𝑬', class = 'ord', cs = 'mbfitE', alphabet = 'bold' } -- mathematical bold italic capital e
+ , { code = 0x1D46D, char = '𝑭', class = 'ord', cs = 'mbfitF', alphabet = 'bold' } -- mathematical bold italic capital f
+ , { code = 0x1D46E, char = '𝑮', class = 'ord', cs = 'mbfitG', alphabet = 'bold' } -- mathematical bold italic capital g
+ , { code = 0x1D46F, char = '𝑯', class = 'ord', cs = 'mbfitH', alphabet = 'bold' } -- mathematical bold italic capital h
+ , { code = 0x1D470, char = '𝑰', class = 'ord', cs = 'mbfitI', alphabet = 'bold' } -- mathematical bold italic capital i
+ , { code = 0x1D471, char = '𝑱', class = 'ord', cs = 'mbfitJ', alphabet = 'bold' } -- mathematical bold italic capital j
+ , { code = 0x1D472, char = '𝑲', class = 'ord', cs = 'mbfitK', alphabet = 'bold' } -- mathematical bold italic capital k
+ , { code = 0x1D473, char = '𝑳', class = 'ord', cs = 'mbfitL', alphabet = 'bold' } -- mathematical bold italic capital l
+ , { code = 0x1D474, char = '𝑴', class = 'ord', cs = 'mbfitM', alphabet = 'bold' } -- mathematical bold italic capital m
+ , { code = 0x1D475, char = '𝑵', class = 'ord', cs = 'mbfitN', alphabet = 'bold' } -- mathematical bold italic capital n
+ , { code = 0x1D476, char = '𝑶', class = 'ord', cs = 'mbfitO', alphabet = 'bold' } -- mathematical bold italic capital o
+ , { code = 0x1D477, char = '𝑷', class = 'ord', cs = 'mbfitP', alphabet = 'bold' } -- mathematical bold italic capital p
+ , { code = 0x1D478, char = '𝑸', class = 'ord', cs = 'mbfitQ', alphabet = 'bold' } -- mathematical bold italic capital q
+ , { code = 0x1D479, char = '𝑹', class = 'ord', cs = 'mbfitR', alphabet = 'bold' } -- mathematical bold italic capital r
+ , { code = 0x1D47A, char = '𝑺', class = 'ord', cs = 'mbfitS', alphabet = 'bold' } -- mathematical bold italic capital s
+ , { code = 0x1D47B, char = '𝑻', class = 'ord', cs = 'mbfitT', alphabet = 'bold' } -- mathematical bold italic capital t
+ , { code = 0x1D47C, char = '𝑼', class = 'ord', cs = 'mbfitU', alphabet = 'bold' } -- mathematical bold italic capital u
+ , { code = 0x1D47D, char = '𝑽', class = 'ord', cs = 'mbfitV', alphabet = 'bold' } -- mathematical bold italic capital v
+ , { code = 0x1D47E, char = '𝑾', class = 'ord', cs = 'mbfitW', alphabet = 'bold' } -- mathematical bold italic capital w
+ , { code = 0x1D47F, char = '𝑿', class = 'ord', cs = 'mbfitX', alphabet = 'bold' } -- mathematical bold italic capital x
+ , { code = 0x1D480, char = '𝒀', class = 'ord', cs = 'mbfitY', alphabet = 'bold' } -- mathematical bold italic capital y
+ , { code = 0x1D481, char = '𝒁', class = 'ord', cs = 'mbfitZ', alphabet = 'bold' } -- mathematical bold italic capital z
+ , { code = 0x1D482, char = '𝒂', class = 'ord', cs = 'mbfita', alphabet = 'bold' } -- mathematical bold italic small a
+ , { code = 0x1D483, char = '𝒃', class = 'ord', cs = 'mbfitb', alphabet = 'bold' } -- mathematical bold italic small b
+ , { code = 0x1D484, char = '𝒄', class = 'ord', cs = 'mbfitc', alphabet = 'bold' } -- mathematical bold italic small c
+ , { code = 0x1D485, char = '𝒅', class = 'ord', cs = 'mbfitd', alphabet = 'bold' } -- mathematical bold italic small d
+ , { code = 0x1D486, char = '𝒆', class = 'ord', cs = 'mbfite', alphabet = 'bold' } -- mathematical bold italic small e
+ , { code = 0x1D487, char = '𝒇', class = 'ord', cs = 'mbfitf', alphabet = 'bold' } -- mathematical bold italic small f
+ , { code = 0x1D488, char = '𝒈', class = 'ord', cs = 'mbfitg', alphabet = 'bold' } -- mathematical bold italic small g
+ , { code = 0x1D489, char = '𝒉', class = 'ord', cs = 'mbfith', alphabet = 'bold' } -- mathematical bold italic small h
+ , { code = 0x1D48A, char = '𝒊', class = 'ord', cs = 'mbfiti', alphabet = 'bold' } -- mathematical bold italic small i
+ , { code = 0x1D48B, char = '𝒋', class = 'ord', cs = 'mbfitj', alphabet = 'bold' } -- mathematical bold italic small j
+ , { code = 0x1D48C, char = '𝒌', class = 'ord', cs = 'mbfitk', alphabet = 'bold' } -- mathematical bold italic small k
+ , { code = 0x1D48D, char = '𝒍', class = 'ord', cs = 'mbfitl', alphabet = 'bold' } -- mathematical bold italic small l
+ , { code = 0x1D48E, char = '𝒎', class = 'ord', cs = 'mbfitm', alphabet = 'bold' } -- mathematical bold italic small m
+ , { code = 0x1D48F, char = '𝒏', class = 'ord', cs = 'mbfitn', alphabet = 'bold' } -- mathematical bold italic small n
+ , { code = 0x1D490, char = '𝒐', class = 'ord', cs = 'mbfito', alphabet = 'bold' } -- mathematical bold italic small o
+ , { code = 0x1D491, char = '𝒑', class = 'ord', cs = 'mbfitp', alphabet = 'bold' } -- mathematical bold italic small p
+ , { code = 0x1D492, char = '𝒒', class = 'ord', cs = 'mbfitq', alphabet = 'bold' } -- mathematical bold italic small q
+ , { code = 0x1D493, char = '𝒓', class = 'ord', cs = 'mbfitr', alphabet = 'bold' } -- mathematical bold italic small r
+ , { code = 0x1D494, char = '𝒔', class = 'ord', cs = 'mbfits', alphabet = 'bold' } -- mathematical bold italic small s
+ , { code = 0x1D495, char = '𝒕', class = 'ord', cs = 'mbfitt', alphabet = 'bold' } -- mathematical bold italic small t
+ , { code = 0x1D496, char = '𝒖', class = 'ord', cs = 'mbfitu', alphabet = 'bold' } -- mathematical bold italic small u
+ , { code = 0x1D497, char = '𝒗', class = 'ord', cs = 'mbfitv', alphabet = 'bold' } -- mathematical bold italic small v
+ , { code = 0x1D498, char = '𝒘', class = 'ord', cs = 'mbfitw', alphabet = 'bold' } -- mathematical bold italic small w
+ , { code = 0x1D499, char = '𝒙', class = 'ord', cs = 'mbfitx', alphabet = 'bold' } -- mathematical bold italic small x
+ , { code = 0x1D49A, char = '𝒚', class = 'ord', cs = 'mbfity', alphabet = 'bold' } -- mathematical bold italic small y
+ , { code = 0x1D49B, char = '𝒛', class = 'ord', cs = 'mbfitz', alphabet = 'bold' } -- mathematical bold italic small z
+ , { code = 0x1D49C, char = '𝒜', class = 'ord', cs = 'mscrA', alphabet = 'script' } -- mathematical script capital a
+ , { code = 0x1D49E, char = '𝒞', class = 'ord', cs = 'mscrC', alphabet = 'script' } -- mathematical script capital c
+ , { code = 0x1D49F, char = '𝒟', class = 'ord', cs = 'mscrD', alphabet = 'script' } -- mathematical script capital d
+ , { code = 0x1D4A2, char = '𝒢', class = 'ord', cs = 'mscrG', alphabet = 'script' } -- mathematical script capital g
+ , { code = 0x1D4A5, char = '𝒥', class = 'ord', cs = 'mscrJ', alphabet = 'script' } -- mathematical script capital j
+ , { code = 0x1D4A6, char = '𝒦', class = 'ord', cs = 'mscrK', alphabet = 'script' } -- mathematical script capital k
+ , { code = 0x1D4A9, char = '𝒩', class = 'ord', cs = 'mscrN', alphabet = 'script' } -- mathematical script capital n
+ , { code = 0x1D4AA, char = '𝒪', class = 'ord', cs = 'mscrO', alphabet = 'script' } -- mathematical script capital o
+ , { code = 0x1D4AB, char = '𝒫', class = 'ord', cs = 'mscrP', alphabet = 'script' } -- mathematical script capital p
+ , { code = 0x1D4AC, char = '𝒬', class = 'ord', cs = 'mscrQ', alphabet = 'script' } -- mathematical script capital q
+ , { code = 0x1D4AE, char = '𝒮', class = 'ord', cs = 'mscrS', alphabet = 'script' } -- mathematical script capital s
+ , { code = 0x1D4AF, char = '𝒯', class = 'ord', cs = 'mscrT', alphabet = 'script' } -- mathematical script capital t
+ , { code = 0x1D4B0, char = '𝒰', class = 'ord', cs = 'mscrU', alphabet = 'script' } -- mathematical script capital u
+ , { code = 0x1D4B1, char = '𝒱', class = 'ord', cs = 'mscrV', alphabet = 'script' } -- mathematical script capital v
+ , { code = 0x1D4B2, char = '𝒲', class = 'ord', cs = 'mscrW', alphabet = 'script' } -- mathematical script capital w
+ , { code = 0x1D4B3, char = '𝒳', class = 'ord', cs = 'mscrX', alphabet = 'script' } -- mathematical script capital x
+ , { code = 0x1D4B4, char = '𝒴', class = 'ord', cs = 'mscrY', alphabet = 'script' } -- mathematical script capital y
+ , { code = 0x1D4B5, char = '𝒵', class = 'ord', cs = 'mscrZ', alphabet = 'script' } -- mathematical script capital z
+ , { code = 0x1D4B6, char = '𝒶', class = 'ord', cs = 'mscra', alphabet = 'script' } -- mathematical script small a
+ , { code = 0x1D4B7, char = '𝒷', class = 'ord', cs = 'mscrb', alphabet = 'script' } -- mathematical script small b
+ , { code = 0x1D4B8, char = '𝒸', class = 'ord', cs = 'mscrc', alphabet = 'script' } -- mathematical script small c
+ , { code = 0x1D4B9, char = '𝒹', class = 'ord', cs = 'mscrd', alphabet = 'script' } -- mathematical script small d
+ , { code = 0x1D4BB, char = '𝒻', class = 'ord', cs = 'mscrf', alphabet = 'script' } -- mathematical script small f
+ , { code = 0x1D4BD, char = '𝒽', class = 'ord', cs = 'mscrh', alphabet = 'script' } -- mathematical script small h
+ , { code = 0x1D4BE, char = '𝒾', class = 'ord', cs = 'mscri', alphabet = 'script' } -- mathematical script small i
+ , { code = 0x1D4BF, char = '𝒿', class = 'ord', cs = 'mscrj', alphabet = 'script' } -- mathematical script small j
+ , { code = 0x1D4C0, char = '𝓀', class = 'ord', cs = 'mscrk', alphabet = 'script' } -- mathematical script small k
+ , { code = 0x1D4C1, char = '𝓁', class = 'ord', cs = 'mscrl', alphabet = 'script' } -- mathematical script small l
+ , { code = 0x1D4C2, char = '𝓂', class = 'ord', cs = 'mscrm', alphabet = 'script' } -- mathematical script small m
+ , { code = 0x1D4C3, char = '𝓃', class = 'ord', cs = 'mscrn', alphabet = 'script' } -- mathematical script small n
+ , { code = 0x1D4C5, char = '𝓅', class = 'ord', cs = 'mscrp', alphabet = 'script' } -- mathematical script small p
+ , { code = 0x1D4C6, char = '𝓆', class = 'ord', cs = 'mscrq', alphabet = 'script' } -- mathematical script small q
+ , { code = 0x1D4C7, char = '𝓇', class = 'ord', cs = 'mscrr', alphabet = 'script' } -- mathematical script small r
+ , { code = 0x1D4C8, char = '𝓈', class = 'ord', cs = 'mscrs', alphabet = 'script' } -- mathematical script small s
+ , { code = 0x1D4C9, char = '𝓉', class = 'ord', cs = 'mscrt', alphabet = 'script' } -- mathematical script small t
+ , { code = 0x1D4CA, char = '𝓊', class = 'ord', cs = 'mscru', alphabet = 'script' } -- mathematical script small u
+ , { code = 0x1D4CB, char = '𝓋', class = 'ord', cs = 'mscrv', alphabet = 'script' } -- mathematical script small v
+ , { code = 0x1D4CC, char = '𝓌', class = 'ord', cs = 'mscrw', alphabet = 'script' } -- mathematical script small w
+ , { code = 0x1D4CD, char = '𝓍', class = 'ord', cs = 'mscrx', alphabet = 'script' } -- mathematical script small x
+ , { code = 0x1D4CE, char = '𝓎', class = 'ord', cs = 'mscry', alphabet = 'script' } -- mathematical script small y
+ , { code = 0x1D4CF, char = '𝓏', class = 'ord', cs = 'mscrz', alphabet = 'script' } -- mathematical script small z
+ , { code = 0x1D4D0, char = '𝓐', class = 'ord', cs = 'mbfscrA', alphabet = 'script' } -- mathematical bold script capital a
+ , { code = 0x1D4D1, char = '𝓑', class = 'ord', cs = 'mbfscrB', alphabet = 'script' } -- mathematical bold script capital b
+ , { code = 0x1D4D2, char = '𝓒', class = 'ord', cs = 'mbfscrC', alphabet = 'script' } -- mathematical bold script capital c
+ , { code = 0x1D4D3, char = '𝓓', class = 'ord', cs = 'mbfscrD', alphabet = 'script' } -- mathematical bold script capital d
+ , { code = 0x1D4D4, char = '𝓔', class = 'ord', cs = 'mbfscrE', alphabet = 'script' } -- mathematical bold script capital e
+ , { code = 0x1D4D5, char = '𝓕', class = 'ord', cs = 'mbfscrF', alphabet = 'script' } -- mathematical bold script capital f
+ , { code = 0x1D4D6, char = '𝓖', class = 'ord', cs = 'mbfscrG', alphabet = 'script' } -- mathematical bold script capital g
+ , { code = 0x1D4D7, char = '𝓗', class = 'ord', cs = 'mbfscrH', alphabet = 'script' } -- mathematical bold script capital h
+ , { code = 0x1D4D8, char = '𝓘', class = 'ord', cs = 'mbfscrI', alphabet = 'script' } -- mathematical bold script capital i
+ , { code = 0x1D4D9, char = '𝓙', class = 'ord', cs = 'mbfscrJ', alphabet = 'script' } -- mathematical bold script capital j
+ , { code = 0x1D4DA, char = '𝓚', class = 'ord', cs = 'mbfscrK', alphabet = 'script' } -- mathematical bold script capital k
+ , { code = 0x1D4DB, char = '𝓛', class = 'ord', cs = 'mbfscrL', alphabet = 'script' } -- mathematical bold script capital l
+ , { code = 0x1D4DC, char = '𝓜', class = 'ord', cs = 'mbfscrM', alphabet = 'script' } -- mathematical bold script capital m
+ , { code = 0x1D4DD, char = '𝓝', class = 'ord', cs = 'mbfscrN', alphabet = 'script' } -- mathematical bold script capital n
+ , { code = 0x1D4DE, char = '𝓞', class = 'ord', cs = 'mbfscrO', alphabet = 'script' } -- mathematical bold script capital o
+ , { code = 0x1D4DF, char = '𝓟', class = 'ord', cs = 'mbfscrP', alphabet = 'script' } -- mathematical bold script capital p
+ , { code = 0x1D4E0, char = '𝓠', class = 'ord', cs = 'mbfscrQ', alphabet = 'script' } -- mathematical bold script capital q
+ , { code = 0x1D4E1, char = '𝓡', class = 'ord', cs = 'mbfscrR', alphabet = 'script' } -- mathematical bold script capital r
+ , { code = 0x1D4E2, char = '𝓢', class = 'ord', cs = 'mbfscrS', alphabet = 'script' } -- mathematical bold script capital s
+ , { code = 0x1D4E3, char = '𝓣', class = 'ord', cs = 'mbfscrT', alphabet = 'script' } -- mathematical bold script capital t
+ , { code = 0x1D4E4, char = '𝓤', class = 'ord', cs = 'mbfscrU', alphabet = 'script' } -- mathematical bold script capital u
+ , { code = 0x1D4E5, char = '𝓥', class = 'ord', cs = 'mbfscrV', alphabet = 'script' } -- mathematical bold script capital v
+ , { code = 0x1D4E6, char = '𝓦', class = 'ord', cs = 'mbfscrW', alphabet = 'script' } -- mathematical bold script capital w
+ , { code = 0x1D4E7, char = '𝓧', class = 'ord', cs = 'mbfscrX', alphabet = 'script' } -- mathematical bold script capital x
+ , { code = 0x1D4E8, char = '𝓨', class = 'ord', cs = 'mbfscrY', alphabet = 'script' } -- mathematical bold script capital y
+ , { code = 0x1D4E9, char = '𝓩', class = 'ord', cs = 'mbfscrZ', alphabet = 'script' } -- mathematical bold script capital z
+ , { code = 0x1D4EA, char = '𝓪', class = 'ord', cs = 'mbfscra', alphabet = 'script' } -- mathematical bold script small a
+ , { code = 0x1D4EB, char = '𝓫', class = 'ord', cs = 'mbfscrb', alphabet = 'script' } -- mathematical bold script small b
+ , { code = 0x1D4EC, char = '𝓬', class = 'ord', cs = 'mbfscrc', alphabet = 'script' } -- mathematical bold script small c
+ , { code = 0x1D4ED, char = '𝓭', class = 'ord', cs = 'mbfscrd', alphabet = 'script' } -- mathematical bold script small d
+ , { code = 0x1D4EE, char = '𝓮', class = 'ord', cs = 'mbfscre', alphabet = 'script' } -- mathematical bold script small e
+ , { code = 0x1D4EF, char = '𝓯', class = 'ord', cs = 'mbfscrf', alphabet = 'script' } -- mathematical bold script small f
+ , { code = 0x1D4F0, char = '𝓰', class = 'ord', cs = 'mbfscrg', alphabet = 'script' } -- mathematical bold script small g
+ , { code = 0x1D4F1, char = '𝓱', class = 'ord', cs = 'mbfscrh', alphabet = 'script' } -- mathematical bold script small h
+ , { code = 0x1D4F2, char = '𝓲', class = 'ord', cs = 'mbfscri', alphabet = 'script' } -- mathematical bold script small i
+ , { code = 0x1D4F3, char = '𝓳', class = 'ord', cs = 'mbfscrj', alphabet = 'script' } -- mathematical bold script small j
+ , { code = 0x1D4F4, char = '𝓴', class = 'ord', cs = 'mbfscrk', alphabet = 'script' } -- mathematical bold script small k
+ , { code = 0x1D4F5, char = '𝓵', class = 'ord', cs = 'mbfscrl', alphabet = 'script' } -- mathematical bold script small l
+ , { code = 0x1D4F6, char = '𝓶', class = 'ord', cs = 'mbfscrm', alphabet = 'script' } -- mathematical bold script small m
+ , { code = 0x1D4F7, char = '𝓷', class = 'ord', cs = 'mbfscrn', alphabet = 'script' } -- mathematical bold script small n
+ , { code = 0x1D4F8, char = '𝓸', class = 'ord', cs = 'mbfscro', alphabet = 'script' } -- mathematical bold script small o
+ , { code = 0x1D4F9, char = '𝓹', class = 'ord', cs = 'mbfscrp', alphabet = 'script' } -- mathematical bold script small p
+ , { code = 0x1D4FA, char = '𝓺', class = 'ord', cs = 'mbfscrq', alphabet = 'script' } -- mathematical bold script small q
+ , { code = 0x1D4FB, char = '𝓻', class = 'ord', cs = 'mbfscrr', alphabet = 'script' } -- mathematical bold script small r
+ , { code = 0x1D4FC, char = '𝓼', class = 'ord', cs = 'mbfscrs', alphabet = 'script' } -- mathematical bold script small s
+ , { code = 0x1D4FD, char = '𝓽', class = 'ord', cs = 'mbfscrt', alphabet = 'script' } -- mathematical bold script small t
+ , { code = 0x1D4FE, char = '𝓾', class = 'ord', cs = 'mbfscru', alphabet = 'script' } -- mathematical bold script small u
+ , { code = 0x1D4FF, char = '𝓿', class = 'ord', cs = 'mbfscrv', alphabet = 'script' } -- mathematical bold script small v
+ , { code = 0x1D500, char = '𝔀', class = 'ord', cs = 'mbfscrw', alphabet = 'script' } -- mathematical bold script small w
+ , { code = 0x1D501, char = '𝔁', class = 'ord', cs = 'mbfscrx', alphabet = 'script' } -- mathematical bold script small x
+ , { code = 0x1D502, char = '𝔂', class = 'ord', cs = 'mbfscry', alphabet = 'script' } -- mathematical bold script small y
+ , { code = 0x1D503, char = '𝔃', class = 'ord', cs = 'mbfscrz', alphabet = 'script' } -- mathematical bold script small z
+ , { code = 0x1D504, char = '𝔄', class = 'ord', cs = 'mfrakA', alphabet = 'fraktur' } -- mathematical fraktur capital a
+ , { code = 0x1D505, char = '𝔅', class = 'ord', cs = 'mfrakB', alphabet = 'fraktur' } -- mathematical fraktur capital b
+ , { code = 0x1D507, char = '𝔇', class = 'ord', cs = 'mfrakD', alphabet = 'fraktur' } -- mathematical fraktur capital d
+ , { code = 0x1D508, char = '𝔈', class = 'ord', cs = 'mfrakE', alphabet = 'fraktur' } -- mathematical fraktur capital e
+ , { code = 0x1D509, char = '𝔉', class = 'ord', cs = 'mfrakF', alphabet = 'fraktur' } -- mathematical fraktur capital f
+ , { code = 0x1D50A, char = '𝔊', class = 'ord', cs = 'mfrakG', alphabet = 'fraktur' } -- mathematical fraktur capital g
+ , { code = 0x1D50D, char = '𝔍', class = 'ord', cs = 'mfrakJ', alphabet = 'fraktur' } -- mathematical fraktur capital j
+ , { code = 0x1D50E, char = '𝔎', class = 'ord', cs = 'mfrakK', alphabet = 'fraktur' } -- mathematical fraktur capital k
+ , { code = 0x1D50F, char = '𝔏', class = 'ord', cs = 'mfrakL', alphabet = 'fraktur' } -- mathematical fraktur capital l
+ , { code = 0x1D510, char = '𝔐', class = 'ord', cs = 'mfrakM', alphabet = 'fraktur' } -- mathematical fraktur capital m
+ , { code = 0x1D511, char = '𝔑', class = 'ord', cs = 'mfrakN', alphabet = 'fraktur' } -- mathematical fraktur capital n
+ , { code = 0x1D512, char = '𝔒', class = 'ord', cs = 'mfrakO', alphabet = 'fraktur' } -- mathematical fraktur capital o
+ , { code = 0x1D513, char = '𝔓', class = 'ord', cs = 'mfrakP', alphabet = 'fraktur' } -- mathematical fraktur capital p
+ , { code = 0x1D514, char = '𝔔', class = 'ord', cs = 'mfrakQ', alphabet = 'fraktur' } -- mathematical fraktur capital q
+ , { code = 0x1D516, char = '𝔖', class = 'ord', cs = 'mfrakS', alphabet = 'fraktur' } -- mathematical fraktur capital s
+ , { code = 0x1D517, char = '𝔗', class = 'ord', cs = 'mfrakT', alphabet = 'fraktur' } -- mathematical fraktur capital t
+ , { code = 0x1D518, char = '𝔘', class = 'ord', cs = 'mfrakU', alphabet = 'fraktur' } -- mathematical fraktur capital u
+ , { code = 0x1D519, char = '𝔙', class = 'ord', cs = 'mfrakV', alphabet = 'fraktur' } -- mathematical fraktur capital v
+ , { code = 0x1D51A, char = '𝔚', class = 'ord', cs = 'mfrakW', alphabet = 'fraktur' } -- mathematical fraktur capital w
+ , { code = 0x1D51B, char = '𝔛', class = 'ord', cs = 'mfrakX', alphabet = 'fraktur' } -- mathematical fraktur capital x
+ , { code = 0x1D51C, char = '𝔜', class = 'ord', cs = 'mfrakY', alphabet = 'fraktur' } -- mathematical fraktur capital y
+ , { code = 0x1D51E, char = '𝔞', class = 'ord', cs = 'mfraka', alphabet = 'fraktur' } -- mathematical fraktur small a
+ , { code = 0x1D51F, char = '𝔟', class = 'ord', cs = 'mfrakb', alphabet = 'fraktur' } -- mathematical fraktur small b
+ , { code = 0x1D520, char = '𝔠', class = 'ord', cs = 'mfrakc', alphabet = 'fraktur' } -- mathematical fraktur small c
+ , { code = 0x1D521, char = '𝔡', class = 'ord', cs = 'mfrakd', alphabet = 'fraktur' } -- mathematical fraktur small d
+ , { code = 0x1D522, char = '𝔢', class = 'ord', cs = 'mfrake', alphabet = 'fraktur' } -- mathematical fraktur small e
+ , { code = 0x1D523, char = '𝔣', class = 'ord', cs = 'mfrakf', alphabet = 'fraktur' } -- mathematical fraktur small f
+ , { code = 0x1D524, char = '𝔤', class = 'ord', cs = 'mfrakg', alphabet = 'fraktur' } -- mathematical fraktur small g
+ , { code = 0x1D525, char = '𝔥', class = 'ord', cs = 'mfrakh', alphabet = 'fraktur' } -- mathematical fraktur small h
+ , { code = 0x1D526, char = '𝔦', class = 'ord', cs = 'mfraki', alphabet = 'fraktur' } -- mathematical fraktur small i
+ , { code = 0x1D527, char = '𝔧', class = 'ord', cs = 'mfrakj', alphabet = 'fraktur' } -- mathematical fraktur small j
+ , { code = 0x1D528, char = '𝔨', class = 'ord', cs = 'mfrakk', alphabet = 'fraktur' } -- mathematical fraktur small k
+ , { code = 0x1D529, char = '𝔩', class = 'ord', cs = 'mfrakl', alphabet = 'fraktur' } -- mathematical fraktur small l
+ , { code = 0x1D52A, char = '𝔪', class = 'ord', cs = 'mfrakm', alphabet = 'fraktur' } -- mathematical fraktur small m
+ , { code = 0x1D52B, char = '𝔫', class = 'ord', cs = 'mfrakn', alphabet = 'fraktur' } -- mathematical fraktur small n
+ , { code = 0x1D52C, char = '𝔬', class = 'ord', cs = 'mfrako', alphabet = 'fraktur' } -- mathematical fraktur small o
+ , { code = 0x1D52D, char = '𝔭', class = 'ord', cs = 'mfrakp', alphabet = 'fraktur' } -- mathematical fraktur small p
+ , { code = 0x1D52E, char = '𝔮', class = 'ord', cs = 'mfrakq', alphabet = 'fraktur' } -- mathematical fraktur small q
+ , { code = 0x1D52F, char = '𝔯', class = 'ord', cs = 'mfrakr', alphabet = 'fraktur' } -- mathematical fraktur small r
+ , { code = 0x1D530, char = '𝔰', class = 'ord', cs = 'mfraks', alphabet = 'fraktur' } -- mathematical fraktur small s
+ , { code = 0x1D531, char = '𝔱', class = 'ord', cs = 'mfrakt', alphabet = 'fraktur' } -- mathematical fraktur small t
+ , { code = 0x1D532, char = '𝔲', class = 'ord', cs = 'mfraku', alphabet = 'fraktur' } -- mathematical fraktur small u
+ , { code = 0x1D533, char = '𝔳', class = 'ord', cs = 'mfrakv', alphabet = 'fraktur' } -- mathematical fraktur small v
+ , { code = 0x1D534, char = '𝔴', class = 'ord', cs = 'mfrakw', alphabet = 'fraktur' } -- mathematical fraktur small w
+ , { code = 0x1D535, char = '𝔵', class = 'ord', cs = 'mfrakx', alphabet = 'fraktur' } -- mathematical fraktur small x
+ , { code = 0x1D536, char = '𝔶', class = 'ord', cs = 'mfraky', alphabet = 'fraktur' } -- mathematical fraktur small y
+ , { code = 0x1D537, char = '𝔷', class = 'ord', cs = 'mfrakz', alphabet = 'fraktur' } -- mathematical fraktur small z
+ , { code = 0x1D538, char = '𝔸', class = 'ord', cs = 'BbbA', alphabet = 'blackboard' } -- mathematical double-struck capital a
+ , { code = 0x1D539, char = '𝔹', class = 'ord', cs = 'BbbB', alphabet = 'blackboard' } -- mathematical double-struck capital b
+ , { code = 0x1D53B, char = '𝔻', class = 'ord', cs = 'BbbD', alphabet = 'blackboard' } -- mathematical double-struck capital d
+ , { code = 0x1D53C, char = '𝔼', class = 'ord', cs = 'BbbE', alphabet = 'blackboard' } -- mathematical double-struck capital e
+ , { code = 0x1D53D, char = '𝔽', class = 'ord', cs = 'BbbF', alphabet = 'blackboard' } -- mathematical double-struck capital f
+ , { code = 0x1D53E, char = '𝔾', class = 'ord', cs = 'BbbG', alphabet = 'blackboard' } -- mathematical double-struck capital g
+ , { code = 0x1D540, char = '𝕀', class = 'ord', cs = 'BbbI', alphabet = 'blackboard' } -- mathematical double-struck capital i
+ , { code = 0x1D541, char = '𝕁', class = 'ord', cs = 'BbbJ', alphabet = 'blackboard' } -- mathematical double-struck capital j
+ , { code = 0x1D542, char = '𝕂', class = 'ord', cs = 'BbbK', alphabet = 'blackboard' } -- mathematical double-struck capital k
+ , { code = 0x1D543, char = '𝕃', class = 'ord', cs = 'BbbL', alphabet = 'blackboard' } -- mathematical double-struck capital l
+ , { code = 0x1D544, char = '𝕄', class = 'ord', cs = 'BbbM', alphabet = 'blackboard' } -- mathematical double-struck capital m
+ , { code = 0x1D546, char = '𝕆', class = 'ord', cs = 'BbbO', alphabet = 'blackboard' } -- mathematical double-struck capital o
+ , { code = 0x1D54A, char = '𝕊', class = 'ord', cs = 'BbbS', alphabet = 'blackboard' } -- mathematical double-struck capital s
+ , { code = 0x1D54B, char = '𝕋', class = 'ord', cs = 'BbbT', alphabet = 'blackboard' } -- mathematical double-struck capital t
+ , { code = 0x1D54C, char = '𝕌', class = 'ord', cs = 'BbbU', alphabet = 'blackboard' } -- mathematical double-struck capital u
+ , { code = 0x1D54D, char = '𝕍', class = 'ord', cs = 'BbbV', alphabet = 'blackboard' } -- mathematical double-struck capital v
+ , { code = 0x1D54E, char = '𝕎', class = 'ord', cs = 'BbbW', alphabet = 'blackboard' } -- mathematical double-struck capital w
+ , { code = 0x1D54F, char = '𝕏', class = 'ord', cs = 'BbbX', alphabet = 'blackboard' } -- mathematical double-struck capital x
+ , { code = 0x1D550, char = '𝕐', class = 'ord', cs = 'BbbY', alphabet = 'blackboard' } -- mathematical double-struck capital y
+ , { code = 0x1D552, char = '𝕒', class = 'ord', cs = 'Bbba', alphabet = 'blackboard' } -- mathematical double-struck small a
+ , { code = 0x1D553, char = '𝕓', class = 'ord', cs = 'Bbbb', alphabet = 'blackboard' } -- mathematical double-struck small b
+ , { code = 0x1D554, char = '𝕔', class = 'ord', cs = 'Bbbc', alphabet = 'blackboard' } -- mathematical double-struck small c
+ , { code = 0x1D555, char = '𝕕', class = 'ord', cs = 'Bbbd', alphabet = 'blackboard' } -- mathematical double-struck small d
+ , { code = 0x1D556, char = '𝕖', class = 'ord', cs = 'Bbbe', alphabet = 'blackboard' } -- mathematical double-struck small e
+ , { code = 0x1D557, char = '𝕗', class = 'ord', cs = 'Bbbf', alphabet = 'blackboard' } -- mathematical double-struck small f
+ , { code = 0x1D558, char = '𝕘', class = 'ord', cs = 'Bbbg', alphabet = 'blackboard' } -- mathematical double-struck small g
+ , { code = 0x1D559, char = '𝕙', class = 'ord', cs = 'Bbbh', alphabet = 'blackboard' } -- mathematical double-struck small h
+ , { code = 0x1D55A, char = '𝕚', class = 'ord', cs = 'Bbbi', alphabet = 'blackboard' } -- mathematical double-struck small i
+ , { code = 0x1D55B, char = '𝕛', class = 'ord', cs = 'Bbbj', alphabet = 'blackboard' } -- mathematical double-struck small j
+ , { code = 0x1D55C, char = '𝕜', class = 'ord', cs = 'Bbbk', alphabet = 'blackboard' } -- mathematical double-struck small k
+ , { code = 0x1D55D, char = '𝕝', class = 'ord', cs = 'Bbbl', alphabet = 'blackboard' } -- mathematical double-struck small l
+ , { code = 0x1D55E, char = '𝕞', class = 'ord', cs = 'Bbbm', alphabet = 'blackboard' } -- mathematical double-struck small m
+ , { code = 0x1D55F, char = '𝕟', class = 'ord', cs = 'Bbbn', alphabet = 'blackboard' } -- mathematical double-struck small n
+ , { code = 0x1D560, char = '𝕠', class = 'ord', cs = 'Bbbo', alphabet = 'blackboard' } -- mathematical double-struck small o
+ , { code = 0x1D561, char = '𝕡', class = 'ord', cs = 'Bbbp', alphabet = 'blackboard' } -- mathematical double-struck small p
+ , { code = 0x1D562, char = '𝕢', class = 'ord', cs = 'Bbbq', alphabet = 'blackboard' } -- mathematical double-struck small q
+ , { code = 0x1D563, char = '𝕣', class = 'ord', cs = 'Bbbr', alphabet = 'blackboard' } -- mathematical double-struck small r
+ , { code = 0x1D564, char = '𝕤', class = 'ord', cs = 'Bbbs', alphabet = 'blackboard' } -- mathematical double-struck small s
+ , { code = 0x1D565, char = '𝕥', class = 'ord', cs = 'Bbbt', alphabet = 'blackboard' } -- mathematical double-struck small t
+ , { code = 0x1D566, char = '𝕦', class = 'ord', cs = 'Bbbu', alphabet = 'blackboard' } -- mathematical double-struck small u
+ , { code = 0x1D567, char = '𝕧', class = 'ord', cs = 'Bbbv', alphabet = 'blackboard' } -- mathematical double-struck small v
+ , { code = 0x1D568, char = '𝕨', class = 'ord', cs = 'Bbbw', alphabet = 'blackboard' } -- mathematical double-struck small w
+ , { code = 0x1D569, char = '𝕩', class = 'ord', cs = 'Bbbx', alphabet = 'blackboard' } -- mathematical double-struck small x
+ , { code = 0x1D56A, char = '𝕪', class = 'ord', cs = 'Bbby', alphabet = 'blackboard' } -- mathematical double-struck small y
+ , { code = 0x1D56B, char = '𝕫', class = 'ord', cs = 'Bbbz', alphabet = 'blackboard' } -- mathematical double-struck small z
+ , { code = 0x1D56C, char = '𝕬', class = 'ord', cs = 'mbffrakA', alphabet = 'fraktur' } -- mathematical bold fraktur capital a
+ , { code = 0x1D56D, char = '𝕭', class = 'ord', cs = 'mbffrakB', alphabet = 'fraktur' } -- mathematical bold fraktur capital b
+ , { code = 0x1D56E, char = '𝕮', class = 'ord', cs = 'mbffrakC', alphabet = 'fraktur' } -- mathematical bold fraktur capital c
+ , { code = 0x1D56F, char = '𝕯', class = 'ord', cs = 'mbffrakD', alphabet = 'fraktur' } -- mathematical bold fraktur capital d
+ , { code = 0x1D570, char = '𝕰', class = 'ord', cs = 'mbffrakE', alphabet = 'fraktur' } -- mathematical bold fraktur capital e
+ , { code = 0x1D571, char = '𝕱', class = 'ord', cs = 'mbffrakF', alphabet = 'fraktur' } -- mathematical bold fraktur capital f
+ , { code = 0x1D572, char = '𝕲', class = 'ord', cs = 'mbffrakG', alphabet = 'fraktur' } -- mathematical bold fraktur capital g
+ , { code = 0x1D573, char = '𝕳', class = 'ord', cs = 'mbffrakH', alphabet = 'fraktur' } -- mathematical bold fraktur capital h
+ , { code = 0x1D574, char = '𝕴', class = 'ord', cs = 'mbffrakI', alphabet = 'fraktur' } -- mathematical bold fraktur capital i
+ , { code = 0x1D575, char = '𝕵', class = 'ord', cs = 'mbffrakJ', alphabet = 'fraktur' } -- mathematical bold fraktur capital j
+ , { code = 0x1D576, char = '𝕶', class = 'ord', cs = 'mbffrakK', alphabet = 'fraktur' } -- mathematical bold fraktur capital k
+ , { code = 0x1D577, char = '𝕷', class = 'ord', cs = 'mbffrakL', alphabet = 'fraktur' } -- mathematical bold fraktur capital l
+ , { code = 0x1D578, char = '𝕸', class = 'ord', cs = 'mbffrakM', alphabet = 'fraktur' } -- mathematical bold fraktur capital m
+ , { code = 0x1D579, char = '𝕹', class = 'ord', cs = 'mbffrakN', alphabet = 'fraktur' } -- mathematical bold fraktur capital n
+ , { code = 0x1D57A, char = '𝕺', class = 'ord', cs = 'mbffrakO', alphabet = 'fraktur' } -- mathematical bold fraktur capital o
+ , { code = 0x1D57B, char = '𝕻', class = 'ord', cs = 'mbffrakP', alphabet = 'fraktur' } -- mathematical bold fraktur capital p
+ , { code = 0x1D57C, char = '𝕼', class = 'ord', cs = 'mbffrakQ', alphabet = 'fraktur' } -- mathematical bold fraktur capital q
+ , { code = 0x1D57D, char = '𝕽', class = 'ord', cs = 'mbffrakR', alphabet = 'fraktur' } -- mathematical bold fraktur capital r
+ , { code = 0x1D57E, char = '𝕾', class = 'ord', cs = 'mbffrakS', alphabet = 'fraktur' } -- mathematical bold fraktur capital s
+ , { code = 0x1D57F, char = '𝕿', class = 'ord', cs = 'mbffrakT', alphabet = 'fraktur' } -- mathematical bold fraktur capital t
+ , { code = 0x1D580, char = '𝖀', class = 'ord', cs = 'mbffrakU', alphabet = 'fraktur' } -- mathematical bold fraktur capital u
+ , { code = 0x1D581, char = '𝖁', class = 'ord', cs = 'mbffrakV', alphabet = 'fraktur' } -- mathematical bold fraktur capital v
+ , { code = 0x1D582, char = '𝖂', class = 'ord', cs = 'mbffrakW', alphabet = 'fraktur' } -- mathematical bold fraktur capital w
+ , { code = 0x1D583, char = '𝖃', class = 'ord', cs = 'mbffrakX', alphabet = 'fraktur' } -- mathematical bold fraktur capital x
+ , { code = 0x1D584, char = '𝖄', class = 'ord', cs = 'mbffrakY', alphabet = 'fraktur' } -- mathematical bold fraktur capital y
+ , { code = 0x1D585, char = '𝖅', class = 'ord', cs = 'mbffrakZ', alphabet = 'fraktur' } -- mathematical bold fraktur capital z
+ , { code = 0x1D586, char = '𝖆', class = 'ord', cs = 'mbffraka', alphabet = 'fraktur' } -- mathematical bold fraktur small a
+ , { code = 0x1D587, char = '𝖇', class = 'ord', cs = 'mbffrakb', alphabet = 'fraktur' } -- mathematical bold fraktur small b
+ , { code = 0x1D588, char = '𝖈', class = 'ord', cs = 'mbffrakc', alphabet = 'fraktur' } -- mathematical bold fraktur small c
+ , { code = 0x1D589, char = '𝖉', class = 'ord', cs = 'mbffrakd', alphabet = 'fraktur' } -- mathematical bold fraktur small d
+ , { code = 0x1D58A, char = '𝖊', class = 'ord', cs = 'mbffrake', alphabet = 'fraktur' } -- mathematical bold fraktur small e
+ , { code = 0x1D58B, char = '𝖋', class = 'ord', cs = 'mbffrakf', alphabet = 'fraktur' } -- mathematical bold fraktur small f
+ , { code = 0x1D58C, char = '𝖌', class = 'ord', cs = 'mbffrakg', alphabet = 'fraktur' } -- mathematical bold fraktur small g
+ , { code = 0x1D58D, char = '𝖍', class = 'ord', cs = 'mbffrakh', alphabet = 'fraktur' } -- mathematical bold fraktur small h
+ , { code = 0x1D58E, char = '𝖎', class = 'ord', cs = 'mbffraki', alphabet = 'fraktur' } -- mathematical bold fraktur small i
+ , { code = 0x1D58F, char = '𝖏', class = 'ord', cs = 'mbffrakj', alphabet = 'fraktur' } -- mathematical bold fraktur small j
+ , { code = 0x1D590, char = '𝖐', class = 'ord', cs = 'mbffrakk', alphabet = 'fraktur' } -- mathematical bold fraktur small k
+ , { code = 0x1D591, char = '𝖑', class = 'ord', cs = 'mbffrakl', alphabet = 'fraktur' } -- mathematical bold fraktur small l
+ , { code = 0x1D592, char = '𝖒', class = 'ord', cs = 'mbffrakm', alphabet = 'fraktur' } -- mathematical bold fraktur small m
+ , { code = 0x1D593, char = '𝖓', class = 'ord', cs = 'mbffrakn', alphabet = 'fraktur' } -- mathematical bold fraktur small n
+ , { code = 0x1D594, char = '𝖔', class = 'ord', cs = 'mbffrako', alphabet = 'fraktur' } -- mathematical bold fraktur small o
+ , { code = 0x1D595, char = '𝖕', class = 'ord', cs = 'mbffrakp', alphabet = 'fraktur' } -- mathematical bold fraktur small p
+ , { code = 0x1D596, char = '𝖖', class = 'ord', cs = 'mbffrakq', alphabet = 'fraktur' } -- mathematical bold fraktur small q
+ , { code = 0x1D597, char = '𝖗', class = 'ord', cs = 'mbffrakr', alphabet = 'fraktur' } -- mathematical bold fraktur small r
+ , { code = 0x1D598, char = '𝖘', class = 'ord', cs = 'mbffraks', alphabet = 'fraktur' } -- mathematical bold fraktur small s
+ , { code = 0x1D599, char = '𝖙', class = 'ord', cs = 'mbffrakt', alphabet = 'fraktur' } -- mathematical bold fraktur small t
+ , { code = 0x1D59A, char = '𝖚', class = 'ord', cs = 'mbffraku', alphabet = 'fraktur' } -- mathematical bold fraktur small u
+ , { code = 0x1D59B, char = '𝖛', class = 'ord', cs = 'mbffrakv', alphabet = 'fraktur' } -- mathematical bold fraktur small v
+ , { code = 0x1D59C, char = '𝖜', class = 'ord', cs = 'mbffrakw', alphabet = 'fraktur' } -- mathematical bold fraktur small w
+ , { code = 0x1D59D, char = '𝖝', class = 'ord', cs = 'mbffrakx', alphabet = 'fraktur' } -- mathematical bold fraktur small x
+ , { code = 0x1D59E, char = '𝖞', class = 'ord', cs = 'mbffraky', alphabet = 'fraktur' } -- mathematical bold fraktur small y
+ , { code = 0x1D59F, char = '𝖟', class = 'ord', cs = 'mbffrakz', alphabet = 'fraktur' } -- mathematical bold fraktur small z
+ , { code = 0x1D5A0, char = '𝖠', class = 'ord', cs = 'msansA', alphabet = 'sans' } -- mathematical sans-serif capital a
+ , { code = 0x1D5A1, char = '𝖡', class = 'ord', cs = 'msansB', alphabet = 'sans' } -- mathematical sans-serif capital b
+ , { code = 0x1D5A2, char = '𝖢', class = 'ord', cs = 'msansC', alphabet = 'sans' } -- mathematical sans-serif capital c
+ , { code = 0x1D5A3, char = '𝖣', class = 'ord', cs = 'msansD', alphabet = 'sans' } -- mathematical sans-serif capital d
+ , { code = 0x1D5A4, char = '𝖤', class = 'ord', cs = 'msansE', alphabet = 'sans' } -- mathematical sans-serif capital e
+ , { code = 0x1D5A5, char = '𝖥', class = 'ord', cs = 'msansF', alphabet = 'sans' } -- mathematical sans-serif capital f
+ , { code = 0x1D5A6, char = '𝖦', class = 'ord', cs = 'msansG', alphabet = 'sans' } -- mathematical sans-serif capital g
+ , { code = 0x1D5A7, char = '𝖧', class = 'ord', cs = 'msansH', alphabet = 'sans' } -- mathematical sans-serif capital h
+ , { code = 0x1D5A8, char = '𝖨', class = 'ord', cs = 'msansI', alphabet = 'sans' } -- mathematical sans-serif capital i
+ , { code = 0x1D5A9, char = '𝖩', class = 'ord', cs = 'msansJ', alphabet = 'sans' } -- mathematical sans-serif capital j
+ , { code = 0x1D5AA, char = '𝖪', class = 'ord', cs = 'msansK', alphabet = 'sans' } -- mathematical sans-serif capital k
+ , { code = 0x1D5AB, char = '𝖫', class = 'ord', cs = 'msansL', alphabet = 'sans' } -- mathematical sans-serif capital l
+ , { code = 0x1D5AC, char = '𝖬', class = 'ord', cs = 'msansM', alphabet = 'sans' } -- mathematical sans-serif capital m
+ , { code = 0x1D5AD, char = '𝖭', class = 'ord', cs = 'msansN', alphabet = 'sans' } -- mathematical sans-serif capital n
+ , { code = 0x1D5AE, char = '𝖮', class = 'ord', cs = 'msansO', alphabet = 'sans' } -- mathematical sans-serif capital o
+ , { code = 0x1D5AF, char = '𝖯', class = 'ord', cs = 'msansP', alphabet = 'sans' } -- mathematical sans-serif capital p
+ , { code = 0x1D5B0, char = '𝖰', class = 'ord', cs = 'msansQ', alphabet = 'sans' } -- mathematical sans-serif capital q
+ , { code = 0x1D5B1, char = '𝖱', class = 'ord', cs = 'msansR', alphabet = 'sans' } -- mathematical sans-serif capital r
+ , { code = 0x1D5B2, char = '𝖲', class = 'ord', cs = 'msansS', alphabet = 'sans' } -- mathematical sans-serif capital s
+ , { code = 0x1D5B3, char = '𝖳', class = 'ord', cs = 'msansT', alphabet = 'sans' } -- mathematical sans-serif capital t
+ , { code = 0x1D5B4, char = '𝖴', class = 'ord', cs = 'msansU', alphabet = 'sans' } -- mathematical sans-serif capital u
+ , { code = 0x1D5B5, char = '𝖵', class = 'ord', cs = 'msansV', alphabet = 'sans' } -- mathematical sans-serif capital v
+ , { code = 0x1D5B6, char = '𝖶', class = 'ord', cs = 'msansW', alphabet = 'sans' } -- mathematical sans-serif capital w
+ , { code = 0x1D5B7, char = '𝖷', class = 'ord', cs = 'msansX', alphabet = 'sans' } -- mathematical sans-serif capital x
+ , { code = 0x1D5B8, char = '𝖸', class = 'ord', cs = 'msansY', alphabet = 'sans' } -- mathematical sans-serif capital y
+ , { code = 0x1D5B9, char = '𝖹', class = 'ord', cs = 'msansZ', alphabet = 'sans' } -- mathematical sans-serif capital z
+ , { code = 0x1D5BA, char = '𝖺', class = 'ord', cs = 'msansa', alphabet = 'sans' } -- mathematical sans-serif small a
+ , { code = 0x1D5BB, char = '𝖻', class = 'ord', cs = 'msansb', alphabet = 'sans' } -- mathematical sans-serif small b
+ , { code = 0x1D5BC, char = '𝖼', class = 'ord', cs = 'msansc', alphabet = 'sans' } -- mathematical sans-serif small c
+ , { code = 0x1D5BD, char = '𝖽', class = 'ord', cs = 'msansd', alphabet = 'sans' } -- mathematical sans-serif small d
+ , { code = 0x1D5BE, char = '𝖾', class = 'ord', cs = 'msanse', alphabet = 'sans' } -- mathematical sans-serif small e
+ , { code = 0x1D5BF, char = '𝖿', class = 'ord', cs = 'msansf', alphabet = 'sans' } -- mathematical sans-serif small f
+ , { code = 0x1D5C0, char = '𝗀', class = 'ord', cs = 'msansg', alphabet = 'sans' } -- mathematical sans-serif small g
+ , { code = 0x1D5C1, char = '𝗁', class = 'ord', cs = 'msansh', alphabet = 'sans' } -- mathematical sans-serif small h
+ , { code = 0x1D5C2, char = '𝗂', class = 'ord', cs = 'msansi', alphabet = 'sans' } -- mathematical sans-serif small i
+ , { code = 0x1D5C3, char = '𝗃', class = 'ord', cs = 'msansj', alphabet = 'sans' } -- mathematical sans-serif small j
+ , { code = 0x1D5C4, char = '𝗄', class = 'ord', cs = 'msansk', alphabet = 'sans' } -- mathematical sans-serif small k
+ , { code = 0x1D5C5, char = '𝗅', class = 'ord', cs = 'msansl', alphabet = 'sans' } -- mathematical sans-serif small l
+ , { code = 0x1D5C6, char = '𝗆', class = 'ord', cs = 'msansm', alphabet = 'sans' } -- mathematical sans-serif small m
+ , { code = 0x1D5C7, char = '𝗇', class = 'ord', cs = 'msansn', alphabet = 'sans' } -- mathematical sans-serif small n
+ , { code = 0x1D5C8, char = '𝗈', class = 'ord', cs = 'msanso', alphabet = 'sans' } -- mathematical sans-serif small o
+ , { code = 0x1D5C9, char = '𝗉', class = 'ord', cs = 'msansp', alphabet = 'sans' } -- mathematical sans-serif small p
+ , { code = 0x1D5CA, char = '𝗊', class = 'ord', cs = 'msansq', alphabet = 'sans' } -- mathematical sans-serif small q
+ , { code = 0x1D5CB, char = '𝗋', class = 'ord', cs = 'msansr', alphabet = 'sans' } -- mathematical sans-serif small r
+ , { code = 0x1D5CC, char = '𝗌', class = 'ord', cs = 'msanss', alphabet = 'sans' } -- mathematical sans-serif small s
+ , { code = 0x1D5CD, char = '𝗍', class = 'ord', cs = 'msanst', alphabet = 'sans' } -- mathematical sans-serif small t
+ , { code = 0x1D5CE, char = '𝗎', class = 'ord', cs = 'msansu', alphabet = 'sans' } -- mathematical sans-serif small u
+ , { code = 0x1D5CF, char = '𝗏', class = 'ord', cs = 'msansv', alphabet = 'sans' } -- mathematical sans-serif small v
+ , { code = 0x1D5D0, char = '𝗐', class = 'ord', cs = 'msansw', alphabet = 'sans' } -- mathematical sans-serif small w
+ , { code = 0x1D5D1, char = '𝗑', class = 'ord', cs = 'msansx', alphabet = 'sans' } -- mathematical sans-serif small x
+ , { code = 0x1D5D2, char = '𝗒', class = 'ord', cs = 'msansy', alphabet = 'sans' } -- mathematical sans-serif small y
+ , { code = 0x1D5D3, char = '𝗓', class = 'ord', cs = 'msansz', alphabet = 'sans' } -- mathematical sans-serif small z
+ , { code = 0x1D5D4, char = '𝗔', class = 'ord', cs = 'mbfsansA', alphabet = 'sans' } -- mathematical sans-serif bold capital a
+ , { code = 0x1D5D5, char = '𝗕', class = 'ord', cs = 'mbfsansB', alphabet = 'sans' } -- mathematical sans-serif bold capital b
+ , { code = 0x1D5D6, char = '𝗖', class = 'ord', cs = 'mbfsansC', alphabet = 'sans' } -- mathematical sans-serif bold capital c
+ , { code = 0x1D5D7, char = '𝗗', class = 'ord', cs = 'mbfsansD', alphabet = 'sans' } -- mathematical sans-serif bold capital d
+ , { code = 0x1D5D8, char = '𝗘', class = 'ord', cs = 'mbfsansE', alphabet = 'sans' } -- mathematical sans-serif bold capital e
+ , { code = 0x1D5D9, char = '𝗙', class = 'ord', cs = 'mbfsansF', alphabet = 'sans' } -- mathematical sans-serif bold capital f
+ , { code = 0x1D5DA, char = '𝗚', class = 'ord', cs = 'mbfsansG', alphabet = 'sans' } -- mathematical sans-serif bold capital g
+ , { code = 0x1D5DB, char = '𝗛', class = 'ord', cs = 'mbfsansH', alphabet = 'sans' } -- mathematical sans-serif bold capital h
+ , { code = 0x1D5DC, char = '𝗜', class = 'ord', cs = 'mbfsansI', alphabet = 'sans' } -- mathematical sans-serif bold capital i
+ , { code = 0x1D5DD, char = '𝗝', class = 'ord', cs = 'mbfsansJ', alphabet = 'sans' } -- mathematical sans-serif bold capital j
+ , { code = 0x1D5DE, char = '𝗞', class = 'ord', cs = 'mbfsansK', alphabet = 'sans' } -- mathematical sans-serif bold capital k
+ , { code = 0x1D5DF, char = '𝗟', class = 'ord', cs = 'mbfsansL', alphabet = 'sans' } -- mathematical sans-serif bold capital l
+ , { code = 0x1D5E0, char = '𝗠', class = 'ord', cs = 'mbfsansM', alphabet = 'sans' } -- mathematical sans-serif bold capital m
+ , { code = 0x1D5E1, char = '𝗡', class = 'ord', cs = 'mbfsansN', alphabet = 'sans' } -- mathematical sans-serif bold capital n
+ , { code = 0x1D5E2, char = '𝗢', class = 'ord', cs = 'mbfsansO', alphabet = 'sans' } -- mathematical sans-serif bold capital o
+ , { code = 0x1D5E3, char = '𝗣', class = 'ord', cs = 'mbfsansP', alphabet = 'sans' } -- mathematical sans-serif bold capital p
+ , { code = 0x1D5E4, char = '𝗤', class = 'ord', cs = 'mbfsansQ', alphabet = 'sans' } -- mathematical sans-serif bold capital q
+ , { code = 0x1D5E5, char = '𝗥', class = 'ord', cs = 'mbfsansR', alphabet = 'sans' } -- mathematical sans-serif bold capital r
+ , { code = 0x1D5E6, char = '𝗦', class = 'ord', cs = 'mbfsansS', alphabet = 'sans' } -- mathematical sans-serif bold capital s
+ , { code = 0x1D5E7, char = '𝗧', class = 'ord', cs = 'mbfsansT', alphabet = 'sans' } -- mathematical sans-serif bold capital t
+ , { code = 0x1D5E8, char = '𝗨', class = 'ord', cs = 'mbfsansU', alphabet = 'sans' } -- mathematical sans-serif bold capital u
+ , { code = 0x1D5E9, char = '𝗩', class = 'ord', cs = 'mbfsansV', alphabet = 'sans' } -- mathematical sans-serif bold capital v
+ , { code = 0x1D5EA, char = '𝗪', class = 'ord', cs = 'mbfsansW', alphabet = 'sans' } -- mathematical sans-serif bold capital w
+ , { code = 0x1D5EB, char = '𝗫', class = 'ord', cs = 'mbfsansX', alphabet = 'sans' } -- mathematical sans-serif bold capital x
+ , { code = 0x1D5EC, char = '𝗬', class = 'ord', cs = 'mbfsansY', alphabet = 'sans' } -- mathematical sans-serif bold capital y
+ , { code = 0x1D5ED, char = '𝗭', class = 'ord', cs = 'mbfsansZ', alphabet = 'sans' } -- mathematical sans-serif bold capital z
+ , { code = 0x1D5EE, char = '𝗮', class = 'ord', cs = 'mbfsansa', alphabet = 'sans' } -- mathematical sans-serif bold small a
+ , { code = 0x1D5EF, char = '𝗯', class = 'ord', cs = 'mbfsansb', alphabet = 'sans' } -- mathematical sans-serif bold small b
+ , { code = 0x1D5F0, char = '𝗰', class = 'ord', cs = 'mbfsansc', alphabet = 'sans' } -- mathematical sans-serif bold small c
+ , { code = 0x1D5F1, char = '𝗱', class = 'ord', cs = 'mbfsansd', alphabet = 'sans' } -- mathematical sans-serif bold small d
+ , { code = 0x1D5F2, char = '𝗲', class = 'ord', cs = 'mbfsanse', alphabet = 'sans' } -- mathematical sans-serif bold small e
+ , { code = 0x1D5F3, char = '𝗳', class = 'ord', cs = 'mbfsansf', alphabet = 'sans' } -- mathematical sans-serif bold small f
+ , { code = 0x1D5F4, char = '𝗴', class = 'ord', cs = 'mbfsansg', alphabet = 'sans' } -- mathematical sans-serif bold small g
+ , { code = 0x1D5F5, char = '𝗵', class = 'ord', cs = 'mbfsansh', alphabet = 'sans' } -- mathematical sans-serif bold small h
+ , { code = 0x1D5F6, char = '𝗶', class = 'ord', cs = 'mbfsansi', alphabet = 'sans' } -- mathematical sans-serif bold small i
+ , { code = 0x1D5F7, char = '𝗷', class = 'ord', cs = 'mbfsansj', alphabet = 'sans' } -- mathematical sans-serif bold small j
+ , { code = 0x1D5F8, char = '𝗸', class = 'ord', cs = 'mbfsansk', alphabet = 'sans' } -- mathematical sans-serif bold small k
+ , { code = 0x1D5F9, char = '𝗹', class = 'ord', cs = 'mbfsansl', alphabet = 'sans' } -- mathematical sans-serif bold small l
+ , { code = 0x1D5FA, char = '𝗺', class = 'ord', cs = 'mbfsansm', alphabet = 'sans' } -- mathematical sans-serif bold small m
+ , { code = 0x1D5FB, char = '𝗻', class = 'ord', cs = 'mbfsansn', alphabet = 'sans' } -- mathematical sans-serif bold small n
+ , { code = 0x1D5FC, char = '𝗼', class = 'ord', cs = 'mbfsanso', alphabet = 'sans' } -- mathematical sans-serif bold small o
+ , { code = 0x1D5FD, char = '𝗽', class = 'ord', cs = 'mbfsansp', alphabet = 'sans' } -- mathematical sans-serif bold small p
+ , { code = 0x1D5FE, char = '𝗾', class = 'ord', cs = 'mbfsansq', alphabet = 'sans' } -- mathematical sans-serif bold small q
+ , { code = 0x1D5FF, char = '𝗿', class = 'ord', cs = 'mbfsansr', alphabet = 'sans' } -- mathematical sans-serif bold small r
+ , { code = 0x1D600, char = '𝘀', class = 'ord', cs = 'mbfsanss', alphabet = 'sans' } -- mathematical sans-serif bold small s
+ , { code = 0x1D601, char = '𝘁', class = 'ord', cs = 'mbfsanst', alphabet = 'sans' } -- mathematical sans-serif bold small t
+ , { code = 0x1D602, char = '𝘂', class = 'ord', cs = 'mbfsansu', alphabet = 'sans' } -- mathematical sans-serif bold small u
+ , { code = 0x1D603, char = '𝘃', class = 'ord', cs = 'mbfsansv', alphabet = 'sans' } -- mathematical sans-serif bold small v
+ , { code = 0x1D604, char = '𝘄', class = 'ord', cs = 'mbfsansw', alphabet = 'sans' } -- mathematical sans-serif bold small w
+ , { code = 0x1D605, char = '𝘅', class = 'ord', cs = 'mbfsansx', alphabet = 'sans' } -- mathematical sans-serif bold small x
+ , { code = 0x1D606, char = '𝘆', class = 'ord', cs = 'mbfsansy', alphabet = 'sans' } -- mathematical sans-serif bold small y
+ , { code = 0x1D607, char = '𝘇', class = 'ord', cs = 'mbfsansz', alphabet = 'sans' } -- mathematical sans-serif bold small z
+ , { code = 0x1D608, char = '𝘈', class = 'ord', cs = 'mitsansA', alphabet = 'sans' } -- mathematical sans-serif italic capital a
+ , { code = 0x1D609, char = '𝘉', class = 'ord', cs = 'mitsansB', alphabet = 'sans' } -- mathematical sans-serif italic capital b
+ , { code = 0x1D60A, char = '𝘊', class = 'ord', cs = 'mitsansC', alphabet = 'sans' } -- mathematical sans-serif italic capital c
+ , { code = 0x1D60B, char = '𝘋', class = 'ord', cs = 'mitsansD', alphabet = 'sans' } -- mathematical sans-serif italic capital d
+ , { code = 0x1D60C, char = '𝘌', class = 'ord', cs = 'mitsansE', alphabet = 'sans' } -- mathematical sans-serif italic capital e
+ , { code = 0x1D60D, char = '𝘍', class = 'ord', cs = 'mitsansF', alphabet = 'sans' } -- mathematical sans-serif italic capital f
+ , { code = 0x1D60E, char = '𝘎', class = 'ord', cs = 'mitsansG', alphabet = 'sans' } -- mathematical sans-serif italic capital g
+ , { code = 0x1D60F, char = '𝘏', class = 'ord', cs = 'mitsansH', alphabet = 'sans' } -- mathematical sans-serif italic capital h
+ , { code = 0x1D610, char = '𝘐', class = 'ord', cs = 'mitsansI', alphabet = 'sans' } -- mathematical sans-serif italic capital i
+ , { code = 0x1D611, char = '𝘑', class = 'ord', cs = 'mitsansJ', alphabet = 'sans' } -- mathematical sans-serif italic capital j
+ , { code = 0x1D612, char = '𝘒', class = 'ord', cs = 'mitsansK', alphabet = 'sans' } -- mathematical sans-serif italic capital k
+ , { code = 0x1D613, char = '𝘓', class = 'ord', cs = 'mitsansL', alphabet = 'sans' } -- mathematical sans-serif italic capital l
+ , { code = 0x1D614, char = '𝘔', class = 'ord', cs = 'mitsansM', alphabet = 'sans' } -- mathematical sans-serif italic capital m
+ , { code = 0x1D615, char = '𝘕', class = 'ord', cs = 'mitsansN', alphabet = 'sans' } -- mathematical sans-serif italic capital n
+ , { code = 0x1D616, char = '𝘖', class = 'ord', cs = 'mitsansO', alphabet = 'sans' } -- mathematical sans-serif italic capital o
+ , { code = 0x1D617, char = '𝘗', class = 'ord', cs = 'mitsansP', alphabet = 'sans' } -- mathematical sans-serif italic capital p
+ , { code = 0x1D618, char = '𝘘', class = 'ord', cs = 'mitsansQ', alphabet = 'sans' } -- mathematical sans-serif italic capital q
+ , { code = 0x1D619, char = '𝘙', class = 'ord', cs = 'mitsansR', alphabet = 'sans' } -- mathematical sans-serif italic capital r
+ , { code = 0x1D61A, char = '𝘚', class = 'ord', cs = 'mitsansS', alphabet = 'sans' } -- mathematical sans-serif italic capital s
+ , { code = 0x1D61B, char = '𝘛', class = 'ord', cs = 'mitsansT', alphabet = 'sans' } -- mathematical sans-serif italic capital t
+ , { code = 0x1D61C, char = '𝘜', class = 'ord', cs = 'mitsansU', alphabet = 'sans' } -- mathematical sans-serif italic capital u
+ , { code = 0x1D61D, char = '𝘝', class = 'ord', cs = 'mitsansV', alphabet = 'sans' } -- mathematical sans-serif italic capital v
+ , { code = 0x1D61E, char = '𝘞', class = 'ord', cs = 'mitsansW', alphabet = 'sans' } -- mathematical sans-serif italic capital w
+ , { code = 0x1D61F, char = '𝘟', class = 'ord', cs = 'mitsansX', alphabet = 'sans' } -- mathematical sans-serif italic capital x
+ , { code = 0x1D620, char = '𝘠', class = 'ord', cs = 'mitsansY', alphabet = 'sans' } -- mathematical sans-serif italic capital y
+ , { code = 0x1D621, char = '𝘡', class = 'ord', cs = 'mitsansZ', alphabet = 'sans' } -- mathematical sans-serif italic capital z
+ , { code = 0x1D622, char = '𝘢', class = 'ord', cs = 'mitsansa', alphabet = 'sans' } -- mathematical sans-serif italic small a
+ , { code = 0x1D623, char = '𝘣', class = 'ord', cs = 'mitsansb', alphabet = 'sans' } -- mathematical sans-serif italic small b
+ , { code = 0x1D624, char = '𝘤', class = 'ord', cs = 'mitsansc', alphabet = 'sans' } -- mathematical sans-serif italic small c
+ , { code = 0x1D625, char = '𝘥', class = 'ord', cs = 'mitsansd', alphabet = 'sans' } -- mathematical sans-serif italic small d
+ , { code = 0x1D626, char = '𝘦', class = 'ord', cs = 'mitsanse', alphabet = 'sans' } -- mathematical sans-serif italic small e
+ , { code = 0x1D627, char = '𝘧', class = 'ord', cs = 'mitsansf', alphabet = 'sans' } -- mathematical sans-serif italic small f
+ , { code = 0x1D628, char = '𝘨', class = 'ord', cs = 'mitsansg', alphabet = 'sans' } -- mathematical sans-serif italic small g
+ , { code = 0x1D629, char = '𝘩', class = 'ord', cs = 'mitsansh', alphabet = 'sans' } -- mathematical sans-serif italic small h
+ , { code = 0x1D62A, char = '𝘪', class = 'ord', cs = 'mitsansi', alphabet = 'sans' } -- mathematical sans-serif italic small i
+ , { code = 0x1D62B, char = '𝘫', class = 'ord', cs = 'mitsansj', alphabet = 'sans' } -- mathematical sans-serif italic small j
+ , { code = 0x1D62C, char = '𝘬', class = 'ord', cs = 'mitsansk', alphabet = 'sans' } -- mathematical sans-serif italic small k
+ , { code = 0x1D62D, char = '𝘭', class = 'ord', cs = 'mitsansl', alphabet = 'sans' } -- mathematical sans-serif italic small l
+ , { code = 0x1D62E, char = '𝘮', class = 'ord', cs = 'mitsansm', alphabet = 'sans' } -- mathematical sans-serif italic small m
+ , { code = 0x1D62F, char = '𝘯', class = 'ord', cs = 'mitsansn', alphabet = 'sans' } -- mathematical sans-serif italic small n
+ , { code = 0x1D630, char = '𝘰', class = 'ord', cs = 'mitsanso', alphabet = 'sans' } -- mathematical sans-serif italic small o
+ , { code = 0x1D631, char = '𝘱', class = 'ord', cs = 'mitsansp', alphabet = 'sans' } -- mathematical sans-serif italic small p
+ , { code = 0x1D632, char = '𝘲', class = 'ord', cs = 'mitsansq', alphabet = 'sans' } -- mathematical sans-serif italic small q
+ , { code = 0x1D633, char = '𝘳', class = 'ord', cs = 'mitsansr', alphabet = 'sans' } -- mathematical sans-serif italic small r
+ , { code = 0x1D634, char = '𝘴', class = 'ord', cs = 'mitsanss', alphabet = 'sans' } -- mathematical sans-serif italic small s
+ , { code = 0x1D635, char = '𝘵', class = 'ord', cs = 'mitsanst', alphabet = 'sans' } -- mathematical sans-serif italic small t
+ , { code = 0x1D636, char = '𝘶', class = 'ord', cs = 'mitsansu', alphabet = 'sans' } -- mathematical sans-serif italic small u
+ , { code = 0x1D637, char = '𝘷', class = 'ord', cs = 'mitsansv', alphabet = 'sans' } -- mathematical sans-serif italic small v
+ , { code = 0x1D638, char = '𝘸', class = 'ord', cs = 'mitsansw', alphabet = 'sans' } -- mathematical sans-serif italic small w
+ , { code = 0x1D639, char = '𝘹', class = 'ord', cs = 'mitsansx', alphabet = 'sans' } -- mathematical sans-serif italic small x
+ , { code = 0x1D63A, char = '𝘺', class = 'ord', cs = 'mitsansy', alphabet = 'sans' } -- mathematical sans-serif italic small y
+ , { code = 0x1D63B, char = '𝘻', class = 'ord', cs = 'mitsansz', alphabet = 'sans' } -- mathematical sans-serif italic small z
+ , { code = 0x1D63C, char = '𝘼', class = 'ord', cs = 'mbfitsansA', alphabet = 'sans' } -- mathematical sans-serif bold italic capital a
+ , { code = 0x1D63D, char = '𝘽', class = 'ord', cs = 'mbfitsansB', alphabet = 'sans' } -- mathematical sans-serif bold italic capital b
+ , { code = 0x1D63E, char = '𝘾', class = 'ord', cs = 'mbfitsansC', alphabet = 'sans' } -- mathematical sans-serif bold italic capital c
+ , { code = 0x1D63F, char = '𝘿', class = 'ord', cs = 'mbfitsansD', alphabet = 'sans' } -- mathematical sans-serif bold italic capital d
+ , { code = 0x1D640, char = '𝙀', class = 'ord', cs = 'mbfitsansE', alphabet = 'sans' } -- mathematical sans-serif bold italic capital e
+ , { code = 0x1D641, char = '𝙁', class = 'ord', cs = 'mbfitsansF', alphabet = 'sans' } -- mathematical sans-serif bold italic capital f
+ , { code = 0x1D642, char = '𝙂', class = 'ord', cs = 'mbfitsansG', alphabet = 'sans' } -- mathematical sans-serif bold italic capital g
+ , { code = 0x1D643, char = '𝙃', class = 'ord', cs = 'mbfitsansH', alphabet = 'sans' } -- mathematical sans-serif bold italic capital h
+ , { code = 0x1D644, char = '𝙄', class = 'ord', cs = 'mbfitsansI', alphabet = 'sans' } -- mathematical sans-serif bold italic capital i
+ , { code = 0x1D645, char = '𝙅', class = 'ord', cs = 'mbfitsansJ', alphabet = 'sans' } -- mathematical sans-serif bold italic capital j
+ , { code = 0x1D646, char = '𝙆', class = 'ord', cs = 'mbfitsansK', alphabet = 'sans' } -- mathematical sans-serif bold italic capital k
+ , { code = 0x1D647, char = '𝙇', class = 'ord', cs = 'mbfitsansL', alphabet = 'sans' } -- mathematical sans-serif bold italic capital l
+ , { code = 0x1D648, char = '𝙈', class = 'ord', cs = 'mbfitsansM', alphabet = 'sans' } -- mathematical sans-serif bold italic capital m
+ , { code = 0x1D649, char = '𝙉', class = 'ord', cs = 'mbfitsansN', alphabet = 'sans' } -- mathematical sans-serif bold italic capital n
+ , { code = 0x1D64A, char = '𝙊', class = 'ord', cs = 'mbfitsansO', alphabet = 'sans' } -- mathematical sans-serif bold italic capital o
+ , { code = 0x1D64B, char = '𝙋', class = 'ord', cs = 'mbfitsansP', alphabet = 'sans' } -- mathematical sans-serif bold italic capital p
+ , { code = 0x1D64C, char = '𝙌', class = 'ord', cs = 'mbfitsansQ', alphabet = 'sans' } -- mathematical sans-serif bold italic capital q
+ , { code = 0x1D64D, char = '𝙍', class = 'ord', cs = 'mbfitsansR', alphabet = 'sans' } -- mathematical sans-serif bold italic capital r
+ , { code = 0x1D64E, char = '𝙎', class = 'ord', cs = 'mbfitsansS', alphabet = 'sans' } -- mathematical sans-serif bold italic capital s
+ , { code = 0x1D64F, char = '𝙏', class = 'ord', cs = 'mbfitsansT', alphabet = 'sans' } -- mathematical sans-serif bold italic capital t
+ , { code = 0x1D650, char = '𝙐', class = 'ord', cs = 'mbfitsansU', alphabet = 'sans' } -- mathematical sans-serif bold italic capital u
+ , { code = 0x1D651, char = '𝙑', class = 'ord', cs = 'mbfitsansV', alphabet = 'sans' } -- mathematical sans-serif bold italic capital v
+ , { code = 0x1D652, char = '𝙒', class = 'ord', cs = 'mbfitsansW', alphabet = 'sans' } -- mathematical sans-serif bold italic capital w
+ , { code = 0x1D653, char = '𝙓', class = 'ord', cs = 'mbfitsansX', alphabet = 'sans' } -- mathematical sans-serif bold italic capital x
+ , { code = 0x1D654, char = '𝙔', class = 'ord', cs = 'mbfitsansY', alphabet = 'sans' } -- mathematical sans-serif bold italic capital y
+ , { code = 0x1D655, char = '𝙕', class = 'ord', cs = 'mbfitsansZ', alphabet = 'sans' } -- mathematical sans-serif bold italic capital z
+ , { code = 0x1D656, char = '𝙖', class = 'ord', cs = 'mbfitsansa', alphabet = 'sans' } -- mathematical sans-serif bold italic small a
+ , { code = 0x1D657, char = '𝙗', class = 'ord', cs = 'mbfitsansb', alphabet = 'sans' } -- mathematical sans-serif bold italic small b
+ , { code = 0x1D658, char = '𝙘', class = 'ord', cs = 'mbfitsansc', alphabet = 'sans' } -- mathematical sans-serif bold italic small c
+ , { code = 0x1D659, char = '𝙙', class = 'ord', cs = 'mbfitsansd', alphabet = 'sans' } -- mathematical sans-serif bold italic small d
+ , { code = 0x1D65A, char = '𝙚', class = 'ord', cs = 'mbfitsanse', alphabet = 'sans' } -- mathematical sans-serif bold italic small e
+ , { code = 0x1D65B, char = '𝙛', class = 'ord', cs = 'mbfitsansf', alphabet = 'sans' } -- mathematical sans-serif bold italic small f
+ , { code = 0x1D65C, char = '𝙜', class = 'ord', cs = 'mbfitsansg', alphabet = 'sans' } -- mathematical sans-serif bold italic small g
+ , { code = 0x1D65D, char = '𝙝', class = 'ord', cs = 'mbfitsansh', alphabet = 'sans' } -- mathematical sans-serif bold italic small h
+ , { code = 0x1D65E, char = '𝙞', class = 'ord', cs = 'mbfitsansi', alphabet = 'sans' } -- mathematical sans-serif bold italic small i
+ , { code = 0x1D65F, char = '𝙟', class = 'ord', cs = 'mbfitsansj', alphabet = 'sans' } -- mathematical sans-serif bold italic small j
+ , { code = 0x1D660, char = '𝙠', class = 'ord', cs = 'mbfitsansk', alphabet = 'sans' } -- mathematical sans-serif bold italic small k
+ , { code = 0x1D661, char = '𝙡', class = 'ord', cs = 'mbfitsansl', alphabet = 'sans' } -- mathematical sans-serif bold italic small l
+ , { code = 0x1D662, char = '𝙢', class = 'ord', cs = 'mbfitsansm', alphabet = 'sans' } -- mathematical sans-serif bold italic small m
+ , { code = 0x1D663, char = '𝙣', class = 'ord', cs = 'mbfitsansn', alphabet = 'sans' } -- mathematical sans-serif bold italic small n
+ , { code = 0x1D664, char = '𝙤', class = 'ord', cs = 'mbfitsanso', alphabet = 'sans' } -- mathematical sans-serif bold italic small o
+ , { code = 0x1D665, char = '𝙥', class = 'ord', cs = 'mbfitsansp', alphabet = 'sans' } -- mathematical sans-serif bold italic small p
+ , { code = 0x1D666, char = '𝙦', class = 'ord', cs = 'mbfitsansq', alphabet = 'sans' } -- mathematical sans-serif bold italic small q
+ , { code = 0x1D667, char = '𝙧', class = 'ord', cs = 'mbfitsansr', alphabet = 'sans' } -- mathematical sans-serif bold italic small r
+ , { code = 0x1D668, char = '𝙨', class = 'ord', cs = 'mbfitsanss', alphabet = 'sans' } -- mathematical sans-serif bold italic small s
+ , { code = 0x1D669, char = '𝙩', class = 'ord', cs = 'mbfitsanst', alphabet = 'sans' } -- mathematical sans-serif bold italic small t
+ , { code = 0x1D66A, char = '𝙪', class = 'ord', cs = 'mbfitsansu', alphabet = 'sans' } -- mathematical sans-serif bold italic small u
+ , { code = 0x1D66B, char = '𝙫', class = 'ord', cs = 'mbfitsansv', alphabet = 'sans' } -- mathematical sans-serif bold italic small v
+ , { code = 0x1D66C, char = '𝙬', class = 'ord', cs = 'mbfitsansw', alphabet = 'sans' } -- mathematical sans-serif bold italic small w
+ , { code = 0x1D66D, char = '𝙭', class = 'ord', cs = 'mbfitsansx', alphabet = 'sans' } -- mathematical sans-serif bold italic small x
+ , { code = 0x1D66E, char = '𝙮', class = 'ord', cs = 'mbfitsansy', alphabet = 'sans' } -- mathematical sans-serif bold italic small y
+ , { code = 0x1D66F, char = '𝙯', class = 'ord', cs = 'mbfitsansz', alphabet = 'sans' } -- mathematical sans-serif bold italic small z
+ , { code = 0x1D670, char = '𝙰', class = 'ord', cs = 'mttA', alphabet = 'mono' } -- mathematical monospace capital a
+ , { code = 0x1D671, char = '𝙱', class = 'ord', cs = 'mttB', alphabet = 'mono' } -- mathematical monospace capital b
+ , { code = 0x1D672, char = '𝙲', class = 'ord', cs = 'mttC', alphabet = 'mono' } -- mathematical monospace capital c
+ , { code = 0x1D673, char = '𝙳', class = 'ord', cs = 'mttD', alphabet = 'mono' } -- mathematical monospace capital d
+ , { code = 0x1D674, char = '𝙴', class = 'ord', cs = 'mttE', alphabet = 'mono' } -- mathematical monospace capital e
+ , { code = 0x1D675, char = '𝙵', class = 'ord', cs = 'mttF', alphabet = 'mono' } -- mathematical monospace capital f
+ , { code = 0x1D676, char = '𝙶', class = 'ord', cs = 'mttG', alphabet = 'mono' } -- mathematical monospace capital g
+ , { code = 0x1D677, char = '𝙷', class = 'ord', cs = 'mttH', alphabet = 'mono' } -- mathematical monospace capital h
+ , { code = 0x1D678, char = '𝙸', class = 'ord', cs = 'mttI', alphabet = 'mono' } -- mathematical monospace capital i
+ , { code = 0x1D679, char = '𝙹', class = 'ord', cs = 'mttJ', alphabet = 'mono' } -- mathematical monospace capital j
+ , { code = 0x1D67A, char = '𝙺', class = 'ord', cs = 'mttK', alphabet = 'mono' } -- mathematical monospace capital k
+ , { code = 0x1D67B, char = '𝙻', class = 'ord', cs = 'mttL', alphabet = 'mono' } -- mathematical monospace capital l
+ , { code = 0x1D67C, char = '𝙼', class = 'ord', cs = 'mttM', alphabet = 'mono' } -- mathematical monospace capital m
+ , { code = 0x1D67D, char = '𝙽', class = 'ord', cs = 'mttN', alphabet = 'mono' } -- mathematical monospace capital n
+ , { code = 0x1D67E, char = '𝙾', class = 'ord', cs = 'mttO', alphabet = 'mono' } -- mathematical monospace capital o
+ , { code = 0x1D67F, char = '𝙿', class = 'ord', cs = 'mttP', alphabet = 'mono' } -- mathematical monospace capital p
+ , { code = 0x1D680, char = '𝚀', class = 'ord', cs = 'mttQ', alphabet = 'mono' } -- mathematical monospace capital q
+ , { code = 0x1D681, char = '𝚁', class = 'ord', cs = 'mttR', alphabet = 'mono' } -- mathematical monospace capital r
+ , { code = 0x1D682, char = '𝚂', class = 'ord', cs = 'mttS', alphabet = 'mono' } -- mathematical monospace capital s
+ , { code = 0x1D683, char = '𝚃', class = 'ord', cs = 'mttT', alphabet = 'mono' } -- mathematical monospace capital t
+ , { code = 0x1D684, char = '𝚄', class = 'ord', cs = 'mttU', alphabet = 'mono' } -- mathematical monospace capital u
+ , { code = 0x1D685, char = '𝚅', class = 'ord', cs = 'mttV', alphabet = 'mono' } -- mathematical monospace capital v
+ , { code = 0x1D686, char = '𝚆', class = 'ord', cs = 'mttW', alphabet = 'mono' } -- mathematical monospace capital w
+ , { code = 0x1D687, char = '𝚇', class = 'ord', cs = 'mttX', alphabet = 'mono' } -- mathematical monospace capital x
+ , { code = 0x1D688, char = '𝚈', class = 'ord', cs = 'mttY', alphabet = 'mono' } -- mathematical monospace capital y
+ , { code = 0x1D689, char = '𝚉', class = 'ord', cs = 'mttZ', alphabet = 'mono' } -- mathematical monospace capital z
+ , { code = 0x1D68A, char = '𝚊', class = 'ord', cs = 'mtta', alphabet = 'mono' } -- mathematical monospace small a
+ , { code = 0x1D68B, char = '𝚋', class = 'ord', cs = 'mttb', alphabet = 'mono' } -- mathematical monospace small b
+ , { code = 0x1D68C, char = '𝚌', class = 'ord', cs = 'mttc', alphabet = 'mono' } -- mathematical monospace small c
+ , { code = 0x1D68D, char = '𝚍', class = 'ord', cs = 'mttd', alphabet = 'mono' } -- mathematical monospace small d
+ , { code = 0x1D68E, char = '𝚎', class = 'ord', cs = 'mtte', alphabet = 'mono' } -- mathematical monospace small e
+ , { code = 0x1D68F, char = '𝚏', class = 'ord', cs = 'mttf', alphabet = 'mono' } -- mathematical monospace small f
+ , { code = 0x1D690, char = '𝚐', class = 'ord', cs = 'mttg', alphabet = 'mono' } -- mathematical monospace small g
+ , { code = 0x1D691, char = '𝚑', class = 'ord', cs = 'mtth', alphabet = 'mono' } -- mathematical monospace small h
+ , { code = 0x1D692, char = '𝚒', class = 'ord', cs = 'mtti', alphabet = 'mono' } -- mathematical monospace small i
+ , { code = 0x1D693, char = '𝚓', class = 'ord', cs = 'mttj', alphabet = 'mono' } -- mathematical monospace small j
+ , { code = 0x1D694, char = '𝚔', class = 'ord', cs = 'mttk', alphabet = 'mono' } -- mathematical monospace small k
+ , { code = 0x1D695, char = '𝚕', class = 'ord', cs = 'mttl', alphabet = 'mono' } -- mathematical monospace small l
+ , { code = 0x1D696, char = '𝚖', class = 'ord', cs = 'mttm', alphabet = 'mono' } -- mathematical monospace small m
+ , { code = 0x1D697, char = '𝚗', class = 'ord', cs = 'mttn', alphabet = 'mono' } -- mathematical monospace small n
+ , { code = 0x1D698, char = '𝚘', class = 'ord', cs = 'mtto', alphabet = 'mono' } -- mathematical monospace small o
+ , { code = 0x1D699, char = '𝚙', class = 'ord', cs = 'mttp', alphabet = 'mono' } -- mathematical monospace small p
+ , { code = 0x1D69A, char = '𝚚', class = 'ord', cs = 'mttq', alphabet = 'mono' } -- mathematical monospace small q
+ , { code = 0x1D69B, char = '𝚛', class = 'ord', cs = 'mttr', alphabet = 'mono' } -- mathematical monospace small r
+ , { code = 0x1D69C, char = '𝚜', class = 'ord', cs = 'mtts', alphabet = 'mono' } -- mathematical monospace small s
+ , { code = 0x1D69D, char = '𝚝', class = 'ord', cs = 'mttt', alphabet = 'mono' } -- mathematical monospace small t
+ , { code = 0x1D69E, char = '𝚞', class = 'ord', cs = 'mttu', alphabet = 'mono' } -- mathematical monospace small u
+ , { code = 0x1D69F, char = '𝚟', class = 'ord', cs = 'mttv', alphabet = 'mono' } -- mathematical monospace small v
+ , { code = 0x1D6A0, char = '𝚠', class = 'ord', cs = 'mttw', alphabet = 'mono' } -- mathematical monospace small w
+ , { code = 0x1D6A1, char = '𝚡', class = 'ord', cs = 'mttx', alphabet = 'mono' } -- mathematical monospace small x
+ , { code = 0x1D6A2, char = '𝚢', class = 'ord', cs = 'mtty', alphabet = 'mono' } -- mathematical monospace small y
+ , { code = 0x1D6A3, char = '𝚣', class = 'ord', cs = 'mttz', alphabet = 'mono' } -- mathematical monospace small z
+ , { code = 0x1D6A4, char = '𝚤', class = 'ord', cs = 'imath' } -- mathematical italic small dotless i
+ , { code = 0x1D6A5, char = '𝚥', class = 'ord', cs = 'jmath' } -- mathematical italic small dotless j
+ , { code = 0x1D6A8, char = '𝚨', class = 'ord', cs = 'mbfAlpha', alphabet = 'boldgreek' } -- mathematical bold capital alpha
+ , { code = 0x1D6A9, char = '𝚩', class = 'ord', cs = 'mbfBeta', alphabet = 'boldgreek' } -- mathematical bold capital beta
+ , { code = 0x1D6AA, char = '𝚪', class = 'ord', cs = 'mbfGamma', alphabet = 'boldgreek' } -- mathematical bold capital gamma
+ , { code = 0x1D6AB, char = '𝚫', class = 'ord', cs = 'mbfDelta', alphabet = 'boldgreek' } -- mathematical bold capital delta
+ , { code = 0x1D6AC, char = '𝚬', class = 'ord', cs = 'mbfEpsilon', alphabet = 'boldgreek'} -- mathematical bold capital epsilon
+ , { code = 0x1D6AD, char = '𝚭', class = 'ord', cs = 'mbfZeta', alphabet = 'boldgreek' } -- mathematical bold capital zeta
+ , { code = 0x1D6AE, char = '𝚮', class = 'ord', cs = 'mbfEta', alphabet = 'boldgreek' } -- mathematical bold capital eta
+ , { code = 0x1D6AF, char = '𝚯', class = 'ord', cs = 'mbfTheta', alphabet = 'boldgreek' } -- mathematical bold capital theta
+ , { code = 0x1D6B0, char = '𝚰', class = 'ord', cs = 'mbfIota', alphabet = 'boldgreek' } -- mathematical bold capital iota
+ , { code = 0x1D6B1, char = '𝚱', class = 'ord', cs = 'mbfKappa', alphabet = 'boldgreek' } -- mathematical bold capital kappa
+ , { code = 0x1D6B2, char = '𝚲', class = 'ord', cs = 'mbfLambda', alphabet = 'boldgreek' } -- mathematical bold capital lamda
+ , { code = 0x1D6B3, char = '𝚳', class = 'ord', cs = 'mbfMu', alphabet = 'boldgreek' } -- mathematical bold capital mu
+ , { code = 0x1D6B4, char = '𝚴', class = 'ord', cs = 'mbfNu', alphabet = 'boldgreek' } -- mathematical bold capital nu
+ , { code = 0x1D6B5, char = '𝚵', class = 'ord', cs = 'mbfXi', alphabet = 'boldgreek' } -- mathematical bold capital xi
+ , { code = 0x1D6B6, char = '𝚶', class = 'ord', cs = 'mbfOmicron', alphabet = 'boldgreek'} -- mathematical bold capital omicron
+ , { code = 0x1D6B7, char = '𝚷', class = 'ord', cs = 'mbfPi', alphabet = 'boldgreek' } -- mathematical bold capital pi
+ , { code = 0x1D6B8, char = '𝚸', class = 'ord', cs = 'mbfRho', alphabet = 'boldgreek' } -- mathematical bold capital rho
+ , { code = 0x1D6B9, char = '𝚹', class = 'ord', cs = 'mbfvarTheta', alphabet = 'boldgreek'} -- mathematical bold capital theta symbol
+ , { code = 0x1D6BA, char = '𝚺', class = 'ord', cs = 'mbfSigma', alphabet = 'boldgreek' } -- mathematical bold capital sigma
+ , { code = 0x1D6BB, char = '𝚻', class = 'ord', cs = 'mbfTau', alphabet = 'boldgreek' } -- mathematical bold capital tau
+ , { code = 0x1D6BC, char = '𝚼', class = 'ord', cs = 'mbfUpsilon', alphabet = 'boldgreek'} -- mathematical bold capital upsilon
+ , { code = 0x1D6BD, char = '𝚽', class = 'ord', cs = 'mbfPhi', alphabet = 'boldgreek' } -- mathematical bold capital phi
+ , { code = 0x1D6BE, char = '𝚾', class = 'ord', cs = 'mbfChi', alphabet = 'boldgreek' } -- mathematical bold capital chi
+ , { code = 0x1D6BF, char = '𝚿', class = 'ord', cs = 'mbfPsi', alphabet = 'boldgreek' } -- mathematical bold capital psi
+ , { code = 0x1D6C0, char = '𝛀', class = 'ord', cs = 'mbfOmega', alphabet = 'boldgreek' } -- mathematical bold capital omega
+ , { code = 0x1D6C1, char = '𝛁', class = 'ord', cs = 'mbfnabla' } -- mathematical bold nabla
+ , { code = 0x1D6C2, char = '𝛂', class = 'ord', cs = 'mbfalpha', alphabet = 'boldgreek' } -- mathematical bold small alpha
+ , { code = 0x1D6C3, char = '𝛃', class = 'ord', cs = 'mbfbeta', alphabet = 'boldgreek' } -- mathematical bold small beta
+ , { code = 0x1D6C4, char = '𝛄', class = 'ord', cs = 'mbfgamma', alphabet = 'boldgreek' } -- mathematical bold small gamma
+ , { code = 0x1D6C5, char = '𝛅', class = 'ord', cs = 'mbfdelta', alphabet = 'boldgreek' } -- mathematical bold small delta
+ , { code = 0x1D6C6, char = '𝛆', class = 'ord', cs = 'mbfepsilon', alphabet = 'boldgreek'} -- mathematical bold small epsilon
+ , { code = 0x1D6C7, char = '𝛇', class = 'ord', cs = 'mbfzeta', alphabet = 'boldgreek' } -- mathematical bold small zeta
+ , { code = 0x1D6C8, char = '𝛈', class = 'ord', cs = 'mbfeta', alphabet = 'boldgreek' } -- mathematical bold small eta
+ , { code = 0x1D6C9, char = '𝛉', class = 'ord', cs = 'mbftheta', alphabet = 'boldgreek' } -- mathematical bold small theta
+ , { code = 0x1D6CA, char = '𝛊', class = 'ord', cs = 'mbfiota', alphabet = 'boldgreek' } -- mathematical bold small iota
+ , { code = 0x1D6CB, char = '𝛋', class = 'ord', cs = 'mbfkappa', alphabet = 'boldgreek' } -- mathematical bold small kappa
+ , { code = 0x1D6CC, char = '𝛌', class = 'ord', cs = 'mbflambda', alphabet = 'boldgreek' } -- mathematical bold small lamda
+ , { code = 0x1D6CD, char = '𝛍', class = 'ord', cs = 'mbfmu', alphabet = 'boldgreek' } -- mathematical bold small mu
+ , { code = 0x1D6CE, char = '𝛎', class = 'ord', cs = 'mbfnu', alphabet = 'boldgreek' } -- mathematical bold small nu
+ , { code = 0x1D6CF, char = '𝛏', class = 'ord', cs = 'mbfxi', alphabet = 'boldgreek' } -- mathematical bold small xi
+ , { code = 0x1D6D0, char = '𝛐', class = 'ord', cs = 'mbfomicron', alphabet = 'boldgreek'} -- mathematical bold small omicron
+ , { code = 0x1D6D1, char = '𝛑', class = 'ord', cs = 'mbfpi', alphabet = 'boldgreek' } -- mathematical bold small pi
+ , { code = 0x1D6D2, char = '𝛒', class = 'ord', cs = 'mbfrho', alphabet = 'boldgreek' } -- mathematical bold small rho
+ , { code = 0x1D6D3, char = '𝛓', class = 'ord', cs = 'mbfvarsigma', alphabet = 'boldgreek'} -- mathematical bold small final sigma
+ , { code = 0x1D6D4, char = '𝛔', class = 'ord', cs = 'mbfsigma', alphabet = 'boldgreek' } -- mathematical bold small sigma
+ , { code = 0x1D6D5, char = '𝛕', class = 'ord', cs = 'mbftau', alphabet = 'boldgreek' } -- mathematical bold small tau
+ , { code = 0x1D6D6, char = '𝛖', class = 'ord', cs = 'mbfupsilon', alphabet = 'boldgreek'} -- mathematical bold small upsilon
+ , { code = 0x1D6D7, char = '𝛗', class = 'ord', cs = 'mbfphi', alphabet = 'boldgreek' } -- mathematical bold small phi
+ , { code = 0x1D6D8, char = '𝛘', class = 'ord', cs = 'mbfchi', alphabet = 'boldgreek' } -- mathematical bold small chi
+ , { code = 0x1D6D9, char = '𝛙', class = 'ord', cs = 'mbfpsi', alphabet = 'boldgreek' } -- mathematical bold small psi
+ , { code = 0x1D6DA, char = '𝛚', class = 'ord', cs = 'mbfomega', alphabet = 'boldgreek' } -- mathematical bold small omega
+ , { code = 0x1D6DB, char = '𝛛', class = 'ord', cs = 'mbfpartial' } -- mathematical bold partial differential
+ , { code = 0x1D6DC, char = '𝛜', class = 'ord', cs = 'mbfvarepsilon', alphabet = 'boldgreek'} -- mathematical bold epsilon symbol
+ , { code = 0x1D6DD, char = '𝛝', class = 'ord', cs = 'mbfvartheta', alphabet = 'boldgreek'} -- mathematical bold theta symbol
+ , { code = 0x1D6DE, char = '𝛞', class = 'ord', cs = 'mbfvarkappa', alphabet = 'boldgreek'} -- mathematical bold kappa symbol
+ , { code = 0x1D6DF, char = '𝛟', class = 'ord', cs = 'mbfvarphi', alphabet = 'boldgreek' } -- mathematical bold phi symbol
+ , { code = 0x1D6E0, char = '𝛠', class = 'ord', cs = 'mbfvarrho', alphabet = 'boldgreek' } -- mathematical bold rho symbol
+ , { code = 0x1D6E1, char = '𝛡', class = 'ord', cs = 'mbfvarpi', alphabet = 'boldgreek' } -- mathematical bold pi symbol
+ , { code = 0x1D6E2, char = '𝛢', class = 'ord', cs = 'mitAlpha' } -- mathematical italic capital alpha
+ , { code = 0x1D6E3, char = '𝛣', class = 'ord', cs = 'mitBeta' } -- mathematical italic capital beta
+ , { code = 0x1D6E4, char = '𝛤', class = 'ord', cs = 'mitGamma' } -- mathematical italic capital gamma
+ , { code = 0x1D6E5, char = '𝛥', class = 'ord', cs = 'mitDelta' } -- mathematical italic capital delta
+ , { code = 0x1D6E6, char = '𝛦', class = 'ord', cs = 'mitEpsilon' } -- mathematical italic capital epsilon
+ , { code = 0x1D6E7, char = '𝛧', class = 'ord', cs = 'mitZeta' } -- mathematical italic capital zeta
+ , { code = 0x1D6E8, char = '𝛨', class = 'ord', cs = 'mitEta' } -- mathematical italic capital eta
+ , { code = 0x1D6E9, char = '𝛩', class = 'ord', cs = 'mitTheta' } -- mathematical italic capital theta
+ , { code = 0x1D6EA, char = '𝛪', class = 'ord', cs = 'mitIota' } -- mathematical italic capital iota
+ , { code = 0x1D6EB, char = '𝛫', class = 'ord', cs = 'mitKappa' } -- mathematical italic capital kappa
+ , { code = 0x1D6EC, char = '𝛬', class = 'ord', cs = 'mitLambda' } -- mathematical italic capital lamda
+ , { code = 0x1D6ED, char = '𝛭', class = 'ord', cs = 'mitMu' } -- mathematical italic capital mu
+ , { code = 0x1D6EE, char = '𝛮', class = 'ord', cs = 'mitNu' } -- mathematical italic capital nu
+ , { code = 0x1D6EF, char = '𝛯', class = 'ord', cs = 'mitXi' } -- mathematical italic capital xi
+ , { code = 0x1D6F0, char = '𝛰', class = 'ord', cs = 'mitOmicron' } -- mathematical italic capital omicron
+ , { code = 0x1D6F1, char = '𝛱', class = 'ord', cs = 'mitPi' } -- mathematical italic capital pi
+ , { code = 0x1D6F2, char = '𝛲', class = 'ord', cs = 'mitRho' } -- mathematical italic capital rho
+ , { code = 0x1D6F3, char = '𝛳', class = 'ord', cs = 'mitvarTheta' } -- mathematical italic capital theta symbol
+ , { code = 0x1D6F4, char = '𝛴', class = 'ord', cs = 'mitSigma' } -- mathematical italic capital sigma
+ , { code = 0x1D6F5, char = '𝛵', class = 'ord', cs = 'mitTau' } -- mathematical italic capital tau
+ , { code = 0x1D6F6, char = '𝛶', class = 'ord', cs = 'mitUpsilon' } -- mathematical italic capital upsilon
+ , { code = 0x1D6F7, char = '𝛷', class = 'ord', cs = 'mitPhi' } -- mathematical italic capital phi
+ , { code = 0x1D6F8, char = '𝛸', class = 'ord', cs = 'mitChi' } -- mathematical italic capital chi
+ , { code = 0x1D6F9, char = '𝛹', class = 'ord', cs = 'mitPsi' } -- mathematical italic capital psi
+ , { code = 0x1D6FA, char = '𝛺', class = 'ord', cs = 'mitOmega' } -- mathematical italic capital omega
+ , { code = 0x1D6FB, char = '𝛻', class = 'ord', cs = 'mitnabla' } -- mathematical italic nabla
+ , { code = 0x1D6FC, char = '𝛼', class = 'ord', cs = 'mitalpha' } -- mathematical italic small alpha
+ , { code = 0x1D6FD, char = '𝛽', class = 'ord', cs = 'mitbeta' } -- mathematical italic small beta
+ , { code = 0x1D6FE, char = '𝛾', class = 'ord', cs = 'mitgamma' } -- mathematical italic small gamma
+ , { code = 0x1D6FF, char = '𝛿', class = 'ord', cs = 'mitdelta' } -- mathematical italic small delta
+ , { code = 0x1D700, char = '𝜀', class = 'ord', cs = 'mitepsilon' } -- mathematical italic small epsilon
+ , { code = 0x1D701, char = '𝜁', class = 'ord', cs = 'mitzeta' } -- mathematical italic small zeta
+ , { code = 0x1D702, char = '𝜂', class = 'ord', cs = 'miteta' } -- mathematical italic small eta
+ , { code = 0x1D703, char = '𝜃', class = 'ord', cs = 'mittheta' } -- mathematical italic small theta
+ , { code = 0x1D704, char = '𝜄', class = 'ord', cs = 'mitiota' } -- mathematical italic small iota
+ , { code = 0x1D705, char = '𝜅', class = 'ord', cs = 'mitkappa' } -- mathematical italic small kappa
+ , { code = 0x1D706, char = '𝜆', class = 'ord', cs = 'mitlambda' } -- mathematical italic small lamda
+ , { code = 0x1D707, char = '𝜇', class = 'ord', cs = 'mitmu' } -- mathematical italic small mu
+ , { code = 0x1D708, char = '𝜈', class = 'ord', cs = 'mitnu' } -- mathematical italic small nu
+ , { code = 0x1D709, char = '𝜉', class = 'ord', cs = 'mitxi' } -- mathematical italic small xi
+ , { code = 0x1D70A, char = '𝜊', class = 'ord', cs = 'mitomicron' } -- mathematical italic small omicron
+ , { code = 0x1D70B, char = '𝜋', class = 'ord', cs = 'mitpi' } -- mathematical italic small pi
+ , { code = 0x1D70C, char = '𝜌', class = 'ord', cs = 'mitrho' } -- mathematical italic small rho
+ , { code = 0x1D70D, char = '𝜍', class = 'ord', cs = 'mitvarsigma' } -- mathematical italic small final sigma
+ , { code = 0x1D70E, char = '𝜎', class = 'ord', cs = 'mitsigma' } -- mathematical italic small sigma
+ , { code = 0x1D70F, char = '𝜏', class = 'ord', cs = 'mittau' } -- mathematical italic small tau
+ , { code = 0x1D710, char = '𝜐', class = 'ord', cs = 'mitupsilon' } -- mathematical italic small upsilon
+ , { code = 0x1D711, char = '𝜑', class = 'ord', cs = 'mitphi' } -- mathematical italic small phi
+ , { code = 0x1D712, char = '𝜒', class = 'ord', cs = 'mitchi' } -- mathematical italic small chi
+ , { code = 0x1D713, char = '𝜓', class = 'ord', cs = 'mitpsi' } -- mathematical italic small psi
+ , { code = 0x1D714, char = '𝜔', class = 'ord', cs = 'mitomega' } -- mathematical italic small omega
+ , { code = 0x1D715, char = '𝜕', class = 'ord', cs = 'mitpartial' } -- mathematical italic partial differential
+ , { code = 0x1D716, char = '𝜖', class = 'ord', cs = 'mitvarepsilon' } -- mathematical italic epsilon symbol
+ , { code = 0x1D717, char = '𝜗', class = 'ord', cs = 'mitvartheta' } -- mathematical italic theta symbol
+ , { code = 0x1D718, char = '𝜘', class = 'ord', cs = 'mitvarkappa' } -- mathematical italic kappa symbol
+ , { code = 0x1D719, char = '𝜙', class = 'ord', cs = 'mitvarphi' } -- mathematical italic phi symbol
+ , { code = 0x1D71A, char = '𝜚', class = 'ord', cs = 'mitvarrho' } -- mathematical italic rho symbol
+ , { code = 0x1D71B, char = '𝜛', class = 'ord', cs = 'mitvarpi' } -- mathematical italic pi symbol
+ , { code = 0x1D71C, char = '𝜜', class = 'ord', cs = 'mbfitAlpha', alphabet = 'boldgreek' } -- mathematical bold italic capital alpha
+ , { code = 0x1D71D, char = '𝜝', class = 'ord', cs = 'mbfitBeta', alphabet = 'boldgreek' } -- mathematical bold italic capital beta
+ , { code = 0x1D71E, char = '𝜞', class = 'ord', cs = 'mbfitGamma', alphabet = 'boldgreek' } -- mathematical bold italic capital gamma
+ , { code = 0x1D71F, char = '𝜟', class = 'ord', cs = 'mbfitDelta', alphabet = 'boldgreek' } -- mathematical bold italic capital delta
+ , { code = 0x1D720, char = '𝜠', class = 'ord', cs = 'mbfitEpsilon', alphabet = 'boldgreek'} -- mathematical bold italic capital epsilon
+ , { code = 0x1D721, char = '𝜡', class = 'ord', cs = 'mbfitZeta', alphabet = 'boldgreek' } -- mathematical bold italic capital zeta
+ , { code = 0x1D722, char = '𝜢', class = 'ord', cs = 'mbfitEta', alphabet = 'boldgreek' } -- mathematical bold italic capital eta
+ , { code = 0x1D723, char = '𝜣', class = 'ord', cs = 'mbfitTheta', alphabet = 'boldgreek' } -- mathematical bold italic capital theta
+ , { code = 0x1D724, char = '𝜤', class = 'ord', cs = 'mbfitIota', alphabet = 'boldgreek' } -- mathematical bold italic capital iota
+ , { code = 0x1D725, char = '𝜥', class = 'ord', cs = 'mbfitKappa', alphabet = 'boldgreek' } -- mathematical bold italic capital kappa
+ , { code = 0x1D726, char = '𝜦', class = 'ord', cs = 'mbfitLambda', alphabet = 'boldgreek'} -- mathematical bold italic capital lamda
+ , { code = 0x1D727, char = '𝜧', class = 'ord', cs = 'mbfitMu', alphabet = 'boldgreek' } -- mathematical bold italic capital mu
+ , { code = 0x1D728, char = '𝜨', class = 'ord', cs = 'mbfitNu', alphabet = 'boldgreek' } -- mathematical bold italic capital nu
+ , { code = 0x1D729, char = '𝜩', class = 'ord', cs = 'mbfitXi', alphabet = 'boldgreek' } -- mathematical bold italic capital xi
+ , { code = 0x1D72A, char = '𝜪', class = 'ord', cs = 'mbfitOmicron', alphabet = 'boldgreek'} -- mathematical bold italic capital omicron
+ , { code = 0x1D72B, char = '𝜫', class = 'ord', cs = 'mbfitPi', alphabet = 'boldgreek' } -- mathematical bold italic capital pi
+ , { code = 0x1D72C, char = '𝜬', class = 'ord', cs = 'mbfitRho', alphabet = 'boldgreek' } -- mathematical bold italic capital rho
+ , { code = 0x1D72D, char = '𝜭', class = 'ord', cs = 'mbfitvarTheta', alphabet = 'boldgreek'} -- mathematical bold italic capital theta symbol
+ , { code = 0x1D72E, char = '𝜮', class = 'ord', cs = 'mbfitSigma', alphabet = 'boldgreek' } -- mathematical bold italic capital sigma
+ , { code = 0x1D72F, char = '𝜯', class = 'ord', cs = 'mbfitTau', alphabet = 'boldgreek' } -- mathematical bold italic capital tau
+ , { code = 0x1D730, char = '𝜰', class = 'ord', cs = 'mbfitUpsilon', alphabet = 'boldgreek'} -- mathematical bold italic capital upsilon
+ , { code = 0x1D731, char = '𝜱', class = 'ord', cs = 'mbfitPhi', alphabet = 'boldgreek' } -- mathematical bold italic capital phi
+ , { code = 0x1D732, char = '𝜲', class = 'ord', cs = 'mbfitChi', alphabet = 'boldgreek' } -- mathematical bold italic capital chi
+ , { code = 0x1D733, char = '𝜳', class = 'ord', cs = 'mbfitPsi', alphabet = 'boldgreek' } -- mathematical bold italic capital psi
+ , { code = 0x1D734, char = '𝜴', class = 'ord', cs = 'mbfitOmega', alphabet = 'boldgreek' } -- mathematical bold italic capital omega
+ , { code = 0x1D735, char = '𝜵', class = 'ord', cs = 'mbfitnabla' } -- mathematical bold italic nabla
+ , { code = 0x1D736, char = '𝜶', class = 'ord', cs = 'mbfitalpha', alphabet = 'boldgreek' } -- mathematical bold italic small alpha
+ , { code = 0x1D737, char = '𝜷', class = 'ord', cs = 'mbfitbeta', alphabet = 'boldgreek' } -- mathematical bold italic small beta
+ , { code = 0x1D738, char = '𝜸', class = 'ord', cs = 'mbfitgamma', alphabet = 'boldgreek' } -- mathematical bold italic small gamma
+ , { code = 0x1D739, char = '𝜹', class = 'ord', cs = 'mbfitdelta', alphabet = 'boldgreek' } -- mathematical bold italic small delta
+ , { code = 0x1D73A, char = '𝜺', class = 'ord', cs = 'mbfitepsilon', alphabet = 'boldgreek'} -- mathematical bold italic small epsilon
+ , { code = 0x1D73B, char = '𝜻', class = 'ord', cs = 'mbfitzeta', alphabet = 'boldgreek' } -- mathematical bold italic small zeta
+ , { code = 0x1D73C, char = '𝜼', class = 'ord', cs = 'mbfiteta', alphabet = 'boldgreek' } -- mathematical bold italic small eta
+ , { code = 0x1D73D, char = '𝜽', class = 'ord', cs = 'mbfittheta', alphabet = 'boldgreek' } -- mathematical bold italic small theta
+ , { code = 0x1D73E, char = '𝜾', class = 'ord', cs = 'mbfitiota', alphabet = 'boldgreek' } -- mathematical bold italic small iota
+ , { code = 0x1D73F, char = '𝜿', class = 'ord', cs = 'mbfitkappa', alphabet = 'boldgreek' } -- mathematical bold italic small kappa
+ , { code = 0x1D740, char = '𝝀', class = 'ord', cs = 'mbfitlambda', alphabet = 'boldgreek'} -- mathematical bold italic small lamda
+ , { code = 0x1D741, char = '𝝁', class = 'ord', cs = 'mbfitmu', alphabet = 'boldgreek' } -- mathematical bold italic small mu
+ , { code = 0x1D742, char = '𝝂', class = 'ord', cs = 'mbfitnu', alphabet = 'boldgreek' } -- mathematical bold italic small nu
+ , { code = 0x1D743, char = '𝝃', class = 'ord', cs = 'mbfitxi', alphabet = 'boldgreek' } -- mathematical bold italic small xi
+ , { code = 0x1D744, char = '𝝄', class = 'ord', cs = 'mbfitomicron', alphabet = 'boldgreek'} -- mathematical bold italic small omicron
+ , { code = 0x1D745, char = '𝝅', class = 'ord', cs = 'mbfitpi', alphabet = 'boldgreek' } -- mathematical bold italic small pi
+ , { code = 0x1D746, char = '𝝆', class = 'ord', cs = 'mbfitrho', alphabet = 'boldgreek' } -- mathematical bold italic small rho
+ , { code = 0x1D747, char = '𝝇', class = 'ord', cs = 'mbfitvarsigma', alphabet = 'boldgreek'} -- mathematical bold italic small final sigma
+ , { code = 0x1D748, char = '𝝈', class = 'ord', cs = 'mbfitsigma', alphabet = 'boldgreek' } -- mathematical bold italic small sigma
+ , { code = 0x1D749, char = '𝝉', class = 'ord', cs = 'mbfittau', alphabet = 'boldgreek' } -- mathematical bold italic small tau
+ , { code = 0x1D74A, char = '𝝊', class = 'ord', cs = 'mbfitupsilon', alphabet = 'boldgreek'} -- mathematical bold italic small upsilon
+ , { code = 0x1D74B, char = '𝝋', class = 'ord', cs = 'mbfitphi', alphabet = 'boldgreek' } -- mathematical bold italic small phi
+ , { code = 0x1D74C, char = '𝝌', class = 'ord', cs = 'mbfitchi', alphabet = 'boldgreek' } -- mathematical bold italic small chi
+ , { code = 0x1D74D, char = '𝝍', class = 'ord', cs = 'mbfitpsi', alphabet = 'boldgreek' } -- mathematical bold italic small psi
+ , { code = 0x1D74E, char = '𝝎', class = 'ord', cs = 'mbfitomega', alphabet = 'boldgreek' } -- mathematical bold italic small omega
+ , { code = 0x1D74F, char = '𝝏', class = 'ord', cs = 'mbfitpartial' } -- mathematical bold italic partial differential
+ , { code = 0x1D750, char = '𝝐', class = 'ord', cs = 'mbfitvarepsilon', alphabet = 'boldgreek'} -- mathematical bold italic epsilon symbol
+ , { code = 0x1D751, char = '𝝑', class = 'ord', cs = 'mbfitvartheta', alphabet = 'boldgreek'} -- mathematical bold italic theta symbol
+ , { code = 0x1D752, char = '𝝒', class = 'ord', cs = 'mbfitvarkappa', alphabet = 'boldgreek'} -- mathematical bold italic kappa symbol
+ , { code = 0x1D753, char = '𝝓', class = 'ord', cs = 'mbfitvarphi', alphabet = 'boldgreek'} -- mathematical bold italic phi symbol
+ , { code = 0x1D754, char = '𝝔', class = 'ord', cs = 'mbfitvarrho', alphabet = 'boldgreek'} -- mathematical bold italic rho symbol
+ , { code = 0x1D755, char = '𝝕', class = 'ord', cs = 'mbfitvarpi', alphabet = 'boldgreek' } -- mathematical bold italic pi symbol
+ , { code = 0x1D756, char = '𝝖', class = 'ord', cs = 'mbfsansAlpha', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital alpha
+ , { code = 0x1D757, char = '𝝗', class = 'ord', cs = 'mbfsansBeta', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital beta
+ , { code = 0x1D758, char = '𝝘', class = 'ord', cs = 'mbfsansGamma', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital gamma
+ , { code = 0x1D759, char = '𝝙', class = 'ord', cs = 'mbfsansDelta', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital delta
+ , { code = 0x1D75A, char = '𝝚', class = 'ord', cs = 'mbfsansEpsilon', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital epsilon
+ , { code = 0x1D75B, char = '𝝛', class = 'ord', cs = 'mbfsansZeta', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital zeta
+ , { code = 0x1D75C, char = '𝝜', class = 'ord', cs = 'mbfsansEta', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital eta
+ , { code = 0x1D75D, char = '𝝝', class = 'ord', cs = 'mbfsansTheta', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital theta
+ , { code = 0x1D75E, char = '𝝞', class = 'ord', cs = 'mbfsansIota', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital iota
+ , { code = 0x1D75F, char = '𝝟', class = 'ord', cs = 'mbfsansKappa', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital kappa
+ , { code = 0x1D760, char = '𝝠', class = 'ord', cs = 'mbfsansLambda', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital lamda
+ , { code = 0x1D761, char = '𝝡', class = 'ord', cs = 'mbfsansMu', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital mu
+ , { code = 0x1D762, char = '𝝢', class = 'ord', cs = 'mbfsansNu', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital nu
+ , { code = 0x1D763, char = '𝝣', class = 'ord', cs = 'mbfsansXi', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital xi
+ , { code = 0x1D764, char = '𝝤', class = 'ord', cs = 'mbfsansOmicron', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital omicron
+ , { code = 0x1D765, char = '𝝥', class = 'ord', cs = 'mbfsansPi', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital pi
+ , { code = 0x1D766, char = '𝝦', class = 'ord', cs = 'mbfsansRho', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital rho
+ , { code = 0x1D767, char = '𝝧', class = 'ord', cs = 'mbfsansvarTheta', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital theta symbol
+ , { code = 0x1D768, char = '𝝨', class = 'ord', cs = 'mbfsansSigma', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital sigma
+ , { code = 0x1D769, char = '𝝩', class = 'ord', cs = 'mbfsansTau', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital tau
+ , { code = 0x1D76A, char = '𝝪', class = 'ord', cs = 'mbfsansUpsilon', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital upsilon
+ , { code = 0x1D76B, char = '𝝫', class = 'ord', cs = 'mbfsansPhi', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital phi
+ , { code = 0x1D76C, char = '𝝬', class = 'ord', cs = 'mbfsansChi', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital chi
+ , { code = 0x1D76D, char = '𝝭', class = 'ord', cs = 'mbfsansPsi', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital psi
+ , { code = 0x1D76E, char = '𝝮', class = 'ord', cs = 'mbfsansOmega', alphabet = 'sansgreek' } -- mathematical sans-serif bold capital omega
+ , { code = 0x1D76F, char = '𝝯', class = 'ord', cs = 'mbfsansnabla' } -- mathematical sans-serif bold nabla
+ , { code = 0x1D770, char = '𝝰', class = 'ord', cs = 'mbfsansalpha', alphabet = 'sansgreek' } -- mathematical sans-serif bold small alpha
+ , { code = 0x1D771, char = '𝝱', class = 'ord', cs = 'mbfsansbeta', alphabet = 'sansgreek' } -- mathematical sans-serif bold small beta
+ , { code = 0x1D772, char = '𝝲', class = 'ord', cs = 'mbfsansgamma', alphabet = 'sansgreek' } -- mathematical sans-serif bold small gamma
+ , { code = 0x1D773, char = '𝝳', class = 'ord', cs = 'mbfsansdelta', alphabet = 'sansgreek' } -- mathematical sans-serif bold small delta
+ , { code = 0x1D774, char = '𝝴', class = 'ord', cs = 'mbfsansepsilon', alphabet = 'sansgreek' } -- mathematical sans-serif bold small epsilon
+ , { code = 0x1D775, char = '𝝵', class = 'ord', cs = 'mbfsanszeta', alphabet = 'sansgreek' } -- mathematical sans-serif bold small zeta
+ , { code = 0x1D776, char = '𝝶', class = 'ord', cs = 'mbfsanseta', alphabet = 'sansgreek' } -- mathematical sans-serif bold small eta
+ , { code = 0x1D777, char = '𝝷', class = 'ord', cs = 'mbfsanstheta', alphabet = 'sansgreek' } -- mathematical sans-serif bold small theta
+ , { code = 0x1D778, char = '𝝸', class = 'ord', cs = 'mbfsansiota', alphabet = 'sansgreek' } -- mathematical sans-serif bold small iota
+ , { code = 0x1D779, char = '𝝹', class = 'ord', cs = 'mbfsanskappa', alphabet = 'sansgreek' } -- mathematical sans-serif bold small kappa
+ , { code = 0x1D77A, char = '𝝺', class = 'ord', cs = 'mbfsanslambda', alphabet = 'sansgreek' } -- mathematical sans-serif bold small lamda
+ , { code = 0x1D77B, char = '𝝻', class = 'ord', cs = 'mbfsansmu', alphabet = 'sansgreek' } -- mathematical sans-serif bold small mu
+ , { code = 0x1D77C, char = '𝝼', class = 'ord', cs = 'mbfsansnu', alphabet = 'sansgreek' } -- mathematical sans-serif bold small nu
+ , { code = 0x1D77D, char = '𝝽', class = 'ord', cs = 'mbfsansxi', alphabet = 'sansgreek' } -- mathematical sans-serif bold small xi
+ , { code = 0x1D77E, char = '𝝾', class = 'ord', cs = 'mbfsansomicron', alphabet = 'sansgreek' } -- mathematical sans-serif bold small omicron
+ , { code = 0x1D77F, char = '𝝿', class = 'ord', cs = 'mbfsanspi', alphabet = 'sansgreek' } -- mathematical sans-serif bold small pi
+ , { code = 0x1D780, char = '𝞀', class = 'ord', cs = 'mbfsansrho', alphabet = 'sansgreek' } -- mathematical sans-serif bold small rho
+ , { code = 0x1D781, char = '𝞁', class = 'ord', cs = 'mbfsansvarsigma', alphabet = 'sansgreek' } -- mathematical sans-serif bold small final sigma
+ , { code = 0x1D782, char = '𝞂', class = 'ord', cs = 'mbfsanssigma', alphabet = 'sansgreek' } -- mathematical sans-serif bold small sigma
+ , { code = 0x1D783, char = '𝞃', class = 'ord', cs = 'mbfsanstau', alphabet = 'sansgreek' } -- mathematical sans-serif bold small tau
+ , { code = 0x1D784, char = '𝞄', class = 'ord', cs = 'mbfsansupsilon', alphabet = 'sansgreek' } -- mathematical sans-serif bold small upsilon
+ , { code = 0x1D785, char = '𝞅', class = 'ord', cs = 'mbfsansphi', alphabet = 'sansgreek' } -- mathematical sans-serif bold small phi
+ , { code = 0x1D786, char = '𝞆', class = 'ord', cs = 'mbfsanschi', alphabet = 'sansgreek' } -- mathematical sans-serif bold small chi
+ , { code = 0x1D787, char = '𝞇', class = 'ord', cs = 'mbfsanspsi', alphabet = 'sansgreek' } -- mathematical sans-serif bold small psi
+ , { code = 0x1D788, char = '𝞈', class = 'ord', cs = 'mbfsansomega', alphabet = 'sansgreek' } -- mathematical sans-serif bold small omega
+ , { code = 0x1D789, char = '𝞉', class = 'ord', cs = 'mbfsanspartial' } -- mathematical sans-serif bold partial differential
+ , { code = 0x1D78A, char = '𝞊', class = 'ord', cs = 'mbfsansvarepsilon', alphabet = 'sansgreek'} -- mathematical sans-serif bold epsilon symbol
+ , { code = 0x1D78B, char = '𝞋', class = 'ord', cs = 'mbfsansvartheta', alphabet = 'sansgreek' } -- mathematical sans-serif bold theta symbol
+ , { code = 0x1D78C, char = '𝞌', class = 'ord', cs = 'mbfsansvarkappa', alphabet = 'sansgreek' } -- mathematical sans-serif bold kappa symbol
+ , { code = 0x1D78D, char = '𝞍', class = 'ord', cs = 'mbfsansvarphi', alphabet = 'sansgreek' } -- mathematical sans-serif bold phi symbol
+ , { code = 0x1D78E, char = '𝞎', class = 'ord', cs = 'mbfsansvarrho', alphabet = 'sansgreek' } -- mathematical sans-serif bold rho symbol
+ , { code = 0x1D78F, char = '𝞏', class = 'ord', cs = 'mbfsansvarpi', alphabet = 'sansgreek' } -- mathematical sans-serif bold pi symbol
+ , { code = 0x1D790, char = '𝞐', class = 'ord', cs = 'mbfitsansAlpha', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital alpha
+ , { code = 0x1D791, char = '𝞑', class = 'ord', cs = 'mbfitsansBeta', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital beta
+ , { code = 0x1D792, char = '𝞒', class = 'ord', cs = 'mbfitsansGamma', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital gamma
+ , { code = 0x1D793, char = '𝞓', class = 'ord', cs = 'mbfitsansDelta', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital delta
+ , { code = 0x1D794, char = '𝞔', class = 'ord', cs = 'mbfitsansEpsilon', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital epsilon
+ , { code = 0x1D795, char = '𝞕', class = 'ord', cs = 'mbfitsansZeta', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital zeta
+ , { code = 0x1D796, char = '𝞖', class = 'ord', cs = 'mbfitsansEta', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital eta
+ , { code = 0x1D797, char = '𝞗', class = 'ord', cs = 'mbfitsansTheta', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital theta
+ , { code = 0x1D798, char = '𝞘', class = 'ord', cs = 'mbfitsansIota', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital iota
+ , { code = 0x1D799, char = '𝞙', class = 'ord', cs = 'mbfitsansKappa', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital kappa
+ , { code = 0x1D79A, char = '𝞚', class = 'ord', cs = 'mbfitsansLambda', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital lamda
+ , { code = 0x1D79B, char = '𝞛', class = 'ord', cs = 'mbfitsansMu', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital mu
+ , { code = 0x1D79C, char = '𝞜', class = 'ord', cs = 'mbfitsansNu', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital nu
+ , { code = 0x1D79D, char = '𝞝', class = 'ord', cs = 'mbfitsansXi', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital xi
+ , { code = 0x1D79E, char = '𝞞', class = 'ord', cs = 'mbfitsansOmicron', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital omicron
+ , { code = 0x1D79F, char = '𝞟', class = 'ord', cs = 'mbfitsansPi', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital pi
+ , { code = 0x1D7A0, char = '𝞠', class = 'ord', cs = 'mbfitsansRho', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital rho
+ , { code = 0x1D7A1, char = '𝞡', class = 'ord', cs = 'mbfitsansvarTheta', alphabet = 'sansgreek'} -- mathematical sans-serif bold italic capital theta symbol
+ , { code = 0x1D7A2, char = '𝞢', class = 'ord', cs = 'mbfitsansSigma', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital sigma
+ , { code = 0x1D7A3, char = '𝞣', class = 'ord', cs = 'mbfitsansTau', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital tau
+ , { code = 0x1D7A4, char = '𝞤', class = 'ord', cs = 'mbfitsansUpsilon', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital upsilon
+ , { code = 0x1D7A5, char = '𝞥', class = 'ord', cs = 'mbfitsansPhi', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital phi
+ , { code = 0x1D7A6, char = '𝞦', class = 'ord', cs = 'mbfitsansChi', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital chi
+ , { code = 0x1D7A7, char = '𝞧', class = 'ord', cs = 'mbfitsansPsi', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital psi
+ , { code = 0x1D7A8, char = '𝞨', class = 'ord', cs = 'mbfitsansOmega', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic capital omega
+ , { code = 0x1D7A9, char = '𝞩', class = 'ord', cs = 'mbfitsansnabla' } -- mathematical sans-serif bold italic nabla
+ , { code = 0x1D7AA, char = '𝞪', class = 'ord', cs = 'mbfitsansalpha', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small alpha
+ , { code = 0x1D7AB, char = '𝞫', class = 'ord', cs = 'mbfitsansbeta', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small beta
+ , { code = 0x1D7AC, char = '𝞬', class = 'ord', cs = 'mbfitsansgamma', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small gamma
+ , { code = 0x1D7AD, char = '𝞭', class = 'ord', cs = 'mbfitsansdelta', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small delta
+ , { code = 0x1D7AE, char = '𝞮', class = 'ord', cs = 'mbfitsansepsilon', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small epsilon
+ , { code = 0x1D7AF, char = '𝞯', class = 'ord', cs = 'mbfitsanszeta', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small zeta
+ , { code = 0x1D7B0, char = '𝞰', class = 'ord', cs = 'mbfitsanseta', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small eta
+ , { code = 0x1D7B1, char = '𝞱', class = 'ord', cs = 'mbfitsanstheta', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small theta
+ , { code = 0x1D7B2, char = '𝞲', class = 'ord', cs = 'mbfitsansiota', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small iota
+ , { code = 0x1D7B3, char = '𝞳', class = 'ord', cs = 'mbfitsanskappa', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small kappa
+ , { code = 0x1D7B4, char = '𝞴', class = 'ord', cs = 'mbfitsanslambda', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small lamda
+ , { code = 0x1D7B5, char = '𝞵', class = 'ord', cs = 'mbfitsansmu', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small mu
+ , { code = 0x1D7B6, char = '𝞶', class = 'ord', cs = 'mbfitsansnu', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small nu
+ , { code = 0x1D7B7, char = '𝞷', class = 'ord', cs = 'mbfitsansxi', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small xi
+ , { code = 0x1D7B8, char = '𝞸', class = 'ord', cs = 'mbfitsansomicron', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small omicron
+ , { code = 0x1D7B9, char = '𝞹', class = 'ord', cs = 'mbfitsanspi', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small pi
+ , { code = 0x1D7BA, char = '𝞺', class = 'ord', cs = 'mbfitsansrho', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small rho
+ , { code = 0x1D7BB, char = '𝞻', class = 'ord', cs = 'mbfitsansvarsigma', alphabet = 'sansgreek'} -- mathematical sans-serif bold italic small final sigma
+ , { code = 0x1D7BC, char = '𝞼', class = 'ord', cs = 'mbfitsanssigma', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small sigma
+ , { code = 0x1D7BD, char = '𝞽', class = 'ord', cs = 'mbfitsanstau', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small tau
+ , { code = 0x1D7BE, char = '𝞾', class = 'ord', cs = 'mbfitsansupsilon', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small upsilon
+ , { code = 0x1D7BF, char = '𝞿', class = 'ord', cs = 'mbfitsansphi', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small phi
+ , { code = 0x1D7C0, char = '𝟀', class = 'ord', cs = 'mbfitsanschi', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small chi
+ , { code = 0x1D7C1, char = '𝟁', class = 'ord', cs = 'mbfitsanspsi', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small psi
+ , { code = 0x1D7C2, char = '𝟂', class = 'ord', cs = 'mbfitsansomega', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic small omega
+ , { code = 0x1D7C3, char = '𝟃', class = 'ord', cs = 'mbfitsanspartial' } -- mathematical sans-serif bold italic partial differential
+ , { code = 0x1D7C4, char = '𝟄', class = 'ord', cs = 'mbfitsansvarepsilon', alphabet = 'sansgreek'} -- mathematical sans-serif bold italic epsilon symbol
+ , { code = 0x1D7C5, char = '𝟅', class = 'ord', cs = 'mbfitsansvartheta', alphabet = 'sansgreek'} -- mathematical sans-serif bold italic theta symbol
+ , { code = 0x1D7C6, char = '𝟆', class = 'ord', cs = 'mbfitsansvarkappa', alphabet = 'sansgreek'} -- mathematical sans-serif bold italic kappa symbol
+ , { code = 0x1D7C7, char = '𝟇', class = 'ord', cs = 'mbfitsansvarphi', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic phi symbol
+ , { code = 0x1D7C8, char = '𝟈', class = 'ord', cs = 'mbfitsansvarrho', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic rho symbol
+ , { code = 0x1D7C9, char = '𝟉', class = 'ord', cs = 'mbfitsansvarpi', alphabet = 'sansgreek' } -- mathematical sans-serif bold italic pi symbol
+ , { code = 0x1D7CA, char = '𝟊', class = 'ord', cs = 'mbfDigamma', alphabet = 'boldgreek'} -- mathematical bold capital digamma
+ , { code = 0x1D7CB, char = '𝟋', class = 'ord', cs = 'mbfdigamma', alphabet = 'boldgreek'} -- mathematical bold small digamma
+ , { code = 0x1D7CE, char = '𝟎', class = 'ord', cs = 'mbfzero', alphabet = 'bold' } -- mathematical bold digit zero
+ , { code = 0x1D7CF, char = '𝟏', class = 'ord', cs = 'mbfone', alphabet = 'bold' } -- mathematical bold digit one
+ , { code = 0x1D7D0, char = '𝟐', class = 'ord', cs = 'mbftwo', alphabet = 'bold' } -- mathematical bold digit two
+ , { code = 0x1D7D1, char = '𝟑', class = 'ord', cs = 'mbfthree', alphabet = 'bold' } -- mathematical bold digit three
+ , { code = 0x1D7D2, char = '𝟒', class = 'ord', cs = 'mbffour', alphabet = 'bold' } -- mathematical bold digit four
+ , { code = 0x1D7D3, char = '𝟓', class = 'ord', cs = 'mbffive', alphabet = 'bold' } -- mathematical bold digit five
+ , { code = 0x1D7D4, char = '𝟔', class = 'ord', cs = 'mbfsix', alphabet = 'bold' } -- mathematical bold digit six
+ , { code = 0x1D7D5, char = '𝟕', class = 'ord', cs = 'mbfseven', alphabet = 'bold' } -- mathematical bold digit seven
+ , { code = 0x1D7D6, char = '𝟖', class = 'ord', cs = 'mbfeight', alphabet = 'bold' } -- mathematical bold digit eight
+ , { code = 0x1D7D7, char = '𝟗', class = 'ord', cs = 'mbfnine', alphabet = 'bold' } -- mathematical bold digit nine
+ , { code = 0x1D7D8, char = '𝟘', class = 'ord', cs = 'Bbbzero', alphabet = 'blackboard' } -- mathematical double-struck digit zero
+ , { code = 0x1D7D9, char = '𝟙', class = 'ord', cs = 'Bbbone', alphabet = 'blackboard' } -- mathematical double-struck digit one
+ , { code = 0x1D7DA, char = '𝟚', class = 'ord', cs = 'Bbbtwo', alphabet = 'blackboard' } -- mathematical double-struck digit two
+ , { code = 0x1D7DB, char = '𝟛', class = 'ord', cs = 'Bbbthree', alphabet = 'blackboard' } -- mathematical double-struck digit three
+ , { code = 0x1D7DC, char = '𝟜', class = 'ord', cs = 'Bbbfour', alphabet = 'blackboard' } -- mathematical double-struck digit four
+ , { code = 0x1D7DD, char = '𝟝', class = 'ord', cs = 'Bbbfive', alphabet = 'blackboard' } -- mathematical double-struck digit five
+ , { code = 0x1D7DE, char = '𝟞', class = 'ord', cs = 'Bbbsix', alphabet = 'blackboard' } -- mathematical double-struck digit six
+ , { code = 0x1D7DF, char = '𝟟', class = 'ord', cs = 'Bbbseven', alphabet = 'blackboard' } -- mathematical double-struck digit seven
+ , { code = 0x1D7E0, char = '𝟠', class = 'ord', cs = 'Bbbeight', alphabet = 'blackboard' } -- mathematical double-struck digit eight
+ , { code = 0x1D7E1, char = '𝟡', class = 'ord', cs = 'Bbbnine', alphabet = 'blackboard' } -- mathematical double-struck digit nine
+ , { code = 0x1D7E2, char = '𝟢', class = 'ord', cs = 'msanszero', alphabet = 'sans' } -- mathematical sans-serif digit zero
+ , { code = 0x1D7E3, char = '𝟣', class = 'ord', cs = 'msansone', alphabet = 'sans' } -- mathematical sans-serif digit one
+ , { code = 0x1D7E4, char = '𝟤', class = 'ord', cs = 'msanstwo', alphabet = 'sans' } -- mathematical sans-serif digit two
+ , { code = 0x1D7E5, char = '𝟥', class = 'ord', cs = 'msansthree', alphabet = 'sans' } -- mathematical sans-serif digit three
+ , { code = 0x1D7E6, char = '𝟦', class = 'ord', cs = 'msansfour', alphabet = 'sans' } -- mathematical sans-serif digit four
+ , { code = 0x1D7E7, char = '𝟧', class = 'ord', cs = 'msansfive', alphabet = 'sans' } -- mathematical sans-serif digit five
+ , { code = 0x1D7E8, char = '𝟨', class = 'ord', cs = 'msanssix', alphabet = 'sans' } -- mathematical sans-serif digit six
+ , { code = 0x1D7E9, char = '𝟩', class = 'ord', cs = 'msansseven', alphabet = 'sans' } -- mathematical sans-serif digit seven
+ , { code = 0x1D7EA, char = '𝟪', class = 'ord', cs = 'msanseight', alphabet = 'sans' } -- mathematical sans-serif digit eight
+ , { code = 0x1D7EB, char = '𝟫', class = 'ord', cs = 'msansnine', alphabet = 'sans' } -- mathematical sans-serif digit nine
+ , { code = 0x1D7EC, char = '𝟬', class = 'ord', cs = 'mbfsanszero', alphabet = 'sans' } -- mathematical sans-serif bold digit zero
+ , { code = 0x1D7ED, char = '𝟭', class = 'ord', cs = 'mbfsansone', alphabet = 'sans' } -- mathematical sans-serif bold digit one
+ , { code = 0x1D7EE, char = '𝟮', class = 'ord', cs = 'mbfsanstwo', alphabet = 'sans' } -- mathematical sans-serif bold digit two
+ , { code = 0x1D7EF, char = '𝟯', class = 'ord', cs = 'mbfsansthree', alphabet = 'sans' } -- mathematical sans-serif bold digit three
+ , { code = 0x1D7F0, char = '𝟰', class = 'ord', cs = 'mbfsansfour', alphabet = 'sans' } -- mathematical sans-serif bold digit four
+ , { code = 0x1D7F1, char = '𝟱', class = 'ord', cs = 'mbfsansfive', alphabet = 'sans' } -- mathematical sans-serif bold digit five
+ , { code = 0x1D7F2, char = '𝟲', class = 'ord', cs = 'mbfsanssix', alphabet = 'sans' } -- mathematical sans-serif bold digit six
+ , { code = 0x1D7F3, char = '𝟳', class = 'ord', cs = 'mbfsansseven', alphabet = 'sans' } -- mathematical sans-serif bold digit seven
+ , { code = 0x1D7F4, char = '𝟴', class = 'ord', cs = 'mbfsanseight', alphabet = 'sans' } -- mathematical sans-serif bold digit eight
+ , { code = 0x1D7F5, char = '𝟵', class = 'ord', cs = 'mbfsansnine', alphabet = 'sans' } -- mathematical sans-serif bold digit nine
+ , { code = 0x1D7F6, char = '𝟶', class = 'ord', cs = 'mttzero', alphabet = 'mono' } -- mathematical monospace digit zero
+ , { code = 0x1D7F7, char = '𝟷', class = 'ord', cs = 'mttone', alphabet = 'mono' } -- mathematical monospace digit one
+ , { code = 0x1D7F8, char = '𝟸', class = 'ord', cs = 'mtttwo', alphabet = 'mono' } -- mathematical monospace digit two
+ , { code = 0x1D7F9, char = '𝟹', class = 'ord', cs = 'mttthree', alphabet = 'mono' } -- mathematical monospace digit three
+ , { code = 0x1D7FA, char = '𝟺', class = 'ord', cs = 'mttfour', alphabet = 'mono' } -- mathematical monospace digit four
+ , { code = 0x1D7FB, char = '𝟻', class = 'ord', cs = 'mttfive', alphabet = 'mono' } -- mathematical monospace digit five
+ , { code = 0x1D7FC, char = '𝟼', class = 'ord', cs = 'mttsix', alphabet = 'mono' } -- mathematical monospace digit six
+ , { code = 0x1D7FD, char = '𝟽', class = 'ord', cs = 'mttseven', alphabet = 'mono' } -- mathematical monospace digit seven
+ , { code = 0x1D7FE, char = '𝟾', class = 'ord', cs = 'mtteight', alphabet = 'mono' } -- mathematical monospace digit eight
+ , { code = 0x1D7FF, char = '𝟿', class = 'ord', cs = 'mttnine', alphabet = 'mono' } -- mathematical monospace digit nine
+}
diff --git a/macros/luatex/generic/minim-math/minim-math.doc b/macros/luatex/generic/minim-math/minim-math.doc
new file mode 100644
index 0000000000..a176c9b1d0
--- /dev/null
+++ b/macros/luatex/generic/minim-math/minim-math.doc
@@ -0,0 +1,244 @@
+
+\input minim-doc.sty
+
+\manual{minim-math}
+
+\ifchapter \chapter Mathematics
+
+\else \startmetadata
+ author {Esger Renkema}
+ title {minim-math}
+ date {2021-06-01}
+ version {2021/1.0}
+ keywords {LuaTeX; Plain TeX; Unicode mathematics}
+ stopmetadata
+\maketitle \fi
+
+This package gives a simple and higly-configurable way of using unicode and
+OpenType mathematics with plain LuaTeX, making use of most of the latter
+engine’s new capabilities in mathematical typesetting. Also included are proper
+settings and definitions for nearly all unicode mathematical characters, as
+well as a few shorthands and helper macros that seemed useful additions.
+
+Load the package by saying ⟦\input minim-math.tex⟧; this will set up luatex for
+using opentype mathematical fonts and unicode math input.
+It will not, however, select mathematical fonts for you. That you will have to
+do for yourself; see below for instructions.
+
+
+\section Styles and alphabets
+
+For some (mostly alphabetical) characters, multiple variants are available,
+e.g. $\mit A \mup A \mbf A \mbfit A \mbb A \frak A \bffrak A \scr A \bfscr A$.
+You can (locally) override the default style of these with
+⟦*\mathstyle {style}⟧ (equivalent to the old ⟦\bf⟧, ⟦\rm⟧ etc.)
+or with one of the shorthands that apply the style to their argument only:
+\smallskip\smallskip\automarktable \halign{\qquad
+ #\unskip\quad\hfil &#\unskip\quad\hfil &#\unskip\hfil\cr
+Shorthand\quad\strut & Value of ⟦style⟧\quad\strut & Result \cr
+⟦*\mup⟧ & ⟦up⟧/⟦rm⟧ & $\mup {ABC}$ \cr
+⟦*\mit⟧ & ⟦it⟧ & $\mit {ABC}$ \cr
+⟦*\mbf⟧ & ⟦bf⟧ & $\mbf {ABC}$ \cr
+⟦*\mbfit⟧ & ⟦bfit⟧ & $\mbfit {ABC}$ \cr
+⟦*\mbb⟧ & ⟦bb⟧ & $\mbb {ABC}$ \cr
+⟦*\frak⟧ & ⟦frak⟧ & $\frak {ABC}$ \cr
+⟦*\bffrak⟧ & ⟦bffrak⟧ & $\bffrak {ABC}$ \cr
+⟦*\scr⟧ & ⟦cal⟧/⟦scr⟧ & $\scr {ABC}$ \cr
+⟦*\bfscr⟧ & ⟦bfscr⟧ & $\bfscr {ABC}$ \cr
+}
+Styles without shorthand are ⟦sans⟧/⟦sf⟧, ⟦sfit⟧, ⟦sfbf⟧, ⟦sfbfit⟧, ⟦tt⟧/⟦mono⟧
+and finally the special value ⟦*clear⟧ for using the default style.
+You can use the shorthands directly in sub- and superscripts: ⟦v^\scr F⟧ will
+result in $v^\scr F$.
+
+While math families are not used anymore for switching between styles (see
+below), you still can use ⟦\fam⟧ with the values 0, 1, 2, 4, 5, 6 or~7 for
+doing so. This means that plain tex’s ⟦\rm⟧, ⟦\it⟧, ⟦\cal⟧, ⟦\sl⟧, ⟦\bf⟧ and
+⟦\tt⟧ can still be used (at least in math mode).
+
+Please note that ⟦*\mup⟧ is not the right choice for upright multiletter
+symbols or operators: you should use ⟦*\mord⟧ or ⟦*\mop⟧ instead (see near the
+end of this chapter).
+For nonmathematical text, you should use ⟦*\text⟧ instead of ⟦\mup⟧.
+
+The default properties of characters can be set with one of the following three
+commands:
+\startlist
+\item\ignore. ⟦*\mathmap {character list} {style}⟧
+\item\ignore. ⟦*\mathclass {character list} {class}⟧
+\item\ignore. ⟦*\mathfam {character list} nr⟧
+\stoplist
+There, ⟦style⟧ is one of the above and ⟦class⟧ is the name of a class as below.
+Finally, the ⟦character list⟧ should be a comma-separated list with elements of
+one of the following forms:
+\startlist
+{\def\⟦#1{⟦[\uppercase{#1}#1]\kern-1pt}
+\item1. a list of characters, like ⟦abc⟧ or ⟦\partial⟧ or $ℝ$;
+\item2. a character range, like ⟦`A-`Z⟧, ⟦65-90⟧ or ⟦"41-"5A⟧;
+\item3. one of the alphabets \⟦latin⟧, \⟦greek⟧, or ⟦digits⟧;
+\item4. one of the style groups ⟦bold⟧, ⟦boldgreek⟧, ⟦sans⟧, ⟦sansgreek⟧,
+⟦mono⟧, ⟦blackboard⟧, ⟦fraktur⟧ or ⟦script⟧;
+\item5. the name of a math class:
+⟦ord⟧, ⟦op⟧, ⟦bin⟧, ⟦rel⟧, ⟦fence⟧, ⟦open⟧, ⟦close⟧ or ⟦punct⟧.
+}\stoplist
+
+Note that unicode is somewhat irregular in its encoding of mathematical
+letters; this is taken into account when using ranges as under~(2) above. Thus,
+⟦`\mscra-`\mscrz⟧ really gives you all lowercase script characters, despite
+e.g.~$ℯ$ being well outside that range.
+
+The default style settings are ⟦\mathmap {latin, greek, Latin}{it}⟧.
+Since the math family setting is not used anymore for selecting different
+styles, the default family of every symbol is zero.
+Instead, you can use ⟦\mathfam⟧ for mixing fonts (see below).
+The ⟦class⟧ option to ⟦\mathclass⟧ should be one of the names under~5.
+
+
+\section Character variants
+
+You can change the default appearance of several greek characters with
+⟦*\use∥-math∥-variant {chars}⟧ or ⟦*\usemathdefault {chars}⟧, where ⟦chars⟧ is
+a list of normal greek characters.
+As in unicode but against tex’s tradition, the variants are
+$\usemathvariant{εθΘκπρφ}εθΘκπρφ$ and the defaults $εθΘκπρφ$.
+The macros ⟦*\varepsilon⟧ etc. have been updated to reflect the unicode
+variants.
+
+The appearance of root symbols can be set with ⟦*\closedroots⟧ ($\closedroots
+\smash{√2}$) and ⟦*\normalroots⟧ ($\smash{√2}$, the default).
+
+Say ⟦*\unicodedots⟧ to use the unicode dots characters ($\unicodedots…⋮⋰⋱$) and
+⟦*\traditionaldots⟧ to construct these characters from periods ($\smash{…⋮⋰⋱}$,
+the default).
+Both settings affect the meaning of both the actual characters and the ⟦\xdots⟧
+macros ($\mathstyle{mono}x∈\{l,v,c,a,d\}$).
+Unlike in traditional plain tex, the traditional dots are available in script
+sizes, too.
+
+Say ⟦*\decimalcomma⟧ and have commas appear as $\decimalcomma1,2$ instead
+of~$1,2$ (⟦*\nodecimalcomma⟧ restores the default).
+The explicit ⟦*\comma⟧, like ⟦*\colon⟧, will always be punctuation.
+
+The behaviour of limits on integral signs can be set by redefining
+⟦*\intlimits⟧ (the default is ⟦\let \intlimits = \nolimits⟧).
+
+If you want to change the meaning (inside math mode) altogether for a single
+character, you can use the commands ⟦*\mathdef⟧ and ⟦*\mathlet⟧.
+For example, by default, you can use the letter ħ for the reduced planck
+constant~$ħ$;
+this has been made so with ⟦*\mathdef ħ {\hbar}⟧ (you could also have said
+⟦\mathlet ħ \hbar⟧).
+
+
+\section Setting up fonts
+
+The minimum you need do to set up a mathematical font is this:
+
+⟦*\font\tenmath
+ {Latin Modern Math:mode=base;script=math;ssty=0} at 10pt
+\font\tenmaths
+ {Latin Modern Math:mode=base;script=math;ssty=1} at 7pt
+\font\tenmathss
+ {Latin Modern Math:mode=base;script=math;ssty=2} at 5pt
+\textfont 0 = \tenmath
+\scriptfont 0 = \tenmaths
+\scriptscriptfont 0 = \tenmathss⟧
+
+Note that you only have to set up the font for a single family: opentype
+mathematical fonts typically contain all necessary variants of all mathematical
+characters.
+Therefore, the ⟦*\fam⟧ setting has been made a no-op (use ⟦*\setfam⟧ if you
+really need the old primitive) and the default family of all symbols has been
+set to zero.
+
+As mentioned above, you can still change the family number of specific
+characters and this allows you to mix mathematical fonts. For instance, if you
+dislike the current blackboard bold characters, just assign a second font to
+family
+1 and say ⟦\mathfam {blackboard} 1⟧. Less useful are the parameters
+⟦*\accentfam⟧, ⟦*\radicalfam⟧ and ⟦*\extensiblefam⟧ that control the family of
+all accents, radicals and extensibles.
+
+
+\section Shorthands and additions
+
+You can use ⟦*\text⟧ for adding nonmathematical text to your equations.
+It will behave well in sub- and superscripts:
+⟦\text{word}^\text{word}⟧ gives $\smash{\text{word}^\text{word}}$.
+By default, the font used is the normal mathematical font. You can change this
+by setting the ⟦*\textfam⟧ parameter to some nonzero value and assigning
+a different font to that family (see above).
+You probably want to do this, since most commonly-used mathematical fonts do not
+include a normal kerning table.
+
+All the usual arrows can be made extensible by prefacing them with an ⟦x⟧,
+including ⟦\xmapsto⟧ and ⟦\xmapsfrom⟧. Alternatively, you can use ⟦\→⟧ etc. as
+shorthands. Additionally, you can use the following:
+
+{\smallskip\smallskip\automarktable \halign{\qquad
+ \vrule width0pt depth 9pt#\unskip\hfil
+ &&\qquad#\unskip\hfil\cr
+Shorthand & Result \cr
+⟦\bra x, \ket y⟧ & $\bra x, \ket y$ \cr
+⟦\braket x y⟧ & $\braket x y$ \cr
+⟦\norm x, \Norm x⟧ & $\norm x, \Norm x$ \cr
+⟦x \stackrel ?= y⟧ & $x \stackrel ?= y$ \cr
+⟦x \stackbin a+ y⟧ & $x \stackbin a+ y$ \cr
+⟦f\inv⟧ & $f\inv$ \quad (cf. $f^{-1}$) \cr
+⟦a \xrightarrow[down]{up} b⟧ & $a \xrightarrow[down]{up} b$ \cr
+⟦a \xeq[down]{up} b⟧ & $a \xeq[down]{up} b$ \cr
+⟦\frac12, \tfrac12, \dfrac12⟧& $\frac12, \tfrac12, \dfrac12$\cr
+}\smallskip}
+
+Also new are the operators
+⟦\Tr⟧, ⟦\tr⟧, ⟦\Span⟧, ⟦\GL⟧, ⟦\SL⟧, ⟦\SU⟧, ⟦\U⟧, ⟦\SO⟧, ⟦\O⟧,
+⟦\Sp⟧, ⟦\im⟧, ⟦\End⟧, ⟦\Aut⟧, ⟦\Dom⟧ and ⟦\Codom⟧.
+You can define new operators with ⟦*\newmathop⟧ and ⟦*\newlargemathop⟧:
+⟦\newmathop{op}⟧ will define the new operator ⟦\op⟧.
+For single use of an upright symbol, operator or large operator you can use
+⟦*\mord⟧, ⟦*\mop⟧ and ⟦*\mlop⟧.
+The difference between ⟦\mord⟧ and ⟦\mup⟧ is that ⟦\mord⟧ also applies the
+correct symbol spacing.
+
+The accents ⟦\overbrace⟧, ⟦\underbracket⟧ etc. allow a label between square
+brackets:
+⟦$$\underbrace[=1]{(x^2+∥penalty0y^2)}$$⟧ gives
+$$\underbrace[=1]{(x^2 + y^2)}.$$
+
+
+\section Best practices
+
+The following remarks on mathematical typesetting have no relation to the
+contents of this package; I have included them because I find them hard to
+remember.
+
+\startlist
+\item1. ⟦*\eqalign⟧ gives a vertically centered box and can occur many times in
+an equation, while ⟦*\eqalignno⟧ and ⟦*\leqalignno⟧ span whole lines (put the
+equation numbers in the third column). All assume the relation (or operator)
+appears at the right hand side of the ampsersand.
+\item2. The command ⟦*\displaylines⟧ can only have one column that spans the
+whole line (and you will have to add the equation number by hand).
+\item3. Further alignment commands are ⟦*\cases⟧, ⟦*\matrix⟧, ⟦*\pmatrix⟧ (with
+parentheses) and ⟦*\bordermatrix⟧ (includes labels for lines and columns).
+\item4. Finetuning alignments can be done with ⟦*\smash⟧, ⟦*\phantom⟧,
+⟦*\hphantom⟧ and ⟦*\vphantom⟧.
+\item5. Small matrices like $1\;2\choose3\;4$ can be made by misusing
+⟦*\choose⟧ or ⟦*\atop⟧.
+\item6. If you start a line with a binary operator, put a ⟦*{}⟧ before it: this
+way, tex recognises it as such.
+\item7. Thin spaces (⟦*\,⟧) should be inserted: before $\mup dx$, before units,
+after factorials and after ⟦*\dots⟧ if those are followed by a closing
+parenthesis.
+\item8. Whether the differential operator should be set upright or not is as of
+yet an open question in mathematics.
+\item9. You should prefer ⟦*\bigr⟧ and ⟦*\bigl⟧ etc. over ⟦\big⟧, ⟦\Big⟧,
+⟦\bigg⟧ and ⟦\Bigg⟧.
+\item10. An overview of mathematical symbols, with control sequences and their
+availability in different fonts, can be found in ⟦*unimath-symbols.pdf⟧, which
+is part of the unicode-math package.
+\stoplist
+
+\endmanual
+
+
diff --git a/macros/luatex/generic/minim-math/minim-math.lua b/macros/luatex/generic/minim-math/minim-math.lua
new file mode 100644
index 0000000000..194e938819
--- /dev/null
+++ b/macros/luatex/generic/minim-math/minim-math.lua
@@ -0,0 +1,482 @@
+
+local M = {}
+
+local alloc = require ('minim-alloc')
+local callbacks = require ('minim-callbacks')
+
+alloc.remember('minim-math')
+
+-- 1 Alphabet tables
+
+--[[ There are gaps left in the unicode math alphabets
+-- for characters that were already represented
+-- elsewhere. These tables will be used for redirecting
+-- characters mapped to these gaps.
+--]]
+
+local gaps =
+ { [0x1d455] = 0x0210e -- H
+ , [0x1d49d] = 0x0212c -- script B
+ , [0x1d4a0] = 0x02130 -- script E
+ , [0x1d4a1] = 0x02131 -- script F
+ , [0x1d4a3] = 0x0210b -- script H
+ , [0x1d4a4] = 0x02110 -- script I
+ , [0x1d4a7] = 0x02112 -- script L
+ , [0x1d4a8] = 0x02133 -- script M
+ , [0x1d4ad] = 0x0211b -- script R
+ , [0x1d4ba] = 0x0212f -- script e
+ , [0x1d4bc] = 0x0210a -- script g
+ , [0x1d4c4] = 0x02134 -- script o
+ , [0x1d506] = 0x0212d -- fraktur C
+ , [0x1d50b] = 0x0210c -- fraktur H
+ , [0x1d50c] = 0x02111 -- fraktur I
+ , [0x1d515] = 0x0211c -- fraktur R
+ , [0x1d51d] = 0x02128 -- fraktur Z
+ , [0x1d53a] = 0x02102 -- bb C
+ , [0x1d53f] = 0x0210d -- bb H
+ , [0x1d545] = 0x02115 -- bb N
+ , [0x1d547] = 0x02119 -- bb P
+ , [0x1d548] = 0x0211a -- bb Q
+ , [0x1d549] = 0x0211d -- bb R
+ , [0x1d551] = 0x02124 -- bb Z
+ }
+
+-- greek variants have irregular upright values
+local varcorr =
+ { [0x03f4] = 0x03a2 -- ϴ
+ , [0x2207] = 0x03aa -- ∇
+ , [0x2202] = 0x03ca -- ∂
+ , [0x03f5] = 0x03cb -- ϵ
+ , [0x03d1] = 0x03cc -- ϑ
+ , [0x03f0] = 0x03cd -- ϰ
+ , [0x03d5] = 0x03ce -- ϕ
+ , [0x03f1] = 0x03cf -- ϱ
+ , [0x03d6] = 0x03d0 -- ϖ
+ }
+
+--[[ When transforming to other stylistic variants, we need
+-- to know which alphabet a character is in; the transformation
+-- offsets differ for each alphabet.
+--]]
+
+local function getalphabet (n)
+ if n >= 0x61 and n <= 0x7A then return 0x61 -- latin
+ elseif n >= 0x41 and n <= 0x5A then return 0x41 -- Latin
+ elseif n >= 0x30 and n <= 0x39 then return 0x30 -- digits
+ elseif n >= 0x3b1 and n <= 0x3c9 then return 0x3b1 -- greek
+ elseif n >= 0x391 and n <= 0x3a9 then return 0x391 -- Greek
+ elseif (varcorr[n] or 0xfff) < 0x3c0 then return 0x391 -- varGreek
+ elseif (varcorr[n] or 0xfff) < 0x3f0 then return 0x3b1 -- vargreek
+ else return 0 -- the character cannot transform
+ end
+end
+
+--[[ In the offsets table, all transformations can be found for the first
+-- character in the alphabet. The numbers in the table are increments.
+--]]
+
+local offsets =
+ { [0] = {}
+ , [0x61] = -- latin
+ { [1] = 0x1d3ed -- it 𝑎 = 0x1d44e
+ , [3] = 0x1d421 -- bfit 𝒂 = 0x1d482
+ , [4] = 0x1d4f1 -- bb 𝕒 = 0x1d552
+ , [2] = 0x1d3b9 -- bf 𝐚 = 0x1d41a
+ , [5] = 0x1d4bd -- frak 𝔞 = 0x1d51e
+ , [6] = 0x1d525 -- bffrak 𝖆 = 0x1d586
+ , [7] = 0x1d455 -- cal 𝒶 = 0x1d4b6
+ , [8] = 0x1d489 -- bfcal 𝓪 = 0x1d4ea
+ , [9] = 0x1d559 -- sans 𝖺 = 0x1d5ba
+ , [10]= 0x1d5c1 -- sfit 𝘢 = 0x1d622
+ , [11]= 0x1d58d -- sfbf 𝗮 = 0x1d5ee
+ , [12]= 0x1d5f5 -- sfbfit 𝙖 = 0x1d656
+ , [13]= 0x1d629 -- mono 𝚊 = 0x1d68a
+ }
+ , [0x41] = -- Latin
+ { [1] = 0x1d3f3 -- it 𝐴 = 0x1d434
+ , [3] = 0x1d427 -- bfit 𝑨 = 0x1d468
+ , [4] = 0x1d4f7 -- bb 𝔸 = 0x1d538
+ , [2] = 0x1d3bf -- bf 𝐀 = 0x1d400
+ , [5] = 0x1d4c3 -- frak 𝔄 = 0x1d504
+ , [6] = 0x1d52b -- bffrak 𝕬 = 0x1d56c
+ , [7] = 0x1d45b -- cal 𝒜 = 0x1d49c
+ , [8] = 0x1d48f -- bfcal 𝓐 = 0x1d4d0
+ , [9] = 0x1d55f -- sans 𝖠 = 0x1d5a0
+ , [10]= 0x1d5c7 -- sfit 𝘈 = 0x1d608
+ , [11]= 0x1d593 -- sfbf 𝗔 = 0x1d5d4
+ , [12]= 0x1d5fb -- sfbfit 𝘼 = 0x1d63c
+ , [13]= 0x1d62f -- mono 𝙰 = 0x1d670
+ }
+ , [0x30] = -- digits
+ { [2] = 0x1d79e -- bf 𝐀 = 0x1d7ce
+ , [4] = 0x1d7a8 -- bb 𝔸 = 0x1d7d8
+ , [9] = 0x1d7b2 -- sans 𝟬 = 0x1d47e2
+ , [11]= 0x1d7bc -- bfsans 𝟬 = 0x1d47ec
+ , [13]= 0x1d7c6 -- mono 𝟬 = 0x1d47f7
+ }
+ , [0x3b1] = -- greek
+ { [1] = 0x1d34b -- it 𝛼 = 0x1d6fc
+ , [2] = 0x1d311 -- bf 𝛂 = 0x1d6c2
+ , [3] = 0x1d385 -- bfit 𝜶 = 0x1d736
+ , [11]= 0x1d3bf -- sfbf 𝝖 = 0x1d756
+ , [12]= 0x1d3f9 -- sfbfit 𝞪 = 0x1d7aa
+ }
+ , [0x391] = -- Greek
+ { [1] = 0x1d351 -- it 𝛢 = 0x1d6e2
+ , [2] = 0x1d317 -- bf 𝚨 = 0x1d6a8
+ , [3] = 0x1d38b -- bfit 𝜜 = 0x1d71c
+ , [11]= 0x1d3c5 -- sfbf 𝝖 = 0x1d756
+ , [12]= 0x1d3ff -- sfbfit 𝞐 = 0x1d790
+ }
+ }
+
+--[[ The function transform_char() returns a transformed character, or nil if
+-- the character cannot be transformed like that. It is used by the setmap
+-- function (which gives a warning on nil) and by the mlist callback (which
+-- ignores nil).
+--]]
+
+local function add_fam(num)
+ local _, fam, _ = tex.getmathcodes(num)
+ return num, fam
+end
+
+local function transform_char(num, style)
+ if style == 0 then
+ return add_fam(num)
+ else
+ local base = getalphabet(num)
+ local n = offsets[base][style]
+ if n == nil then
+ return nil, nil
+ else
+ local res = varcorr[num] or num
+ res = gaps[n+res] or n+res
+ return add_fam(res)
+ end
+ end
+end
+
+-- 1 Parsing user input
+
+--[[ We accept the following as argument to our lua-side functions:
+-- * An alphabet or class name;
+-- * A numerical range of the form [0-9]+@[0-9]+
+-- * Ordinary strings
+--]]
+
+-- math alphabets like 𝒶𝒷𝒸, 𝔞𝔟𝔠, 𝕒𝕓𝕔, and classes like ord, rel etc.
+local alphabets = alloc.saved_table('math:alphabets')
+
+local function add_to_alphabet(num, code)
+ alphabets[code] = (alphabets[code] or '') .. string.utfcharacter(num)
+end
+
+local function chars_iterator(input)
+ local a = alphabets[input]
+ if a then
+ return string.utfvalues(a)
+ else
+ local from, to = string.match(input, '^([0-9]+)@([0-9]+)$')
+ if from then
+ local i, n = tonumber(from) - 1, tonumber(to)
+ return function()
+ i = i + 1
+ if i <= n then return gaps[i] or i end
+ end
+ else
+ return string.utfvalues(input)
+ end
+ end
+end
+
+local function apply_settings(input, fn, ...)
+ for char in chars_iterator(input) do
+ fn(char, ...)
+ end
+end
+
+-- 1 Switching class and family
+
+--[[ Setting class and family information is rather simple: the difficult part
+-- of this package is switching between math alphabets.
+--]]
+
+local classes = {}
+classes.ord = 0
+classes.op = 1
+classes.bin = 2
+classes.rel = 3
+classes.fence = 3
+classes.open = 4
+classes.close = 5
+classes.punct = 6
+classes.var = 7
+
+local function setclass(char, class)
+ local _, fam , sym = tex.getmathcodes (char)
+ tex.setmathcode (char, classes[class] or class, fam, sym)
+end
+
+local function setfam(char, fam)
+ local class, _, sym = tex.getmathcodes (char)
+ tex.setmathcode (char, class, fam, sym)
+end
+
+function M.setclass (input, class)
+ apply_settings(input, setclass, class)
+end
+
+function M.setfam (input, fam)
+ apply_settings(input, setfam, fam)
+end
+
+-- 1 Character variants
+
+--[[ The settings of variant characters is not coupled to the style mechanism:
+-- rather, it changes the \Umathcode-s directly. Of course, the variant
+-- characters can transform.
+--]]
+
+M.greek_variants =
+ { [0x3b5] = 0x3f5 -- ε ϵ
+ , [0x398] = 0x3f4 -- Θ ϴ
+ , [0x3b8] = 0x3d1 -- θ ϑ
+ , [0x3ba] = 0x3f0 -- κ ϰ
+ , [0x3c6] = 0x3d5 -- φ ϕ
+ , [0x3c1] = 0x3f1 -- ρ ϱ
+ , [0x3c0] = 0x3d6 -- π ϖ
+ }
+
+function M.usevariant (char)
+ for num in string.utfvalues (char) do
+ local class, fam, _ = tex.getmathcodes(num)
+ tex.setmathcode (num, class, fam, M.greek_variants[num] or num)
+ end
+end
+
+function M.usedefault (char)
+ for num in string.utfvalues (char) do
+ local class, fam, _ = tex.getmathcodes(num)
+ tex.setmathcode (num, class, fam, num)
+ end
+end
+
+-- 1 Styles
+
+--[[ The style table gives a numerical value to every math style. The value
+-- `clear' unsets the style attribute.
+--]]
+
+local styles = {}
+styles.clear = alloc.unset
+styles.up = 0
+styles.rm = 0
+styles.it = 1
+styles.mit = 1
+styles.bf = 2
+styles.bfit = 3
+styles.bb = 4
+styles.frak = 5
+styles.bffrak = 6
+styles.cal = 7
+styles.scr = 7
+styles.script = 7
+styles.bfcal = 8
+styles.bfscr = 8
+styles.sf = 9
+styles.sans = 9
+styles.sfit = 10
+styles.sfbf = 11
+styles.sfbfit = 12
+styles.mono = 13
+styles.tt = 13
+
+local style_attribute = alloc.new_attribute ('math style attribute')
+
+function M.setstyle (style)
+ tex.setattribute (style_attribute, styles[style])
+end
+
+-- 1 Switching alphabets
+
+--[[ Which glyph a variable character should transform to is determined by
+-- a tex \count register. This ensures that changes to the math style respect
+-- grouping.
+--
+-- On the lua side, we keep track of these counts in a table (it is filled
+-- from the tex side).
+--]]
+
+local transformcodes = alloc.saved_table ('math:transformcodes')
+
+-- set a character as transformable
+local function set_transform (num, char)
+ c = alloc.new_count ('math transform '..char)
+ transformcodes[num] = c
+ tex.setcount ('global', c, num)
+end
+
+-- query the destination
+local function dest_char (num)
+ local c = transformcodes[num]
+ if c == nil then
+ return num, nil
+ else
+ return add_fam(tex.count[c])
+ end
+end
+
+-- set the destination
+local function setmap (char, style)
+ local target = transform_char (char, styles[style])
+ if target == nil then
+ texio.write_nl ('! minim warning: style '..style..' not available for char '..char..'.')
+ else
+ tex.count[transformcodes[char]] = target
+ end
+end
+
+function M.setmap(input, style)
+ apply_settings(input, setmap, style)
+end
+
+--[[ To allow saving and restoring math style settings, the following function
+-- is a dump of \count and \Umathcode values.
+--]]
+
+function M.save_mathstyles ()
+ for _,v in pairs(transformcodes) do
+ tex.sprint('\\count'..v..'='..tex.count[v]..'\\relax')
+ end
+ for v,_ in pairs(M.greek_variants) do
+ local a,b,c = tex.getmathcodes(v)
+ tex.sprint('\\Umathcode'..v..'='..a..' '..b..' '..c..'\\relax')
+ end
+end
+
+-- 1 The transformation callback
+
+--[[ The stilistic mappings are done in the mlist_to_mlist callback. The
+-- function noad_iterator returns an iterator over the noad list; all
+-- math_char nodes are inspected.
+--
+-- The listmathfields table contains all noad fields that can contain another
+-- list of noads.
+--]]
+
+local listmathfields = { 'head', 'nucleus', 'sub', 'sup', 'accent', 'bot_accent',
+ 'display', 'text', 'script', 'scriptscript', 'num', 'denom', 'degree', 'next' }
+
+local function noad_iterator (head)
+ local nodelist = { link=nil, content=head }
+ return function ()
+ if nodelist == nil then return nil end
+ local n = nodelist.content
+ nodelist = nodelist.link
+ for _,f in pairs(listmathfields) do
+ if node.has_field (n, f) and n[f] ~= nil then
+ nodelist = { link=nodelist, content=n[f] }
+ end
+ end
+ return n
+ end
+end
+
+local math_char = node.id ('math_char')
+
+local function inspect_noads (h,d,n)
+ for nd in noad_iterator (h) do
+ if nd.id == math_char then
+ local sa = node.has_attribute(nd, style_attribute)
+ local char, fam
+ if sa then
+ char, fam = transform_char(nd.char, sa)
+ else
+ char, fam = dest_char(nd.char)
+ end
+ nd.char, nd.fam = char or nd.char, fam or nd.fam
+ end
+ end
+ -- if we would not use minim-callbacks, we would have to call
+ -- node.mlist_to_hlist (h,d,n) here
+ return true
+end
+
+callbacks.register ('mlist_to_mlist', inspect_noads)
+
+-- 1 Reading the math character table
+
+--[[ The following are used for processing the character table. Control
+-- sequences are defined from the lua side; for accents and radicals this
+-- means using tex-side helper macros.
+--
+-- When using the add_mathchar function with accents or radicals, please keep
+-- in mind that it assumes \catcode`\:=11.
+--]]
+
+local default_fam = 0
+
+local accents =
+ { accent = 'accent{}'
+ , botaccent = 'accent{bottom}'
+ , overlay = 'accent{overlay}'
+ , over = 'stack{}'
+ , under = 'stack{bottom}'
+ }
+local is_delimiter =
+ { fence = true
+ , open = true
+ , close = true
+ }
+
+local function tex_accent(class, num, char)
+ kind = kind or ''
+ return '\\math:'..accents[class]..'{'..num..'}'..char
+end
+
+local function add_mathchar(code, char, class, cs, alphabet)
+ if char:sub(0,1) == ' ' then
+ -- accents can be given above a space (compare ' ́' with '́')
+ char = char:sub(2)
+ end
+ local class_nr = classes[class]
+ if class_nr then
+ tex.setmathcode(code, class_nr, default_fam, code)
+ if cs then token.set_macro(cs, char) end
+ if class_nr == 7 then set_transform(code, char) end
+ if is_delimiter[class] then tex.setdelcode(code, default_fam, code, 0, 0) end
+ elseif class == 'radical' then
+ if cs then
+ token.set_macro(cs, '\\math:radical{'..code..'}'..char)
+ tex.print('\\mathlet\\'..char..'\\'..cs)
+ end
+ else
+ -- TODO: in the future, allow accent characters by re-ordering them
+ tex.setmathcode(code, 0, default_fam, 0) -- provisional
+ if cs then token.set_macro(cs, tex_accent(class, code, char)) end
+ end
+ add_to_alphabet(code, class)
+ if alphabet then
+ add_to_alphabet(code, alphabet)
+ end
+end
+
+function M.add_mathchar(t)
+ add_mathchar(t.code, t.char, t.class, t.cs, t.alphabet)
+end
+
+-- 1 Tex-side user interface
+
+alloc.luadef('math:mathcls', function() M.setclass(token.scan_string(), token.scan_string()) end)
+alloc.luadef('math:mathfam', function() M.setfam(token.scan_string(), token.scan_string()) end)
+alloc.luadef('math:mathmap', function() M.setmap(token.scan_string(), token.scan_string()) end)
+
+alloc.luadef('usemathvariant', function() M.usevariant(token.scan_string()) end, 'protected')
+alloc.luadef('usemathdefault', function() M.usedefault(token.scan_string()) end, 'protected')
+alloc.luadef('mathstyle', function() M.setstyle(token.scan_string()) end, 'protected')
+
+--
+
+return M
+
diff --git a/macros/luatex/generic/minim-math/minim-math.pdf b/macros/luatex/generic/minim-math/minim-math.pdf
new file mode 100644
index 0000000000..b5269815dc
--- /dev/null
+++ b/macros/luatex/generic/minim-math/minim-math.pdf
Binary files differ
diff --git a/macros/luatex/generic/minim-math/minim-math.tex b/macros/luatex/generic/minim-math/minim-math.tex
new file mode 100644
index 0000000000..e05ce17f7c
--- /dev/null
+++ b/macros/luatex/generic/minim-math/minim-math.tex
@@ -0,0 +1,517 @@
+
+\ifdefined \minimmathloaded
+ \message{(skipped)}
+ \expandafter\endinput \fi
+\chardef\minimmathloaded=\catcode`:
+\catcode`:=11
+
+\input minim-alloc
+
+% \mathdef c {expansion}
+\protected\def\mathdef#1#2{%
+ \def\mathdef:tmp{#2}%
+ \mathlet{#1}\mathdef:tmp}
+% \mathlet c \csname
+\protected\def\mathlet#1#2{%
+ \mathcode`#1="8000\relax
+ \letcharcode`#1=#2}
+
+% 1 Global style transformations
+
+% first, helper functions for parsing arguments
+
+\def\math:parselist#1#2#3#4{% \function \argwrap {list} {arg}
+ \edef\math:expandedlist{{#3}}%
+ \def\math:listaction##1{#1{##1}{#2{#4}}}%
+ \expandafter\splitcommalist
+ \expandafter\math:parseitem
+ \math:expandedlist}
+
+\def\math:parseitem#1{\math:getrange#1--\math:getrange}
+\def\math:getrange#1-#2-{\def\math:tmp{#2}%
+ \ifx\math:tmp\empty \math:singleargument{#1}\fi
+ \math:rangeargument{#1}{#2}}
+\def\math:singleargument#1#2\math:getrange{\fi%
+ \math:listaction{#1}}
+\def\math:rangeargument#1#2#3\math:getrange{%
+ \math:listaction{\the\numexpr(#1)@\the\numexpr(#2)}}
+
+\def\math:simplequote#1{#1}
+\def\math:tonumber#1{\the\numexpr(#1)\relax}
+
+% then, the user interface
+
+\protected\def\mathcls{\math:parselist\math:mathcls\math:simplequote}
+\protected\def\mathfam{\math:parselist\math:mathfam\math:tonumber}
+\protected\def\mathmap{\math:parselist\math:mathmap\math:simplequote}
+
+% defined from the lua side: \usemathvariant, \usemathdefault, \mathstyle
+
+% 1 Local style transformations
+
+% We use the variable class, but not the family mechanism
+\fam = -1
+\let\setfam=\fam
+
+% for backwards compatibility with plain.tex
+\newcount\math:famcount
+\protected\def\fam{%
+ \afterassignment\math:fam
+ \math:famcount}
+\def\math:fam{%
+ \ifcase\math:famcount
+ \mathstyle{up}\or
+ \mathstyle{it}\or
+ \mathstyle{cal}\or
+ \or % plain family 3 is \tenex
+ \mathstyle{it}\or
+ \mathstyle{sf}\or % slanted math not in unicode
+ \mathstyle{bf}\or
+ \mathstyle{tt}\fi}
+
+% style switches
+\protected\def\mit#1{{\mathstyle{it}#1}}
+\protected\def\mup#1{{\mathstyle{up}#1}}
+\protected\def\mbf#1{{\mathstyle{bf}#1}}
+\protected\def\mbfit#1{{\mathstyle{bfit}#1}}
+\protected\def\mbb#1{{\mathstyle{bb}#1}}
+\protected\def\frak#1{{\mathstyle{frak}#1}}
+\protected\def\bffrak#1{{\mathstyle{bffrak}#1}}
+\protected\def\scr#1{{\mathstyle{scr}#1}} \let\mcal = \cal
+\protected\def\bfscr#1{{\mathstyle{bfscr}#1}} \let\bfcal = \bfscr
+
+% 1 Processing the character table
+
+\newcount \radicalfam \radicalfam = 0
+\newcount \accentfam \accentfam = 0
+\newcount \extensiblefam \extensiblefam = 0
+
+\def\math:accent{\ifmmode% spec num char
+ \expandafter\math:mathaccent\else
+ \expandafter\math:textaccent\fi}
+\def\math:mathaccent#1#2#3{\Umathaccent #1"0 \accentfam #2 }
+\def\math:textaccent#1#2#3#4{#4#3}% might be a normal combining accent
+
+\def\math:stack#1#2#3{% spec num char
+ \withoptions[]{\math:stack:{#1}{#2}{#3}}}
+\def\math:stack:#1#2#3[#4]#5{%
+ {\mathop{\math:accent{#1}{#2}{#3}{#5}}%
+ \ifx\math:stack#4\math:stack\else \limits
+ \ifx\math:stack#1\math:stack^\else_\fi{#4}\fi}}
+
+\def\math:radical{\ifmmode% num char
+ \expandafter\math:mathradical\else
+ \expandafter\math:textradical\fi}
+\def\math:mathradical#1#2{\Uradical\radicalfam #1 }
+\def\math:textradical#1#2{#2}
+
+% We initiate the processing here instead of from the lua side, because the lua
+% file will be executed again inside \everyjob. We are only setting parameters
+% here that will be saved to the format file, so we need not repeat it.
+
+\directlua{%
+ local m = require('minim-math')
+ local file = kpse.find_file('minim-math-table', 'lua')
+ local table = loadfile(file)()
+ for _, t in ipairs(table) do
+ m.add_mathchar(t)
+ end
+}
+
+% 1 Fixing a few characters
+
+% fixing a math cs (prevents expansion loops)
+\def\explicitmathchar#1{%
+ \expandafter\Umathcharnumdef
+ \expandafter#1%
+ \expandafter\Umathcodenum
+ \expandafter`#1}
+
+% special characters must be explicit
+\explicitmathchar\lbrace \let\{=\lbrace
+\explicitmathchar\rbrace \let\}=\rbrace
+\explicitmathchar\percent
+\explicitmathchar\mathdollar
+\explicitmathchar\octothorpe
+\explicitmathchar\ampersand
+
+% decimal comma settings
+\explicitmathchar \comma
+\protected\def\decimalcomma {\Umathcode`\, = 0 \Umathcharfam`\, `\,}
+\protected\def\nodecimalcomma{\Umathcode`\, = 6 \Umathcharfam`\, `\,}
+
+% set the colon to how it used to be
+\Umathcode`\:="3"0"2236 % \ratio
+\Umathchardef\colon "6"0"3A
+
+% ldot as a punctuation mark
+\Umathchardef\ldotp "6"0"2E
+\let \period = \ldotp
+
+% remapping two characters
+\mathlet * \ast
+\mathlet - \minus
+
+% interpret the normal middle dot as the middle dot operator
+\mathlet · \cdot
+\Umathchardef\cdotp "6"0"B7
+
+% some aliases
+\let\neq = \ne
+\let\le = \leq
+\let\ge = \geq
+\let\owns = \ni
+\let\gets = \leftarrow
+\let\to = \rightarrow
+\let\land = \wedge
+\let\lor = \vee
+\let\lnot = \neg
+
+% replace \mathhexbox macros
+\protected\def\mathcharbox#1{\leavevmode
+ \hbox{$\mathsurround0pt\relax#1$}}
+\protected\def\dag{\mathcharbox†}
+\protected\def\ddag{\mathcharbox‡}
+\protected\def\S{\mathcharbox§}
+\protected\def\P{\mathcharbox¶}
+\protected\def\Orb{\mathcharbox◯}
+
+% wide accents are default
+\let\widehat = \hat
+\let\widetilde = \tilde
+\let\overline = \overbar
+\let\underline = \underbar
+
+% integrals
+\let\intlimits=\nolimits
+
+\explicitmathchar\intop
+\explicitmathchar\iintop
+\explicitmathchar\iiintop
+\explicitmathchar\ointop
+\explicitmathchar\oiintop
+\explicitmathchar\oiiintop
+\explicitmathchar\intclockwiseop
+\explicitmathchar\varointclockwiseop
+\explicitmathchar\ointctrclockwiseop
+
+\edef\int {\intop\intlimits}
+\edef\iint {\iintop\intlimits}
+\edef\iiint {\iiintop\intlimits}
+\edef\oint {\ointop\intlimits}
+\edef\oiint {\oiintop\intlimits}
+\edef\oiiint {\oiiintop\intlimits}
+\edef\intclockwise {\intclockwiseop\intlimits}
+\edef\varointclockwise {\varointclockwiseop\intlimits}
+\edef\ointctrclockwise {\ointctrclockwiseop\intlimits}
+
+\mathlet ∫ \int
+\mathlet ∬ \iint
+\mathlet ∭ \iiint
+\mathlet ∮ \oint
+\mathlet ∯ \oiint
+\mathlet ∰ \oiiint
+\mathlet ∱ \intclockwise
+\mathlet ∲ \varointclockwise
+\mathlet ∳ \ointctrclockwise
+
+% 1 Roots
+
+\protected\def\sqrt{\sqrt:make{\Uradical\radicalfam"221A}}
+\protected\def\root#1\of{\sqrt:make{\Uroot\radicalfam"221A{#1}}}
+\def\sqrt:open#1#2{#1{#2}} % braces are necessary
+\def\sqrt:close#1{\mathpalette{\sqrt:closed{#1}}}
+\def\sqrt:closed#1#2#3{% root style content
+ \setbox0=\hbox{$#2\Uradical\radicalfam"221A{#3}$}%
+ #2#1{#3\mkern2mu}\kern-\Umathradicalrule#2%
+ \raise\dimexpr\ht0-1\Umathradicalkern#2-.5\Umathradicalrule#2\hbox
+ {\vrule height0pt depth.2\ht0 width\Umathradicalrule#2}%
+ \kern\Umathradicalkern#2}
+
+\protected\def\normalroots{\let\sqrt:make\sqrt:open}
+\protected\def\closedroots{\let\sqrt:make\sqrt:close}
+
+\normalroots
+
+\mathlet √ \sqrt
+\mathdef ∛ {\root3\of}
+\mathdef ∜ {\root4\of}
+
+% 1 Dots
+
+% \vdots, \ddots, \adots
+\newdimen\mathdots:pt
+\newbox\mathdots:box
+\def\mathdots:init#1#2{%
+ \mathdots:pt=.1\fontdimen6#20\relax
+ \setbox\mathdots:box=\hbox{$#1.$}%
+ \ht\mathdots:box=\mathdots:pt}
+\def\mathdots:choice#1{\mathinner{\mathchoice
+ {\mathdots:init\displaystyle\textfont#1}
+ {\mathdots:init\textstyle\textfont#1}
+ {\mathdots:init\scriptstyle\scriptfont#1}
+ {\mathdots:init\scriptscriptstyle\scriptscriptfont#1}}}
+\protected\def\texvdots{\mathdots:choice{\vbox{%
+ \baselineskip4\mathdots:pt\lineskiplimit0pt\relax \kern6\mathdots:pt
+ \copy\mathdots:box \copy\mathdots:box \copy\mathdots:box}}}
+\protected\def\texddots{\mathdots:choice{\mkern1mu
+ \raise7\mathdots:pt \vbox{\kern7\mathdots:pt\copy\mathdots:box}\mkern2mu
+ \raise4\mathdots:pt \copy\mathdots:box\mkern2mu
+ \raise1\mathdots:pt \copy\mathdots:box\mkern1mu}}
+\protected\def\texadots{\mathdots:choice{\mkern1mu
+ \raise1\mathdots:pt \copy\mathdots:box\mkern2mu
+ \raise4\mathdots:pt \copy\mathdots:box\mkern2mu
+ \raise7\mathdots:pt \vbox{\kern7\mathdots:pt\copy\mathdots:box}\mkern1mu}}
+
+% \ldots and \cdots are unchanged from plain.tex
+\protected\edef\texldots{\ldots}
+\protected\edef\texcdots{\cdots}
+
+% \traditionaldots
+\protected\def\traditionaldots{%
+ \mathlet \⋮ \texvdots \let\vdots = \texvdots
+ \mathlet \⋯ \texcdots \let\cdots = \texcdots
+ \mathlet \⋰ \texadots \let\adots = \texadots
+ \mathlet \⋱ \texddots \let\ddots = \texddots
+ \mathlet \… \texldots \let\ldots = \texldots}
+
+% \unicodedots
+\protected\def\unicodedots{%
+ \Umathcode `\⋮ = "3"0"22EE \let\vdots = \unicodevdots
+ \Umathcode `\⋯ = "0"0"22EF \let\cdots = \unicodecdots
+ \Umathcode `\⋰ = "3"0"22F0 \let\adots = \unicodeadots
+ \Umathcode `\⋱ = "3"0"22F1 \let\ddots = \unicodeddots
+ \Umathcode `\… = "3"0"2026 \let\ldots = \unicodeellipsis}
+
+\traditionaldots
+
+% 1 Primes
+
+% primes
+\mathdef'{\math:prime{}}
+\mathdef`{\math:bprime{}}
+\def\math:prime#1{%
+ \nextifx'{\math:prime:plus{#1}}%
+ {^\csname#1prime\endcsname}}
+\def\math:prime:plus#1'{%
+ \math:prime{#1p}}
+\def\math:bprime#1{%
+ \nextifx`{\math:bprime:plus{#1}}%
+ {^\csname b#1prime\endcsname}}
+\def\math:bprime:plus#1`{%
+ \math:bprime{#1p}}
+% \pprime etc.
+\let\pprime=\dprime
+\let\ppprime=\trprime
+\let\pppprime=\qprime
+\let\bprime=\backprime
+\let\bpprime=\backdprime
+\let\bppprime=\backtrprime
+
+% 1 Superscripts and subscripts
+
+\edef\math:tmp{%
+ \mathdef\Uchar"00B2{^2}
+ \mathdef\Uchar"00B3{^3}
+ \mathdef\Uchar"00B9{^1}
+ \mathdef\Uchar"2070{^0}
+ \mathdef\Uchar"2071{^i}
+ \mathdef\Uchar"2074{^4}
+ \mathdef\Uchar"2075{^5}
+ \mathdef\Uchar"2076{^6}
+ \mathdef\Uchar"2077{^7}
+ \mathdef\Uchar"2078{^8}
+ \mathdef\Uchar"2079{^9}
+ \mathdef\Uchar"207A{^+}
+ \mathdef\Uchar"207B{^-}
+ \mathdef\Uchar"207C{^=}
+ \mathdef\Uchar"207D{^(}
+ \mathdef\Uchar"207E{^)}
+ \mathdef\Uchar"207F{^n}
+ \mathdef\Uchar"1D62{_i}
+ \mathdef\Uchar"1D63{_r}
+ \mathdef\Uchar"1D64{_u}
+ \mathdef\Uchar"1D65{_v}
+ \mathdef\Uchar"1D66{_β}
+ \mathdef\Uchar"1D67{_γ}
+ \mathdef\Uchar"1D68{_ρ}
+ \mathdef\Uchar"1D69{_φ}
+ \mathdef\Uchar"1D6A{_χ}
+ \mathdef\Uchar"2080{_0}
+ \mathdef\Uchar"2081{_1}
+ \mathdef\Uchar"2082{_2}
+ \mathdef\Uchar"2083{_3}
+ \mathdef\Uchar"2084{_4}
+ \mathdef\Uchar"2085{_5}
+ \mathdef\Uchar"2086{_6}
+ \mathdef\Uchar"2087{_7}
+ \mathdef\Uchar"2088{_8}
+ \mathdef\Uchar"2089{_9}
+ \mathdef\Uchar"208A{_+}
+ \mathdef\Uchar"208B{_-}
+ \mathdef\Uchar"208C{_=}
+ \mathdef\Uchar"208D{_(}
+ \mathdef\Uchar"208E{_)}
+ \mathdef\Uchar"2090{_a}
+ \mathdef\Uchar"2091{_e}
+ \mathdef\Uchar"2092{_o}
+ \mathdef\Uchar"2093{_x}
+ \mathdef\Uchar"2094{_ə}
+ \mathdef\Uchar"2095{_h}
+ \mathdef\Uchar"2096{_k}
+ \mathdef\Uchar"2097{_l}
+ \mathdef\Uchar"2098{_m}
+ \mathdef\Uchar"2099{_n}
+ \mathdef\Uchar"209A{_p}
+ \mathdef\Uchar"209B{_s}
+ \mathdef\Uchar"209C{_t}
+ \mathdef\Uchar"2C7C{_j}}
+\math:tmp
+
+% 1 Long arrows
+
+\def\extend#1#2#3{\withoptions[]{\extend:#1{#2}{#3}}}
+\def\extend:#1#2#3[#4]#5{\mathrel{% char left right below above
+ \mathpalette\extend:choose{#1{#2}{#3}{#4}{#5}}}}
+\def\extend:choose#1#2{\extend:choose:#1#2}
+\def\extend:choose:#1#2#3#4#5#6{% style char left right below above
+ \setbox0=\hbox{$#1#5$}\setbox2=\hbox{$#1#6$}%
+ \ifdim \wd0 < \wd2
+ \mathop{\Uoverdelimiter \extensiblefam `#2
+ {\mkern#3mu#6\mkern#4mu}}\limits_{#5}\else
+ \mathop{\Uunderdelimiter \extensiblefam `#2
+ {\mkern#3mu#5\mkern#4mu}}\limits^{#6}\fi}
+
+\protected\def\xleftarrow {\extend←73}
+\protected\def\xrightarrow{\extend→37}
+
+\protected\def\xLeftarrow {\extend⇐73}
+\protected\def\xRightarrow{\extend⇒37}
+
+\protected\def\xleftrightarrow{\extend↔77}
+\protected\def\xLeftrightarrow{\extend⇔77}
+
+\protected\def\xmapsto {\extend↦47}
+\protected\def\xmapsfrom {\extend↤74}
+
+\protected\def\xhookrightarrow {\extend↪67}
+\protected\def\xhookleftarrow {\extend↩76}
+
+\protected\def\xleftrightarrows {\extend⇆77}
+\protected\def\xleftleftarrows {\extend⇇73}
+\protected\def\xrightrightarrows {\extend⇉37}
+
+\protected\def\xeq{\extend=11}
+
+\let \→ \xrightarrow
+\let \⇒ \xRightarrow
+\let \← \xleftarrow
+\let \⇐ \xLeftarrow
+\let \↔ \xleftrightarrow
+\let \⇔ \xLeftrightarrow
+\let \↦ \xmapsto
+\let \↤ \xmapsfrom
+
+% 1 Miscellaneous mathematical functions
+
+% \stackrel {super} {rel}
+\protected\def\stackrel#1#2{\mathrel{\mathop{#2}\limits^{#1}}}
+% \stackbin {super} {bin}
+\protected\def\stackbin#1#2{\mathbin{\mathop{#2}\limits^{#1}}}
+
+% \text {text}
+\newcount\textfam
+\textfam=0
+\protected\def\text#1{{\mathchoice
+ {\hbox{\the\textfont\textfam#1}}%
+ {\hbox{\the\textfont\textfam#1}}%
+ {\hbox{\the\scriptfont\textfam#1}}%
+ {\hbox{\the\scriptscriptfont\textfam#1}}}}
+
+% some definitions with vertical lines
+\def\bra#1{\left⟨#1\right\vert}
+\def\ket#1{\left\vert#1\right⟩}
+\def\braket#1#2{\left⟨#1\middle\vert#2\right⟩}
+\def\norm#1{\left\vert#1\right\vert} \let \abs=\norm
+\def\Norm#1{\left\Vert#1\right\Vert}
+
+% a smaller inverse-function sign
+\protected\def\inv{^{\scriptscriptstyle
+ \mathbin{\setbox0=\hbox{$\scriptscriptstyle-$}
+ \kern.75\wd0 \pdfextension save
+ \pdfextension setmatrix{.75 0 0 1}
+ \kern-\wd0\box0 \pdfextension restore}
+ \mkern-2mu 1}}
+
+% upright multiletter symbols
+\def\mord#1{\mathord{\mathstyle{up}#1}}
+\def\mop #1{\mathop {\mathstyle{up}#1}\nolimits}
+\def\mlop#1{\mathop {\mathstyle{up}#1}\limits}
+
+% \frac, \tfrac, \dfrac
+\protected\def\frac#1#2{\Ustack{#1\over#2}}
+\protected\def\tfrac#1#2{{\textstyle{#1\over#2}}}
+\protected\def\dfrac#1#2{{\displaystyle{#1\over#2}}}
+
+% make a few plain macros \protected
+\def\minim:protect#1{\protected\edef#1{\expandafter\unexpanded\expandafter{#1}}}
+\minim:protect\smash
+\minim:protect\dotfill
+
+% 1 Operators
+
+\def\newmathop#1{\protected\expandafter\def
+ \csname#1\endcsname{\mathop{\mathstyle{up}#1}\nolimits}}
+\def\newlargemathop#1{\protected\expandafter\def
+ \csname#1\endcsname{\mathop{\mathstyle{up}#1}}}
+
+% ported operators
+\newlargemathop {lim}
+\newlargemathop {gcd} \newlargemathop {lcm}
+\newlargemathop {max} \newlargemathop {min}
+\newlargemathop {sup} \newlargemathop {inf}
+\newlargemathop {det}
+\newlargemathop {Pr}
+\newmathop {log} \newmathop {lg} \newmathop {ln}
+\newmathop {sin} \newmathop {arcsin} \newmathop {sinh}
+\newmathop {cos} \newmathop {arccos} \newmathop {cosh}
+\newmathop {tan} \newmathop {arctan} \newmathop {tanh}
+\newmathop {cot} \newmathop {coth}
+\newmathop {sec} \newmathop {csc}
+\newmathop {arg}
+\newmathop {ker}
+\newmathop {dim}
+\newmathop {hom}
+\newmathop {exp}
+\newmathop {deg}
+
+\protected\def\limsup{\mathop{\mathstyle{up}lim\,sup}}
+\protected\def\liminf{\mathop{\mathstyle{up}lim\,inf}}
+
+\let\para=\parallel
+
+% additional operators
+\newmathop {Tr} \newmathop {tr} \newmathop{Span}
+\newmathop {GL} \newmathop {SL}
+\newmathop {SU} \newmathop {U}
+\newmathop {SO} \newmathop {O}
+\newmathop {Sp}
+\newmathop {im}
+\newmathop {End} \newmathop {Aut}
+\newmathop {Dom} \newmathop {Codom}
+
+
+%  standard mappings
+
+\mathstyle{clear}
+\mathmap{latin, greek, Latin}{it}
+
+% map ħ (h-with-stroke) to ℏ (planck-constant)
+\mathdef ħ {ℏ}
+
+% \reqno
+\let\reqno = \eqno
+
+\let\math:tmp=\undefined
+\catcode`:=\minimmathloaded
+
diff --git a/macros/luatex/generic/minim-mp/EUPL-1.2-EN.txt b/macros/luatex/generic/minim-mp/EUPL-1.2-EN.txt
new file mode 100644
index 0000000000..4153cd3775
--- /dev/null
+++ b/macros/luatex/generic/minim-mp/EUPL-1.2-EN.txt
@@ -0,0 +1,287 @@
+ EUROPEAN UNION PUBLIC LICENCE v. 1.2
+ EUPL © the European Union 2007, 2016
+
+This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined
+below) which is provided under the terms of this Licence. Any use of the Work,
+other than as authorised under this Licence is prohibited (to the extent such
+use is covered by a right of the copyright holder of the Work).
+
+The Work is provided under the terms of this Licence when the Licensor (as
+defined below) has placed the following notice immediately following the
+copyright notice for the Work:
+
+ Licensed under the EUPL
+
+or has expressed by any other means his willingness to license under the EUPL.
+
+1. Definitions
+
+In this Licence, the following terms have the following meaning:
+
+- ‘The Licence’: this Licence.
+
+- ‘The Original Work’: the work or software distributed or communicated by the
+ Licensor under this Licence, available as Source Code and also as Executable
+ Code as the case may be.
+
+- ‘Derivative Works’: the works or software that could be created by the
+ Licensee, based upon the Original Work or modifications thereof. This Licence
+ does not define the extent of modification or dependence on the Original Work
+ required in order to classify a work as a Derivative Work; this extent is
+ determined by copyright law applicable in the country mentioned in Article 15.
+
+- ‘The Work’: the Original Work or its Derivative Works.
+
+- ‘The Source Code’: the human-readable form of the Work which is the most
+ convenient for people to study and modify.
+
+- ‘The Executable Code’: any code which has generally been compiled and which is
+ meant to be interpreted by a computer as a program.
+
+- ‘The Licensor’: the natural or legal person that distributes or communicates
+ the Work under the Licence.
+
+- ‘Contributor(s)’: any natural or legal person who modifies the Work under the
+ Licence, or otherwise contributes to the creation of a Derivative Work.
+
+- ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of
+ the Work under the terms of the Licence.
+
+- ‘Distribution’ or ‘Communication’: any act of selling, giving, lending,
+ renting, distributing, communicating, transmitting, or otherwise making
+ available, online or offline, copies of the Work or providing access to its
+ essential functionalities at the disposal of any other natural or legal
+ person.
+
+2. Scope of the rights granted by the Licence
+
+The Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
+sublicensable licence to do the following, for the duration of copyright vested
+in the Original Work:
+
+- use the Work in any circumstance and for all usage,
+- reproduce the Work,
+- modify the Work, and make Derivative Works based upon the Work,
+- communicate to the public, including the right to make available or display
+ the Work or copies thereof to the public and perform publicly, as the case may
+ be, the Work,
+- distribute the Work or copies thereof,
+- lend and rent the Work or copies thereof,
+- sublicense rights in the Work or copies thereof.
+
+Those rights can be exercised on any media, supports and formats, whether now
+known or later invented, as far as the applicable law permits so.
+
+In the countries where moral rights apply, the Licensor waives his right to
+exercise his moral right to the extent allowed by law in order to make effective
+the licence of the economic rights here above listed.
+
+The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to
+any patents held by the Licensor, to the extent necessary to make use of the
+rights granted on the Work under this Licence.
+
+3. Communication of the Source Code
+
+The Licensor may provide the Work either in its Source Code form, or as
+Executable Code. If the Work is provided as Executable Code, the Licensor
+provides in addition a machine-readable copy of the Source Code of the Work
+along with each copy of the Work that the Licensor distributes or indicates, in
+a notice following the copyright notice attached to the Work, a repository where
+the Source Code is easily and freely accessible for as long as the Licensor
+continues to distribute or communicate the Work.
+
+4. Limitations on copyright
+
+Nothing in this Licence is intended to deprive the Licensee of the benefits from
+any exception or limitation to the exclusive rights of the rights owners in the
+Work, of the exhaustion of those rights or of other applicable limitations
+thereto.
+
+5. Obligations of the Licensee
+
+The grant of the rights mentioned above is subject to some restrictions and
+obligations imposed on the Licensee. Those obligations are the following:
+
+Attribution right: The Licensee shall keep intact all copyright, patent or
+trademarks notices and all notices that refer to the Licence and to the
+disclaimer of warranties. The Licensee must include a copy of such notices and a
+copy of the Licence with every copy of the Work he/she distributes or
+communicates. The Licensee must cause any Derivative Work to carry prominent
+notices stating that the Work has been modified and the date of modification.
+
+Copyleft clause: If the Licensee distributes or communicates copies of the
+Original Works or Derivative Works, this Distribution or Communication will be
+done under the terms of this Licence or of a later version of this Licence
+unless the Original Work is expressly distributed only under this version of the
+Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee
+(becoming Licensor) cannot offer or impose any additional terms or conditions on
+the Work or Derivative Work that alter or restrict the terms of the Licence.
+
+Compatibility clause: If the Licensee Distributes or Communicates Derivative
+Works or copies thereof based upon both the Work and another work licensed under
+a Compatible Licence, this Distribution or Communication can be done under the
+terms of this Compatible Licence. For the sake of this clause, ‘Compatible
+Licence’ refers to the licences listed in the appendix attached to this Licence.
+Should the Licensee's obligations under the Compatible Licence conflict with
+his/her obligations under this Licence, the obligations of the Compatible
+Licence shall prevail.
+
+Provision of Source Code: When distributing or communicating copies of the Work,
+the Licensee will provide a machine-readable copy of the Source Code or indicate
+a repository where this Source will be easily and freely available for as long
+as the Licensee continues to distribute or communicate the Work.
+
+Legal Protection: This Licence does not grant permission to use the trade names,
+trademarks, service marks, or names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the copyright notice.
+
+6. Chain of Authorship
+
+The original Licensor warrants that the copyright in the Original Work granted
+hereunder is owned by him/her or licensed to him/her and that he/she has the
+power and authority to grant the Licence.
+
+Each Contributor warrants that the copyright in the modifications he/she brings
+to the Work are owned by him/her or licensed to him/her and that he/she has the
+power and authority to grant the Licence.
+
+Each time You accept the Licence, the original Licensor and subsequent
+Contributors grant You a licence to their contributions to the Work, under the
+terms of this Licence.
+
+7. Disclaimer of Warranty
+
+The Work is a work in progress, which is continuously improved by numerous
+Contributors. It is not a finished work and may therefore contain defects or
+‘bugs’ inherent to this type of development.
+
+For the above reason, the Work is provided under the Licence on an ‘as is’ basis
+and without warranties of any kind concerning the Work, including without
+limitation merchantability, fitness for a particular purpose, absence of defects
+or errors, accuracy, non-infringement of intellectual property rights other than
+copyright as stated in Article 6 of this Licence.
+
+This disclaimer of warranty is an essential part of the Licence and a condition
+for the grant of any rights to the Work.
+
+8. Disclaimer of Liability
+
+Except in the cases of wilful misconduct or damages directly caused to natural
+persons, the Licensor will in no event be liable for any direct or indirect,
+material or moral, damages of any kind, arising out of the Licence or of the use
+of the Work, including without limitation, damages for loss of goodwill, work
+stoppage, computer failure or malfunction, loss of data or any commercial
+damage, even if the Licensor has been advised of the possibility of such damage.
+However, the Licensor will be liable under statutory product liability laws as
+far such laws apply to the Work.
+
+9. Additional agreements
+
+While distributing the Work, You may choose to conclude an additional agreement,
+defining obligations or services consistent with this Licence. However, if
+accepting obligations, You may act only on your own behalf and on your sole
+responsibility, not on behalf of the original Licensor or any other Contributor,
+and only if You agree to indemnify, defend, and hold each Contributor harmless
+for any liability incurred by, or claims asserted against such Contributor by
+the fact You have accepted any warranty or additional liability.
+
+10. Acceptance of the Licence
+
+The provisions of this Licence can be accepted by clicking on an icon ‘I agree’
+placed under the bottom of a window displaying the text of this Licence or by
+affirming consent in any other similar way, in accordance with the rules of
+applicable law. Clicking on that icon indicates your clear and irrevocable
+acceptance of this Licence and all of its terms and conditions.
+
+Similarly, you irrevocably accept this Licence and all of its terms and
+conditions by exercising any rights granted to You by Article 2 of this Licence,
+such as the use of the Work, the creation by You of a Derivative Work or the
+Distribution or Communication by You of the Work or copies thereof.
+
+11. Information to the public
+
+In case of any Distribution or Communication of the Work by means of electronic
+communication by You (for example, by offering to download the Work from a
+remote location) the distribution channel or media (for example, a website) must
+at least provide to the public the information requested by the applicable law
+regarding the Licensor, the Licence and the way it may be accessible, concluded,
+stored and reproduced by the Licensee.
+
+12. Termination of the Licence
+
+The Licence and the rights granted hereunder will terminate automatically upon
+any breach by the Licensee of the terms of the Licence.
+
+Such a termination will not terminate the licences of any person who has
+received the Work from the Licensee under the Licence, provided such persons
+remain in full compliance with the Licence.
+
+13. Miscellaneous
+
+Without prejudice of Article 9 above, the Licence represents the complete
+agreement between the Parties as to the Work.
+
+If any provision of the Licence is invalid or unenforceable under applicable
+law, this will not affect the validity or enforceability of the Licence as a
+whole. Such provision will be construed or reformed so as necessary to make it
+valid and enforceable.
+
+The European Commission may publish other linguistic versions or new versions of
+this Licence or updated versions of the Appendix, so far this is required and
+reasonable, without reducing the scope of the rights granted by the Licence. New
+versions of the Licence will be published with a unique version number.
+
+All linguistic versions of this Licence, approved by the European Commission,
+have identical value. Parties can take advantage of the linguistic version of
+their choice.
+
+14. Jurisdiction
+
+Without prejudice to specific agreement between parties,
+
+- any litigation resulting from the interpretation of this License, arising
+ between the European Union institutions, bodies, offices or agencies, as a
+ Licensor, and any Licensee, will be subject to the jurisdiction of the Court
+ of Justice of the European Union, as laid down in article 272 of the Treaty on
+ the Functioning of the European Union,
+
+- any litigation arising between other parties and resulting from the
+ interpretation of this License, will be subject to the exclusive jurisdiction
+ of the competent court where the Licensor resides or conducts its primary
+ business.
+
+15. Applicable Law
+
+Without prejudice to specific agreement between parties,
+
+- this Licence shall be governed by the law of the European Union Member State
+ where the Licensor has his seat, resides or has his registered office,
+
+- this licence shall be governed by Belgian law if the Licensor has no seat,
+ residence or registered office inside a European Union Member State.
+
+Appendix
+
+‘Compatible Licences’ according to Article 5 EUPL are:
+
+- GNU General Public License (GPL) v. 2, v. 3
+- GNU Affero General Public License (AGPL) v. 3
+- Open Software License (OSL) v. 2.1, v. 3.0
+- Eclipse Public License (EPL) v. 1.0
+- CeCILL v. 2.0, v. 2.1
+- Mozilla Public Licence (MPL) v. 2
+- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
+- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for
+ works other than software
+- European Union Public Licence (EUPL) v. 1.1, v. 1.2
+- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong
+ Reciprocity (LiLiQ-R+).
+
+The European Commission may update this Appendix to later versions of the above
+licences without producing a new version of the EUPL, as long as they provide
+the rights granted in Article 2 of this Licence and protect the covered Source
+Code from exclusive appropriation.
+
+All other changes or additions to this Appendix require the production of a new
+EUPL version.
diff --git a/macros/luatex/generic/minim-mp/README b/macros/luatex/generic/minim-mp/README
new file mode 100644
index 0000000000..dee13d1bfe
--- /dev/null
+++ b/macros/luatex/generic/minim-mp/README
@@ -0,0 +1,28 @@
+Version: 2021/1.0
+
+SUMMARY
+
+This package offers low-level mplib integration for plain LuaTeX and is
+designed with the purpose of being easy to extend.
+
+The use of multiple simultaneous MetaPost instances is supported, as well as
+running TeX or lua code from within MetaPost. With the included minim-mp
+format file, you can even use LuaTeX as a stand-alone MetaPost compiler.
+
+
+DOCUMENTATION
+
+In order to obtain the typeset manual of this package, simply say:
+
+ luatex minim-mp.doc
+
+
+COPYING
+
+(c) 2021 Esger Renkema
+
+These files may be distributed under the terms of the European Union Public
+Licence (EUPL) version 1.2 or later. A copy can be obtained at:
+
+https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+
diff --git a/macros/luatex/generic/minim-mp/minim-mp.doc b/macros/luatex/generic/minim-mp/minim-mp.doc
new file mode 100644
index 0000000000..788d26b6a0
--- /dev/null
+++ b/macros/luatex/generic/minim-mp/minim-mp.doc
@@ -0,0 +1,329 @@
+
+\input minim-doc.sty
+
+\manual{minim-mp}
+
+\ifchapter \chapter Metapost
+
+\else \startmetadata
+ author {Esger Renkema}
+ title {minim-mp}
+ date {2021-06-01}
+ version {2021/1.0}
+ keywords {LuaTeX; Plain TeX; MetaPost; mplib}
+ stopmetadata
+\maketitle \fi
+
+This package offers low-level mplib integration for plain luatex.
+The use of multiple simultaneous metapost instances is supported, as well as
+running tex or lua code from within metapost.
+In order to use it, simply say ⟦\input minim-mp.tex⟧.
+
+After this, ⟦*\directmetapost [ options ] { mp code }⟧ will result in a series
+of images corresponding to the ⟦beginfig ... endfig⟧ statements in your
+⟦mp code⟧. Every image will be in a box of its own.
+
+Every call to ⟦\directmetapost⟧ opens and closes a separate metapost instance.
+If you want your second call to remember the first, you will have to define
+a persistent metapost instance. This will also give you more control over image
+extraction. See below under „Metapost instances”. The ⟦options⟧ will also be
+explained there (for simple cases, you will not need them).
+
+The logging of the metapost run will be included in the regular log file. If an
+error occurs, the logging will also be shown on the terminal.
+
+This package can also be used as a stand-alone metapost compiler. Saying
+\stopformulatagging$$\hbox{⟦luatex --fmt=minim-mp your_file.mp⟧}$$\startformulatagging
+will create a pdf file of all images in ⟦your_file.mp⟧, in order, with page
+sizes adjusted to image dimensions.
+
+\section Metapost instances % 1
+
+For more complicated uses, you can define your own instances by saying
+⟦*\newmetapostinstance [ options ] \id⟧.
+An instance can be closed with ⟦*\closemetapostinstance \id⟧.
+These are the options you can use:
+
+\smallskip\smallskip\automarktable
+\halign{#\quad\hfil&#\quad\hfil&#\hfil\cr
+Option&Default&Description\cr
+⟦jobname⟧&⟦':metapost:'⟧&Used in error messages.\cr
+⟦format⟧&⟦'plain.mp'⟧&Format to initialise the instance with.\cr
+⟦math⟧&⟦'scaled'⟧&One of ⟦scaled⟧, ⟦decimal⟧ or ⟦double⟧.\cr
+⟦seed⟧&⟦nil⟧&Random seed for this instance.\cr
+⟦catcodes⟧&⟦0⟧&Catcode table for ⟦btex ... etex⟧.\cr
+⟦env⟧&copy of ⟦_G⟧&Lua environment; see below.\cr
+}\smallskip
+
+Now that you have your own instance, you can run chunks of metapost code in it
+with ⟦*\runmetapost \id { code }⟧. Any images that your code may have contained
+will have to be extracted explicitly. This is possible in a number of ways,
+although each image can be retrieved only once.
+
+⟦*\getnextmpimage \id⟧
+– Writes the first unretrieved image to the current node list.
+There, the image will be contained in a single box node.
+
+⟦*\getnamedmpimage \id {name}⟧
+– Retrieves an image by name
+regardless of its position,
+and writes it to the current node list.
+
+⟦*\boxnextmpimage \id box-nr⟧
+– Puts the next unretrieved image in box ⟦box-nr⟧. The number may be anything
+tex can parse as a number.
+
+⟦*\boxnamedmpimage \id box-nr {name}⟧
+– Puts the image named ⟦name⟧ in box ⟦box-nr⟧.
+
+Say ⟦*\remainingmpimages \id⟧ for the number of images not yet retrieved.
+Finally, as a shorthand, ⟦*\runmetapostimage \id { code }⟧ will add
+⟦beginfig ... endfig⟧ to your ⟦code⟧ and write the resulting image immediately
+to the current list.
+
+
+\section Running tex from within metapost % 1
+
+You can include tex snippets with either ⟦*maketext "tex text"⟧ or
+⟦*btex ... etex⟧ statements. The tex code will be executed in the current
+environment without an extra grouping level. The result of either statement at
+the place where it is invoked is an image object of the proper dimensions that
+can be moved, scaled, rotated and mirrored. You can even specify a colour. Its
+contents, however, will only be added afterwards and are invisible to metapost.
+
+Arbitrary tex statements may be included in ⟦*verbatimtex ... etex⟧, which may
+occur anywhere. These ⟦btex⟧ and ⟦verbatimtex⟧ statements are executed in the
+order they are given.
+
+You can also use metapost’s ⟦*infont⟧ operator, which restricts the text
+to-be-typeset to a single font, but returns an ⟦picture⟧ containing a ⟦picture⟧
+for each character. The right-hand argument of ⟦infont⟧ should either be
+a (numerical) font id or the (cs)name of a font.
+
+One possible use of the ⟦infont⟧ operator is setting text along curves:
+
+⟦beginfig(1)
+ save t, w, r, a; picture t;
+ t = "Running TeX from within MetaPost" infont "tenrm";
+ w = xpart lrcorner t = 3.141593 r;
+ for c within t :
+ x := xpart (llcorner c + lrcorner c)/2;
+ a := 90 - 180 x/w;
+ draw c rotatedaround((x,0), a)
+ shifted (-r*sind(a)-x, r*cosd(a));
+ endfor
+endfig;⟧
+\vskip-2\parskip plus 2\parskip
+\quitvmode\hfil
+\startelement alt {The text ‘Running TeX from within MetaPost’ set along a half-circle.} {Figure}%
+\stoptagging\directmetapost{%
+beginfig(1)
+ save t, w, r, a; picture t;
+ t = "Running TeX from within MetaPost" infont "tenrm";
+ w = xpart lrcorner t = 3.141593 r;
+ for c within t :
+ x := xpart (llcorner c + lrcorner c)/2;
+ a := 90 - 180 x/w;
+ draw c rotatedaround((x,0), a)
+ shifted (-r*sind(a)-x, r*cosd(a));
+ endfor
+endfig;}\starttagging \stopelement{Figure}
+
+\section Running lua from within metapost % 1
+
+You can call out to lua with ⟦*runscript "lua code"⟧. For this purpose, each
+metapost instance carries around its own lua environment so that assignments
+you make are local to the instance. (You can of course order the global
+environment to be used by giving ⟦env = _G⟧ as option to
+⟦\newmetapostinstance⟧.)
+
+If your lua snippet returns nothing, the ⟦runscript⟧ call will be invisible to
+metapost. If on the other hand it does return a value, that value will have to
+be translated to metapost. Numbers and strings will be returned as they are
+(so make sure the string is surrounded by quotes if you want to return
+a metapost string). You can return a point or colour by returning an array of
+two to four elements. For other return values, ⟦tostring()⟧ will be called.
+
+Do keep in mind that metapost and lua represent numbers in different ways and
+that rounding errors may occur. For instance, metapost’s ⟦decimal epsilon⟧
+returns ⟦0.00002⟧, which metapost understands as ⟦1/65536⟧, but lua as
+⟦1/50000⟧. Use the metapost macro ⟦*hexadecimal⟧ instead of ⟦decimal⟧ for
+passing unambiguous numbers to lua.
+
+Additionally, you should be aware that metapost uses slightly bigger points
+than tex, so that ⟦epsilon⟧ when taken as a dimension is not quite equal to
+⟦1sp⟧. Use the metapost macro ⟦*scaledpoints⟧ for passing to lua a metapost
+dimension as an integral number of scaled points.
+
+
+\section Tiling patterns % 1
+
+The ⟦*withpattern(<name>)⟧ added to a ⟦fill⟧ statement will fill the path with
+a pattern instead of a solid colour. If the patterns contains no colour
+information of itself, it will have the colour given by ⟦withcolor⟧.
+Stroking operations (the ⟦draw⟧ part) will not be affected.
+Patterns will always look the same, irrespective of any transformations you
+apply to the picture.
+
+To define a pattern, sketch it between
+⟦*beginpattern(<name>) ... endpattern(xstep, ystep);⟧
+where ⟦<name>⟧ is a suffix and ⟦(xstep, ystep)⟧ are the horizontal and vertical
+distances between applications of the pattern.
+Inside the definition, you can draw the pattern using whatever coordinates you
+like; assign a value to the ⟦*matrix⟧ transformation to specify how the pattern
+should be projected onto the page. This ⟦matrix⟧ will also be applied to
+⟦xstep⟧ and ⟦ystep⟧.
+
+You can also change the internal variable ⟦*tilingtype⟧ and the normal variable
+⟦*painttype⟧, although the latter will be set to~1 automatically if you use any
+colour inside the pattern definition. Consult the pdf specification for more
+information on these parameters.
+
+You can use text inside patterns, as in this example:
+\hfill \vbox to 0pt{
+\startelement alt{A circle filled with red As in a rectangular pattern.}{Figure}
+\directmetapost{
+% define the pattern
+picture letter; letter = maketext("a");
+beginpattern(a)
+ draw letter rotated 45;
+ matrix = identity rotated 45;
+endpattern(12pt,12pt);
+% use the pattern
+beginfig(1)
+ fill fullcircle scaled 3cm withpattern(a) withcolor 3/4red;
+ draw fullcircle scaled 3cm withpen pencircle scaled 1;
+endfig;}\stopelement{Figure}\vss}\hskip10pt\strut
+
+⟦% define the pattern
+picture letter; letter = maketext("a");
+beginpattern(a)
+ draw letter rotated 45;
+ matrix = identity rotated 45;
+endpattern(12pt,12pt);
+% use the pattern
+beginfig(1)
+ fill fullcircle scaled 3cm withpattern(a) withcolor 3/4red;
+ draw fullcircle scaled 3cm withpen pencircle scaled 1;
+endfig;⟧
+
+A small pattern library is available in the ⟦*minim-hatching.mp⟧ file; see the
+accompanying documentation sheet for an overview of patterns.
+Tiling patterns cannot be used together with tikz/pgf; see below under
+‘Resource management’.
+
+
+\section Other metapost extensions % 1
+
+There is currently no support for the ⟦*glyph of⟧ operator.
+
+You can set the baseline of an image with ⟦*baseline(p)⟧. There, ⟦p⟧ must
+either be a point through which the baseline should pass, or a number (where an
+x~coordinate of zero will be added). Transformations will be taken into
+account, hence the specification of two coordinates. The last given baseline
+will be used.
+
+Previously-defined box resources can be included with ⟦*boxresource(nr)⟧. The
+result will be an image object with the proper dimensions. This image can be
+transformed in any way you like, but you cannot inspect the contents of the
+resource within metapost.
+
+You can write to tex’s log directly with ⟦*texmessage "hello"⟧.
+
+You can write direct pdf statements with ⟦*special "pdf: statements"⟧ and you
+can add comments to the pdf file with ⟦*special "pdfcomment: comments"⟧.
+Say ⟦*special "latelua: lua code"⟧ to insert a ⟦late_lua⟧ whatsit.
+All three specials can also be given as pre- or postscripts to another object.
+In that case, they will be added before or after the object they are attached to.
+
+
+\section Lua interface % 1
+
+In what follows, you should assume ⟦M⟧ to be the result of
+\stopformulatagging$$\hbox{⟦M = require('minim-mp')⟧}$$\startformulatagging
+as this package does not claim a table in the global environment for itself.
+
+You can open a new instance with ⟦*nr = M.open {options}⟧.
+This returns an index in the ⟦*M.instances⟧ table.
+Run code with ⟦*M.run (nr, code)⟧ and close the instance with ⟦*M.close (nr)⟧.
+Images can be retrieved only with ⟦*box_node = M.get_image(nr, [name])⟧; omit
+the ⟦name⟧ to select the first image.
+Say ⟦*nr_remaining = M.left(nr)⟧ for the number of remaining images.
+
+Each metapost instance is a table containing the following entries:
+
+\smallskip\smallskip
+\marktableaslist \halign{\qquad#\quad\hfil&#\hfil\cr
+⟦jobname⟧&The jobname.\cr
+⟦instance⟧&The primitive metapost instance.\cr
+⟦results⟧&A linked list of unretrieved images.\cr
+⟦status⟧&The last exit status (will never decrease).\cr
+⟦catcodes⟧&Number of the catcode table used with ⟦btex ... etex⟧.\cr
+⟦env⟧&The lua environment for ⟦runscript⟧.\cr}
+
+
+\section PDF resource management % 1
+
+This package can add ⟦/Pattern⟧ and ⟦/ColorSpace⟧ entries to all page and xform
+resource dictionaries.
+Both refer to a single, global dictionary shared by all pages.
+Support for other keys may be added in the future.
+
+At the moment, this implementation only serves tiling pattern support;
+the mechanism will be enabled automatically at the first use of a tiling
+pattern (merely defining a pattern will not enable it) and is of little use for
+anything else.
+The relevant tables, should you want to expand on it yourself, are
+⟦M.colourspaces⟧ and ⟦M.patterns⟧; see the source file for additional
+instructions.
+
+Since pdf resource management must be done exactly once, this package may clash
+with other graphics packages doing the same.
+In particular, minim’s resource management will cause double (and thus invalid)
+entries in pages’ attribute dictionaries when used together with \red{tikz} or
+\red{pgf}.
+They can be used together, however, if you do not use minim’s tiling patterns.
+
+
+\section Debugging % 1
+
+You can enable (global) debugging by saying ⟦*debug_pdf⟧ to metapost or
+⟦*M.enable_debugging()⟧ to lua. This will write out a summary of metapost
+object information to the pdf file, just above the pdf instructions that object
+was translated into. For this purpose, the pdf will be generated uncompressed.
+Additionally, a small summary of every generated image will be written to log
+and terminal.
+
+
+\section Extending metapost % 1
+
+You can extend this package by adding new metapost specials. Specials should
+have the form ⟦"identifier: instructions"⟧ and can be added as pre- or
+postscript to metapost objects. A single object can carry multiple specials and a
+⟦*special "..."⟧ statement is equivalent to an empty object with a single
+prefix.
+
+Handling of specials is specified in three lua tables: ⟦*M.specials⟧,
+⟦*M.prescripts⟧ and ⟦*M.postscripts⟧.
+The ⟦identifier⟧ above should equal the key of an entry in the relevant table,
+while the value of an entry in one of these tables should be a function with
+three parameters: the internal image processor state, the ⟦instructions⟧ from
+above and the metapost object itself.
+
+If the ⟦identifier⟧ of a prescript is present in the first table, the
+corresponding function will replace normal object processing.
+Only one prescript may match with this table.
+Functions in the the other two tables will run before or after normal
+processing.
+
+Specials can store information in the ⟦user⟧ table of the picture that is being
+processed; this information is still available inside the ⟦*finish_mpfigure⟧
+callback that is executed just before the processed image is surrounded by
+properly-dimensioned boxes.
+
+The ⟦*M.init_files⟧ table contains the list of metapost files that new instances
+are initialised with.
+The actual format will be loaded after the files in this table.
+
+\endmanual %
+
diff --git a/macros/luatex/generic/minim-mp/minim-mp.ini b/macros/luatex/generic/minim-mp/minim-mp.ini
new file mode 100644
index 0000000000..a257f6a18a
--- /dev/null
+++ b/macros/luatex/generic/minim-mp/minim-mp.ini
@@ -0,0 +1,17 @@
+
+\catcode`\{=1 \catcode`\}=2
+\def\fmtname{minim-mp}
+\def\fmtversion{2021/1.0}
+
+\input minim.ini
+
+\toksapp\everyjob{%
+ \message{This is the minim metapost processor.}\relax
+ \newmetapostinstance[jobname="\jobname", mathmode="scaled"]\MP
+ \runmetapost\MP{input "\jobname";}%
+ \directlua {require('minim-mp').shipout(\the\MP)}%
+ \closemetapostinstance\MP
+ \bye}
+
+\dump
+
diff --git a/macros/luatex/generic/minim-mp/minim-mp.lua b/macros/luatex/generic/minim-mp/minim-mp.lua
new file mode 100644
index 0000000000..0f1851eba0
--- /dev/null
+++ b/macros/luatex/generic/minim-mp/minim-mp.lua
@@ -0,0 +1,1282 @@
+
+local alloc = require ('minim-alloc')
+local cb = require('minim-callbacks')
+alloc.remember ('minim-mp')
+
+local M = {}
+
+-- 1 AUXILIARY FUNCTIONS
+
+-- 2 pdf resource management
+
+-- We add /ColorSpace and /Pattern entries to all page and xform resources.
+-- Each key refers to a central (global) object mapping names to objects. This
+-- central dictionary will be written to the pdf inside the finish_pdffile
+-- callback.
+--
+-- In the future, /Shading and /ExtGState may also be added.
+--
+-- Central resource dictionaries and all used resources will be written to the
+-- pdf inside the finish_pdf callback.
+--
+-- Since a resource dictionary can only contain one entry of each kind, this
+-- package cannot coëxist with other packages doing their own resource
+-- management. I am aware of only one other package doing that, however, which
+-- is pgf. Luckily, pgf users are unlikely to be interested in metapost. Due to
+-- this incompatibility, however, resource management must be enabled
+-- explicitly.
+
+-- keys are pdf names (starting with a slash)
+local patterns = { }; M.patterns = patterns
+local colourspaces = { }; M.colourspaces = colourspaces
+
+local global_resources, pattern_dict_objnum, colourspace_dict_objnum
+function M.enable_resource_management()
+ if global_resources then return end
+ -- central dictionary objects
+ pattern_dict_objnum = pdf.reserveobj()
+ colourspace_dict_objnum = pdf.reserveobj()
+ global_resources = string.format('/Pattern %d 0 R /ColorSpace %d 0 R',
+ pattern_dict_objnum, colourspace_dict_objnum)
+ -- add to page and xform resources
+ pdf.setpageresources((pdf.getpageresources() or '')..global_resources)
+ pdf.setxformresources((pdf.getxformresources() or '')..global_resources)
+end
+
+-- Saved patterns should have the following fields:
+-- objnum the reserved object number for the pattern (optional)
+-- used true if the pattern is in use (should be set automatically)
+-- attr the pattern attributes
+-- stream the pattern drawing statements
+-- painttype the paint type of the pattern (1 or 2)
+-- Saved colour spaces should have the following fields:
+-- objnum the reserved object number for the colour space (optional)
+-- used true if the pattern is in use (should be set automatically)
+-- content the colour space contents (a pdf array)
+
+function M.write_resources()
+ if not global_resources then return end
+ -- patterns
+ local used_patterns = { '<<' }
+ for name, pat in pairs(patterns) do
+ if pat.used then
+ local objnum = pat.objnum or pdf.reserveobj()
+ pdf.immediateobj(objnum, 'stream', pat.stream, pat.attr)
+ table.insert(used_patterns, string.format('%s %d 0 R', name, objnum))
+ end
+ end
+ table.insert(used_patterns, '>>')
+ pdf.immediateobj(pattern_dict_objnum, table.concat(used_patterns, ' '))
+ -- colour spaces
+ local used_spaces = { '<<' }
+ for name, space in pairs(colourspaces) do
+ if space.used then
+ local objnum = space.objnum or pdf.reserveobj()
+ pdf.immediateobj(objnum, space.content)
+ table.insert(used_spaces, string.format('%s %d 0 R', name, objnum))
+ end
+ end
+ table.insert(used_spaces, '>>')
+ pdf.immediateobj(colourspace_dict_objnum, table.concat(used_spaces, ' '))
+end
+
+-- Write out resource objects at the end of the run
+cb.register('finish_pdffile', M.write_resources)
+
+-- 2 state metatable
+
+-- q Q store/restore graphics state
+
+-- In what follows, ‘append’ is a structure that contains a (tex) node list
+-- that will become the picture that is being constructed and an internal
+-- graphics state.
+--
+-- We can call append:somefunction(...) to append a node or append:somevariable
+-- to query the graphics state. These go via its metatable:
+
+local A = { } -- appending functions
+local append_meta =
+{
+ -- Either return an appending function or an entry in the graphics state.
+ __index = function(table, key)
+ return A[key] or table.state[#table.state][key]
+ end,
+ __newindex = function(table, key, value)
+ table.state[#table.state][key] = value
+ end
+}
+
+local function init_append()
+ return setmetatable({
+ head = false, tail = false, -- node list
+ baseline = false, -- internal state
+ node_count = 0, -- node count
+ state = { }, -- graphics state variables
+ user = { }, -- user data for extensions
+ }, append_meta)
+end
+
+function A.node(append, nd)
+ append.node_count = append.node_count + 1
+ append.head, append.tail = node.insert_after(append.head or nil, append.tail or nil, nd)
+end
+
+function A.save(append)
+ local st = append.state[#append.state] or { }
+ append.state[#append.state+1] =
+ {
+ miterlimit = st.miterlimit,
+ linejoin = st.linejoin,
+ linecap = st.linecap,
+ dashed = st.dashed,
+ stroke = st.stroke,
+ fill = st.fill
+ }
+ append:node(node.new(8, 30)) -- q
+end
+
+function A.restore(append)
+ append.state[#append.state] = nil
+ append:node(node.new(8, 31)) -- Q
+end
+
+-- The following callback is executed just before the final step of surrounding
+-- the image in properly-dimensioned boxes. It receives the processed image
+-- object as argument. That object has the following fields:
+-- head the head of the node list
+-- name the image name
+-- user the image user table
+-- wd, ht, dp tex dimensions
+-- x0, y0 position of (0,0) w.r.t. tex dimension
+-- bbox original metapost bounding box
+-- discard whether not to save this image
+cb.new_callback('finish_mpfigure', 'simple')
+
+-- 2 debugging
+
+local debugging = false
+
+function M.enable_debugging()
+ debugging = true
+ pdf.setcompresslevel(0)
+end
+
+local function print_prop(append, obj, prop)
+ if obj[prop] then
+ local val = string.gsub(tostring(obj[prop]), '\r', '<CR>')
+ append:literal('%% %s: %s', prop, val)
+ end
+end
+
+local function print_multi(append, obj, prop)
+ if obj[prop] then
+ local x = ''
+ for i = 1,#obj[prop] do
+ x = x .. tostring(obj[prop][i])..' '
+ end
+ append:literal('%% %s: %s', prop, x)
+ end
+end
+
+local function print_knots(append, obj, ptype)
+ if obj[ptype] then
+ append:literal('%% %s: see below', ptype)
+ for i = 1, #obj[ptype] do
+ local a,b = obj[ptype][i].left_type or 'joined', obj[ptype][i].right_type or 'joined'
+ append:literal('%% -+- knot: %s-%s', a, b)
+ append:literal('%% | x_coord: %s', tostring(obj[ptype][i].x_coord))
+ append:literal('%% | y_coord: %s', tostring(obj[ptype][i].y_coord))
+ append:literal('%% | right_x: %s', tostring(obj[ptype][i].right_x))
+ append:literal('%% | right_y: %s', tostring(obj[ptype][i].right_y))
+ append:literal('%% | left_x: %s', tostring(obj[ptype][i].left_x))
+ append:literal('%% | left_y: %s', tostring(obj[ptype][i].left_y))
+ end
+ end
+end
+
+function A.printobj(append, obj)
+ if not debugging then return end
+ local nc = append.node_count
+ append:literal('%%Object Type: %s', obj.type)
+ print_prop(append, obj, 'text')
+ print_prop(append, obj, 'font')
+ print_prop(append, obj, 'dsize')
+ print_prop(append, obj, 'width')
+ print_prop(append, obj, 'height')
+ print_prop(append, obj, 'depth')
+ print_multi(append, obj, 'transform')
+ print_multi(append, obj, 'color')
+ print_knots(append, obj, 'path')
+ print_knots(append, obj, 'htap')
+ if obj.pen then
+ local x = obj.pen.type or 'not elliptical'
+ append:literal('%% pen: see below, form: %s', x)
+ local x = mplib.pen_info(obj)
+ append:literal('%% | width: %s', tostring(x.width))
+ append:literal('%% | sx: %s', tostring(x.sx))
+ append:literal('%% | sy: %s', tostring(x.sy))
+ append:literal('%% | rx: %s', tostring(x.rx))
+ append:literal('%% | ry: %s', tostring(x.ry))
+ append:literal('%% | tx: %s', tostring(x.tx))
+ append:literal('%% | ty: %s', tostring(x.ty))
+ print_knots(append, obj, 'pen')
+ end
+ if obj.dash then
+ local d = ''
+ for i = 1,#obj.dash.dashes do
+ d = d ..tonumber(obj.dash.dashes[i]).. ' '
+ end
+ append:literal('%% dashes: %s', d)
+ append:literal('%%dash offset: %s', tostring(obj.dash.offset))
+ end
+ print_prop(append, obj, 'prescript')
+ print_prop(append, obj, 'postscript')
+ print_prop(append, obj, 'miterlimit')
+ print_prop(append, obj, 'linejoin')
+ print_prop(append, obj, 'linecap')
+ append.node_count = nc
+end
+
+-- 2 pdf literal helpers
+
+local function format_numbers(...)
+ return (string.format(...)
+ :gsub('[.]0+ ', ' ')
+ :gsub('([.][1-9]+)0+ ', '%1 '))
+end
+
+-- Only to be used for coordinates: ‘cm’ parameters should not be rounded.
+local function pdfnum(operator, ...)
+ local fmt = string.format('%%.%sf %s', pdf.getdecimaldigits(), operator)
+ return format_numbers(fmt, ...)
+end
+
+local function point_fmt(operator, ...)
+ local dd = pdf.getdecimaldigits()
+ local fmt = string.format('%%.%sf %%.%sf %s', dd, dd, operator)
+ return format_numbers(fmt, ...)
+end
+
+local function bbox_fmt(...)
+ local dd = pdf.getdecimaldigits()
+ local fmt = string.format('/BBox [ %%.%sf %%.%sf %%.%sf %%.%sf ]', dd, dd, dd, dd)
+ return format_numbers(fmt, ...)
+end
+
+local function curve_fmt(...)
+ local dd = pdf.getdecimaldigits()
+ local fmt = string.format('%%.%sf %%.%sf %%.%sf %%.%sf %%.%sf %%.%sf c', dd, dd, dd, dd, dd, dd)
+ return format_numbers(fmt, ...)
+end
+
+function A.literal(append, fmt, ...)
+ local lit = node.new(8,16)
+ lit.data = fmt:format(...)
+ append:node(lit)
+end
+
+-- 2 colour conversion
+
+local function rgb_to_gray (r,g,b)
+ return ( tex.count['RtoG'] * r / 10000
+ + tex.count['GtoG'] * g / 10000
+ + tex.count['BtoG'] * b / 10000 )
+end
+
+local function cmyk_to_rgb (c,m,y,k)
+ return (1-k)*(1-c), (1-k)*(1-m), (1-k)*(1-y)
+end
+
+local function rgb_to_cmyk (r, g, b)
+ local k = 1 - math.max(r, g, b)
+ if k == 1 then
+ return 0, 0, 0, k
+ else
+ return (1-r-k)/(1-k), (1-g-k)/(1-k), (1-b-k)/(1-k), k
+ end
+end
+
+local function convert_colour(cr)
+ -- always write rgb or cmyk black as grayscale
+ if cr[1] == 0 and cr[2] == 0 and cr[3] == 0
+ and (cr[4] == 1 or not cr[4]) then
+ return { 0 }
+ end
+ -- see if we must convert to another colour space
+ local n = #cr
+ local convert = tex.count['convertmpcolours']
+ if convert == 1 then
+ if n == 3 then
+ return { rgb_to_gray(table.unpack(cr)) }
+ elseif n == 4 then
+ return { rgb_to_gray(cmyk_to_rgb(table.unpack(cr))) }
+ end
+ elseif convert == 3 and n == 4 then
+ return { cmyk_to_rgb(table.unpack(cr)) }
+ elseif convert == 4 and n == 3 then
+ return { rgb_to_cmyk(table.unpack(cr)) }
+ end
+ -- otherwise return the colour unchanged
+ return cr
+end
+
+-- 2 colour literals
+
+-- MetaPost supports colour models with 1, 3 or 4 parameters. The corresponding
+-- pdf operators are
+
+-- RG rg RGB colour model for stroke/filling
+-- K k CMYK colour model for stroke/filling
+-- G g Grayscale colour model for stroke/filling
+
+-- ... CS cs select colourspace for stroke/filling
+-- ... SCN scn select colour in colourspace for stroke/filling
+
+-- In order to prevent duplicate colour settings, ‘append’ contains the state
+-- variables ‘stroke’ and ‘fill’ that record the last-used colour settings.
+
+-- preload device colour pattern colour spaces
+colourspaces['/PsG'] = { content = '[ /Pattern /DeviceGray ]' }
+colourspaces['/PsRG'] = { content = '[ /Pattern /DeviceRGB ]' }
+colourspaces['/PsK'] = { content = '[ /Pattern /DeviceCMYK ]' }
+
+local colour_template = { '%.3f ', '%.3f %.3f ', '%.3f %.3f %.3f ', '%.3f %.3f %.3f %.3f ' }
+local colour_stroke_operators = { 'G', nil, 'RG', 'K' }
+local colour_fill_operators = { 'g', nil, 'rg', 'k' }
+local colour_pattern_spaces = { '/PsG', nil, '/PsRG', '/PsK' }
+
+local function get_colour_params(cr)
+ return format_numbers(colour_template[#cr], table.unpack(cr))
+end
+
+local function get_stroke_colour(cr)
+ return get_colour_params(cr)..colour_stroke_operators[#cr]
+end
+
+local function get_fill_colour(cr, pattern)
+ local params = get_colour_params(cr)
+ if pattern then
+ local ptype, pname = table.unpack(pattern)
+ if ptype == 2 then -- coloured pattern
+ local space = colour_pattern_spaces[#cr]
+ colourspaces[space].used = true
+ return string.format('%s cs %s%s scn', space, params, pname)
+ elseif ptype == 1 then -- uncoloured pattern
+ return string.format('/Pattern cs %s scn', pname)
+ else -- should be unreachable
+ alloc.err('Unknown pattern paint type %s', ptype)
+ end
+ end
+ return params..colour_fill_operators[#cr]
+end
+
+-- TODO We should allow the user access to the internals here, so that support
+-- for other colour spaces may be added. Then, pattern support could also be
+-- moved into a plugin.
+function A.colour(append, cr, otype)
+ if cr and #cr > 0 then
+ cr = convert_colour(cr)
+ -- stroke colour
+ if otype ~= 'fill' then
+ local stroke = get_stroke_colour(cr)
+ if stroke ~= append.stroke then
+ append.stroke = stroke
+ append:literal(stroke)
+ end
+ end
+ -- fill colour (possibly a pattern)
+ if otype ~= 'outline' then
+ local fill = get_fill_colour(cr, append.pattern)
+ append.pattern = nil -- patterns only apply to one object
+ if fill ~= append.fill then
+ append.fill = fill
+ append:literal(fill)
+ end
+ end
+ end
+end
+
+-- 2 stroke setting literals
+
+-- M miterlimit
+-- j linejoin
+-- J linecap
+-- d dash
+
+-- As with colour, we record the last-used settings in ‘append’. This function
+-- is only called for fill/outline objects.
+
+function A.linestate (append, object)
+ local ml = object.miterlimit
+ local res = { }
+ if ml and ml ~= append.miterlimit then
+ append.miterlimit = ml
+ table.insert(res, pdfnum('M', ml)) -- TODO is pdfnum here correct?
+ end
+ local lj = object.linejoin
+ if lj and lj ~= append.linejoin then
+ append.linejoin = lj
+ table.insert(res, string.format('%i j', lj))
+ end
+ local lc = object.linecap
+ if lc and lc ~= append.linecap then
+ append.linecap = lc
+ table.insert(res, string.format('%i J', lc))
+ end
+ local dl = object.dash
+ if dl then
+ local d = string.format('[%s] %i d', table.concat(dl.dashes or {},' '), dl.offset)
+ if d ~= append.dashed then
+ append.dashed = d
+ table.insert(res, d)
+ end
+ elseif append.dashed then
+ append.dashed = false
+ table.insert(res, string.format('[] 0 d'))
+ end
+ append:literal(table.concat(res, ' '))
+end
+
+-- 2 path literals
+
+-- MetaPost only gives us curved lines; if some of the segments are straight,
+-- we have to find out ourselves:
+
+local bend_tolerance = 131/65536 -- context uses this value, presumably with good reasons
+
+local function curved (a,b)
+ local d = b.left_x - a.right_x
+ if math.abs(a.right_x - a.x_coord - d) <= bend_tolerance
+ and math.abs(b.x_coord - b.left_x - d) <= bend_tolerance then
+ d = b.left_y - a.right_y
+ if math.abs(a.right_y - a.y_coord - d) <= bend_tolerance
+ and math.abs(b.y_coord - b.left_y - d) <= bend_tolerance then
+ return false
+ end
+ end
+ return true
+end
+
+-- Write the path as list of points.
+
+-- m move to this point without drawing anything
+-- c make a curved line (two control points)
+-- l make a straight line
+
+function A.curve(append, path, open, concat)
+ -- The ‘concat’ function transforms the given coordinate pairs
+ -- according to the current transformation.
+ concat = concat or function(px, py) return px, py end
+ local res = { }
+ local append_line = function(to, op)
+ table.insert(res, point_fmt(op, concat(to.x_coord, to.y_coord)))
+ end
+ local append_curve = function(from, to)
+ local a, b = concat(from.right_x, from.right_y)
+ local c, d = concat(to.left_x, to.left_y)
+ table.insert(res, curve_fmt(a,b,c,d,concat(to.x_coord, to.y_coord)))
+ end
+ local append_knot = function(from, to)
+ if not from then
+ append_line(to, 'm')
+ elseif curved(from, to) then
+ append_curve(from, to)
+ else
+ append_line(to, 'l')
+ end
+ end
+ local knot, prev_knot
+ for i=1, #path do
+ knot = path[i]
+ append_knot(prev_knot, knot)
+ prev_knot = knot
+ end
+ if not open then
+ append_knot(knot, path[1])
+ elseif #path == 1 then
+ append_line(path[1], 'l') -- special case: draw a point
+ end
+ append:literal(table.concat(res, ' '))
+end
+
+-- And actually draw the path.
+
+-- S draw the path
+-- h close the path
+-- s close and draw the path (equivalent to h S)
+-- f fill the path (implies h)
+-- b close, fill and draw the path (equivalent to h B)
+-- n do nothing (used for clipping paths)
+
+local function get_path_operator (otype, open)
+ if otype == 'fill' then
+ return 'f'
+ elseif otype == 'outline' then
+ return (open and 'S') or 's'
+ elseif otype == 'both' then
+ return 'b'
+ end
+end
+
+--
+
+-- 1 PROCESSING OBJECTS
+
+-- Our processors are located in two tables: one that contains a processor for
+-- each object and one that contains processors for certain ‘special’ statements. Every
+-- table contains functions that take the ‘append’ structure and the current
+-- object as arguments. The tables are indexed by object/special name.
+
+-- The treatment of pre- and postscripts is like this:
+-- * Pre- and postscripts should be of the form ‘type: instruction’.
+-- * If the type of a prescript is present in the ‘specials’ table, the
+-- corresponding function will be used in place of the default handling.
+-- * Execution of other prescripts and of all postscripts will be given by the
+-- entries in the ‘prescripts’ and ‘postscripts’ table corresponding to the
+-- type.
+
+local process = {}
+local specials = {}
+M.specials = specials
+
+local prescripts = {}
+local postscripts = {}
+M.prescripts = prescripts
+M.postscripts = postscripts
+
+-- 2 choosing a parser
+
+local function split_specials(specials)
+ if not specials then return function() return end end
+ local l = specials:explode('\r')
+ local i, n = 0, #l
+ return function()
+ if i < n then i = i + 1 else return end
+ local sp, instr = l[i]:match('^([a-zA-Z_]+): *(.*)')
+ return sp, instr or l[i]
+ end
+end
+
+local function parse_object (append, object)
+ append:printobj(object)
+ local processor = nil
+ for sp, instr in split_specials(object.prescript) do
+ if not sp then
+ alloc.err('Unrecognised prescript: %s', instr)
+ append:literal('%% unsupported special excluded (see log file)')
+ elseif specials[sp] then
+ processor = function() specials[sp](append, instr, object) end
+ elseif prescripts[sp] then
+ prescripts[sp](append, instr, object)
+ else
+ alloc.err('Unrecognised prescript ‘%s’ with instruction: %s', sp, instr)
+ append:literal('%% unsupported special excluded (see log file)')
+ end
+ end
+ if processor then
+ processor()
+ else
+ process[object.type](append, object)
+ end
+ for sp, instr in split_specials(object.postscript) do
+ if not sp then
+ alloc.err('Unrecognised postscript: %s', instr)
+ append:literal('%% unsupported special excluded (see log file)')
+ elseif postscripts[sp] then
+ postscripts[sp](append, instr, object)
+ else
+ alloc.err('Unrecognised postscript ‘%s’ with instruction: %s', sp, instr)
+ append:literal('%% unsupported special excluded (see log file)')
+ end
+ end
+end
+
+-- 2 start/stop bounds
+
+-- These can be ignored, because they are taken into account by MetaPost when
+-- it reports the bounding box of the picture.
+
+process.start_bounds = function(append, object) end
+process.stop_bounds = function(append, object) end
+
+-- 2 clipping
+
+-- W clipping operator
+-- n path no-op
+
+process.start_clip = function(append, object)
+ append:save()
+ append:curve(object.path, false)
+ append:literal('W n')
+end
+
+process.stop_clip = function(append, object)
+ append:restore()
+end
+
+-- 2 fill and outline
+
+function A.set_pen(append, object, otype, open)
+ if object.pen and object.pen.type == 'elliptical' then
+ -- metapost includes nonelliptical pens in the outline
+ local t = mplib.pen_info(object)
+ append:literal(pdfnum('w', t.width))
+ if otype == 'fill' then otype = 'both' end
+ local transformed = not ( t.sx == 1 and t.rx == 0
+ and t.ry == 0 and t.sy == 1
+ and t.tx == 0 and t.ty == 0 )
+ return transformed and t, get_path_operator(otype, open), otype
+ else
+ return false, get_path_operator(otype, open), otype
+ end
+end
+
+process.fill_or_outline = function(append, object, otype)
+ local open = object.path
+ and object.path[1].left_type
+ and object.path[#object.path].right_type
+ local t, operator, otype = append:set_pen(object, otype, open)
+ append:colour(object.color, otype)
+ append:linestate(object)
+ local appendpath
+ if t then
+ local d = t.sx * t.sy - t.rx - t.ry
+ local concat = function(px, py)
+ return (t.sy*px - t.ry*py)/d, (t.sx*py - t.rx*px)/d
+ end
+ appendpath = function(path)
+ append:save()
+ append:literal('%f %f %f %f %f %f cm', t.sx, t.rx, t.ry, t.sy, t.tx, t.ty)
+ append:curve(path, open, concat)
+ append:literal(operator)
+ append:restore()
+ end
+ else
+ appendpath = function(path)
+ append:curve(path, open)
+ append:literal(operator)
+ end
+ end
+ if object.path then appendpath(object.path) end
+ if object.htap then appendpath(object.htap) end -- reversed trajectory
+end
+
+process.fill = function(append, object)
+ process.fill_or_outline(append, object, 'fill')
+end
+
+process.outline = function(append, object)
+ process.fill_or_outline(append, object, 'outline')
+end
+
+-- 2 specials
+
+-- pure specials are already taken care of in parse_object (they only have
+-- a ‘prescript’ field).
+process.special = function(append, object) end
+
+prescripts.pdf = function(append, special, object)
+ append:literal(special)
+end
+postscripts.pdf = prescripts.pdf
+
+prescripts.pdfcomment = function(append, str, object)
+ append:literal('%% %s', str)
+end
+postscripts.pdfcomment = prescripts.pdfcomment
+
+prescripts.latelua = function(append, str, object)
+ local n = node.new(8,7) -- late_lua
+ n.data = str
+ append:node(n)
+end
+postscripts.latelua = prescripts.latelua
+
+specials.BASELINE = function(append, str, object)
+ -- object is a ‘fill’ statement with only a single point in its path (and
+ -- will thus not have to be transformed).
+ append.baseline = object.path[1].y_coord
+end
+
+-- 2 patterns
+
+prescripts.fillpattern = function(append, str, object)
+ M.enable_resource_management()
+ local name = '/MnmP'..tonumber(str)
+ local pat = patterns[name]
+ if not pat then
+ alloc.err('Unknown pattern %s', name)
+ else
+ append.pattern = { pat.painttype, name }
+ pat.used = true
+ end
+end
+
+specials.definepattern = function(append, str, object)
+ local nr, tiling, paint, xs, ys, xx, xy, yx, yy = table.unpack(str:explode())
+ append.user.pattern_info = { nr = nr, xstep = xs, ystep = ys,
+ tilingtype = tiling, painttype = paint,
+ matrix = { xx = xx, xy = xy, yx = yx, yy = yy, x = 0, y = 0 } }
+end
+
+local function definepattern(head, user, bb)
+ local bb = bbox_fmt(table.unpack(bb))
+ local pat, literals, resources = { }, { }
+ -- pattern content
+ for n in node.traverse(head) do
+ -- try if we can construct the content stream ourselves; otherwise,
+ -- stuff the pattern template into an xform.
+ if n.id == 8 then
+ -- try if we can simply concatenate pdf statements
+ if n.subtype == 16 then -- literal
+ table.insert(literals, n.data)
+ elseif n.subtype == 30 then -- save
+ table.insert(literals, 'q')
+ elseif n.subtype == 31 then -- restore
+ table.insert(literals, 'Q')
+ else
+ goto fail
+ end
+ end
+ pat.stream = table.concat(literals, '\n')
+ end
+ ::fail:: do
+ -- regrettably, pdf.refobj does not work with xforms, so we must
+ -- write it to the pdf immediately, whether the pattern will be
+ -- used or not.
+ local xform = tex.saveboxresource(node.hpack(node.copy_list(head)),
+ '/Subtype/Form '..bb, resources, true, 4)
+ resources = string.format(' /Resources << /XObject << /PTempl %d 0 R >> >>', xform)
+ pat.stream = '/PTempl Do'
+ end
+ -- construct the pattern object
+ local i = user.pattern_info
+ local m = i.matrix
+ pat.painttype = tonumber(i.painttype)
+ pat.attr = table.concat({
+ string.format(' /PatternType 1 /PaintType %d /TilingType %s /XStep %f /YStep %f\n',
+ i.painttype, i.tilingtype, i.xstep, i.ystep),
+ string.format('%s\n/Matrix [ %s %s %s %s %s %s ]', bb, m.xx, m.xy, m.yx, m.yy, m.x, m.y),
+ resources }, '')
+ -- remember the pattern
+ patterns['/MnmP'..i.nr] = pat
+end
+
+cb.register('finish_mpfigure', function(img)
+ if img.user.pattern_info then
+ definepattern(img.head, img.user, img.bbox)
+ img.discard = true
+ end
+end)
+
+-- 2 text
+
+process.text = function(append, object)
+ alloc.err('Text figure primitives are not supported (this message should not occur)')
+end
+
+local function get_transform(rect)
+ -- reconstruct the applied transformation by examining a unit square, i.e.
+ -- ‘rect’ was originally the path (0,0) -- (0,1) -- (1,1) -- (1,0)
+ local ll, lr, ul = rect[1], rect[2], rect[4]
+ -- determine translation from (0,0)
+ local tx, ty = ll.x_coord, ll.y_coord
+ -- determine rotation and scaling from the diagonals
+ local sx, rx = lr.x_coord - tx, lr.y_coord - ty
+ local ry, sy = ul.x_coord - tx, ul.y_coord - ty
+ return sx, rx, ry, sy, tx, ty
+end
+
+local function make_surrounding(nd_id, head)
+ local nd = node.new(nd_id)
+ nd.dir = 'TLT'
+ nd.head = head
+ return nd
+end
+
+local function apply_translation(box, tx, ty)
+ local horizontal = make_surrounding(0, box)
+ local vertical = make_surrounding(1, horizontal)
+ local outer = make_surrounding(0, vertical)
+ vertical.shift = tex.sp('-'..ty..'bp')
+ horizontal.shift = tex.sp(''..tx..'bp')
+ return outer
+end
+
+local function apply_transform(rect, box)
+ local sx, rx, ry, sy, tx, ty = get_transform(rect)
+ local transform = node.new(8,29)
+ transform.next, box.prev = box, transform
+ transform.data = string.format('%f %f %f %f', sx, rx, ry, sy)
+ return apply_translation(transform, tx, ty)
+end
+
+function A.box(append, object, box)
+ box.width = 0 ; box.height = 0 ; box.depth = 0;
+ local outer = apply_transform(object.path, box)
+ append:colour(object.color, 'fill')
+ append:save()
+ append:node(outer)
+ append:restore()
+end
+
+specials.TEXBOX = function(append, box, object)
+ local box = tex.getbox(tonumber(box))
+ append:box(object, node.copy_list(box))
+end
+
+specials.CHAR = function(append, data, object)
+ local char, font, xo, yo = table.unpack(data:explode(' '))
+ local n = node.new(29)
+ n.char, n.font, n.xoffset, n.yoffset =
+ tonumber(char), tonumber(font), tonumber(xo), tonumber(yo)
+ append:box(object, node.hpack(n))
+end
+
+specials.BOXRESOURCE = function(append, resource, object)
+ local rule = tex.useboxresource(tonumber(resource))
+ append:box(object, rule)
+end
+
+--
+
+-- 1 METAPOST INSTANCES
+
+local instances = { }
+M.instances = instances
+
+-- 2 small instance helper functions
+
+local default_catcodes = alloc.new_catcodetable('minim:mp:catcodes')
+
+-- parameters: wd, ht+dp, dp
+local function make_transform(w, h, d)
+ return string.format('identity xscaled %fpt yscaled %fpt shifted (0,-%fpt)',
+ w/65536, (h+d)/65536, d/65536)
+end
+
+local function print_log (nr, res)
+ local i = instances[nr]
+ -- only write to term if exit status increases
+ local log, alog
+ if res.status > i.status then
+ local nrlines, maxlines = 0, 16
+ alog = alloc.amsg
+ log = function(...)
+ if nrlines == maxlines then
+ alloc.log(...)
+ alloc.term('╧ [... see log file for full report ...]')
+ log, alog = alloc.log, alloc.alog
+ else
+ nrlines = nrlines + 1
+ alloc.msg(...)
+ end
+ end
+ else
+ log, alog = alloc.log, alloc.alog
+ end
+ -- split log into lines; discard empty lines at the end
+ local report = res.log and res.log:explode('\n') or { }
+ while report[#report] == '' do
+ report[#report] = nil
+ end
+ -- write out the log
+ if #report > 0 then
+ log('┌ exit status %d', res.status)
+ for _,line in ipairs(report) do
+ log('│ '..line)
+ end
+ log('└')
+ else
+ log('[ no logs for this run; exit status %d ]', res.status)
+ end
+ -- generate error or warning if needed
+ if res.status > i.status then
+ if res.status == 3 then
+ alloc.err('Metapost instance now defunct')
+ elseif res.status == 2 then
+ alloc.err('Error in metapost code. Further errors will be ignored')
+ elseif res.status == 1 then
+ alloc.msg('Metapost: code caused warning')
+ end
+ end
+ -- save the exit status for later comparison
+ i.status = res.status
+end
+
+local function finder (name, mode, ftype)
+ if mode == 'w' then
+ return name
+ else
+ return kpse.find_file(name,ftype)
+ end
+end
+
+-- 2 processing results
+
+local function process_results(nr, res)
+ print_log(nr, res)
+ local pictures = {}
+ if res.fig then
+ alloc.alog (' (%d figures)', #res.fig)
+ for i=1, #res.fig do
+ local fig = res.fig[i]
+ local name = fig:filename()
+ local append = init_append()
+ -- parse and append all objects
+ append:save()
+ local objects = fig:objects()
+ for j=1, #objects do
+ parse_object (append, objects[j])
+ end
+ append:restore()
+ -- bounding box and baseline information
+ local bb = fig:boundingbox()
+ local llx, lly, urx, ury = table.unpack(bb)
+ local bas = append.baseline or lly
+ local pic =
+ { head = append.head
+ , user = append.user
+ , name = name
+ , bbox = bb }
+ if llx > urx and lly > ury then
+ pic.discard = true -- picture is empty
+ pic.wd, pic.ht, pic.dp, pic.x0, pic.y0 = 0,0,0,0,0
+ else
+ pic.wd = tex.sp(string.format('%s bp', urx - llx))
+ pic.ht = tex.sp(string.format('%s bp', ury - bas))
+ pic.dp = tex.sp(string.format('%s bp', bas - lly))
+ pic.x0 = tex.sp(string.format('%s bp', -llx ))
+ pic.y0 = tex.sp(string.format('%s bp', -bas ))
+ end
+ cb.call_callback('finish_mpfigure', pic)
+ if not pic.discard then
+ pic.head = apply_translation(append.head, -llx, -bas)
+ end
+ if debugging then
+ alloc.msg('┌ image %s, with %s objects, %s nodes',
+ name, #objects, append.node_count)
+ alloc.msg('│ dimensions (%fpt+%fpt)x%fpt',
+ pic.ht/65536, pic.dp/65536, pic.wd/65536)
+ alloc.msg('└ origin (%fpt,%fpt)',
+ pic.x0/65536, pic.y0/65536)
+ if pic.discard then alloc.amsg(' [discarded]') end
+ end
+ table.insert(pictures, pic)
+ end
+ else
+ alloc.alog (' (no figures)')
+ end
+ return pictures
+end
+
+-- 2 running lua scripts
+
+-- Code run with runscript may return a value; we will try and convert it to
+-- a string that metapost can understand.
+--
+-- Tables of the form { 'box_size', width, height, depth, margin } are
+-- converted to a transformation. (The margin will be ignored for now, this may
+-- change in the future.)
+
+local function default_env()
+ local env = { }
+ for k,v in pairs(_G) do
+ env[k] = v
+ end
+ return env
+end
+
+local current_instance = false
+
+local function runscript(code)
+ local f, msg = load(code, current_instance.jobname, 't', current_instance.env)
+ if f then
+ local result = f()
+ if result == nil then
+ return
+ else
+ local t = type(result)
+ if t == 'number' then
+ return string.format('%.16f', result)
+ elseif t == 'string' then
+ return result
+ elseif t == 'table' and t[1] == 'box_size' then
+ -- TODO: take the margin into account if present (t[5])?
+ return make_transform(t[2], t[3], t[4])
+ elseif t == 'table' and #t < 5 then
+ local fmt = #t == 1 and '%.16f'
+ or #t == 2 and '(%.16f, %.16f)'
+ or #t == 3 and '(%.16f, %.16f, %.16f)'
+ or #t == 4 and '(%.16f, %.16f, %.16f, %.16f)'
+ return fmt:format(table.unpack(t))
+ else
+ return tostring(result)
+ end
+ end
+ else
+ local mp_msg = string.gsub(msg, '"', '"&ditto&"')
+ -- TODO: provide errhelp once the echo is gone
+ return string.format('hide(errmessage "Lua error: %s")', mp_msg)
+ end
+end
+
+-- 2 typesetting with tex
+
+-- The result of the maketext function is fed back into metapost; on that side,
+-- the representation of a <picture primary> will be expected for btex...etex
+-- and an empty string for verbatimtex...etex. maketext is indistinguishable
+-- from btex...etex.
+--
+-- We return here an image() containing a single path; it is that path that
+-- will be replaced with a stored node list later on.
+--
+-- The path itself is a unit rectangle: from the rectangle we will be able to
+-- reconstruct how the tex box will have been transformed. We indicate with
+-- a prescript that the rectangle should be replaced.
+--
+-- The size of the picture is communicated to MetaPost by a ‘setbounds’
+-- instruction.
+
+local function maketext(text, mode)
+ if mode == 0 then -- btex or maketext
+ local nr = alloc.new_box()
+ table.insert(current_instance.boxes, nr)
+ local assignment = string.format('\\global\\setbox%s=\\hbox{%s}', nr, text)
+ tex.runtoks(function() tex.print(current_instance.catcodes, assignment:explode('\n')) end)
+ local box = tex.box[nr]
+ return 'image ( fill unitsquare withprescript "TEXBOX:' ..nr..'";'..
+ 'setbounds currentpicture to unitsquare transformed '..
+ make_transform(box.width, box.height, box.depth) .. ';)'
+ elseif mode == 1 then -- verbatimtex
+ tex.runtoks(function() tex.print(current_instance.catcodes, text:explode('\n')) end)
+ end
+end
+
+local infont_box = alloc.new_box('infont box')
+function M.infont(text, fnt)
+ local fontid = tonumber(fnt) or font.id(fnt)
+ tex.runtoks(function()
+ tex.sprint(default_catcodes, string.format(
+ '\\setbox%d=\\hbox{\\setfontid%d\\relax', infont_box, fontid))
+ tex.sprint(-2, text); tex.sprint(default_catcodes, '}')
+ end)
+ local res, x = { }, 0
+ for n in node.traverse(tex.box[infont_box].list) do
+ if n.id == 29 then -- glyph
+ table.insert(res, string.format(
+ 'draw image ( fill unitsquare shifted (%fpt,0) withprescript "CHAR:%d %d %d %d";'
+ ..'setbounds currentpicture to unitsquare transformed %s shifted (%fpt,0););',
+ x/65536, n.char, n.font, n.xoffset, n.yoffset,
+ make_transform(n.width, n.height, n.depth), x/65536))
+ x = x + n.width
+ elseif n.id == 12 then -- glue
+ x = x + n.width
+ elseif n.id == 13 then -- kern
+ x = x + n.kern
+ end
+ end
+ return table.concat(res, '')
+end
+
+-- 2 opening, running and and closing instances
+
+local function apply_default_instance_opts(t)
+ return
+ { ini_version = true
+ , error_line = (texconfig.error_line or 79) - 5
+ , extensions = 1
+ , find_file = finder
+ --, script_error = ...
+ , job_name = t.jobname
+ , math_mode = t.math or 'scaled'
+ , random_seed = t.seed or nil
+ -- , file_line_error_style
+ , make_text = maketext
+ , run_script = runscript
+ }
+end
+
+local function save_image_list(self, res)
+ for _, img in ipairs(res) do
+ if img.discard then
+ node.flush_list(img.head)
+ else
+ self.results.count = self.results.count + 1
+ img.prev, img.next = self.results.last, nil
+ self.results.by_name[img.name] = img
+ if nil == self.results.first then
+ self.results.first = img
+ else
+ self.results.last.next = img
+ end
+ self.results.last = img
+ end
+ end
+end
+
+function M.run (nr, code)
+ local self = instances[nr]
+ if self.status == 3 then
+ alloc.msg('metapost instance %s (%s) is defunct and will not run', self.jobname, nr)
+ return
+ end
+ current_instance = self
+ alloc.log ('metapost: executing chunk in %s (%d)', self.jobname, nr)
+ local res = process_results(nr, self.instance:execute(code))
+ save_image_list(self, res)
+end
+
+M.init_files = { 'minim.mp' }
+
+function M.open (t)
+ local nr = #instances + 1
+ t.jobname = t.jobname or ':metapost:'
+ alloc.log ('metapost: creating instance %s (%d)', t.jobname, nr)
+ -- creating instance options
+ local init = ""
+ for _, f in ipairs(M.init_files) do
+ init = string.format('%s input %s;', init, f)
+ end
+ init = string.format('%s input %s;', init, t.format or 'plain.mp')
+ local opts = apply_default_instance_opts(t)
+ local instance = mplib.new(opts)
+ instance:execute(init)
+ local continue
+ -- adding the instance
+ instances[nr] =
+ { nr = nr
+ , instance = instance
+ , jobname = t.jobname
+ , results = { first = nil, last = nil, by_name = {}, count = 0 }
+ , status = 0
+ , catcodes = t.catcodes or default_catcodes
+ , boxes = { } -- allocated by maketext
+ , env = t.env or default_env()
+ }
+ return nr
+end
+
+function M.close (nr)
+ local i = instances[nr]
+ alloc.log ('metapost: closing instance %s (%d) ', i.jobname, nr)
+ if i.instance then
+ local res = i.instance:finish()
+ print_log(nr, res)
+ end
+ for _, nr in ipairs(i.boxes) do
+ -- remove allocated boxes
+ tex.box[nr] = nil
+ end
+ instances[nr] = false
+end
+
+-- 2 retrieving and using results
+
+local function retrieve(nr, name)
+ local results = instances[nr].results
+ local image
+ if name then
+ image = results.by_name[name]
+ results.by_name [name] = nil
+ else
+ image = results.first
+ end
+ results.count = results.count - 1
+ if image.prev then
+ if image.next then
+ image.prev.next = image.next
+ image.next.prev = image.prev
+ else
+ image.prev.next = nil
+ results.last = image.prev
+ end
+ elseif image.next then
+ results.first = image.next
+ image.next.prev = nil
+ else
+ results.first = nil
+ results.last = nil
+ end
+ return image
+end
+
+function M.left (nr)
+ return instances[nr].results.count
+end
+
+function M.get_image(nr, name)
+ local image = retrieve(nr, name)
+ if image then
+ local box = node.hpack(image.head)
+ box.width = image.wd
+ box.height = image.ht
+ box.depth = image.dp
+ return box
+ end
+end
+
+function M.shipout(nr)
+ local ox, oy = pdf.getorigin
+ local ho, vo = tex.hoffset, tex.voffset
+ pdf.setorigin()
+ tex.hoffset = 0
+ while M.left(nr) > 0 do
+ local image = retrieve(nr)
+ tex.pageheight = (image.ht + image.dp)
+ tex.pagewidth = image.wd
+ tex.voffset = image.ht
+ tex.box[255] = node.vpack(node.hpack(image.head))
+ tex.shipout(255)
+ tex.count[0] = tex.count[0] + 1
+ end
+ pdf.setorigin(ox, oy)
+ tex.hoffset, tex.voffset = ho, vo
+end
+
+-- 2 tex interface
+
+local scan_int = token.scan_int
+local scan_string = token.scan_string
+
+alloc.luadef('closemetapostinstance', function() M.close(scan_int()) end)
+
+alloc.luadef('runmetapost', function()
+ M.run(scan_int(), scan_string())
+end, 'protected')
+alloc.luadef('runmetapostimage', function()
+ local i = scan_int()
+ M.run(i, 'beginfig(0); '..scan_string()..' endfig;')
+ node.write(M.get_image(i))
+end, 'protected')
+
+alloc.luadef('getnextmpimage', function()
+ node.write(M.get_image(scan_int()))
+end)
+alloc.luadef('getnamedmpimage', function()
+ node.write(M.get_image(scan_int(), scan_string()))
+end)
+
+alloc.luadef('boxnextmpimage', function()
+ local i = scan_int()
+ local b = scan_int()
+ tex.box[b] = M.get_image(i)
+end)
+
+alloc.luadef('boxnamedmpimage', function()
+ local i = scan_int()
+ local b = scan_int()
+ local n = scan_string()
+ tex.box[b] = M.get_image(i, n)
+end)
+
+alloc.luadef('remainingmpimages', function()
+ tex.sprint(M.left(scan_int()))
+end)
+
+--
+
+--
+
+return M
+
diff --git a/macros/luatex/generic/minim-mp/minim-mp.pdf b/macros/luatex/generic/minim-mp/minim-mp.pdf
new file mode 100644
index 0000000000..b511de3297
--- /dev/null
+++ b/macros/luatex/generic/minim-mp/minim-mp.pdf
Binary files differ
diff --git a/macros/luatex/generic/minim-mp/minim-mp.tex b/macros/luatex/generic/minim-mp/minim-mp.tex
new file mode 100644
index 0000000000..8e39c7f227
--- /dev/null
+++ b/macros/luatex/generic/minim-mp/minim-mp.tex
@@ -0,0 +1,61 @@
+
+\ifdefined\minimmploaded
+ \message{(skipped)}
+ \expandafter\endinput\fi
+\chardef\minimmploaded = \catcode`\:
+\catcode`\: = 11
+
+\input minim-alloc
+
+% a default catcode table
+\newcatcodetable \minim:mp:catcodes
+{\catcode`\:=12 \catcode`\@=12
+ \savecatcodetable\csname minim:mp:catcodes\endcsname}
+
+\directlua { require('minim-mp') }
+
+% The following are provided from the lua side.
+%
+% Note that only two of these are \protected – you are responsible for the
+% proper time and place of expansion of the others.
+%
+% \closemetapostinstance \instance
+% \runmetapost \instance { code } % \protected
+% \runmetapostimage \instance { code } % \protected
+% \getnextmpimage \instance
+% \getnamedmpimage \instance {name}
+% \remainingmpimages \instance
+% \boxnextmpimage \instance box-nr
+% \boxnamedmpimage \instance box-nr {name}
+
+% \directmetapost [ options ] { code }
+\protected\def\directmetapost{\withoptions[]\directmetapost:}
+\def\directmetapost:[#1]#2{%
+ \begingroup
+ \newmetapostinstance[#1]\:mpinst:
+ \runmetapost\:mpinst:{#2}%
+ \loop \ifnum\remainingmpimages\:mpinst:>0\relax
+ \getnextmpimage\:mpinst: \repeat
+ \closemetapostinstance\:mpinst:
+ \endgroup}
+
+% \newmetapostinstance [ options ] \instance
+\protected\def\newmetapostinstance{\withoptions[]\newmetapostinstance:}
+\def\newmetapostinstance:[#1]#2{%
+ \chardef#2=\directlua{
+ tex.sprint(require('minim-mp').open{#1})
+ }\relax}
+
+% colour conversion: 1 grayscale 2 cmyk 3 rgb 4 rgb as spot
+\newcount \convertmpcolours
+\convertmpcolours = 0
+
+\newcount\RtoG \RtoG = 2126
+\newcount\GtoG \GtoG = 7152
+\newcount\BtoG \BtoG = 0722
+
+\catcode`\: = \minimmploaded
+
+
+
+
diff --git a/macros/luatex/generic/minim-mp/minim.mp b/macros/luatex/generic/minim-mp/minim.mp
new file mode 100644
index 0000000000..c78dde2a92
--- /dev/null
+++ b/macros/luatex/generic/minim-mp/minim.mp
@@ -0,0 +1,73 @@
+
+delimiters ();
+
+message "Loading the minim extension macros";
+
+% interaction with tex
+def baseline expr o =
+ fill if numeric o: (0,o) else o fi
+ -- cycle withprescript "BASELINE:"; enddef;
+def boxresource expr nr = image(
+ fill unitsquare withprescript "BOXRESOURCE:" & decimal nr ;
+ setbounds currentpicture to unitsquare transformed runscript
+ ("return { 'box_size', tex.getboxresourcedimensions(" & decimal nr & ") }");
+ ) enddef;
+
+primarydef t infont f = image( runscript(
+ "return require('minim-mp').infont("&ditto&t&ditto&", "
+ &if numeric f: decimal(f) else: ditto&f&ditto fi&")" ) ) enddef;
+
+% interaction with lua
+vardef hexadecimal expr n =
+ % TODO: support other number systems
+ save d, a, m; a = ASCII("a"); m := abs n;
+ if n < 0: "-0x" else: "0x" fi
+ for i = 1 upto 7: &
+ hide(d := floor m div 256; m := 16(m - 256d);)
+ if d < 10: decimal d else: char(a+d-10) fi
+ if i = 3: & "." fi
+ endfor enddef;
+vardef scaledpoints expr n =
+ % use the fact that 800bp = 803pt
+ save a, m; m := abs n;
+ a1 = m div (1025/1024); % 1025/1024 = 800epsilon * 82
+ m := m mod (1025/1024);
+ a2 = m div 800epsilon; % max 82
+ m := (m mod 800epsilon) div epsilon;
+ a3 = floor(m*803/800 + 1/2);
+ if n < 0: "-(" else: "(" fi
+ & decimal(a1) & "*803*82 + "
+ & decimal(a2) & "*803 + "
+ & decimal(a3) & ")" enddef;
+
+% reporting
+def debug_pdf = runscript
+ ("require('minim-mp').enable_debugging()") enddef;
+def texmessage expr msg = runscript
+ ("texio.write_nl("&ditto&msg&ditto&")") enddef;
+
+% patterns
+def withpattern(suffix s) = withprescript
+ ("fillpattern: " & decimal(_patterns_.s)) enddef;
+def beginpattern(suffix s) =
+ begingroup clearxy; clearit;
+ interim defaultcolormodel:=1;
+ charcode:=incr _patterns_._last_;
+ _patterns_.s:=charcode; drawoptions();
+ pickup pencircle scaled 0.4pt;
+ save painttype; painttype:=2;
+ save _withcolor; let _withcolor = withcolor; save withcolor;
+ def withcolor = hide(painttype:=1) _withcolor enddef;
+ save matrix; transform matrix; enddef;
+def endpattern (expr xstep, ystep) =
+ if unknown matrix : matrix:=identity; fi
+ special "definepattern:" for e = charcode, tilingtype, painttype,
+ xstep, ystep, xxpart matrix, xypart matrix, yxpart matrix, yypart matrix:
+ & " " & decimal(e) endfor;
+ shipit; endgroup enddef;
+newinternal tilingtype; tilingtype:=1;
+_patterns_._last_ := 0;
+
+% so that we can load plain.mp after this
+let dump = endinput ;
+
diff --git a/macros/luatex/generic/minim-pdf/EUPL-1.2-EN.txt b/macros/luatex/generic/minim-pdf/EUPL-1.2-EN.txt
new file mode 100644
index 0000000000..4153cd3775
--- /dev/null
+++ b/macros/luatex/generic/minim-pdf/EUPL-1.2-EN.txt
@@ -0,0 +1,287 @@
+ EUROPEAN UNION PUBLIC LICENCE v. 1.2
+ EUPL © the European Union 2007, 2016
+
+This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined
+below) which is provided under the terms of this Licence. Any use of the Work,
+other than as authorised under this Licence is prohibited (to the extent such
+use is covered by a right of the copyright holder of the Work).
+
+The Work is provided under the terms of this Licence when the Licensor (as
+defined below) has placed the following notice immediately following the
+copyright notice for the Work:
+
+ Licensed under the EUPL
+
+or has expressed by any other means his willingness to license under the EUPL.
+
+1. Definitions
+
+In this Licence, the following terms have the following meaning:
+
+- ‘The Licence’: this Licence.
+
+- ‘The Original Work’: the work or software distributed or communicated by the
+ Licensor under this Licence, available as Source Code and also as Executable
+ Code as the case may be.
+
+- ‘Derivative Works’: the works or software that could be created by the
+ Licensee, based upon the Original Work or modifications thereof. This Licence
+ does not define the extent of modification or dependence on the Original Work
+ required in order to classify a work as a Derivative Work; this extent is
+ determined by copyright law applicable in the country mentioned in Article 15.
+
+- ‘The Work’: the Original Work or its Derivative Works.
+
+- ‘The Source Code’: the human-readable form of the Work which is the most
+ convenient for people to study and modify.
+
+- ‘The Executable Code’: any code which has generally been compiled and which is
+ meant to be interpreted by a computer as a program.
+
+- ‘The Licensor’: the natural or legal person that distributes or communicates
+ the Work under the Licence.
+
+- ‘Contributor(s)’: any natural or legal person who modifies the Work under the
+ Licence, or otherwise contributes to the creation of a Derivative Work.
+
+- ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of
+ the Work under the terms of the Licence.
+
+- ‘Distribution’ or ‘Communication’: any act of selling, giving, lending,
+ renting, distributing, communicating, transmitting, or otherwise making
+ available, online or offline, copies of the Work or providing access to its
+ essential functionalities at the disposal of any other natural or legal
+ person.
+
+2. Scope of the rights granted by the Licence
+
+The Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
+sublicensable licence to do the following, for the duration of copyright vested
+in the Original Work:
+
+- use the Work in any circumstance and for all usage,
+- reproduce the Work,
+- modify the Work, and make Derivative Works based upon the Work,
+- communicate to the public, including the right to make available or display
+ the Work or copies thereof to the public and perform publicly, as the case may
+ be, the Work,
+- distribute the Work or copies thereof,
+- lend and rent the Work or copies thereof,
+- sublicense rights in the Work or copies thereof.
+
+Those rights can be exercised on any media, supports and formats, whether now
+known or later invented, as far as the applicable law permits so.
+
+In the countries where moral rights apply, the Licensor waives his right to
+exercise his moral right to the extent allowed by law in order to make effective
+the licence of the economic rights here above listed.
+
+The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to
+any patents held by the Licensor, to the extent necessary to make use of the
+rights granted on the Work under this Licence.
+
+3. Communication of the Source Code
+
+The Licensor may provide the Work either in its Source Code form, or as
+Executable Code. If the Work is provided as Executable Code, the Licensor
+provides in addition a machine-readable copy of the Source Code of the Work
+along with each copy of the Work that the Licensor distributes or indicates, in
+a notice following the copyright notice attached to the Work, a repository where
+the Source Code is easily and freely accessible for as long as the Licensor
+continues to distribute or communicate the Work.
+
+4. Limitations on copyright
+
+Nothing in this Licence is intended to deprive the Licensee of the benefits from
+any exception or limitation to the exclusive rights of the rights owners in the
+Work, of the exhaustion of those rights or of other applicable limitations
+thereto.
+
+5. Obligations of the Licensee
+
+The grant of the rights mentioned above is subject to some restrictions and
+obligations imposed on the Licensee. Those obligations are the following:
+
+Attribution right: The Licensee shall keep intact all copyright, patent or
+trademarks notices and all notices that refer to the Licence and to the
+disclaimer of warranties. The Licensee must include a copy of such notices and a
+copy of the Licence with every copy of the Work he/she distributes or
+communicates. The Licensee must cause any Derivative Work to carry prominent
+notices stating that the Work has been modified and the date of modification.
+
+Copyleft clause: If the Licensee distributes or communicates copies of the
+Original Works or Derivative Works, this Distribution or Communication will be
+done under the terms of this Licence or of a later version of this Licence
+unless the Original Work is expressly distributed only under this version of the
+Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee
+(becoming Licensor) cannot offer or impose any additional terms or conditions on
+the Work or Derivative Work that alter or restrict the terms of the Licence.
+
+Compatibility clause: If the Licensee Distributes or Communicates Derivative
+Works or copies thereof based upon both the Work and another work licensed under
+a Compatible Licence, this Distribution or Communication can be done under the
+terms of this Compatible Licence. For the sake of this clause, ‘Compatible
+Licence’ refers to the licences listed in the appendix attached to this Licence.
+Should the Licensee's obligations under the Compatible Licence conflict with
+his/her obligations under this Licence, the obligations of the Compatible
+Licence shall prevail.
+
+Provision of Source Code: When distributing or communicating copies of the Work,
+the Licensee will provide a machine-readable copy of the Source Code or indicate
+a repository where this Source will be easily and freely available for as long
+as the Licensee continues to distribute or communicate the Work.
+
+Legal Protection: This Licence does not grant permission to use the trade names,
+trademarks, service marks, or names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the copyright notice.
+
+6. Chain of Authorship
+
+The original Licensor warrants that the copyright in the Original Work granted
+hereunder is owned by him/her or licensed to him/her and that he/she has the
+power and authority to grant the Licence.
+
+Each Contributor warrants that the copyright in the modifications he/she brings
+to the Work are owned by him/her or licensed to him/her and that he/she has the
+power and authority to grant the Licence.
+
+Each time You accept the Licence, the original Licensor and subsequent
+Contributors grant You a licence to their contributions to the Work, under the
+terms of this Licence.
+
+7. Disclaimer of Warranty
+
+The Work is a work in progress, which is continuously improved by numerous
+Contributors. It is not a finished work and may therefore contain defects or
+‘bugs’ inherent to this type of development.
+
+For the above reason, the Work is provided under the Licence on an ‘as is’ basis
+and without warranties of any kind concerning the Work, including without
+limitation merchantability, fitness for a particular purpose, absence of defects
+or errors, accuracy, non-infringement of intellectual property rights other than
+copyright as stated in Article 6 of this Licence.
+
+This disclaimer of warranty is an essential part of the Licence and a condition
+for the grant of any rights to the Work.
+
+8. Disclaimer of Liability
+
+Except in the cases of wilful misconduct or damages directly caused to natural
+persons, the Licensor will in no event be liable for any direct or indirect,
+material or moral, damages of any kind, arising out of the Licence or of the use
+of the Work, including without limitation, damages for loss of goodwill, work
+stoppage, computer failure or malfunction, loss of data or any commercial
+damage, even if the Licensor has been advised of the possibility of such damage.
+However, the Licensor will be liable under statutory product liability laws as
+far such laws apply to the Work.
+
+9. Additional agreements
+
+While distributing the Work, You may choose to conclude an additional agreement,
+defining obligations or services consistent with this Licence. However, if
+accepting obligations, You may act only on your own behalf and on your sole
+responsibility, not on behalf of the original Licensor or any other Contributor,
+and only if You agree to indemnify, defend, and hold each Contributor harmless
+for any liability incurred by, or claims asserted against such Contributor by
+the fact You have accepted any warranty or additional liability.
+
+10. Acceptance of the Licence
+
+The provisions of this Licence can be accepted by clicking on an icon ‘I agree’
+placed under the bottom of a window displaying the text of this Licence or by
+affirming consent in any other similar way, in accordance with the rules of
+applicable law. Clicking on that icon indicates your clear and irrevocable
+acceptance of this Licence and all of its terms and conditions.
+
+Similarly, you irrevocably accept this Licence and all of its terms and
+conditions by exercising any rights granted to You by Article 2 of this Licence,
+such as the use of the Work, the creation by You of a Derivative Work or the
+Distribution or Communication by You of the Work or copies thereof.
+
+11. Information to the public
+
+In case of any Distribution or Communication of the Work by means of electronic
+communication by You (for example, by offering to download the Work from a
+remote location) the distribution channel or media (for example, a website) must
+at least provide to the public the information requested by the applicable law
+regarding the Licensor, the Licence and the way it may be accessible, concluded,
+stored and reproduced by the Licensee.
+
+12. Termination of the Licence
+
+The Licence and the rights granted hereunder will terminate automatically upon
+any breach by the Licensee of the terms of the Licence.
+
+Such a termination will not terminate the licences of any person who has
+received the Work from the Licensee under the Licence, provided such persons
+remain in full compliance with the Licence.
+
+13. Miscellaneous
+
+Without prejudice of Article 9 above, the Licence represents the complete
+agreement between the Parties as to the Work.
+
+If any provision of the Licence is invalid or unenforceable under applicable
+law, this will not affect the validity or enforceability of the Licence as a
+whole. Such provision will be construed or reformed so as necessary to make it
+valid and enforceable.
+
+The European Commission may publish other linguistic versions or new versions of
+this Licence or updated versions of the Appendix, so far this is required and
+reasonable, without reducing the scope of the rights granted by the Licence. New
+versions of the Licence will be published with a unique version number.
+
+All linguistic versions of this Licence, approved by the European Commission,
+have identical value. Parties can take advantage of the linguistic version of
+their choice.
+
+14. Jurisdiction
+
+Without prejudice to specific agreement between parties,
+
+- any litigation resulting from the interpretation of this License, arising
+ between the European Union institutions, bodies, offices or agencies, as a
+ Licensor, and any Licensee, will be subject to the jurisdiction of the Court
+ of Justice of the European Union, as laid down in article 272 of the Treaty on
+ the Functioning of the European Union,
+
+- any litigation arising between other parties and resulting from the
+ interpretation of this License, will be subject to the exclusive jurisdiction
+ of the competent court where the Licensor resides or conducts its primary
+ business.
+
+15. Applicable Law
+
+Without prejudice to specific agreement between parties,
+
+- this Licence shall be governed by the law of the European Union Member State
+ where the Licensor has his seat, resides or has his registered office,
+
+- this licence shall be governed by Belgian law if the Licensor has no seat,
+ residence or registered office inside a European Union Member State.
+
+Appendix
+
+‘Compatible Licences’ according to Article 5 EUPL are:
+
+- GNU General Public License (GPL) v. 2, v. 3
+- GNU Affero General Public License (AGPL) v. 3
+- Open Software License (OSL) v. 2.1, v. 3.0
+- Eclipse Public License (EPL) v. 1.0
+- CeCILL v. 2.0, v. 2.1
+- Mozilla Public Licence (MPL) v. 2
+- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
+- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for
+ works other than software
+- European Union Public Licence (EUPL) v. 1.1, v. 1.2
+- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong
+ Reciprocity (LiLiQ-R+).
+
+The European Commission may update this Appendix to later versions of the above
+licences without producing a new version of the EUPL, as long as they provide
+the rights granted in Article 2 of this Licence and protect the covered Source
+Code from exclusive appropriation.
+
+All other changes or additions to this Appendix require the production of a new
+EUPL version.
diff --git a/macros/luatex/generic/minim-pdf/README b/macros/luatex/generic/minim-pdf/README
new file mode 100644
index 0000000000..1d1f02a913
--- /dev/null
+++ b/macros/luatex/generic/minim-pdf/README
@@ -0,0 +1,36 @@
+Version: 2021/1.0
+
+SUMMARY
+
+This package adds low-level support to plain LuaTeX for marking up the
+structure of a PDF document. The implementation is rather basic, but should
+allow you to make your PDFs fully PDF/A-compliant.
+
+This encompasses the following features:
+
+ - Creating Tagged PDF
+ - Marking hyperlinks, bookmarks and page labels
+ - Marking spaces and (implicit) hyphens
+ - Embedding associated files
+ - Declaring PDF/A conformance
+
+Support for XMP data inclusion (another requirement of PDF/A) is provided by
+a separate package, minim-xmp.
+
+
+DOCUMENTATION
+
+In order to obtain the typeset manual of this package, simply say:
+
+ luatex minim-pdf.doc
+
+
+COPYING
+
+(c) 2021 Esger Renkema
+
+These files may be distributed under the terms of the European Union Public
+Licence (EUPL) version 1.2 or later. A copy can be obtained at:
+
+https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+
diff --git a/macros/luatex/generic/minim-pdf/minim-languagecodes.lua b/macros/luatex/generic/minim-pdf/minim-languagecodes.lua
new file mode 100644
index 0000000000..df3e95a65e
--- /dev/null
+++ b/macros/luatex/generic/minim-pdf/minim-languagecodes.lua
@@ -0,0 +1,146 @@
+
+-- Associating language codes with language names used with \uselanguage.
+
+return {
+ afrikaans = 'af',
+ akkadian = 'akk',
+ american = 'en-US',
+ amharic = 'am',
+ ancientgreek = 'grc',
+ arabic = 'ar',
+ aramaic = 'arc',
+ armenian = 'hy',
+ assamese = 'as',
+ avestan = 'ae',
+ basque = 'eu',
+ belarusian = 'be',
+ bengali = 'bn',
+ biblicalhebrew = 'hbo',
+ bohairic = 'cop-x-bohairic',
+ bokmal = 'nb',
+ bosnian = 'bs',
+ brazilian = 'pt-BR',
+ breton = 'br',
+ british = 'en-UK',
+ bulgarian = 'bg',
+ burmese = 'my',
+ byzantine = 'gkm',
+ cantonese = 'yue',
+ catalan = 'ca',
+ chechen = 'ce',
+ cherokee = 'chr',
+ chinese = 'zh',
+ churchlatin = 'la-x-liturgic',
+ churchslavonic = 'cu',
+ classiclatin = 'la-x-classic',
+ classictibetan = 'xtc',
+ coptic = 'cop',
+ croatian = 'hr',
+ czech = 'cs',
+ danish = 'da',
+ dari = 'prs',
+ dutch = 'nl',
+ english = 'en',
+ espanol = 'es',
+ esperanto = 'eo',
+ estonian = 'et',
+ ethiopic = 'mul-ethi',
+ etruscan = 'ett',
+ farsi = 'fa',
+ finnish = 'fi',
+ flemish = 'nl-BE',
+ francais = 'fr',
+ french = 'fr',
+ frisian = 'fy',
+ friulan = 'fur',
+ galician = 'gl',
+ geez = 'gez',
+ georgian = 'ka',
+ german = 'de',
+ ['german-x-latest'] = 'de',
+ gothic = 'got',
+ greek = 'el',
+ gujarati = 'gu',
+ hebrew = 'he',
+ hindi = 'hi',
+ hittite = 'hit',
+ hungarian = 'hu',
+ icelandic = 'is',
+ indonesian = 'id',
+ interlingua = 'ia',
+ irish = 'ga',
+ italian = 'it',
+ japanese = 'ja',
+ kannada = 'kn',
+ koine = 'grc-x-koine',
+ kurmanji = 'kmr',
+ latin = 'la',
+ latvian = 'lv',
+ lithuanian = 'lt',
+ liturgicallatin = 'la-x-liturgic',
+ malayalam = 'ml',
+ marathi = 'mr',
+ medievalgreek = 'gkm',
+ medievallatin = 'la-x-medieval',
+ mongolian = 'mn-cyrl',
+ mongolianlmc = 'mn-cyrl-x-lmc',
+ monogreek = 'el-monoton',
+ multiple = 'mul',
+ ngerman = 'de-1996',
+ ['ngerman-x-latest'] = 'de-1996',
+ nohyph = 'und',
+ nolang = 'zxx',
+ norsk = 'nb',
+ norwegian = 'nb',
+ nynorsk = 'nn',
+ occitan = 'oc',
+ oriya = 'or',
+ pali = 'pi',
+ patois = 'fr',
+ persian = 'fa',
+ piedmontese = 'pms',
+ pinyin = 'zh-latn-pinyin',
+ polish = 'pl',
+ polygreek = 'el-polyton',
+ portuges = 'pt',
+ portuguese = 'pt',
+ punjabi = 'pa',
+ romanian = 'ro',
+ romansh = 'rm',
+ russian = 'ru',
+ sahidic = 'cop-x-sahidic',
+ samaritan = 'smp',
+ sanskrit = 'sa',
+ serbian = 'sr-latn',
+ serbianc = 'sr-cyrl',
+ slovak = 'sk',
+ slovene = 'sl',
+ slovenian = 'sl',
+ spanish = 'es',
+ sumerian = 'sux',
+ swedish = 'sv',
+ swissgerman = 'de-CH',
+ syriac = 'syr',
+ talmudic = 'tmr',
+ tamil = 'ta',
+ telugu = 'te',
+ thai = 'th',
+ tibetan = 'bo',
+ turkish = 'tr',
+ turkmen = 'tk',
+ ugaritic = 'uga',
+ uncoded = 'mis',
+ undetermined = 'und',
+ ukenglish = 'en-UK',
+ UKenglish = 'en-UK',
+ ukrainian = 'uk',
+ uppersorbian = 'hsb',
+ usenglish = 'en-US',
+ USenglish = 'en-US',
+ usenglishmax = 'en-US',
+ vedic = 'sa-vaidika',
+ walloon = 'wa',
+ welsh = 'cy',
+ yiddish = 'yi',
+}
+
diff --git a/macros/luatex/generic/minim-pdf/minim-pdf.doc b/macros/luatex/generic/minim-pdf/minim-pdf.doc
new file mode 100644
index 0000000000..2c06dd25b0
--- /dev/null
+++ b/macros/luatex/generic/minim-pdf/minim-pdf.doc
@@ -0,0 +1,425 @@
+
+\input minim-doc.sty
+
+\manual{minim-pdf}
+
+\ifchapter \chapter Hypertext
+
+This chapter and the next document the support of the modern pdf features
+provided by the minim-pdf package.
+Load it by saying ⟦\input minim-pdf⟧.
+The next chapter concerns the creation of tagged pdf;
+all other features of the package are described here.
+
+\else \startmetadata
+ author {Esger Renkema}
+ title {minim-pdf}
+ date {2021-06-01}
+ version {2021/1.0}
+ keywords {LuaTeX; Plain TeX; PDF/A; Tagged PDF; accessibility; a11y;
+ hypertext; bookmarks; document outline; associated files}
+ stopmetadata
+\maketitle
+
+This package adds low-level support to plain luatex for marking up the
+structure of a pdf document. The implementation is rather basic, but should
+allow you to make your pdfs fully pdf/a-compliant.
+Load the package by saying ⟦\input minim-pdf⟧.
+
+The creation of tagged pdf will be described in the second half of this manual;
+all other features will be covered first.
+
+\fi
+
+\section Hyperlinks % 1
+
+For most simple cases, you can use
+⟦*\hyperlink [name {...} | url {...}] ... \endlink⟧ for linking to a named
+destination in your own document or to an external hyperlink respectively.
+There is no support for nonsimple cases.
+
+A named destination can be created with ⟦*\nameddestination {...}⟧ (also in
+horizontal mode, unlike the backend primitive) and if you cannot think of
+a name, ⟦*\newdestinationname⟧ should generate a unique one.
+If you need the latter twice, ⟦*\lastdestinationname⟧ gives the last
+generated name.
+
+
+\section Bookmarks % 1
+
+Bookmarks can be added with ⟦*\outline [open] [dest {name}] {title}⟧.
+Add ⟦open⟧ to have the bookmark appear initially open and
+say ⟦dest {name}⟧ for having it refer to a specific named destination
+(otherwise, a new one will be created where the ⟦\outline⟧ command appears).
+
+A bookmark is automatically associated with the current structure element and
+the hierarchy of structure elements determines the nesting of bookmarks.
+Therefore, if you want nested bookmarks, you \emph{must} precede the ⟦\outline⟧
+command with a declaration of the current structure element, even if you have
+otherwise disabled tagging. See the next chapter on how to do this.
+
+
+\section Page labels % 1
+
+If the page numbers of your document are not a simple sequence starting with~1,
+you can use ⟦*\setpagelabels [pre {prefix}] style nr⟧ for communicating
+this to the pdf viewer.
+This command affects the page labels from the next page on: ⟦nr⟧ should be the
+numerical page number of that page.
+The ⟦prefix⟧ is prepended to each number and the
+⟦style⟧ must be one of ⟦decimal⟧, ⟦roman⟧, ⟦Roman⟧, ⟦alphabetic⟧, ⟦Alphabetic⟧
+or ⟦none⟧. In the last case, only the prefix is used.
+
+
+\section PDF/A % 1
+
+You can declare pdf/a conformance with ⟦*\pdfalevel xy⟧, with version $\tt
+x ∈ \{1,2,3\}$ and conformance level $\tt y ∈ \{a,b,u\}$. This will set the
+correct pdf version and ⟦pdfaid⟧ metadata. If the conformance level is ‘⟦a⟧’,
+tagging will be enabled (see the next chapter). Finally, a default RGB colour
+profile will be included.
+The conformance level can be queried from the ⟦*\pdfaconformancelevel⟧ register.
+
+Note that merely declaring conformance will not make your document pdf/a
+compliant, and that minim will not warn you if it is not.
+However, the features described in this chapter and the next should be enough
+to make pdf/a compliance possible.
+
+Also note that there currently is no documented way of choosing a different
+colour profile from the default (i.e. the default rgb profile provided by the
+colorprofiles package).
+Should you need do that, you will have to do so manually, after
+disabling the automatic inclusion by saying
+⟦\expandafter\let \csname minim:default:rgb:profile\endcsname = \relax⟧.
+
+Finally, note that pdf/a requires that spaces are represented by actual space
+characters and that discretionary hyphens are marked as soft hyphens
+(⟦U+00AD⟧).
+Since both features benefit accessibility and text extraction in general, they
+are enabled by default.
+You can disable them by setting ⟦*\writehyphensandspaces⟧ to a nonpositive value.
+
+
+\section Embedded files % 1
+
+You can attach (associate) files with ⟦*\embedfile <options>⟧.
+The file will be attached to the current structure element (see the next
+chapter) unless the ⟦global⟧ option is given: then it will be added to the
+document catalog.
+Arguments consisting of a single word can be given without braces and
+exactly one of the options ⟦file⟧ or ⟦string⟧ must be present.
+
+\smallskip\marktableaslist \halign{#\quad\hfil&#\hfil\cr
+⟦file ⟧\hfill⟦{...}⟧ & The file to embed.\cr
+⟦string ⟧\hfill⟦{...}⟧ & The string to embed.\cr
+⟦global⟧ & Attach to the document catalog.\cr
+⟦uncompressed⟧ & Do not compress the file stream.\cr
+⟦mimetype ⟧\hfill⟦{...}⟧ & The file’s mime type.\cr
+⟦moddate ⟧\hfill⟦{...}⟧\rlap{*} & The modification date (see * below).\cr
+⟦desc ⟧\hfill⟦{...}⟧ & A description (the ⟦/Desc⟧ key).\cr
+⟦relation ⟧\hfill⟦{...}⟧ & The ⟦/AFRelationship⟧ value as defined in pdf/a-3.\cr
+⟦name ⟧\hfill⟦{...}⟧ & The file name (only required when writing a ⟦string⟧).\cr }
+
+* The modification date must be of the form ⟦yyyy[-m[m][-d[d]]]⟧. A default
+moddate can be set with ⟦*\setembeddedfilesmoddate {default}⟧.
+The ⟦default⟧ date will be expanded fully at the time of embedding.
+With the minim-xmp package, a useful setting is
+⟦\setembeddedfilesmoddate {\getmetadata date}⟧.
+
+\section Lua module % 1
+
+The interface of the lua module (available via
+⟦local M = require('minim-pdf')⟧) is not stable yet, and may change.
+One function of interest, however, is
+⟦M.pdf_string(...)⟧, wich converts a lua string to a pdf string. The
+surrounding ⟦<>⟧ or ⟦()⟧ characters are included in the return value.
+
+
+% 
+
+\chapter Tagged PDF
+
+This chapter is a continuation of the previous and describes the parts of
+minim-pdf that concern the creation of tagged pdf. All features in this chapter
+must be explicitly enabled by setting ⟦*\writedocumentstructure⟧ to a positive
+value. This will be done automatically if you declare pdf/a conformance (see
+above).
+
+This part of the package is rather low-level and this chapter rather technical.
+For a more general introduction to and discussion of tagged pdf, please read
+the (excellent) manual of latex’s tagpdf package.
+
+
+\section Purpose, limitations and pitfalls % 1
+
+The main purpose of this package is semi-automatically marking up the
+(hierarchical) structure of your document, thereby creating so-called tagged pdf.
+The mechanism presented here is not quite as versatile as the pdf format
+allows. The most important restriction is that all content of the document must
+be seen by tex’s stomach in the \emph{logical} order.
+
+Furthermore, while the macros in this package are sophisticated enough that
+tagging can be done without any manual intervantion, it is quite possible and
+rather easy to generate the wrong document structore, or even cause syntax
+errors in the resulting pdf code.
+You should always check the result in an external application.
+
+This is the full list of limitations, pitfalls and shortcomings:
+\startlist
+\item1. Document content must be seen by tex in its logical order (although you
+can mark out-of-order content explicitly if you know what you are doing; see
+below).
+\item2. Artifacts cannot be split across pages. A pagebreak inmidst an artifact
+will cause incorrect pdf without error or warning.
+\item3. The contents of ⟦\localleftbox⟧ and ⟦\localrightbox⟧ must be marked
+manually, probably as artifact.
+\item4. You must mark page header, page footer and footnote rule yourself; no
+default is set.
+\item5. There currently is no way of marking xforms or other pdf objects as
+content items of themselves.
+\item6. The content of xforms (i.e. pdf objects created by ⟦\useboxresource⟧)
+should not contain tagging commands.
+\item7. Likewise, you should be careful with box reuse: it might work, but you
+should check.
+\item8. The use of structure element attributes is currently not supported
+except in a limited number of cases.
+\item9. This package currently only supports pdf~1.7 tagging and is not yet
+ready for use with pdf~2.0.
+\stoplist
+
+In order to help you debugging, some errors will refer you to the resulting pdf
+file. If you get such errors, decompress the pdf and search for the string
+‘Warning:’. It will appear in the pdf stream at the exact spot the problem
+occurs.
+
+
+\section General overview % 1
+
+When speaking about tagging, we have to do with two (or perhaps three) separate
+and orthogonal tagging processes.
+The first is the creation of a hierarchical \emph{document structure}, made up
+of \emph{structure elements} (SEs). The document structure describes the
+logical structure of a document, made up of chapters, paragraphs, references
+etc.
+The second tagging process is the tagging of \emph{marked content items}
+(MCIs): this is the partition of the actual page contents into (disjoint)
+blocks that can be assigned to the proper structure element.
+Finally, as a separate process, some parts of the page can be marked as
+\emph{artifacts}, excluding their content from both content and structure
+tagging.
+
+When using this package, artifacts and structure elements (excluding
+paragraphs; see below) must be marked explicitly, while marked content items
+will be created, marked and assigned automatically.
+There is some (partial and optional) logic for automatically arranging
+structure elements in their correct hierarchical relation.
+
+The mechanism through which this is achieved uses attributes and whatsits for
+marking the contents and borders of SEs, MCIs and artifacts. At the end of the
+output routine, just before the pdf page is assembled, this information will be
+converted into markers inserted in the pdf stream.
+
+
+\section Marked content items % 1
+
+Content items are automatically delineated at page, artifact and structure
+element boundaries and terminated at paragraph or display skips.
+This should relieve you from any manual intervention. However, if you run into
+problems, the commands below might be helpful.
+
+Use of ⟦ActualText⟧, ⟦Alt⟧ or ⟦Lang⟧ attribute on MCIs, while allowed by the
+pdf standard, is not supported by this package. You should set these on the
+structure element instead.
+
+The begining and ending of a content item can be forced with
+⟦*\startcontentitem⟧ and ⟦*\stopcontentitem⟧, while ⟦*\ensurecontentitem⟧ will
+only open a new content item if you are currently outside any.
+If you need some part to be a single content item, that can use
+⟦*\startsinglecontentitem ... \stopsinglecontentitem⟧.
+This will disable all SE and MCI tagging inside.
+
+Tagging (both of MCIs and SEs) can be disabled and re-enabled locally with
+⟦*\stoptagging⟧ and ⟦*\starttagging⟧.
+
+
+\section Artifacts % 1
+
+Artifacts can be marked in two ways: with ⟦*\markartifact {type} {...}⟧ or with
+⟦*\startartifact {type} ... \stopartifact⟧.
+The ⟦type⟧ is written to the pdf attribute dictionary directly, so that if you
+need a subtype, you can write e.g.
+⟦\startartifact {Pagination /Subtype/Header} etc⟧.
+Do make sure your artifact does not contain a page break, as this will result
+in invalid output.
+
+Inside artifacts, other structure content markers will be ignored. Furthermore,
+this package makes sure artifacts are never part of marked content items,
+automatically closing and re-opening content items before and after the
+artifact.
+While the pdf standard does not require the latter, not enforcing this seems to
+confuse some pdf software.
+
+
+\section Document structure % 1
+
+Like artifacts, structure elements can be given as ⟦*\markelement {Tag} {...}⟧
+or ⟦*\startelement {Tag} ... \stopelement {Tag}⟧.
+Here, in many cases the ⟦\stopelement⟧ is optional: whenever opening an element
+would cause a nesting of incompatible ⟦Tag⟧s, the current element will be
+closed until such a nesting is possible.
+Thus, opening a ⟦TR⟧ will close the previous ⟦TR⟧, opening an ⟦H1⟧ will
+automatically close any open inline or block structure elements, opening
+a ⟦TOCI⟧ will close all elements up until the current ⟦TOC⟧ etc. etc.
+
+As a special case, the tags ⟦Document⟧, ⟦Part⟧, ⟦Art⟧, ⟦Sect⟧ and ⟦Div⟧ (and
+their aliases) will try and close all open structure elements up to and
+including the last structure element with the same tag.
+(An alias will of course only match the same alias.)
+
+While the above can greatly reduce the effort of tagging, the logic is neither
+perfect nor complete. You should always check the results in an external
+application.
+Particular care should be taken when ‘skipping’ structure levels: the sequence
+chapter – subsection – section will result in the section beneath the subsection.
+If you are in doubt about an element being closed already, you can use
+⟦*\ensurestopelement {Tag}⟧ instead of ⟦\stopelement⟧
+to prevent an error being raised.
+
+All these helpful features can also be disabled by setting
+⟦*\strictstructuretagging⟧ to a positive value. Then, every structure element
+will have to be closed by an explicit closing tag, as in xml.
+In this case, ⟦\stopelement⟧ and ⟦\ensurestopelement⟧ will be equivalent.
+
+By default, ⟦P⟧ structure elements are inserted automatically at the start of
+every paragraph. The tag can be changed with ⟦*\nextpartag {Tag}⟧; leaving the
+argument empty will prevent marking the next paragraph.
+Auto-marking paragraphs can be (locally) disabled or enabled by saying
+⟦*\markparagraphsfalse⟧ or ⟦*\markparagraphstrue⟧.
+
+
+\section Structure element aliases % 1
+
+New structure element tags can be created with
+⟦*\addstructuretype [options] Existing Alias⟧.
+This will create a new structure tag named ⟦Alias⟧ with the same properties as
+⟦Existing⟧.
+The properties can be modified by specifying ⟦options⟧: these will set values
+of the corresponding entry in the ⟦structure_types⟧ table (see the lua source
+file for this package).
+Any aliases you declare will be written to the pdf’s ⟦RoleMap⟧ only if they
+have actually been used.
+
+
+\section Manipulating the logical order % 1
+
+With the process outlined above, the logical order of structure elements has to
+coincide with the order in which the SEs are ‘digested’ by tex.
+This, together with the marked content items being assigned to structure
+elements in their order of appearance, lies behind the restriction that logical
+and processing orders should match.
+
+With manual intervention, this restriction can be relaxed somewhat.
+Issuing the pair ⟦*\savecurrentelement ... \continueelement⟧ will append the
+MCIs following ⟦\continueelement⟧ to the SE containing ⟦\savecurrentelement⟧.
+Since the assignments made here are global, this process cannot be nested;
+in more complicated situations you should therefore use
+⟦*\savecurrentelementto\name ... \continueelementfrom\name⟧ which restores the
+current SE from a named identifier ⟦\name⟧.
+
+
+\section Structure element options % 1
+
+The ⟦\startcontentitem⟧ command allows a few options that are not mentioned
+above: its full syntax is ⟦*\startcontentitem <options> {Tag}⟧.
+The three most useful options are ⟦alt⟧ for setting an alt-text (the ⟦/Alt⟧
+entry in the structure element dicionary), ⟦actual⟧ for a text replacement
+(⟦/ActualText⟧) and ⟦lang⟧ for the language (⟦/Lang⟧; see the next section).
+The alternative and actual texts can also be given after the fact with
+⟦*\setalttext{...}⟧ and ⟦*\setactualtext{...}⟧. These apply to the current
+structure element.
+
+Setting structure element attributes is not supported at this moment, except
+the placement attributes ⟦block⟧ and ⟦inline⟧, which can be given as options.
+
+
+\section Languages % 1
+
+If you do not specify a language code for a structure element, its language
+will be determined automatically.
+In order for this to work, you must associate a language code to every used
+language; you can do so with ⟦*\setlanguagecode name code⟧, where ⟦name⟧ must
+be an identifier used with ⟦\uselanguage {name}⟧ and ⟦code⟧ must be a two or
+three-letter language code, optionally followed by a dialect specification,
+a country code, and/or some other tag.
+Note that the language code is associated to a language \emph{name}, not to the
+numerical value of the ⟦\language⟧ parameter. This allows you to assign
+separate codes to dialects.
+
+There is a small set of default language code associations, which can be found
+in the file ⟦minim-languagecodes.lua⟧.
+It covers most languages defined by the hyph-utf8 package, as well as (due to
+their ubiquitous use) many ancient languages.
+
+An actual language change introduced by ⟦\uselanguage⟧ will not otherwise be
+acted upon by this package. Therefore, you will probably want to add
+⟦\startelement{Span}⟧ after every in-line invocation of ⟦\uselanguage⟧.
+
+You can set the document language with ⟦*\setdocumentlanguage language-code⟧.
+If unset, the language code associated with the first ⟦\uselanguage⟧ statement
+will be used, or else ⟦und⟧ (undetermined). The only function of the document
+language is that it is mentioned in the pdf catalog: it has no other influence.
+
+New languages can be declared with ⟦*\newnamedlanguage {name} {lhm} {rhm}⟧ and
+new dialects with ⟦*\newnameddialect {language name} {dialect name}⟧.
+Dialects will use the same hyphenation patterns (and will indeed have the same
+⟦\language⟧ value) as their parent languages; newly declared languages will
+start with no hyphenation patterns.
+Do note that you will probably also have to specify language codes for new
+languages or dialects.
+
+This package ensures the existence of the ⟦nohyph⟧, ⟦nolang⟧, ⟦uncoded⟧ and
+⟦undetermined⟧ dummy languages, all without hyphenation.
+
+
+\section Helper macros
+
+For marking up an entry in a table of contents, you can use the macro
+⟦*\marktocentry {dest} {lbl} {title} {filler} {pageno}⟧, which should insert all
+tags in the correct way. (The ⟦dest⟧ is a link destination and can be empty;
+the ⟦lbl⟧ is a section number and can also be empty.)
+
+For marking up tables, a whole array of helper macros is available. First,
+⟦*\marktable⟧ should be given \emph{before} the ⟦\halign⟧.
+Then, in the template, the first cell should start with ⟦*\marktablerow⟧ and
+each subsequent cell with ⟦*\marktablecell⟧.
+If your table starts with a header, insert ⟦*\marktableheader⟧ before it and
+⟦*\marktablebody⟧ after.
+Before a table footer, insert ⟦*\marktablefooter⟧.
+
+For greater convenience, insert just ⟦*\automarktable⟧ before the ⟦\halign⟧.
+Then you can leave out all the above commands (unless you ⟦\omit⟧ a template of
+course).
+This assumes the table has a single header row and more than one column.
+If you use a table for typesetting a list, you can use ⟦*\marktableaslist⟧
+instead, which marks the first column as list label and the second column as
+list item. Of course, this only works with two-column tables.
+
+Finally, you can auto-tag equations as formulas by specifing
+⟦*\autotagformulas⟧. This is especially dangerous, because sometimes equations
+are used for lay-out and should not be marked as such.
+After the latter command, auto-tagging can be switched off and on with
+⟦*\stopformulatagging⟧ and ⟦*\startformulatagging⟧.
+
+Both alt and actualtext of the ⟦Formula⟧ structure element will be set to the
+(unexpanded) source code of the equation, surrounded by the appropriate number
+of dollar signs.
+Furthermore, if ⟦\pdfaconformancelevel⟧ equals three, the source of the formula
+will be attached in an embedded file with the ⟦/AFRelation⟧ set to ⟦Source⟧.
+The name of this file can be changed by redefining ⟦*\formulafilename⟧ inside
+the equation.
+
+
+% 
+
+\endmanual
+
diff --git a/macros/luatex/generic/minim-pdf/minim-pdf.lua b/macros/luatex/generic/minim-pdf/minim-pdf.lua
new file mode 100644
index 0000000000..ffe845061c
--- /dev/null
+++ b/macros/luatex/generic/minim-pdf/minim-pdf.lua
@@ -0,0 +1,1114 @@
+
+local M = { }
+local alloc = require('minim-alloc')
+local cb = require('minim-callbacks')
+alloc.remember('minim-pdf')
+
+-- 1 helper functions
+
+local function insert_formatted(t, ...)
+ table.insert(t, string.format(...))
+end
+
+local function add_to_catalog(...)
+ pdf.setcatalog((pdf.getcatalog() or '') .. string.format(...) .. ' ')
+end
+
+local function add_to_names(...)
+ pdf.setnames((pdf.getnames() or '') .. string.format(...) .. ' ')
+end
+
+-- in-depth node list traversal
+-- returns current and parent node
+-- only dives into hbox and vbox nodes
+local function full_traverse(head)
+ return function(stack, last)
+ local next = last.next
+ if not next then
+ next, stack.box = table.unpack(table.remove(stack))
+ else
+ while next.list do
+ table.insert(stack, { next, stack.box })
+ next, stack.box = next.list, next
+ end
+ end
+ return next, stack.box
+ end, { { } }, { next = head }
+end
+
+-- re-encode to utf-16 and surround by <>
+local function pdf_hex_string(text)
+ local str = { [1] = '<feff' }
+ for i in text:utfvalues() do
+ if i < 0xFFFF then
+ insert_formatted(str, '%04x', i)
+ else
+ i = i - 0x10000
+ m = math.floor(i/0x400) + 0xD800
+ n = ( i % 0x400 ) + 0xDC00
+ insert_formatted(str, '%04x%04x' ,m, n)
+ end
+ end
+ table.insert(str, '>')
+ return table.concat(str,'')
+end
+
+-- try and produce a () string first, then fall back to <>
+function M.pdf_string(text)
+ local str = { '(' }
+ for i in text:utfvalues() do
+ if i > 0x7E then
+ return pdf_hex_string(text)
+ elseif i < 0x20 then
+ insert_formatted(str, '\\%03o', i)
+ elseif i == 0x28 or i == 0x29 or i == 0x5c then
+ insert_formatted(str, '\\%c', i)
+ else
+ insert_formatted(str, '%c', i)
+ end
+ end
+ table.insert(str, ')')
+ return table.concat(str,'')
+ end
+
+-- make available as \pdfstring{...}
+alloc.luadef('pdfstring', function() M.pdf_string(token.scan_string()) end)
+
+-- try and produce a date of the format (D:YYYYMMDD)
+function M.pdf_date(text)
+ local y, m, d = string.match(text, '^([12][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)$')
+ if not y then d, m, y = string.match(text, '^([0-9][0-9]?)-([0-9][0-9]?)-([12][0-9][0-9][0-9])$') end
+ if y then
+ return string.format('(D:%4d%02d%02d)', y, m, d)
+ else
+ return string.format('(D:%s)', text)
+ end
+end
+
+function M.options_scanner()
+ return { scanners = { },
+ add = function(this, name, scanner)
+ this.scanners[name] = scanner
+ return this
+ end,
+ keyword = function(this, name)
+ return this:add(name, function() return true end)
+ end,
+ int = function(this, name)
+ return this:add(name, token.scan_int)
+ end,
+ glue = function(this, name)
+ return this:add(name, token.scan_glue)
+ end,
+ dimen = function(this, name)
+ return this:add(name, token.scan_dimen)
+ end,
+ string = function(this, name)
+ return this:add(name, token.scan_string)
+ end,
+ argument = function(this, name)
+ return this:add(name, token.scan_argument)
+ end,
+ word = function(this, name)
+ return this:add(name, token.scan_word)
+ end,
+ list = function(this, name)
+ return this:add(name, token.scan_list)
+ end,
+ scan = function(this, defaults)
+ local res = defaults or { }
+ repeat
+ local matched = false
+ for name, scanner in pairs(this.scanners) do
+ if token.scan_keyword(name) then
+ matched, this.scanners[name] = true, nil
+ res[name] = scanner()
+ end
+ end
+ until not matched
+ return res
+ end
+ }
+end
+
+local function pdf_err(n, msg)
+ local m = node.new(8,16)
+ m.mode, m.token = 2, '%% Warning: '..msg
+ node.insert_after(n, n, m)
+end
+
+-- 1 infrastructure and bookkeeping
+
+local function tagging_enabled()
+ return tex.count['writedocumentstructure'] > 0
+end
+
+local function spaces_enabled()
+ return tex.count['writehyphensandspaces'] > 0
+end
+
+-- we start with the document at the top level
+local structure = { {
+ index = 1,
+ struct = 'Document',
+ children = { },
+} }
+
+-- the parent tree will be filled automatically and separately
+local parent_tree = { } -- list of list of structure elements
+
+-- Our four helper attributes
+local current_struct = alloc.new_attribute('tagging:current:se')
+local current_order = alloc.new_attribute('tagging:element:order')
+local current_status = alloc.new_attribute('tagging:current:status')
+local current_lang = alloc.new_attribute('tagging:current:language')
+
+local function current_structure_element()
+ return structure[tex.attribute[current_struct]]
+end
+
+-- Marker whatsits
+local marker_whatsit = alloc.new_whatsit('tagged pdf marker')
+
+local function make_whatsit(t, se, order)
+ local n = node.new(8, 8); -- user_defined
+ n.user_id, n.type = marker_whatsit, 108
+ n[current_struct] = se or tex.attribute['tagging:current:se']
+ n[current_order] = order or tex.attribute['tagging:element:order']
+ n.value = t
+ return n
+end
+
+alloc.luadef('tagging:mci:content', function()
+ node.write(make_whatsit{ what = 'content' })
+end, 'protected')
+alloc.luadef('tagging:mci:markstart', function()
+ node.write(make_whatsit{ what = 'mci_start' })
+end, 'protected')
+alloc.luadef('tagging:mci:markstop', function()
+ node.write(make_whatsit{ what = 'mci_stop' })
+end, 'protected')
+alloc.luadef('tagging:art:markstart', function()
+ node.write(make_whatsit{ what = 'art_start', it = token.scan_string() })
+end, 'protected')
+alloc.luadef('tagging:art:markstop', function()
+ node.write(make_whatsit{ what = 'art_stop' })
+end, 'protected')
+
+-- 1 structure type table and type aliases
+
+local structure_types = alloc.saved_table('structure types', {
+ -- grouping types that may carry a bookmark
+ Document = { type = 'section' },
+ Part = { type = 'section' },
+ Art = { type = 'section' },
+ Sect = { type = 'section' },
+ Div = { type = 'group' },
+ -- grouping elements
+ BlockQuote = { type = 'group' },
+ Caption = { type = 'group' },
+ TOC = { type = 'group', contains = { TOC=1, TOCI=1, Caption=1 } },
+ TOCI = { contains = { Lbl=1, Reference=1, P=1, NonStruct=1, TOC=1 }, contained = { TOC=1 } },
+ Index = { type = 'group' },
+ NonStruct = { type = 'none' }, -- meaningless grouping
+ -- illustration elements
+ Figure = { type = 'inline', needsalt=1 },
+ Formula = { type = 'inline', needsalt=1 },
+ Form = { type = 'inline', needsalt=1 },
+ -- block level structure elements (BLSE)
+ P = { type = 'block' },
+ H = { type = 'block' },
+ H1 = { type = 'block' }, -- for nonhierarchical tagging (do not use?)
+ H2 = { type = 'block' }, -- __________ „ __________
+ H3 = { type = 'block' }, -- __________ „ __________
+ H4 = { type = 'block' }, -- __________ „ __________
+ H5 = { type = 'block' }, -- __________ „ __________
+ H6 = { type = 'block' }, -- __________ „ __________
+ L = { type = 'block', contains = { LI=1, Caption=1 } },
+ LI = { contains = { Lbl=1, LBody=1 }, contained = { L=1 } },
+ LBody = { type = 'contain', contained = { LI=1 } },
+ Lbl = { type = 'block', contained = { Note=1, Bibentry=1, LI=1, TOCI=1 } },
+ -- tables (neither BLSE nor ILSE)
+ Table = { type = 'block', contains = { TR=1, THead=1, TBody=1, TFoot=1, Caption=1 } },
+ THead = { contains = { TR=1 }, contained = { Table=1 } },
+ TBody = { contains = { TR=1 }, contained = { Table=1 } },
+ TFoot = { contains = { TR=1 }, contained = { Table=1 } },
+ TR = { contains = { TH=1, TD=1 }, contained = { THead=1, TBody=1, TFoot=1 } },
+ TH = { type = 'contain', contained = { TR=1 } }, -- header cell
+ TD = { type = 'contain', contained = { TR=1 } }, -- data cell
+ -- inline structure elements ILSE
+ Span = { type = 'inline' },
+ Quote = { type = 'inline' },
+ Note = { type = 'inline' },
+ Reference = { type = 'inline' },
+ BibEntry = { type = 'inline' },
+ Code = { type = 'inline' },
+ Link = { type = 'inline' }, -- contains link objects
+ Annot = { type = 'inline' }, -- contains other annotations
+ -- ruby/warichu
+ Ruby = { type = 'inline', contains = { RB=1, RT=1, RP=1 } },
+ RB = { contains = { }, contained = { Ruby=1 } },
+ RT = { contains = { }, contained = { Ruby=1 } },
+ RP = { contains = { }, contained = { Ruby=1 } },
+ Warichu = { type = 'inline', contains = { WT=1, WP=1 } },
+ WT = { contains = { }, contained = { Warichu=1 } },
+ WP = { contains = { }, contained = { Warichu=1 } },
+})
+
+local structure_type_compatibility = {
+ none = { none=1, section=1, group=1, block=1, inline=1, contain=1 },
+ section = { none=1, section=1, group=1, block=1 },
+ group = { none=1, group=1, block=1 },
+ block = { none=1, inline=1 },
+ inline = { none=1, inline=1 },
+ contain = { none=1, inline=1, block=1, group=1 },
+}
+
+local function check_structure_compatibility(parent, child, childtype)
+ local p, c = structure_types[parent], structure_types[child]
+ childtype = childtype or c.type
+ if p.contains then
+ return p.contains[child]
+ elseif c.contained then
+ return c.contained[parent]
+ elseif childtype == 'section' and parent == child then
+ return false
+ else
+ return structure_type_compatibility[p.type][childtype]
+ end
+end
+
+local function determine_parent_node(current, se)
+ local c = current
+ if tex.count['strictstructuretagging'] > 0 then
+ c = check_structure_compatibility(c.struct, se.struct, c.type) and c
+ else
+ while c and not check_structure_compatibility(c.struct, se.struct, c.type) do
+ c = c.parent
+ end
+ end
+ if not c then
+ alloc.err('Structure type mismatch: %s in %s', se.struct, current.struct)
+ end
+ return c or current
+end
+
+function M.add_structure_alias(stype, alias, settings)
+ local t, attr = { }, { }
+ local info = structure_types[stype] or
+ alloc.err('Unknown structure type ‘%s’', stype) and {}
+ for k, v in pairs(info) do t[k] = v end
+ for k,v in pairs(t.attributes or {}) do attr[k] = v end -- copy to new table
+ t.attributes = nil
+ for k, v in pairs(settings or {}) do t[k] = v end -- may re-set attributes
+ for k,v in pairs(t.attributes or {}) do attr[k] = v end
+ if #attr > 0 then t.attributes = attr end
+ for _, s in pairs(structure_types) do
+ if s.contains and s.contains[stype] then s.contains[alias] = 1 end
+ if s.contained and s.contained[stype] then s.contained[alias] = 1 end
+ end
+ t.aliasof, t.inuse = t.aliasof or stype, false
+ structure_types[alias] = t
+end
+
+alloc.luadef('struct:addalias', function()
+ local settings = load(token.scan_string())()
+ local stype = token.scan_string()
+ local alias = token.scan_string()
+ M.add_structure_alias(stype, alias, settings)
+end, 'protected')
+
+
+-- 1 writing the document structure
+
+local function stable_sort_on_order_field(unsorted)
+ -- n.b. ‘unsorted’ is likely to closely resemble two concatenated
+ -- monotonously increasing lists.
+ local sorted, oldsorted = { unsorted[1] }, nil
+ local i, next, c = 2, unsorted[2], nil
+ while next do
+ oldsorted, sorted = sorted, { }
+ for _, e in ipairs(oldsorted) do
+ c = e.order
+ while next and next.order < c do
+ table.insert(sorted, next);
+ i = i+1; next = unsorted[i]
+ end
+ table.insert(sorted, e);
+ end
+ while next and c <= next.order do
+ c = next.order
+ table.insert(sorted, next);
+ i = i+1; next = unsorted[i]
+ end
+ end
+ return sorted
+end
+
+local function format_K_array(se)
+ local res = { '[' }
+ for _, k in ipairs(stable_sort_on_order_field(se.children)) do
+ se.mainpage = se.mainpage or k.pageobj
+ if k.mcid then
+ if se.mainpage == k.pageobj then
+ insert_formatted(res, '%d', k.mcid)
+ else
+ insert_formatted(res, '<< /Type/MCR /Pg %d 0 R /MCID %d >>', k.pageobj, k.mcid)
+ end
+ elseif k.children then
+ insert_formatted(res, '%s 0 R', k.objnum)
+ else
+ if se.mainpage == k.pageobj then
+ insert_formatted(res, '<< /Type/OBJR /Obj %d 0 R >>', k.objnum)
+ else
+ insert_formatted(res, '<< /Type/OBJR /Obj %d 0 R /Pg %s 0 R >>', k.objnum, k.pageobj)
+ end
+ end
+ end
+ table.insert(res, ']')
+ return table.concat(res, ' ')
+end
+
+local function make_rolemap()
+ local aliases = { }
+ for k, v in pairs(structure_types) do
+ if v.aliasof and v.inuse and v.aliasof ~= k then
+ insert_formatted(aliases, '/%s/%s', k, v.aliasof)
+ end
+ end
+ if #aliases > 0 then
+ return '\n/RoleMap << ' .. table.concat(aliases,' ') .. ' >>'
+ end
+ return ''
+end
+
+local function write_structure()
+ if #structure == 1 then return end
+ -- reserve object numbers, prepare for writing
+ local root_obj, parent_tree_obj = pdf.reserveobj(), pdf.reserveobj()
+ structure[1].parent = { objnum = root_obj }
+ for _, se in ipairs(structure) do
+ if not se.hidden then se.objnum = pdf.reserveobj() end
+ end
+ -- update the document catalog
+ add_to_catalog('/MarkInfo << /Marked true >>')
+ add_to_catalog('/StructTreeRoot %s 0 R', root_obj)
+ -- write the structure tree root
+ pdf.immediateobj(root_obj, string.format(
+ '<< /Type/StructTreeRoot /K %d 0 R /ParentTree %d 0 R%s >>',
+ structure[1].objnum, parent_tree_obj, make_rolemap()))
+ -- write structure elements
+ for _, se in ipairs(structure) do
+ if not se.hidden then
+ local res = { '<<' }
+ insert_formatted(res, '/Type/StructElem /S/%s /P %d 0 R', se.struct, se.parent.objnum)
+ if se.lang and se.lang ~= se.parent.lang then insert_formatted(res, '/Lang (%s)', se.lang) end
+ if se.alt then insert_formatted(res, '/Alt %s', M.pdf_string(se.alt)) end
+ if se.actual then insert_formatted(res, '/ActualText %s', M.pdf_string(se.actual)) end
+ if #se.children > 0 then insert_formatted(res, '\n/K %s', format_K_array(se)) end
+ if se.mainpage then insert_formatted(res, '/Pg %d 0 R', se.mainpage) end
+ if se.attributes then
+ table.insert(res, '/A <<')
+ for k,v in pairs(se.attributes) do insert_formatted(res, '/%s %s', k, v) end
+ table.insert(res, '>>')
+ end
+ if se.files then
+ table.insert(res, '/AF [')
+ for _, fs in ipairs(se.files) do
+ insert_formatted(res, '%d 0 R', fs)
+ end
+ table.insert(res, ']')
+ end
+ table.insert(res, '>>')
+ pdf.immediateobj(se.objnum, table.concat(res, ' '))
+ end
+ end
+ -- write the parent tree
+ local res = { '<< /Nums [' }
+ for i, parents in ipairs(parent_tree) do
+ -- i, parents = StructParents index + 1, list of structure elems
+ if type(parents) == 'number' then
+ table.insert(res, string.format('%d %d 0 R', i-1, structure[parents].objnum))
+ else
+ local entry = { }
+ insert_formatted(entry, '%d [', i-1)
+ for _, p in ipairs(parents) do
+ insert_formatted(entry, '%d 0 R', p.objnum)
+ end
+ table.insert(entry, ']')
+ table.insert(res, table.concat(entry, ' '))
+ end
+ end
+ table.insert(res, '] >>')
+ pdf.immediateobj(parent_tree_obj, table.concat(res, '\n'))
+end
+
+-- 1 languages
+
+-- name|code ↦ nr & nr ↦ code
+local language_codes = alloc.saved_table('language codes')
+
+function M.set_language_code(name, code)
+ if not language_codes[code] then
+ table.insert(language_codes, code)
+ language_codes[code] = #language_codes
+ end
+ language_codes[name] = language_codes[code]
+end
+
+if not language_codes.sumerian then
+ local defaults = require('minim-languagecodes')
+ for name, code in pairs(defaults) do
+ M.set_language_code(name, code)
+ end
+end
+
+-- \setlanguagecode dutch nl_BE
+alloc.luadef('setlanguagecode', function()
+ M.set_language_code(token.scan_string(), token.scan_string())
+end, 'protected')
+
+function M.get_language_code(name_or_code)
+ local nr = language_codes[name_or_code]
+ return nr and language_codes[nr] or name_or_code
+end
+
+function M.get_current_language_code()
+ return language_codes[tex.attribute['tagging:current:language']]
+end
+
+function M.set_document_language(code)
+ structure[1].lang = code
+end
+
+alloc.luadef('setdocumentlanguage', function()
+ M.set_document_language(M.get_language_code(token.scan_string()))
+end, 'protected')
+
+-- \uselanguage patch; provide default document language
+-- and associate names with numbers
+alloc.luadef('minim:apply:language:code', function()
+ local name = token.scan_string()
+ local nr = language_codes[name] or alloc.err('No language code known for ‘%s’', name) and 1
+ if not structure[1].lang then M.set_document_language(language_codes[nr]) end
+ tex.sprint(nr)
+end)
+
+local function write_language()
+ add_to_catalog('/Lang (%s)', structure[1].lang or 'und')
+end
+
+-- 1 marking structure elements
+
+local function get_ancestor_of_type(se, stype)
+ while se and se.struct ~= stype do
+ if se.level == -1000 then return end
+ se = se.parent
+ end
+ return se and se.parent
+end
+
+function M.close_structure_node(stype, raiseerror)
+ local strict = tex.count['strictstructuretagging'] > 0
+ local current, open = current_structure_element(), false
+ if strict then
+ open = current.struct == stype and current.parent
+ else
+ open = get_ancestor_of_type(current, stype)
+ end
+ if open then
+ tex.setattribute(current_struct, open.index)
+ elseif strict then
+ alloc.err('Cannot close structure element %s: %s still open', stype, current.struct)
+ elseif raiseerror then
+ alloc.err('Cannot close structure element %s: no open tag found', stype)
+ end
+end
+
+alloc.luadef('tagging:stopelement', function()
+ M.close_structure_node(token.scan_string(), true)
+end, 'protected')
+
+alloc.luadef('tagging:ensurestopelement', function()
+ M.close_structure_node(token.scan_string(), false)
+end, 'protected')
+
+function M.open_structure_node(n)
+ local info = structure_types[n.struct]
+ if not info then
+ alloc.err('Unknown structure type %s replaced by NonStruct', n.struct)
+ n.struct, info = 'NonStruct', structure_types.NonStruct
+ end
+ info.inuse = true
+ if info.attributes then
+ n.attributes = n.attributes or { }
+ for k,v in pairs(info.attributes) do
+ n.attributes[k] = n.attributes[k] or v
+ end
+ end
+ if n.block then
+ n.type = 'block'
+ n.attributes = n.attributes or { }
+ n.attributes.Placement = '/Block'
+ elseif n.inline then
+ n.type = 'inline'
+ n.attributes = n.attributes or { }
+ n.attributes.Placement = '/Inline'
+ end
+ n.index = #structure + 1
+ n.children = { }
+ -- order and parent can be forced (needed for asynchronous elements)
+ n.order = n.order or tex.getattribute(current_order)
+ n.parent = (n.parent and structure[n.parent])
+ or determine_parent_node(current_structure_element(), n)
+ table.insert(structure, n)
+ if n.lang then
+ n.lang = get_language_code(n.lang)
+ else
+ local lang = tex.getattribute(current_lang)
+ n.lang = language_codes[lang]
+ end
+ if not n.hidden then table.insert(n.parent.children, n) end
+ if not n.async then tex.setattribute(current_struct, #structure) end
+end
+
+alloc.luadef('tagging:startelement', function()
+ local s = M.options_scanner()
+ :string('type') -- 'section', 'group', 'block' etc.
+ :argument('alt')
+ :argument('actual')
+ :string('lang')
+ :keyword('block')
+ :keyword('inline')
+ :scan()
+ s.struct = token.scan_string()
+ M.open_structure_node(s)
+end, 'protected')
+
+alloc.luadef('tagging:alt', function()
+ current_structure_element().alt = token.scan_string()
+end)
+
+alloc.luadef('tagging:actual', function()
+ current_structure_element().actual = token.scan_string()
+end)
+
+
+-- 1 marking content items
+
+-- All content items should be explicitly opened and closed, per page, by the
+-- late_lua nodes constructed beneath. After the page is finished, the MCIDs
+-- will be stored in the parent tree entry associated to the page.
+
+-- For the insertion of these late_lua nodes, see the next section; this one
+-- only deals with the bookkeeping mechanics.
+
+-- Note that we do not nest artifacts within marked content items. This would
+-- be allowed by the spec, but confuses some pdf readers (e.g. poppler).
+
+local mcid_list, pageobj
+
+local function clear_page_tagging_parameters()
+ mcid_list, pageobj = { }, nil
+ _open_mci_node_ = function (se_num, order)
+ pageobj = pageobj or pdf.getpageref(status.total_pages + 1)
+ local se = structure[se_num]
+ pdf.print(string.format('/%s <</MCID %d>> BDC ', se.struct, #mcid_list))
+ table.insert(se.children, { mcid = #mcid_list, order = order, pageobj = pageobj })
+ table.insert(mcid_list, se)
+ -- unhide hidden parents (done here to preserve the correct order)
+ if se.hidden then
+ table.insert(se.parent.children, se)
+ se.hidden = false
+ end
+ end
+end
+clear_page_tagging_parameters()
+
+local function new_open_mci_node(se, order)
+ local n = node.new(8,7) -- late_lua
+ n.token = string.format('_open_mci_node_(%d, %d)', se, order)
+ return n
+end
+
+local function new_open_art_node(atype)
+ local n = node.new(8,16) -- pdf_literal
+ n.mode, n.token = 1, string.format('/Artifact << /Type/%s >> BDC', atype)
+ return n
+end
+
+local function new_emc_node()
+ local n = node.new(8,16) -- pdf_literal
+ n.mode, n.token = 1, 'EMC'
+ return n
+end
+
+cb.register('finish_pdfpage', function(shippingout)
+ if shippingout then
+ local pageattr = string.gsub(pdf.getpageattributes() or '', ' */StructParents %d+', '' )
+ if #mcid_list > 0 then
+ pageattr = pageattr..string.format('/StructParents %d', #parent_tree)
+ table.insert(parent_tree, mcid_list)
+ end
+ pdf.setpageattributes(pageattr)
+ clear_page_tagging_parameters()
+ end
+end)
+
+-- 1 content item boundaries and linking
+
+function M.mark_content_items(box)
+ local se, order, open
+ local start_node, end_node, parent_node
+ local pageobj = pdf.getpageref(status.total_pages + 1)
+ -- inserting mci markers
+ local insert_tags = function(end_parent)
+ if not open then return end
+ parent_node.list = node.insert_before(parent_node.list, start_node, open)
+ node.insert_after(end_parent.list, end_node, new_emc_node())
+ start_node, end_node, parent_node, open = nil, nil, nil, nil
+ end
+ local start_content = function(n, b)
+ se, order = n[current_struct], n[current_order]
+ start_node, end_node, parent_node = n, n, b
+ end
+ -- traversing all nodes
+ for n, b in full_traverse(box) do
+ local marker = n.id == 8 and n.subtype == 8
+ and n.user_id == marker_whatsit and n.value
+ if marker and marker.what == 'art_start' then
+ -- first we start with marking artifacts
+ insert_tags(b);
+ start_content(n, b)
+ open = new_open_art_node(marker.it)
+ elseif marker and marker.what == 'art_stop' then
+ end_node = n
+ insert_tags(b);
+ elseif n[current_status] then
+ -- inside artifact, do nothing
+ elseif n.id == 8 and n.subtype == 19 then -- pdf_start_link
+ -- then attach links to Link elements
+ local _se, _order = n[current_struct], n[current_order]
+ local link = structure[_se]
+ if link.struct == 'Link' then
+ table.insert(link.children, { objnum = n.objnum, order = _order, pageobj = pageobj })
+ n.link_attr = string.format('%s /StructParent %d', n.link_attr, #parent_tree)
+ table.insert(parent_tree, _se)
+ else
+ alloc.err('Link found outside Link structure element (see pdf)')
+ pdf_err(n, 'unmarked link')
+ end
+ elseif marker and marker.what == 'mci_start' then
+ -- explicit start and stop nodes
+ insert_tags(b);
+ start_content(n, b)
+ open = new_open_mci_node(se, order)
+ elseif marker and marker.what == 'mci_stop' then
+ end_node = end_node and n; insert_tags(b)
+ elseif n.id == 2 or n.id == 29 -- rule, glyph or content marker
+ or marker and marker.what == 'content' then
+ -- now see if we need to intervene between content nodes
+ local _se, _order = n[current_struct], n[current_order]
+ if n.id == 2 and (n.width == 0 or n.height == 0 and n.depth == 0) then
+ -- ignore invisible rules
+ elseif not _se or not _order then
+ -- unmarkable content should not be possible (but is)
+ alloc.err('Unmarkable content on page %d (see pdf)', status.total_pages + 1)
+ pdf_err(n, 'possible unmarked content')
+ elseif se ~= _se or order ~= _order or not end_node then
+ -- new content item on changing attributes
+ insert_tags(b);
+ start_content(n, b)
+ open = new_open_mci_node(se, order)
+ else
+ -- nothing changed: continue current mci
+ end_node = n
+ end
+ elseif n.id == 12 and n.subtype > 2 and n.subtype < 8 then
+ -- parskip or displayskip always closes mci
+ insert_tags(b)
+ end
+ end
+ -- close the last mci
+ if start_node and start_node.user_id and start_node.value
+ and start_node.value.what == 'art_start' then
+ alloc.err('Page %d ends with a broken artifact', status.total_pages+1)
+ end
+ insert_tags(box)
+end
+
+cb.register('pre_shipout', function(nr)
+ if tagging_enabled() then
+ M.mark_content_items(tex.box[nr])
+ end
+end)
+
+-- 1 destinations
+
+local dest_count = alloc.new_count('link dest count')
+local function new_dest_name()
+ local dest_nr = tex.count[dest_count] + 1
+ tex.setcount('global', dest_count, dest_nr)
+ return 'hyper:dest:'..dest_nr
+end
+
+local function last_dest_name()
+ return 'hyper:dest:'..tex.count[dest_count]
+end
+
+local function write_new_dest()
+ local name = new_dest_name()
+ tex.sprint(string.format('\\nameddestination{%s}', name))
+ return name
+end
+
+-- make available as \newdestinationname, \lastdestinationname
+alloc.luadef('newdestinationname', function() tex.sprint(new_dest_name()) end)
+alloc.luadef('lastdestinationname', function() tex.sprint(last_dest_name()) end)
+
+-- 1 bookmarks
+
+-- start with a dummy top-level bookmark
+local bookmarks = { { count = 0 } }
+structure[1].bookmark = bookmarks[1]
+
+local function write_bookmarks()
+ if #bookmarks == 1 then return end
+ -- reserve objects in a row
+ for i=1, #bookmarks do
+ bookmarks[i].outline_obj = pdf.reserveobj()
+ end
+ -- write outlines object
+ add_to_catalog('/Outlines %s 0 R', bookmarks[1].outline_obj)
+ pdf.immediateobj(bookmarks[1].outline_obj, string.format(
+ ' <</Type /Outlines /First %s 0 R /Last %s 0 R /Count %s >> ',
+ bookmarks[2].outline_obj, bookmarks[1].last.outline_obj, #bookmarks - 1))
+ -- write bookmark objects
+ for i=2, #bookmarks do
+ local bm, res = bookmarks[i], { }
+ insert_formatted(res, '<< /Title %s\n/Parent %s 0 R /Dest (%s)', M.pdf_string(bm.title),
+ bm.parent and bm.parent.outline_obj or bookmarks[1].outline_obj, bm.dest)
+ if bm.next then insert_formatted(res, '/Next %s 0 R', bm.next.outline_obj) end
+ if bm.prev then insert_formatted(res, '/Prev %s 0 R', bm.prev.outline_obj) end
+ if bm.struct and bm.struct.objnum then
+ insert_formatted(res, '/SE %s 0 R', bm.struct.objnum)
+ end
+ if bm.count > 0 then
+ insert_formatted(res, '/First %s 0 R /Last %s 0 R /Count %s%s',
+ bm.first.outline_obj, bm.last.outline_obj, bm.open and '' or '-', bm.count)
+ end
+ pdf.immediateobj(bm.outline_obj, table.concat(res,'\n')..' >>')
+ end
+end
+
+function M.add_bookmark(bm)
+ local se = current_structure_element()
+ bm.parent, bm.count = false, 0
+ bm.dest = bm.dest or write_new_dest()
+ se.bookmark, bm.struct = bm, se
+ -- find and update the parent bookmarks
+ local p = se.parent
+ while p do
+ local pbm = p.bookmark
+ if pbm then
+ if not bm.parent then
+ if pbm.last then pbm.last.next = bm end
+ bm.parent, bm.prev = pbm, pbm.last
+ pbm.first, pbm.last = pbm.first or bm, bm
+ end
+ -- update the count until the first closed bookmark
+ pbm.count = pbm.count + 1
+ p = pbm.open and pbm.parent
+ else
+ p = p.parent
+ end
+ end
+ table.insert(bookmarks, bm)
+end
+
+alloc.luadef('outline', function()
+ local s = M.options_scanner()
+ :keyword('open')
+ :keyword('closed') -- default; ignored
+ :string('dest')
+ :scan()
+ s.title = token.scan_string()
+ M.add_bookmark(s)
+end, 'protected')
+
+
+-- 1 associated files
+
+local attached_files = { }
+local function write_fileattachments()
+ if #attached_files > 0 then
+ table.sort(attached_files, function(a,b) return a.name < b.name end)
+ local afs = { '/AF [' }
+ local nms = { '<< /Names [' }
+ for _, t in ipairs(attached_files) do
+ insert_formatted(afs, '%d 0 R', t.objnum)
+ insert_formatted(nms, '%s %d 0 R', t.name, t.objnum)
+ end
+ table.insert(afs, ']')
+ table.insert(nms, '] >>')
+ add_to_catalog(table.concat(afs, ' '))
+ local efs = pdf.immediateobj(table.concat(nms, ' '))
+ add_to_names('/EmbeddedFiles %d 0 R', efs)
+ end
+end
+
+function M.embed_file(t)
+ -- default moddate
+ if not t.moddate then
+ tex.runtoks(function() tex.print('\\csname minim:makedefaultmoddate\\endcsname') end)
+ local moddate = tex.toks['embeddedfiles:moddate']
+ if moddate ~= '' then t.moddate = moddate end
+ end
+ -- embed the file
+ local attr = { '/Type/EmbeddedFile' }
+ if t.mimetype then insert_formatted(attr, '/Subtype/%s', string.gsub(t.mimetype, '/', '#2F')) end
+ if t.moddate then insert_formatted(attr, '/Params << /ModDate %s >>', M.pdf_date(t.moddate)) end
+ local ef = pdf.obj {
+ immediate = true,
+ compresslevel = t.uncompressed and 0 or nil,
+ type = 'stream',
+ file = t.file and kpse.find_file(t.file),
+ string = t.string,
+ attr = table.concat(attr, ' ') }
+ -- write the filespec
+ local res = { '<< /Type/Filespec' }
+ insert_formatted(res, '/F %s /UF %s /EF << /F %d 0 R /UF %d 0 R >>', t.name, t.name, ef, ef)
+ if t.desc then insert_formatted(res, '/Desc %s', M.pdf_string(t.desc)) end
+ if t.relation then insert_formatted(res, '/AFRelationship /%s', t.relation) end
+ table.insert(res, '>>')
+ local fs = pdf.immediateobj(table.concat(res, ' '))
+ -- (globally) attach the file
+ return fs, ef
+end
+
+alloc.luadef('embedfile', function()
+ local t = M.options_scanner()
+ :string('desc')
+ :string('file')
+ :string('string')
+ :string('mimetype')
+ :string('moddate')
+ :string('relation')
+ :string('name')
+ :keyword('global')
+ :keyword('uncompressed')
+ :scan()
+ if not t.name then
+ t.name = t.file or aloc.err('No name specified for embedded file stream')
+ end
+ t.name = M.pdf_string(t.name or '(unnamed)')
+ local fs, ef = M.embed_file(t, t.global)
+ -- where to attach?
+ if t.global then
+ table.insert(attached_files, { name = t.name, objnum = fs } )
+ elseif tagging_enabled() then
+ local se = current_structure_element()
+ se.files = se.files or { }
+ table.insert(se.files, fs)
+ else
+ alloc.err('In untagged pdf, \\embedfile must be used with ‘global’ keyword')
+ table.insert(attached_files, { name = t.name, objnum = fs } )
+ end
+end, 'protected')
+
+
+-- 1 hyphenation
+
+function M.mark_discretionaries(head, gc)
+ if not spaces_enabled() then return end
+ for disc in node.traverse_id(7, head) do
+ if disc.subtype ~= 2 then -- ‘automatic’ (exclude explicit hyphens)
+ local pre, post, replace = disc.pre, disc.post, disc.replace
+ local se, order = disc[current_struct], disc[current_order]
+ -- get the replacement text
+ local actual = { }
+ for c in node.traverse_id(29, replace) do
+ table.insert(actual, c.char)
+ end
+ -- special case: a single hyphen
+ if #actual == 0 and pre.char and pre.char == 0x2D then
+ actual = '­' -- soft hyphen U+00AD
+ elseif #actual > 0 then
+ actual = string.utfcharacter(table.unpack(actual))
+ else
+ goto continue
+ end
+ -- reserve a structure element (but hide it)
+ M.open_structure_node { hidden = true, async = true,
+ struct = 'Span', parent = se, order = order, actual = actual }
+ -- apply the new se to pre and post
+ for n, _ in full_traverse(pre) do n[current_struct] = #structure end
+ for n, _ in full_traverse(past) do n[current_struct] = #structure end
+ end
+ ::continue::
+ end
+ return true
+end
+
+cb.register('pre_linebreak_filter', M.mark_discretionaries)
+
+-- 1 spaces
+
+local space_attr = alloc.new_attribute('space insertion marker')
+
+function M.mark_spaces(head, gc)
+ if not spaces_enabled() then return end
+ for g in node.traverse_id(12, head) do -- glue
+ if g.prev and g.subtype == 13 or g.subtype == 14 then -- (x)spaceskip
+ local p = g.prev
+ p[space_attr] = p.id == 29 and p.font
+ or g.next and g.next.id == 29 and g.next.font
+ or font.current()
+ end
+ end
+ return true
+end
+
+local function create_space(n)
+ local s = node.new(29) -- glyph
+ s.char, s.font, s.attr = 0x20, n[space_attr], n.attr
+ local b = node.hpack(s)
+ b.width, b.height, b.depth = 0, 0, 0
+ return b
+end
+
+local function insert_spaces(head)
+ for n in node.traverse(head) do
+ if n[space_attr] then
+ node.insert_after(head, n, create_space(n))
+ end
+ end
+end
+
+function M.insert_spaces(head, gc)
+ if not spaces_enabled() then return end
+ for line in node.traverse_id(0, head) do
+ insert_spaces(line.head)
+ end
+ return true
+end
+
+function M.mark_and_insert_spaces(head, gc, ...)
+ if not spaces_enabled() then return end
+ M.mark_spaces(head, gc)
+ insert_spaces(head)
+ return true
+end
+
+cb.register('pre_linebreak_filter', M.mark_spaces)
+cb.register('post_linebreak_filter', M.insert_spaces)
+cb.register('hpack_filter', M.mark_and_insert_spaces)
+
+-- 1 page labels
+
+local pagelabels = { }
+
+function M.page_labels(abs_nr, nr, style, prefix)
+ table.insert(pagelabels, { start = abs_nr, st = nr, s = style, p = prefix })
+end
+
+local pagelabel_styles = {
+ Decimal = 'D',
+ Roman = 'R',
+ roman = 'r',
+ Alphabetic = 'A',
+ alphabetic = 'a',
+ none = false }
+
+alloc.luadef('setpagelabels', function()
+ local prefix = token.scan_keyword('prefix') and token.scan_string()
+ local style = token.scan_word()
+ local nr = token.scan_int()
+ local st = pagelabel_styles[style]
+ if st == nil then alloc.err('Unknown page label style »%s«', style) end
+ M.page_labels(status.total_pages, nr, st, prefix)
+end, 'protected')
+
+local function write_pagelabels()
+ if #pagelabels == 0 then return end
+ if pagelabels[1].start ~= 0 then
+ table.insert(pagelabels, 1, { start = 0, st = 1, s = 'D' })
+ end
+ local res = { '/PageLabels << /Nums [' }
+ for _, l in ipairs(pagelabels) do
+ local s, p = l.s and '/S/'..l.s, l.p and ' /P '..M.pdf_string(l.p)
+ table.insert(res, string.format('%d << /St %d %s%s >>', l.start, l.st, s or '', p or ''))
+ end
+ table.insert(res, ']')
+ add_to_catalog(table.concat(res, ' '))
+end
+
+-- 1 output intents
+
+local output_intents = { }
+
+function M.add_output_intent(t)
+ table.insert(output_intents, t)
+end
+
+local function write_output_intents()
+ if #output_intents == 0 then return end
+ local res = { '[' }
+ for _, oi in ipairs(output_intents) do
+ local p = pdf.obj { type = 'stream',
+ file = kpse.find_file(oi.path),
+ compresslevel = 9,
+ attr = string.format('/N %d', oi.N),
+ immediate = true }
+ insert_formatted(res, '<< /Type/OutputIntent /DestOutputProfile %d 0 R', p)
+ insert_formatted(res, '/S/%s /OutputConditionIdentifier (%s)', oi.subtype, oi.id)
+ if oi.info then insert_formatted(res, '/Info (%s)', oi.info) end
+ if oi.condition then insert_formatted(res, '/OutputCondition (%s)', oi.condition) end
+ if oi.registry then insert_formatted(res, '/RegistryName (%s)', oi.registry) end
+ table.insert(res, '>>')
+ end
+ table.insert(res, ']')
+ local objnum = pdf.immediateobj(table.concat(res, ' '))
+ add_to_catalog('/OutputIntents %d 0 R', objnum)
+end
+
+function M.add_default_rgb_output_intent(t)
+ t = t or {}
+ M.add_output_intent {
+ subtype = t.subtype or 'GTS_PDFA1',
+ info = t.info or 'IEC 61966-2.1 Default RGB colour space - sRGB',
+ condition = t.condition,
+ registry = 'http://www.iev.ch',
+ id = 'IEC sRGB',
+ N = 3, path = 'sRGB.icc' }
+end
+
+function M.add_default_cmyk_output_intents(t)
+ t = t or {}
+ M.add_output_intent {
+ subtype = t.subtype or 'GTS_PDFA1',
+ info = t.info or 'FOGRA39L Coated',
+ condition = t.condition or 'FOGRA39L Coated',
+ registry = 'http://www.fogra.org',
+ id = 'Offset printing, according to ISO 12647-2:2004/Amd 1, OFCOM, paper type 1 or 2 = coated art, 115 g/m2, tone value increase curves A (CMY) and B (K)',
+ N = 4, path = 'FOGRA39L_coated.icc' }
+end
+
+alloc.luadef('minim:default:rgb:profile', function() M.add_default_rgb_output_intent() end)
+alloc.luadef('minim:default:cmyk:profile', function() M.add_default_cmyk_output_intent() end)
+
+--
+
+cb.register ('finish_pdffile', function()
+ if tagging_enabled() then
+ write_language()
+ write_structure()
+ end
+ write_bookmarks()
+ write_pagelabels()
+ write_output_intents()
+ write_fileattachments()
+end)
+
+return M
+
diff --git a/macros/luatex/generic/minim-pdf/minim-pdf.pdf b/macros/luatex/generic/minim-pdf/minim-pdf.pdf
new file mode 100644
index 0000000000..b460bdf4ed
--- /dev/null
+++ b/macros/luatex/generic/minim-pdf/minim-pdf.pdf
Binary files differ
diff --git a/macros/luatex/generic/minim-pdf/minim-pdf.tex b/macros/luatex/generic/minim-pdf/minim-pdf.tex
new file mode 100644
index 0000000000..f8075ae6e4
--- /dev/null
+++ b/macros/luatex/generic/minim-pdf/minim-pdf.tex
@@ -0,0 +1,351 @@
+
+\ifdefined\minimpdfloaded
+ \message{(skipped)}
+ \expandafter\endinput\fi
+\chardef\minimpdfloaded = \catcode`\:
+\catcode`\: = 11
+
+% Abbreviations used throughout this document:
+% se structure element
+% mci marked content item
+
+\newcount \writedocumentstructure
+\newcount \writehyphensandspaces
+\newcount \strictstructuretagging
+
+\writedocumentstructure = 0
+\writehyphensandspaces = 1
+\strictstructuretagging = 0
+
+% 1 the attributes
+
+\input minim-alloc
+\input minim-hooks
+
+% By three attributes do we determine the document structure.
+%
+% One for marking the current structure element:
+% - is the index of the lua-side se table
+% - assignments are always local
+\newattribute \tagging:current:se \tagging:current:se = 1
+%
+% One for ordering children of structure elements:
+% - assignments are always global
+% - should generally increase monotously
+% - should change (increase) at every se boundary
+\newattribute \tagging:element:order \tagging:element:order = 1
+%
+% One for marking the status:
+% - assignments are generally local
+% - if set, disables tagging and content marking
+\newattribute \tagging:current:status \tagging:current:status = \unset
+%
+% A fourth attribute keeps track of the current language
+% - assignments are local
+% - sets language of structure elements
+\newattribute \tagging:current:language \tagging:current:language = \language
+
+\directlua { require('minim-pdf') }
+
+% 1 artifacts and content items
+
+% \stoptagging ... \starttagging
+% disables marking structure elements
+\newif\iftagging:enabled \tagging:enabledtrue
+\protected\def\starttagging{\tagging:enabledtrue
+ \ifnum1=\tagging:current:status
+ \tagging:current:status\unset\fi}
+\protected\def\stoptagging{\tagging:enabledfalse
+ \ifnum\unset=\tagging:current:status
+ \tagging:current:status1\relax\fi}
+
+% \markartifact {Layout} {...}
+% \startartifact {Pagination /Subtype/Header} ... \stopartifact
+\long\def\markartifact#1#2{\startartifact{#1}#2\stopartifact}
+\protected\def\startartifact{\begingroup\stoptagging
+ \tagging:mci:incr\tagging:art:markstart}
+\protected\def\stopartifact{\tagging:art:markstop\tagging:mci:incr\endgroup}
+
+% \startcontentitem ... \stopcontentitem
+\protected\def\startcontentitem{\iftagging:enabled\tagging:mci:incr\tagging:mci:markstart\fi}
+\protected\def\stopcontentitem{\iftagging:enabled\tagging:mci:markstop\tagging:mci:incr\fi}
+
+% \startsinglecontentitem ... \stopsinglecontentitem
+\protected\def\startsinglecontentitem{\begingroup \startcontentitem\stoptagging}
+\protected\def\stopsinglecontentitem{\endgroup\stopcontentitem}
+
+% \ensurecontentitem
+\protected\def\ensurecontentitem{\iftagging:enabled\tagging:mci:content\fi}
+\protected\def\tagging:mci:incr{\global\advance\tagging:element:order1\relax}
+
+% 1 structure elements
+
+% \savecurrentelement ... \continueelement
+% \savecurrentelementto\name ... \continueelementfrom\name
+\protected\def\savecurrentelementto#1{\global\chardef#1\tagging:current:se}
+\protected\def\continueelementfrom#1{\tagging:current:se#1\tagging:mci:incr}
+\def\savecurrentelement{\savecurrentelementto\tagging:saved:se}
+\def\continueelement{\continueelementfrom\tagging:saved:se}
+
+% \markelement {Tag} {...}
+% \startelement {Tag} ... \stopelement {Tag}
+% \ensurestopelement {Tag}
+\long\protected\def\markelement#1#2{\iftagging:enabled
+ \startelement{#1}#2\stopelement{#1}\else#2\fi}
+\protected\def\startelement{\iftagging:enabled \tagging:mci:incr
+ \expandafter\tagging:startelement\else
+ \expandafter\tagging:ignore\fi}
+\protected\def\stopelement{\iftagging:enabled \tagging:mci:incr
+ \expandafter\tagging:stopelement\else
+ \expandafter\tagging:ignore\fi}
+\protected\def\ensurestopelement{\iftagging:enabled \tagging:mci:incr
+ % n.b. this can cause problems if you skip levels
+ \expandafter\tagging:ensurestopelement\else
+ \expandafter\tagging:ignore\fi}
+\def\tagging:ignore#1#{\ignore}
+
+% \addstructuretype [options] Existing Alias
+\protected\def\addstructuretype{\withoptions[]\addstructure:type}
+\def\addstructure:type[#1]{\struct:addalias{return {#1}}}
+
+% \setalttext {...} and \setactualtext {...}
+\protected\def\setalttext{\iftagging:enabled
+ \expandafter\tagging:alt\fi}
+\protected\def\setactualtext{\iftagging:enabled
+ \expandafter\tagging:actual\fi}
+
+
+% 1 auto-marking paragraphs
+
+% \nextpartag {H}
+% \nextpartag {} % no tag inserted for next paragraph
+% \markparagraphs(true|false)
+\newif\ifmarkparagraphs \markparagraphstrue
+\newtoks\nextpartag \nextpartag{P}
+\toksapp\minim:ateverypar{\iftagging:enabled \ifmarkparagraphs
+ \expandafter\ifx\expandafter\relax\the\nextpartag\relax\else
+ \startelement{\the\nextpartag}\fi
+ \nextpartag{P}\fi \fi}
+
+% 1 tagging helper macros
+
+% \marktocentry {destination}{label}{title}{filler}{page}
+\def\marktocentry#1#2#3#4#5{%
+ \ifx\marktocentry#1\marktocentry
+ \def\marktocentry:link##1{##1}\else
+ \def\marktocentry:link##1{\hyperlink dest{#1}##1\endlink}\fi
+ \markelement{TOCI}{\nextpartag{}\quitvmode
+ \ifx\marktocentry#2\marktocentry\else
+ \markelement{Lbl}{\marktocentry:link{#2}}\fi
+ \markelement{Reference}{\marktocentry:link{#3%
+ \ifx\marktocentry#4\marktocentry\else
+ \markartifact{Layout}{#4}\fi#5}}}}
+
+% \marktable \halign {\marktablerow#&\marktablecell#\cr
+% \marktableheader
+% Header & cells \cr
+% \marktablebody
+% ... & ... \cr ...
+% \marktablefooter
+% ... & ... \cr ... }
+%
+\def\marktable{\startelement{Table}%
+ \def\tagging:cell{TD}}
+\def\marktableheader{%
+ \noalign{\gdef\tagging:cell{TH}%
+ \startelement{THead}%
+ \savecurrentelementto\tagging:tpart}}
+\def\marktablebody{%
+ \noalign{\gdef\tagging:cell{TD}%
+ \startelement{TBody}%
+ \savecurrentelementto\tagging:tpart}}
+\def\marktablefooter{%
+ \noalign{\startelement{TFoot}%
+ \savecurrentelementto\tagging:tpart}}
+\def\marktablerow{
+ \unless\ifdefined\tagging:tpart
+ \startelement{TBody}%
+ \savecurrentelementto\tagging:tpart\fi
+ \continueelementfrom\tagging:tpart
+ \startelement{TR}%
+ \savecurrentelementto\tagging:row
+ \startelement{\tagging:cell}}
+\def\marktablecell{%
+ \continueelementfrom\tagging:row
+ \startelement{\tagging:cell}}
+
+% \automarktable \halign ... { ... }
+\def\automarktable#1#{\marktable
+ \def\tagging:table{\tagging:mktrow{#1}}%
+ \afterassignment\tagging:table
+ \let\tagging:tmp= }
+\def\tagging:mktrow#1#2&#3\cr{\iftrue
+ \tagging:mktcell{#1\bgroup\marktablerow#2}\fi
+ #3&\tagging:mktrow&\cr}
+\def\tagging:mktcell#1#2\fi#3&{\fi
+ \ifx\tagging:mktrow#3\tagging:mkthdr{#1}\fi
+ \ifx\tagging:mktrow#3\tagging:mktrow
+ \tagging:mktcell{#1&}\else
+ \tagging:mktcell{#1&\marktablecell#3}\fi}
+\def\tagging:mkthdr#1#2\cr#3\cr{\fi#1\cr
+ \marktableheader#3\cr\marktablebody}
+\def\tagging:fi{\fi}
+
+% \marktableaslist \halign ... { ... }
+\def\marktableaslist#1#{\startelement{L}%
+ \def\tagging:table{\tagging:mktlist{#1}}%
+ \afterassignment\tagging:table
+ \let\tagging:tmp= }
+\def\tagging:mktlist#1#2&{#1\bgroup
+ \startelement{LI}\savecurrentelement
+ \startelement{Lbl}#2&\continueelement
+ \startelement{LBody}}
+
+% \autotagformulas
+% \stopformulatagging ... \startformulatagging
+% \formulafilename
+\newif \iftagging:indisplay
+\newif \iftagging:toplevelmath \tagging:toplevelmathtrue
+\newif \iftagging:formulaenabled
+\let\startformulatagging = \tagging:formulaenabledtrue
+\let\stopformulatagging = \tagging:formulaenabledfalse
+\newcount \tagging:formulanr
+\def\formulafilename{unnumbered-equation-\the\tagging:formulanr}
+\def\autotagformulas{\startformulatagging
+ \everymath\expandafter{\the\everymath
+ \tagging:formula\tagging:startformula}%
+ \everydisplay\expandafter{\the\everydisplay \tagging:indisplaytrue
+ \tagging:formula\tagging:startdisplay}}
+\def\tagging:formula#1{%
+ \iftagging:enabled \iftagging:formulaenabled \iftagging:toplevelmath
+ \tagging:toplevelmathfalse #1\fi\fi\fi}
+\def\tagging:startformula\fi\fi\fi#1${\tagging:makeformula{#1}{$}}
+\def\tagging:startdisplay\fi\fi\fi#1$${\tagging:makeformula{#1}{$$}}
+\def\tagging:makeformula#1#2{\fi\fi\fi
+ \global\advance\tagging:formulanr1\relax
+ \startelement\iftagging:indisplay block\else inline\fi{Formula}%
+ \setalttext{\tagging:formulasource{#1}}%
+ \setactualtext{\tagging:formulasource{#1}}%
+ \ifnum3=\pdfaconformancelevel
+ \embedfile mimetype text/x-tex
+ relation Source desc {Equation source}
+ name {\formulafilename.tex}
+ string {\tagging:formulasource{#1}}\fi
+ \scantextokens{#1}#2}
+\def\tagging:formulasource#1{%
+ $\iftagging:indisplay$\fi
+ \unexpanded{#1}%
+ $\iftagging:indisplay$\fi}
+
+% 1 hyperlinks
+
+% provided by the lua module:
+% \newdestinationname
+% \lastdestinationname
+
+% \nameddestination {name}
+\def\nameddestination{\ifhmode\expandafter\linkdest:h\else\expandafter\linkdest:v\fi}
+\def\linkdest:h#1{\vadjust pre{\linkdest:v{#1}}}
+\def\linkdest:v#1{\pdfextension dest name {#1} xyz\nobreak}
+
+% \hyperlink dest {name} ... \endlink
+% \hyperlink url {url} ... \endlink
+\protected\def\endlink{\pdfextension endlink\stopelement{Link}\relax}
+\protected\def\startlink{\startelement{Link}\pdfextension startlink}
+\def\hyperlink#1#{\quitvmode\hyperlink:rmspace#1 \hyperlink:rmspace}
+\def\hyperlink:rmspace#1 #2\hyperlink:rmspace{%
+ \startlink attr {\minim:linkattr}%
+ \csname hyperlink:#1\endcsname}
+\def\hyperlink:dest#1{user {/Subtype/Link /F 4 /A <</S/GoTo /D (#1)>>}}
+\def\hyperlink:url#1{user {/Subtype/Link /F 4 /A <</S/URI /URI (#1)>>}}
+\def\minim:linkattr{/Border [0 0 0]}
+
+% 1 languages
+
+% provided by the lua module:
+% \setdocumentlanguage {name or code}
+% \setlanguagecode {name} {code}
+% \minim:apply:language:code{name} → index
+
+% patch in language codes to \uselanguage
+\ifcsname uselanguage@hook\endcsname
+ \expandafter\let
+ \expandafter\minim:uselanguagehook
+ \lastnamedcs \fi
+\expandafter\edef\csname uselanguage@hook\endcsname#1{%
+ % tagging support
+ \noexpand\tagging:current:language
+ \noexpand\minim:apply:language:code{#1}%
+ % previous definitions
+ \ifdefined\minim:uselanguagehook
+ \noexpand\minim:uselanguagehook{#1}\fi}
+
+% \newnamedlanguage {name} {lhm} {rhm}
+\def\newnamedlanguage#1#2#3{%
+ \expandafter\newlanguage\csname lang@#1\endcsname
+ \expandafter\chardef\csname lhm@#1\endcsname=#2\relax
+ \expandafter\chardef\csname rhm@#1\endcsname=#3\relax
+ \csname lu@texhyphen@loaded@\the\csname lang@#1\endcsname\endcsname}
+
+% \newnameddialect {language} {dialect}
+\def\newnameddialect#1#2{%
+ \expandafter\chardef\csname lang@#2\endcsname\csname lang@#1\endcsname
+ \expandafter\chardef\csname lhm@#2\endcsname\csname lhm@#1\endcsname
+ \expandafter\chardef\csname rhm@#2\endcsname\csname rhm@#1\endcsname}
+
+% and provide several dummy languages
+\ifcsname lang@nohyph\endcsname \else
+ \newnamedlanguage {nohyph} 1 1 \fi
+\ifcsname lang@nolang\endcsname \else
+ \newnameddialect {nohyph} {nolang} \fi
+\ifcsname lang@uncoded\endcsname \else
+ \newnameddialect {nohyph} {uncoded} \fi
+\ifcsname lang@undetermined\endcsname \else
+ \newnameddialect {nohyph} {undetermined} \fi
+
+% 1 embedded files
+
+% provided by the lua module
+% \embedfile <options>
+
+% \setembeddedfilesmodate { yyyy-mm-dd }
+\newtoks\setembeddedfilesmoddate
+ \setembeddedfilesmoddate{}
+\newtoks\embeddedfiles:moddate
+\def\minim:makedefaultmoddate{%
+ \expandafter\edef\expandafter
+ \minim:tmp\expandafter{\the\setembeddedfilesmoddate}%
+ \embeddedfiles:moddate\expandafter{\minim:tmp}}
+
+% 1 declarations of pdf/a conformance
+
+\newcount \pdfaconformancelevel
+\pdfaconformancelevel = 0
+
+% \pdfalevel 2b
+\def\pdfalevel#1#2{%
+ \global\pdfaconformancelevel=#1\relax
+ \ifcsname minim:pdfa:#1#2\endcsname \lastnamedcs\else
+ \errmessage{Unknown pdf/a standard pdf/a-#1}\fi}
+
+\def\minim:pdfasettings#1#2#3{%
+ \pdfvariable minorversion #1\relax
+ \minim:default:rgb:profile
+ \if#2A\writedocumentstructure1\fi
+ \input minim-xmp
+ \setmetadata pdfaid:conformance{#2}%
+ \setmetadata pdfaid:part{#3}}
+
+\expandafter\def\csname minim:pdfa:1a\endcsname{\minim:pdfasettings 4A1}
+\expandafter\def\csname minim:pdfa:1b\endcsname{\minim:pdfasettings 4B1}
+\expandafter\def\csname minim:pdfa:2a\endcsname{\minim:pdfasettings 7A2}
+\expandafter\def\csname minim:pdfa:2b\endcsname{\minim:pdfasettings 7B2}
+\expandafter\def\csname minim:pdfa:2u\endcsname{\minim:pdfasettings 7U2}
+\expandafter\def\csname minim:pdfa:3a\endcsname{\minim:pdfasettings 7A3}
+\expandafter\def\csname minim:pdfa:3b\endcsname{\minim:pdfasettings 7B3}
+\expandafter\def\csname minim:pdfa:3u\endcsname{\minim:pdfasettings 7U3}
+
+% 
+
+\catcode`\: = \minimpdfloaded
+
diff --git a/macros/luatex/generic/minim/EUPL-1.2-EN.txt b/macros/luatex/generic/minim/EUPL-1.2-EN.txt
new file mode 100644
index 0000000000..4153cd3775
--- /dev/null
+++ b/macros/luatex/generic/minim/EUPL-1.2-EN.txt
@@ -0,0 +1,287 @@
+ EUROPEAN UNION PUBLIC LICENCE v. 1.2
+ EUPL © the European Union 2007, 2016
+
+This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined
+below) which is provided under the terms of this Licence. Any use of the Work,
+other than as authorised under this Licence is prohibited (to the extent such
+use is covered by a right of the copyright holder of the Work).
+
+The Work is provided under the terms of this Licence when the Licensor (as
+defined below) has placed the following notice immediately following the
+copyright notice for the Work:
+
+ Licensed under the EUPL
+
+or has expressed by any other means his willingness to license under the EUPL.
+
+1. Definitions
+
+In this Licence, the following terms have the following meaning:
+
+- ‘The Licence’: this Licence.
+
+- ‘The Original Work’: the work or software distributed or communicated by the
+ Licensor under this Licence, available as Source Code and also as Executable
+ Code as the case may be.
+
+- ‘Derivative Works’: the works or software that could be created by the
+ Licensee, based upon the Original Work or modifications thereof. This Licence
+ does not define the extent of modification or dependence on the Original Work
+ required in order to classify a work as a Derivative Work; this extent is
+ determined by copyright law applicable in the country mentioned in Article 15.
+
+- ‘The Work’: the Original Work or its Derivative Works.
+
+- ‘The Source Code’: the human-readable form of the Work which is the most
+ convenient for people to study and modify.
+
+- ‘The Executable Code’: any code which has generally been compiled and which is
+ meant to be interpreted by a computer as a program.
+
+- ‘The Licensor’: the natural or legal person that distributes or communicates
+ the Work under the Licence.
+
+- ‘Contributor(s)’: any natural or legal person who modifies the Work under the
+ Licence, or otherwise contributes to the creation of a Derivative Work.
+
+- ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of
+ the Work under the terms of the Licence.
+
+- ‘Distribution’ or ‘Communication’: any act of selling, giving, lending,
+ renting, distributing, communicating, transmitting, or otherwise making
+ available, online or offline, copies of the Work or providing access to its
+ essential functionalities at the disposal of any other natural or legal
+ person.
+
+2. Scope of the rights granted by the Licence
+
+The Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
+sublicensable licence to do the following, for the duration of copyright vested
+in the Original Work:
+
+- use the Work in any circumstance and for all usage,
+- reproduce the Work,
+- modify the Work, and make Derivative Works based upon the Work,
+- communicate to the public, including the right to make available or display
+ the Work or copies thereof to the public and perform publicly, as the case may
+ be, the Work,
+- distribute the Work or copies thereof,
+- lend and rent the Work or copies thereof,
+- sublicense rights in the Work or copies thereof.
+
+Those rights can be exercised on any media, supports and formats, whether now
+known or later invented, as far as the applicable law permits so.
+
+In the countries where moral rights apply, the Licensor waives his right to
+exercise his moral right to the extent allowed by law in order to make effective
+the licence of the economic rights here above listed.
+
+The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to
+any patents held by the Licensor, to the extent necessary to make use of the
+rights granted on the Work under this Licence.
+
+3. Communication of the Source Code
+
+The Licensor may provide the Work either in its Source Code form, or as
+Executable Code. If the Work is provided as Executable Code, the Licensor
+provides in addition a machine-readable copy of the Source Code of the Work
+along with each copy of the Work that the Licensor distributes or indicates, in
+a notice following the copyright notice attached to the Work, a repository where
+the Source Code is easily and freely accessible for as long as the Licensor
+continues to distribute or communicate the Work.
+
+4. Limitations on copyright
+
+Nothing in this Licence is intended to deprive the Licensee of the benefits from
+any exception or limitation to the exclusive rights of the rights owners in the
+Work, of the exhaustion of those rights or of other applicable limitations
+thereto.
+
+5. Obligations of the Licensee
+
+The grant of the rights mentioned above is subject to some restrictions and
+obligations imposed on the Licensee. Those obligations are the following:
+
+Attribution right: The Licensee shall keep intact all copyright, patent or
+trademarks notices and all notices that refer to the Licence and to the
+disclaimer of warranties. The Licensee must include a copy of such notices and a
+copy of the Licence with every copy of the Work he/she distributes or
+communicates. The Licensee must cause any Derivative Work to carry prominent
+notices stating that the Work has been modified and the date of modification.
+
+Copyleft clause: If the Licensee distributes or communicates copies of the
+Original Works or Derivative Works, this Distribution or Communication will be
+done under the terms of this Licence or of a later version of this Licence
+unless the Original Work is expressly distributed only under this version of the
+Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee
+(becoming Licensor) cannot offer or impose any additional terms or conditions on
+the Work or Derivative Work that alter or restrict the terms of the Licence.
+
+Compatibility clause: If the Licensee Distributes or Communicates Derivative
+Works or copies thereof based upon both the Work and another work licensed under
+a Compatible Licence, this Distribution or Communication can be done under the
+terms of this Compatible Licence. For the sake of this clause, ‘Compatible
+Licence’ refers to the licences listed in the appendix attached to this Licence.
+Should the Licensee's obligations under the Compatible Licence conflict with
+his/her obligations under this Licence, the obligations of the Compatible
+Licence shall prevail.
+
+Provision of Source Code: When distributing or communicating copies of the Work,
+the Licensee will provide a machine-readable copy of the Source Code or indicate
+a repository where this Source will be easily and freely available for as long
+as the Licensee continues to distribute or communicate the Work.
+
+Legal Protection: This Licence does not grant permission to use the trade names,
+trademarks, service marks, or names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the copyright notice.
+
+6. Chain of Authorship
+
+The original Licensor warrants that the copyright in the Original Work granted
+hereunder is owned by him/her or licensed to him/her and that he/she has the
+power and authority to grant the Licence.
+
+Each Contributor warrants that the copyright in the modifications he/she brings
+to the Work are owned by him/her or licensed to him/her and that he/she has the
+power and authority to grant the Licence.
+
+Each time You accept the Licence, the original Licensor and subsequent
+Contributors grant You a licence to their contributions to the Work, under the
+terms of this Licence.
+
+7. Disclaimer of Warranty
+
+The Work is a work in progress, which is continuously improved by numerous
+Contributors. It is not a finished work and may therefore contain defects or
+‘bugs’ inherent to this type of development.
+
+For the above reason, the Work is provided under the Licence on an ‘as is’ basis
+and without warranties of any kind concerning the Work, including without
+limitation merchantability, fitness for a particular purpose, absence of defects
+or errors, accuracy, non-infringement of intellectual property rights other than
+copyright as stated in Article 6 of this Licence.
+
+This disclaimer of warranty is an essential part of the Licence and a condition
+for the grant of any rights to the Work.
+
+8. Disclaimer of Liability
+
+Except in the cases of wilful misconduct or damages directly caused to natural
+persons, the Licensor will in no event be liable for any direct or indirect,
+material or moral, damages of any kind, arising out of the Licence or of the use
+of the Work, including without limitation, damages for loss of goodwill, work
+stoppage, computer failure or malfunction, loss of data or any commercial
+damage, even if the Licensor has been advised of the possibility of such damage.
+However, the Licensor will be liable under statutory product liability laws as
+far such laws apply to the Work.
+
+9. Additional agreements
+
+While distributing the Work, You may choose to conclude an additional agreement,
+defining obligations or services consistent with this Licence. However, if
+accepting obligations, You may act only on your own behalf and on your sole
+responsibility, not on behalf of the original Licensor or any other Contributor,
+and only if You agree to indemnify, defend, and hold each Contributor harmless
+for any liability incurred by, or claims asserted against such Contributor by
+the fact You have accepted any warranty or additional liability.
+
+10. Acceptance of the Licence
+
+The provisions of this Licence can be accepted by clicking on an icon ‘I agree’
+placed under the bottom of a window displaying the text of this Licence or by
+affirming consent in any other similar way, in accordance with the rules of
+applicable law. Clicking on that icon indicates your clear and irrevocable
+acceptance of this Licence and all of its terms and conditions.
+
+Similarly, you irrevocably accept this Licence and all of its terms and
+conditions by exercising any rights granted to You by Article 2 of this Licence,
+such as the use of the Work, the creation by You of a Derivative Work or the
+Distribution or Communication by You of the Work or copies thereof.
+
+11. Information to the public
+
+In case of any Distribution or Communication of the Work by means of electronic
+communication by You (for example, by offering to download the Work from a
+remote location) the distribution channel or media (for example, a website) must
+at least provide to the public the information requested by the applicable law
+regarding the Licensor, the Licence and the way it may be accessible, concluded,
+stored and reproduced by the Licensee.
+
+12. Termination of the Licence
+
+The Licence and the rights granted hereunder will terminate automatically upon
+any breach by the Licensee of the terms of the Licence.
+
+Such a termination will not terminate the licences of any person who has
+received the Work from the Licensee under the Licence, provided such persons
+remain in full compliance with the Licence.
+
+13. Miscellaneous
+
+Without prejudice of Article 9 above, the Licence represents the complete
+agreement between the Parties as to the Work.
+
+If any provision of the Licence is invalid or unenforceable under applicable
+law, this will not affect the validity or enforceability of the Licence as a
+whole. Such provision will be construed or reformed so as necessary to make it
+valid and enforceable.
+
+The European Commission may publish other linguistic versions or new versions of
+this Licence or updated versions of the Appendix, so far this is required and
+reasonable, without reducing the scope of the rights granted by the Licence. New
+versions of the Licence will be published with a unique version number.
+
+All linguistic versions of this Licence, approved by the European Commission,
+have identical value. Parties can take advantage of the linguistic version of
+their choice.
+
+14. Jurisdiction
+
+Without prejudice to specific agreement between parties,
+
+- any litigation resulting from the interpretation of this License, arising
+ between the European Union institutions, bodies, offices or agencies, as a
+ Licensor, and any Licensee, will be subject to the jurisdiction of the Court
+ of Justice of the European Union, as laid down in article 272 of the Treaty on
+ the Functioning of the European Union,
+
+- any litigation arising between other parties and resulting from the
+ interpretation of this License, will be subject to the exclusive jurisdiction
+ of the competent court where the Licensor resides or conducts its primary
+ business.
+
+15. Applicable Law
+
+Without prejudice to specific agreement between parties,
+
+- this Licence shall be governed by the law of the European Union Member State
+ where the Licensor has his seat, resides or has his registered office,
+
+- this licence shall be governed by Belgian law if the Licensor has no seat,
+ residence or registered office inside a European Union Member State.
+
+Appendix
+
+‘Compatible Licences’ according to Article 5 EUPL are:
+
+- GNU General Public License (GPL) v. 2, v. 3
+- GNU Affero General Public License (AGPL) v. 3
+- Open Software License (OSL) v. 2.1, v. 3.0
+- Eclipse Public License (EPL) v. 1.0
+- CeCILL v. 2.0, v. 2.1
+- Mozilla Public Licence (MPL) v. 2
+- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
+- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for
+ works other than software
+- European Union Public Licence (EUPL) v. 1.1, v. 1.2
+- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong
+ Reciprocity (LiLiQ-R+).
+
+The European Commission may update this Appendix to later versions of the above
+licences without producing a new version of the EUPL, as long as they provide
+the rights granted in Article 2 of this Licence and protect the covered Source
+Code from exclusive appropriation.
+
+All other changes or additions to this Appendix require the production of a new
+EUPL version.
diff --git a/macros/luatex/generic/minim/README b/macros/luatex/generic/minim/README
new file mode 100644
index 0000000000..4a16b4e801
--- /dev/null
+++ b/macros/luatex/generic/minim/README
@@ -0,0 +1,40 @@
+Version: 2021/1.0
+
+SUMMARY
+
+This is a modern plain format for the LuaTeX engine, adding improved low-level
+support for many LuaTeX extensions and newer PDF features. While it can be
+used as drop-in replacement for plain TeX, it probably is most useful as
+a basis for your own formats.
+
+Most features included in the format are provided by separate packages that
+can be used on their own; see the packages
+
+ minim-mp for mplib (MetaPost) support
+ minim-math for unicode mathematics
+ minim-pdf for creating Tagged PDF
+ minim-xmp for XMP (metadata) inclusion
+
+This package proper only contains their shared lowest-level programming
+interface, together with their combined format.
+
+
+DOCUMENTATION
+
+In order to obtain the typeset manual of this package, simply say:
+
+ luatex minim.doc
+
+For the sake of completeness, this manual also includes the documentation of
+the packages mentioned above.
+
+
+COPYING
+
+(c) 2021 Esger Renkema
+
+These files may be distributed under the terms of the European Union Public
+Licence (EUPL) version 1.2 or later. A copy can be obtained at:
+
+https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+
diff --git a/macros/luatex/generic/minim/minim-alloc.doc b/macros/luatex/generic/minim/minim-alloc.doc
new file mode 100644
index 0000000000..fa08988bf4
--- /dev/null
+++ b/macros/luatex/generic/minim/minim-alloc.doc
@@ -0,0 +1,216 @@
+
+\input minim-doc.sty
+
+This chapter describes the programming helper modules on which all the above
+modules depend. It mainly concerns register allocation, callback management and
+format file inclusion.
+
+They can be loaded separately by saying ⟦\input minim-alloc⟧;
+thereafter, you can use ⟦local M = require('minim-alloc')⟧ to access the lua
+interface.
+In this chapter, when discussing lua functions, you are assumed to have issued
+the latter statement, so that the table ⟦M⟧ refers to the contents of this
+module.
+
+The callback-related code lives in a separate file that can and must be loaded
+separately as ⟦local C = require('minim-callbacks')⟧. This is the only file in
+this collection that does not itself depend on the minim-alloc module.
+
+There is a large functional overlap between this module and the ltluatex
+package. You can use both at the same time, however, and the order in which you
+load both packages should not matter.
+
+\section Format files
+
+A major motivation for writing this module (and not, instead, depending on
+⟦ltluatex.tex⟧) is the ability to write lua-heavy code that can be safely
+included in format files.
+For this purpose, the register allocation functions described below allow
+ensuring that the allocation is made only once.
+
+Apart from registers, you need only do two more things to make your code format
+file safe. The first is saying ⟦*M.remember('your-file.lua')⟧ somewhere,
+anywhere. This will mark your file for inclusion in the format. At the start of
+every job, all remembered files will be executed (in order) and their return
+values will be stored to be retrieved whenever you say ⟦require('your-file')⟧.
+Note that while this feature does not improve speed in any meaningful way, it
+will ensure the lua file used by the format is identical to the one used to
+create it.
+
+It does mean, however, that your file may be executed twice: once when building
+the format and once when the format is used. In most cases (e.g. callback
+registration) this is exactly what you want.
+Sometimes however, you may need to store variable (configurable) data in the
+format file.
+You can do this by saying
+⟦*local t = M.saved_table('identifier', default-table)⟧.
+This will retrieve the table from the format file if possible; otherwise, it
+will return ⟦default-table⟧ and mark it to be saved to the format. A missing
+second argument is equivalent to an empty table.
+Saved tables may only contain (arbitrary but non-cyclic nestings of) tables,
+numbers and strings.
+
+\section Register allocation
+
+For allocating the new luatex registers, you can use the following:
+⟦*\newfunction⟧,
+⟦*\newattribute⟧,
+⟦*\newwhatsit⟧,
+⟦*\newluabytecode⟧,
+⟦*\newluachunkname⟧,
+⟦*\newcatcodetable⟧ and
+⟦*\newuserrule⟧.
+Note the one difference with ltluatex, which has ⟦\newluafunction⟧ instead.
+(The reason for this is that ltluatex, instead of a more sensible method, uses
+this macro for determining whether it has been read before.)
+Internally, the very same counts are used for keeping track of register
+allocation as in ltluatex.
+Their effect should therefore be identical in all circumstances, with one
+exception:
+no bounds checking is performed on any allocation macro defined by minim.
+Please do not go and use more than sixty five thousand different whatsits.
+
+All the above and all traditional registers can be allocated from within lua as
+well, using ⟦*M.new_count('name')⟧, ⟦*M.new_whatsit('name')⟧ etc. All return
+the allocated number. The (optional) string ⟦name⟧ prevents the same allocation
+from being made twice: if another register has been retrieved with the same
+name, the number of that register will be returned. You will need this when you
+want to allow your lua code to be included in a format file; it has nothing to
+do with the tex-side ⟦\countdef⟧ and the like.
+
+For the new allocation macros listed above and (as a special case) for
+⟦\newbox⟧,
+after saying ⟦\newwhatsit\name⟧, the call ⟦M.new_whatsit('name')⟧ will return
+the number of ⟦\name⟧. For the other (older) allocation macros, this is not the
+case. After all, because of the ⟦\countdef⟧ etc. included in ⟦\newcount⟧ etc.
+you can already use ⟦tex.count['name']⟧ etc. for retrieving tex-side
+allocations from lua. The exceptions to this are ⟦\newbox⟧, which is why it is
+included with the new macros, and ⟦\newattribute⟧, for which you can use both
+methods.
+
+Besides ⟦\newluachunkname\name⟧, you can also use
+⟦*\setluachunkname \name {actual name}⟧
+to enter the value of the name directly.
+
+Finally, for the registers for which etex defines a local allocation macro (and
+for those only), you can use ⟦*M.local_count()⟧ etc. These allocation functions
+take no parameters.
+
+
+\section Callbacks
+
+As noted at the beginning of this chapter, the callback functions are only
+available after you say ⟦local C = require('minim-callbacks')⟧.
+
+This module will override the primitive callback functions with its own
+⟦*C.register⟧, ⟦*C.find⟧ and ⟦*C.list⟧; the original primitive functions can be
+found in the ⟦*C.primitives⟧ table.
+
+The simple function of this module is allowing multiple callbacks to co-exist.
+Different callbacks call for different implementations, and some callbacks can
+only contain a single function.
+Any callbacks that are already assigned before loading this module will be
+preserved; this includes the ltluatex callback mechanism if it has already been
+installed.
+
+You can create your own callbacks with ⟦*C.new_callback(name, type)⟧. The ⟦type⟧
+should be one of the types mentioned below or ⟦'single'⟧ for callbacks that
+allow only one function. If the ⟦name⟧ is that of a primitive callback, new
+registrations will target your new callback.
+You can call the new callback with ⟦*C.call_callback(name, ...)⟧, adding any
+number of parameters.
+
+Callbacks of type ⟦*node⟧ operate on a node list: for these, all registered
+functions will be called in order, each function receiving the result of the
+last.
+After one function returns ⟦false⟧, no others will be called.
+Callbacks of this type are
+⟦pre_linebreak_filter⟧,
+⟦post_linebreak_filter⟧,
+⟦hpack_filter⟧,
+⟦vpack_filter⟧,
+⟦pre_output_filter⟧ and
+⟦mlist_to_mlist⟧.
+There is no way of unregistering callbacks of this type.
+
+Similarly, for the ⟦*data⟧ callbacks
+⟦process_input_buffer⟧,
+⟦process_output_buffer⟧ and
+⟦process_jobname⟧,
+all registered functions will be called in order on the output of the previous.
+Returning ⟦false⟧ will in this case result in the output of the previous
+function passing to the next.
+
+For ⟦*stack⟧ callbacks, a stack is kept and only the top function on the stack
+will be called. These are
+⟦mlist_to_hlist⟧,
+⟦hpack_quality⟧,
+⟦vpack_quality⟧,
+⟦hyphenate⟧,
+⟦linebreak_filter⟧,
+⟦buildpage_filter⟧ and
+⟦build_page_insert⟧.
+Register ⟦nil⟧ at the callback to pop a function off the stack.
+
+Finally, for the ⟦*simple⟧ callbacks
+⟦contribute_filter⟧,
+⟦pre_dump⟧,
+⟦wrapup_run⟧,
+⟦finish_pdffile⟧,
+⟦finish_pdfpage⟧,
+⟦insert_local_par⟧,
+⟦ligaturing⟧,
+⟦kerning⟧ and
+⟦process_rule⟧.
+all registered functions are called in order with the same arguments.
+
+The new ⟦*mlist_to_mlist⟧ callback is called before ⟦mlist_to_hlist⟧ and should
+not convert noads to nodes.
+
+If you create a new callback with a number for a name, that callback will
+replace the ⟦*process_rule⟧ callback when its number matches the index property
+of the rule.
+
+
+\section Miscellaneous functions
+
+This section describes functions and macros that are internal to this package,
+but might be of general usefulness.
+
+For instance, you might find the function ⟦*M.table_to_text(table)⟧ useful when
+debugging lua code.
+The small functions
+⟦*M.msg(...)⟧, ⟦*M.log(...)⟧ and ⟦*M.err(...)⟧
+include a call to ⟦M.string.format⟧;
+additionally,
+⟦*M.amsg(...)⟧ and ⟦*M.alog(...)⟧
+do not start a new line.
+
+Very useful is ⟦*M.luadef('csname', function, ...)⟧ for defining primitive-like
+tex macros from lua: ⟦function⟧ can be any function (it will be assigned a lua
+function register) and at the place of the dots you may append ⟦'protected'⟧
+and/or ⟦'global'⟧.
+
+Both ⟦*M.unset⟧ and ⟦*\unset⟧ contain the value ⟦-0x7FFFFFFF⟧ that can be used
+for clearing attributes.
+
+On the tex side, ⟦*\voidbox⟧, ⟦*\ignore⟧, ⟦*\spacechar⟧, ⟦*\unbrace⟧,
+⟦*\firstoftwo⟧ and ⟦*\secondoftwo⟧ should be self-explanatory and
+uncontroversial additions. For looking ahead, you can use
+⟦*\nextif \token {executed if present} {executed if not}⟧
+or its siblings ⟦*\nextifx⟧ and ⟦*\nextifcat⟧.
+For defining macros with optional arguments, ⟦*\withoptions[default]{code}⟧
+will ensure something within square brackets follows ⟦code⟧.
+
+Finally, ⟦*\splitcommalist {code} {list}⟧ will apply ⟦code⟧ to every nonempty
+item on a comma-separated ⟦list⟧.
+Items of the list will be re-tokenised and have surrounding spaces removed.
+This macro is fully expandable.
+
+Because of their usefulness and simplicity, these macros have been made
+available without special characters in their names; I hope you can tolerate
+their presence. Please let me know if their names clash with something
+important.
+
+\endinput
+
diff --git a/macros/luatex/generic/minim/minim-alloc.lua b/macros/luatex/generic/minim/minim-alloc.lua
new file mode 100644
index 0000000000..c99ca2c73d
--- /dev/null
+++ b/macros/luatex/generic/minim/minim-alloc.lua
@@ -0,0 +1,196 @@
+
+local M = {}
+
+-- 1 messages
+
+function M.msg(...)
+ texio.write_nl(string.format(...))
+end
+
+function M.amsg(...)
+ texio.write(string.format(...))
+end
+
+function M.log(...)
+ texio.write_nl('log', string.format(...))
+end
+
+function M.alog(...)
+ texio.write('log', string.format(...))
+end
+
+function M.term(...)
+ texio.write_nl('term', string.format(...))
+end
+
+function M.err (...)
+ tex.error(string.format(...))
+end
+
+-- 1 saving modules and tables
+
+local tables = package.loaded['minim-saved-tables']
+ or { ['minim:modules'] = { } }
+local modules = tables ['minim:modules']
+
+function M.remember (name)
+ if modules[name] == nil then
+ modules[name] = false -- will be a number if a bytecode register is reserved
+ modules[#modules+1] = name
+ end
+end
+
+function M.saved_table (identifier, table)
+ if tables[identifier] == nil then
+ tables[identifier] = table or { }
+ end
+ return tables[identifier]
+end
+
+-- saved tables may only contain values that can be converted to and from
+-- strings with tostring() or other tables meeting the same requirement.
+function M.table_to_text (tbl)
+ local r = { }
+ for i,t in pairs(tbl) do
+ local l = ''
+ if type(i) == 'string' then
+ l = string.format('[%q] = ', i)
+ else
+ l = string.format('[%s] = ', i)
+ end
+ if type(t) == 'table' then
+ l = l .. M.table_to_text (t)
+ elseif type(t) == 'string' then
+ l = l .. string.format ('%q', t)
+ else
+ l = l .. tostring(t)
+ end
+ r[#r+1] = l
+ end
+ return '{ ' .. table.concat (r,', ') .. ' }'
+end
+
+require('minim-callbacks')
+M.remember('minim-callbacks')
+M.remember('minim-alloc')
+
+-- 1 allocation functions
+
+-- like \unset
+M.unset = -0x7FFFFFFF
+
+local allocations = M.saved_table ('minim:allocations')
+
+local function make_alloc_new (fname, globcount)
+ allocations[fname] = allocations[fname] or { }
+ M['new_'..fname] = function (id)
+ local nr
+ if id and allocations[fname][id] then
+ nr = allocations[fname][id]
+ else
+ nr = tex.count[globcount] + 1
+ tex.setcount('global', globcount, nr)
+ if id then allocations[fname][id] = nr end
+ M.log('\\%s%d : %s', fname, nr, id or '<unnamed>')
+ end
+ return nr
+ end
+end
+
+make_alloc_new ('attribute' , 'e@alloc@attribute@count' )
+make_alloc_new ('whatsit' , 'e@alloc@whatsit@count' )
+make_alloc_new ('luabytecode' , 'e@alloc@bytecode@count' )
+make_alloc_new ('function' , 'e@alloc@luafunction@count' )
+make_alloc_new ('luachunkname' , 'e@alloc@luachunk@count' )
+make_alloc_new ('catcodetable' , 'e@alloc@ccodetable@count' )
+make_alloc_new ('userrule' , 'e@alloc@rule@count' )
+
+-- We need different allocation functions for the older registers, because
+-- etex’s global allocation macros are off-by-one w.r.t. all other.
+--
+local function make_alloc_old (fname, globcount, loccount)
+ allocations[fname] = allocations[fname] or { }
+ M['new_'..fname] = function (id)
+ local nr
+ if id and allocations[fname][id] then
+ nr = allocations[fname][id]
+ else
+ nr = tex.count[globcount]
+ tex.setcount('global', globcount, nr + 1)
+ if id then allocations[fname][id] = nr end
+ M.log('\\%s%d : %s', fname, nr, id or '<unnamed>')
+ end
+ return nr
+ end
+ M['local_'..fname] = function ()
+ local nr = tex.count[loccount] - 1
+ tex.setcount(loccount, nr)
+ return nr
+ end
+end
+
+-- existing allocation counters
+make_alloc_old ('count', 260, 270 )
+make_alloc_old ('dimen', 261, 271 )
+make_alloc_old ('skip', 262, 272 )
+make_alloc_old ('muskip', 263, 273 )
+make_alloc_old ('box', 264, 274 )
+make_alloc_old ('toks', 265, 275 )
+make_alloc_old ('marks', 266, 276 )
+
+function M.luadef (csname, fn, ...)
+ local nr = M.new_function(csname)
+ lua.get_functions_table()[nr] = fn
+ token.set_lua(csname, nr, ...)
+end
+
+M.luadef ('minim:rememberalloc', function()
+ allocations[token.scan_string()][token.scan_string()] = tex.count['allocationnumber']
+end)
+
+-- 1 dumping information to the format file
+
+-- reserve a bytecode register
+local saved_tables_bytecode = M.new_luabytecode('saved_tables_bytecode')
+
+-- we cannot use set_lua because lua functions are not included in the format file
+token.set_macro('minim:restoremodules', '\\luabytecodecall'..saved_tables_bytecode)
+
+local function dump_saved_tables()
+ M.msg('pre_dump: save modules and tables to format file')
+ -- save modules
+ for i,name in ipairs (modules) do
+ if not modules[name] then
+ M.msg('saving module '..name)
+ -- reserve (if necessary) a bytecode register
+ modules[name] = M.new_luabytecode ('module '..name)
+ -- store the file into the format file
+ lua.bytecode[modules[name]] = loadfile(kpse.find_file(name,'lua'))
+ end
+ end
+ -- save tables (and restore modules)
+ local saved_tables = [[
+
+ -- include all saved tables in this bytecode register
+ local t = ]]..M.table_to_text(tables)..[[
+
+ -- and make them available via require()
+ package.loaded['minim-saved-tables'] = t
+
+ -- restore all remembered modules from their saved bytecode
+ local s = t['minim:modules']
+ for _, name in ipairs (s) do
+ texio.write_nl('log', 'minim: restoring module '..name)
+ package.loaded[name] = lua.bytecode[ s[name] ] ()
+ end
+
+ ]]
+ lua.bytecode[saved_tables_bytecode] = load(saved_tables)
+end
+
+callback.register ('pre_dump', dump_saved_tables)
+
+--
+
+return M
+
diff --git a/macros/luatex/generic/minim/minim-alloc.tex b/macros/luatex/generic/minim/minim-alloc.tex
new file mode 100644
index 0000000000..66f08c9045
--- /dev/null
+++ b/macros/luatex/generic/minim/minim-alloc.tex
@@ -0,0 +1,184 @@
+
+\ifdefined \minimloaded
+ \message{(skipped)}
+ \expandafter\endinput\fi
+\chardef\minimloaded=\catcode`\:
+\catcode`\:=11
+
+% 1 settings
+
+\suppressoutererror = 1
+\frenchspacing
+
+% 1 programming macros
+
+\newbox\voidbox \setbox0=\box\voidbox
+
+\long\def\ignore#1{}
+\long\def\unbrace#1{#1}
+\long\def\firstoftwo#1#2{#1}
+\long\def\secondoftwo#1#2{#2}
+
+% \spacechar is equivalent to a space character
+{\let\@\relax \global\futurelet\spacechar\@ \relax}
+
+% \nextif c {yes} {no}
+\protected\def\nextif{\nextif:\if}
+% \nextifx c {yes} {no}
+\protected\def\nextifx{\nextif:\ifx}
+% \nextifcat c {yes} {no}
+\protected\def\nextifcat{\nextif:\ifcat}
+
+\long\def\nextif:#1#2#3#4{\begingroup % \if c {yes} {no}
+ \def\nextif:test{#1\nextif:token#2\relax
+ \expandafter\firstoftwo\else
+ \expandafter\secondoftwo\fi
+ {\endgroup#3}{\endgroup#4}}%
+ \futurelet\nextif:token\nextif:test}
+
+% \withoptions [default] {code}
+\protected\def\withoptions[#1]#2{\nextifx[{#2}{#2[#1]}} %]
+
+% \splitcommalist {code} {list}
+\def\splitcommalist#1#2{\splitcommalist:parse{#1}#2,\splitcommalist:end,}
+\def\splitcommalist:parse#1#2,{% command partial-list,
+ \ifx\splitcommalist:end#2\empty\else % test for end-of-list
+ \expandafter\splitcommalist:item
+ \expandafter{\scantextokens{#2}}{#1}\fi} % remove spaces
+\def\splitcommalist:item#1#2\fi{\fi
+ \ifx\splitcommalist:end#1\splitcommalist:end\else#2{#1}\fi
+ \splitcommalist:parse{#2}}
+\protected\def\splitcommalist:end{\splitcommalist:end}
+
+% \decompressedpdf
+\def\decompressedpdf{%
+ \pdfvariable compresslevel = 0
+ \pdfvariable objcompresslevel = 0
+ \pdfvariable recompress = 1
+}
+
+% \unset
+\newcount\unset \unset = -"7FFFFFFF
+
+% 1 ltluatex compatibility
+
+% repair ltluatex, which, without apparent reason, resets all allocation
+% counters, even if they already exist
+\def\minim:ltltx:file{ltluatex.tex}
+\let\ProvidesFile:saved=\ProvidesFile
+\def\ProvidesFile#1#2[#3]{%
+ \ifdefined\ProvidesFile:saved \ProvidesFile:saved{#1}#2[#3]\fi
+ \def\minim:ltltx:arg{#1}%
+ \ifx\minim:ltltx:file\minim:ltltx:arg
+ \let\ProvidesFile=\ProvidesFile:saved
+ \let\endinput:saved=\endinput
+ \protected\edef\endinput{%
+ \minim:ltltx:fix{e@alloc@attribute@count}%
+ \minim:ltltx:fix{e@alloc@whatsit@count}%
+ \minim:ltltx:fix{e@alloc@bytecode@count}%
+ \minim:ltltx:fix{e@alloc@luafunction@count}%
+ \minim:ltltx:fix{e@alloc@luachunk@count}%
+ \minim:ltltx:fix{e@alloc@ccodetable@count}%
+ % also patch in remembering allocations to lua
+ \alloc:patch \noexpand\attribute
+ \alloc:patch \noexpand\whatsit
+ \alloc:patch \noexpand\luabytecode
+ \alloc:patch \noexpand\luachunkname
+ \alloc:patch \noexpand\catcodetable
+ \alloc:patch \noexpand\userrule
+ % restore register allocation functions
+ \directlua{ local C = require('minim-callbacks')
+ callback.register, callback.find, callback.list
+ = C.register, C.find, C.list }%
+ \let\noexpand\endinput=\noexpand\endinput:saved
+ \noexpand\endinput}\fi}
+\def\minim:ltltx:fix#1{%
+ \ifnum0<\the\csname#1\endcsname
+ \wlog{Restoring \csname#1\endcsname to previous value \the\csname#1\endcsname}%
+ \expandafter\noexpand\csname#1\endcsname =\the\csname#1\endcsname\relax\fi}
+\protected\def\alloc:patch#1{%
+ \expandafter\expandafter\expandafter\let
+ \expandafter\expandafter\csname\csstring#1:ltluatex:new\endcsname
+ \csname new\csstring#1\endcsname
+ \expandafter\edef\csname new\csstring#1\endcsname##1{%
+ \noexpand\minim:rememberalloc{\csstring#1}{\noexpand\csstring##1}%
+ \expandafter\noexpand\csname\csstring#1:ltluatex:new\endcsname{##1}}}
+
+% 1 allocation
+
+% use global allocation (see etex.src)
+\let\newcount = \globcount
+\let\newdimen = \globdimen
+\let\newskip = \globskip
+\let\newmuskip = \globmuskip
+\let\newbox = \globbox
+\let\newtoks = \globtoks
+\let\newmarks = \globmarks
+
+% new allocation macros
+
+\def\alloc:makenew#1#2#3{%
+ \unless\ifcsname#3\endcsname
+ \expandafter\newcount \csname#3\endcsname
+ \csname#3\endcsname 0\fi
+ \ifcsname new\csstring#1\endcsname
+ \alloc:patch#1\else
+ \expandafter\edef\csname new\csstring#1\endcsname{%
+ \noexpand\minim:alloc\noexpand#1\noexpand#2%
+ \expandafter\noexpand\csname#3\endcsname}\fi}
+
+\def\minim:alloc#1#2#3#4{% \register \chardef \alloccount \name
+ \global\advance#31%
+ \allocationnumber#3%
+ \global#2#4\allocationnumber
+ \wlog{\string#4=\string#1\the\allocationnumber}%
+ % minim:rememberalloc will be defined from lua side
+ \minim:rememberalloc{\csstring#1}{\csstring#4}}
+
+% all names and counters below are identical to those from ltluatex
+% note: we cannot use \newluafunction, or ltluatex will not load
+\alloc:makenew \function \chardef {e@alloc@luafunction@count}
+\alloc:makenew \attribute \attributedef {e@alloc@attribute@count}
+\alloc:makenew \whatsit \chardef {e@alloc@whatsit@count}
+\alloc:makenew \luabytecode \chardef {e@alloc@bytecode@count}
+\alloc:makenew \luachunkname \chardef:chunk {e@alloc@luachunk@count}
+\alloc:makenew \catcodetable \catcode:chardef {e@alloc@ccodetable@count}
+\alloc:makenew \userrule \chardef {e@alloc@rule@count}
+
+% initialise new catcode tables
+\def\catcode:chardef#1#2{\chardef#1#2\initcatcodetable#2}
+\csname e@alloc@ccodetable@count\endcsname = 4 % because ltluatex allocates 4...
+
+% set initial chunk name value
+\def\chardef:chunk#1#2{\chardef#1#2\directlua{lua.name[\the#2]='\csstring#1'}}
+
+% \setluachunkname
+\protected\def\setluachunkname#1#2{\newluachunkname#1%
+ \directlua{lua.name[\the#1]='\luaescapestring{#2}'}}
+
+% patch in remembering box allocations
+\def\minim:boxchardef#1{%
+ \minim:rememberalloc{box}{\csstring#1}%
+ \mathchardef#1}
+\edef\newbox{%
+ \expandafter\noexpand\csname et@xglob\endcsname
+ 4\box\noexpand\minim:boxchardef}
+
+% undefine our helper functions
+\let\alloc:makenew=\undefined
+
+% 1 format file compatibility
+
+% all other work is done at the lua end
+\directlua { require ('minim-alloc') }
+\directlua { require ('minim-callbacks') }
+
+% restore lua modules (the macro will be defined from the lua end)
+\toksapp\everyjob{\minim:restoremodules
+ \message{... all done.}}
+
+% 
+
+\catcode`\:=\minimloaded
+\endinput
+
diff --git a/macros/luatex/generic/minim/minim-callbacks.lua b/macros/luatex/generic/minim/minim-callbacks.lua
new file mode 100644
index 0000000000..3ac075dc01
--- /dev/null
+++ b/macros/luatex/generic/minim/minim-callbacks.lua
@@ -0,0 +1,265 @@
+
+local M = {}
+
+local function log(msg, ...)
+ texio.write_nl('log', string.format(msg, ...))
+end
+
+-- 1 capturing the callback mechanism
+
+-- if ltluatex is loaded, we must get callback.register back
+if luatexbase ~= nil then
+ local luatex_base = luatexbase
+ luatexbase.uninstall ()
+ luatexbase = luatex_base
+end
+
+local primitives = { }
+M.primitives = primitives
+primitives.register = callback.register
+primitives.find = callback.find
+primitives.list = callback.list
+
+local own_callbacks = {}
+local callback_lists = {}
+local callback_stacks = {}
+
+-- 1 finding callbacks
+
+function M.find (name)
+ local f = own_callbacks[name]
+ if f == nil then
+ return primitives.find(name)
+ else
+ return f
+ end
+end
+
+function M.list (name)
+ local t = {}
+ for n,f in pairs(callback_lists) do
+ if f then
+ t[n] = #f
+ else
+ t[n] = false
+ end
+ end
+ for n,f in pairs(own_callbacks) do
+ if f then
+ t[n] = t[n] or true
+ else
+ t[n] = t[n] or false
+ end
+ end
+ for n,f in pairs(primitives.list()) do
+ if f then
+ t[n] = t[n] or true
+ else
+ t[n] = t[n] or false
+ end
+ end
+ return t
+end
+
+-- 1 registering callbacks
+
+local function register_simple (cb,f)
+ -- prefer user-defined callbacks over built-in
+ local x = own_callbacks[cb]
+ if x == nil then
+ return primitives.register (cb, f)
+ else
+ -- default to false because nil would delete the callback itself
+ own_callbacks[cb] = f or false
+ return -1
+ end
+end
+
+-- will be redefined later
+local function announce_callback(cb, f) end
+
+function M.register (cb, f)
+ announce_callback(cb, f)
+ local list = callback_lists[cb]
+ local stack = callback_stacks[cb]
+ if stack then
+ if f == nil then -- pop
+ local p = stack[#stack]
+ stack[#stack] = nil
+ return register_simple (cb,p)
+ else -- push
+ stack[#stack+1] = M.find (cb)
+ return register_simple (cb,f)
+ end
+ elseif list ~= nil then
+ list[#list+1] = f
+ return -2
+ else
+ return register_simple (cb,f)
+ end
+end
+
+
+-- 1 lists of callback functions
+
+local function call_list_node (lst)
+ return function (head, ...)
+ local list = callback_lists[lst]
+ for _,f in ipairs(list) do
+ local newhead = f(head,...)
+ if node.is_node(newhead) then
+ head = newhead
+ elseif newhead == false then
+ return false
+ end
+ end
+ return head
+ end
+end
+
+local function call_list_data (lst)
+ return function (str)
+ local list = callback_lists[lst]
+ for _,f in ipairs(list) do
+ str = f(str) or str
+ end
+ return str
+ end
+end
+
+local function call_list_simple (lst)
+ return function (...)
+ local list = callback_lists[lst]
+ for _,f in ipairs(list) do
+ f(...)
+ end
+ end
+end
+
+-- 1 creating and calling callbacks
+
+local function register_list (lst, fn)
+ M.register (lst, fn(lst))
+ callback_lists[lst] = {}
+end
+
+local function stack_callback (cb)
+ callback_stacks[cb] = {}
+end
+
+function M.new_callback (name, prop)
+ own_callbacks[name] = false -- false means empty here
+ if prop == 'stack' then
+ stack_callback (name)
+ elseif prop == 'node' then
+ register_list (name, call_list_node)
+ elseif prop == 'simple' then
+ register_list (name, call_list_simple)
+ elseif prop == 'data' then
+ register_list (name, call_list_data)
+ end
+end
+
+function M.call_callback (name, ...)
+ local f = own_callbacks[name]
+ if f then
+ return f (...)
+ else
+ return false
+ end
+end
+
+-- 1 initialisation
+
+-- save all registered callbacks
+local saved = {}
+for n,s in pairs(primitives.list()) do
+ if s then
+ log('save callback: %s', n)
+ saved[n] = callback.find(n)
+ end
+end
+
+-- replace the primitive registering
+callback.register = M.register
+callback.find = M.find
+callback.list = M.list
+
+-- string processing callbacks
+register_list ('process_input_buffer', call_list_data)
+register_list ('process_output_buffer', call_list_data)
+register_list ('process_jobname', call_list_data)
+
+-- node list processing callbacks
+register_list ('pre_linebreak_filter', call_list_node)
+register_list ('post_linebreak_filter', call_list_node)
+--register_list ('append_to_vlist_filter', call_list_node) -- TODO this breaks something
+register_list ('hpack_filter', call_list_node)
+register_list ('vpack_filter', call_list_node)
+register_list ('pre_output_filter', call_list_node)
+
+-- mlist_to_mlist and mlist_to_mlist
+M.new_callback ('mlist_to_mlist', 'node')
+M.new_callback ('mlist_to_hlist', 'stack')
+M.register ('mlist_to_hlist', node.mlist_to_hlist )
+primitives.register ('mlist_to_hlist', function (head, ...)
+ local newhead = M.call_callback ('mlist_to_mlist', head, ...)
+ if newhead ~= true then
+ head = newhead or head
+ end
+ newhead = M.call_callback ('mlist_to_hlist', head, ...)
+ return newhead
+end)
+
+-- simple listable callbacks
+register_list ('contribute_filter', call_list_simple)
+register_list ('pre_dump', call_list_simple)
+register_list ('wrapup_run', call_list_simple)
+register_list ('finish_pdffile', call_list_simple)
+register_list ('finish_pdfpage', call_list_simple)
+register_list ('insert_local_par', call_list_simple)
+
+register_list ('ligaturing', call_list_simple)
+register_list ('kerning', call_list_simple)
+
+-- stack callbacks
+stack_callback ('hpack_quality')
+stack_callback ('vpack_quality')
+stack_callback ('hyphenate')
+stack_callback ('linebreak_filter')
+stack_callback ('buildpage_filter')
+stack_callback ('build_page_insert')
+
+-- process_rule
+M.new_callback ('process_rule', 'simple')
+primitives.register ('process_rule', function (rule, ...)
+ local p = own_callbacks[rule.index]
+ if p then
+ p (rule, ...)
+ else
+ M.call_callback ('process_rule')
+ end
+end)
+
+-- restore all registered callbacks
+for n,f in pairs(saved) do
+ log('restore callback: %s', n)
+ M.register (n,f)
+end
+saved = nil
+
+
+local function announce_callback(cb, f)
+ if f then
+ log('callback added: %s', cb)
+ else
+ log('callback removed: %s', cb)
+ end
+end
+
+
+--
+
+return M
+
+
diff --git a/macros/luatex/generic/minim/minim-doc.sty b/macros/luatex/generic/minim/minim-doc.sty
new file mode 100644
index 0000000000..1d3c2d4cea
--- /dev/null
+++ b/macros/luatex/generic/minim/minim-doc.sty
@@ -0,0 +1,215 @@
+
+%% This is the style file for the manuals of the minim format and related
+%% packages.
+
+\ifdefined \manual
+ \expandafter\endinput\fi
+
+\input minim
+
+\pdfalevel 3a
+\overfullrule = 0pt
+
+% 1 page layout
+
+\pdfvariable horigin 0pt
+\pdfvariable vorigin 0pt
+\frenchspacing
+\raggedbottom
+
+\uselanguage{ukenglish}
+\hyphenation {
+ mark-tab-le-cell
+ }
+
+\parindent 0pt
+\baselineskip 12pt plus 1pt
+\parskip 8pt plus 4pt minus 1pt
+
+\abovedisplayskip 3pt plus 2pt
+\belowdisplayskip 4pt plus 2pt
+
+\hsize 12cm
+\vsize 56\baselineskip
+
+\voffset = \dimexpr (\pageheight-\vsize)/2\relax
+\hoffset = \dimexpr (\pagewidth-\hsize)/2\relax
+
+% 1 fonts
+
+\input luaotfload.sty
+\font\tenrm {Latin Modern Roman:script=latn;protrusion=default} at 10pt
+\font\tenbf {Latin Modern Roman/B:script=latn} at 10pt
+\font\tenit {Latin Modern Roman/I:script=latn} at 10pt
+\font\tentt {Latin Modern Mono:script=latn;+smcp} at 10pt
+\font\title {Latin Modern Roman/B:script=latn} at 12pt
+\font\Title {Latin Modern Roman/B:script=latn} at 16pt
+
+\font\tenmath {Latin Modern Math:mode=base;script=math;ssty=0} at 10pt
+\font\tenmaths {Latin Modern Math:mode=base;script=math;ssty=1} at 7pt
+\font\tenmathss {Latin Modern Math:mode=base;script=math;ssty=2} at 5pt
+\textfont 0 = \tenmath
+\scriptfont 0 = \tenmaths
+\scriptscriptfont 0 = \tenmathss
+
+\font\altmath {Tex Gyre Pagella Math:mode=base;script=math;ssty=0} at 10pt
+\font\altmaths {Tex Gyre Pagella Math:mode=base;script=math;ssty=1} at 7pt
+\font\altmathss {Tex Gyre Pagella Math:mode=base;script=math;ssty=2} at 5pt
+\textfont 1 = \altmath
+\scriptfont 1 = \altmaths
+\scriptscriptfont 1 = \altmathss
+
+\expandglyphsinfont \tenrm 40 25 5
+\protrudechars=2 \adjustspacing=2
+\tenrm
+
+\mathfam{blackboard, `\mscra-`\mscrz} 1
+
+% 1 code typesetting
+
+\def\red#1{\quitvmode\pdfextension
+ literal{0.75 0 0 rg}{#1}\pdfextension literal{0 g}}
+
+\def\emph#1{{\tenit #1\/}}
+
+\def\breakablespace{\penalty0~}
+\catcode`\⟦=\active
+\def⟦{\quitvmode\begingroup\catcode`\∥=0\relax
+ \markparagraphsfalse
+ \def\do##1{\catcode`##1=12}\dospecials
+ \catcode`\ =\active
+ \letcharcode`\ =\breakablespace\obeylines
+ \parskip0pt\tentt
+ \nextif*{\verbatim\ignore}{\expandafter\ignore\verbatim}}
+\def\verbatim#1⟧{\red{\markelement{Code}{#1}}\endgroup}
+
+% 1 the minim symbol
+
+\newbox\notehead
+\newmetapostinstance \mnmMP
+\runmetapost \mnmMP {
+beginfig(1)
+ w:=1/27; pickup pencircle scaled 1/9;
+ path c; c :=
+ (-3/5,-1/6 ) {down}..
+ (-1/5,-1/2 ) {right}..
+ ( 3/5, 1/6 ) {up}..
+ ( 1/5, 1/2 ) {left}.. cycle;
+ filldraw c withcolor .75 red;
+ path p; p :=
+ (-0.383-w,-0.323-w) ..tension 1.35.. (-0.094-w, 0.094+w) ..tension 1.5..
+ ( 0.383+w, 0.323+w) ..tension 1.35.. ( 0.094+w,-0.094-w) ..tension 1.5.. cycle ;
+ p := (-1,-1) -- (1,-1) -- (1,1) -- p -- (1,1) -- (-1,1) -- cycle ;
+ clip currentpicture to p;
+ draw (3/5, 1/6) -- (3/5, 5/2) withcolor .75 red;
+ setbounds currentpicture to c;
+ currentpicture := currentpicture scaled 8pt ;
+endfig;}
+\boxnextmpimage \mnmMP \notehead
+\setbox\notehead=\hbox{\markartifact{Layout}{\box\notehead}}
+\closemetapostinstance \mnmMP
+
+%
+% 1 document structure
+
+% page artifacts
+\edef\tmp{\markartifact{Pagination /Subtype/Footer}{\the\footline}}
+\footline\expandafter{\tmp}
+\def\footnoterule{\markartifact{Layout}{\kern-3\p@
+ \hrule width 2truein \kern 2.6\p@}} % the \hrule is .4pt high
+
+% \startlist \item x. ... \stoplist
+\def\listskip{\vskip 3pt plus 2pt\vskip-\parskip}
+\def\startlist{\smallskip\startelement{L}}
+\def\stoplist{\stopelement{L}\smallskip}
+\def\item#1.{\listskip
+ \nextpartag{LI}\hangindent2em\quitvmode
+ \hbox to 2em{\hss\startelement{Lbl}#1.~~}%
+ \startelement{LBody}\ignorespaces}
+
+% \chapter Title \par
+\addstructuretype Sect Chapter
+\protected\def\chapter#1 \par{%
+ \vfil\break
+ \ensurestopelement{Section}%
+ \startelement{Chapter}%
+ \outline open {#1}%
+ \nextpartag{H}\red{\Title#1\hfill\copy\notehead}%
+ \addtotoc{\chapter{#1}{\lastdestinationname}}%
+ \bigskip}
+
+% \section Title \par
+\addstructuretype Sect Section
+\protected\def\section#1 \par{%
+ \bigskip\penalty-50\relax
+ \startelement{Section}%
+ \outline closed {#1}%
+ \nextpartag{H}\quitvmode
+ \addtotoc{\section{#1}{\lastdestinationname}}%
+ \red{\title#1}%
+ \par\nobreak}
+
+% table of contents
+\newtoks\toc \newif\iftoc \toctrue
+\def\addtotoc#1{%
+ \iftoc \edef\toctmp{#1}%
+ \write\auxfile\expandafter
+ {\expandafter\toksapp\expandafter\toc
+ \expandafter{\toctmp{\the\count0}}}\fi\toctrue}
+
+% an auxiliary file
+\newread \auxfile
+\immediate\openin\auxfile = \jobname.aux
+\ifeof\auxfile
+ \def\next{}\else
+ \def\next{\input \jobname.aux}\fi
+\immediate\closein\auxfile \next
+\newwrite \auxfile
+\immediate\openout\auxfile = \jobname.aux
+
+\autotagformulas
+
+\def\maketitle{%
+ \setembeddedfilesmoddate {\getmetadata date}
+ \begingroup
+ \def\outline##1##{\ignore}
+ \tocfalse \chapter \getmetadata title
+ \hfill \tenrm version \getmetadata version
+ \par\endgroup
+ \marktableaslist \halign {\strut
+ \qquad##\quad&##\hfil\cr
+ author&\getmetadata author\cr
+ contact&{\def\tmp{@}\def\TMP{.}%
+ minim\tmp elrenkema\TMP nl}\cr}
+ \smallskip}
+
+% 1 Chapters and full manuals
+
+\def\licencesection{\section Licence
+
+\embedfile global file {EUPL-1.2-EN.txt}
+ desc {Licence for this package (EUPL).}
+ name LICENCE mimetype text/plain
+ relation Unspecified uncompressed
+
+This package may be distributed under the terms of the European Union Public
+Licence (EUPL) version 1.2 or later. An english version of this licence has
+been included as an attachment to this file; copies in other languages can be
+obtained at
+\stopformulatagging$$\hbox
+{\hyperlink url {https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12}%
+https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\endlink}$$\startformulatagging}
+
+
+% for identifying which file we are typesetting
+\edef\thejobname{\expandafter\scantextokens\expandafter{\jobname}}
+\newif \ifchapter
+\def\manual#1{\def\tmp{#1}\ifx\thejobname\tmp
+ \chapterfalse\else\chaptertrue\fi}
+\def\endmanual{\ifchapter\expandafter\endinput\else
+ \licencesection\expandafter\bye\fi}
+
+%  introduction
+
+\endinput
+
diff --git a/macros/luatex/generic/minim/minim-etex.tex b/macros/luatex/generic/minim/minim-etex.tex
new file mode 100644
index 0000000000..bdf71def16
--- /dev/null
+++ b/macros/luatex/generic/minim/minim-etex.tex
@@ -0,0 +1,413 @@
+
+% This is a stripped-down version of etex.src, meant as companion to
+% minim-plain.tex.
+%
+% It follows e-TeX V2.1;0-luatex2.
+%
+% The following has been removed:
+% - Module loading
+% - Version checks
+%
+% The following has been retained:
+% - Language handling (somewhat simplified)
+% - Tracing and logging extensions
+% - The \eTeX symbol
+% - Register allocation
+
+\catcode `\@=\catcode `\A
+
+% Define the language-handling commands
+
+\def \uselanguage #1%
+ {\ifcsname lang@#1\endcsname
+ \language=\csname lang@#1\endcsname
+ \lefthyphenmin=\csname lhm@#1\endcsname
+ \righthyphenmin=\csname rhm@#1\endcsname
+ \ifcsname lu@texhyphen@loaded@\the\language\endcsname \else
+ \global\expandafter\def\csname
+ lu@texhyphen@loaded@\the\language\endcsname{}%
+ \directlua{
+ if not status.ini_version then
+ require("luatex-hyphen")
+ luatexhyphen.loadlanguage("\luatexluaescapestring{#1}",
+ \the\language)
+ end}%
+ \fi
+ \ifdefined\uselanguage@hook \uselanguage@hook{#1}\fi
+ \else
+ \begingroup\errorcontextlines=0\relax
+ \errhelp {You are trying to use a language which has not previously
+ been defined; remember that any language you want to use
+ will need to have been specified at the time the format
+ was created.%
+ }%
+ \errmessage {Language #1 undefined.}\endgroup
+ \fi}
+
+\def \addlanguage #1#2#3#4#5{% language patterns exceptions lhm rhm
+ \expandafter\newlanguage \csname lang@#1\endcsname
+ \expandafter\chardef \csname lhm@#1\endcsname=#4
+ \expandafter\chardef \csname rhm@#1\endcsname=#5
+ \csname if\directlua{% do we want to skip this language now?
+ require("luatex-hyphen")
+ if (luatexhyphen.lookupname("\luatexluaescapestring{#1}") == nil)
+ or (\number\csname lang@#1\endcsname == 0) then
+ tex.sprint("false") % no, load it (execute 'else' part)
+ else
+ tex.sprint("true") % yes, skip
+ end}\endcsname
+ \else
+ \uselanguage {#1}%
+ \input #2
+ \if *#3*\else \input #3 \fi
+ \edef \fmtversion {\fmtversion/#1}%
+ \fi
+ \ifdefined\addlanguage@hook \addlanguage@hook{#1}\fi}
+
+% Decrement \count 19, because \newlanguage will increment it again
+
+\advance \count 19 by -1
+
+% We are about to try to process a user/site-specific file "language.def",
+% which establishes a Babel-like language selection environment.
+
+\input language.def
+
+% All that was just to set up natural language handling...
+% The "real" work of "etex.src", however, is to augment the non-primitives
+% of Plain.TeX to incorporate e-TeX specific features, and to add new
+% non-primitives to simplify access to new e-TeX specific primitives.
+
+\message {Augmenting the Plain TeX definitions:}
+\message {\string \tracingall;}
+
+\def \tracingall
+ {\tracingonline=\@ne
+ \tracingcommands=\thr@@ % plain.tex has \tw@
+ \tracingstats=\tw@
+ \tracingpages=\@ne
+ \tracingoutput=\@ne
+ \tracinglostchars=\tw@ % plain.tex has \@ne
+ \tracingmacros=\tw@
+ \tracingparagraphs=\@ne
+ \tracingrestores=\@ne
+ \showboxbreadth=\maxdimen
+ \showboxdepth=\maxdimen
+ \errorstopmode
+ \tracinggroups=\@ne
+ \tracingifs=\@ne
+ \tracingscantokens=\@ne
+ \tracingnesting=\@ne
+ \tracingassigns=\tw@
+ }
+
+\message {Adding new e-TeX definitions:}
+
+\message {\string \eTeX,}
+\def \eTeX {$\varepsilon$-\TeX} %%% the simple version, not suitable for maths;
+
+\message {\string \loggingall,}
+\def \loggingall {\tracingall \tracingonline=\z@}
+
+\message {\string \tracingnone,}
+\def \tracingnone
+ {\tracingassigns=\z@
+ \tracingnesting=\z@
+ \tracingscantokens=\z@
+ \tracingifs=\z@
+ \tracinggroups=\z@
+ \showboxdepth=\thr@@
+ \showboxbreadth=5
+ \tracingrestores=\z@
+ \tracingparagraphs=\z@
+ \tracingmacros=\z@
+ \tracinglostchars=\@ne
+ \tracingoutput=\z@
+ \tracingpages=\z@
+ \tracingstats=\z@
+ \tracingcommands=\z@
+ \tracingonline=\z@
+ }
+
+\message {register allocation;}
+
+\newcount \et@xins % our insertion counter (\insc@unt is used differently)
+
+% We have to adjust the Plain TeX register allocation counts for our
+% slightly modified book-keeping:
+
+\advance \count 10 by 1 % \count 10=23 % allocates \count registers 23, 24, ...
+\advance \count 11 by 1 % \count 11=10 % allocates \dimen registers 10, 11, ...
+\advance \count 12 by 1 % \count 12=10 % allocates \skip registers 10, 11, ...
+\advance \count 13 by 1 % \count 13=10 % allocates \muskip registers 10, 11, ...
+\advance \count 14 by 1 % \count 14=10 % allocates \box registers 10, 11, ...
+\advance \count 15 by 1 % \count 15=10 % allocates \toks registers 10, 11, ...
+\advance \count 16 by 1 % \count 16=0 % allocates input streams 0, 1, ...
+\advance \count 17 by 1 % \count 17=0 % allocates output streams 0, 1, ...
+\advance \count 18 by 1 % \count 18=4 % allocates math families 4, 5, ...
+\advance \count 19 by 1 % \count 19=0 % allocates \language codes 0, 1, ...
+
+\et@xins=\insc@unt % \et@xins=255 % allocates insertions 254, 253, ...
+
+% We don't change the Plain TeX definitions of \newcount, etc., but the
+% \alloc@ macro doing the actual work is redefined.
+
+% When the normal register pool for \count, \dimen, \skip, \muskip,
+% \box, or \toks registers is exhausted, we switch to the extended pool.
+
+\def \alloc@ #1#2#3#4#5%
+ {\ifnum \count 1#1 < #4% make sure there's still room
+ \allocationnumber=\count 1#1
+ \global \advance \count 1#1 by \@ne
+ \global #3#5=\allocationnumber
+ \wlog {\string #5=\string #2\the \allocationnumber}%
+ \else \ifnum #1 < 6
+ \begingroup \escapechar=\m@ne
+ \expandafter \alloc@@ \expandafter {\string #2}#5%
+ \else
+ \errmessage {No room for a new #2}%
+ \fi
+ \fi
+ }
+
+% The \expandafter construction used here allows the generation of
+% \newcount and \globcount from #1=count. Moreover (and more important)
+% this construction avoids the appearance of \outer macros inside
+% macro definitions or conditionals.
+
+\def \alloc@@ #1#2%
+ {\endgroup % restore \escapechar
+ \message {Normal \csname#1\endcsname register pool exhausted,
+ switching to extended pool.}%
+ \global \expandafter
+ \let \csname new#1\expandafter \endcsname \csname glob#1\endcsname
+ \csname new#1\endcsname#2%
+ }
+
+% We do change the Plain TeX definition of \newinsert
+
+\outer \def \newinsert #1%make sure there's still room for ...
+ {\ch@ck 0 \et@xins \count % ... a \count, ...
+ {\ch@ck 1 \et@xins \dimen % ... \dimen, ...
+ {\ch@ck 2 \et@xins \skip % ... \skip, ...
+ {\ch@ck 4 \et@xins \box % ... and \box register
+ {\global \advance \et@xins by \m@ne
+ \unless
+ \ifnum \insc@unt < \et@xins
+ \global \insc@unt=\et@xins
+ \fi
+ \allocationnumber=\et@xins
+ \global \chardef #1=\allocationnumber
+ \wlog {\string #1=\string \insert \the \allocationnumber}%
+ }%
+ }%
+ }%
+ }%
+ }
+
+\def \ch@ck #1#2#3#4%
+ {\ifnum \count 1#1 < #2#4\else \errmessage {No room for a new #3}\fi}
+
+% And we define \reserveinserts, so that you can say \reserveinserts{17}
+% in order to reserve room for up to 17 additional insertion classes that will
+% not be taken away by \newcount, \newdimen, \newskip, or \newbox.
+
+\outer \def \reserveinserts#1%
+ {\global \insc@unt=\numexpr \et@xins \ifnum #1 > \z@ -#1\fi \relax}
+
+\message {extended register allocation;}
+
+% Now, we define \globcount, \globbox, etc., so that you can say
+% \globcount\foo and \foo will be defined (with \countdef) to be the
+% next count register from the vastly larger but somewhat less efficient
+% extended register pool. We also define \loccount, etc., but these
+% register definitions are local to the current group.
+
+\count 260=277 % globally allocates \count registers 277, 278, ...
+\count 261=\@cclvi % globally allocates \dimen registers 256, 257, ...
+\count 262=\@cclvi % globally allocates \skip registers 256, 257, ...
+\count 263=\@cclvi % globally allocates \muskip registers 256, 257, ...
+\count 264=\@cclvi % globally allocates \box registers 256, 257, ...
+\count 265=\@cclvi % globally allocates \toks registers 256, 257, ...
+\count 266=\@ne % globally allocates \marks classes 1, 2, ...
+
+\def \et@xmaxregs {32768}
+
+\count 270=\et@xmaxregs % locally allocates \count registers 32767, 32766, ...
+\count 271=\et@xmaxregs % ditto for \dimen registers
+\count 272=\et@xmaxregs % ditto for \skip registers
+\count 273=\et@xmaxregs % ditto for \muskip registers
+\count 274=\et@xmaxregs % ditto for \box registers
+\count 275=\et@xmaxregs % ditto for \toks registers
+\count 276=\et@xmaxregs % ditto for \marks classes
+
+% \count registers 256-259 and 267-269 are not (yet) used
+
+\outer \def \globcount {\et@xglob 0 \count \countdef}
+ \def \loccount {\et@xloc 0 \count \countdef}
+\outer \def \globdimen {\et@xglob 1 \dimen \dimendef}
+ \def \locdimen {\et@xloc 1 \dimen \dimendef}
+\outer \def \globskip {\et@xglob 2 \skip \skipdef}
+ \def \locskip {\et@xloc 2 \skip \skipdef}
+\outer \def \globmuskip {\et@xglob 3 \muskip \muskipdef}
+ \def \locmuskip {\et@xloc 3 \muskip \muskipdef}
+\outer \def \globbox {\et@xglob 4 \box \mathchardef}
+ \def \locbox {\et@xloc 4 \box \mathchardef}
+\outer \def \globtoks {\et@xglob 5 \toks \toksdef}
+ \def \loctoks {\et@xloc 5 \toks \toksdef}
+\outer \def \globmarks {\et@xglob 6 \marks \mathchardef}
+ \def \locmarks {\et@xloc 6 \marks \mathchardef}
+
+\let\newmark=\globmarks %%% 2.0;14
+\let\newmarks=\globmarks
+
+\def \et@xglob #1#2#3#4%
+ {\et@xchk #1#2% make sure there's still room
+ {\allocationnumber=\count 26#1
+ \global \advance \count 26#1 by \@ne
+ \global #3#4=\allocationnumber
+ \wlog {\string #4=\string #2\the \allocationnumber}%
+ }%
+ }
+
+\def \et@xloc#1#2#3#4%
+ {\et@xchk #1#2% make sure there's still room
+ {\advance \count 27#1 by \m@ne
+ \allocationnumber=\count 27#1
+ #3#4=\allocationnumber
+ \wlog {\string #4=\string #2\the \allocationnumber \space (local)}%
+ }%
+ }
+
+\def \et@xchk #1#2#3%
+ {\ifnum \count 26#1 < \count 27#1
+ #3%
+ \else
+ \errmessage {No room for a new #2}%
+ \fi
+ }
+
+% Next we define \globcountblk, \loccountblk, etc., so that one can
+% write \globcountblk\foo{17} and \foo will be defined (with \mathchardef)
+% as the first (the zeroth?) of a block of 17 consecutive registers.
+% Thus the user is intended to reference elements <\foo+0> to <\foo+n-1>,
+% where n is the length of the block allocated.
+
+\outer \def \globcountblk {\et@xgblk 0 \count}
+ \def \loccountblk {\et@xlblk 0 \count}
+\outer \def \globdimenblk {\et@xgblk 1 \dimen}
+ \def \locdimenblk {\et@xlblk 1 \dimen}
+\outer \def \globskipblk {\et@xgblk 2 \skip}
+ \def \locskipblk {\et@xlblk 2 \skip}
+\outer \def \globmuskipblk {\et@xgblk 3 \muskip}
+ \def \locmuskipblk {\et@xlblk 3 \muskip}
+\outer \def \globboxblk {\et@xgblk 4 \box}
+ \def \locboxblk {\et@xlblk 4 \box}
+\outer \def \globtoksblk {\et@xgblk 5 \toks}
+ \def \loctoksblk {\et@xlblk 5 \toks}
+\outer \def \globmarksblk {\et@xgblk 6 \marks}
+ \def \locmarksblk {\et@xlblk 6 \marks}
+
+% And, both to provide a higher-level interface to the block allocation
+% scheme, and to demonstrate possible applications of the new \...expr
+% primitives, we also define \globcountvector and \loccountvector (etc)
+% which allow the user to access elements with embedded arithmetic, as in
+
+% \globcountvector \foo {12}
+% \foo {\count 0 + 3} = \foo {\count 1 * 2}
+
+\outer \def \globcountvector {\et@xgvec 0 \count}
+ \def \loccountvector {\et@xlvec 0 \count}
+\outer \def \globdimenvector {\et@xgvec 1 \dimen}
+ \def \locdimenvector {\et@xlvec 1 \dimen}
+\outer \def \globskipvector {\et@xgvec 2 \skip}
+ \def \locskipvector {\et@xlvec 2 \skip}
+\outer \def \globmuskipvector {\et@xgvec 3 \muskip}
+ \def \locmuskipvector {\et@xlvec 3 \muskip}
+\outer \def \globboxvector {\et@xgvec 4 \box}
+ \def \locboxvector {\et@xlvec 4 \box}
+\outer \def \globtoksvector {\et@xgvec 5 \toks}
+ \def \loctoksvector {\et@xlvec 5 \toks}
+\outer \def \globmarksvector {\et@xgvec 6 \marks}
+ \def \locmarksvector {\et@xlvec 6 \marks}
+
+\def \et@xgblk #1#2#3#4%
+ {\et@xchkblk #1#2{#4}% make sure there's still room
+ {\allocationnumber=\count 26#1
+ \global \advance \count 26#1 by #4%
+ \global \mathchardef #3=\allocationnumber
+ \wlog {\string #3=\string #2blk{\number #4} at \the \allocationnumber}%
+ }%
+ }
+
+\def \et@xlblk #1#2#3#4%
+ {\et@xchkblk #1#2{#4}% make sure there's still room
+ {\advance \count 27#1 by -#4%
+ \allocationnumber=\count 27#1
+ \mathchardef #3=\allocationnumber
+ \wlog {\string #3=\string #2blk{\number #4}
+ at \the \allocationnumber \space (local)%
+ }%
+ }%
+ }
+
+\begingroup
+\catcode `\# = 12
+\gdef \et@xhash {#}
+\endgroup
+
+\def \et@xgvec #1#2#3#4%
+ {\et@xchkblk #1#2{#4}% make sure there's still room
+ {\allocationnumber=\count 26#1
+ \global \advance \count 26#1 by #4%
+ \ifx #2\box
+ \def \2{}%
+ \else \ifx #2\marks
+ \def \2{}%
+ \else
+ \def \2{\string #2}%
+ \fi
+ \fi
+ \xdef #3##1{\2 \noexpand \numexpr \the \allocationnumber+##1\relax}%
+ \wlog {\string #3 {\et@xhash 1} =
+ \2 {\the \allocationnumber+\et@xhash 1} (global #2 vector)%
+ }%
+ }%
+ }
+
+\def \et@xlvec #1#2#3#4%
+ {\et@xchkblk #1#2{#4}% make sure there's still room
+ {\advance \count 27#1 by -#4%
+ \allocationnumber=\count27#1
+ \mathchardef #3=\allocationnumber
+ \ifx #2\box
+ \def \2{}%
+ \else \ifx #2\marks
+ \def \2{}%
+ \else
+ \def \2{\string #2}%
+ \fi
+ \fi
+ \edef #3##1{\2 \noexpand \numexpr \the \allocationnumber+##1\relax}%
+ \wlog {\string #3 {\et@xhash 1} =
+ \2 {\the \allocationnumber+\et@xhash 1} (local #2 vector)%
+ }%
+ }%
+ }
+
+\def \et@xchkblk #1#2#3#4%
+ {\ifnum #3 < \z@
+ \errmessage {Negative register block size \number #3}%
+ \else \ifnum \numexpr \count 26#1+#3 > \count 27#1
+ \errmessage {No room for new #2block of size \number#3}%
+ \else
+ #4%
+ \fi
+ \fi
+ }
+
+% And finally re-catcode commercial-at
+
+\catcode `\@=12
+
+
diff --git a/macros/luatex/generic/minim/minim-hooks.lua b/macros/luatex/generic/minim/minim-hooks.lua
new file mode 100644
index 0000000000..c399547c9e
--- /dev/null
+++ b/macros/luatex/generic/minim/minim-hooks.lua
@@ -0,0 +1,30 @@
+
+-- Adds a callback just before a box is shipped out, opposite to
+-- 'finish_pdfpage'.
+
+local alloc = require('minim-alloc')
+local cb = require ('minim-callbacks')
+alloc.remember('minim-hooks')
+
+local M = { }
+
+cb.new_callback('pre_shipout', 'simple')
+
+M.primitive_shipout = tex.shipout
+function tex.shipout(nr)
+ cb.call_callback('pre_shipout', nr)
+ M.primitive_shipout(nr)
+end
+
+local shipout_box = alloc.new_box('minim:shipout:box')
+
+alloc.luadef('minim:shipout', function()
+ tex.box[shipout_box] = token.scan_list()
+ cb.call_callback('pre_shipout', shipout_box)
+ -- we must let tex do the rest, because some other package may have
+ -- redefined \shipout before us.
+ tex.sprint(token.create('minim:shipout:do'))
+end, 'protected')
+
+return M
+
diff --git a/macros/luatex/generic/minim/minim-hooks.tex b/macros/luatex/generic/minim/minim-hooks.tex
new file mode 100644
index 0000000000..b3b8092654
--- /dev/null
+++ b/macros/luatex/generic/minim/minim-hooks.tex
@@ -0,0 +1,56 @@
+
+% The purpose of this module is allowing arbitrary code be run at specific
+% places. I have not yet included it in the manual, because I still am a bit
+% unsure about the details of the implementation.
+%
+% The first thing done here is inserting a callback into \shipout (and
+% tex.shipout) mirroring finish_pdf, allowing last-minute manipulation before
+% the pdf code will be assembled.
+%
+% The second feature is adding things to the beginning of a paragraph without
+% (seemingly) disturbing \everypar, and also adding things to the next
+% paragraph only.
+%
+% Both features are implemented in a way that is repeatable and should coexist
+% peacefully with other packages doing something of the same. But please let me
+% know if you run into any problems.
+
+\ifdefined\minimhooksloaded
+ \message{(skipped)}
+ \expandafter\endinput\fi
+\chardef\minimhooksloaded = \catcode`\:
+\catcode`\: = 11
+
+\input minim-alloc
+
+% 1 the pre_shipout callback
+
+\newbox\minim:shipout:box \let\minim:shipout:orig = \shipout
+\def\minim:shipout:do{\minim:shipout:orig\box\minim:shipout:box}
+\directlua{require('minim-hooks')} \let\shipout\minim:shipout
+
+% 1 invisibly adding to \everypar
+
+\let\minim:everypar = \everypar
+\newtoks\minim:ateverypar
+\newtoks\minim:atnextpar
+\newtoks\everypar \everypar\minim:everypar
+\minim:everypar\expandafter{\expandafter
+ \minim:changeparindent
+ % expansion makes this process repeatable
+ \expandafter\the\everypar
+ \the\minim:ateverypar
+ \minim:atnextpar\expandafter
+ {\expandafter}\the\minim:atnextpar}
+\let\minim:changeparindent = \relax % as of yet unused
+
+% There is no need for the following.
+
+%\let\minim:par = \par
+%\newtoks\minim:aftereverypar
+%\protected\def\par{\ifhmode \unskip
+% \the\minim:aftereverypar \fi \minim:par}
+
+\catcode`\: = \minimhooksloaded
+
+
diff --git a/macros/luatex/generic/minim/minim-lmodern.tex b/macros/luatex/generic/minim/minim-lmodern.tex
new file mode 100644
index 0000000000..61bc0054e9
--- /dev/null
+++ b/macros/luatex/generic/minim/minim-lmodern.tex
@@ -0,0 +1,28 @@
+
+% This file, used in the minim and minim-mp formats, replaces the named fonts
+% from plain.tex with latin modern equivalents.
+
+\ifdefined\minimlmodernloaded
+ \message{(skipped)}
+ \expandafter\endinput\fi
+\chardef\minimlmodernloaded=\catcode`\:
+\catcode`\:=11
+
+\def\preloadfont#1#2#3{\def#1{\initfontloader\font#1{#2}at#3#1}}
+\def\initfontloader{\input luaotfload.sty \let\initfontloader=\relax}
+
+\preloadfont \tenrm {Latin Modern Roman:script=latn;+liga;+kern;+dlig}{10pt}
+\preloadfont \tenit {Latin Modern Roman/I:script=latn;+liga;+kern;+dlig}{10pt}
+\preloadfont \tenbf {Latin Modern Roman/B:script=latn;+liga;+kern;+dlig}{10pt}
+\preloadfont \tensl {Latin Modern Roman Slanted:script=latn;+liga;+kern;+dlig}{10pt}
+\preloadfont \tentt {Latin Modern Mono:script=latn;+liga;+kern;+dlig}{10pt}
+
+\preloadfont\tenmath {Latin Modern Math:mode=base;script=math;ssty=0}{10pt}
+\preloadfont\tenmaths {Latin Modern Math:mode=base;script=math;ssty=1}{7pt}
+\preloadfont\tenmathss {Latin Modern Math:mode=base;script=math;ssty=2}{5pt}
+
+\toksapp\everyjob{\tenmath\tenmaths\tenmathss\tenrm
+ \textfont0=\tenmath\scriptfont0=\tenmaths\scriptscriptfont0=\tenmathss}
+
+\catcode`\:=\minimlmodernloaded
+
diff --git a/macros/luatex/generic/minim/minim-plain.tex b/macros/luatex/generic/minim/minim-plain.tex
new file mode 100644
index 0000000000..85fd802b8b
--- /dev/null
+++ b/macros/luatex/generic/minim/minim-plain.tex
@@ -0,0 +1,786 @@
+
+% This is a stripped-down version of plain TeX.
+%
+% It follows plain.tex version 3.141592653.
+%
+% The following has been removed:
+% - All fonts and font switches
+% - \fmtname and \fmtversion
+% - \mathcode, \delcode, \mathchardef, \mathaccent and \delimiter settings
+% - Most math-related macros
+% - Loading hyphen.tex
+
+\catcode`\{=1 % left brace is begin-group character
+\catcode`\}=2 % right brace is end-group character
+\catcode`\$=3 % dollar sign is math shift
+\catcode`\&=4 % ampersand is alignment tab
+\catcode`\#=6 % hash mark is macro parameter character
+\catcode`\^=7 \catcode`\^^K=7 % circumflex and uparrow are for superscripts
+\catcode`\_=8 \catcode`\^^A=8 % underline and downarrow are for subscripts
+\catcode`\^^I=10 % ascii tab is a blank space
+\chardef\active=13 \catcode`\~=\active % tilde is active
+\catcode`\^^L=\active \outer\def^^L{\par} % ascii form-feed is "\outer\par"
+
+\message{Preloading the plain format: codes,}
+
+% We had to define the \catcodes right away, before the message line,
+% since \message uses the { and } characters.
+% When INITEX (the TeX initializer) starts up,
+% it has defined the following \catcode values:
+% \catcode`\^^@=9 % ascii null is ignored
+% \catcode`\^^M=5 % ascii return is end-line
+% \catcode`\\=0 % backslash is TeX escape character
+% \catcode`\%=14 % percent sign is comment character
+% \catcode`\ =10 % ascii space is blank space
+% \catcode`\^^?=15 % ascii delete is invalid
+% \catcode`\A=11 ... \catcode`\Z=11 % uppercase letters
+% \catcode`\a=11 ... \catcode`\z=11 % lowercase letters
+% all others are type 12 (other)
+
+% Here is a list of the characters that have been specially catcoded:
+\def\dospecials{\do\ \do\\\do\{\do\}\do\$\do\&%
+ \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~}
+% (not counting ascii null, tab, linefeed, formfeed, return, delete)
+% Each symbol in the list is preceded by \do, which can be defined
+% if you want to do something to every item in the list.
+
+% We make @ signs act like letters, temporarily, to avoid conflict
+% between user names and internal control sequences of plain format.
+\catcode`@=11
+
+% INITEX sets \uccode`x=`X and \uccode `X=`X for all letters x,
+% and \lccode`x=`x, \lccode`X=`x; all other values are zero.
+% No changes to those tables are needed in plain TeX format.
+
+% INITEX sets \sfcode x=1000 for all x, except that \sfcode`X=999
+% for uppercase letters. The following changes are needed:
+\sfcode`\)=0 \sfcode`\'=0 \sfcode`\]=0
+% The \nonfrenchspacing macro will make further changes to \sfcode values.
+
+% To make the plain macros more efficient in time and space,
+% several constant values are declared here as control sequences.
+% If they were changed, anything could happen; so they are private symbols.
+\chardef\@ne=1
+\chardef\tw@=2
+\chardef\thr@@=3
+\chardef\sixt@@n=16
+\chardef\@cclv=255
+\mathchardef\@cclvi=256
+\mathchardef\@m=1000
+\mathchardef\@M=10000
+\mathchardef\@MM=20000
+
+% Allocation of registers
+
+% Here are macros for the automatic allocation of \count, \box, \dimen,
+% \skip, \muskip, and \toks registers, as well as \read and \write
+% stream numbers, \fam codes, \language codes, and \insert numbers.
+
+\message{registers,}
+
+% When a register is used only temporarily, it need not be allocated;
+% grouping can be used, making the value previously in the register return
+% after the close of the group. The main use of these macros is for
+% registers that are defined by one macro and used by others, possibly at
+% different nesting levels. All such registers should be defined through
+% these macros; otherwise conflicts may occur, especially when two or more
+% macro packages are being used at once.
+
+% The following counters are reserved:
+% 0 to 9 page numbering
+% 10 count allocation
+% 11 dimen allocation
+% 12 skip allocation
+% 13 muskip allocation
+% 14 box allocation
+% 15 toks allocation
+% 16 read file allocation
+% 17 write file allocation
+% 18 math family allocation
+% 19 language allocation
+% 20 insert allocation
+% 21 the most recently allocated number
+% 22 constant -1
+% New counters are allocated starting with 23, 24, etc. Other registers are
+% allocated starting with 10. This leaves 0 through 9 for the user to play
+% with safely, except that counts 0 to 9 are considered to be the page and
+% subpage numbers (since they are displayed during output). In this scheme,
+% \count 10 always contains the number of the highest-numbered counter that
+% has been allocated, \count 14 the highest-numbered box, etc.
+% Inserts are given numbers 254, 253, etc., since they require a \count,
+% \dimen, \skip, and \box all with the same number; \count 20 contains the
+% lowest-numbered insert that has been allocated. Of course, \box255 is
+% reserved for \output; \count255, \dimen255, and \skip255 can be used freely.
+
+% It is recommended that macro designers always use
+% \global assignments with respect to registers numbered 1, 3, 5, 7, 9, and
+% always non-\global assignments with respect to registers 0, 2, 4, 6, 8, 255.
+% This will prevent ``save stack buildup'' that might otherwise occur.
+
+\count10=22 % allocates \count registers 23, 24, ...
+\count11=9 % allocates \dimen registers 10, 11, ...
+\count12=9 % allocates \skip registers 10, 11, ...
+\count13=9 % allocates \muskip registers 10, 11, ...
+\count14=9 % allocates \box registers 10, 11, ...
+\count15=9 % allocates \toks registers 10, 11, ...
+\count16=-1 % allocates input streams 0, 1, ...
+\count17=-1 % allocates output streams 0, 1, ...
+\count18=3 % allocates math families 4, 5, ...
+\count19=0 % allocates \language codes 1, 2, ...
+\count20=255 % allocates insertions 254, 253, ...
+\countdef\insc@unt=20 % the insertion counter
+\countdef\allocationnumber=21 % the most recent allocation
+\countdef\m@ne=22 \m@ne=-1 % a handy constant
+\def\wlog{\immediate\write\m@ne} % write on log file (only)
+
+% Here are abbreviations for the names of scratch registers
+% that don't need to be allocated.
+
+\countdef\count@=255
+\dimendef\dimen@=0
+\dimendef\dimen@i=1 % global only
+\dimendef\dimen@ii=2
+\skipdef\skip@=0
+\toksdef\toks@=0
+
+% Now, we define \newcount, \newbox, etc. so that you can say \newcount\foo
+% and \foo will be defined (with \countdef) to be the next counter.
+% To find out which counter \foo is, you can look at \allocationnumber.
+% Since there's no \boxdef command, \chardef is used to define a \newbox,
+% \newinsert, \newfam, and so on.
+
+\outer\def\newcount{\alloc@0\count\countdef\insc@unt}
+\outer\def\newdimen{\alloc@1\dimen\dimendef\insc@unt}
+\outer\def\newskip{\alloc@2\skip\skipdef\insc@unt}
+\outer\def\newmuskip{\alloc@3\muskip\muskipdef\@cclvi}
+\outer\def\newbox{\alloc@4\box\chardef\insc@unt}
+\let\newtoks=\relax % we do this to allow plain.tex to be read in twice
+\outer\def\newhelp#1#2{\newtoks#1#1\expandafter{\csname#2\endcsname}}
+\outer\def\newtoks{\alloc@5\toks\toksdef\@cclvi}
+\outer\def\newread{\alloc@6\read\chardef\sixt@@n}
+\outer\def\newwrite{\alloc@7\write\chardef\sixt@@n}
+\outer\def\newfam{\alloc@8\fam\chardef\sixt@@n}
+\outer\def\newlanguage{\alloc@9\language\chardef\@cclvi}
+\def\alloc@#1#2#3#4#5{\global\advance\count1#1by\@ne
+ \ch@ck#1#4#2% make sure there's still room
+ \allocationnumber=\count1#1%
+ \global#3#5=\allocationnumber
+ \wlog{\string#5=\string#2\the\allocationnumber}}
+\outer\def\newinsert#1{\global\advance\insc@unt by\m@ne
+ \ch@ck0\insc@unt\count
+ \ch@ck1\insc@unt\dimen
+ \ch@ck2\insc@unt\skip
+ \ch@ck4\insc@unt\box
+ \allocationnumber=\insc@unt
+ \global\chardef#1=\allocationnumber
+ \wlog{\string#1=\string\insert\the\allocationnumber}}
+\def\ch@ck#1#2#3{\ifnum\count1#1<#2%
+ \else\errmessage{No room for a new #3}\fi}
+
+% Here are some examples of allocation.
+\newdimen\maxdimen \maxdimen=16383.99999pt % the largest legal <dimen>
+\newskip\hideskip \hideskip=-1000pt plus 1fill % negative but can grow
+\newskip\centering \centering=0pt plus 1000pt minus 1000pt
+\newdimen\p@ \p@=1pt % this saves macro space and time
+\newdimen\z@ \z@=0pt % can be used both for 0pt and 0
+\newskip\z@skip \z@skip=0pt plus0pt minus0pt
+\newbox\voidb@x % permanently void box register
+
+% And here's a different sort of allocation:
+% For example, \newif\iffoo creates \footrue, \foofalse to go with \iffoo.
+\outer\def\newif#1{\count@\escapechar \escapechar\m@ne
+ \expandafter\expandafter\expandafter
+ \def\@if#1{true}{\let#1=\iftrue}%
+ \expandafter\expandafter\expandafter
+ \def\@if#1{false}{\let#1=\iffalse}%
+ \@if#1{false}\escapechar\count@} % the condition starts out false
+\def\@if#1#2{\csname\expandafter\if@\string#1#2\endcsname}
+{\uccode`1=`i \uccode`2=`f \uppercase{\gdef\if@12{}}} % `if' is required
+
+% Assign initial values to TeX's parameters
+
+\message{parameters,}
+
+% All of TeX's numeric parameters are listed here,
+% but the code is commented out if no special value needs to be set.
+% INITEX makes all parameters zero except where noted.
+
+\pretolerance=100
+\tolerance=200 % INITEX sets this to 10000
+\hbadness=1000
+\vbadness=1000
+\linepenalty=10
+\hyphenpenalty=50
+\exhyphenpenalty=50
+\binoppenalty=700
+\relpenalty=500
+\clubpenalty=150
+\widowpenalty=150
+\displaywidowpenalty=50
+\brokenpenalty=100
+\predisplaypenalty=10000
+% \postdisplaypenalty=0
+% \interlinepenalty=0
+% \floatingpenalty=0, set during \insert
+% \outputpenalty=0, set before TeX enters \output
+\doublehyphendemerits=10000
+\finalhyphendemerits=5000
+\adjdemerits=10000
+% \looseness=0, cleared by TeX after each paragraph
+% \pausing=0
+% \holdinginserts=0
+% \tracingonline=0
+% \tracingmacros=0
+% \tracingstats=0
+% \tracingparagraphs=0
+% \tracingpages=0
+% \tracingoutput=0
+\tracinglostchars=1
+% \tracingcommands=0
+% \tracingrestores=0
+% \language=0
+\uchyph=1
+% \lefthyphenmin=2 \righthyphenmin=3 set below
+% \globaldefs=0
+% \maxdeadcycles=25 % INITEX does this
+% \hangafter=1 % INITEX does this, also TeX after each paragraph
+% \fam=0
+% \mag=1000 % INITEX does this
+% \escapechar=`\\ % INITEX does this
+\defaulthyphenchar=`\-
+\defaultskewchar=-1
+% \endlinechar=`\^^M % INITEX does this
+\newlinechar=-1
+\delimiterfactor=901
+% \time=now % TeX does this at beginning of job
+% \day=now % TeX does this at beginning of job
+% \month=now % TeX does this at beginning of job
+% \year=now % TeX does this at beginning of job
+\showboxbreadth=5
+\showboxdepth=3
+\errorcontextlines=5
+
+\hfuzz=0.1pt
+\vfuzz=0.1pt
+\overfullrule=5pt
+\hsize=6.5in
+\vsize=8.9in
+\maxdepth=4pt
+\splitmaxdepth=\maxdimen
+\boxmaxdepth=\maxdimen
+% \lineskiplimit=0pt, changed by \normalbaselines
+\delimitershortfall=5pt
+\nulldelimiterspace=1.2pt
+\scriptspace=0.5pt
+% \mathsurround=0pt
+% \predisplaysize=0pt, set before TeX enters $$
+% \displaywidth=0pt, set before TeX enters $$
+% \displayindent=0pt, set before TeX enters $$
+\parindent=20pt
+% \hangindent=0pt, zeroed by TeX after each paragraph
+% \hoffset=0pt
+% \voffset=0pt
+
+% \baselineskip=0pt, changed by \normalbaselines
+% \lineskip=0pt, changed by \normalbaselines
+\parskip=0pt plus 1pt
+\abovedisplayskip=12pt plus 3pt minus 9pt
+\abovedisplayshortskip=0pt plus 3pt
+\belowdisplayskip=12pt plus 3pt minus 9pt
+\belowdisplayshortskip=7pt plus 3pt minus 4pt
+% \leftskip=0pt
+% \rightskip=0pt
+\topskip=10pt
+\splittopskip=10pt
+% \tabskip=0pt
+% \spaceskip=0pt
+% \xspaceskip=0pt
+\parfillskip=0pt plus 1fil
+
+\thinmuskip=3mu
+\medmuskip=4mu plus 2mu minus 4mu
+\thickmuskip=5mu plus 5mu
+
+% We also define special registers that function like parameters:
+\newskip\smallskipamount \smallskipamount=3pt plus 1pt minus 1pt
+\newskip\medskipamount \medskipamount=6pt plus 2pt minus 2pt
+\newskip\bigskipamount \bigskipamount=12pt plus 4pt minus 4pt
+\newskip\normalbaselineskip \normalbaselineskip=12pt
+\newskip\normallineskip \normallineskip=1pt
+\newdimen\normallineskiplimit \normallineskiplimit=0pt
+\newdimen\jot \jot=3pt
+\newcount\interdisplaylinepenalty \interdisplaylinepenalty=100
+\newcount\interfootnotelinepenalty \interfootnotelinepenalty=100
+
+% Definitions for preloaded fonts
+
+\def\magstephalf{1095 }
+\def\magstep#1{\ifcase#1 \@m\or 1200\or 1440\or 1728\or 2074\or 2488\fi\relax}
+
+\message{fonts (omitted),}
+
+\def\rm{\fam\z@\tenrm}
+\def\mit{\fam\@ne}
+\def\cal{\fam\tw@}
+\def\it{\fam4\tenit}
+\def\sl{\fam5\tensl}
+\def\bf{\fam6\tenbf}
+\def\tt{\fam7\tentt}
+
+% Macros for setting ordinary text
+\message{macros,}
+
+\def\frenchspacing{\sfcode`\.\@m \sfcode`\?\@m \sfcode`\!\@m
+ \sfcode`\:\@m \sfcode`\;\@m \sfcode`\,\@m}
+\def\nonfrenchspacing{\sfcode`\.3000\sfcode`\?3000\sfcode`\!3000%
+ \sfcode`\:2000\sfcode`\;1500\sfcode`\,1250 }
+
+\def\normalbaselines{\lineskip\normallineskip
+ \baselineskip\normalbaselineskip \lineskiplimit\normallineskiplimit}
+
+\def\^^M{\ } % control <return> = control <space>
+\def\^^I{\ } % same for <tab>
+
+\def\lq{`} \def\rq{'}
+\def\lbrack{[} \def\rbrack{]}
+
+\let\endgraf=\par \let\endline=\cr
+
+\def\space{ }
+\def\empty{}
+\def\null{\hbox{}}
+
+\let\bgroup={ \let\egroup=}
+
+% In \obeylines, we say `\let^^M=\par' instead of `\def^^M{\par}'
+% since this allows, for example, `\let\par=\cr \obeylines \halign{...'
+{\catcode`\^^M=\active % these lines must end with %
+ \gdef\obeylines{\catcode`\^^M\active \let^^M\par}%
+ \global\let^^M\par} % this is in case ^^M appears in a \write
+\def\obeyspaces{\catcode`\ \active}
+{\obeyspaces\global\let =\space}
+
+\def\loop#1\repeat{\def\body{#1}\iterate}
+\def\iterate{\body \let\next\iterate \else\let\next\relax\fi \next}
+\let\repeat=\fi % this makes \loop...\if...\repeat skippable
+
+\def\thinspace{\kern .16667em }
+\def\negthinspace{\kern-.16667em }
+\def\enspace{\kern.5em }
+
+\def\enskip{\hskip.5em\relax}
+\def\quad{\hskip1em\relax}
+\def\qquad{\hskip2em\relax}
+
+\def\smallskip{\vskip\smallskipamount}
+\def\medskip{\vskip\medskipamount}
+\def\bigskip{\vskip\bigskipamount}
+
+\def\nointerlineskip{\prevdepth-1000\p@}
+\def\offinterlineskip{\baselineskip-1000\p@
+ \lineskip\z@ \lineskiplimit\maxdimen}
+
+\def\topglue{\nointerlineskip\vglue-\topskip\vglue} % for top of page
+\def\vglue{\afterassignment\vgl@\skip@=}
+\def\vgl@{\par \dimen@\prevdepth \hrule height\z@
+ \nobreak\vskip\skip@ \prevdepth\dimen@}
+\def\hglue{\afterassignment\hgl@\skip@=}
+\def\hgl@{\leavevmode \count@\spacefactor \vrule width\z@
+ \nobreak\hskip\skip@ \spacefactor\count@}
+
+\def~{\penalty\@M \ } % tie
+\def\slash{/\penalty\exhyphenpenalty} % a `/' that acts like a `-'
+
+\def\break{\penalty-\@M}
+\def\nobreak{\penalty \@M}
+\def\allowbreak{\penalty \z@}
+
+\def\filbreak{\par\vfil\penalty-200\vfilneg}
+\def\goodbreak{\par\penalty-500 }
+\def\eject{\par\break}
+\def\supereject{\par\penalty-\@MM}
+
+\def\removelastskip{\ifdim\lastskip=\z@\else\vskip-\lastskip\fi}
+\def\smallbreak{\par\ifdim\lastskip<\smallskipamount
+ \removelastskip\penalty-50\smallskip\fi}
+\def\medbreak{\par\ifdim\lastskip<\medskipamount
+ \removelastskip\penalty-100\medskip\fi}
+\def\bigbreak{\par\ifdim\lastskip<\bigskipamount
+ \removelastskip\penalty-200\bigskip\fi}
+
+\def\line{\hbox to\hsize}
+\def\leftline#1{\line{#1\hss}}
+\def\rightline#1{\line{\hss#1}}
+\def\centerline#1{\line{\hss#1\hss}}
+
+\def\rlap#1{\hbox to\z@{#1\hss}}
+\def\llap#1{\hbox to\z@{\hss#1}}
+
+\def\m@th{\mathsurround\z@}
+\def\underbar#1{$\setbox\z@\hbox{#1}\dp\z@\z@
+ \m@th \underline{\box\z@}$}
+
+\newbox\strutbox
+\setbox\strutbox=\hbox{\vrule height8.5pt depth3.5pt width\z@}
+\def\strut{\relax\ifmmode\copy\strutbox\else\unhcopy\strutbox\fi}
+
+\def\hidewidth{\hskip\hideskip} % for alignment entries that can stick out
+\def\ialign{\everycr{}\tabskip\z@skip\halign} % initialized \halign
+\newcount\mscount
+\def\multispan#1{\omit \mscount#1\relax
+ \loop\ifnum\mscount>\@ne \sp@n\repeat}
+\def\sp@n{\span\omit\advance\mscount\m@ne}
+
+\newif\ifus@ \newif\if@cr
+\newbox\tabs \newbox\tabsyet \newbox\tabsdone
+
+\def\cleartabs{\global\setbox\tabsyet\null \setbox\tabs\null}
+\def\settabs{\setbox\tabs\null \futurelet\next\sett@b}
+\let\+=\relax % in case this file is being read in twice
+\def\sett@b{\ifx\next\+\def\nxt{\afterassignment\s@tt@b\let\nxt}%
+ \else\let\nxt\s@tcols\fi \let\next\relax \nxt}
+\def\s@tt@b{\let\nxt\relax \us@false\m@ketabbox}
+\def\tabalign{\us@true\m@ketabbox} % non-\outer version of \+
+\outer\def\+{\tabalign}
+\def\s@tcols#1\columns{\count@#1\dimen@\hsize
+ \loop\ifnum\count@>\z@ \@nother \repeat}
+\def\@nother{\dimen@ii\dimen@ \divide\dimen@ii\count@
+ \setbox\tabs\hbox{\hbox to\dimen@ii{}\unhbox\tabs}%
+ \advance\dimen@-\dimen@ii \advance\count@\m@ne}
+
+\def\m@ketabbox{\begingroup
+ \global\setbox\tabsyet\copy\tabs
+ \global\setbox\tabsdone\null
+ \def\cr{\@crtrue\crcr\egroup\egroup
+ \ifus@\unvbox\z@\lastbox\fi\endgroup
+ \setbox\tabs\hbox{\unhbox\tabsyet\unhbox\tabsdone}}%
+ \setbox\z@\vbox\bgroup\@crfalse
+ \ialign\bgroup&\t@bbox##\t@bb@x\crcr}
+
+\def\t@bbox{\setbox\z@\hbox\bgroup}
+\def\t@bb@x{\if@cr\egroup % now \box\z@ holds the column
+ \else\hss\egroup \global\setbox\tabsyet\hbox{\unhbox\tabsyet
+ \global\setbox\@ne\lastbox}% now \box\@ne holds its size
+ \ifvoid\@ne\global\setbox\@ne\hbox to\wd\z@{}%
+ \else\setbox\z@\hbox to\wd\@ne{\unhbox\z@}\fi
+ \global\setbox\tabsdone\hbox{\box\@ne\unhbox\tabsdone}\fi
+ \box\z@}
+
+\def\hang{\hangindent\parindent}
+\def\textindent#1{\indent\llap{#1\enspace}\ignorespaces}
+\def\item{\par\hang\textindent}
+\def\itemitem{\par\indent \hangindent2\parindent \textindent}
+\def\narrower{\advance\leftskip\parindent
+ \advance\rightskip\parindent}
+
+\outer\def\beginsection#1\par{\vskip\z@ plus.3\vsize\penalty-250
+ \vskip\z@ plus-.3\vsize\bigskip\vskip\parskip
+ \message{#1}\leftline{\bf#1}\nobreak\smallskip\noindent}
+\outer\def\proclaim #1. #2\par{\medbreak
+ \noindent{\bf#1.\enspace}{\sl#2\par}%
+ \ifdim\lastskip<\medskipamount \removelastskip\penalty55\medskip\fi}
+
+\def\raggedright{\rightskip\z@ plus2em \spaceskip.3333em \xspaceskip.5em\relax}
+\def\ttraggedright{\tt\rightskip\z@ plus2em\relax} % for use with \tt only
+
+\chardef\%=`\%
+\chardef\&=`\&
+\chardef\#=`\#
+\chardef\$=`\$
+
+\def\leavevmode{\unhbox\voidb@x} % begins a paragraph, if necessary
+\def\_{\leavevmode \kern.06em \vbox{\hrule width.3em}}
+\def\AA{\leavevmode\setbox0\hbox{!}\dimen@\ht0\advance\dimen@-1ex%
+ \rlap{\raise.67\dimen@\hbox{\char'27}}A}
+
+\def\mathhexbox#1#2#3{\leavevmode
+ \hbox{$\m@th \mathchar"#1#2#3$}}
+
+\def\oalign#1{\leavevmode\vtop{\baselineskip\z@skip \lineskip.25ex%
+ \ialign{##\crcr#1\crcr}}} \def\o@lign{\lineskiplimit\z@ \oalign}
+\def\ooalign{\lineskiplimit-\maxdimen \oalign} % chars over each other
+{\catcode`p=12 \catcode`t=12 \gdef\\#1pt{#1}} \let\getf@ctor=\\
+\def\sh@ft#1{\dimen@#1\kern\expandafter\getf@ctor\the\fontdimen1\font
+ \dimen@} % kern by #1 times the current slant
+\def\d#1{{\o@lign{\relax#1\crcr\hidewidth\sh@ft{-1ex}.\hidewidth}}}
+\def\b#1{{\o@lign{\relax#1\crcr\hidewidth\sh@ft{-3ex}%
+ \vbox to.2ex{\hbox{\char22}\vss}\hidewidth}}}
+\def\c#1{{\setbox\z@\hbox{#1}\ifdim\ht\z@=1ex\accent24 #1%
+ \else\ooalign{\unhbox\z@\crcr\hidewidth\char24\hidewidth}\fi}}
+\def\copyright{{\ooalign{\hfil\raise.07ex\hbox{c}\hfil\crcr\Orb}}}
+
+\def\dots{\relax\ifmmode\ldots\else$\m@th\ldots\,$\fi}
+\def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX}
+
+\def\`#1{{\accent18 #1}}
+\def\'#1{{\accent19 #1}}
+\def\v#1{{\accent20 #1}} \let\^^_=\v
+\def\u#1{{\accent21 #1}} \let\^^S=\u
+\def\=#1{{\accent22 #1}}
+\def\^#1{{\accent94 #1}} \let\^^D=\^
+\def\.#1{{\accent95 #1}}
+\def\H#1{{\accent"7D #1}}
+\def\~#1{{\accent"7E #1}}
+\def\"#1{{\accent"7F #1}}
+\def\t#1{{\edef\next{\the\font}\the\textfont1\accent"7F\next#1}}
+
+\def\hrulefill{\leaders\hrule\hfill}
+\def\dotfill{\cleaders\hbox{$\m@th \mkern1.5mu.\mkern1.5mu$}\hfill}
+\def\rightarrowfill{$\m@th\smash-\mkern-7mu%
+ \cleaders\hbox{$\mkern-2mu\smash-\mkern-2mu$}\hfill
+ \mkern-7mu\mathord\rightarrow$}
+\def\leftarrowfill{$\m@th\mathord\leftarrow\mkern-7mu%
+ \cleaders\hbox{$\mkern-2mu\smash-\mkern-2mu$}\hfill
+ \mkern-7mu\smash-$}
+\mathchardef\braceld="37A \mathchardef\bracerd="37B
+\mathchardef\bracelu="37C \mathchardef\braceru="37D
+\def\downbracefill{$\m@th \setbox\z@\hbox{$\braceld$}%
+ \braceld\leaders\vrule height\ht\z@ depth\z@\hfill\braceru
+ \bracelu\leaders\vrule height\ht\z@ depth\z@\hfill\bracerd$}
+\def\upbracefill{$\m@th \setbox\z@\hbox{$\braceld$}%
+ \bracelu\leaders\vrule height\ht\z@ depth\z@\hfill\bracerd
+ \braceld\leaders\vrule height\ht\z@ depth\z@\hfill\braceru$}
+
+\outer\def\bye{\par\vfill\supereject\end}
+
+% Macros for math setting
+\message{math definitions,}
+
+\let\sp=^ \let\sb=_
+\def\,{\mskip\thinmuskip}
+\def\>{\mskip\medmuskip}
+\def\;{\mskip\thickmuskip}
+\def\!{\mskip-\thinmuskip}
+\def\*{\discretionary{\thinspace\the\textfont2\char2}{}{}}
+{\catcode`\'=\active \gdef'{^\bgroup\prim@s}}
+\def\prim@s{\prime\futurelet\next\pr@m@s}
+\def\pr@m@s{\ifx'\next\let\nxt\pr@@@s \else\ifx^\next\let\nxt\pr@@@t
+ \else\let\nxt\egroup\fi\fi \nxt}
+\def\pr@@@s#1{\prim@s} \def\pr@@@t#1#2{#2\egroup}
+{\catcode`\^^Z=\active \gdef^^Z{\not=}} % ^^Z is like \ne in math
+
+{\catcode`\_=\active \global\let_=\_} % _ in math is either subscript or \_
+
+\def\joinrel{\mathrel{\mkern-3mu}}
+\def\relbar{\mathrel{\smash-}} % \smash, because - has the same height as +
+\def\Relbar{\mathrel=}
+\def\bowtie{\mathrel\triangleright\joinrel\mathrel\triangleleft}
+\def\models{\mathrel|\joinrel=}
+\def\Longrightarrow{\Relbar\joinrel\Rightarrow}
+\def\longrightarrow{\relbar\joinrel\rightarrow}
+\def\longleftarrow{\leftarrow\joinrel\relbar}
+\def\Longleftarrow{\Leftarrow\joinrel\Relbar}
+\def\longmapsto{\mapstochar\longrightarrow}
+\def\longleftrightarrow{\leftarrow\joinrel\rightarrow}
+\def\Longleftrightarrow{\Leftarrow\joinrel\Rightarrow}
+\def\iff{\;\Longleftrightarrow\;}
+
+\def\ldots{\mathinner{\ldotp\ldotp\ldotp}}
+\def\cdots{\mathinner{\cdotp\cdotp\cdotp}}
+
+\def\skew#1#2#3{{\muskip\z@#1mu\divide\muskip\z@\tw@ \mkern\muskip\z@
+ #2{\mkern-\muskip\z@{#3}\mkern\muskip\z@}\mkern-\muskip\z@}{}}
+
+\def\bigl{\mathopen\big}
+\def\bigm{\mathrel\big}
+\def\bigr{\mathclose\big}
+\def\Bigl{\mathopen\Big}
+\def\Bigm{\mathrel\Big}
+\def\Bigr{\mathclose\Big}
+\def\biggl{\mathopen\bigg}
+\def\biggm{\mathrel\bigg}
+\def\biggr{\mathclose\bigg}
+\def\Biggl{\mathopen\Bigg}
+\def\Biggm{\mathrel\Bigg}
+\def\Biggr{\mathclose\Bigg}
+\def\big#1{{\hbox{$\left#1\vbox to8.5\p@{}\right.\n@space$}}}
+\def\Big#1{{\hbox{$\left#1\vbox to11.5\p@{}\right.\n@space$}}}
+\def\bigg#1{{\hbox{$\left#1\vbox to14.5\p@{}\right.\n@space$}}}
+\def\Bigg#1{{\hbox{$\left#1\vbox to17.5\p@{}\right.\n@space$}}}
+\def\n@space{\nulldelimiterspace\z@ \m@th}
+
+\def\choose{\atopwithdelims()}
+\def\brack{\atopwithdelims[]}
+\def\brace{\atopwithdelims\{\}}
+
+\def\mathpalette#1#2{\mathchoice{#1\displaystyle{#2}}%
+ {#1\textstyle{#2}}{#1\scriptstyle{#2}}{#1\scriptscriptstyle{#2}}}
+\newif\ifv@ \newif\ifh@
+\def\vphantom{\v@true\h@false\ph@nt}
+\def\hphantom{\v@false\h@true\ph@nt}
+\def\phantom{\v@true\h@true\ph@nt}
+\def\ph@nt{\ifmmode\def\next{\mathpalette\mathph@nt}%
+ \else\let\next\makeph@nt\fi\next}
+\def\makeph@nt#1{\setbox\z@\hbox{#1}\finph@nt}
+\def\mathph@nt#1#2{\setbox\z@\hbox{$\m@th#1{#2}$}\finph@nt}
+\def\finph@nt{\setbox\tw@\null
+ \ifv@ \ht\tw@\ht\z@ \dp\tw@\dp\z@\fi
+ \ifh@ \wd\tw@\wd\z@\fi \box\tw@}
+\def\mathstrut{\vphantom(}
+\def\smash{\relax % \relax, in case this comes first in \halign
+ \ifmmode\def\next{\mathpalette\mathsm@sh}\else\let\next\makesm@sh
+ \fi\next}
+\def\makesm@sh#1{\setbox\z@\hbox{#1}\finsm@sh}
+\def\mathsm@sh#1#2{\setbox\z@\hbox{$\m@th#1{#2}$}\finsm@sh}
+\def\finsm@sh{\ht\z@\z@ \dp\z@\z@ \box\z@}
+
+\def\cong{\mathrel{\mathpalette\@vereq\sim}} % congruence sign
+\def\@vereq#1#2{\lower.5\p@\vbox{\lineskiplimit\maxdimen\lineskip-.5\p@
+ \ialign{$\m@th#1\hfil##\hfil$\crcr#2\crcr=\crcr}}}
+\def\notin{\mathrel{\mathpalette\c@ncel\in}}
+\def\c@ncel#1#2{\m@th\ooalign{$\hfil#1\mkern1mu/\hfil$\crcr$#1#2$}}
+\def\rightleftharpoons{\mathrel{\mathpalette\rlh@{}}}
+\def\rlh@#1{\vcenter{\m@th\hbox{\ooalign{\raise2pt
+ \hbox{$#1\rightharpoonup$}\crcr
+ $#1\leftharpoondown$}}}}
+\def\buildrel#1\over#2{\mathrel{\mathop{\kern\z@#2}\limits^{#1}}}
+\def\doteq{\buildrel\textstyle.\over=}
+
+\def\cases#1{\left\{\,\vcenter{\normalbaselines\m@th
+ \ialign{$##\hfil$&\quad##\hfil\crcr#1\crcr}}\right.}
+\def\matrix#1{\null\,\vcenter{\normalbaselines\m@th
+ \ialign{\hfil$##$\hfil&&\quad\hfil$##$\hfil\crcr
+ \mathstrut\crcr\noalign{\kern-\baselineskip}
+ #1\crcr\mathstrut\crcr\noalign{\kern-\baselineskip}}}\,}
+\def\pmatrix#1{\left(\matrix{#1}\right)}
+\newdimen\p@renwd
+\setbox0=\hbox{\kern8.75002pt} \p@renwd=\wd0 % width of the big left (
+\def\bordermatrix#1{\begingroup \m@th
+ \setbox\z@\vbox{\def\cr{\crcr\noalign{\kern2\p@\global\let\cr\endline}}%
+ \ialign{$##$\hfil\kern2\p@\kern\p@renwd&\thinspace\hfil$##$\hfil
+ &&\quad\hfil$##$\hfil\crcr
+ \omit\strut\hfil\crcr\noalign{\kern-\baselineskip}%
+ #1\crcr\omit\strut\cr}}%
+ \setbox\tw@\vbox{\unvcopy\z@\global\setbox\@ne\lastbox}%
+ \setbox\tw@\hbox{\unhbox\@ne\unskip\global\setbox\@ne\lastbox}%
+ \setbox\tw@\hbox{$\kern\wd\@ne\kern-\p@renwd\left(\kern-\wd\@ne
+ \global\setbox\@ne\vbox{\box\@ne\kern2\p@}%
+ \vcenter{\kern-\ht\@ne\unvbox\z@\kern-\baselineskip}\,\right)$}%
+ \null\;\vbox{\kern\ht\@ne\box\tw@}\endgroup}
+
+\def\openup{\afterassignment\@penup\dimen@=}
+\def\@penup{\advance\lineskip\dimen@
+ \advance\baselineskip\dimen@
+ \advance\lineskiplimit\dimen@}
+\def\eqalign#1{\null\,\vcenter{\openup\jot\m@th
+ \ialign{\strut\hfil$\displaystyle{##}$&$\displaystyle{{}##}$\hfil
+ \crcr#1\crcr}}\,}
+\newif\ifdt@p
+\def\displ@y{\global\dt@ptrue\openup\jot\m@th
+ \everycr{\noalign{\ifdt@p \global\dt@pfalse \ifdim\prevdepth>-1000\p@
+ \vskip-\lineskiplimit \vskip\normallineskiplimit \fi
+ \else \penalty\interdisplaylinepenalty \fi}}}
+\def\@lign{\tabskip\z@skip\everycr{}} % restore inside \displ@y
+\def\displaylines#1{\displ@y \tabskip\z@skip
+ \halign{\hbox to\displaywidth{$\@lign\hfil\displaystyle##\hfil$}\crcr
+ #1\crcr}}
+\def\eqalignno#1{\displ@y \tabskip\centering
+ \halign to\displaywidth{\hfil$\@lign\displaystyle{##}$\tabskip\z@skip
+ &$\@lign\displaystyle{{}##}$\hfil\tabskip\centering
+ &\llap{$\@lign##$}\tabskip\z@skip\crcr
+ #1\crcr}}
+\def\leqalignno#1{\displ@y \tabskip\centering
+ \halign to\displaywidth{\hfil$\@lign\displaystyle{##}$\tabskip\z@skip
+ &$\@lign\displaystyle{{}##}$\hfil\tabskip\centering
+ &\kern-\displaywidth\rlap{$\@lign##$}\tabskip\displaywidth\crcr
+ #1\crcr}}
+
+% Definitions related to output
+
+\message{output routines,}
+
+\countdef\pageno=0 \pageno=1 % first page is number 1
+\newtoks\headline \headline={\hfil} % headline is normally blank
+\newtoks\footline \footline={\hss\tenrm\folio\hss}
+ % footline is normally a centered page number in font \tenrm
+\newif\ifr@ggedbottom
+\def\raggedbottom{\topskip 10\p@ plus60\p@ \r@ggedbottomtrue}
+\def\normalbottom{\topskip 10\p@ \r@ggedbottomfalse} % undoes \raggedbottom
+\def\folio{\ifnum\pageno<\z@ \romannumeral-\pageno \else\number\pageno \fi}
+\def\nopagenumbers{\footline{\hfil}} % blank out the footline
+\def\advancepageno{\ifnum\pageno<\z@ \global\advance\pageno\m@ne
+ \else\global\advance\pageno\@ne \fi} % increase |pageno|
+
+\newinsert\footins
+\def\footnote#1{\let\@sf\empty % parameter #2 (the text) is read later
+ \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi
+ #1\@sf\vfootnote{#1}}
+\def\vfootnote#1{\insert\footins\bgroup
+ \interlinepenalty\interfootnotelinepenalty
+ \splittopskip\ht\strutbox % top baseline for broken footnotes
+ \splitmaxdepth\dp\strutbox \floatingpenalty\@MM
+ \leftskip\z@skip \rightskip\z@skip \spaceskip\z@skip \xspaceskip\z@skip
+ \textindent{#1}\footstrut\futurelet\next\fo@t}
+\def\fo@t{\ifcat\bgroup\noexpand\next \let\next\f@@t
+ \else\let\next\f@t\fi \next}
+\def\f@@t{\bgroup\aftergroup\@foot\let\next}
+\def\f@t#1{#1\@foot}
+\def\@foot{\strut\egroup}
+\def\footstrut{\vbox to\splittopskip{}}
+\skip\footins=\bigskipamount % space added when footnote is present
+\count\footins=1000 % footnote magnification factor (1 to 1)
+\dimen\footins=8in % maximum footnotes per page
+
+\newinsert\topins
+\newif\ifp@ge \newif\if@mid
+\def\topinsert{\@midfalse\p@gefalse\@ins}
+\def\midinsert{\@midtrue\@ins}
+\def\pageinsert{\@midfalse\p@getrue\@ins}
+\skip\topins=\z@skip % no space added when a topinsert is present
+\count\topins=1000 % magnification factor (1 to 1)
+\dimen\topins=\maxdimen % no limit per page
+\def\@ins{\par\begingroup\setbox\z@\vbox\bgroup} % start a \vbox
+\def\endinsert{\egroup % finish the \vbox
+ \if@mid \dimen@\ht\z@ \advance\dimen@\dp\z@ \advance\dimen@12\p@
+ \advance\dimen@\pagetotal \advance\dimen@-\pageshrink
+ \ifdim\dimen@>\pagegoal\@midfalse\p@gefalse\fi\fi
+ \if@mid \bigskip\box\z@\bigbreak
+ \else\insert\topins{\penalty100 % floating insertion
+ \splittopskip\z@skip
+ \splitmaxdepth\maxdimen \floatingpenalty\z@
+ \ifp@ge \dimen@\dp\z@
+ \vbox to\vsize{\unvbox\z@\kern-\dimen@}% depth is zero
+ \else \box\z@\nobreak\bigskip\fi}\fi\endgroup}
+
+\output{\plainoutput}
+\def\plainoutput{\shipout\vbox{\makeheadline\pagebody\makefootline}%
+ \advancepageno
+ \ifnum\outputpenalty>-\@MM \else\dosupereject\fi}
+\def\pagebody{\vbox to\vsize{\boxmaxdepth\maxdepth \pagecontents}}
+\def\makeheadline{\vbox to\z@{\vskip-22.5\p@
+ \line{\vbox to8.5\p@{}\the\headline}\vss}\nointerlineskip}
+\def\makefootline{\baselineskip24\p@\lineskiplimit\z@\line{\the\footline}}
+\def\dosupereject{\ifnum\insertpenalties>\z@ % something is being held over
+ \line{}\kern-\topskip\nobreak\vfill\supereject\fi}
+
+\def\pagecontents{\ifvoid\topins\else\unvbox\topins\fi
+ \dimen@=\dp\@cclv \unvbox\@cclv % open up \box255
+ \ifvoid\footins\else % footnote info is present
+ \vskip\skip\footins
+ \footnoterule
+ \unvbox\footins\fi
+ \ifr@ggedbottom \kern-\dimen@ \vfil \fi}
+\def\footnoterule{\kern-3\p@
+ \hrule width 2truein \kern 2.6\p@} % the \hrule is .4pt high
+
+% Hyphenation, miscellaneous macros, and initial values for standard layout
+\message{hyphenation}
+
+\lefthyphenmin=2 \righthyphenmin=3 % disallow x- or -xx breaks
+
+\def\magnification{\afterassignment\m@g\count@}
+\def\m@g{\mag\count@
+ \hsize6.5truein\vsize8.9truein\dimen\footins8truein}
+
+\def\loggingall{\tracingcommands\tw@\tracingstats\tw@
+ \tracingpages\@ne\tracingoutput\@ne\tracinglostchars\@ne
+ \tracingmacros\tw@\tracingparagraphs\@ne\tracingrestores\@ne
+ \showboxbreadth\maxdimen\showboxdepth\maxdimen}
+\def\tracingall{\tracingonline\@ne\loggingall}
+
+\def\showhyphens#1{\setbox0\vbox{\parfillskip\z@skip\hsize\maxdimen\tenrm
+ \pretolerance\m@ne\tolerance\m@ne\hbadness0\showboxdepth0\ #1}}
+
+\normalbaselines
+\catcode`@=12 % at signs are no longer letters
+
diff --git a/macros/luatex/generic/minim/minim.doc b/macros/luatex/generic/minim/minim.doc
new file mode 100644
index 0000000000..d16250a0fe
--- /dev/null
+++ b/macros/luatex/generic/minim/minim.doc
@@ -0,0 +1,81 @@
+
+\input minim-doc.sty
+
+\startmetadata
+ author {Esger Renkema}
+ title {minim}
+ date {2021-06-01}
+ version {2021/1.0}
+ keywords {LuaTeX; Plain TeX; MetaPost; PDF/A; Tagged PDF; accessibility; a11y;
+ Unicode mathematics; XMP; metadata; hypertext; bookmarks}
+stopmetadata
+
+\maketitle
+
+This is a modern plain format for the LuaTeX engine, adding improved low-level
+support for many LuaTeX extensions and newer PDF features. While it can be
+used as drop-in replacement for plain TeX, it probably is most useful as
+a basis for your own formats.
+
+Most features included in the format are provided by separate packages that can
+be used on their own; see the packages
+
+\smallskip\marktableaslist \halign {\strut
+ \vrule height10ptdepth2ptwidth0pt\qquad
+ \red{#}\quad\hfil&#\hfil\cr
+minim-mp&for mplib (MetaPost) support\cr
+minim-math&for Unicode mathematics\cr
+minim-pdf&for hypertext and Tagged PDF\cr
+minim-xmp&for XMP (metadata) inclusion\cr}
+
+The documentation for the above packages will be replicated in separate
+chapters below.
+
+You can use this package by simply saying ⟦\input minim⟧; this will load the
+file \red{minim.tex}.
+For building your own format files, you can re-use the file \red{minim.ini}:
+if you define ⟦\fmtname⟧ before inputting this file, no ⟦\dump⟧ will be
+performed.
+
+
+\bigskip
+
+\tocfalse \section Contents \par \bigskip
+\begingroup \parskip1pt
+\protected\def\chapter#1#2#3{%
+ \stopelement{TOC}\smallskip
+ \nextpartag{}\red{\tenbf\marktocentry{#2}{}{\strut#1}{\hfill~}{#3}}%
+ \smallskip\startelement{TOC}}
+\protected\def\section#1#2#3{%
+ \marktocentry{#2}{}{\strut\quad#1}{\dotfill~}{#3}\par}
+\startelement{TOC} \startelement{TOC}
+\the\toc
+\stopelement{TOC} \stopelement{TOC}
+\endgroup
+
+\section Compatibility
+
+One central design goal of minim is to be as unobtrusive as possible: you
+should be able to safely ignore any function you do not want to use.
+Please get in touch if you find this not the case.
+
+Particular care has been taken to be compatible with \red{ltluatex}. All
+overlapping functions should produce the same results and ltluatex can be
+loaded either before or after minim.
+
+One point of incompatibility exists between \red{tikz/pgf} and the pattern
+functionality of minim-mp, due to conflicting implementations of pdf resource
+management.
+If you do not use filling patterns, however, the two packages can be used
+together.
+
+\licencesection
+
+\input minim-mp.doc
+\input minim-math.doc
+\input minim-pdf.doc
+\input minim-xmp.doc
+\input minim-alloc.doc
+
+\bye
+
diff --git a/macros/luatex/generic/minim/minim.ini b/macros/luatex/generic/minim/minim.ini
new file mode 100644
index 0000000000..26aed3a2c5
--- /dev/null
+++ b/macros/luatex/generic/minim/minim.ini
@@ -0,0 +1,25 @@
+
+% following luatex.ini
+\input luatexconfig
+\input luatexiniconfig
+\input load-unicode-data
+
+\input minim-plain
+
+\unless\ifdefined\fmtversion
+ \def\fmtversion{2021/1.0}\fi
+\suppressoutererror = 1
+
+\input minim-etex
+
+% and the actual minim
+\input minim
+
+% prepare default fonts
+\input minim-lmodern
+
+\unless\ifdefined\fmtname
+ \def\fmtname{minim}
+ \expandafter\dump\fi
+
+
diff --git a/macros/luatex/generic/minim/minim.pdf b/macros/luatex/generic/minim/minim.pdf
new file mode 100644
index 0000000000..715525bcf9
--- /dev/null
+++ b/macros/luatex/generic/minim/minim.pdf
Binary files differ
diff --git a/macros/luatex/generic/minim/minim.tex b/macros/luatex/generic/minim/minim.tex
new file mode 100644
index 0000000000..6003e52a85
--- /dev/null
+++ b/macros/luatex/generic/minim/minim.tex
@@ -0,0 +1,8 @@
+
+\input minim-alloc
+\input minim-mp
+\input minim-math
+\input minim-pdf
+\input minim-xmp
+
+