/ docs / manual.typ
manual.typ
  1  #import "@preview/fontawesome:0.4.0": *
  2  #import "@preview/mantys:0.1.4": *
  3  #import "@preview/metalogo:1.0.2": LaTeX
  4  #import "@preview/suiji:0.3.0"
  5  #import "@preview/wrap-it:0.1.0": *
  6  
  7  #import "@preview/babel:0.1.1": *
  8  #import "../assets/logo.typ": logo
  9  #import "../src/alphabets.typ": alphabets, maze
 10  
 11  #let redcell = table.cell.with(fill: rgb("#FFCCCC"))
 12  #let grncell = table.cell.with(fill: rgb("#CCDDAA"))
 13  #let ylwcell = table.cell.with(fill: rgb("#EEEEBB"))
 14  
 15  // By default Mantys sets the font on the title page; this is a way around that.
 16  #let gentium-titlepage(..args) = {
 17    set text(font: ("Gentium Plus", "Noto Emoji"))
 18    show raw: set text(font: "Iosevka") // https://typeof.net/Iosevka/
 19    titlepage(..args, toc: false)
 20  }
 21  #show: mantys.with(
 22    titlepage: gentium-titlepage,
 23    title: "Babel",
 24    ..toml("../typst.toml"),
 25    abstract: [
 26      #align(center, text(size: 32pt, logo()))
 27  
 28      This package provides functions that replace actual text with random characters, which is useful for redacting confidential information or sharing the design and structure of an existing document without disclosing the content itself.
 29      A variety of ready-made sets of characters for replacement are available (#alphabets.len() in total), representing diverse writing systems, codes, notations and symbols.
 30      Some of these are more conservative (such as emulating redaction using a wide black pen) and many are more whimsical, as demonstrated by the following example:
 31  
 32      #example[```
 33        #import "@preview/babel:0.1.1": *
 34  
 35        #baffle(alphabet: "welsh")[Hello]. My #tippex[name] is #baffle(alphabet: "underscore")[Inigo Montoya]. You #baffle(alphabet: "alchemy")[killed] my #baffle(alphabet: "shavian")[father]. Prepare to #redact[die].
 36  
 37        Using show rules strings, regular expressions and other selectors can be redacted automatically:
 38  
 39        #show "jan Maja": baffle.with(alphabet: "sitelen-pona")
 40        #show regex("[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*"): baffle.with(alphabet: "maze-3") 
 41  
 42        I’m jan Maja, and my email is `foo@digitalwords.net`.
 43      ```]
 44    ],
 45    examples-scope: (
 46      baffle: baffle,
 47      redact: redact,
 48      tippex: tippex,
 49      redcell: redcell,
 50      grncell: grncell,
 51      ylwcell: ylwcell,
 52      alert: mty.alert,
 53    ),
 54  )
 55  
 56  
 57  #set text(font: (("Gentium Plus", "Noto Emoji")))
 58  #show regex("[⟨⟩]"): it => {text(font: "Gentium Basic", it)} // for some reason the Gentium Plus glyphs look horrible 𓂜
 59  #show raw: set text(font: "Iosevka") // https://typeof.net/Iosevka/
 60  #set raw(theme: "tokyonight_day.tmTheme") // https://github.com/folke/tokyonight.nvim/blob/main/extras/sublime/tokyonight_day.tmTheme
 61  #show link: it => [#it#text(fill: rgb("#993333"))[°]]
 62  #show figure.where(kind: table): set figure.caption(position: top)
 63  #set heading(supplement: "§")
 64  #set table(stroke: none)
 65  
 66  #let hbo = text.with(font: "SBL Hebrew", lang: "he")
 67  
 68  = Introduction
 69  
 70  == Purpose and usage scenarios
 71  
 72  At times one wishes to make portions of text (or the whole text) hidden from the recipient:
 73  
 74  - The most common case is when redacting confidential information.
 75    Traditionally this is done by overwriting portions of text with a wide black pen and photocopying the result.
 76  - Another usage scenario is sharing the design and structure of a document, but not the text itself.
 77    While _lorem ipsum_#footnote[
 78      Typst provides a built-in function for this, #link("https://typst.app/docs/reference/text/lorem/")[`lorem()`], which outputs pseudo-Latin.
 79      For a Japanese blind text generator, see #link("https://typst.app/universe/package/roremu")[#package[roremu]].
 80    ] blocks help when demonstrating the design of a template~— replacing places where actual text would go with placeholder text~— when sharing the way a particular existing document looks they are less helpful, since in order to use them one would have to make a copy of the document and manually substitute text with placeholder text of more or less the same length, which is tiresome and prone to errors.
 81  
 82  In addition, playing with various contemporary, historical and constructed writing systems is a special kind of geeky fun…
 83  While the package does have serious, practical use, most of the provided alphabets (@alphabets) are there just for fun.
 84  
 85  One thing I ask you to avoid is using #package[Babel] for mocking cultures, as often done with mimicry typefaces such as #link("https://en.wikipedia.org/wiki/Faux_Cyrillic")[Faux Cyrillic], #link("https://en.wikipedia.org/wiki/Faux_Hebrew")[Faux Hebrew] or #link("https://en.wikipedia.org/wiki/Wonton_font")[Wonton font], which have more than subtle racist undertone. This package is a celebration of the variety and diversity of writing#footnote[
 86    Just look at @alphabets! Human beings~— as well as Klingons and Elves…~— came up with so many different graphic symbols to represent sounds and ideas it’s mind-boggling.
 87  ].
 88  
 89  If you wish to share the Typst source files of your document, not just the precompiled output, a tool called #link("https://github.com/frozolotl/typst-mutilate")[_Typst Mutilate_] might be useful for you.
 90  Unlike #package[Babel], it is not a Typst package but an external tool, written in Rust.
 91  It replaces the content of a Typst document with random words selected from a wordlist or random characters (similarly to Babel), changing the document in place (so make sure to run it on a _copy_!).
 92  As a package for Typst, #package[Babel] cannot change your source files.
 93  
 94  == Name
 95  
 96  Have a seat, it’s story time.
 97  #package[Babel] is named so as a wordplay on two things: the Biblical myth of the Tower of Babel and the #link("https://ctan.org/pkg/babel")[#LaTeX package] sharing the same name.
 98  For anyone who isn’t familiar with the story, here is the full fragment (Genesis 11.1–9):
 99  
100  #let verse(number) = [#super(number) ]
101  #let hl = highlight.with(fill: eastern.transparentize(85%), radius: 1pt)
102  #[
103    #set text(size: 10pt)
104    #table(
105      columns: (65%, 35%),
106      gutter: 0.75em,
107      [
108        #show "YHWH": smallcaps[Yhwh]
109        #verse("1")Now all the earth was of one language and one set-of-words.
110        #verse("2")And it was when they migrated to the east that they found a valley in the land of Shin’ar and settled there.
111        #verse("3")They said, each one to his neighbor: Come-now! Let us bake bricks and let us burn them well-burnt! —;For them brick-stone was like building-stone, and raw-bitumen was for them like red-mortar.
112        #verse("4")And they said: Come-now! Let us build ourselves a city and a tower, its top in the heavens, and let us make ourselves a name, lest we be scattered over the face of all the earth!
113        #verse("5")But YHWH came down to look over the city and the tower that the humans were building.
114        #verse("6")YHWH said: Here, [they are] one people with one language for them all, and this is [merely] the first of their doings— now there will be no barrier for them in all that they scheme to do!
115        #verse("7")#hl[Come-now! Let us go down and there let us baffle their language, so that no one will understand the language of his neighbor.]
116        #verse("8")So YHWH scattered them from there over the face of all the earth, and they had to stop building the city.
117        #verse("9")#hl[Therefore its name was called Bavel/Babble, for there YHWH baffled the language of all the earth-folk, and from there, YHWH scattered them over the face of all the earth.]
118      ],
119      hbo[
120        #verse("1")וַיְהִ֥י כׇל־הָאָ֖רֶץ שָׂפָ֣ה אֶחָ֑ת וּדְבָרִ֖ים אֲחָדִֽים׃
121        #verse("2")וַיְהִ֖י בְּנׇסְעָ֣ם מִקֶּ֑דֶם וַֽיִּמְצְא֥וּ בִקְעָ֛ה בְּאֶ֥רֶץ שִׁנְעָ֖ר וַיֵּ֥שְׁבוּ שָֽׁם׃
122        #verse("3")וַיֹּאמְר֞וּ אִ֣ישׁ אֶל־רֵעֵ֗הוּ הָ֚בָה נִלְבְּנָ֣ה לְבֵנִ֔ים וְנִשְׂרְפָ֖ה לִשְׂרֵפָ֑ה וַתְּהִ֨י לָהֶ֤ם הַלְּבֵנָה֙ לְאָ֔בֶן וְהַ֣חֵמָ֔ר הָיָ֥ה לָהֶ֖ם לַחֹֽמֶר׃
123        #verse("4")וַיֹּאמְר֞וּ הָ֣בָה ׀ נִבְנֶה־לָּ֣נוּ עִ֗יר וּמִגְדָּל֙ וְרֹאשׁ֣וֹ בַשָּׁמַ֔יִם וְנַֽעֲשֶׂה־לָּ֖נוּ שֵׁ֑ם פֶּן־נָפ֖וּץ עַל־פְּנֵ֥י כׇל־הָאָֽרֶץ׃
124        #verse("5")וַיֵּ֣רֶד יְהֹוָ֔ה לִרְאֹ֥ת אֶת־הָעִ֖יר וְאֶת־הַמִּגְדָּ֑ל אֲשֶׁ֥ר בָּנ֖וּ בְּנֵ֥י הָאָדָֽם׃
125        #verse("6")וַיֹּ֣אמֶר יְהֹוָ֗ה הֵ֣ן עַ֤ם אֶחָד֙ וְשָׂפָ֤ה אַחַת֙ לְכֻלָּ֔ם וְזֶ֖ה הַחִלָּ֣ם לַעֲשׂ֑וֹת וְעַתָּה֙ לֹֽא־יִבָּצֵ֣ר מֵהֶ֔ם כֹּ֛ל אֲשֶׁ֥ר יָזְמ֖וּ לַֽעֲשֽׂוֹת׃
126        #verse("7")#hl[הָ֚בָה נֵֽרְדָ֔ה וְנָבְלָ֥ה שָׁ֖ם שְׂפָתָ֑ם אֲשֶׁר֙ לֹ֣א יִשְׁמְע֔וּ אִ֖ישׁ שְׂפַ֥ת רֵעֵֽהוּ׃]
127        #verse("8")וַיָּ֨פֶץ יְהֹוָ֥ה אֹתָ֛ם מִשָּׁ֖ם עַל־פְּנֵ֣י כׇל־הָאָ֑רֶץ וַֽיַּחְדְּל֖וּ לִבְנֹ֥ת הָעִֽיר׃
128        #verse("9")#hl[עַל־כֵּ֞ן קָרָ֤א שְׁמָהּ֙ בָּבֶ֔ל כִּי־שָׁ֛ם בָּלַ֥ל יְהֹוָ֖ה שְׂפַ֣ת כׇּל־הָאָ֑רֶץ וּמִשָּׁם֙ הֱפִיצָ֣ם יְהֹוָ֔ה עַל־פְּנֵ֖י כׇּל־הָאָֽרֶץ׃]
129      ]
130    )
131  ]
132  
133  The myth explains why people are scattered everywhere and why they speak different languages, and it also provides folk etymology for the name of the city of Babylon (#hbo[בָּבֶל] _Bāḇel_): #hbo[בָּלַ֥ל] _bālal_ ‘he mixed, he confounded’ in verse~9 and #hbo[וְנָבְלָ֥ה] _wə-nāḇlâ_ ‘and let us mix, and let us confound’ in verse~7 (both from the root #hbo[ב־ל־ל] _√BLL_ ‘to mix, to confound, to confuse’) sounds a bit like #hbo[בָּבֶל] _Bāḇel_ ‘Babel’.#footnote[
134    Interestingly, the Babylonian Akkadian name which is the basis for the Hebrew name is 𒆍𒀭𒊏𒆠 _Bābilim_ ‘(lit.) the gate of the gods’.
135    Even more interestingly, there is evidence this Akkadian interpretation of the name (as ‘the gate of the gods’) itself was a Semitic folk etymology on a non-Semitic name!
136    This is all very… confusing, how people mix up things.
137  ]
138  Everett Fox translated these verbs brilliantly in the #link("https://www.sefaria.org.il/Genesis.11?ven=The_Five_Books_of_Moses,_by_Everett_Fox._New_York,_Schocken_Books,_1995&lang=bi")[_Schocken Bible_], with the English verb _baffle_, where all other translation I looked at have _confound_ or _confuse_.
139  This is the reason for choosing that translation for the above excerpt and the name #cmd("baffle") for the main function provided by #package[Babel].
140  
141  Now, idea of the Tower of Babel as the explanatory myth behind linguistic diversity still persists in contemporary culture, as demonstrated by the Babel fish in Douglas Adams’s _the Hitchhiker's Guide to the Galaxy_, the dictionary and machine-translation software _Babylon_ and the #LaTeX package #link("https://ctan.org/pkg/babel")[_Babel_].
142  Fittingly, the Babel #LaTeX package enhances the capabilities of localisation and internationalisation.
143  With our Typst #package[Babel] I chose to take the other connotation, of confusion, bafflement and mixing 🙃
144  
145  == Logo
146  
147  #wrap-content(
148    column-gutter: 0.5em,
149    text(size: 16pt, logo()),
150    [
151      The logo features a minimalist icon of the Tower of Babel or a ziggurat; see @licence for attribution.
152      The background colour is the same shade of turquoise used by #package[Mantys].
153    ]
154  )
155  
156  == Copyright and licence <licence>
157  
158  The this package is released under #link("https://spdx.org/licenses/MIT-0.html")[MIT-0].
159  
160  #package[Babel]’s logo features an #link("https://thenounproject.com/icon/babel-2526388/")[image] by #link("https://andrejskirma.com/")[Andrejs Kirma] which is released under CC~BY-3.0.
161      I attribute them willingly, as I find the graphics very fitting for the logo.
162      Go check #link("https://thenounproject.com/creator/andrejs/")[their other icons].
163  
164  == Versioning and stability <ver>
165  
166  #package[Babel] follows the Semantic Versioning scheme (#link("https://semver.org/spec/v2.0.0.html")[SemVer 2.0.0]).
167  While it is fully usable in its current form (version `0.*.*`), changes to the API might occur in future versions.
168  This should not pose a problem:
169  
170  - When you import a package in Typst you can indicate the version (for example, `#import "@preview/example:0.1.0"`), so no surprises should occur.
171  - Changes to the API will be clearly indicated in the documentation.#footnote[
172      If the characters replaced by the package change between versions, this is not counted as a change: the whole point is the actual identity of the random characters is, well, random.
173      Changes to the alphabets (@alphabets) are also considered minor.
174    ]
175  
176  == Participation and contact <contact>
177  
178  If there is anything that doesn’t work well or any feature you want added or changed, don’t hesitate to #link("https://codeberg.org/afiaith/babel/issues")[open an issue] on the Git repository, and I will do my best to make the package more useful for you and others.
179  If you want to contribute code/documentation (changes, additions, corrections, improvements, etc. no matter how small or large), #link("https://codeberg.org/afiaith/babel/pulls")[pull requests] are very welcome; thanks!
180  
181  In particular, contributions of alphabets (`src/alphabets.yaml`) are welcome.
182  This version contains #alphabets.len()~(!) alphabets, but like Pokémon, you gotta catch ’em all… When choosing a font for the script of your alphabet:
183    - If only basic Latin characters are used, don’t set a font.
184    - If the new alphabet uses a script already represented on #package[Babel], prefer the font already in use (for example, Gentium Plus for Latin, Greek and Cyrillic, SBL Hebrew for Hebrew,~…).
185    - Prefer free, gratis and libre open-source fonts (FLOSS).
186    - Prefer serif#footnote[
187        Admittedly, for many scripts Noto Sans is the only good FLOSS option.
188      ] fonts (wherever serif makes sense) that go well with Gentium Plus.
189  
190  Not everyone is familiar with Git, so if that is a problem feel free to contact me in any other way; see #link("https://me.digitalwords.net/")[`https://me.digitalwords.net/`] for contact information.
191  
192  == Disclaimer
193  
194  I hold no responsibility for anything that may occur as a result of using this package, nor can I guarantee there are no edge cases where text that should have been redacted stays readable (please do report such cases; see @contact).
195  If you use this package with actual confidential information, please read the manual (especially @limitations), check the results and understand the risks.
196  
197  = Usage
198  
199  == Provided functions <functions>
200  
201  #import "../src/baffle.typ": punctuation
202  #tidy-module(
203    read("../src/baffle.typ"),
204    include-examples-scope: true,
205    name: "fonts",
206    show-outline: false,
207    scope: (
208      punctuation: punctuation
209    )
210  )
211  
212  If you frequently use #cmd("baffle") with certain parameters, defining an alias of your own makes things simpler, easier, and more elegant; for example:
213  
214  #example(```
215  #let tp = baffle.with(alphabet: "sitelen-pona", punctuate: false, output-word-divider: "\u{200b}")
216  Hi! #tp[this!] and #tp[that…] are confidential.
217  ```)
218  
219  === Using show rules <show-rules>
220  
221  While surrounding segments of commands is useful for short amounts of text, applying commands to long segments~— or even the whole document~— is cumbersome.
222  Fortunately, Typst provides us with a clever solution for that: show rules.
223  Consider the following example:
224  
225  #example[```
226  This text is shown as plaintext.
227  
228  #show: baffle.with(alphabet: "astrology")
229  
230  Now from here on the text is baffled!
231  ```]
232  
233  Show rules can be used for redacting strings, regular expressions and other selectors automatically (see the #link("https://typst.app/docs/reference/styling/#show-rules")[documentation]):
234  
235  #example[```
236  #show "Ramona Flowers": baffle.with(alphabet: "redaction")
237  #show regex("[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*"): baffle.with(alphabet: "maze-3") 
238  
239  Her name is Ramona Flowers, and her email is `ramona@flowers.name`.
240  ```]
241  
242  At the moment (version 0.11.0) there is no way to revoke show rules#footnote[
243    It is planned, though.
244    See the #link("https://typst.app/docs/roadmap/")[roadmap] and #link("https://github.com/typst/typst/issues/420")[this issue].
245  ].
246  As a workaround, bracketing the relevant segments can limit the scope of a show rule:
247  
248  #example[```
249  This is plaintext.
250  
251  #[
252    #show: baffle
253  
254    A baffled part of the document.
255  ]
256  
257  Plaintext again. 
258  ```]
259  
260  
261  
262  === Limitations and considerations <limitations>
263  
264  ==== General matters
265  
266  ===== Educated guesses
267  
268  From an information-theoretical point of view, the #cmd("baffle") loses a lot of information: it may retain only the length of each word, capitalisation, and punctuation, and each of the three can be turned off.
269  Unlike encryption, where by definition the plaintext can be deciphered using the proper technique and secret information, here the original text cannot be recovered algorithmically.
270  Given certain conditions, educated guesses can be made though: for example (and an extreme one at that…), if you see a baffled word that is 27 letters long, you can assume with confidence that it is _electroencephalographically_ if the text deals with neurology or _ethylenediaminetetraacetate_ if it deals with chemistry.
271  In more realistic scenarios contextual information and the nature of the text (rigid forms are more predictable than literary prose, for example) can assist in making educated guesses.
272  
273  For maximal obfuscation, turn word division, capitalisation and punctuation off, but realistically I don’t think this is needed, and the result might be less aesthetically pleasing, depending on the alphabet used.
274  
275  Note that #cmd("baffle") retain information about the length of words in characters#footnote[
276    Some alphabets may increase the number of characters, as they include multi-character ‘letters’ (e.g. digraphs).
277  ], not in horizontal length.
278  This covers some attack vectors involving proportional fonts and kerning, but opens others, based on counting characters.
279  
280  ===== Unintended meanings
281  
282  Letters are chosen from the alphabets randomly.
283  In theory, unintended meanings may occur, especially with relatively short words.
284  Also, note that some scripts (Egyptian hieroglyphs and Phaistos Disc, sitelen sitelen,~…) contain pictograms which might be taboo in your culture.
285  
286  ==== Particular, implementation-dependant matters <particular-limitations>
287  
288  Limitations concerning the #arg("as-string") argument are discussed in @functions, and those concerning particular alphabets are discussed in @alphabets.
289  
290  If elements which are included in the table of contents appear within #cmd("baffle"), they appear in plaintext in the PDF table of contents#footnote[
291    This is the one accessible using a sidebar or the tab key, depending on the PDF reader, not the one typeset in the document itself.
292  ] unless they are bound within a #cmd("baffle") command with #arg("as-string") set to #value(true), in which case the bound text disappears from the PDF table of contents.
293  The baffled text in a typeset table of contents (#cmd("outline")) is different to the one used in the headings.
294  
295  == Provided alphabets <alphabets>
296  
297  In total #alphabets.len() alphabets are provided by #package[Babel].
298  ‘Alphabet’ is used here in the sense used in formal language theory, not linguistics (neither in the narrow nor the wide sense).#footnote[
299    If these distinctions are not clear to you, read the following Wikipedia articles if you’d like to learn about them: #link("https://en.wikipedia.org/wiki/Alphabet")[Alphabet] (linguistics, both senses) and #link("https://en.wikipedia.org/wiki/Alphabet_(formal_languages)")[Alphabet (formal languages)].
300  ]
301  Many of the ‘alphabets’ below are not alphabets in the linguistic sense.
302  
303  #let font-icon = text(font: "Linux Libertine", size: 15pt)[_Aa_]
304  
305  === Legend
306  
307  #table(
308    columns: 2,
309    align: (x, y) => if x == 0 { center } else { left },
310    fa-icon("wikipedia-w"),
311    [a link to the relevant article in Wikipedia. If anything piques your interest, down to the rabbit hole you go.],
312    font-icon,
313    [a link to the font used in the example.],
314    [`slug`],
315    [the string you provide the #arg("alphabet") argument with (`arabic` for Arabic, `alchemy` for Alchemical symbols, …).],
316  )
317  
318  === Notes
319  - The characters from the output alphabet are chosen at random, which has several implications:
320    - Phonotactics is not taken into consideration.
321    - The output contains mostly non-words which defy the rules of how words look in the alphabet in question.
322    - Letter frequency is also not taken into consideration.
323      At most, the vowels or consonants are superficially doubled in order to account for severe disparity in the type:token ratio.
324    Because characters are chosen at random final letters have been removed from the Hebrew script and the Canadian Aboriginal syllabics, so they will not occur in incorrect positions.#footnote[
325      It’s a better compromise not to represent the final forms than to have them occur in incorrect positions.
326    ]
327  - Some of the scripts~— such as Egyptian and Anatolian hieroglyphs or the sitelen pona and sitelen sitelen scripts~— are normally written with grouping of characters in a non-linear manner. This is not done here, where the glyphs are stringed one after the other in a linear manner.
328  
329  === A menu of alphabets
330  
331  #let rng = suiji.gen-rng(0)
332  
333  #let sample = "Ni malleviĝu do, kaj Ni konfuzu tie ilian lingvon, por ke unu ne komprenu la parolon de alia. Kaj la Eternulo disigis ilin de tie sur la supraĵon de la tuta tero, kaj ili ĉesis konstrui la urbon."//Tial oni donis al ĝi la nomon Babel, ĉar tie la Eternulo konfuzis la lingvon de la tuta tero kaj de tie la Eternulo disigis ilin sur la supraĵon de la tuta tero."
334  
335  #let describe-alphabet(slug, alphabet) = [
336    #box(
337      fill: luma(245),
338      inset: 0.75em,
339      radius: 0.75em,
340    )[
341      #strong(alphabet.at("name"))
342      #if "native" in alphabet.keys() [
343        #h(1em)#[#set text(font: alphabet.at("font")) if "font" in alphabet.keys();#alphabet.at("native")]
344      ]
345      #h(1fr)
346      #text(font: "Iosevka", slug)
347      #h(1em)
348      #link("https://en.wikipedia.org/wiki/" + alphabet.at("wiki"), fa-icon("wikipedia-w"))
349      #if "fonturl" in alphabet.keys() {link(alphabet.at("fonturl"), font-icon)}
350      \
351      #[
352        #set text(lang: alphabet.at("lang")) if "lang" in alphabet.keys()
353        #box(
354          width: 100%, height: 1.5em, clip: true, baseline: -0.2em,
355          // TODO Make less hackish and ugly
356          box(width: 1000%, baseline: 1.2em)[
357            #baffle(
358              sample,
359              alphabet: slug,
360              punctuate: if "punctuate" in alphabet.keys() {alphabet.at("punctuate")} else {true},
361              output-word-divider: if "word-divider" in alphabet.keys() {alphabet.at("word-divider")} else {" "},
362              as-string: true,
363            )
364          ]
365        )
366      ]
367      #v(-0.5em)#if "note" in alphabet.keys() {
368        eval(
369          mode: "markup",
370          alphabet.at("note"),
371          scope: (
372            maze: maze,
373            arg: arg,
374            cmd: cmd,
375            baffle: baffle,
376          ))
377      }
378    ]
379    #v(0.5em)
380  ]
381  
382  #for pair in alphabets.pairs() {
383    describe-alphabet(pair.at(0), pair.at(1))
384  }