From 544836cf0f6373a0a753d0953ce7e60fd96337af Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Wed, 19 Aug 2026 08:57:42 +0200 Subject: feat(render): XML emitter and schema Element-per-field; attributes carry identity only and there is no mixed content, so a consumer's XPath never has to distinguish the two. Schema validation is an opt-in make check-schema via xmllint, not an in-suite assertion: validating XSD needs an XML library and the dependency list is frozen. It prints SKIPPED loudly when xmllint is absent, because a silent skip reads as a pass. The suite asserts well-formedness properties directly instead. This corrects the design spec, which claimed in-test validation. --- Makefile | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'Makefile') diff --git a/Makefile b/Makefile index 5b3bb55..0d4d1d5 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ MAN5DIR := $(PREFIX)/share/man/man5 # over documenting the dune commands. DUNE := opam exec -- -.PHONY: help build test check install uninstall reinstall clean fmt man doc release +.PHONY: help build test check check-schema install uninstall reinstall clean fmt man doc release help: ## show this help @grep -hE '^[a-z-]+:.*##' $(MAKEFILE_LIST) | sed -E 's/:.*## /\t/' | sort @@ -30,6 +30,15 @@ test: ## fast suite (~5s): properties sample 200 years check: ## full gate (~2min): every year 1583-9999, not a sample COLITUR_EXHAUSTIVE_SWEEP=1 $(DUNE) dune test --force +check-schema: build ## validate emitted XML against schema/colitur-v1.xsd (needs xmllint; skipped if absent) + @if command -v xmllint >/dev/null 2>&1; then \ + opam exec -- dune exec colitur -- emit --format xml --from 2027 --to 2027 > /tmp/colitur-check.xml && \ + xmllint --noout --schema schema/colitur-v1.xsd /tmp/colitur-check.xml && \ + echo "xml: valid against schema/colitur-v1.xsd"; \ + else \ + echo "SKIPPED: xmllint not installed -- XML is emitted but NOT schema-validated"; \ + fi + install: build ## install binary, calendar data and man page into PREFIX (default ~/.local) $(DUNE) dune install --prefix $(PREFIX) @mkdir -p $(MANDIR) -- cgit v1.3 From b90678e560808dd788fa7d7eb319d93a83005db4 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Wed, 19 Aug 2026 10:32:33 +0200 Subject: docs(render): template reference, install rules, typesetting check colitur-templates.5 documents the four syntax forms, the six flavours and their escaping, and the full view-model field reference. It states plainly that there are no partials, no raw form and no expression evaluation -- a template is data, never a program. It documents two real hazards found during this build, not theoretical ones: the outward scope fallback silently shadowing an inner name/num key with an outer one of the same name (with the safe {{#name}}...{{^la}} idiom), and the engine's lack of host-comment awareness (a {{...}} inside a LaTeX %, groff .\" or HTML comment is still parsed as a tag). It also states the limitation rather than hiding it: AsciiDoc and Markdown are not escaped, so a feast name containing * or _ renders as emphasis. templates/ and schema/ now install into /share/colitur/, matching data/ef/, via new install stanzas; colitur-templates.5 installs to man5 beside colitur-overlay.5. Verified against a scratch prefix: the installed binary resolves both from the prefix, not the source tree, when run from an unrelated working directory. make check-templates typesets every shipped template through pdflatex and groff when they are installed, and prints SKIPPED loudly when they are not. Golden tests prove templates render; only this proves they typeset. A silent skip would read as a pass. Fixed a real doc/help drift while here: bin/main.ml's --help still said --overlay was accepted on day and readings only, three commands out of date (emit, table/render and publish all accept it too), disagreeing with the man page's own OVERLAYS section, which carried the identical stale line. Both are corrected; --overlay's own behaviour is unchanged. --- Makefile | 43 ++- README.md | 12 + bin/main.ml | 18 +- man/colitur-templates.5 | 699 ++++++++++++++++++++++++++++++++++++++++++++++++ man/colitur.1 | 26 +- schema/dune | 16 ++ templates/dune | 22 ++ 7 files changed, 821 insertions(+), 15 deletions(-) create mode 100644 man/colitur-templates.5 create mode 100644 schema/dune create mode 100644 templates/dune (limited to 'Makefile') diff --git a/Makefile b/Makefile index 0d4d1d5..aa4bce6 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,11 @@ MAN5DIR := $(PREFIX)/share/man/man5 # (/share/colitur/ef), so `dune install` -- not a hand-rolled copy -- # is what places the four .sexp files where a running colitur will look for # them. See bin/main.ml's own [data_dir] for the full resolution order. +# Task 13 (schema/dune, templates/dune) extends the same `dune install` +# mechanism to /share/colitur/schema/ (bin/main.ml's own +# [schema_path], read by `colitur publish`) and /share/colitur/ +# templates/ (a convenience install -- `--template` takes a plain file path, +# nothing in colitur probes this location the way [data_dir]/[schema_path] do). # # dune needs the project-local opam switch on PATH. Every recipe that invokes # dune goes through this, so `make` works from a plain shell with no @@ -17,7 +22,7 @@ MAN5DIR := $(PREFIX)/share/man/man5 # over documenting the dune commands. DUNE := opam exec -- -.PHONY: help build test check check-schema install uninstall reinstall clean fmt man doc release +.PHONY: help build test check check-schema check-templates install uninstall reinstall clean fmt man doc release help: ## show this help @grep -hE '^[a-z-]+:.*##' $(MAKEFILE_LIST) | sed -E 's/:.*## /\t/' | sort @@ -39,19 +44,47 @@ check-schema: build ## validate emitted XML against schema/colitur-v1.xsd (needs echo "SKIPPED: xmllint not installed -- XML is emitted but NOT schema-validated"; \ fi -install: build ## install binary, calendar data and man page into PREFIX (default ~/.local) +# Typesets every shipped template through the real tool that would typeset it +# for a reader, not merely through this program's own renderer. The golden +# tests already prove `colitur table` PRODUCES the expected LaTeX/groff/HTML +# text; only this proves that text actually TYPESETS -- a template can render +# byte-for-byte as pinned and still be malformed LaTeX or groff. Each tool is +# genuinely optional (neither is in colitur's own frozen deps), so absence is +# printed LOUDLY as SKIPPED rather than silently treated as a pass -- a +# silent skip reads as a pass, which is the whole failure mode this guards +# against. +check-templates: build ## typeset every shipped template (needs pdflatex/groff; skipped if absent) + @ok=1; \ + if command -v pdflatex >/dev/null 2>&1; then \ + for t in ordo grid; do \ + opam exec -- dune exec colitur -- table --year 2027 --template templates/ef/$$t.tex > /tmp/$$t.tex && \ + (cd /tmp && pdflatex -halt-on-error -interaction=nonstopmode $$t.tex >/dev/null) && \ + echo "pdflatex: $$t.tex OK" || { echo "pdflatex: $$t.tex FAILED"; ok=0; }; \ + done; \ + else echo "SKIPPED: pdflatex not installed -- LaTeX templates render but are NOT typeset"; fi; \ + if command -v groff >/dev/null 2>&1; then \ + for t in ordo grid; do \ + opam exec -- dune exec colitur -- table --year 2027 --template templates/ef/$$t.ms > /tmp/$$t.ms && \ + groff -ms -t -Tpdf /tmp/$$t.ms > /tmp/$$t-ms.pdf && \ + echo "groff: $$t.ms OK" || { echo "groff: $$t.ms FAILED"; ok=0; }; \ + done; \ + else echo "SKIPPED: groff not installed -- groff templates render but are NOT typeset"; fi; \ + test $$ok -eq 1 + +install: build ## install binary, calendar data, templates, schema and man pages into PREFIX (default ~/.local) $(DUNE) dune install --prefix $(PREFIX) @mkdir -p $(MANDIR) install -m 644 man/colitur.1 $(MANDIR)/colitur.1 @mkdir -p $(MAN5DIR) install -m 644 man/colitur-overlay.5 $(MAN5DIR)/colitur-overlay.5 - @echo "installed $(BINDIR)/$(COLITUR), data in $(PREFIX)/share/colitur/ef, man pages in $(MANDIR) and $(MAN5DIR)" + install -m 644 man/colitur-templates.5 $(MAN5DIR)/colitur-templates.5 + @echo "installed $(BINDIR)/$(COLITUR), data in $(PREFIX)/share/colitur/{ef,templates,schema}, man pages in $(MANDIR) and $(MAN5DIR)" @command -v $(COLITUR) >/dev/null 2>&1 || \ echo "note: $(BINDIR) is not on PATH -- add it, or run $(BINDIR)/$(COLITUR) directly" uninstall: ## remove everything install put into PREFIX -$(DUNE) dune uninstall --prefix $(PREFIX) - rm -f $(MANDIR)/colitur.1 $(MAN5DIR)/colitur-overlay.5 + rm -f $(MANDIR)/colitur.1 $(MAN5DIR)/colitur-overlay.5 $(MAN5DIR)/colitur-templates.5 @echo "removed $(COLITUR) from $(PREFIX)" reinstall: uninstall install ## uninstall then install (the installed copy is a snapshot, not a link) @@ -59,10 +92,12 @@ reinstall: uninstall install ## uninstall then install (the installed copy is a man: ## preview the man pages man -l man/colitur.1 man -l man/colitur-overlay.5 + man -l man/colitur-templates.5 doc: ## lint the man pages (groff warnings; silence means clean) groff -man -Tutf8 -ww -z man/colitur.1 groff -man -Tutf8 -ww -z man/colitur-overlay.5 + groff -man -Tutf8 -ww -z man/colitur-templates.5 fmt: ## format the OCaml sources $(DUNE) dune build @fmt --auto-promote diff --git a/README.md b/README.md index 6f71f6c..aafde4e 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,18 @@ dune exec colitur -- temporal 2026 # the EF temporal cycle only, one line per d dune exec colitur -- day 2026 # the full resolved EF calendar (temporal + sanctoral) ``` +## Rendering + +```sh +dune exec colitur -- table --year 2027 --template templates/ef/ordo.tex > ordo.tex && pdflatex ordo.tex +dune exec colitur -- table --year 2027 --template templates/ef/grid.tex > grid.tex && pdflatex grid.tex +dune exec colitur -- publish --from 2027 --to 2027 --out ./public +``` + +See `colitur-templates(5)` for the template format (syntax, escaping, the +full field reference) and `colitur(1)` for `emit`, `table`/`render` and +`publish` in full. + ## License AGPL-3.0-or-later. See `LICENSE`. diff --git a/bin/main.ml b/bin/main.ml index 1669a47..4f1fbf2 100644 --- a/bin/main.ml +++ b/bin/main.ml @@ -763,9 +763,9 @@ overlays: the shipped universal one, never instead of it, so local feasts add to it rather than replacing it. Later files win over earlier ones, and over the universal calendar, when they name the same - slug. Accepted on `day` and `readings` only -- the other commands - read no sanctoral data, so the flag is refused there rather than - silently ignored. + slug. Accepted on `day`, `readings`, `emit`, `table`, `render` and + `publish` -- `easter` and `temporal` read no sanctoral data, so + the flag is refused there rather than silently ignored. An overlay is applied, NOT validated: colitur's test layers assert things about the shipped calendar and cannot vouch for a file you @@ -804,8 +804,11 @@ rendering: renders against is the same schema `emit` uses (season, week, slug, rank, colour, subject, names, citations, commemorations), reshaped into a booklet (`days`) and a month grid (`weeks`, with - padding cells for the leading/trailing blanks); see colitur(1) - for the full field list. + padding cells for the leading/trailing blanks); see + colitur-templates(5) for the full field list, the syntax and the + scope-shadowing hazard (an inner key silently loses to an outer + key of the same name -- a bare {{name.la}} inside a day resolves + to the enclosing MONTH's name, not the day's own). --flavour X selects how interpolated VALUES are escaped (never the template's own literal markup, which is the author's). One of: @@ -882,7 +885,10 @@ exit status: Reading references only (e.g. "Jn 3:16"); never scripture text. See colitur(1) for the full description and the sources it computes against, -and colitur-overlay(5) for the overlay file format in full.|} +colitur-overlay(5) for the overlay file format in full, and +colitur-templates(5) for the template format in full -- the syntax, the +scope-shadowing hazard, the six flavours' escaping, and the full view-model +field reference.|} let print_help () = print_endline help_text; diff --git a/man/colitur-templates.5 b/man/colitur-templates.5 new file mode 100644 index 0000000..ec883cb --- /dev/null +++ b/man/colitur-templates.5 @@ -0,0 +1,699 @@ +.TH COLITUR\-TEMPLATES 5 "2026" "colitur" "File Formats" +.SH NAME +colitur\-templates \- template format for colitur(1)'s table, render and publish +.SH SYNOPSIS +.I booklet.tex +.br +.I calendar.html +.br +.I feed.ics +.SH DESCRIPTION +A +.B colitur +template is the file named by +.BR "colitur table" 's +and +.BR "colitur render" 's +.B \-\-template +flag (and used internally by +.BR "colitur publish" ). +It is a deliberately logic\-less, Mustache\-family format: the file is +.I data, +never a program. There are exactly four constructs \(em variable +interpolation, a section, an inverted section, and a comment \(em and nothing +else. +.PP +.B There are no partials, no lambdas, no arithmetic, no expression +.B evaluation, and no "raw" or triple\-brace form that could opt out of +.B escaping. +A template cannot include another file, cannot compute anything, and cannot +choose to skip the escaping its own flavour applies. Everything a rendered +document needs \(em conditionals on emptiness, iteration over days or weeks, +formatting \(em is expressed with the four constructs below over the fields +.B VIEW MODEL +describes; nothing else is available, and nothing else will be added by +supplying cleverer template syntax \(em that is what the escaping and +scope rules exist to prevent. +.SH SYNTAX +.TP +.BI "{{" name "}}" +Interpolates the value at +.I name, +a dot\-separated path resolved against the current scope (see +.B SCOPE AND LOOKUP +below). A string value is escaped per the active flavour and inserted; a +boolean +.B true +renders as the literal text +.RB \(lq true \(rq, +.B false +renders as nothing; a list or an object value used as a plain variable also +renders as nothing \(em only a section can iterate one. A path that resolves +to nothing renders as nothing, silently: this is the one deliberate silence +in the engine, so a template survives a day that does not carry every +optional field (an empty +.I week +on a day the rite does not number, an empty +.I first +or +.I gospel +citation, and so on). +.TP +.BI "{{#" name "}}...{{/" name "}}" +A section. If +.I name +resolves to a +.B list, +the body is rendered once per item, with each item pushed onto the scope +stack (see below). If it resolves to a truthy non\-list value (a non\-empty +string, or an object), the body is rendered once, with that value pushed onto +the stack. If it resolves to nothing, or to a falsy value (an empty string, +.BR false , +or an empty list), the body is skipped entirely. +.TP +.BI "{{^" name "}}...{{/" name "}}" +An inverted section: the mirror image of +.BR # . +The body renders \(em exactly once, without pushing anything new onto the +scope \(em only when +.I name +resolves to nothing, or to a falsy value. This is how a template supplies a +fallback for an optional or absent field. +.TP +.BI "{{!" " text " "}}" +A comment. Everything between +.B {{! +and the closing +.B }} +is discarded; nothing is written to the rendered output. See +.B HOST\-LANGUAGE COMMENTS +below before relying on this for documentation inside a template that also +has its own comment syntax. +.PP +A section and its inverted counterpart, and a section and its close tag, must +name the identical path \(em +.BR {{#days}} " ... " {{/months}} +is a parse error, not a silently mismatched close. An empty path +( +.BR {{.}} ", " {{#}} ", " {{^}} ", " {{/}} +) is also a parse error: there is no "current context" concept for a bare dot +to mean, so nothing is guessed on a template's behalf. +.PP +A malformed template \(em an unterminated +.BR {{ , +a section left unclosed, a close tag with no matching open \(em is reported +with the parser's own reason and exits 2. A template is user input, exactly +like an +.BR colitur\-overlay (5) +file, and is never allowed to crash the program that reads it. +.SH SCOPE AND LOOKUP +.B This section documents a real hazard, not a theoretical one \(em it has +.B produced wrong output during this program's own development. +.PP +Scope is a stack. Rendering starts with the whole view (the year) as the one +entry on the stack; each +.B {{#section}} +pushes the value it iterates or opens onto the stack for the duration of its +body, and pops it again at +.BR {{/section}} . +A lookup for +.I name +is tried against the +.I innermost +(most recently pushed) entry first. If +.I name +is not found there, the lookup falls back to the +.I next +entry outward, and so on to the outermost (the year itself). This fallback is +deliberate and necessary \(em without it, a cell deep inside +.B {{#months}}{{#weeks}}{{#days}} +could never reach +.BR {{year}} , +which lives only on the outermost object. +.PP +.B The hazard: an inner key silently loses to an outer key of the SAME NAME. +Falling back outward means a name that exists at +.I both +levels never fails and never warns \(em it just silently resolves to the +.I outer +one, because the inner object's own absence of that key is indistinguishable +from "look further out" and "this key does not apply here". Two collisions +are known to exist in the shipped view model: +.TP +.B name +Both a +.B month +and a +.B day +carry a +.I name +field (each an object keyed by language, e.g. +.BR la " and " en ). +Written naively, inside +.BR {{#days}} , +a bare +.B {{name.la}} +does +.I not +resolve to the day's own Latin name. It resolves to the +.I enclosing month's +Latin name, because the day's own +.I name +object either has no +.B la +key (an unnamed day) or the dotted path fails partway and the WHOLE path +falls back to the outer scope, which does have one. This is not a corner +case: on an ordinary month, most days carry no Latin name at all (only named +sanctoral days do), so the naive form renders the +.I month's +name on nearly every day \(em in a flat booklet, dozens of wrong lines; in a +month grid, EVERY cell reads the month's own name. +.TP +.B num +Both a +.B month +and a +.B week +carry a +.I num +field. Inside +.BR {{#weeks}} , +a bare +.B {{num}} +is the week's own number, correctly \(em but only because nothing between +the week and the day currently redefines it. A template that reaches +.I num +from any scope where the immediately enclosing section does not itself +carry it will silently climb to whichever ancestor does, and that may not be +the one the author meant. +.PP +.B The safe idiom. +Push the object you actually want onto the scope stack yourself, with a +.B {{#name}} +section, before reading its fields \(em then a bare field inside that +section can only resolve against the object you just pushed, or fail +outright and fall through to an inverted fallback you write explicitly: +.RS +.nf + +{{#name}}{{la}}{{^la}}{{slug}}{{/la}}{{/name}} +.fi +.RE +This opens the day's own +.I name +object (never the month's \(em a +.B {{#section}} +always resolves its OWN path from the point it appears, which for +.B {{#name}} +written inside +.B {{#days}} +is the day's +.IR name , +shadowing the month's identically\-named field exactly as intended), reads +.B la +from it, and falls back to the day's own +.B slug +only when +.B la +is genuinely absent from +.I that +object \(em never when it is merely absent from an ancestor. Every shipped +template that prints a day's name uses exactly this idiom; none uses the +bare dotted form. +.SH HOST\-LANGUAGE COMMENTS +.B The engine has no awareness of the target language's own comment syntax. +A +.B {{...}} +tag inside a LaTeX +.BR % , +a groff +.BR .\e" , +or an HTML +.B +comment is still lexed and rendered exactly as if it were live template +markup \(em the engine sees only its own +.B {{ +/ +.B }} +delimiters, never the host format's comment sigils, because a template is +rendered as one flat character stream, not parsed as LaTeX, groff or HTML +first. This broke a shipped template during development: an explanatory +.B {{example}} +written inside a LaTeX +.B % +comment, meant purely as documentation for a future reader, was parsed as a +real variable reference. +.PP +Write in\-template documentation without any +.B {{ +or +.B }} +characters in it, in whatever host\-comment syntax the target format uses. +Use +.B {{!comment}} +only where the surrounding host format has no comment syntax of its own that +would otherwise be preferable (its own body is safe \(em text between +.B {{! +and +.B }} +is discarded unparsed, so a stray +.B {{ +inside a +.B {{!...}} +comment is not itself a hazard \(em but the comment's own delimiters are +still ordinary +.B {{ +/ +.B }} +tokens, so they compete with the host format's own comment syntax for the +same file exactly as any other tag would). +.SH FLAVOURS +.B \-\-flavour +selects how an interpolated +.I value +is escaped before being written. It never touches the template's own literal +markup (the LaTeX, groff, HTML, XML or ICS surrounding a +.BR {{tag}} ), +which is the template author's and is trusted exactly as written. One of six: +.TP +.B latex +.BR \e " \(-> " \etextbackslash{} , +.BR { " \(-> " \e{ , +.BR } " \(-> " \e} , +.BR $ " \(-> " \e$ , +.BR & " \(-> " \e& , +.BR # " \(-> " \e# , +.BR _ " \(-> " \e_ , +.BR % " \(-> " \e% , +.BR ^ " \(-> " \etextasciicircum{} , +.BR ~ " \(-> " \etextasciitilde{} . +Every LaTeX special character is covered; nothing else is touched. +.TP +.B groff +A backslash is escaped to +.BR \ee , +because a bare backslash starts a groff escape. If the ESCAPED string then +begins with +.B . +or +.BR ' , +the zero\-width non\-printing character +.B \e& +is prefixed \(em a +.B . +or +.B ' +in column one would otherwise start a request rather than print literally. +.TP +.B html +(also used for the +.B xml +flavour, identically) +.BR & " \(-> " & , +.BR < " \(-> " < , +.BR > " \(-> " > , +.BR \(dq " \(-> " " , +.BR ' " \(-> " ' . +.TP +.B xml +Identical to +.B html +above. +.TP +.B ics +Per RFC 5545: a backslash doubles, a semicolon and a comma are each +backslash\-escaped, a newline becomes the two\-character sequence +.BR \en , +and a carriage return is dropped outright (never doubled or passed through). +Line folding at 75 octets, on a UTF\-8 character boundary, is applied +separately to the whole rendered line \(em it is not part of value escaping +and is not something a template can see or control. +.TP +.B none +Escapes nothing at all: the value is inserted byte\-for\-byte. See +.B LIMITATIONS +below \(em this is not an oversight, and it is not safe to treat as one. +.PP +.B \-\-flavour +is inferred from +.BR \-\-template 's +own file extension when the flag is omitted: +.RS +.nf + +.I .tex \(-> latex +.I .ms .mom .me \(-> groff +.I .html .htm \(-> html +.I .xml \(-> xml +.I .ics \(-> ics +.I .md .adoc .txt \(-> none +.fi +.RE +.PP +An extension +.B colitur +does not recognise is a hard +.B ERROR +naming the six flavours above; it is +.I never +a silent fallback to +.BR none . +Guessing the flavour wrong would produce output that looks fine right up +until the metacharacters it silently failed to escape appear in a rendered +document. +.SH LIMITATIONS +.B AsciiDoc and Markdown are NOT escaped. +The +.B none +flavour (selected for +.IR .md " and " .adoc , +as well as +.IR .txt ) +passes every interpolated value through unchanged. This is a deliberate +choice, not a gap: unlike LaTeX, groff, HTML, XML or ICS, AsciiDoc and +Markdown have no fixed, small metacharacter set that could be escaped +mechanically \(em their own metacharacters are context\-dependent (a +.B * +means something different at the start of a line than in the middle of a +word), and escaping them here, generically, would produce +.I worse +output than leaving values alone in the ordinary case. +.PP +The consequence is real and is stated here plainly rather than left for a +reader to discover: a feast name, or any other interpolated field, containing +.B * +or +.B _ +renders as Markdown/AsciiDoc emphasis in the rendered document, not as a +literal asterisk or underscore. No shipped sanctoral name currently contains +either character, but a +.BR colitur\-overlay (5) +file supplying a local celebration's own name is not validated against this +constraint, and its author is responsible for avoiding both characters, or +accepting the emphasis, in any name rendered through a +.I .md +or +.I .adoc +template. +.PP +Only the Extraordinary Form (1962) view model is documented below; see +.BR colitur (1) +for the rite's own scope and limitations (readings cover only the Epistle +and Gospel; the votive Office of the Blessed Virgin Mary on Saturday does not +yet select among its five seasonal Masses). +.SH VIEW MODEL +The value a template renders against is built once per +.B colitur table +/ +.B render +/ +.B publish +invocation, from the same resolved calendar +.B colitur emit +uses, and is shaped for two artefacts from one model: a flat booklet (the +.B days +list, one entry per day of the requested year) and a month grid (the +.B months +list, each carrying its own +.B weeks +list of Sunday\-started, seven\-cell rows, padded at both ends with blank +cells so every row has exactly seven). This is the same shape published at +.IR schema/day\-v1.json , +described here in prose; the JSON Schema is the machine\-checked contract and +this page is its worked explanation. +.SS Top level +.TP +.B rite +The rite identifier, currently always the string +.BR ef . +.TP +.B year +The civil year requested, as a four\-digit string. +.TP +.B months +A list of twelve +.B month +objects, January through December. +.TP +.B days +A flat list of every day's own +.B day +object, in date order, for the whole requested year \(em what a booklet +template iterates over directly, without going through +.BR months . +.SS month +.TP +.B num +The month number, 1 through 12, as a string. +.TP +.B name +An object keyed by language (currently +.B la +and +.BR en ), +each value the month's own name in that language (e.g. +.RB \(lq Ianuarius \(rq +/ +.RB \(lq January \(rq ). +.TP +.B days +This month's own +.B day +objects, in date order, only the days that actually fall in this month. +.TP +.B weeks +This month's +.B day +objects grouped into Sunday\-started rows of exactly seven, the first and +last rows padded with blank cells (see +.B day \(-> in_month +below) so every row has seven entries regardless of which weekday the month +starts or ends on. +.SS week +.TP +.B num +The week's ordinal within its month (1, 2, 3, ...), as a string. This is +.I not +a liturgical week number \(em see +.B day \(-> week +below for that. +.TP +.B days +Exactly seven +.B day +objects, Sunday first. +.SS day +Every key below is always present on every day object, including a padding +cell (see +.BR in_month ), +so a template never hits a missing key on a real day OR a blank grid cell \(em +the one deliberate exception is that a padding cell's own string fields are +all set to the empty string and its boolean and list fields to +.B false +/empty, which read as absent under +.BR # / ^ / {{var}} +exactly as a genuinely unset field would. +.TP +.B iso +The date, ISO\-8601 (\c +.IR YYYY\-MM\-DD ). +Empty on a grid padding cell. +.TP +.B dom +The day of the month, as a string (no leading zero). Empty on a padding +cell. +.TP +.B dow +The day of the week as a string digit, +.B 0 +for Sunday through +.B 6 +for Saturday. Present, and meaningful, even on a padding cell \(em it is how +a grid template knows which column a blank cell belongs in. +.TP +.B in_month +Boolean. +.B false +on a padding cell (a blank cell added so a month's first or last week has +seven entries); a template checks this, not +.BR iso 's +emptiness, to decide whether to render a cell's contents. +.TP +.B season +The liturgical season's own string name (e.g. +.BR paschaltide ", " lent ). +.TP +.B week +The liturgical week number within the season, as a string, or the empty +string on a day the rite does not number (this is +.I not +the same field as a +.B week +object's own +.BR num , +described above \(em see +.B SCOPE AND LOOKUP +for why the two identically\-named fields do not collide here: a plain +.B day +object has no +.B num +key of its own at all, only +.BR week , +so there is nothing for it to shadow). +.TP +.B slug +The observed celebration's stable identifier (e.g. +.BR ef\-easter\-sunday ). +.TP +.B name +An object keyed by language, the observed celebration's own name in each +language colitur's data supplies one for. Frequently has no +.B la +or +.B en +key at all (most temporal days, most sanctoral entries in the shipped data) +\(em see +.B SCOPE AND LOOKUP +above for the resulting month\-name collision and its safe idiom. +.TP +.B rank +The observed celebration's class, as the kernel's own string (e.g. +.BR class\-1 ). +There is deliberately no separate, localized rank label: the kernel carries +no per\-language rank names to draw one from. +.TP +.B colour +The observed celebration's liturgical colour, lowercase (one of +.BR white ", " red ", " green ", " violet ", " rose ", " black , +or the empty string). +.TP +.BR is_white ", " is_red ", " is_green ", " is_violet ", " is_rose ", " is_black +Six booleans, exactly one true (matching +.BR colour ) +on a real day, all false on a padding cell. Provided so a template can +select styling (a cell background colour, a class name) with a plain +.B {{#is_white}} +section instead of a string comparison the engine does not offer \(em there +is no expression evaluation, so this is the only way a template branches on +colour at all. +.TP +.B subject +Whose feast this is, lowercase (one of +.BR lord ", " bvm ", " saint ", " temporal ). +.TP +.B comms +A list of commemoration objects admitted on this day, each carrying +.BR slug , +.B name +(an object keyed by language, same shape as the day's own +.BR name ), +and +.B privileged +(boolean: true for a privileged commemoration under RG 109, which survives +even where an ordinary one would be capped out). Empty list on a day with no +commemorations, and always an empty list \(em never absent \(em on a padding +cell. +.TP +.B transferred_in +A list of at most one object, present when a feast impeded elsewhere was +transferred onto THIS day (RG 96\(en98); carries the transferred +celebration's own +.BR slug . +Empty list when nothing transferred in. +.TP +.B transferred_out +A list of objects, one per celebration that would have fallen on this day +but was displaced and moved to a later date; each carries +.B slug +and +.B to +(the ISO\-8601 date it was moved to). Empty on the ordinary day. +.TP +.B first +The Epistle/Lesson reading citation (e.g. +.RB \(lq "Heb 1:1\-12" \(rq ), +never scripture text \(em a reference only. Empty string when none resolved. +.TP +.B gospel +The Gospel reading citation, same shape as +.BR first . +.TP +.B last +Boolean, true on the seventh (final) cell of a grid row, false everywhere +else including every entry of the flat +.B days +list. Exists because the engine offers no "unless this is the last item" +construct, so a template that must print a separator BETWEEN cells but not +after the last one (a table row's column rule, for instance) reads this flag +rather than computing it: without it, a seven\-column LaTeX grid would emit +an eighth, empty column and +.B pdflatex +would reject the file outright. +.SH A WORKED MINIMAL TEMPLATE +A plain\-text booklet, one line per day, using the safe name idiom from +.BR "SCOPE AND LOOKUP" : +.RS +.nf + +{{rite}} {{year}} +{{#days}} +{{iso}} {{#name}}{{la}}{{^la}}{{slug}}{{/la}}{{/name}} {{colour}}{{#comms}} +{{slug}}{{/comms}} +{{/days}} +.fi +.RE +.PP +Rendered (extension +.IR .txt , +so flavour +.BR none , +no escaping applied; the blank lines are the template's own \(em its section +body starts and ends with a literal newline, and this engine does not trim +one): +.RS +.nf + +.B colitur table \-\-year 2026 \-\-template minimal.txt | head \-7 +ef 2026 + +2026\-01\-01 ef\-circumcision white + +2026\-01\-02 ef\-christmas\-1\-friday white + +2026\-01\-03 Officium sanctae Mariae in sabbato white +.fi +.RE +.PP +The second data line shows the fallback firing: 2 January carries no Latin +.B name +in the shipped data, so +.B {{^la}} +supplies +.B {{slug}} +instead. The third shows the non\-fallback case: 3 January +.I does +carry a Latin name (the votive Office of the Blessed Virgin Mary on +Saturday), and the idiom prints it correctly. A template using the unsafe, +bare +.B {{name.la}} +form would instead have printed +.RB \(lq Ianuarius \(rq +on BOTH of those lines \(em the enclosing month's own name \(em see +.B SCOPE AND LOOKUP +above. +.SH SEE ALSO +.BR colitur (1) +for +.BR table ", " render " and " publish , +and for the five +.B emit +formats that share this same view model. +.PP +.BR colitur\-overlay (5) +for the local\-calendar file format that supplies the celebrations a +template's +.B name +and +.B slug +fields can carry. +.SH LICENSE +AGPL\-3.0\-or\-later. diff --git a/man/colitur.1 b/man/colitur.1 index d015a49..005cc0a 100644 --- a/man/colitur.1 +++ b/man/colitur.1 @@ -448,6 +448,17 @@ needs and a booklet does not). A key absent on a given day (an optional field a rite does not always set) renders as the empty string rather than an error \(em the one deliberate silence, so a template survives a day that does not carry every optional field. +.PP +See +.BR colitur\-templates (5) +for the full syntax, the escaping table per flavour, the complete +view\-model field reference, and \(em before writing a template of any +complexity \(em its +.B SCOPE AND LOOKUP +section: an inner key silently loses to an outer key of the same name (a bare +.B {{name.la}} +inside a day resolves to the enclosing MONTH's name, not the day's own), +which has produced wrong output in this project's own templates. .SS Flavours .BI \-\-flavour controls how interpolated @@ -692,11 +703,9 @@ shapes: .RE .PP Accepted on -.B day -and -.B readings -only. The other commands read no sanctoral data at all, so the flag would have -no effect there and is +.BR day ", " readings ", " emit ", " table ", " render " and " publish . +.BR easter " and " temporal +read no sanctoral data at all, so the flag would have no effect there and is .I refused rather than silently ignored. .PP @@ -845,6 +854,13 @@ reading citations fall back to the day's ordinary ones. for the overlay file format \(em every directive, every field, the three date shapes and worked examples. .PP +.BR colitur\-templates (5) +for the template format used by +.BR table ", " render " and " publish +\(em the four syntax forms, the six flavours and their escaping, the full +view\-model field reference, and the scope\-shadowing hazard a template author +will hit. +.PP .BR lectio (1) .SH LICENSE AGPL\-3.0\-or\-later. diff --git a/schema/dune b/schema/dune new file mode 100644 index 0000000..b3c7dfe --- /dev/null +++ b/schema/dune @@ -0,0 +1,16 @@ +; The published contracts, installed into /share/colitur/schema/ so +; an installed `colitur` can find schema/day-v1.json from an arbitrary +; working directory, not only a build-tree checkout -- bin/main.ml's own +; [schema_path] (`colitur publish`) probes exactly this location as its +; INSTALLED candidate, mirroring data/dune's own ef/ layout. Task 13. +; +; colitur-v1.xsd ships alongside it as the XML sibling contract (`colitur +; emit --format xml`); nothing in colitur itself reads it at runtime -- only +; `make check-schema`, via xmllint, and a template author who wants to +; validate their own rendered XML by hand. +(install + (section share) + (package colitur) + (files + (day-v1.json as schema/day-v1.json) + (colitur-v1.xsd as schema/colitur-v1.xsd))) diff --git a/templates/dune b/templates/dune new file mode 100644 index 0000000..e5918a0 --- /dev/null +++ b/templates/dune @@ -0,0 +1,22 @@ +; The shipped templates, installed into /share/colitur/templates/ +; so a user can render a booklet or a wall calendar straight from an +; installed `colitur`, without a source checkout on hand -- the same +; "runnable documentation" reasoning data/dune already gives +; examples/diocesan-example.sexp. Nothing in colitur's own code path looks +; these up (--template takes a plain, user-given file path, read exactly +; like an overlay file), so this is a convenience install, not something a +; probe function depends on the way [data_dir]/[schema_path] depend on +; data/ef/ and schema/. Task 13. +(install + (section share) + (package colitur) + (files + (ef/ordo.tex as templates/ef/ordo.tex) + (ef/ordo.ms as templates/ef/ordo.ms) + (ef/ordo.html as templates/ef/ordo.html) + (ef/ordo.adoc as templates/ef/ordo.adoc) + (ef/ordo.md as templates/ef/ordo.md) + (ef/ordo.txt as templates/ef/ordo.txt) + (ef/grid.tex as templates/ef/grid.tex) + (ef/grid.ms as templates/ef/grid.ms) + (ef/grid.html as templates/ef/grid.html))) -- cgit v1.3 From a9464100bb02d74c90d585f8334f449b1fefa9d7 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Wed, 19 Aug 2026 11:35:13 +0200 Subject: fix(templates): grid.ms wall calendar dropped four of seven columns pdftotext -layout of the shipped grid.ms showed only 3-4 of 7 columns and roughly a third of each month's day numbers: tbl's plain columns (no w()) size to their widest single entry and never wrap, so a long fallback slug (some run past 40 characters) forced every column that wide, the table ran far past the page, and whatever fell past the physical edge was gone, not merely ugly. groff exited 0 throughout (warnings, not errors), so make check-templates reported OK on a broken artefact. Fixed both halves. (a) The table now fits: true landscape via gropdf's own -P-pa4l (an in-document Xpapersize=a4l escape was tried and rejected -- it does not rotate the page in this groff), ms's own title macro widened back out after narrowing the line length for the title text (a second, independent way the original lost its width, found by reading s.tmac), and every column rewritten as a genuine tbl text-block (T{/T}, not a plain w() cell -- w() alone does not wrap, confirmed against tbl's own generated troff code) so long, hyphenated slugs wrap at their own hyphens instead of forcing the column wider. (b) check-templates now captures groff's stderr per template and fails the target if it is non-empty, rather than trusting groff's exit code. Verified: 0 warnings (was 12), pdftotext -layout shows all 7 columns and every day number for all 12 months (was 3-4 columns, ~12-23 of each month's day numbers). The golden fixture is regenerated: 0 "{{", 12 month headings, exactly one Ianuarius, and each week's block (now spread across several physical lines by the T{/T} wrap) carries exactly 6 tabs joining its 7 cells. --- Makefile | 19 +- templates/ef/grid.ms | 78 +++- test/golden/grid-2027.ms | 1126 ++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 1128 insertions(+), 95 deletions(-) (limited to 'Makefile') diff --git a/Makefile b/Makefile index aa4bce6..d9377df 100644 --- a/Makefile +++ b/Makefile @@ -64,9 +64,22 @@ check-templates: build ## typeset every shipped template (needs pdflatex/groff; else echo "SKIPPED: pdflatex not installed -- LaTeX templates render but are NOT typeset"; fi; \ if command -v groff >/dev/null 2>&1; then \ for t in ordo grid; do \ - opam exec -- dune exec colitur -- table --year 2027 --template templates/ef/$$t.ms > /tmp/$$t.ms && \ - groff -ms -t -Tpdf /tmp/$$t.ms > /tmp/$$t-ms.pdf && \ - echo "groff: $$t.ms OK" || { echo "groff: $$t.ms FAILED"; ok=0; }; \ + gflags=""; \ + [ "$$t" = grid ] && gflags="-P-pa4l"; \ + if opam exec -- dune exec colitur -- table --year 2027 --template templates/ef/$$t.ms \ + > /tmp/$$t.ms 2>/tmp/$$t-render.err; then \ + groff -ms -t -Tpdf $$gflags /tmp/$$t.ms > /tmp/$$t-ms.pdf 2>/tmp/$$t-ms.warnings; \ + if [ -s /tmp/$$t-ms.warnings ]; then \ + echo "groff: $$t.ms FAILED (groff exits 0 on a tbl/troff warning -- this target"; \ + echo " treats ANY stderr output as a failure, since a warning here has meant"; \ + echo " silently lost table columns before):"; \ + cat /tmp/$$t-ms.warnings; ok=0; \ + else \ + echo "groff: $$t.ms OK"; \ + fi; \ + else \ + echo "groff: $$t.ms FAILED (colitur table render):"; cat /tmp/$$t-render.err; ok=0; \ + fi; \ done; \ else echo "SKIPPED: groff not installed -- groff templates render but are NOT typeset"; fi; \ test $$ok -eq 1 diff --git a/templates/ef/grid.ms b/templates/ef/grid.ms index 0ec2fb3..703f46b 100644 --- a/templates/ef/grid.ms +++ b/templates/ef/grid.ms @@ -1,5 +1,67 @@ .\" colitur wall calendar -- groff ms with tbl. flavour: groff -.\" Build: colitur table --year 2027 --template grid.ms | groff -ms -t -Tpdf > grid.pdf +.\" Build: colitur table --year 2027 --template grid.ms | groff -ms -t -Tpdf -P-pa4l > grid.pdf +.\" +.\" LANDSCAPE, not the ms default portrait: with allbox cells and Latin-less +.\" days falling back to the raw slug (some fallback slugs run past 40 +.\" characters, e.g. "commemoration-of-the-baptism-of-the-lord"), seven +.\" columns of real content do not fit a portrait line length at any +.\" reasonable point size. "-P-pa4l" is gropdf's own landscape papersize +.\" (groff_font(5): a trailing "l" on a papersize name swaps width/height at +.\" the OUTPUT DEVICE level) -- it must be a command-line flag, not a request +.\" inside this file: an in-document "\X'papersize=a4l'" escape was tried and +.\" rejected (it does not actually rotate gropdf's page in this groff, and +.\" throws diagnostics doing it). ".pl"/".po"/".ll" below independently widen +.\" TROFF's OWN idea of the page to match -- ".pl"/".ll" are requests, unlike +.\" the device's own physical page size, and are not implied by "-P-pa4l" -- +.\" so both halves are needed, or one side clips the other. +.\" +.\" ".TL" (the ms title macro, s.tmac) ITSELF narrows the line length to +.\" 5/6 of register "LL" for the title text, and never widens it back +.\" afterward -- there is no third place in s.tmac that ever does. Setting +.\" only the primitive ".ll" before ".TL" is therefore not enough: ".TL" +.\" overwrites it and every table for the rest of the document inherits +.\" the NARROWED value, silently, which is a second, independent way the +.\" original template lost its width (found by reading s.tmac itself, not +.\" guessed). Fixed by setting register "LL" (what ".TL" actually reads) +.\" and re-asserting ".ll" once more, explicitly, right after the title. +.\" +.\" Every column is a FIXED-WIDTH, WRAPPING tbl "w()" block, not a plain "l": +.\" without "w()" tbl sizes a column to its single widest entry and does NOT +.\" wrap, so a 40-character slug forces every column that wide -- seven of +.\" them together run far past any line length, tbl warns "table wider than +.\" line length", and whatever falls past the physical page edge is not a +.\" rendering nicety missing, it is GONE: `pdftotext -layout` (and a printed +.\" page) show only however many columns fit, not all seven. "w()" makes +.\" each column wrap its own text block instead, the same fix grid.tex +.\" already uses via LaTeX's "p{2.6cm}" (see that file's own comment) -- +.\" this is the tbl-native equivalent, not a different design. +.\" +.\" "w()" alone is NOT sufficient, and this is the part that actually cost +.\" the time: tbl only wraps a cell as a text block when its content is +.\" delimited by "T{"/"T}" on their own lines. A PLAIN cell entry in a +.\" "w()" column (what the first attempt at this fix used) is never +.\" wrapped at all -- tbl just widens the column past the requested "w()" +.\" to fit the single longest unbroken entry, exactly reproducing the +.\" original bug. Confirmed directly against tbl's own generated troff +.\" code (`tbl grid.ms`, grep "3w0 .*>?"): every column width register is +.\" `max(w(), \w'cell text')`, so an un-delimited 40-character cell always +.\" wins that max. Every day cell below is therefore its own "T{"/"T}" +.\" block; the closing "T}" and the following column's opening "T{" share +.\" one line with the tab between them (the standard tbl idiom: "T} +.\" T{"). The template writes that as "{{#last}}T}{{/last}}{{^last}}T} +.\" {{/last}}" rather than "T}{{^last}}{{/last}}T{" so that no +.\" literal "T{" ever sits directly against a "{{"/"}}" delimiter in the +.\" source -- three braces in a row there parses as a malformed tag, not +.\" as literal text followed by a tag. +.\" +.\" ".na" (no-adjust, ragged right) is required alongside the wrap, not +.\" cosmetic: a hyphenated slug like "commemoration-of-the-baptism-of-the- +.\" lord" DOES break at its own hyphens once wrapping is active (verified: +.\" troff's filler treats an ASCII hyphen as a break point), but adjusted +.\" (justified) fill in a column this narrow cannot always stretch such a +.\" line to the full measure and troff warns "cannot adjust line" for +.\" every such row -- another warning `make check-templates` must fail on. +.\" Ragged-right removes the stretching, not the wrapping. .\" .\" Day label falls back to the slug when the day carries no Latin name (most .\" temporal days, and most sanctoral entries, which are Latin-less in the @@ -10,16 +72,24 @@ .\" Every cell also carries a last flag, true on the seventh of its row: tbl .\" needs the tab separator BETWEEN columns, not after the last one, and the .\" engine has no unless-last construct, so the flag comes from data. +.pl 8.27i +.po 0.3i +.nr LL 10.9i +.ll \n[LL]u .TL Calendarium {{year}} \(bu {{rite}} +.ll \n[LL]u +.na {{#months}} .SH {{name.la}} .TS allbox; -c c c c c c c -l l l l l l l. +cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) +lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i). Dom Lun Mar Mer Iov Ven Sab -{{#weeks}}{{#days}}{{#in_month}}{{dom}} {{#name}}{{la}}{{^la}}{{slug}}{{/la}}{{/name}}{{/in_month}}{{^last}} {{/last}}{{/days}} +{{#weeks}}{{#days}}T{ +{{#in_month}}\fB{{dom}}\fP \s-2{{#name}}{{la}}{{^la}}{{slug}}{{/la}}{{/name}}\s+2{{/in_month}} +{{#last}}T}{{/last}}{{^last}}T} {{/last}}{{/days}} {{/weeks}}.TE {{/months}} diff --git a/test/golden/grid-2027.ms b/test/golden/grid-2027.ms index 785d59a..5668b86 100644 --- a/test/golden/grid-2027.ms +++ b/test/golden/grid-2027.ms @@ -1,5 +1,67 @@ .\" colitur wall calendar -- groff ms with tbl. flavour: groff -.\" Build: colitur table --year 2027 --template grid.ms | groff -ms -t -Tpdf > grid.pdf +.\" Build: colitur table --year 2027 --template grid.ms | groff -ms -t -Tpdf -P-pa4l > grid.pdf +.\" +.\" LANDSCAPE, not the ms default portrait: with allbox cells and Latin-less +.\" days falling back to the raw slug (some fallback slugs run past 40 +.\" characters, e.g. "commemoration-of-the-baptism-of-the-lord"), seven +.\" columns of real content do not fit a portrait line length at any +.\" reasonable point size. "-P-pa4l" is gropdf's own landscape papersize +.\" (groff_font(5): a trailing "l" on a papersize name swaps width/height at +.\" the OUTPUT DEVICE level) -- it must be a command-line flag, not a request +.\" inside this file: an in-document "\X'papersize=a4l'" escape was tried and +.\" rejected (it does not actually rotate gropdf's page in this groff, and +.\" throws diagnostics doing it). ".pl"/".po"/".ll" below independently widen +.\" TROFF's OWN idea of the page to match -- ".pl"/".ll" are requests, unlike +.\" the device's own physical page size, and are not implied by "-P-pa4l" -- +.\" so both halves are needed, or one side clips the other. +.\" +.\" ".TL" (the ms title macro, s.tmac) ITSELF narrows the line length to +.\" 5/6 of register "LL" for the title text, and never widens it back +.\" afterward -- there is no third place in s.tmac that ever does. Setting +.\" only the primitive ".ll" before ".TL" is therefore not enough: ".TL" +.\" overwrites it and every table for the rest of the document inherits +.\" the NARROWED value, silently, which is a second, independent way the +.\" original template lost its width (found by reading s.tmac itself, not +.\" guessed). Fixed by setting register "LL" (what ".TL" actually reads) +.\" and re-asserting ".ll" once more, explicitly, right after the title. +.\" +.\" Every column is a FIXED-WIDTH, WRAPPING tbl "w()" block, not a plain "l": +.\" without "w()" tbl sizes a column to its single widest entry and does NOT +.\" wrap, so a 40-character slug forces every column that wide -- seven of +.\" them together run far past any line length, tbl warns "table wider than +.\" line length", and whatever falls past the physical page edge is not a +.\" rendering nicety missing, it is GONE: `pdftotext -layout` (and a printed +.\" page) show only however many columns fit, not all seven. "w()" makes +.\" each column wrap its own text block instead, the same fix grid.tex +.\" already uses via LaTeX's "p{2.6cm}" (see that file's own comment) -- +.\" this is the tbl-native equivalent, not a different design. +.\" +.\" "w()" alone is NOT sufficient, and this is the part that actually cost +.\" the time: tbl only wraps a cell as a text block when its content is +.\" delimited by "T{"/"T}" on their own lines. A PLAIN cell entry in a +.\" "w()" column (what the first attempt at this fix used) is never +.\" wrapped at all -- tbl just widens the column past the requested "w()" +.\" to fit the single longest unbroken entry, exactly reproducing the +.\" original bug. Confirmed directly against tbl's own generated troff +.\" code (`tbl grid.ms`, grep "3w0 .*>?"): every column width register is +.\" `max(w(), \w'cell text')`, so an un-delimited 40-character cell always +.\" wins that max. Every day cell below is therefore its own "T{"/"T}" +.\" block; the closing "T}" and the following column's opening "T{" share +.\" one line with the tab between them (the standard tbl idiom: "T} +.\" T{"). The template writes that as "T} +.\" " rather than "T}T{" so that no +.\" literal "T{" ever sits directly against a "" delimiter in the +.\" source -- three braces in a row there parses as a malformed tag, not +.\" as literal text followed by a tag. +.\" +.\" ".na" (no-adjust, ragged right) is required alongside the wrap, not +.\" cosmetic: a hyphenated slug like "commemoration-of-the-baptism-of-the- +.\" lord" DOES break at its own hyphens once wrapping is active (verified: +.\" troff's filler treats an ASCII hyphen as a break point), but adjusted +.\" (justified) fill in a column this narrow cannot always stretch such a +.\" line to the full measure and troff warns "cannot adjust line" for +.\" every such row -- another warning `make check-templates` must fail on. +.\" Ragged-right removes the stretching, not the wrapping. .\" .\" Day label falls back to the slug when the day carries no Latin name (most .\" temporal days, and most sanctoral entries, which are Latin-less in the @@ -10,177 +72,1065 @@ .\" Every cell also carries a last flag, true on the seventh of its row: tbl .\" needs the tab separator BETWEEN columns, not after the last one, and the .\" engine has no unless-last construct, so the flag comes from data. +.pl 8.27i +.po 0.3i +.nr LL 10.9i +.ll \n[LL]u .TL Calendarium 2027 \(bu ef +.ll \n[LL]u +.na .SH Ianuarius .TS allbox; -c c c c c c c -l l l l l l l. +cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) +lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i). Dom Lun Mar Mer Iov Ven Sab - 1 ef-circumcision 2 Officium sanctae Mariae in sabbato -3 Sanctissimi Nominis Iesu 4 ef-christmas-1-monday 5 ef-christmas-1-tuesday 6 ef-epiphany 7 ef-christmas-2-thursday 8 ef-christmas-2-friday 9 Officium sanctae Mariae in sabbato -10 Sanctae Familiae Iesu, Mariae, Ioseph 11 ef-time-after-epiphany-1-monday 12 ef-time-after-epiphany-1-tuesday 13 commemoration-of-the-baptism-of-the-lord 14 hilary 15 paul-the-first-hermit 16 marcellus-i -17 ef-time-after-epiphany-sunday-2 18 ef-time-after-epiphany-2-monday 19 ef-time-after-epiphany-2-tuesday 20 sts-fabian-sebastian 21 agnes 22 sts-vincent-anastasius 23 raymond-of-pe-afort -24 ef-septuagesima-sunday-1 25 conversion-of-st-paul 26 polycarp 27 john-chrysostom 28 peter-nolasco 29 francis-de-sales 30 martina -31 ef-septuagesima-sunday-2 +T{ + +T} T{ + +T} T{ + +T} T{ + +T} T{ + +T} T{ +\fB1\fP \s-2ef-circumcision\s+2 +T} T{ +\fB2\fP \s-2Officium sanctae Mariae in sabbato\s+2 +T} +T{ +\fB3\fP \s-2Sanctissimi Nominis Iesu\s+2 +T} T{ +\fB4\fP \s-2ef-christmas-1-monday\s+2 +T} T{ +\fB5\fP \s-2ef-christmas-1-tuesday\s+2 +T} T{ +\fB6\fP \s-2ef-epiphany\s+2 +T} T{ +\fB7\fP \s-2ef-christmas-2-thursday\s+2 +T} T{ +\fB8\fP \s-2ef-christmas-2-friday\s+2 +T} T{ +\fB9\fP \s-2Officium sanctae Mariae in sabbato\s+2 +T} +T{ +\fB10\fP \s-2Sanctae Familiae Iesu, Mariae, Ioseph\s+2 +T} T{ +\fB11\fP \s-2ef-time-after-epiphany-1-monday\s+2 +T} T{ +\fB12\fP \s-2ef-time-after-epiphany-1-tuesday\s+2 +T} T{ +\fB13\fP \s-2commemoration-of-the-baptism-of-the-lord\s+2 +T} T{ +\fB14\fP \s-2hilary\s+2 +T} T{ +\fB15\fP \s-2paul-the-first-hermit\s+2 +T} T{ +\fB16\fP \s-2marcellus-i\s+2 +T} +T{ +\fB17\fP \s-2ef-time-after-epiphany-sunday-2\s+2 +T} T{ +\fB18\fP \s-2ef-time-after-epiphany-2-monday\s+2 +T} T{ +\fB19\fP \s-2ef-time-after-epiphany-2-tuesday\s+2 +T} T{ +\fB20\fP \s-2sts-fabian-sebastian\s+2 +T} T{ +\fB21\fP \s-2agnes\s+2 +T} T{ +\fB22\fP \s-2sts-vincent-anastasius\s+2 +T} T{ +\fB23\fP \s-2raymond-of-pe-afort\s+2 +T} +T{ +\fB24\fP \s-2ef-septuagesima-sunday-1\s+2 +T} T{ +\fB25\fP \s-2conversion-of-st-paul\s+2 +T} T{ +\fB26\fP \s-2polycarp\s+2 +T} T{ +\fB27\fP \s-2john-chrysostom\s+2 +T} T{ +\fB28\fP \s-2peter-nolasco\s+2 +T} T{ +\fB29\fP \s-2francis-de-sales\s+2 +T} T{ +\fB30\fP \s-2martina\s+2 +T} +T{ +\fB31\fP \s-2ef-septuagesima-sunday-2\s+2 +T} T{ + +T} T{ + +T} T{ + +T} T{ + +T} T{ + +T} T{ + +T} .TE .SH Februarius .TS allbox; -c c c c c c c -l l l l l l l. +cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) +lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i). Dom Lun Mar Mer Iov Ven Sab - 1 ignatius-of-antioch 2 purification-of-the-blessed-virgin-mary 3 ef-septuagesima-2-wednesday 4 andrew-corsini 5 agatha 6 titus -7 ef-septuagesima-sunday-3 8 john-of-matha 9 cyril-of-alexandria 10 ef-ash-wednesday 11 ef-lent-after-ashes-thursday 12 ef-lent-after-ashes-friday 13 ef-lent-after-ashes-saturday -14 ef-lent-sunday-1 15 ef-lent-1-monday 16 ef-lent-1-tuesday 17 ef-lent-ember-wed 18 ef-lent-1-thursday 19 ef-lent-ember-fri 20 ef-lent-ember-sat -21 ef-lent-sunday-2 22 chair-of-st-peter 23 ef-lent-2-tuesday 24 matthias 25 ef-lent-2-thursday 26 ef-lent-2-friday 27 ef-lent-2-saturday -28 ef-lent-sunday-3 +T{ + +T} T{ +\fB1\fP \s-2ignatius-of-antioch\s+2 +T} T{ +\fB2\fP \s-2purification-of-the-blessed-virgin-mary\s+2 +T} T{ +\fB3\fP \s-2ef-septuagesima-2-wednesday\s+2 +T} T{ +\fB4\fP \s-2andrew-corsini\s+2 +T} T{ +\fB5\fP \s-2agatha\s+2 +T} T{ +\fB6\fP \s-2titus\s+2 +T} +T{ +\fB7\fP \s-2ef-septuagesima-sunday-3\s+2 +T} T{ +\fB8\fP \s-2john-of-matha\s+2 +T} T{ +\fB9\fP \s-2cyril-of-alexandria\s+2 +T} T{ +\fB10\fP \s-2ef-ash-wednesday\s+2 +T} T{ +\fB11\fP \s-2ef-lent-after-ashes-thursday\s+2 +T} T{ +\fB12\fP \s-2ef-lent-after-ashes-friday\s+2 +T} T{ +\fB13\fP \s-2ef-lent-after-ashes-saturday\s+2 +T} +T{ +\fB14\fP \s-2ef-lent-sunday-1\s+2 +T} T{ +\fB15\fP \s-2ef-lent-1-monday\s+2 +T} T{ +\fB16\fP \s-2ef-lent-1-tuesday\s+2 +T} T{ +\fB17\fP \s-2ef-lent-ember-wed\s+2 +T} T{ +\fB18\fP \s-2ef-lent-1-thursday\s+2 +T} T{ +\fB19\fP \s-2ef-lent-ember-fri\s+2 +T} T{ +\fB20\fP \s-2ef-lent-ember-sat\s+2 +T} +T{ +\fB21\fP \s-2ef-lent-sunday-2\s+2 +T} T{ +\fB22\fP \s-2chair-of-st-peter\s+2 +T} T{ +\fB23\fP \s-2ef-lent-2-tuesday\s+2 +T} T{ +\fB24\fP \s-2matthias\s+2 +T} T{ +\fB25\fP \s-2ef-lent-2-thursday\s+2 +T} T{ +\fB26\fP \s-2ef-lent-2-friday\s+2 +T} T{ +\fB27\fP \s-2ef-lent-2-saturday\s+2 +T} +T{ +\fB28\fP \s-2ef-lent-sunday-3\s+2 +T} T{ + +T} T{ + +T} T{ + +T} T{ + +T} T{ + +T} T{ + +T} .TE .SH Martius .TS allbox; -c c c c c c c -l l l l l l l. +cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) +lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i). Dom Lun Mar Mer Iov Ven Sab - 1 ef-lent-3-monday 2 ef-lent-3-tuesday 3 ef-lent-3-wednesday 4 ef-lent-3-thursday 5 ef-lent-3-friday 6 ef-lent-3-saturday -7 ef-lent-sunday-4 8 ef-lent-4-monday 9 ef-lent-4-tuesday 10 ef-lent-4-wednesday 11 ef-lent-4-thursday 12 ef-lent-4-friday 13 ef-lent-4-saturday -14 ef-passion-sunday 15 ef-passiontide-1-monday 16 ef-passiontide-1-tuesday 17 ef-passiontide-1-wednesday 18 ef-passiontide-1-thursday 19 joseph-spouse-of-the-bl-virgin-mary 20 ef-passiontide-1-saturday -21 ef-palm-sunday 22 ef-passiontide-2-monday 23 ef-passiontide-2-tuesday 24 ef-passiontide-2-wednesday 25 Feria V in Cena Domini 26 Feria VI in Passione et Morte Domini 27 Sabbato sancto -28 ef-easter-sunday 29 ef-easter-1-monday 30 ef-easter-1-tuesday 31 ef-easter-1-wednesday +T{ + +T} T{ +\fB1\fP \s-2ef-lent-3-monday\s+2 +T} T{ +\fB2\fP \s-2ef-lent-3-tuesday\s+2 +T} T{ +\fB3\fP \s-2ef-lent-3-wednesday\s+2 +T} T{ +\fB4\fP \s-2ef-lent-3-thursday\s+2 +T} T{ +\fB5\fP \s-2ef-lent-3-friday\s+2 +T} T{ +\fB6\fP \s-2ef-lent-3-saturday\s+2 +T} +T{ +\fB7\fP \s-2ef-lent-sunday-4\s+2 +T} T{ +\fB8\fP \s-2ef-lent-4-monday\s+2 +T} T{ +\fB9\fP \s-2ef-lent-4-tuesday\s+2 +T} T{ +\fB10\fP \s-2ef-lent-4-wednesday\s+2 +T} T{ +\fB11\fP \s-2ef-lent-4-thursday\s+2 +T} T{ +\fB12\fP \s-2ef-lent-4-friday\s+2 +T} T{ +\fB13\fP \s-2ef-lent-4-saturday\s+2 +T} +T{ +\fB14\fP \s-2ef-passion-sunday\s+2 +T} T{ +\fB15\fP \s-2ef-passiontide-1-monday\s+2 +T} T{ +\fB16\fP \s-2ef-passiontide-1-tuesday\s+2 +T} T{ +\fB17\fP \s-2ef-passiontide-1-wednesday\s+2 +T} T{ +\fB18\fP \s-2ef-passiontide-1-thursday\s+2 +T} T{ +\fB19\fP \s-2joseph-spouse-of-the-bl-virgin-mary\s+2 +T} T{ +\fB20\fP \s-2ef-passiontide-1-saturday\s+2 +T} +T{ +\fB21\fP \s-2ef-palm-sunday\s+2 +T} T{ +\fB22\fP \s-2ef-passiontide-2-monday\s+2 +T} T{ +\fB23\fP \s-2ef-passiontide-2-tuesday\s+2 +T} T{ +\fB24\fP \s-2ef-passiontide-2-wednesday\s+2 +T} T{ +\fB25\fP \s-2Feria V in Cena Domini\s+2 +T} T{ +\fB26\fP \s-2Feria VI in Passione et Morte Domini\s+2 +T} T{ +\fB27\fP \s-2Sabbato sancto\s+2 +T} +T{ +\fB28\fP \s-2ef-easter-sunday\s+2 +T} T{ +\fB29\fP \s-2ef-easter-1-monday\s+2 +T} T{ +\fB30\fP \s-2ef-easter-1-tuesday\s+2 +T} T{ +\fB31\fP \s-2ef-easter-1-wednesday\s+2 +T} T{ + +T} T{ + +T} T{ + +T} .TE .SH Aprilis .TS allbox; -c c c c c c c -l l l l l l l. +cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) +lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i). Dom Lun Mar Mer Iov Ven Sab - 1 ef-easter-1-thursday 2 ef-easter-1-friday 3 ef-easter-1-saturday -4 ef-low-sunday 5 annunciation-of-the-blessed-virgin-mary 6 ef-easter-2-tuesday 7 ef-easter-2-wednesday 8 ef-easter-2-thursday 9 ef-easter-2-friday 10 Officium sanctae Mariae in sabbato -11 ef-easter-sunday-3 12 ef-easter-3-monday 13 hermenegild 14 justin 15 ef-easter-3-thursday 16 ef-easter-3-friday 17 Officium sanctae Mariae in sabbato -18 ef-easter-sunday-4 19 ef-easter-4-monday 20 ef-easter-4-tuesday 21 anselm 22 sts-soter-caius 23 ef-easter-4-friday 24 fidelis-of-sigmaringen -25 ef-easter-sunday-5 26 sts-cletus-marcellinus 27 peter-canisius 28 paul-of-the-cross 29 peter-of-verona 30 catherine-of-siena +T{ + +T} T{ + +T} T{ + +T} T{ + +T} T{ +\fB1\fP \s-2ef-easter-1-thursday\s+2 +T} T{ +\fB2\fP \s-2ef-easter-1-friday\s+2 +T} T{ +\fB3\fP \s-2ef-easter-1-saturday\s+2 +T} +T{ +\fB4\fP \s-2ef-low-sunday\s+2 +T} T{ +\fB5\fP \s-2annunciation-of-the-blessed-virgin-mary\s+2 +T} T{ +\fB6\fP \s-2ef-easter-2-tuesday\s+2 +T} T{ +\fB7\fP \s-2ef-easter-2-wednesday\s+2 +T} T{ +\fB8\fP \s-2ef-easter-2-thursday\s+2 +T} T{ +\fB9\fP \s-2ef-easter-2-friday\s+2 +T} T{ +\fB10\fP \s-2Officium sanctae Mariae in sabbato\s+2 +T} +T{ +\fB11\fP \s-2ef-easter-sunday-3\s+2 +T} T{ +\fB12\fP \s-2ef-easter-3-monday\s+2 +T} T{ +\fB13\fP \s-2hermenegild\s+2 +T} T{ +\fB14\fP \s-2justin\s+2 +T} T{ +\fB15\fP \s-2ef-easter-3-thursday\s+2 +T} T{ +\fB16\fP \s-2ef-easter-3-friday\s+2 +T} T{ +\fB17\fP \s-2Officium sanctae Mariae in sabbato\s+2 +T} +T{ +\fB18\fP \s-2ef-easter-sunday-4\s+2 +T} T{ +\fB19\fP \s-2ef-easter-4-monday\s+2 +T} T{ +\fB20\fP \s-2ef-easter-4-tuesday\s+2 +T} T{ +\fB21\fP \s-2anselm\s+2 +T} T{ +\fB22\fP \s-2sts-soter-caius\s+2 +T} T{ +\fB23\fP \s-2ef-easter-4-friday\s+2 +T} T{ +\fB24\fP \s-2fidelis-of-sigmaringen\s+2 +T} +T{ +\fB25\fP \s-2ef-easter-sunday-5\s+2 +T} T{ +\fB26\fP \s-2sts-cletus-marcellinus\s+2 +T} T{ +\fB27\fP \s-2peter-canisius\s+2 +T} T{ +\fB28\fP \s-2paul-of-the-cross\s+2 +T} T{ +\fB29\fP \s-2peter-of-verona\s+2 +T} T{ +\fB30\fP \s-2catherine-of-siena\s+2 +T} T{ + +T} .TE .SH Maius .TS allbox; -c c c c c c c -l l l l l l l. +cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) +lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i). Dom Lun Mar Mer Iov Ven Sab - 1 joseph-the-workman -2 ef-easter-sunday-6 3 ef-rogation-monday 4 monica 5 ef-ascension-vigil 6 ef-ascension 7 stanislaus 8 Officium sanctae Mariae in sabbato -9 ef-easter-sunday-7 10 antoninus 11 sts-philip-james 12 sts-nereus-achilleus-domitilla-pancras 13 robert-bellarmine 14 ef-easter-7-friday 15 ef-pentecost-vigil -16 ef-pentecost 17 ef-easter-8-monday 18 ef-easter-8-tuesday 19 ef-pentecost-ember-wed 20 ef-easter-8-thursday 21 ef-pentecost-ember-fri 22 ef-pentecost-ember-sat -23 ef-trinity 24 ef-time-after-pentecost-1-monday 25 gregory-vii 26 philip-neri 27 ef-corpus-christi 28 augustine-of-canterbury 29 mary-magdalene-de-pazzi -30 ef-time-after-pentecost-sunday-2 31 queenship-of-the-blessed-virgin-mary +T{ + +T} T{ + +T} T{ + +T} T{ + +T} T{ + +T} T{ + +T} T{ +\fB1\fP \s-2joseph-the-workman\s+2 +T} +T{ +\fB2\fP \s-2ef-easter-sunday-6\s+2 +T} T{ +\fB3\fP \s-2ef-rogation-monday\s+2 +T} T{ +\fB4\fP \s-2monica\s+2 +T} T{ +\fB5\fP \s-2ef-ascension-vigil\s+2 +T} T{ +\fB6\fP \s-2ef-ascension\s+2 +T} T{ +\fB7\fP \s-2stanislaus\s+2 +T} T{ +\fB8\fP \s-2Officium sanctae Mariae in sabbato\s+2 +T} +T{ +\fB9\fP \s-2ef-easter-sunday-7\s+2 +T} T{ +\fB10\fP \s-2antoninus\s+2 +T} T{ +\fB11\fP \s-2sts-philip-james\s+2 +T} T{ +\fB12\fP \s-2sts-nereus-achilleus-domitilla-pancras\s+2 +T} T{ +\fB13\fP \s-2robert-bellarmine\s+2 +T} T{ +\fB14\fP \s-2ef-easter-7-friday\s+2 +T} T{ +\fB15\fP \s-2ef-pentecost-vigil\s+2 +T} +T{ +\fB16\fP \s-2ef-pentecost\s+2 +T} T{ +\fB17\fP \s-2ef-easter-8-monday\s+2 +T} T{ +\fB18\fP \s-2ef-easter-8-tuesday\s+2 +T} T{ +\fB19\fP \s-2ef-pentecost-ember-wed\s+2 +T} T{ +\fB20\fP \s-2ef-easter-8-thursday\s+2 +T} T{ +\fB21\fP \s-2ef-pentecost-ember-fri\s+2 +T} T{ +\fB22\fP \s-2ef-pentecost-ember-sat\s+2 +T} +T{ +\fB23\fP \s-2ef-trinity\s+2 +T} T{ +\fB24\fP \s-2ef-time-after-pentecost-1-monday\s+2 +T} T{ +\fB25\fP \s-2gregory-vii\s+2 +T} T{ +\fB26\fP \s-2philip-neri\s+2 +T} T{ +\fB27\fP \s-2ef-corpus-christi\s+2 +T} T{ +\fB28\fP \s-2augustine-of-canterbury\s+2 +T} T{ +\fB29\fP \s-2mary-magdalene-de-pazzi\s+2 +T} +T{ +\fB30\fP \s-2ef-time-after-pentecost-sunday-2\s+2 +T} T{ +\fB31\fP \s-2queenship-of-the-blessed-virgin-mary\s+2 +T} T{ + +T} T{ + +T} T{ + +T} T{ + +T} T{ + +T} .TE .SH Iunius .TS allbox; -c c c c c c c -l l l l l l l. +cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) +lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i). Dom Lun Mar Mer Iov Ven Sab - 1 angela-merici 2 ef-time-after-pentecost-2-wednesday 3 ef-time-after-pentecost-2-thursday 4 ef-sacred-heart 5 boniface -6 ef-time-after-pentecost-sunday-3 7 ef-time-after-pentecost-3-monday 8 ef-time-after-pentecost-3-tuesday 9 ef-time-after-pentecost-3-wednesday 10 margaret-of-scotland 11 barnabas 12 john-of-san-fecundo -13 ef-time-after-pentecost-sunday-4 14 basil-the-great 15 ef-time-after-pentecost-4-tuesday 16 ef-time-after-pentecost-4-wednesday 17 gregory-barbarigo 18 ephrem-of-syria 19 julia-of-falconieri -20 ef-time-after-pentecost-sunday-5 21 aloysius-gongzaga 22 paulinus-of-nola 23 vigil-of-the-nativity-of-st-john-the-baptist 24 nativity-of-st-john-the-baptist 25 william 26 sts-john-paul -27 ef-time-after-pentecost-sunday-6 28 vigil-of-sts-peter-paul 29 sts-peter-paul 30 in-commemoratione-sancti-pauli-apostoli +T{ + +T} T{ + +T} T{ +\fB1\fP \s-2angela-merici\s+2 +T} T{ +\fB2\fP \s-2ef-time-after-pentecost-2-wednesday\s+2 +T} T{ +\fB3\fP \s-2ef-time-after-pentecost-2-thursday\s+2 +T} T{ +\fB4\fP \s-2ef-sacred-heart\s+2 +T} T{ +\fB5\fP \s-2boniface\s+2 +T} +T{ +\fB6\fP \s-2ef-time-after-pentecost-sunday-3\s+2 +T} T{ +\fB7\fP \s-2ef-time-after-pentecost-3-monday\s+2 +T} T{ +\fB8\fP \s-2ef-time-after-pentecost-3-tuesday\s+2 +T} T{ +\fB9\fP \s-2ef-time-after-pentecost-3-wednesday\s+2 +T} T{ +\fB10\fP \s-2margaret-of-scotland\s+2 +T} T{ +\fB11\fP \s-2barnabas\s+2 +T} T{ +\fB12\fP \s-2john-of-san-fecundo\s+2 +T} +T{ +\fB13\fP \s-2ef-time-after-pentecost-sunday-4\s+2 +T} T{ +\fB14\fP \s-2basil-the-great\s+2 +T} T{ +\fB15\fP \s-2ef-time-after-pentecost-4-tuesday\s+2 +T} T{ +\fB16\fP \s-2ef-time-after-pentecost-4-wednesday\s+2 +T} T{ +\fB17\fP \s-2gregory-barbarigo\s+2 +T} T{ +\fB18\fP \s-2ephrem-of-syria\s+2 +T} T{ +\fB19\fP \s-2julia-of-falconieri\s+2 +T} +T{ +\fB20\fP \s-2ef-time-after-pentecost-sunday-5\s+2 +T} T{ +\fB21\fP \s-2aloysius-gongzaga\s+2 +T} T{ +\fB22\fP \s-2paulinus-of-nola\s+2 +T} T{ +\fB23\fP \s-2vigil-of-the-nativity-of-st-john-the-baptist\s+2 +T} T{ +\fB24\fP \s-2nativity-of-st-john-the-baptist\s+2 +T} T{ +\fB25\fP \s-2william\s+2 +T} T{ +\fB26\fP \s-2sts-john-paul\s+2 +T} +T{ +\fB27\fP \s-2ef-time-after-pentecost-sunday-6\s+2 +T} T{ +\fB28\fP \s-2vigil-of-sts-peter-paul\s+2 +T} T{ +\fB29\fP \s-2sts-peter-paul\s+2 +T} T{ +\fB30\fP \s-2in-commemoratione-sancti-pauli-apostoli\s+2 +T} T{ + +T} T{ + +T} T{ + +T} .TE .SH Iulius .TS allbox; -c c c c c c c -l l l l l l l. +cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) +lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i). Dom Lun Mar Mer Iov Ven Sab - 1 precious-blood-of-our-lord-jesus-christ 2 visitation-of-the-blessed-virgin-mary 3 irenaeus -4 ef-time-after-pentecost-sunday-7 5 anthony-mary-zaccariah 6 ef-time-after-pentecost-7-tuesday 7 sts-cyril-methodius 8 elizabeth-of-portugal 9 ef-time-after-pentecost-7-friday 10 seven-holy-brothers-and-sts-rufina-secunda -11 ef-time-after-pentecost-sunday-8 12 john-gualbert 13 ef-time-after-pentecost-8-tuesday 14 bonaventure 15 henry-the-emperor 16 ef-time-after-pentecost-8-friday 17 Officium sanctae Mariae in sabbato -18 ef-time-after-pentecost-sunday-9 19 vincent-de-paul 20 jerome-emiliani 21 laurence-of-brindisi 22 mary-magdalene 23 apollinaris 24 Officium sanctae Mariae in sabbato -25 ef-time-after-pentecost-sunday-10 26 anne-mother-of-the-blessed-virgin 27 ef-time-after-pentecost-10-tuesday 28 sts-nazarius-celsus-st-victor-i-st-innocent-i 29 martha 30 ef-time-after-pentecost-10-friday 31 ignatius-loyola +T{ + +T} T{ + +T} T{ + +T} T{ + +T} T{ +\fB1\fP \s-2precious-blood-of-our-lord-jesus-christ\s+2 +T} T{ +\fB2\fP \s-2visitation-of-the-blessed-virgin-mary\s+2 +T} T{ +\fB3\fP \s-2irenaeus\s+2 +T} +T{ +\fB4\fP \s-2ef-time-after-pentecost-sunday-7\s+2 +T} T{ +\fB5\fP \s-2anthony-mary-zaccariah\s+2 +T} T{ +\fB6\fP \s-2ef-time-after-pentecost-7-tuesday\s+2 +T} T{ +\fB7\fP \s-2sts-cyril-methodius\s+2 +T} T{ +\fB8\fP \s-2elizabeth-of-portugal\s+2 +T} T{ +\fB9\fP \s-2ef-time-after-pentecost-7-friday\s+2 +T} T{ +\fB10\fP \s-2seven-holy-brothers-and-sts-rufina-secunda\s+2 +T} +T{ +\fB11\fP \s-2ef-time-after-pentecost-sunday-8\s+2 +T} T{ +\fB12\fP \s-2john-gualbert\s+2 +T} T{ +\fB13\fP \s-2ef-time-after-pentecost-8-tuesday\s+2 +T} T{ +\fB14\fP \s-2bonaventure\s+2 +T} T{ +\fB15\fP \s-2henry-the-emperor\s+2 +T} T{ +\fB16\fP \s-2ef-time-after-pentecost-8-friday\s+2 +T} T{ +\fB17\fP \s-2Officium sanctae Mariae in sabbato\s+2 +T} +T{ +\fB18\fP \s-2ef-time-after-pentecost-sunday-9\s+2 +T} T{ +\fB19\fP \s-2vincent-de-paul\s+2 +T} T{ +\fB20\fP \s-2jerome-emiliani\s+2 +T} T{ +\fB21\fP \s-2laurence-of-brindisi\s+2 +T} T{ +\fB22\fP \s-2mary-magdalene\s+2 +T} T{ +\fB23\fP \s-2apollinaris\s+2 +T} T{ +\fB24\fP \s-2Officium sanctae Mariae in sabbato\s+2 +T} +T{ +\fB25\fP \s-2ef-time-after-pentecost-sunday-10\s+2 +T} T{ +\fB26\fP \s-2anne-mother-of-the-blessed-virgin\s+2 +T} T{ +\fB27\fP \s-2ef-time-after-pentecost-10-tuesday\s+2 +T} T{ +\fB28\fP \s-2sts-nazarius-celsus-st-victor-i-st-innocent-i\s+2 +T} T{ +\fB29\fP \s-2martha\s+2 +T} T{ +\fB30\fP \s-2ef-time-after-pentecost-10-friday\s+2 +T} T{ +\fB31\fP \s-2ignatius-loyola\s+2 +T} .TE .SH Augustus .TS allbox; -c c c c c c c -l l l l l l l. +cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) +lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i). Dom Lun Mar Mer Iov Ven Sab -1 ef-time-after-pentecost-sunday-11 2 alphonsus-liguori 3 ef-time-after-pentecost-11-tuesday 4 dominic 5 dedication-of-the-basilica-of-st-mary-major 6 transfiguration-of-our-lord 7 cajetan -8 ef-time-after-pentecost-sunday-12 9 vigil-of-st-lawrence 10 lawrence 11 ef-time-after-pentecost-12-wednesday 12 clare 13 ef-time-after-pentecost-12-friday 14 vigil-of-the-assumption -15 assumption-of-the-blessed-virgin-mary 16 joachim-father-of-the-blessed-virgin 17 hyacinth 18 ef-time-after-pentecost-13-wednesday 19 john-eudes 20 bernard-of-clairvaux 21 jane-frances-de-chantal -22 ef-time-after-pentecost-sunday-14 23 philip-benizi 24 bartholomew 25 louis-ix 26 ef-time-after-pentecost-14-thursday 27 joseph-calasance 28 augustine -29 ef-time-after-pentecost-sunday-15 30 rose-of-lima 31 raymond-nonnatus +T{ +\fB1\fP \s-2ef-time-after-pentecost-sunday-11\s+2 +T} T{ +\fB2\fP \s-2alphonsus-liguori\s+2 +T} T{ +\fB3\fP \s-2ef-time-after-pentecost-11-tuesday\s+2 +T} T{ +\fB4\fP \s-2dominic\s+2 +T} T{ +\fB5\fP \s-2dedication-of-the-basilica-of-st-mary-major\s+2 +T} T{ +\fB6\fP \s-2transfiguration-of-our-lord\s+2 +T} T{ +\fB7\fP \s-2cajetan\s+2 +T} +T{ +\fB8\fP \s-2ef-time-after-pentecost-sunday-12\s+2 +T} T{ +\fB9\fP \s-2vigil-of-st-lawrence\s+2 +T} T{ +\fB10\fP \s-2lawrence\s+2 +T} T{ +\fB11\fP \s-2ef-time-after-pentecost-12-wednesday\s+2 +T} T{ +\fB12\fP \s-2clare\s+2 +T} T{ +\fB13\fP \s-2ef-time-after-pentecost-12-friday\s+2 +T} T{ +\fB14\fP \s-2vigil-of-the-assumption\s+2 +T} +T{ +\fB15\fP \s-2assumption-of-the-blessed-virgin-mary\s+2 +T} T{ +\fB16\fP \s-2joachim-father-of-the-blessed-virgin\s+2 +T} T{ +\fB17\fP \s-2hyacinth\s+2 +T} T{ +\fB18\fP \s-2ef-time-after-pentecost-13-wednesday\s+2 +T} T{ +\fB19\fP \s-2john-eudes\s+2 +T} T{ +\fB20\fP \s-2bernard-of-clairvaux\s+2 +T} T{ +\fB21\fP \s-2jane-frances-de-chantal\s+2 +T} +T{ +\fB22\fP \s-2ef-time-after-pentecost-sunday-14\s+2 +T} T{ +\fB23\fP \s-2philip-benizi\s+2 +T} T{ +\fB24\fP \s-2bartholomew\s+2 +T} T{ +\fB25\fP \s-2louis-ix\s+2 +T} T{ +\fB26\fP \s-2ef-time-after-pentecost-14-thursday\s+2 +T} T{ +\fB27\fP \s-2joseph-calasance\s+2 +T} T{ +\fB28\fP \s-2augustine\s+2 +T} +T{ +\fB29\fP \s-2ef-time-after-pentecost-sunday-15\s+2 +T} T{ +\fB30\fP \s-2rose-of-lima\s+2 +T} T{ +\fB31\fP \s-2raymond-nonnatus\s+2 +T} T{ + +T} T{ + +T} T{ + +T} T{ + +T} .TE .SH September .TS allbox; -c c c c c c c -l l l l l l l. +cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) +lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i). Dom Lun Mar Mer Iov Ven Sab - 1 ef-time-after-pentecost-15-wednesday 2 stephen-of-hungary 3 pius-x 4 Officium sanctae Mariae in sabbato -5 ef-time-after-pentecost-sunday-16 6 ef-time-after-pentecost-16-monday 7 ef-time-after-pentecost-16-tuesday 8 nativity-of-the-blessed-virgin-mary 9 ef-time-after-pentecost-16-thursday 10 nicholas-of-tolentino 11 Officium sanctae Mariae in sabbato -12 ef-time-after-pentecost-sunday-17 13 ef-time-after-pentecost-17-monday 14 exaltation-of-the-holy-cross 15 seven-sorrows-of-the-blessed-virgin-mary 16 sts-cornelius-cyprian 17 ef-time-after-pentecost-17-friday 18 joseph-of-cupertino -19 ef-time-after-pentecost-sunday-18 20 ef-time-after-pentecost-18-monday 21 matthew 22 ef-september-ember-wed 23 linus 24 ef-september-ember-fri 25 ef-september-ember-sat -26 ef-time-after-pentecost-sunday-19 27 sts-cosmas-damian 28 wenceslaus 29 dedication-of-st-michael-the-archangel 30 jerome +T{ + +T} T{ + +T} T{ + +T} T{ +\fB1\fP \s-2ef-time-after-pentecost-15-wednesday\s+2 +T} T{ +\fB2\fP \s-2stephen-of-hungary\s+2 +T} T{ +\fB3\fP \s-2pius-x\s+2 +T} T{ +\fB4\fP \s-2Officium sanctae Mariae in sabbato\s+2 +T} +T{ +\fB5\fP \s-2ef-time-after-pentecost-sunday-16\s+2 +T} T{ +\fB6\fP \s-2ef-time-after-pentecost-16-monday\s+2 +T} T{ +\fB7\fP \s-2ef-time-after-pentecost-16-tuesday\s+2 +T} T{ +\fB8\fP \s-2nativity-of-the-blessed-virgin-mary\s+2 +T} T{ +\fB9\fP \s-2ef-time-after-pentecost-16-thursday\s+2 +T} T{ +\fB10\fP \s-2nicholas-of-tolentino\s+2 +T} T{ +\fB11\fP \s-2Officium sanctae Mariae in sabbato\s+2 +T} +T{ +\fB12\fP \s-2ef-time-after-pentecost-sunday-17\s+2 +T} T{ +\fB13\fP \s-2ef-time-after-pentecost-17-monday\s+2 +T} T{ +\fB14\fP \s-2exaltation-of-the-holy-cross\s+2 +T} T{ +\fB15\fP \s-2seven-sorrows-of-the-blessed-virgin-mary\s+2 +T} T{ +\fB16\fP \s-2sts-cornelius-cyprian\s+2 +T} T{ +\fB17\fP \s-2ef-time-after-pentecost-17-friday\s+2 +T} T{ +\fB18\fP \s-2joseph-of-cupertino\s+2 +T} +T{ +\fB19\fP \s-2ef-time-after-pentecost-sunday-18\s+2 +T} T{ +\fB20\fP \s-2ef-time-after-pentecost-18-monday\s+2 +T} T{ +\fB21\fP \s-2matthew\s+2 +T} T{ +\fB22\fP \s-2ef-september-ember-wed\s+2 +T} T{ +\fB23\fP \s-2linus\s+2 +T} T{ +\fB24\fP \s-2ef-september-ember-fri\s+2 +T} T{ +\fB25\fP \s-2ef-september-ember-sat\s+2 +T} +T{ +\fB26\fP \s-2ef-time-after-pentecost-sunday-19\s+2 +T} T{ +\fB27\fP \s-2sts-cosmas-damian\s+2 +T} T{ +\fB28\fP \s-2wenceslaus\s+2 +T} T{ +\fB29\fP \s-2dedication-of-st-michael-the-archangel\s+2 +T} T{ +\fB30\fP \s-2jerome\s+2 +T} T{ + +T} T{ + +T} .TE .SH October .TS allbox; -c c c c c c c -l l l l l l l. +cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) +lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i). Dom Lun Mar Mer Iov Ven Sab - 1 ef-time-after-pentecost-19-friday 2 holy-guardian-angels -3 ef-time-after-pentecost-sunday-20 4 francis-of-assisi 5 ef-time-after-pentecost-20-tuesday 6 bruno 7 our-lady-of-the-rosary 8 bridget-of-sweden 9 john-leonardi -10 ef-time-after-pentecost-sunday-21 11 maternity-of-the-blessed-virgin-mary 12 ef-time-after-pentecost-21-tuesday 13 edward 14 callistus-i 15 teresa-of-avila 16 hedwig -17 ef-time-after-pentecost-sunday-22 18 luke-the-evangelist 19 peter-of-alcantara 20 john-cantius 21 ef-time-after-pentecost-22-thursday 22 ef-time-after-pentecost-22-friday 23 anthony-mary-claret -24 ef-time-after-pentecost-sunday-23 25 ef-time-after-pentecost-23-monday 26 ef-time-after-pentecost-23-tuesday 27 ef-time-after-pentecost-23-wednesday 28 sts-simon-jude 29 ef-time-after-pentecost-23-friday 30 Officium sanctae Mariae in sabbato -31 ef-christ-the-king +T{ + +T} T{ + +T} T{ + +T} T{ + +T} T{ + +T} T{ +\fB1\fP \s-2ef-time-after-pentecost-19-friday\s+2 +T} T{ +\fB2\fP \s-2holy-guardian-angels\s+2 +T} +T{ +\fB3\fP \s-2ef-time-after-pentecost-sunday-20\s+2 +T} T{ +\fB4\fP \s-2francis-of-assisi\s+2 +T} T{ +\fB5\fP \s-2ef-time-after-pentecost-20-tuesday\s+2 +T} T{ +\fB6\fP \s-2bruno\s+2 +T} T{ +\fB7\fP \s-2our-lady-of-the-rosary\s+2 +T} T{ +\fB8\fP \s-2bridget-of-sweden\s+2 +T} T{ +\fB9\fP \s-2john-leonardi\s+2 +T} +T{ +\fB10\fP \s-2ef-time-after-pentecost-sunday-21\s+2 +T} T{ +\fB11\fP \s-2maternity-of-the-blessed-virgin-mary\s+2 +T} T{ +\fB12\fP \s-2ef-time-after-pentecost-21-tuesday\s+2 +T} T{ +\fB13\fP \s-2edward\s+2 +T} T{ +\fB14\fP \s-2callistus-i\s+2 +T} T{ +\fB15\fP \s-2teresa-of-avila\s+2 +T} T{ +\fB16\fP \s-2hedwig\s+2 +T} +T{ +\fB17\fP \s-2ef-time-after-pentecost-sunday-22\s+2 +T} T{ +\fB18\fP \s-2luke-the-evangelist\s+2 +T} T{ +\fB19\fP \s-2peter-of-alcantara\s+2 +T} T{ +\fB20\fP \s-2john-cantius\s+2 +T} T{ +\fB21\fP \s-2ef-time-after-pentecost-22-thursday\s+2 +T} T{ +\fB22\fP \s-2ef-time-after-pentecost-22-friday\s+2 +T} T{ +\fB23\fP \s-2anthony-mary-claret\s+2 +T} +T{ +\fB24\fP \s-2ef-time-after-pentecost-sunday-23\s+2 +T} T{ +\fB25\fP \s-2ef-time-after-pentecost-23-monday\s+2 +T} T{ +\fB26\fP \s-2ef-time-after-pentecost-23-tuesday\s+2 +T} T{ +\fB27\fP \s-2ef-time-after-pentecost-23-wednesday\s+2 +T} T{ +\fB28\fP \s-2sts-simon-jude\s+2 +T} T{ +\fB29\fP \s-2ef-time-after-pentecost-23-friday\s+2 +T} T{ +\fB30\fP \s-2Officium sanctae Mariae in sabbato\s+2 +T} +T{ +\fB31\fP \s-2ef-christ-the-king\s+2 +T} T{ + +T} T{ + +T} T{ + +T} T{ + +T} T{ + +T} T{ + +T} .TE .SH November .TS allbox; -c c c c c c c -l l l l l l l. +cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) +lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i). Dom Lun Mar Mer Iov Ven Sab - 1 all-saints 2 commemoration-of-all-souls 3 ef-time-after-pentecost-24-wednesday 4 charles-borromeo 5 ef-time-after-pentecost-24-friday 6 Officium sanctae Mariae in sabbato -7 ef-time-after-epiphany-sunday-5 8 ef-time-after-pentecost-25-monday 9 dedication-of-the-archbasilica-of-our-holy-savior 10 andrew-avellino 11 martin-of-tours 12 martin-i 13 didacus -14 ef-time-after-epiphany-sunday-6 15 albert-the-great 16 gertrude-the-great 17 gregory-the-wonderworker 18 dedication-of-the-basilicas-of-sts-peter-paul 19 elizabeth-of-hungary 20 felix-of-valois -21 ef-time-after-pentecost-sunday-24 22 cecilia 23 clement-i 24 john-of-the-cross 25 catherine-of-alexandria 26 sylvester 27 Officium sanctae Mariae in sabbato -28 ef-advent-sunday-1 29 ef-advent-1-monday 30 andrew +T{ + +T} T{ +\fB1\fP \s-2all-saints\s+2 +T} T{ +\fB2\fP \s-2commemoration-of-all-souls\s+2 +T} T{ +\fB3\fP \s-2ef-time-after-pentecost-24-wednesday\s+2 +T} T{ +\fB4\fP \s-2charles-borromeo\s+2 +T} T{ +\fB5\fP \s-2ef-time-after-pentecost-24-friday\s+2 +T} T{ +\fB6\fP \s-2Officium sanctae Mariae in sabbato\s+2 +T} +T{ +\fB7\fP \s-2ef-time-after-epiphany-sunday-5\s+2 +T} T{ +\fB8\fP \s-2ef-time-after-pentecost-25-monday\s+2 +T} T{ +\fB9\fP \s-2dedication-of-the-archbasilica-of-our-holy-savior\s+2 +T} T{ +\fB10\fP \s-2andrew-avellino\s+2 +T} T{ +\fB11\fP \s-2martin-of-tours\s+2 +T} T{ +\fB12\fP \s-2martin-i\s+2 +T} T{ +\fB13\fP \s-2didacus\s+2 +T} +T{ +\fB14\fP \s-2ef-time-after-epiphany-sunday-6\s+2 +T} T{ +\fB15\fP \s-2albert-the-great\s+2 +T} T{ +\fB16\fP \s-2gertrude-the-great\s+2 +T} T{ +\fB17\fP \s-2gregory-the-wonderworker\s+2 +T} T{ +\fB18\fP \s-2dedication-of-the-basilicas-of-sts-peter-paul\s+2 +T} T{ +\fB19\fP \s-2elizabeth-of-hungary\s+2 +T} T{ +\fB20\fP \s-2felix-of-valois\s+2 +T} +T{ +\fB21\fP \s-2ef-time-after-pentecost-sunday-24\s+2 +T} T{ +\fB22\fP \s-2cecilia\s+2 +T} T{ +\fB23\fP \s-2clement-i\s+2 +T} T{ +\fB24\fP \s-2john-of-the-cross\s+2 +T} T{ +\fB25\fP \s-2catherine-of-alexandria\s+2 +T} T{ +\fB26\fP \s-2sylvester\s+2 +T} T{ +\fB27\fP \s-2Officium sanctae Mariae in sabbato\s+2 +T} +T{ +\fB28\fP \s-2ef-advent-sunday-1\s+2 +T} T{ +\fB29\fP \s-2ef-advent-1-monday\s+2 +T} T{ +\fB30\fP \s-2andrew\s+2 +T} T{ + +T} T{ + +T} T{ + +T} T{ + +T} .TE .SH December .TS allbox; -c c c c c c c -l l l l l l l. +cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) cw(1.3i) +lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i) lw(1.3i). Dom Lun Mar Mer Iov Ven Sab - 1 ef-advent-1-wednesday 2 vivian 3 francis-xavier 4 peter-chrysologus -5 ef-advent-sunday-2 6 nicholas 7 ambrose 8 immaculate-conception-of-the-blessed-virgin-mary 9 ef-advent-2-thursday 10 ef-advent-2-friday 11 damasus-i -12 ef-advent-sunday-3 13 lucy 14 ef-advent-3-tuesday 15 ef-advent-ember-wed 16 eusebius 17 ef-advent-ember-fri 18 ef-advent-ember-sat -19 ef-advent-sunday-4 20 ef-advent-4-monday 21 thomas 22 ef-advent-4-wednesday 23 ef-advent-4-thursday 24 ef-nativity-vigil 25 ef-nativity -26 ef-christmas-sunday-0 27 john-the-evangelist 28 holy-innocents 29 ef-nativity-octave-day-5 30 ef-nativity-octave-day-6 31 ef-nativity-octave-day-7 +T{ + +T} T{ + +T} T{ + +T} T{ +\fB1\fP \s-2ef-advent-1-wednesday\s+2 +T} T{ +\fB2\fP \s-2vivian\s+2 +T} T{ +\fB3\fP \s-2francis-xavier\s+2 +T} T{ +\fB4\fP \s-2peter-chrysologus\s+2 +T} +T{ +\fB5\fP \s-2ef-advent-sunday-2\s+2 +T} T{ +\fB6\fP \s-2nicholas\s+2 +T} T{ +\fB7\fP \s-2ambrose\s+2 +T} T{ +\fB8\fP \s-2immaculate-conception-of-the-blessed-virgin-mary\s+2 +T} T{ +\fB9\fP \s-2ef-advent-2-thursday\s+2 +T} T{ +\fB10\fP \s-2ef-advent-2-friday\s+2 +T} T{ +\fB11\fP \s-2damasus-i\s+2 +T} +T{ +\fB12\fP \s-2ef-advent-sunday-3\s+2 +T} T{ +\fB13\fP \s-2lucy\s+2 +T} T{ +\fB14\fP \s-2ef-advent-3-tuesday\s+2 +T} T{ +\fB15\fP \s-2ef-advent-ember-wed\s+2 +T} T{ +\fB16\fP \s-2eusebius\s+2 +T} T{ +\fB17\fP \s-2ef-advent-ember-fri\s+2 +T} T{ +\fB18\fP \s-2ef-advent-ember-sat\s+2 +T} +T{ +\fB19\fP \s-2ef-advent-sunday-4\s+2 +T} T{ +\fB20\fP \s-2ef-advent-4-monday\s+2 +T} T{ +\fB21\fP \s-2thomas\s+2 +T} T{ +\fB22\fP \s-2ef-advent-4-wednesday\s+2 +T} T{ +\fB23\fP \s-2ef-advent-4-thursday\s+2 +T} T{ +\fB24\fP \s-2ef-nativity-vigil\s+2 +T} T{ +\fB25\fP \s-2ef-nativity\s+2 +T} +T{ +\fB26\fP \s-2ef-christmas-sunday-0\s+2 +T} T{ +\fB27\fP \s-2john-the-evangelist\s+2 +T} T{ +\fB28\fP \s-2holy-innocents\s+2 +T} T{ +\fB29\fP \s-2ef-nativity-octave-day-5\s+2 +T} T{ +\fB30\fP \s-2ef-nativity-octave-day-6\s+2 +T} T{ +\fB31\fP \s-2ef-nativity-octave-day-7\s+2 +T} T{ + +T} .TE -- cgit v1.3