--- /dev/null
+/build
+/public
--- /dev/null
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
--- /dev/null
+SHELL = /bin/sh
+
+# ━ § BASIC INFORMATION ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+override define makefileinfo
+ ╭────────────────────────────╮
+╔╡ ⁌ ⛩️📰 书社 ∷ GNUmakefile ╞════════════════════════════════╗
+║╰────────────────────────────╯ ║
+╟┬ ¶ Prerequisites ───────────────────────────────────────────┬╢
+║│ │║
+║│ Requires G·N·U Make, at least version 3.81, a version of │║
+║│ uuencode with base64 support, and the various programs │║
+║│ offered by libxml2 and libxslt. Beyond this, only programs │║
+║│ required by Posix are used, altho there is a chance of │║
+║│ version incompatibilities. The full list of program │║
+║│ requirements is as follows :— │║
+║│ │║
+║│ • cat │║
+║│ • cp │║
+║│ • echo │║
+║│ • file │║
+║│ • find │║
+║│ • mkdir (requires support for `-p´) │║
+║│ • mv │║
+║│ • printf │║
+║│ • sed │║
+║│ • test │║
+║│ • touch │║
+║│ • tr (requires support for `-d´) │║
+║│ • uuencode (requires support for `-m´ and `-r´) │║
+║│ • xmlcatalog (provided by libxml2) │║
+║│ • xmllint (provided by libxml2) │║
+║│ • xsltproc (provided by libxslt) │║
+║│ │║
+║│ In all cases, you can supply your own version of any │║
+║│ program `program´ by overriding the corresponding variable │║
+║│ `PROGRAM´ when calling Make. │║
+║╰────────────────────────────────────────────────────────────╯║
+╟┬ ¶ Usage ───────────────────────────────────────────────────┬╢
+║│ │║
+║│ • `make all´: Compile, but do not install, all files. │║
+║│ │║
+║│ • `make clean´: Remove `BUILDDIR´. │║
+║│ │║
+║│ • `make gone´: Remove installed files. │║
+║│ │║
+║│ • `make help´ (default): Print this message. │║
+║│ │║
+║│ • `make install´: Compile all files and install in │║
+║│ `DESTDIR´. │║
+║│ │║
+║│ • `make list´: List all recognized source files and their │║
+║│ classification (including media type and dependencies). │║
+║│ │║
+║│ Set `VERBOSE=1´ to see the text of commands as they are │║
+║│ executed. │║
+║│ │║
+║│ See `README.markdown´ for a more involved description of │║
+║│ the capabilities and configuration of this program. │║
+║╰────────────────────────────────────────────────────────────╯║
+╟┬ ¶ License ─────────────────────────────────────────────────┬╢
+║│ This Source Code Form is subject to the terms of the │║
+║│ Mozilla Public License, v 2.0. If a copy of the M·P·L was │║
+║│ not distributed with this file, You can obtain one at │║
+║│ <http://mozilla.org/MPL/2.0/>. │║
+║╰────────────────────────────────────────────────────────────╯║
+╚══════════════════════════════════════════════════════════════╝
+endef
+
+# ━ § MAKE·FILE SETUP ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+# Programs needed to run this make·file.
+#
+# If these are not installed on your computer, or you need to use a
+# different implementation, you can override the appropriate variable.
+CAT := cat
+CP := cp
+ECHO := echo
+FILE := file
+FIND := find
+MKDIR := mkdir
+MV := mv
+PRINTF := printf
+RM := rm
+SED := sed
+TEST := test
+TOUCH := touch
+TR := tr
+UUENCODE := uuencode
+XMLCATALOG := xmlcatalog
+XMLLINT := xmllint
+XSLTPROC := xsltproc
+
+# The directory which contains the source files.
+SRCDIR := sources
+
+# The directory which contains “includes”: Files which may be included
+# in other files but for which no final output will be generated.
+#
+# This can be inside of `SOURCES_DIRECTORY´ if desired.
+INCLUDEDIR := sources/includes
+
+# The directory in which to generate temporary buildfiles.
+BUILDDIR := build
+
+# The directory into which to output files on `make install´.
+DESTDIR := public
+
+# The location of this Makefile (and related ⛩️📰 书社 files),
+# relative to the current working directory.
+#
+# By default, this is inferred from the variable `MAKEFILE_LIST´.
+THISDIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
+
+# The location of the magic files to use when determining media types.
+#
+# One is provided as part of this repository, but you can override it
+# if you need different media type detection.
+#
+# Your computer probably has a more comprehensive one installed at
+# `/usr/share/file/magic´, but it is not recommended that you use this
+# directly. Instead, link or copy just the files you expect to need for
+# your project.
+MAGICDIR := $(patsubst ./%,%,$(THISDIR)/magic)
+
+# Configuration of `find´.
+#
+# By default, `find´ will follow symlinks and use extended regular
+# expressions, ignoring hidden files and those which begin with a
+# period.
+FINDOPTS := -LE
+FINDRULES := -flags -nohidden -and -not -name '.*'
+
+# The list of parsers for plaintext file types.
+#
+# Which parsers are provided will influence which kinds of files are
+# recognized as plaintext.
+#
+# Each parser ⁜must⁜ have a template which matches ⁜only⁜ X·H·T·M·L
+# `<script>´ elements that have a `@type´ of a plaintext type supported
+# by the parser. They may have multiple.
+PARSERS := $(patsubst ./%,%,$(wildcard $(THISDIR)/parsers/*.xslt))
+
+# The list of transforms.
+TRANSFORMS := $(patsubst ./%,%,$(wildcard $(THISDIR)/transforms/*.xslt))
+
+# List of types which should be treated as X·M·L.
+XMLTYPES := application/xml text/xml
+
+# Set to a non·empty value to print all commands as they run.
+VERBOSE :=
+
+# The default target for this makefile.
+#
+# Print help and exit.
+.DEFAULT_GOAL := help
+
+# ━ § BEGIN MAKE·FILE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+# ─ ¶ Non‐Recipe Variable Definitions ─────────────────────────────────
+
+# A variable with no value, usable when assigning values which contain
+# whitespace.
+override empty :=
+
+# A variable which contains a newline, to allow the generation of
+# multiline strings in function calls.
+override define newline
+
+
+endef
+
+# A variable which contains a single space.
+override space := $(empty) $(empty)
+
+# A variable which contains a single comma.
+override comma := ,
+
+# (callable) Quote the given string for use within shell calls.
+override quote = '$(subst ','"'"',$1)'
+
+# Outputs an `@´ to silence rules, unless `VERBOSE´ is nonempty.
+override silent := $(if $(VERBOSE),,@)
+
+# (callable) Escape special characters for use in sed regular
+# expressions.
+override sedesc = $(subst $$,\$$,$(subst *,\*,$(subst .,\.,$(subst [,\[,$(subst ^,\^,$(subst \,\\,$1))))))
+
+# Collect all of the applicable includes from the includes directory.
+sourceincludes := $(shell $(FIND) $(FINDOPTS) $(INCLUDEDIR) -type f '(' $(FINDRULES) ')')
+
+# Collect all of the applicable source files from the source directory,
+# removing any which are also includes.
+sourcefiles := $(filter-out $(sourceincludes),$(shell $(FIND) $(FINDOPTS) $(SRCDIR) -type f '(' $(FINDRULES) ')'))
+
+# Figure out the file type of each source file and source include.
+ifneq ($(wildcard $(BUILDDIR)/magic.mgc),)
+override types := $(shell $(SED) 's/^ *//;s/ *$$//;s/ {2,}/ /g' <<< $(call quote,$(sourcefiles) $(sourceincludes)) | $(TR) ' ' '\n' | $(FILE) -m $(call quote,$(BUILDDIR)/magic.mgc) --mime-type --separator '`' --files-from - | $(SED) 's/` */?type=/g')
+endif
+
+# Get the list of supported plaintext file types from the parser.
+ifneq ($(wildcard $(BUILDDIR)/parser.xslt),)
+override plaintexttypes := $(shell $(XSLTPROC) $(call quote,$(THISDIR)/lib/parser2types.xslt) $(call quote,$(BUILDDIR)/parser.xslt))
+endif
+
+# Simplify the file type by only taking the first component (image,
+# text, ⁊·c).
+override simpletypes := $(shell $(TR) ' ' '\n' <<< $(call quote,$(types)) | $(SED) 's`/[^/]*$$``g')
+
+# (callable) Get all of the files (source and includes) which have the
+# given types.
+override filesoftype = $(foreach type,$1,$(patsubst %?type=$(type),%,$(filter %?type=$(type),$(types))))
+
+# Build up collections of various file types.
+override plaintextfiles := $(call filesoftype,$(plaintexttypes))
+override xmlfiles := $(filter-out $(plaintextfiles),$(call filesoftype,$(XMLTYPES)))
+override assetfiles := $(filter-out $(xmlfiles) $(plaintextfiles),$(sourcefiles) $(sourceincludes))
+
+# (callable) Get the types of the given files.
+override typeoffile = $(patsubst $(foreach file,$1,$(file)?type=%),%,$(filter $(foreach file,$1,$(file)?type=%),$(types)))
+
+# (callable) Get base64 data u·r·i’s for the given files.
+override datauri = $(foreach file,$1,data:$(call typeoffile,$(file));base64,$(shell $(UUENCODE) -m -r $(call quote,$(file)) _ | tr -d ' \n'))
+
+# (callable) Get local leiris for the given files.
+override localuri = $(foreach file,$1,$(if $(filter $(file),$(sourceincludes)),$(patsubst $(INCLUDEDIR)/%,about:shushe?include=%,$(file)),$(patsubst $(SRCDIR)/%,about:shushe?source=%,$(file))))
+
+# (callable) Get the source files for the given local leiris.
+override sourcefile = $(foreach file,$1,$(if $(filter about:shushe?include=%,$(file)),$(patsubst about:shushe?include=%,$(INCLUDEDIR)/%,$(file)),$(patsubst about:shushe?source=%,$(SRCDIR)/%,$(file))))
+
+# Adds a requirement on `$(BUILDDIR)/.update-types´ if the file is
+# present.
+#
+# This file is created after a reload due to type changes, and is
+# removed after. Requiring it ensures that file classifications are
+# up‐to‐date immediately after the reload.
+override typeupdates := $(if $(wildcard $(BUILDDIR)/.update-types),$(BUILDDIR)/.update-types,)
+
+# (callable) Get the location of the transformed X·M·L files for the
+# given source files.
+override parsed = $(foreach file,$1,$(if $(filter $(file),$(sourceincludes)),$(patsubst $(INCLUDEDIR)/%,$(BUILDDIR)/includes/%,$(file)),$(patsubst $(SRCDIR)/%,$(BUILDDIR)/sources/%,$(file))))
+
+ifneq ($(wildcard $(BUILDDIR)/dependencies),)
+# Pair each file with a list of dependencies for it.
+override dependenciesforfile := $(foreach file,$(sourcefiles),$(file)`$(subst $(space),`,$(shell $(CAT) $(call quote,$(BUILDDIR)/dependencies) | $(SED) $(call quote,/^$(call sedesc,$(call localuri,$(file)))$$/$(comma)/^[^ ]/!d;/^ /!d;s/^ //))))
+
+# (callable) Get the list of dependency leiris for the given source
+# files.
+#
+# Recursive dependencies are marked with a leading `!´.
+override dependencyuris = $(foreach file,$1,$(subst `, ,$(patsubst $(file)`%,%,$(filter $(file)`%,$(dependenciesforfile)))))
+
+# (callable) Get the list of recursive dependencies for the given
+# source files.
+override recursives = $(foreach uri,$(filter !%,$(call dependencyuris,$1)),$(call sourcefile,$(patsubst !%,%,$(uri))))
+
+# (callable) Get the list of (nonrecursive) dependencies for the given
+# source files.
+override dependencies = $(foreach uri,$(filter-out !%,$(call dependencyuris,$1)),$(call sourcefile,$(uri)))
+endif
+
+# Collect all files with recursive dependencies.
+override recursivefiles := $(foreach file,$(filter-out $(assetfiles),$(sourcefiles)),$(if $(call recursives,$(file)),$(file),))
+
+# Collect all files which should be compiled.
+#
+# This is all of the non·asset, nonrecursive files.
+override compilablefiles := $(filter-out $(assetfiles) $(recursivefiles),$(sourcefiles))
+
+# (callable) Get the compiled locations for the given source files.
+override compiled = $(patsubst $(SRCDIR)/%,$(BUILDDIR)/public/%,$(1))
+
+# (callable) Get the installed locations for the given source files.
+override installed = $(patsubst $(SRCDIR)/%,$(DESTDIR)/%,$(1))
+
+# ─ ¶ Recipe Variable Definitions ─────────────────────────────────────
+
+# (callable) Check to see if the given directory exists and
+# create it if not.
+override ensuredirectory = if $(TEST) ! -d $(call quote,$1); then $(MKDIR) -p $(call quote,$1); fi
+
+# (callable) Sanitize and wrap the provided plaintext file in
+# X·M·L, printing to `stdout´.
+override wrapplaintext = $(PRINTF) '%s\n' "$$($(PRINTF) '%b' '<?xml version=\042\061.0\042?>\n<script xmlns=\042http://www.w3.org/1999/xhtml\042 type=\042$(patsubst $1?type=%,%,$(filter $1?type=%,$(types)))\042><![CDATA['; $(CAT) $(call quote,$1) | $(TR) '\000\013\014' '\032\011\012' | $(SED) $$($(PRINTF) '%s%b' 's/]]>/]]]]><!\[CDATA\[>/g;s/\xEF\xBF\xBE/�/g;s/\xEF\xBF\xBF/�/g;$$!s/\r$$//g;s/\r/\n/g;$$!s/\xC2\x85$$//g;s/\xC2\x85/\n/g;s/\xE2\x80\xA8/\n/g;' 's/[\0001-\0010]/�/g;s/[\0016-\0037]/�/g'); $(PRINTF) '%s' ']]></script>')"
+
+# ─ ¶ Phony Targets ───────────────────────────────────────────────────
+
+# Provide help.
+help:
+ $(silent)$(PRINTF) '%b' '$(subst $(newline),\n,$(makefileinfo))'
+
+# Compile all files, or error if any are recursive.
+all: $(call compiled,$(recursivefiles) $(compilablefiles) $(assetfiles)) ;
+
+# Destroy buildfiles.
+clean:
+ $(silent)$(RM) -rf $(BUILDDIR)/
+
+# Destroy buildfiles and the install directory.
+gone:
+ $(silent)$(RM) -rf $(BUILDDIR)/ $(call compiled,$(recursivefiles) $(compilablefiles))
+
+# Install the compiled files into `DESTDIR´.
+install: $(call installed,$(recursivefiles) $(compilablefiles) $(assetfiles)) ;
+
+# List all source files and includes and their computed types.
+list:
+ $(silent)$(PRINTF) '%b' $(call quote,$(foreach file,$(sort $(sourcefiles)) $(sort $(sourceincludes)),\0033[1m$(file)\0033[22m`$(call typeoffile,$(file))`[\0033[3m$(if $(filter $(file),$(xmlfiles)),xml,$(if $(filter $(file),$(plaintextfiles)),text,asset))$(if $(filter $(file),$(sourceincludes)), include,)\0033[23m]$(if $(call dependencies,$(file))$(call recursives,$(file)), $(strip $(foreach recursive,$(call recursives,$(file)),\0033[93;41m•`Recursive`Dependency:\0033[39;49m`$(recursive)) $(foreach dependency,$(call dependencies,$(file)),\0033[2m•`Dependency:\0033[22m`$(dependency)))) )) | $(TR) ' `' '\n '
+
+# Raise an error when attempting to build any files with recursive
+# dependencies.
+$(call compiled,$(recursivefiles)): $(BUILDDIR)/public/%:
+ @$(PRINTF) '%b\n' $(call quote,\0033[93;41mError:\0033[39;49m `$*´ has recursive dependencies:\n$(subst `, ,$(subst $(space),$(newline),$(foreach recursive,$(call recursives,$(SRCDIR)/$*),•`$(patsubst $(SRCDIR)/%,%,$(recursive)))))) && false
+
+# ─ ¶ Special Targets ─────────────────────────────────────────────────
+
+# Perform secondary expansion; this enables pattern rules to determine
+# their prerequisites based on the matched pattern.
+.SECONDEXPANSION: ;
+
+# Don’t use any implicit rules.
+.SUFFIXES: ;
+
+# Phony rules; always consider these out‐of‐date.
+.PHONY: all default clean gone info install list $(call compiled,$(recursivefiles));
+
+# Reload this make·file if any of the magic files or parsers have
+# changed.
+#
+# These are used to classify source files, so if they have changed then
+# the make·file must be reloaded.
+$(THISDIR)/GNUmakefile:: $(BUILDDIR)/magic.mgc $(BUILDDIR)/parser.xslt $(THISDIR)/lib/parser2types.xslt
+ $(silent)$(TOUCH) $(THISDIR)/GNUmakefile
+ $(silent)$(TOUCH) $(call quote,$(BUILDDIR)/.update-types)
+ $(silent)$(RM) -f $(call quote,$(BUILDDIR)/dependencies)
+ @$(PRINTF) '%b\n' '\0033[1mMagic file or parsers have updated. Restarting…\0033[22m'
+
+ifneq ($(wildcard $(BUILDDIR)/.update-types)$(wildcard $(BUILDDIR)/dependencies),)
+# Reload this make·file if the dependency graph has changed.
+#
+# This graph is a dependency for some of the variables that this
+# make·file uses, so it’s important to ensure that they are actually
+# up‐to‐date prior to executing any later rules.
+#
+# This recipe only exists after types have been updated or when the
+# dependency graph already exists.
+$(THISDIR)/GNUmakefile:: $(BUILDDIR)/dependencies
+ $(silent)$(TOUCH) $(THISDIR)/GNUmakefile
+ $(silent)$(RM) -f $(BUILDDIR)/.update-types
+ @$(PRINTF) '%b\n' '\0033[1mDependency graph updated. Restarting…\0033[22m'
+endif
+
+# ─ ¶ Build Targets ───────────────────────────────────────────────────
+
+# Generate the compiled magic file from its sources.
+#
+# It must be updated if any of the files in the magic directory change.
+# It ⁜also⁜ should be updated if any of the files in the magic
+# directory are deleted, but this isn’t tracked presently.
+$(BUILDDIR)/magic.mgc: $(wildcard $(MAGICDIR)/*)
+ @$(ECHO) "Compiling new magic…"
+ $(silent)$(call ensuredirectory,$(dir $@))
+ $(silent)$(FILE) -C -m $(call quote,$(MAGICDIR))
+ $(silent)$(MV) $(call quote,$(MAGICDIR).mgc) $(call quote,$(BUILDDIR)/magic.mgc)
+
+# Generate the main parser.
+$(BUILDDIR)/parser.catalog: $(PARSERS)
+ @$(ECHO) "Generating catalog of parsers…"
+ $(silent)$(XMLCATALOG) --create --noout $(call quote,$@)
+ $(foreach parser,$(PARSERS),$(silent)$(XMLCATALOG) --add uri $(call quote,$(basename $(notdir $(parser)))) $(call quote,../$(parser)) --noout $(call quote,$@)$(newline))
+$(BUILDDIR)/parser.xslt: $(BUILDDIR)/parser.catalog $(THISDIR)/lib/catalog2parser.xslt
+ @$(ECHO) "Generating main parser…"
+ $(silent)$(XSLTPROC) -o $(call quote,$@) $(call quote,$(THISDIR)/lib/catalog2parser.xslt) $(call quote,$<)
+
+# Note updates to parsers or magic.
+#
+# This file is actually generated as part of the make·file restart
+# process, so it doesn’t need any recipes.
+$(BUILDDIR)/.update-types: $(BUILDDIR)/magic.mgc $(BUILDDIR)/parser.xslt $(THISDIR)/lib/parser2types.xslt ;
+
+# Parse the files.
+#
+# Even plain X·M·L files are parsed, because they may contain X·H·T·M·L
+# `<script>´ elements which contain other kinds of data. Asset files
+# are turned into H·T·M·L embeds pointing to `data:´ U·R·I’s.
+$(call parsed,$(sourceincludes)): $(BUILDDIR)/includes/%: $(INCLUDEDIR)/% $(typeupdates)
+ @$(PRINTF) '%s\n' $(call quote,Processing `$<´…)
+ $(silent)$(call ensuredirectory,$(dir $@))
+ $(silent)$(if $(filter $<,$(assetfiles)),$(PRINTF) '%s\n' $(call quote,<object xmlns="http://www.w3.org/1999/xhtml" type="$(call typeoffile,$(INCLUDEDIR)/$*)" data="$(call datauri,$<)"/>) > $(call quote,$@),$(if $(filter $<,$(plaintextfiles)),$(call wrapplaintext,$<),$(CAT) $(call quote,$<)) | $(XSLTPROC) -o $(call quote,$@) $(call quote,$(BUILDDIR)/parser.xslt) -)
+$(call parsed,$(sourcefiles)): $(BUILDDIR)/sources/%: $(SRCDIR)/% $(typeupdates)
+ @$(PRINTF) '%s\n' $(call quote,Processing `$<´…)
+ $(silent)$(call ensuredirectory,$(dir $@))
+ $(silent)$(if $(filter $<,$(assetfiles)),$(PRINTF) '%s\n' $(call quote,<object xmlns="http://www.w3.org/1999/xhtml" type="$(call typeoffile,$(SRCDIR)/$*)" data="$(call datauri,$<)"/>) > $(call quote,$@),$(if $(filter $<,$(plaintextfiles)),$(call wrapplaintext,$<),$(CAT) $(call quote,$<)) | $(XSLTPROC) -o $(call quote,$@) $(call quote,$(BUILDDIR)/parser.xslt) -)
+
+# Generate a catalog of all transformed files, for use when processing
+# includes. This does not depend on actually transforming the files.
+$(BUILDDIR)/catalog: $(sourcefiles) $(sourceincludes) $(typeupdates)
+ @$(ECHO) "Generating catalog of parsed files…"
+ $(silent)$(XMLCATALOG) --create --noout $(call quote,$@)
+ $(foreach source,$(sourcefiles) $(sourceincludes),$(silent)$(XMLCATALOG) --add uri $(call quote,$(call localuri,$(source))) $(call quote,$(patsubst $(BUILDDIR)/%,%,$(call parsed,$(source)))#$(if $(filter $(source),$(assetfiles)),asset,xml)) --noout $(call quote,$@)$(newline))
+
+# Build a list of dependencies for each transformed file.
+#
+# This recipe also adjusts backwards the modification time of this
+# make·file by one second, to ensure that it is always more outdated
+# than the built dependencies (triggering a restart).
+$(BUILDDIR)/dependencies: $(BUILDDIR)/catalog $(call parsed,$(plaintextfiles) $(xmlfiles)) $(THISDIR)/lib/catalog2dependencies.xslt
+ @$(ECHO) "Identifying dependencies…"
+ $(silent)$(XSLTPROC) -o $(call quote,$@) $(call quote,$(THISDIR)/lib/catalog2dependencies.xslt) $(call quote,$<)
+ $(silent)$(TOUCH) -A -000001 -am $(THISDIR)/GNUmakefile
+
+# Generate the main transform.
+$(BUILDDIR)/transform.catalog: $(TRANSFORMS)
+ @$(ECHO) "Generating catalog of transforms…"
+ $(silent)$(XMLCATALOG) --create --noout $(call quote,$@)
+ $(foreach transform,$(TRANSFORMS),$(silent)$(XMLCATALOG) --add uri $(call quote,$(basename $(notdir $(transform)))) $(call quote,../$(transform)) --noout $(call quote,$@)$(newline))
+$(BUILDDIR)/transform.xslt: $(BUILDDIR)/transform.catalog $(THISDIR)/lib/catalog2transform.xslt
+ @$(ECHO) "Generating main transform…"
+ $(silent)$(XSLTPROC) -o $(call quote,$@) $(call quote,$(THISDIR)/lib/catalog2transform.xslt) $(call quote,$<)
+
+# Generate the output files using the dependencies as necessary.
+$(call compiled,$(compilablefiles)): $(BUILDDIR)/public/%: $$(call parsed,$(SRCDIR)/%) $(BUILDDIR)/transform.xslt $$(call parsed,$$(call dependencies,$(SRCDIR)/%))
+ $(silent)$(call ensuredirectory,$(dir $@))
+ @$(PRINTF) '%s\n' $(call quote,Compiling `$*´…)
+ $(silent)$(XSLTPROC) -o $(call quote,$@) --stringparam catalog 'catalog' $(call quote,$(BUILDDIR)/transform.xslt) $(call quote,$<)
+$(call compiled,$(filter $(assetfiles),$(sourcefiles))): $(BUILDDIR)/public/%: $(SRCDIR)/%
+ @$(PRINTF) '%s\n' $(call quote,Compiling `$*´…)
+ $(silent)$(call ensuredirectory,$(dir $@))
+ $(silent)$(CP) $(call quote,$<) $(call quote,$@)
+
+# Install compiled files (or error in the case of recursive ones).
+$(call installed,$(filter $(assetfiles),$(sourcefiles)) $(recursivefiles) $(compilablefiles)): $(DESTDIR)/%: $(BUILDDIR)/public/%
+ @$(PRINTF) '%s\n' $(call quote,Installing `$*´…)
+ $(silent)$(call ensuredirectory,$(dir $@))
+ $(silent)$(CP) $(call quote,$<) $(call quote,$@)
--- /dev/null
+# ⛩️📰 书社
+
+<b>An X·S·L·T‐based static site generator.</b>
+
+<dfn>⛩️📰 书社</dfn> aims to make it easy to generate websites with
+ X·S·L·T and G·N·U Make.
+It is consequently only a good choice for people who like X·S·L·T and
+ G·N·U Make and wish it were easier to make websites with them.
+
+It makes things easier by :—
+
+- Automatically identifying source files and characterizing them by
+ type (X·M·L, text, or asset).
+
+- Parsing supported text types into X·M·L trees.
+
+- Enabling easy inclusion of source files within each other.
+
+It aims to do this with zero dependencies beyond the programs already
+ installed on your computer.
+
+## Nomenclature
+
+<i lang="cmn-Hans">书社</i> is a Chinese word meaning “publishing
+ house”.
+
+The first character, <i lang="cmn-Hans">书</i>, is the simplified form
+ of “document”.
+
+The second character, <i lang="cmn-Hans">社</i>, contemporarily means
+ “association”, but historically referred to the god of the soil and
+ related altars or festivities.
+In Japanese, it is an alternate spelling for <i lang="ja">やしろ</i>,
+ the word for “Shinto shrine”.
+
+The name <i lang="cmn-Hans">书社</i> was chosen to play on this pun, as
+ it is intended as a publishing program for webshrines.
+
+In Ascii environments, ⛩️📰 书社 should be written `Shushe`, following
+ the pinyin transliteration.
+
+## Basic Usage
+
+Place source files in `sources/` and run `make install` to compile
+ the result to `public/`.
+Compilation involves the following steps :—
+
+1. ⛩️📰 书社 compiles all of the magic files in `magic/` into a single
+ file, `build/magic.mgc`.
+
+2. ⛩️📰 书社 processes all of the parsers in `parsers/` and determines
+ the list of supported plaintext types.
+
+3. ⛩️📰 书社 identifies all of the source files and includes and uses
+ `build/magic.mgc` to classify them by media type.
+
+4. ⛩️📰 书社 parses all plaintext and X·M·L source files and includes
+ and then builds a dependency tree between them.
+
+5. ⛩️📰 书社 uses the dependency tree to establish prerequisites for
+ each output file.
+
+6. ⛩️📰 书社 compiles each output file to `build/public`.
+
+7. ⛩️📰 书社 copies the output files to `public`.
+
+You can use `make list` to list each identified source file or include
+ alongside its computed type and dependencies.
+As this is a Make‐based program, steps will only be run if the
+ corresponding buildfile or output file is older than its
+ prerequisites.
+
+## Namespaces
+
+The ⛩️📰 书社 namespace is `urn:fdc:ladys.computer:20231231:Shu1She4`.
+
+This document uses a few namespace prefixes, with the following
+ meanings :—
+
+| Prefix | Expansion |
+| -------: | :----------------------------------------- |
+| `html:` | `http://www.w3.org/1999/xhtml` |
+| `xlink:` | `http://www.w3.org/1999/xlink` |
+| `xslt:` | `http://www.w3.org/1999/XSL/Transform` |
+| `书社:` | `urn:fdc:ladys.computer:20231231:Shu1She4` |
+
+## Setup and Configuration
+
+⛩️📰 书社 depends on the following programs to run.
+In every case, you may supply your own implementation by overriding the
+ corresponding (allcaps) variable (e·g, set `MKDIR` to supply your own
+ `mkdir` implementation).
+
+- `cat`
+- `cp`
+- `echo`
+- `file`
+- `find`
+- `mkdir` (requires support for `-p`)
+- `mv`
+- `printf`
+- `sed`
+- `test`
+- `touch`
+- `tr` (requires support for `-d`)
+- `uuencode` (requires support for `-m` and `-r`)
+- `xmlcatalog` (provided by `libxml2`)
+- `xmllint` (provided by `libxml2`)
+- `xsltproc` (provided by `libxslt`)
+
+The following additional variables can be used to control the behaviour
+ of ⛩️📰 书社 :—
+
+- **`SRCDIR`:**
+ The location of the source files (default: `sources`).
+
+- **`INCLUDEDIR`:**
+ The location of the source files (default: `sources/includes`).
+ This can be inside of `SRCDIR`, but needn’t be.
+
+- **`BUILDDIR`:**
+ The location of the (temporary) build directory (default: `build`).
+
+- **`DESTDIR`:**
+ The location of directory to output files to (default: `public`).
+
+- **`THISDIR`:**
+ The location of the ⛩️📰 书社 `GNUmakefile`.
+ This should be set automatically when calling Make and shouldn’t ever
+ need to be set manually.
+ This variable is used to find the ⛩️📰 书社 `lib/` folder, which is
+ expected to be in the same location.
+
+- **`MAGICDIR`:**
+ The location of the magic files to use (default: `$(THISDIR)/magic`).
+
+- **`FINDOPTS`:**
+ Options to pass to `find` when searching for source files (default:
+ `-LE`).
+
+- **`FINDRULES`:**
+ Rules to use with `find` when searching for source files (default:
+ `-flags -nohidden -and -not -name '.*'`).
+
+- **`PARSERS`:**
+ A white·space‐separated list of parsers to use (default:
+ `$(THISDIR)/parsers/*.xslt`).
+
+- **`TRANSFORMS`:**
+ A white·space‐separated list of transforms to use (default:
+ `$(THISDIR)/transforms/*.xslt`).
+
+- **`XMLTYPES`:**
+ A white·space‐separated list of media types to consider X·M·L
+ (default: `application/xml text/xml`).
+
+- **`VERBOSE`:**
+ If this variable has a value, every recipe instruction will be
+ printed when it runs (default: empty).
+ This is helpful for debugging, but typically too noisy for general
+ usage.
+
+## Source Files
+
+Source files may be placed in `SRCDIR` in any manner; the file
+ structure used there will match the output.
+The type of source files is *not* determined by file extension, but
+ rather by magic number; this means that files **must** begin with
+ something recognizable.
+Supported magic numbers include :—
+
+- `<?xml` for `application/xml` files
+- `#!js` for `text/javascript` files
+- `@charset "` for `text/css` files
+- `#!tsv` for `text/tab-separated-values` files
+
+Text formats with associated X·S·L·T parsers are wrapped in a H·T·M·L
+ `<script>` element whose `@type` gives its media type, and then
+ passed to the parser to process.
+Source files whose media type does not have an associated X·S·L·T
+ parser are considered “assets” and will not be transformed.
+
+For compatibility with this program, source filenames should conform to
+ the following rules :—
+
+- They should not start with a hyphen‐minus.
+ This is to prevent confusion between filenames and options on the
+ commandline.
+
+- They should not contain spaces, colons, percent signs, backticks,
+ question marks, hashes, or backslashes.
+
+In general, filenames should be such that they do not require
+ percent‐encoding in the path component of an i·r·i.
+
+## Parsers
+
+Parsers are used to convert plaintext files into X·M·L trees, as well
+ as convert plaintext formats which are already included inline in
+ existing source X·M·L documents.
+⛩️📰 书社 comes with some parsers; namely :—
+
+- **`parsers/plain.xslt`:**
+ Wraps `text/plain` contents in a `<html:pre>` element.
+
+- **`parsers/tsv.xslt`:**
+ Converts `text/tab-separated-values` contents into an `<html:table>`
+ element.
+
+New ⛩️📰 书社 parsers should have a `<xslt:template>` element with no
+ `@name` or `@mode` and whose `@match` attribute…
+
+- Starts with an appropriately‐namespaced qualified name for a
+ `<html:script>` element.
+
+- Follows this with the string `[@type=`.
+
+- Follows this with a quoted string giving a media type supported by
+ the parser.
+ Media type parameters are *not* supported.
+
+- Follows this with the string `]`.
+
+For example, the trivial `text/plain` parser is defined as follows :—
+
+```xml
+<?xml version="1.0"?>
+<transform
+ xmlns="http://www.w3.org/1999/XSL/Transform"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ version="1.0"
+>
+ <template match="html:script[@type='text/plain']">
+ <html:pre><value-of select="."/></html:pre>
+ </template>
+</transform>
+```
+
+⛩️📰 书社 will scan the provided parsers for this pattern to determine
+ the set of allowed plaintext file types.
+Multiple such `<xslt:template>` elements may be provided in a single
+ parser, for example if the parser supports multiple media types.
+
+It is **strongly recommended** that all templates in parsers other than
+ those described above be namespaced (by `@name` or `@mode`), to avoid
+ conflicts between templates in multiple parsers.
+
+## Embedding
+
+Documents can be embedded in other documents using a `<书社:link>`
+ element with `@xlink:show="embed"`.
+The `@xlink:href`s of these elements should have the format
+ `about:shushe?source=<path>`, where `<path>` provides the path to the
+ file within `SRCDIR`.
+Includes, which do not generate outputs of their own but may still be
+ freely embedded, instead use the format
+ `about:shushe?include=<path>`, where `<path>` provides the path
+ within `INCLUDEDIR`.
+
+Embeds are replaced with the parsed contents of a file, unless the file
+ is an asset, in which case an `<html:object>` element is produced
+ instead (with the contents of the asset file provided as a base64
+ `data:` u·r·i).
+
+Embedding takes place after parsing but before transformation, so
+ parsers are able to generate their own embeds.
+⛩️📰 书社 is able to detect the transitive embed dependencies of files
+ and update them accordingly; it will signal an error if the
+ dependencies are recursive.
+
+## Transforms
+
+Transforms are used to convert X·M·L files into their final output,
+ after all necessary parsing and embedding has taken place.
+⛩️📰 书社 comes with some transforms; namely :—
+
+- **`transforms/asset.xslt`:**
+ Converts `<html:object type="text/css">` elements into corresponding
+ `<html:link rel="stylesheet">` elements and
+ `<html:object type="text/javascript">` elements into corresponding
+ `<html:script>` elements.
+ This transform enables embedding of `text/css` and `text/javascript`
+ files, which ordinarily are considered assets (as they lack
+ associated parsers).
+
+- **`transforms/metadata.xslt`:**
+ Provides basic `<html:head>` metadata.
+ This metadata is generated from `<html:meta>` descendants of the
+ first element with an `@itemscope` attribute (recommended to just
+ be the root element).
+ Such elements can provide metadata using the following `@itemprop`
+ attributes :—
+
+ - **`urn:fdc:ladys.computer:20231231:Shu1She4:title`:**
+ Provides the title of the page.
+
+The following are recommendations on effective creation of
+ transforms :—
+
+- Make template matchers as specific as possible.
+ It is likely an error if two transforms have templates which match
+ the same element (unless the templates have different priority).
+
+- Namespace templates (with `@name` or `@mode`) whenever possible.
+
+- Set `@exclude-result-prefixes` on the root `xslt:transform` element
+ to reduce the number of declared namespaces in the final result.
+
+## Output Wrapping
+
+⛩️📰 书社 will wrap the final output of the transforms in appropriate
+ `<html:html>` and `<html:body>` elements, so it is not necessary for
+ transforms to do this explicitly.
+The `<html:head>` of the output will contain the result tree generated
+ by matching the root node in the `书社:metadata` mode; the provided
+ `transforms/metadata.xslt` transform uses this mode to generate basic
+ metadata, but it is possible for other transforms to add their own.
+
+## License
+
+Source files are licensed under the terms of the <cite>Mozilla Public
+ License, version 2.0</cite>.
+For more information, see [LICENSE](./LICENSE).
--- /dev/null
+<?xml version="1.0"?>
+<!--
+⁌ ⛩️📰 书社 ∷ lib/catalog2dependencies.xslt
+
+© 2023 Lady [@ Lady’s Computer]
+
+This Source Code Form is subject to the terms of the Mozilla Public License, v 2.0.
+If a copy of the M·P·L was not distributed with this file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
+-->
+<transform
+ xmlns="http://www.w3.org/1999/XSL/Transform"
+ xmlns:catalog="urn:oasis:names:tc:entity:xmlns:xml:catalog"
+ xmlns:exsl="http://exslt.org/common"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:书社="urn:fdc:ladys.computer:20231231:Shu1She4"
+ version="1.0"
+>
+ <variable name="uris" select="//catalog:uri"/>
+ <template name="书社:process-dependencies">
+ <param name="processed"/>
+ <param name="unprocessed"/>
+ <variable name="queue">
+ <copy-of select="exsl:node-set($unprocessed)/书社:dependency-root"/>
+ <for-each select="exsl:node-set($unprocessed)/书社:dependency">
+ <if test="not((exsl:node-set($processed)/书社:*|preceding-sibling::书社:*|following-sibling::书社:recursive-dependency)[string()=string(current())])">
+ <copy-of select="."/>
+ </if>
+ </for-each>
+ </variable>
+ <variable name="old">
+ <copy-of select="exsl:node-set($processed)/书社:dependency-root"/>
+ <copy-of select="exsl:node-set($processed)/书社:recursive-dependency"/>
+ <for-each select="exsl:node-set($unprocessed)/书社:recursive-dependency">
+ <if test="not((exsl:node-set($processed)/书社:recursive-dependency|preceding-sibling::书社:recursive-dependency)[string()=string(current())])">
+ <copy-of select="."/>
+ </if>
+ </for-each>
+ <for-each select="exsl:node-set($processed)/书社:dependency">
+ <if test="not(exsl:node-set($unprocessed)/书社:recursive-dependency[string()=string(current())])">
+ <copy-of select="."/>
+ </if>
+ </for-each>
+ <copy-of select="$queue"/>
+ </variable>
+ <variable name="new">
+ <for-each select="exsl:node-set($queue)/书社:*">
+ <for-each select="$uris[@name=string(current()) and substring-after(@uri, '#')!='asset']">
+ <variable name="parent" select="@name"/>
+ <for-each select="document(substring-before(@uri, '#'), .)//书社:link[@xlink:show='embed']">
+ <if test="exsl:node-set($old)/书社:dependency-root[string()=string(current()/@xlink:href)]">
+ <书社:recursive-dependency>
+ <value-of select="$parent"/>
+ </书社:recursive-dependency>
+ </if>
+ <if test="$uris/@name[string()=string(current()/@xlink:href)]">
+ <书社:dependency>
+ <value-of select="@xlink:href"/>
+ </书社:dependency>
+ </if>
+ </for-each>
+ </for-each>
+ </for-each>
+ </variable>
+ <choose>
+ <when test="exsl:node-set($new)/书社:dependency">
+ <call-template name="书社:process-dependencies">
+ <with-param name="processed">
+ <copy-of select="$old"/>
+ </with-param>
+ <with-param name="unprocessed">
+ <copy-of select="$new"/>
+ </with-param>
+ </call-template>
+ </when>
+ <otherwise>
+ <copy-of select="$old"/>
+ </otherwise>
+ </choose>
+ </template>
+ <template match="catalog:uri" mode="书社:dependencies">
+ <if test="substring-after(@uri, '#')!='asset'">
+ <call-template name="书社:process-dependencies">
+ <with-param name="unprocessed">
+ <书社:dependency-root>
+ <value-of select="@name"/>
+ </书社:dependency-root>
+ </with-param>
+ </call-template>
+ </if>
+ </template>
+ <template match="/">
+ <for-each select="$uris[not(substring-after(@uri, '#')='asset')]">
+ <variable name="parent" select="@name"/>
+ <variable name="dependencies">
+ <apply-templates select="." mode="书社:dependencies"/>
+ </variable>
+ <value-of select="@name"/>
+ <text>
</text>
+ <for-each select="exsl:node-set($dependencies)/书社:recursive-dependency">
+ <text>	</text>
+ <text>!</text>
+ <value-of select="."/>
+ <text>
</text>
+ </for-each>
+ <for-each select="exsl:node-set($dependencies)/书社:dependency">
+ <text>	</text>
+ <value-of select="."/>
+ <text>
</text>
+ </for-each>
+ </for-each>
+ </template>
+ <output method="text" encoding="UTF-8"/>
+</transform>
--- /dev/null
+<?xml version="1.0"?>
+<!--
+⁌ ⛩️📰 书社 ∷ lib/catalog2parser.xslt
+
+© 2023 Lady [@ Lady’s Computer]
+
+This Source Code Form is subject to the terms of the Mozilla Public License, v 2.0.
+If a copy of the M·P·L was not distributed with this file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
+-->
+<transform
+ xmlns="http://www.w3.org/1999/XSL/Transform"
+ xmlns:catalog="urn:oasis:names:tc:entity:xmlns:xml:catalog"
+ xmlns:xsla="http://www.w3.org/1999/XSL/TransformAlias"
+ exclude-result-prefixes="catalog"
+ version="1.0"
+>
+ <namespace-alias stylesheet-prefix="xsla" result-prefix="#default"/>
+ <template match="/">
+ <xsla:transform version="1.0">
+ <for-each select="//catalog:uri">
+ <xsla:include href="{@uri}"/>
+ </for-each>
+ <xsla:template match="@*|node()" priority="-1">
+ <xsla:copy>
+ <xsla:apply-templates select="@*|node()"/>
+ </xsla:copy>
+ </xsla:template>
+ </xsla:transform>
+ </template>
+</transform>
--- /dev/null
+<?xml version="1.0"?>
+<!--
+⁌ ⛩️📰 书社 ∷ lib/catalog2transform.xslt
+
+© 2023 Lady [@ Lady’s Computer]
+
+This Source Code Form is subject to the terms of the Mozilla Public License, v 2.0.
+If a copy of the M·P·L was not distributed with this file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
+-->
+<transform
+ xmlns="http://www.w3.org/1999/XSL/Transform"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns:catalog="urn:oasis:names:tc:entity:xmlns:xml:catalog"
+ xmlns:exsl="http://exslt.org/common"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:xslt="http://www.w3.org/1999/XSL/TransformAlias"
+ xmlns:书社="urn:fdc:ladys.computer:20231231:Shu1She4"
+ version="1.0"
+>
+ <namespace-alias stylesheet-prefix="xslt" result-prefix="#default"/>
+ <template match="/">
+ <xslt:transform exclude-result-prefixes="catalog exsl" version="1.0">
+ <xslt:param name="catalog" select="'catalog'"/>
+ <for-each select="//catalog:uri">
+ <xslt:include href="{@uri}"/>
+ </for-each>
+ <xslt:template match="/" priority="1">
+ <xslt:variable name="expansion">
+ <xslt:apply-templates select="." mode="书社:expand"/>
+ </xslt:variable>
+ <xslt:variable name="result">
+ <xslt:apply-templates select="exsl:node-set($expansion)/*"/>
+ </xslt:variable>
+ <xslt:variable name="metadata">
+ <xslt:copy-of select="exsl:node-set($result)/html/head/*"/>
+ <xslt:apply-templates select="exsl:node-set($result)" mode="书社:metadata"/>
+ </xslt:variable>
+ <html:html>
+ <xslt:copy-of select="exsl:node-set($result)/html:html/@*"/>
+ <html:head>
+ <xslt:copy-of select="exsl:node-set($result)/html:html/html:head/@*"/>
+ <html:title>
+ <xslt:for-each select="exsl:node-set($metadata)/html:title">
+ <xslt:value-of select="."/>
+ </xslt:for-each>
+ </html:title>
+ <xslt:copy-of select="exsl:node-set($metadata)/*[not(self::html:title)]"/>
+ <xslt:if test="not(exsl:node-set($metadata)/html:meta[@name='generator'])">
+ <html:meta name="generator" content="⛩️📰 书社"/>
+ </xslt:if>
+ </html:head>
+ <html:body>
+ <xslt:copy-of select="exsl:node-set($result)/*[not(self::html:html or self::html:body)]|exsl:node-set($result)/html:html/*[not(self::html:head or self::html:body)]|exsl:node-set($result)/html:html/html:body/*|exsl:node-set($result)/html:body/*"/>
+ </html:body>
+ </html:html>
+ </xslt:template>
+ <xslt:template match="@*|node()" priority="-1">
+ <xslt:copy>
+ <xslt:apply-templates select="@*|node()"/>
+ </xslt:copy>
+ </xslt:template>
+ <xslt:template match="书社:link[@xlink:show='embed']" mode="书社:expand">
+ <xslt:variable name="uri" select="substring-before(document($catalog)//catalog:uri[@name=current()/@xlink:href]/@uri[1], '#')"/>
+ <xslt:choose>
+ <xslt:when test="$uri">
+ <xslt:apply-templates select="document($uri)" mode="书社:expand"/>
+ </xslt:when>
+ <xslt:otherwise>
+ <xslt:copy>
+ <xslt:apply-templates select="@*|node()" mode="书社:expand"/>
+ </xslt:copy>
+ </xslt:otherwise>
+ </xslt:choose>
+ </xslt:template>
+ <xslt:template match="@*|text()|*[not(self::书社:link) or not(@xlink:show='embed')]" mode="书社:expand">
+ <xslt:copy>
+ <xslt:apply-templates select="@*|node()" mode="书社:expand"/>
+ </xslt:copy>
+ </xslt:template>
+ <xslt:template match="text()" mode="书社:metadata"/>
+ <xslt:output method="xml" encoding="UTF-8" cdata-section-elements="html:script html:style html:textarea"/>
+ </xslt:transform>
+ </template>
+</transform>
--- /dev/null
+<?xml version="1.0"?>
+<!--
+⁌ ⛩️📰 书社 ∷ lib/parser2types.xslt
+
+© 2023 Lady [@ Lady’s Computer]
+
+This Source Code Form is subject to the terms of the Mozilla Public License, v 2.0.
+If a copy of the M·P·L was not distributed with this file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
+-->
+<transform
+ xmlns="http://www.w3.org/1999/XSL/Transform"
+ xmlns:catalog="urn:oasis:names:tc:entity:xmlns:xml:catalog"
+ xmlns:xslt="http://www.w3.org/1999/XSL/Transform"
+ xmlns:书社="urn:fdc:ladys.computer:20231231:Shu1She4"
+ version="1.0"
+>
+ <template match="/">
+ <for-each select="//xslt:include">
+ <for-each select="document(@href, .)//xslt:template[not(@name) and not(@mode)]">
+ <variable name="match" select="@match"/>
+ <for-each select="namespace::*[local-name() and string()='http://www.w3.org/1999/xhtml']">
+ <variable name="matchstart">
+ <value-of select="local-name()"/>
+ <text>:</text>
+ <text>script[@type=</text>
+ </variable>
+ <if test="starts-with($match, $matchstart) and substring($match, string-length($match))=']' and contains($match, '/')">
+ <variable name="inner" select="substring-before(substring-after($match, $matchstart), ']')"/>
+ <if test="starts-with($inner, '"') and substring($inner, string-length($inner))='"' or starts-with($inner, "'") and substring($inner, string-length($inner))="'"">
+ <variable name="type" select="substring($inner, 2, string-length($inner)-2)"/>
+ <if test="not(translate($type, '0123456789abcdefghijklmnopqrstuvwxyz!#$&-^_.+/', ''))">
+ <value-of select="$type"/>
+ <text>
</text>
+ </if>
+ </if>
+ </if>
+ </for-each>
+ </for-each>
+ </for-each>
+ </template>
+ <output method="text" encoding="UTF-8"/>
+</transform>
--- /dev/null
+0 string /*css CSS text
+!:mime text/css
+!:strength + 255
+
+0 string @charset\ " CSS text
+!:mime text/css
+!:strength + 255
+
+0 byte 0xEF
+>1 byte 0xBB
+>>2 byte 0xBF
+>>>3 string @charset\ " CSS text
+!:mime text/css
+!:strength + 255
--- /dev/null
+0 string #!js Javascript text
+!:mime text/javascript
+!:strength + 255
+
+0 string #!javascript Javascript text
+!:mime text/javascript
+!:strength + 255
--- /dev/null
+0 string #!tsv TSV text
+!:mime text/tab-separated-values
+!:strength + 255
+
+0 byte 0xEF
+>1 byte 0xBB
+>>2 byte 0xBF
+>>>3 string #!tsv TSV text
+!:mime text/tab-separated-values
+!:strength + 255
--- /dev/null
+0 string \<?xml XML data
+!:mime application/xml
+!:strength + 255
+
+0 byte 0xEF
+>1 byte 0xBB
+>>2 byte 0xBF
+>>>3 string \<?xml XML data
+!:mime application/xml
+!:strength + 255
--- /dev/null
+<?xml version="1.0"?>
+<!--
+⁌ ⛩️📰 书社 ∷ parsers/plain.xslt
+
+© 2023 Lady [@ Lady’s Computer]
+
+This Source Code Form is subject to the terms of the Mozilla Public License, v 2.0.
+If a copy of the M·P·L was not distributed with this file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
+-->
+<transform
+ xmlns="http://www.w3.org/1999/XSL/Transform"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ version="1.0"
+>
+ <template match="html:script[@type='text/plain']">
+ <html:pre><value-of select="."/></html:pre>
+ </template>
+</transform>
--- /dev/null
+<?xml version="1.0"?>
+<!--
+⁌ ⛩️📰 书社 ∷ parsers/tsv.xslt
+
+© 2023 Lady [@ Lady’s Computer]
+
+This Source Code Form is subject to the terms of the Mozilla Public License, v 2.0.
+If a copy of the M·P·L was not distributed with this file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
+-->
+<transform
+ xmlns="http://www.w3.org/1999/XSL/Transform"
+ xmlns:exsl="http://exslt.org/common"
+ xmlns:exslstr="http://exslt.org/strings"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ exclude-result-prefixes="exsl exslstr"
+ version="1.0"
+>
+ <template match="html:script[@type='text/tab-separated-values']">
+ <variable name="rows" select="exslstr:tokenize(., '
')[normalize-space(.) and not(starts-with(., '#'))]"/>
+ <variable name="head" select="exsl:node-set($rows)[1]"/>
+ <variable name="body" select="exsl:node-set($rows)[not(position()=1)]"/>
+ <html:table>
+ <html:thead>
+ <html:tr>
+ <for-each select="exslstr:tokenize($head, '	')">
+ <html:th scope="row">
+ <value-of select="."/>
+ </html:th>
+ </for-each>
+ </html:tr>
+ </html:thead>
+ <html:tbody>
+ <for-each select="exsl:node-set($body)">
+ <html:tr>
+ <for-each select="exslstr:tokenize(., '	')">
+ <html:td>
+ <value-of select="."/>
+ </html:td>
+ </for-each>
+ </html:tr>
+ </for-each>
+ </html:tbody>
+ </html:table>
+ </template>
+</transform>
--- /dev/null
+<?xml version="1.0"?>
+<!--
+⁌ ⛩️📰 书社 ∷ transforms/asset.xslt
+
+© 2023 Lady [@ Lady’s Computer]
+
+This Source Code Form is subject to the terms of the Mozilla Public License, v 2.0.
+If a copy of the M·P·L was not distributed with this file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
+-->
+<transform
+ xmlns="http://www.w3.org/1999/XSL/Transform"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns:书社="urn:fdc:ladys.computer:20231231:Shu1She4"
+ exclude-result-prefixes="书社"
+ version="1.0"
+>
+ <template match="html:object[@type='text/css']">
+ <comment>
+ <text>[书社:CSS] </text>
+ <value-of select="@data"/>
+ </comment>
+ </template>
+ <template match="comment()[starts-with(., '[书社:CSS] ')]" mode="书社:metadata">
+ <html:link rel="stylesheet" type="text/css" href="{substring-after(., '[书社:CSS] ')}"/>
+ </template>
+ <template match="html:object[@type='text/javascript']">
+ <html:script type="{@type}" src="{@data}"/>
+ </template>
+</transform>
--- /dev/null
+<?xml version="1.0"?>
+<!--
+⁌ ⛩️📰 书社 ∷ transforms/metadata.xslt
+
+© 2023 Lady [@ Lady’s Computer]
+
+This Source Code Form is subject to the terms of the Mozilla Public License, v 2.0.
+If a copy of the M·P·L was not distributed with this file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
+-->
+<transform
+ xmlns="http://www.w3.org/1999/XSL/Transform"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns:书社="urn:fdc:ladys.computer:20231231:Shu1She4"
+ exclude-result-prefixes="书社"
+ version="1.0"
+>
+ <template match="html:*[@itemscope][1]//html:meta[not(@name) and starts-with(@itemprop, 'urn:fdc:ladys.computer:20231231:Shu1She4:')]">
+ <comment>
+ <text>[书社:META] </text>
+ <value-of select="substring-after(@itemprop, 'urn:fdc:ladys.computer:20231231:Shu1She4:')"/>
+ <text>: </text>
+ <value-of select="@content"/>
+ </comment>
+ </template>
+ <template match="comment()[starts-with(., '[书社:META] ')]" mode="书社:metadata">
+ <variable name="property" select="substring-before(substring-after(., '[书社:META] '), ': ')"/>
+ <variable name="value" select="substring-after(., concat('[书社:META] ', $property, ': '))"/>
+ <choose>
+ <when test="$property='title'">
+ <html:title>
+ <value-of select="$value"/>
+ </html:title>
+ </when>
+ </choose>
+ </template>
+</transform>