summaryrefslogtreecommitdiff
path: root/graphics
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2020-06-07 03:03:23 +0000
committerNorbert Preining <norbert@preining.info>2020-06-07 03:03:23 +0000
commit666248863665f4318b13e1c1b7a2b94ef90a8b9a (patch)
tree9e682f3dd1e75d918244c2e0d615e58850a0e1e4 /graphics
parent527cbc8280407d055d185ad11f79b81b032eec7e (diff)
CTAN sync 202006070303
Diffstat (limited to 'graphics')
-rw-r--r--graphics/pgf/contrib/commutative-diagrams/README6
-rw-r--r--graphics/pgf/contrib/commutative-diagrams/commutative-diagrams-doc.pdfbin0 -> 538765 bytes
-rw-r--r--graphics/pgf/contrib/commutative-diagrams/commutative-diagrams-doc.tex1729
-rw-r--r--graphics/pgf/contrib/commutative-diagrams/commutative-diagrams.sty14
-rw-r--r--graphics/pgf/contrib/commutative-diagrams/commutative-diagrams.tex14
-rw-r--r--graphics/pgf/contrib/commutative-diagrams/kodi.sty60
-rw-r--r--graphics/pgf/contrib/commutative-diagrams/t-commutative-diagrams.tex16
-rw-r--r--graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.bapto.code.tex56
-rw-r--r--graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.code.tex47
-rw-r--r--graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.diorthono.code.tex78
-rw-r--r--graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.ektropi.code.tex66
-rw-r--r--graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.katharizo.code.tex136
-rw-r--r--graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.koinos.code.tex168
-rw-r--r--graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.mandyas.code.tex319
-rw-r--r--graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.mitra.code.tex207
-rw-r--r--graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.ozos.code.tex58
-rw-r--r--graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.ramma.code.tex158
-rw-r--r--graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.velos.code.tex280
-rw-r--r--graphics/pstricks/contrib/pst-func/Changes2
-rw-r--r--graphics/pstricks/contrib/pst-func/README.md4
-rw-r--r--graphics/pstricks/contrib/pst-func/doc/pst-func-doc.pdfbin3956145 -> 3889616 bytes
-rw-r--r--graphics/pstricks/contrib/pst-func/doc/pst-func-doc.tex69
-rw-r--r--graphics/pstricks/contrib/pst-func/tex/pst-func.tex48
23 files changed, 3529 insertions, 6 deletions
diff --git a/graphics/pgf/contrib/commutative-diagrams/README b/graphics/pgf/contrib/commutative-diagrams/README
new file mode 100644
index 0000000000..d439579378
--- /dev/null
+++ b/graphics/pgf/contrib/commutative-diagrams/README
@@ -0,0 +1,6 @@
+CoDi: Commutative Diagrams for TeX
+==================================
+
+CoDi is a TikZ library. Its aim
+is making commutative diagrams
+easy to design, parse and tweak.
diff --git a/graphics/pgf/contrib/commutative-diagrams/commutative-diagrams-doc.pdf b/graphics/pgf/contrib/commutative-diagrams/commutative-diagrams-doc.pdf
new file mode 100644
index 0000000000..e479e4960f
--- /dev/null
+++ b/graphics/pgf/contrib/commutative-diagrams/commutative-diagrams-doc.pdf
Binary files differ
diff --git a/graphics/pgf/contrib/commutative-diagrams/commutative-diagrams-doc.tex b/graphics/pgf/contrib/commutative-diagrams/commutative-diagrams-doc.tex
new file mode 100644
index 0000000000..5c68664271
--- /dev/null
+++ b/graphics/pgf/contrib/commutative-diagrams/commutative-diagrams-doc.tex
@@ -0,0 +1,1729 @@
+%
+% CoDi: Commutative Diagrams for TeX
+% Copyright (c) 2015-2020 Paolo Brasolin <paolo.brasolin@gmail.com>
+% SPDX-License-Identifier: MIT
+%
+% This file is part of CoDi 1.0.0, released on 2020/06/06 under MIT license.
+%
+
+%==[ document class ]===========================================================
+
+\documentclass[12pt]{scrbook}
+
+%==[ languages ]================================================================
+
+\usepackage[british]{babel}
+% \hyphenation{Fortran hy-phen-ation}
+
+%==[ fonts, encoding ]==========================================================
+
+\usepackage{libertine}
+\usepackage{libertinust1math}
+\usepackage[ttdefault=true]{AnonymousPro}
+
+\usepackage[utf8]{inputenc}
+\usepackage[T1]{fontenc}
+
+%==[ page geometry ]============================================================
+
+\usepackage{geometry}
+
+\geometry{
+ a4paper,
+ portrait,
+ marginparwidth=4.25cm,
+ marginparsep=.75cm,
+ %% showframe,
+ width=11cm,
+ hmarginratio=10:25,
+ height=23cm,
+ vmarginratio=20:30,
+}
+
+\makeatletter
+\let\org@Gm@pageframes\Gm@pageframes
+\renewcommand*{\Gm@pageframes}{%
+ \begingroup
+ \color{gray}%
+ \org@Gm@pageframes
+ \endgroup
+}
+\makeatother
+
+%==[ page layout ]==============================================================
+
+%\usepackage{multicol}
+%\usepackage{tabularx}
+\usepackage{booktabs}
+%\usepackage{verbatimbox}
+%\usepackage{wrapfig}
+
+\usepackage{float}
+% \usepackage{framed}
+% \usepackage{lipsum}
+\usepackage{enumitem}
+% \usepackage{pdfpages}
+
+% \usepackage{caption}
+\usepackage{sidenotes}
+
+% \DeclareCaptionStyle{sidenote}{font=scriptsize}
+
+% \usepackage{todonotes}
+% \usepackage{marginnote}
+
+\usepackage[
+ headwidth=textwithmarginpar,
+ footwidth=textwithmarginpar,
+]{scrlayer-scrpage}
+%\clearpairofpagestyles
+
+% \lofoot{}
+% \cofoot{}
+% \rofoot{}
+% \lohead{}
+% \cohead{}
+% \rohead{\thepage}
+
+%==[ page style ]===============================================================
+
+\setkomafont{disposition}{\rmfamily\scshape}
+
+\usepackage{parskip}
+
+% \usepackage{csquotes}
+
+\usepackage{caption}
+\usepackage{subcaption}
+
+\DeclareCaptionStyle{marginfigure}{
+ font=footnotesize,
+ justification=centering,
+}
+
+\captionsetup[subfigure]{
+ textfont=footnotesize,
+ %% singlelinecheck=off,
+ justification=centering
+}
+
+\setcounter{secnumdepth}{0}
+
+%==[ commonplace math ]=========================================================
+
+\usepackage{mathtools}
+\usepackage{amsfonts}
+\usepackage{amssymb}
+
+\DeclareMathOperator{\coker}{coker}
+
+% \def\id{{\mathbf 1}}
+% \DeclareUnicodeCharacter{0131}{{\noexpand\mathbf R}}
+% \DeclareUnicodeCharacter{00D7}{{\otimes}}
+% \catcode`ı=\active \letı\id
+% \catcode`×=\active \let×\otimes
+% NOTE: needed just for the associahedron example
+\usepackage{newunicodechar}
+\newunicodechar{ı}{\mathbf 1}
+\newunicodechar{×}{\otimes}
+
+%==[ graphics ]=================================================================
+
+\usepackage{graphicx}
+\usepackage{xcolor}
+% TODO: what did I need soul for again?
+\usepackage{color,soul}
+
+\usepackage{tikz}
+\usetikzlibrary{decorations.pathreplacing}
+
+%==[ CoDi ]=====================================================================
+
+% \usetikzlibrary{commutative-diagrams}
+\usepackage{commutative-diagrams}
+\usetikzlibrary{positioning}
+
+%==[ alternatives to CoDi ]=====================================================
+
+% So, yeah, I got *really* tired...
+\usepackage{filecontents}
+
+% Copied from Xy sourcecode
+\def\Xy{\hbox{\kern-.1em X\kern-.3em\lower.4ex\hbox{Y\kern-.15em}}}
+
+%==[ utilities and custom macros ]==============================================
+
+\usepackage{etoolbox}
+\usepackage{xparse}
+
+% \NewDocumentCommand{\SmashAndCenter}{m}{%
+% \begingroup\setbox0=\hbox{#1}%
+% \newdimen\tmp\tmp=\dimexpr-.5\ht0+.5\dp0\relax%
+% \hfill\smash{\raisebox{\the\tmp}{\box0}}\hfill\null\endgroup%
+% }
+
+\newsavebox\SmashAndCenterBox
+\newdimen\SmashandCenterRaise
+
+% TODO: make overflow on left pages go left
+\NewDocumentEnvironment{SmashAndCenter}{}{%
+\begin{lrbox}{\SmashAndCenterBox}}{%
+\end{lrbox}%
+\SmashandCenterRaise=\dimexpr-.5\ht\SmashAndCenterBox+.5\dp\SmashAndCenterBox\relax%
+\hfill\smash{\raisebox{\the\SmashandCenterRaise}{\usebox\SmashAndCenterBox}}\hfill\null%
+}
+
+\def\eg{e.\,g.}
+%% \deg\ie{i.\,e.}
+
+%==[ sourcecode and examples ]==================================================
+
+\usepackage{listings}
+
+% http://tex.stackexchange.com/a/336331/82186
+\makeatletter
+\lst@Key{lastline}\relax{\ifnumcomp{#1}{<}{0}{%
+ \let\mylst@file\kvtcb@listingfile\sbox0{\lstinputlisting{\mylst@file}}%
+ \def\lst@lastline{\the\numexpr#1+\value{lstnumber}-1\relax}}%
+ {\def\lst@lastline{#1\relax}}}
+\makeatother
+
+\usepackage{showexpl}
+
+\makeatletter
+\lst@Key{postset}\relax{\def\SX@postset{#1}}
+\newcommand\SX@postset{}
+\renewcommand*\SX@resultInput{%
+ \ifx\SX@graphicname\@empty
+ \begingroup
+ \MakePercentComment\makeatother\catcode`\^^M=5\relax
+ \SX@@preset\SX@preset
+ \if@SX@rangeaccept
+ \let\SX@tempa=\SX@input
+ \else
+ \let\SX@tempa=\input
+ \fi
+ \if\SX@scaled ?%
+ \let\SX@tempb=\@firstofone
+ \else
+ \if\SX@scaled !%
+ \def\SX@tempb##1{\resizebox{\SX@width}{!}{##1}}%
+ \else
+ \def\SX@tempb##1{\scalebox{\SX@scaled}{##1}}%
+ \fi
+ \fi
+ \SX@tempb{\SX@tempa{\SX@codefile}}\SX@postset\par
+ \endgroup
+ \else
+ \expandafter\includegraphics\expandafter[\SX@graphicparam]%
+ {\SX@graphicname}%
+ \fi
+}
+\makeatother
+
+% \lstdefinelanguage{TikZ}{
+% morekeywords={for},
+% sensitive=false,
+% morecomment=[l]{//},
+% morecomment=[s]{/*}{*/},
+% morestring=[b]",
+% }
+
+\lstdefinestyle{TeX}{
+ language=[LaTeX]TeX,
+ basicstyle=\ttfamily\lst@ifdisplaystyle\scriptsize\fi,
+ backgroundcolor=\color{teal!10},
+ % keywordstyle=*\color{blue},
+ % identifierstyle=\color{orange}\bfseries,
+ % morekeywords={\path},
+ alsoother={@},
+ moretexcs={
+ \starttext,\stoptext,\usemodule,
+ \tikzpicture,\endtikzpicture,
+ \tikzexternalize,
+ \starttikzpicture,\stoptikzpicture,
+ \usetikzlibrary,
+ \codi,\endcodi,
+ \startcodi,\stopcodi,
+ \lay,\obj,\mor,
+ \bye,
+ \draw,\foreach,
+ \ar,
+ \psset,\everypsbox,\ncline,\ncarc,
+ \xymatrix,
+ },
+ texcsstyle=*\bfseries,
+ % morestring=[b]",
+ commentstyle=\itshape\color{black!60},
+ frame=none,
+ % extendedchars=false,
+ inputencoding=utf8,
+ escapeinside={(@}{@)},
+ moredelim=**[is][\color{orange!80!black}]{@opt@}{@/opt@},
+ moredelim=**[is][\color{blue!80!black}]{@nws@}{@/nws@},
+ % moredelim=**[is][\color\underbar]{@rep@}{@/rep@},
+ moredelim=**[s][\itshape]{<}{>},
+ % NOTE: × and ı are needed just for the associahedron example
+ literate={~}{{\textvisiblespace}}1 {XOR}{{$\vert$}}1 {:}{{\textbf{:}}}1 {:=}{{$\equiv$}}1 {×}{{\texttimes}}1 {ı}{{\i}}1,
+}
+
+\lstset{style=TeX}
+% \lstMakeShortInline[style=TeX]"
+
+% \makeatletter
+% \newcount\ublvl\ublvl=0
+% \newcount\ubdpt\ubdpt=0
+% \newdimen\ubgap\ubgap=.2em
+% \def\underbra#1{\underline {\sbox \tw@ {\global\advance\ubdpt1\advance\ublvl1#1}\dp \tw@ \dimexpr\ubgap*(\ubdpt-\ublvl-1)\relax \box \tw@ }\ifnum\ublvl=0\ubdpt=0\fi}
+% \makeatother
+
+% \lstset{explpreset={
+% wide,
+% basicstyle=\ttfamily\scriptsize,
+% pos=o,
+% width=\marginparwidth,
+% hsep=\marginparsep,
+% rframe={},
+% preset={\centering\tikzpicture[codi]},
+% postset={\endtikzpicture}
+% }}
+
+\usepackage{tcolorbox}
+\tcbuselibrary{listingsutf8}
+\tcbset{listing utf8=latin1}
+
+\tcbset{
+ smash and center/.style={
+ if odd page={
+ before lower=\begin{SmashAndCenter},
+ after lower=\end{SmashAndCenter}
+ }{
+ before upper=\begin{SmashAndCenter},
+ after upper=\end{SmashAndCenter}
+ }},
+ trim/.style args={#1 and #2}{
+ listing options={
+ firstline=#1,
+ lastline=#2}},
+ trim/.default={2 and -1},
+ snippet/.style={
+ size=tight,
+ colback=white,
+ colframe=white,
+ if odd page={
+ listing side text,
+ lefthand width=\textwidth,
+ righthand width=\marginparwidth,
+ halign lower=center,
+ }{
+ text side listing,
+ righthand width=\textwidth,
+ lefthand width=\marginparwidth,
+ halign upper=center,
+ },
+ toggle enlargement,
+ grow to right by=\marginparsep+\marginparwidth,
+ sidebyside gap=\marginparsep,
+ smash and center,
+ listing options={}
+ },
+ commented snippet/.style={
+ snippet,
+ comment={}, % avoids text compilation (possible tcb bug?)
+ if odd page={
+ listing side comment,
+ }{
+ comment side listing,
+ },
+ },
+ gallery/.style={
+ size=tight,
+ colback=white,
+ colframe=white,
+ if odd page={
+ % listing side text,
+ % lefthand width=\textwidth,
+ % righthand width=\marginparwidth,
+ grow to right by=\marginparsep+\marginparwidth,
+ }{
+ grow to right by=\marginparsep+\marginparwidth,
+ % text side listing,
+ % righthand width=\textwidth,
+ % lefthand width=\marginparwidth,
+ % halign upper=center,
+ },
+ toggle enlargement,
+ % grow to right by=\marginparsep+\marginparwidth,
+ text above listing,
+ listing options={}
+ }
+}
+
+% \tcbset{codi snippet/.style={snippet, trim, smash and center}}
+
+\def\nilstrut{\rule{0sp}{0sp}}
+
+%==[ extra stuff ]==============================================================
+
+\usepackage{soul}
+
+% \usepackage{lipsum}
+
+\usepackage{hologo}
+\def\ConTeXt{\hologo{ConTeXt}}
+\def\CoDi{{\scshape CoDi}}
+\def\TikZ{{\scshape TikZ}}
+
+% \usepackage[lastpage,user]{zref}
+\usepackage[
+ % colorlinks=true,
+ % urlcolor=blue,
+ % linkbordercolor=black,
+ % pdfborderstyle={/S/U/W .4}% border style will be underline of width 1pt
+ % urlbordercolor=cyan % color of external links
+ hidelinks
+]{hyperref}
+
+\def\NiceURL#1#2{\href{#2}{\color{blue}\ul{#1}}}
+
+%==[ microtype ]================================================================
+
+\usepackage{microtype}
+
+\begin{document}
+
+%==[ TITLE PAGE ]===============================================================
+
+\thispagestyle{empty}
+\noindent
+\resizebox{\linewidth}{!}{\scshape CoDi}\\[0.62em]
+\resizebox{\linewidth}{!}{\scshape Commutative Diagrams for \TeX}\\[1.62em]
+\resizebox{\linewidth}{!}{\scshape enchiridion}\par
+\vfill
+\marginpar{
+ \resizebox{\linewidth}{!}{\scshape 1.0.0}\\[0.62em]
+ \resizebox{\linewidth}{!}{\scshape \today}
+}
+
+%==[ FOREWORD ]=================================================================
+
+\newpage
+\begin{adjustwidth}{.47\textwidth-\marginparwidth-\marginparsep}{.47\textwidth}
+\noindent\CoDi\ is a \TikZ\ library. Its aim is\linebreak
+making commutative diagrams\linebreak
+easy to design, parse and tweak.\par
+\end{adjustwidth}
+
+\newpage
+\section{Preliminaries}
+\TikZ\ is the only dependency of \CoDi.
+This ensures compatibility with most\footnote{\CoDi\ builds upon \TikZ, which builds upon {\ttfamily\small pgf}, which after version 3.1 requires at least \hologo{eTeX} version 2. This is inconsequential except in the unlikely event you're using Knuth's original {\ttfamily\small tex} format.} \TeX\ flavours.
+Furthermore, it can be invoked both as a standalone and as a \TikZ\ library.
+Below are minimal working examples for the main dialects.
+
+\begin{figure}[H]
+ \begin{adjustwidth}{0sp}{-\marginparwidth-\marginparsep}
+ \begin{subfigure}{\marginparwidth}
+ \caption*{\TeX\ package}
+ \begin{lstlisting}[gobble=8]
+
+ \input
+ {commutative-diagrams}
+
+ \codi
+ % diagram here
+ \endcodi
+ \bye
+ \end{lstlisting}
+ \end{subfigure}
+ \hfill
+ \begin{subfigure}{\marginparwidth}
+ \caption*{\ConTeXt\ module}
+ \begin{lstlisting}[gobble=8]
+
+ \usemodule
+ [commutative-diagrams]
+ \starttext
+ \startcodi
+ % diagram here
+ \stopcodi
+ \stoptext
+ \end{lstlisting}
+ \end{subfigure}
+ \hfill
+ \begin{subfigure}{\marginparwidth}
+ \caption*{\LaTeX\ package}
+ \begin{lstlisting}[gobble=8]
+ \documentclass{article}
+ \usepackage
+ {commutative-diagrams}
+ \begin{document}
+ \begin{codi}
+ % diagram here
+ \end{codi}
+ \end{document}
+ \end{lstlisting}
+ \end{subfigure}
+ \par
+ \begin{subfigure}{\marginparwidth}
+ \caption*{\TeX\ (\TikZ\ library)}
+ \begin{lstlisting}[gobble=8]
+
+ \input{tikz}
+ \usetikzlibrary
+ [commutative-diagrams]
+
+ \tikzpicture[codi]
+ % diagram here
+ \endtikzpicture
+ \bye
+ \end{lstlisting}
+ \end{subfigure}
+ \hfill
+ \begin{subfigure}{\marginparwidth}
+ \caption*{\ConTeXt\ (\TikZ\ library)}
+ \begin{lstlisting}[gobble=8]
+
+ \usemodule[tikz]
+ \usetikzlibrary
+ [commutative-diagrams]
+ \starttext
+ \starttikzpicture[codi]
+ % diagram here
+ \stoptikzpicture
+ \stoptext
+ \end{lstlisting}
+ \end{subfigure}
+ \hfill
+ \begin{subfigure}{\marginparwidth}
+ \caption*{\LaTeX\ (\TikZ\ library)}
+ \begin{lstlisting}[gobble=8]
+ \documentclass{article}
+ \usepackage{tikz}
+ \usetikzlibrary
+ {commutative-diagrams}
+ \begin{document}
+ \begin{tikzpicture}[codi]
+ % diagram here
+ \end{tikzpicture}
+ \end{document}
+ \end{lstlisting}
+ \end{subfigure}
+ \end{adjustwidth}
+\end{figure}
+
+\begin{marginfigure}[0em]
+ % \caption*{\TikZ\ externalization}
+ \begin{lstlisting}[gobble=4]
+ \documentclass{article}
+
+ \usepackage
+ {commutative-diagrams}
+ % Or, equivalently:
+ %\usepackage{tikz}
+ %\usetikzlibrary
+ % {commutative-diagrams}
+
+ \usetikzlibrary{external}
+ \tikzexternalize
+ [prefix=tikzpics/]
+
+ \begin{document}
+ \begin{tikzpicture}[codi]
+ % diagram here
+ \end{tikzpicture}
+ \end{document}
+ \end{lstlisting}
+\end{marginfigure}
+
+A useful \TikZ\ feature exclusive to \LaTeX\ is
+\NiceURL
+ {externalization}
+ {http://texdoc.net/texmf-dist/doc/generic/pgf/pgfmanual.pdf\#page=607}.
+It is an effective way to boost processing times by (re)\-compiling figures as
+external files only when strictly necessary.
+
+A small expedient is necessary to use it with \CoDi: diagrams must be wrapped in
+\lstinline|tikzpicture| environments endowed with the \lstinline|/tikz/codi| key.
+
+On the side is an example saving the pictures in the \lstinline|./tikzpics/| folder
+to keep things tidy.
+
+\hfill$\therefore$\hfill\null
+
+Basic knowledge of \TikZ\ is assumed. A plethora of excellent
+resources exist, so no crash course on the matter will be improvised
+here.
+Higher proficiency is not necessary, though recommended:
+it will make \CoDi\ a pliable framework instead of a black box.
+\newpage
+\section{Quick tour}
+Objects are typeset using the \lstinline|\obj| macro.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\obj {X};
+\end{codi}
+\end{tcblisting}
+
+Almost every diagram is laid along a regular grid,
+so the customary tabular syntax of \TeX\ is recognized.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\obj {
+ A & B \\
+ C & D \\
+};
+\end{codi}
+\end{tcblisting}
+
+\CoDi\ objects are self-aware and clever enough to name themselves
+so you can comfortably refer to them.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\obj {\lim F};
+\draw (lim F) circle (4ex);
+\end{codi}
+\end{tcblisting}
+
+Morphisms are typeset using the \lstinline!\mor! macro.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\obj { A & B \\ };
+\mor A f:-> B;
+\end{codi}
+\end{tcblisting}
+
+Commutative diagrams exist to illustrate composition and commutation,
+so \CoDi\ allows arrow chaining and chain gluing.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\obj { A & B \\ C & D \\ };
+\mor A -> B -> D;
+\mor * -> C -> *;
+\end{codi}
+\end{tcblisting}
+
+These are the only two macros defined by \CoDi.
+
+There are more features, though.\\
+Read on if this caught your attention.
+\newpage
+\section{Alternatives}
+It is only fair to mutely offer a comparison with mainstream packages,
+showing idiomatic code to draw the same diagram.
+
+Let \NiceURL
+ {\Xy-pic}
+ {http://texdoc.net/texmf-dist/doc/generic/xypic/xyrefer.pdf\#page=1}
+set the bar with a \emph{verbatim} extract from its manual.
+
+% Well, I got to admit that among the three alternatives
+% Xy-pics was by far the best citizen. Mad props.
+
+\begin{filecontents*}{alternatives-xypic-pic.tex}
+\documentclass[12pt]{standalone}
+\usepackage{libertine}
+\usepackage{libertinust1math}
+\usepackage[all]{xy}
+\begin{document}
+\xymatrix{
+ U \ar@/_/[ddr]_y \ar[dr] \ar@/^/[drr]^x \\
+ & X \times_Z Y \ar[d]^q \ar[r]_p
+ & X \ar[d]_f \\
+ & Y \ar[r]^g & Z }
+\end{document}
+\end{filecontents*}
+
+\IfFileExists{alternatives-xypic-pic.pdf}{}{\immediate\write18{pdflatex alternatives-xypic-pic.tex}}
+
+\begin{tcblisting}{
+ commented snippet,
+ image comment={}{alternatives-xypic-pic.pdf},
+}
+\xymatrix{
+ U \ar@/_/[ddr]_y \ar[dr] \ar@/^/[drr]^x \\
+ & X \times_Z Y \ar[d]^q \ar[r]_p
+ & X \ar[d]_f \\
+ & Y \ar[r]^g & Z }
+\end{tcblisting}
+
+Here is an example adapted from \NiceURL
+ {\ttfamily\small pst-node}
+ {http://texdoc.net/texmf-dist/doc/generic/pst-node/pst-node-doc.pdf\#page=23}'s
+documentation.
+
+% I got really, really tired of pstricks subtle limitations.
+% auto-pst-pdf doesnt really work on externalized listings.
+% Ordinary compilation gotta pass through PS so it's tricky.
+% Furthermore it just breaks TikZ opacity unless you use PS.
+% Ain't nobody got time for that.
+
+\begin{filecontents*}{alternatives-pstnode-pic.tex}
+\documentclass[12pt]{standalone}
+\usepackage{libertine}
+\usepackage{libertinust1math}
+\usepackage{pstricks}
+\usepackage{pst-node}
+\begin{document}
+$ \psset{colsep=2.5em, rowsep=2em}
+ \begin{psmatrix}
+ U \\
+ & X\times_Z Y & X \\
+ & Y & Z
+ \psset{arrows=->, nodesep=3pt}
+ \everypsbox{\scriptstyle}
+ \ncline{1,1}{2,2}
+ \ncarc[arcangle=-10]{1,1}{3,2}_{y}
+ \ncarc[arcangle=10]{1,1}{2,3}^{x}
+ \ncline{2,2}{3,2}>{q}
+ \ncline{2,2}{2,3}_{p}
+ \ncline{2,3}{3,3}<{f}
+ \ncline{3,2}{3,3}^{g}
+ \end{psmatrix}$
+\end{document}
+\end{filecontents*}
+
+\IfFileExists{alternatives-pstnode-pic.pdf}{}{\immediate\write18{latex alternatives-pstnode-pic.tex && dvips alternatives-pstnode-pic.dvi && ps2pdf alternatives-pstnode-pic.ps}}
+
+\begin{tcblisting}{
+ commented snippet,
+ image comment={}{alternatives-pstnode-pic.pdf}
+}
+$ \psset{colsep=2.5em, rowsep=2em}
+ \begin{psmatrix}
+ U \\
+ & X\times_Z Y & X \\
+ & Y & Z
+ \psset{arrows=->, nodesep=3pt}
+ \everypsbox{\scriptstyle}
+ \ncline{1,1}{2,2}
+ \ncarc[arcangle=-10]{1,1}{3,2}_{y}
+ \ncarc[arcangle=10]{1,1}{2,3}^{x}
+ \ncline{2,2}{3,2}>{q}
+ \ncline{2,2}{2,3}_{p}
+ \ncline{2,3}{3,3}<{f}
+ \ncline{3,2}{3,3}^{g}
+ \end{psmatrix}$
+\end{tcblisting}
+
+Next one is refitted from the guide to \NiceURL
+ {\ttfamily\small\{tikz-cd\}}
+ {http://texdoc.net/texmf-dist/doc/latex/tikz-cd/tikz-cd-doc.pdf\#page=3}.
+
+% It seems that tikz-cd is overwriting some arrows.meta
+% global keys. I have no intention of investigating
+% so let's just isolate the problem.
+
+\begin{filecontents*}{alternatives-tikzcd-pic.tex}
+\documentclass[12pt]{standalone}
+\usepackage{libertine}
+\usepackage{libertinust1math}
+\usepackage{tikz}
+\usetikzlibrary{cd}
+\begin{document}
+\begin{tikzcd}[column sep=scriptsize, row sep=scriptsize]
+ U
+ \arrow[drr, bend left=10, "x"]
+ \arrow[ddr, bend right=10, swap, "y"]
+ \arrow[dr] & & \\
+ & X \times_Z Y \arrow[r, swap, "p"] \arrow[d, "q"]
+ & X \arrow[d, swap, "f"] \\
+ & Y \arrow[r, "g"]
+ & Z
+\end{tikzcd}
+\end{document}
+\end{filecontents*}
+
+\IfFileExists{alternatives-tikzcd-pic.pdf}{}{\immediate\write18{pdflatex alternatives-tikzcd-pic.tex}}
+
+\begin{tcblisting}{
+ commented snippet,
+ image comment={}{alternatives-tikzcd-pic.pdf},
+}
+\begin{tikzcd}[column sep=scriptsize, row sep=scriptsize]
+ U
+ \arrow[drr, bend left=10, "x"]
+ \arrow[ddr, bend right=10, swap, "y"]
+ \arrow[dr] & & \\
+ & X \times_Z Y \arrow[r, swap, "p"] \arrow[d, "q"]
+ & X \arrow[d, swap, "f"] \\
+ & Y \arrow[r, "g"]
+ & Z
+\end{tikzcd}
+\end{tcblisting}
+
+Finally, \textbf{\CoDi}.
+
+\begin{tcblisting}{snippet}
+\begin{codi}[tetragonal]
+ \obj { |(pb)| X \times_Z Y & X \\
+ Y & Z \\ };
+ \obj [above left=of pb] {U};
+
+ \mor[swap] pb p:-> X f:-> Z;
+ \mor * q:-> Y g:-> *;
+
+ \mor U -> pb;
+ \mor :[bend left=10] * x:-> X;
+ \mor[swap]:[bend right=10] * y:-> Y;
+\end{codi}
+\end{tcblisting}
+\newpage
+\section{Syntax: objects}
+The first of the two macros that \CoDi\ offers is \lstinline|\obj|.
+It is polymorphic and can draw both single objects and layouts.
+
+\begin{lstlisting}
+\obj@opt@ <object options> @/opt@{<math>};(@
+ \marginpar{\scriptsize {\color{orange!80!black}Orange fragments} are optional.}@)
+\obj@opt@ <layout options> @/opt@{<layout>};
+\end{lstlisting}
+
+Layouts are described using the customary \TeX\ tabular syntax.
+
+\begin{lstlisting}
+<layout> := (@\itshape\underbar{<row> <row separator>}@)(@
+ \marginpar{\scriptsize \underbar{Underlined fragments} can repeat one or more times.}@)
+<row> := <cell> (@\itshape\color{orange!80!black}\underbar{<cell separator> <cell>}@)
+<row separator> := \\ @opt@[<length>]@/opt@
+<cell> := @opt@|<object options>| @/opt@<math>
+<cell separator> := & @opt@[<length>]@/opt@
+\end{lstlisting}
+
+The discretionary options syntax is analogous to standard \TikZ\ nodes and
+matrices, respectively.
+
+\begin{lstlisting}
+<object options> := (@\itshape\color{orange!80!black}\underbar{[object keylist]}@) @opt@(<name>) at (<coordinate>)@/opt@
+<layout options> := (@\itshape\color{orange!80!black}\underbar{[layout keylist]}@) @opt@(<name>) at (<coordinate>)@/opt@
+\end{lstlisting}
+
+\hfill$\therefore$\hfill\null
+
+Nothing of the given syntax is specific to \CoDi.
+In fact, \lstinline|\obj| can draw both single objects and layouts
+by behaving like the standard \TikZ\ macros
+\lstinline|\node| and \lstinline|\matrix| respectively.
+
+Furthermore, layouts content is specified using the common \TeX\
+tabular syntax.
+The only catch is that row and column separators are always mandatory.
+
+Here is a kitchen sink that includes custom spacing:
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}[square=3em]
+\obj {
+ A & B &[1em] C \\
+ D & E & F \\[-1em]
+ G & H & I \\
+};
+\end{codi}
+\end{tcblisting}
+
+Here is another one that includes custom options:
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}[square=3em]
+\obj [red] {
+ A & |[blue]| B & C \\
+};
+\end{codi}
+\end{tcblisting}
+
+A standard feature inherited from \TikZ\ worth a mention
+is the ability to name a layout and refer to cells
+by their row/column index pairs.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}[square=3em]
+\obj (M) { A & A \\ A & A \\ };
+\node [draw=red, shape=circle, minimum size=2em] at (M-1-2) {};
+\node [draw=blue, shape=circle, minimum size=2em] at (M-2-1) {};
+\end{codi}
+\end{tcblisting}
+\newpage
+\section{Syntax: morphisms}
+\begingroup\tcbset{trim/.default={3 and -1}}
+
+The second and last macro that \CoDi\ offers is \lstinline|\mor|.
+It can draw single or chained morphisms.
+
+\begin{lstlisting}
+\mor@opt@ <chain options> @/opt@<object>(@
+ \itshape\underbar{\textvisiblespace<morphism>\textvisiblespace<object>}@);(@
+ \marginpar{\scriptsize Whitespace marked as \textvisiblespace\ is mandatory.}@)
+\end{lstlisting}
+
+Source and target objects are referred to by their name.
+
+\begin{lstlisting}
+<object> := @nws@(<name>)@/nws@ (@
+ \marginpar{\scriptsize {\color{blue!80!black}Blue fragments} can be either enclosed in the shown delimiters, or a \TeX\ group (not idiomatic), or simply devoid of whitespace.}@)
+\end{lstlisting}
+
+Morphisms consist of one or more optional labels and an arrow.
+
+\begin{lstlisting}
+<morphism> := @opt@<labels> : @/opt@<arrow>
+<labels> := @nws@"<math>"@/nws@ XOR (@\underbar{[{\itshape "<math>", <label keylist>}]}@) (@
+ \marginpar{\scriptsize Alternatives are separated by $\vert$s.}@)
+<arrow> := @nws@[<arrow keylist>]@/nws@
+\end{lstlisting}
+% <labels> := @nws@"<math>"@/nws@ XOR @nws@[<label keylist>]@/nws@ XOR (@\underbar{[{\itshape <label keylist>}]}@)
+
+Global options can be given to both labels and arrows.
+
+\begin{lstlisting}
+<chain options> := [<label keylist>] @opt@: [<arrow keylist>]@/opt@
+\end{lstlisting}
+
+\hfill$\therefore$\hfill\null
+
+These rules allow for a label syntax that sprouts gracefully
+from the simplest to the most complex case.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\obj { A & B & C \\ F & E & D \\ };
+\mor A -> B;
+\mor B f:-> C;
+\mor C \hat g:-> D;
+\mor D "h i":-> E;
+\mor E ["L", above]:-> F;
+\mor F ["m", near start]["n", swap]["o", near end]:-> A;
+\end{codi}
+\end{tcblisting}
+
+The same holds for arrow syntax.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\obj { A & B & C \\ };
+\mor A -> B;
+\mor B [>-, dashed] C;
+\end{codi}
+\end{tcblisting}
+
+Global options can be used to minimize local ones
+and keep the code terse and readable.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\obj { A & B & C \\ F & E & D \\ };
+\mor [swap]:[bend left] B f:-> C g:>-> D h:>- E i:- B;
+\mor :[bend right] E x:-> F y:>-> A z:>- B;
+\mor [mid] B m:-> D;
+\end{codi}
+\end{tcblisting}
+
+\endgroup
+\newpage
+\section{Names}
+As you'll have guessed by now, objects name themselves.
+
+The process happens in three steps:
+\begin{itemize}[nosep]
+ \item expand tokens;
+ \item replace characters;
+ \item apply name, overwriting if necessary.
+\end{itemize}
+
+Each one can be configured in any \CoDi\ scope with the keys.
+
+While you're getting acquainted with the process
+you can use the \lstinline|/codi/prompter| key to
+display labels with generated names.
+
+\begin{tcblisting}{snippet}
+\begin{codi}[prompter]
+ \obj{ A & \lim A \\ };
+ \mor A f:-> (lim A);
+\end{codi}
+\end{tcblisting}
+\newpage
+\subsection{Names: shortcuts}
+\begingroup\tcbset{trim/.default={3 and -1}}
+
+Two special labels exist: {\ttfamily *} and {\ttfamily +}.
+
+As a source, {\ttfamily *} evaluates to the head of the previous chain.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\obj [square=2.5em] { A & B & C & \phantom{D} \\ };
+\mor B -> C;
+\mor * -> A;
+\end{codi}
+\end{tcblisting}
+
+As a target, {\ttfamily *} evaluates to the tail of the previous chain.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\obj [square=2.5em] { \phantom{A} & B & C & D \\ };
+\mor B -> C;
+\mor D -> *;
+\end{codi}
+\end{tcblisting}
+
+The natural use case for {\ttfamily *} is chain gluing.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\obj [square=2.5em] { A & B \\ D & C \\ };
+\mor A -> B -> C;
+\mor * -> D -> *;
+\end{codi}
+\end{tcblisting}
+
+As a source, {\ttfamily +} evaluates to the tail of the previous chain.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\obj [square=2.5em] { \phantom{A} & B & C & D \\ };
+\mor B -> C;
+\mor + -> D;
+\end{codi}
+\end{tcblisting}
+
+As a target, {\ttfamily +} evaluates to the head of the previous chain.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\obj [square=2.5em] { A & B & C & \phantom{D} \\ };
+\mor B -> C;
+\mor A -> +;
+\end{codi}
+\end{tcblisting}
+
+The natural use case for {\ttfamily +} is chain extension.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\obj [square=2.5em] { A & B & C & D \\ };
+\mor B -> C;
+\mor A -> + -> D;
+\end{codi}
+\end{tcblisting}
+
+The meanings of {\ttfamily *} and {\ttfamily +} swap on opposite chains.
+
+Chain extension can be obtained using {\ttfamily *}.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\obj [square=2.5em] { A & B & C & D \\ };
+\mor B <- C;
+\mor D -> * -> A;
+\end{codi}
+\end{tcblisting}
+
+Chain gluing can be obtained using {\ttfamily +}.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\obj [square=2.5em] { A & B \\ D & C \\ };
+\mor A <- B <- C;
+\mor + -> D -> +;
+\end{codi}
+\end{tcblisting}
+
+\endgroup
+\newpage
+\subsection{Names: expansion}
+The expansion behaviour of the naming routine can be configured
+inside any \CoDi\ scope using the \lstinline!expand! key.
+
+\begin{lstlisting}
+/codi/expand = none | once | full
+\end{lstlisting}
+
+The three available settings correspond to different degrees of expansion.
+A side by side comparison completely illustrates their meanings.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\def\B{Z}
+\def\A{\B}
+\obj{ |[expand=none]| \A & % name: A (default)
+ |[expand=once]| \A & % name: B
+ |[expand=full]| \A \\ }; % name: Z
+\mor A -> B -> Z;
+\end{codi}
+\end{tcblisting}
+
+\hfill$\therefore$\hfill\null
+
+The default behaviour is to avoid expansion in compliance with the principle
+that \emph{names should be predictable from the \emph{literal} code}.
+Furthermore, it is seldom wise to liberally expand tokens.
+
+There are circumstances in which it is useful to perform token expansion,
+though. A useful application is procedural drawing.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\foreach [count=\r] \l in {A,B,C}
+ \foreach [count=\c] \n in {n-1,n,n+1}
+ \obj [expand=full] at (3em*\c,-2em*\r) {\l_{\n}};
+\mor (A_{n}) -> (B_{n+1}) -> (C_{n}) -> (B_{n-1}) -> (A_{n});
+\end{codi}
+\end{tcblisting}
+
+In some cases finer control is needed. For instance, full expansion
+yields unpractical results when parametrizing macros.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\foreach [count=\c] \m in {\lim,\prod}
+ \obj [expand=full] at (4em*\c,0) {\m F};
+\mor (protect mathop {relax kern z@ mathgroup
+ symoperators lim}nmlimits@ F)
+ -> (DOTSI prodop slimits@ F);
+\end{codi}
+\end{tcblisting}
+
+This explains why a setting to force a single expansion exists.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\foreach [count=\c] \m in {\lim,\prod}
+ \obj [expand=once] at (4em*\c,0) {\m F};
+\mor (lim F) -> (prod F);
+\end{codi}
+\end{tcblisting}
+\newpage
+\subsection{Names: replacement}
+The character replacement behaviour of the naming routine can be configured
+inside any \CoDi\ scope using various keys.
+
+\begin{lstlisting}
+/codi/replace character = <character> with <character>
+/codi/replace charcode = <charcode> with <character>
+/codi/remove characters = <characters>
+/codi/remove character = <character>
+/codi/remove charcode = <charcode>
+\end{lstlisting}
+
+You can set up a replacement for any character, using the character code for
+the hardest to type, like {\ttfamily \textvisiblespace} or {\ttfamily \textbackslash}.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}[tetragonal]
+\obj{ |[replace character=F with G]| \lim F & % name: lim G
+ |[remove character=F]| \lim F \\ % name: lim
+ |[replace charcode=92 with /]| \lim F & % name: /lim F
+ |[remove charcode=32]| \lim F \\ }; % name: limF
+\mor (lim G) -> (lim) -> (/lim F) -> (limF);
+\end{codi}
+\end{tcblisting}
+
+\hfill$\therefore$\hfill\null
+
+The default behaviour is removal of the minimal set of universally annoying%
+\footnote{The difficult part is not creating the names but having to type them.}
+characters: {\ttfamily (),.:} have special meanings to \TikZ\ while
+{\ttfamily \textbackslash} is impossible to type by ordinary means, so they're \emph{kaput}.
+
+Each one can be restored by replacing it with itself. Don't.
+
+Another egregiously bad idea is replacing characters with spaces.
+It's tempting because it solves a somewhat common edge case.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}[tetragonal]
+\obj{ \beta & F & b\eta \\ };
+\mor F -> beta;
+\end{codi}
+\end{tcblisting}
+
+Since characters in names are literal, this causes whitespace
+duplication and names become inaccessible by ordinary means.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}[tetragonal]
+\obj [replace charcode=92 with \space]
+ { \beta & b\eta & \beta \eta \\ };
+\mor beta -> (b eta) -> (beta \space eta);
+\end{codi}
+\end{tcblisting}
+
+The wise solution is writing better code.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}[tetragonal]
+\obj{ \beta & F & b \eta \\ };
+\mor F -> beta;
+\end{codi}
+\end{tcblisting}
+
+\newpage
+\subsection{Names: overwriting}
+The name overwriting behaviour of the naming routine can be configured
+inside any \CoDi\ scope using the \lstinline!overwrite! key.
+
+\begin{lstlisting}
+/codi/overwrite = false | alias | true
+\end{lstlisting}
+
+The three available settings correspond to different naming priorities.
+A side by side comparison completely illustrates their meanings.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\obj{ |[overwrite=false] (A')| A & % names: A' (default)
+ |[overwrite=alias] (B')| B & % names: B', B
+ |[overwrite=true] (C')| C \\ }; % names: C
+\mor A' -> B';
+\mor B -> C;
+\end{codi}
+\end{tcblisting}
+
+\hfill$\therefore$\hfill\null
+
+The default behaviour avoids overwriting explicit labels in order
+to give you a simple means of naming conflict resolution.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}[tetragonal]
+\obj { A & |(A')| A \\
+ |(Z')| Z & Z \\ };
+\mor A -> A';
+\mor Z -> Z';
+\end{codi}
+\end{tcblisting}
+
+Sometimes you might want an object to have both a literal and a
+semantic alias.
+
+\begin{tcblisting}{snippet, trim}
+\begin{codi}
+\obj [overwrite=alias] { A & |(center)| B & |(right)| C \\ };
+\mor A -> B;
+\mor center -> right;
+\end{codi}
+\end{tcblisting}
+
+The hard overwriting behaviour ignores any label except generated
+ones; it exists for completeness and debugging purposes.
+\newpage
+\section{Styles: scopes}
+\CoDi\ structures diagrams into five layers implemented with \TikZ.
+
+\begin{center}
+\begin{tabular}{ccc}
+ \toprule
+ \CoDi's & represents an & using \TikZ's \\
+ \midrule
+ \lstinline|diagram| & (commutative) diagram & \lstinline|tikzpicture| \\
+ \lstinline|layout| & arrangement of vertices & \lstinline|matrix| \\
+ \lstinline|object| & vertex & \lstinline|node| \\
+ \lstinline|arrow| & edge between vertices & \lstinline|edge| \\
+ \lstinline|label| & label of an edge & \lstinline|node| \\
+ \bottomrule
+\end{tabular}
+\end{center}
+
+Each layer can be styled using \TikZ\ keys.
+
+Each layer possesses a default style:
+\begin{lstlisting}
+/codi/every diagram
+/codi/every layout
+/codi/every object
+/codi/every arrow
+/codi/every label
+\end{lstlisting}
+
+You can customize them using \TikZ\ key handlers, \eg
+\begin{lstlisting}
+/codi/every label/.append style={red}
+\end{lstlisting}
+
+Each layer possesses a library of commonplace styles:
+\begin{lstlisting}
+/codi/diagrams/
+/codi/layouts/
+/codi/objects/
+/codi/arrows/
+/codi/labels/
+\end{lstlisting}
+
+They are the proper place to find styles and define you own:
+\begin{lstlisting}
+/codi/arrows/fat/.style={ultra thick}
+\end{lstlisting}
+
+Fully scoping keys is usually unnecessary, as \CoDi\ searches for keys
+in the library of the layer it's in before falling back to \TikZ\ default
+search algorithm. Here's some meta code demonstrating this:
+
+\begin{lstlisting}
+\begin{codi}[<diagram keylist>]
+ \obj [<layout keylist>] { |[<object keylist>]| a & b \\ };
+ \obj [<object keylist>] {x};
+ \mor [<label keylist>]:[<arrow keylist>]
+ a [<label keylist>]:[<arrow keylist>] b;
+\end{codi}
+\end{lstlisting}
+
+\newpage
+\section{Styles: diagrams}
+\tikzset{
+ versor/.style={ultra thick, black, ->, >=latex, line cap=round},
+ checkers/.style={fill=teal!15},
+ measure/.style={decorate, decoration={brace, amplitude=4pt, aspect=#1}},
+ measure/.default=0.5,
+ label/.style={font=\scriptsize, outer sep=.5em, inner sep=0sp},
+ dots/.style={fill=teal!50},
+ label style/.style={label, outer sep=.2em, font={\ttfamily\tiny}},
+ anchor style/.style={inner sep=0sp, outer sep=0sp, anchor=center},
+ pin style/.style={pin distance=.75em, pin edge={thin, black, shorten <=3pt}, label style}
+}
+
+\begin{marginfigure}[0cm]
+ \begin{subfigure}{\marginparwidth}
+ \begin{tikzpicture}[codi, tetragonal=base {0.2\marginparwidth} height {0.2*1.618\marginparwidth}]
+ % drawing area
+ \clip (-2.5,-2.5) rectangle (2.5,2.5);
+ % checkers and dots
+ \foreach \i in {-3, ..., 2} \foreach \j in {-3, ..., 2} {
+ \pgfmathparse{int(1+abs(\i)+abs(\j))}
+ \ifodd\pgfmathresult \fill [checkers] (\i,\j) rectangle +(1,1);\fi
+ \pgfmathparse{ \i == sign(\i) && \j == sign(\j) && abs(\i) != -abs(\j) }
+ \fill [fill/.expanded={\ifnum\pgfmathresult=1 red\else teal!50\fi}]
+ (\i,\j) circle (2pt);
+ }
+ % base circle
+ \fill [red, opacity=0.1] (1,1) -- (-1,1) -- (-1,-1) -- (1,-1) -- cycle;
+ % width marker
+ \draw
+ [measure, decoration=mirror, yshift=-3pt]
+ (0,0) -- (1,0)
+ node [label style, midway, below, yshift=-3pt] {base};
+ % height marker
+ \draw
+ [measure=0.7, xshift=-3pt]
+ (0,0) -- (0,1)
+ node [label style, pos=0.7, left, xshift=-3pt] {height};
+ % origin
+ \coordinate (O) at (0,0);
+ \node at (O) [anchor style, pin={[pin style]-135:{O}}] {};
+ % neighbours
+ \node [anchor style, pin={[pin style]-45:{above=of O}}, above=of O] {};
+ \node [anchor style, pin={[pin style]60:{above left=of O}}, above left=of O] {};
+ \node [anchor style, pin={[pin style]90:{left=1 of O}}, left=1 of O] {};
+ \node [anchor style, pin={[pin style]120:{below right=2 of O}}, below right=2 of O] {};
+ \node [anchor style, pin={[pin style]-45:{below left=1 and 2 of O}}, below left=1 and 2 of O] {};
+ % versors
+ \draw [versor] (0,0) -- (1,0);
+ \draw [versor] (0,0) -- (0,1);
+ \end{tikzpicture}
+ \subcaption*{Tetragonal}\bigskip
+ \end{subfigure}
+ \begin{subfigure}{\linewidth}
+ \begin{tikzpicture}[codi, hexagonal=horizontal side {0.4*\marginparwidth} angle 60]
+ % drawing area
+ \clip (-2.5,-2.5) rectangle (2.5,2.5);
+ % checkers and dots
+ \foreach \i in {-4, ..., 2} \foreach \j in {-3, ..., 2} {
+ \pgfmathparse{int(abs(\i)+abs(\j))}
+ \ifodd\pgfmathresult\else \fill [checkers] (\i,\j) -- +(1,1) -- +(2,0);\fi
+ \pgfmathsetmacro\dotsize{isodd(\pgfmathresult)?1:2}
+ \fill [fill/.expanded={\ifnum\pgfmathresult=2 red\else teal!50\fi}]
+ (\i,\j) circle (\dotsize pt);
+ }
+ % base circle
+ \fill [red, opacity=0.1]
+ (2,0) -- (0,2) -- (-2,0) -- (0,-2) -- cycle;
+ % side marker
+ \draw [measure, decoration=mirror, yshift=-3pt]
+ (0,0) -- (2,0)
+ node [label style, midway, below, yshift=-3pt] {side};
+ % angle marker
+ \draw (0.66*1.7cm, 0)
+ arc (0:30:0.66*1.7cm)
+ node [label style, above right] {angle}
+ arc (30:60:0.66*1.7cm);
+ % origin
+ \coordinate (O) at (0,0);
+ \node at (O) [anchor style, pin={[pin style]-135:{O}}] {};
+ % neighbours
+ \node [anchor style, pin={[pin style]-45:{above=of O}}, above=of O] {};
+ \node [anchor style, pin={[pin style]60:{above left=of O}}, above left=of O] {};
+ \node [anchor style, pin={[pin style]90:{left=1 of O}}, left=1 of O] {};
+ \node [anchor style, pin={[pin style]120:{below right=2 of O}}, below right=2 of O] {};
+ \node [anchor style, pin={[pin style]-45:{below left=1 and 2 of O}}, below left=1 and 2 of O] {};
+ % versors
+ \draw [versor] (0,0) -- (1,0);
+ \draw [versor] (0,0) -- (0,1);
+ \end{tikzpicture}
+ \subcaption*{Hexagonal (horizontal)}\bigskip
+ \end{subfigure}
+ \begin{subfigure}{\linewidth}
+ \begin{tikzpicture}[codi, hexagonal=vertical side {0.2*\marginparwidth*2/sqrt(3)} angle 60]
+ % drawing area
+ \clip (-2.5,-2.5) rectangle (2.5,2.5);
+ % checkers and dots
+ \foreach \i in {-3, ..., 2} \foreach \j in {-4, ..., 3} {
+ \pgfmathparse{int(1+abs(\i)+abs(\j))}
+ \ifodd\pgfmathresult \fill [checkers] (\i,\j) -- +(1,1) -- +(0,2);\fi
+ \pgfmathsetmacro\dotsize{isodd(\pgfmathresult)?2:1}
+ \fill [fill/.expanded={\ifnum\pgfmathresult=3 red\else teal!50\fi}]
+ (\i,\j) circle (\dotsize pt);
+ }
+ % base circle
+ \fill [red, opacity=0.1] (2,0) -- (0,2) -- (-2,0) -- (0,-2) -- cycle;
+ % side marker
+ \draw [measure=0.3, xshift=-3pt]
+ (0,0) -- (0,2) node [label style, pos=0.3, left, xshift=-3pt] {side};
+ % angle marker
+ \draw
+ ([shift=(30:0.66*0.982cm)]0,0)
+ arc (30:60:0.66*0.982cm)
+ node [label style, above right] {angle}
+ arc (60:90:0.66*0.982cm);
+ % origin
+ \coordinate (O) at (0,0);
+ % neighbours
+ % versors
+ \draw [versor] (0,0) -- (1,0);
+ \draw [versor] (0,0) -- (0,1);
+ \end{tikzpicture}
+ \subcaption*{Hexagonal (vertical)}\bigskip
+ \end{subfigure}
+ %% \caption*{Diagram grid examples}
+\end{marginfigure}
+
+Diagrams can be laid over regular grids:
+
+\begin{lstlisting}
+/codi/diagrams/tetragonal=base <length> height <length>
+ (@\hfill@) (default: base 4.5em height 2.8em)
+\end{lstlisting}
+
+\begin{lstlisting}
+/codi/diagrams/hexagonal=<direction> side <length> angle <angle>
+ (@\hfill@) (default: horizontal side 4.5em angle 60)
+\end{lstlisting}
+
+When one of these keys is used
+\begin{itemize}[noitemsep]
+ \item the versors of the \NiceURL{coordinate system}{http://texdoc.net/texmf-dist/doc/generic/pgf/pgfmanual.pdf\#page=357} are changed,
+ \item the \NiceURL{node positioning}{http://texdoc.net/texmf-dist/doc/generic/pgf/pgfmanual.pdf\#page=229} is set up to lay them on grid,
+ \item and the corresponding key will be applied to all layouts.
+\end{itemize}
+
+The pictures show the key parameters, versors, and a unitary grid.
+
+This setup allows you to mix coordinates and
+relative positioning keys to arrange objects.
+
+As usual, relative positioning keys can accept two components, a radius,
+or nothing at all (which defaults to a certain radius).
+
+When using a radius (or defaulting to $1$)
+the tetragonal grid uses Manhattan distance to
+lay objects along concentric rectangles.
+
+When using a radius (or defaulting to $2$)
+the hexagonal grid%
+\footnote{which in truth is built upon a tetragonal grid}
+uses Chebyshev distance to
+lay objects along concentric rhombi.
+
+To clarify, a few relative positioning keys are drawn along
+with red zones displaying the default radii around the origins.
+\newpage
+\section{Styles: layouts}
+Layouts can be laid over regular grids:
+
+\begin{lstlisting}
+/codi/layouts/tetragonal=base <length> height <length>
+ (@\hfill@) (default: base 4.5em height 2.8em)
+\end{lstlisting}
+
+\begin{lstlisting}
+/codi/layouts/hexagonal=<direction> side <length> angle <angle>
+ (@\hfill@) (default: horizontal side 4.5em angle 60)
+\end{lstlisting}
+
+When one of these keys is used the layout columns and rows will be
+spaced and offset in order to reproduce the grids given by diagram styles.
+
+\begin{tcblisting}{snippet, trim={2 and -1}}
+\begin{codi}
+ \obj [hexagonal=horizontal side 1.5em angle 60] {
+ A & B & \\
+ C & D & E \\
+ F & G & \\
+ };
+\end{codi}
+\end{tcblisting}
+
+\begin{tcblisting}{snippet, trim={2 and -1}}
+\begin{codi}
+ \obj [hexagonal=vertical side 1.5em angle 60] {
+ A & C & F \\
+ B & D & G \\
+ & E & \\
+ };
+\end{codi}
+\end{tcblisting}
+
+Note that \emph{each row must have the same number of cells}%
+\footnote{this is different from the behaviour of, say, tables}
+or the spacing will be incorrect.
+\newpage
+\section{Styles: objects}
+No styles are available at the moment.
+\newpage
+\section{Styles: arrows}
+\begin{lstlisting}
+/codi/arrows/crossing over
+/codi/arrows/crossing over/clearance=<length> (@\hfill@) (default: 0.5ex)
+/codi/arrows/crossing over/color=<color> (@\hfill@) (default: white)
+\end{lstlisting}
+
+This key a provides the configurable illusion of an arrow passing
+over a \emph{previously drawn} one.
+
+\begin{tcblisting}{snippet, trim={3 and -1}}
+\begin{codi}[tetragonal=base 4.5em height 1em]
+\obj { A & B \\ D & C \\};
+\mor A -> C;
+\mor :[crossing over] D -> B;
+\end{codi}
+\end{tcblisting}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\begin{lstlisting}
+/codi/arrows/slide=<length>
+\end{lstlisting}
+
+This key slides an arrow backward (negative) and forward (positive) along its direction of the given length.
+
+\begin{tcblisting}{snippet, trim={3 and -1}}
+\begin{codi}[tetragonal=base 4.5em height 1em]
+\obj { A & B \\ C & D \\ E & F \\ };
+\mor :[slide=-.3em, red] A -> B;
+\mor C -> D;
+\mor :[slide=+.3em, blue] E -> F;
+\end{codi}
+\end{tcblisting}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\begin{lstlisting}
+/codi/arrows/shove=<length>
+\end{lstlisting}
+
+This key shoves an arrow to the left (negative) and to the right (positive) with respect to its direction of the given length.
+
+\begin{tcblisting}{snippet, trim={3 and -1}}
+\begin{codi}
+\obj { A & B \\ };
+\mor :[shove=-.3em, red] A -> B;
+\mor A -> B;
+\mor :[shove=+.3em, blue] A -> B;
+\end{codi}
+\end{tcblisting}
+\newpage
+\section{Styles: labels}
+\begin{lstlisting}
+/codi/labels/mid
+\end{lstlisting}
+
+This key places a label in the middle of an arrow.
+
+\begin{tcblisting}{snippet, trim={3 and -1}}
+\begin{codi}
+\obj { A & B \\ };
+\mor [mid] A f:-> B;
+\end{codi}
+\end{tcblisting}
+\newpage
+\section{Gallery}
+% \makeatletter
+% \newcommand\prev{\the\tikz@lastxsaved,\the\tikz@lastysaved}
+% \makeatother
+
+The remainder of the text is just commented examples.
+
+\clearpage
+
+\subsection{Snake}
+
+\begin{tcblisting}{gallery}
+\begin{codi}[tetragonal]
+ \obj{ & \ker a & \ker b & \ker c & \\
+ & A & B & C & 0 \\
+ |(0')| 0 & A' & B' & C' & \\
+ & \coker a & \coker b & \coker c & \\ };
+
+ \mor (ker a) -> (ker b) -> (ker c);
+ \mor (coker a) -> (coker b) -> (coker c);
+ \mor A f :-> B g :-> C -> 0;
+ \mor 0' -> A' f':-> B' g':-> C';
+
+ \mor[near start] (ker a) -> A a:-> A' -> (coker a);
+ \mor[near start] (ker b) -> B b:-> B' -> (coker b);
+ \mor[near start] (ker c) -> C c:-> C' -> (coker c);
+
+ \draw[/codi/arrows/crossing over, ->, rounded corners, >=stealth]
+ (ker c) -- ++( 0.6,0) -- ++(0,-1.55)
+ -- ++(-3.2,0) -- ++(0,-1.45) -- (coker a);
+\end{codi}
+\end{tcblisting}
+
+\clearpage
+
+\subsection{The fourth associahedron}
+
+\begin{tcblisting}{gallery}
+\begin{codi}
+% From the LaTeX preamble:
+% \usepackage{newunicodechar}
+% \newunicodechar{ı}{\mathbf 1}
+% \newunicodechar{×}{\otimes}
+
+ \foreach [count=\n] \o in {
+ ((w×x)×y)×x,
+ (w×(x×y))×x,
+ w×((x×y)×x),
+ w×(x×(y×x)),
+ (w×x)×(y×x)
+ } \obj (\n) at (72*\n:7em) {\o};
+
+ \mor 1 "a_{w,x,y}×ı_z": -> 2
+ "a_{w,x×y,z}": -> 3
+ "ı_w×a_{x,y,z}": -> 4;
+ \mor * "a_{w×x,y,z}": -> 5
+ "a_{w,x,y×z}": -> *;
+\end{codi}
+\end{tcblisting}
+
+\clearpage
+
+\subsection{Pullback \& pushout}
+
+\begin{tcblisting}{gallery}
+\begin{codi}[hexagonal]
+ \obj{ |(pb)| A \times_Z B & B \\
+ A & Z \\ };
+ \obj[above left=of pb] {Q};
+
+ \mor[swap] pb p_1:-> A f:-> Z;
+ \mor * p_2:-> B g:-> *;
+
+ \mor[swap]:[bend right] Q q_1:-> A;
+ \mor :[bend left] * q_2:-> B;
+ \mor [mid]:[dashed] * u:-> pb;
+\end{codi}
+\end{tcblisting}
+
+\begin{tcblisting}{gallery}
+\begin{codi}[hexagonal]
+ \obj{ Z & B \\
+ A & |(po)| A \sqcup_Z B \\ };
+ \obj[below right=of po] {Q};
+
+ \mor[swap] Z f:-> A i_1:-> po;
+ \mor * g:-> B i_2:-> *;
+
+ \mor[swap]:[bend right] A j_1:-> Q;
+ \mor :[bend left] B j_2:-> *;
+ \mor [mid]:[dashed] po u:-> *;
+\end{codi}
+\end{tcblisting}
+
+\clearpage
+
+\subsection{Complexes sequence}
+
+\begin{tcblisting}{gallery}
+\begin{codi}
+ \obj (M) { & \vdots & \vdots & \vdots & \\
+ 0 & A_{n+1} & B_{n+1} & C_{n+1} & 0 \\
+ 0 & A_{n} & B_{n} & C_{n} & 0 \\
+ 0 & A_{n-1} & B_{n-1} & C_{n-1} & 0 \\
+ & \vdots & \vdots & \vdots & \\ };
+
+ \foreach \n/\row in {n+1/2, n/3, n-1/4}
+ \mor (M-\row-1) -> (A_{\n}) "\alpha_{\n}":-> (B_{\n})
+ "\beta_{\n}":-> (C_{\n}) -> (M-\row-5);
+
+ \foreach \l/\col/\q in {A/2/, B/3/', C/4/''}
+ \mor (M-1-\col) -> (\l_{n+1}) "\partial\q_{n+1}":-> (\l_{n})
+ "\partial\q_{n}" :-> (\l_{n-1}) -> (M-5-\col);
+\end{codi}
+\end{tcblisting}
+
+\clearpage
+
+\subsection{Braid}
+
+% TODO: there's a bug here. If one does \begin{codi}[ l/.style={bend left}
+% TODO: (note the space before l) then it's not recognized. Investigate.
+\begin{tcblisting}{gallery}
+\begin{codi}[l/.style={bend left}, r/.style={bend right} ]
+ \obj [ hexagonal=horizontal side 6em angle 45, remove characters=H_\{q+\} ] {
+ H_{q+2}(X) & H_{q+2}(X,Y) & H_{q+1}(Y,Z) & H_{q}(Z) \\
+ H_{q+2}(Y) & H_{q+2}(X,Z) & H_{q+1}(Y) & H_{q+1}(X,Z) \\
+ H_{q+2}(Y,Z) & H_{q+1}(Z) & H_{q+1}(X) & \\
+ };
+
+ \mor :[blue] 2Y -> 2X l,-> 2XY -> 1Y -> 1X;
+ \mor :[green] 2Y -> 2YZ r,-> 1Z -> 1Y -> 1YZ l,-> Z;
+ \mor :[cyan] 2X -> 2XZ -> 1Z r,-> 1X -> 1XZ -> Z;
+ \mor :[red] 2YZ -> 2XZ -> 2XY l,-> 1YZ -> 1XZ;
+\end{codi}
+\end{tcblisting}
+
+\clearpage
+
+\subsection{Hammock}
+
+\begingroup\catcode`~=12
+\begin{tcblisting}{gallery}
+\begin{codi}[x=4em, y=-3em, node distance=1 and 1,
+ sim/.style={sloped, auto,
+ edge node={node[every edge quotes][/velos/install quote
+ handler,"\sim", anchor=south, outer sep=-.15em]}
+ },
+ ~>/.style={->, sim},
+ <~/.style={<-, sim},
+ ../.style={line width=.25ex, dash pattern=on 0sp off .75ex, line cap=round},
+ remove characters=_\{\},
+ expand=full,
+ ]
+
+ \foreach [count=\c] \col in {1, 2, 3, n}
+ \foreach [count=\r] \row in {K_{\col}, C_{0\col}, \vdots, C_{m\col}, L_{\col}}
+ \obj [name/.expanded={\ifnum\r=3 vdots\col\fi}] at (\c,\r) {\row};
+
+ \obj [left=of vdots1] {X};
+ \obj [right=of vdotsn] {Y};
+
+ \foreach \col in {1, 2, 3, n}
+ \mor (K\col) ~> (C0\col) ~> (vdots\col) ~> (Cm\col) ~> (L\col);
+
+ \foreach \row in {K, C0, Cm, L} {
+ \mor (\row1) -> (\row2) <~ (\row3) .. (\row n);
+ \mor X <~ + -> Y;
+ }
+\end{codi}
+\end{tcblisting}
+\endgroup
+
+
+% \input{test}
+
+\end{document}
diff --git a/graphics/pgf/contrib/commutative-diagrams/commutative-diagrams.sty b/graphics/pgf/contrib/commutative-diagrams/commutative-diagrams.sty
new file mode 100644
index 0000000000..63bfde447f
--- /dev/null
+++ b/graphics/pgf/contrib/commutative-diagrams/commutative-diagrams.sty
@@ -0,0 +1,14 @@
+%
+% CoDi: Commutative Diagrams for TeX
+% Copyright (c) 2015-2020 Paolo Brasolin <paolo.brasolin@gmail.com>
+% SPDX-License-Identifier: MIT
+%
+% This file is part of CoDi 1.0.0, released on 2020/06/06 under MIT license.
+%
+
+\RequirePackage{tikz}%[2013/12/13] % pgf version 3.0.0 required
+\ProvidesPackage{commutative-diagrams}[2020/06/06 1.0.0 CoDi: Commutative Diagrams for TeX]
+\usetikzlibrary{commutative-diagrams}
+\let\codi\kDRammaOpen
+\let\endcodi\kDRammaShut
+\endinput
diff --git a/graphics/pgf/contrib/commutative-diagrams/commutative-diagrams.tex b/graphics/pgf/contrib/commutative-diagrams/commutative-diagrams.tex
new file mode 100644
index 0000000000..f9ac654c65
--- /dev/null
+++ b/graphics/pgf/contrib/commutative-diagrams/commutative-diagrams.tex
@@ -0,0 +1,14 @@
+%
+% CoDi: Commutative Diagrams for TeX
+% Copyright (c) 2015-2020 Paolo Brasolin <paolo.brasolin@gmail.com>
+% SPDX-License-Identifier: MIT
+%
+% This file is part of CoDi 1.0.0, released on 2020/06/06 under MIT license.
+%
+
+\input tikz.tex
+% TODO: loading message
+\usetikzlibrary{commutative-diagrams}
+\let\codi\kDRammaOpen
+\let\endcodi\kDRammaShut
+\endinput
diff --git a/graphics/pgf/contrib/commutative-diagrams/kodi.sty b/graphics/pgf/contrib/commutative-diagrams/kodi.sty
new file mode 100644
index 0000000000..9443a2d8b0
--- /dev/null
+++ b/graphics/pgf/contrib/commutative-diagrams/kodi.sty
@@ -0,0 +1,60 @@
+%
+% CoDi: Commutative Diagrams for TeX
+% Copyright (c) 2015-2020 Paolo Brasolin <paolo.brasolin@gmail.com>
+% SPDX-License-Identifier: MIT
+%
+% This file is part of CoDi 1.0.0, released on 2020/06/06 under MIT license.
+%
+
+\RequirePackage{commutative-diagrams}
+
+\PackageWarningNoLine{kodi}{this package is only a compatibility layer
+to help you migrate from 'kodi' to 'commutative-diagrams'. It is NOT
+intended for production use. Please solve all other warnings and then
+switch to 'commutative-diagrams'}
+
+% TikZ keys: /kodi/**/* -> /codi/**/*
+
+\pgfkeys{
+ /handlers/.unknown/.code={%
+ \def\pgfkeysisdescendantof@impl/##1/##2\pgf@@eov{%
+ \def\wot{##1}%
+ \def\asd{kD}%
+ \ifx\wot\asd
+ \def\tmp{/codi/##2}%
+ \PackageWarning{kodi}{automatically remapped key '\pgfkeyscurrentkey'
+ to key '\tmp'. Please switch to the latter}
+ \ifx\pgfkeyscurrentvalue\pgfkeysnovalue
+ \expandafter\pgfkeysalso\expandafter{\tmp}%
+ \else
+ \expandafter\expandafter\expandafter\pgfkeysalso\expandafter\expandafter\expandafter{\expandafter\expandafter\expandafter\tmp\expandafter=\pgfkeyscurrentvalue}%
+ \fi
+ \else
+ % NOTE: this is the default /handlers/.unknown/.code
+ \def\pgf@marshal{\pgfkeysvalueof{/errors/unknown key/.@cmd}}%
+ {\expandafter\expandafter\expandafter\pgf@marshal\expandafter\expandafter\expandafter{\expandafter\pgfkeyscurrentkey\expandafter}\expandafter{\pgfkeyscurrentvalue}\pgfeov}%
+ \fi
+ }%
+ \expandafter\pgfkeysisdescendantof@impl\pgfkeyscurrentkey\pgf@@eov
+ }
+}
+
+% TikZ key: /tikz/kodi -> /tikz/codi
+
+\pgfkeys{
+ /tikz/kodi/.code={%
+ \PackageWarning{kodi}{automatically remapped key '/tikz/kodi'
+ to key '/tikz/codi'. Please switch to the latter}%
+ \pgfkeysalso{/tikz/codi}%
+ }
+}
+
+% Environment: kodi -> codi
+
+\def\kodi{%
+ \PackageWarning{kodi}{automatically remapped environment 'kodi'
+ to environment 'codi'. Please switch to the latter}%
+ \codi}
+\let\endkodi\endcodi
+
+\endinput
diff --git a/graphics/pgf/contrib/commutative-diagrams/t-commutative-diagrams.tex b/graphics/pgf/contrib/commutative-diagrams/t-commutative-diagrams.tex
new file mode 100644
index 0000000000..2c03eaa948
--- /dev/null
+++ b/graphics/pgf/contrib/commutative-diagrams/t-commutative-diagrams.tex
@@ -0,0 +1,16 @@
+%
+% CoDi: Commutative Diagrams for TeX
+% Copyright (c) 2015-2020 Paolo Brasolin <paolo.brasolin@gmail.com>
+% SPDX-License-Identifier: MIT
+%
+% This file is part of CoDi 1.0.0, released on 2020/06/06 under MIT license.
+%
+
+\writestatus{loading}{2020/06/06 1.0.0 CoDi: Commutative Diagrams for TeX}
+\startmodule[commutative-diagrams]
+\usemodule[tikz]
+\usetikzlibrary[commutative-diagrams]
+\let\startcodi\kDRammaOpen
+\let\stopcodi\kDRammaShut
+\stopmodule
+\endinput
diff --git a/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.bapto.code.tex b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.bapto.code.tex
new file mode 100644
index 0000000000..e417dc7f08
--- /dev/null
+++ b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.bapto.code.tex
@@ -0,0 +1,56 @@
+%
+% CoDi: Commutative Diagrams for TeX
+% Copyright (c) 2015-2020 Paolo Brasolin <paolo.brasolin@gmail.com>
+% SPDX-License-Identifier: MIT
+%
+% This file is part of CoDi 1.0.0, released on 2020/06/06 under MIT license.
+%
+
+% βάπτω • (báptō)
+% 1. I dip, submerge
+% 2. I dye, colour
+% 3. I baptise
+
+% Bapto is a node labeling mechanism.
+% It allows non-invasive relabeling and preprocessing.
+
+% ,-- input input hook
+% `-> controller --. the controller conditionally
+% ,---[overwrite]--' (depending upon the given overwriting behaviour)
+% `-> trigger -----. calls the trigger
+% ,--- ??? <-------' either short the keys or do preprocessing here
+% `-> dispatcher --. the dispatcher conditionally
+% ,---[overwrite]--| (depending upon the given overwriting behaviour)
+% `-> (name|alias) | assigns the label
+% output <-----' output hook
+
+%==[ input ]====================================================================
+
+\pgfqkeys{/bapto/input}{
+ .forward to=/bapto/controller
+}
+
+%==[ controller/dispatcher ]====================================================
+
+\pgfqkeys{/bapto/overwrite}{.is choice,
+ false/.style={/bapto/controller/.code={\def\kDTmp{##1}\ifx\kDTmp\empty\else
+ \tikz@fig@name\ifx\tikz@fig@name\empty
+ \pgfqkeys{/bapto}{trigger={##1}}\fi\fi},
+ /bapto/dispatcher/.code={\pgfqkeys{/tikz}{name=##1}%
+ \pgfqkeys{/bapto}{output=##1}}},
+ alias/.style={/bapto/controller/.code={\def\kDTmp{##1}\ifx\kDTmp\empty\else
+ \pgfqkeys{/bapto}{trigger={##1}}\fi},
+ /bapto/dispatcher/.code={\pgfqkeys{/tikz}{alias=##1}%
+ \pgfqkeys{/bapto}{output=##1}}},
+ true/.style= {/bapto/controller/.code={\def\kDTmp{##1}\ifx\kDTmp\empty\else
+ \pgfqkeys{/bapto}{trigger={##1}}\fi},
+ /bapto/dispatcher/.code={\pgfqkeys{/tikz}{name=##1}%
+ \pgfqkeys{/bapto}{output=##1}}},
+ false, % default is no name overwriting and no aliasing
+}
+
+%==[ output ]===================================================================
+
+\pgfqkeys{/bapto/output}{
+ .code={}
+}
diff --git a/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.code.tex b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.code.tex
new file mode 100644
index 0000000000..eabf14dd06
--- /dev/null
+++ b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.code.tex
@@ -0,0 +1,47 @@
+%
+% CoDi: Commutative Diagrams for TeX
+% Copyright (c) 2015-2020 Paolo Brasolin <paolo.brasolin@gmail.com>
+% SPDX-License-Identifier: MIT
+%
+% This file is part of CoDi 1.0.0, released on 2020/06/06 under MIT license.
+%
+
+%==[ dependencies graph ]=======================================================
+
+% NOTE: arrow notation means targets require sources.
+% TODO: does mandyas depend upon ramma?
+
+%====[ TikZ/pgf standard libraries ]===============%
+% %
+% calc ------------------------------------. %
+% matrix -------------------------------. | %
+% | | %
+%====[ Volatile layer: TikZ bugfixes ]=======|==|==%
+% | | %
+% commutative-diagrams.diorthono | | %
+% | | %
+%====[ Inner layer: base infrastructure ]====|==|==%
+% | | %
+% ,-> commutative-diagrams.ektropi ------. | | %
+% | commutative-diagrams.bapto --------| | | %
+% | commutative-diagrams.katharizo ----| | | %
+% `-- commutative-diagrams.koinos ----. | | | %
+% ,---' | | | | %
+%==|=[ Middle layer: custom parsers ]==|==|==|==|==%
+% | | | | | %
+% |-- commutative-diagrams.mitra <----+--|--' | %
+% |-- commutative-diagrams.ozos <-----| | | %
+% |-- commutative-diagrams.velos <----' | | %
+% | | | %
+%==|=[ Outer layer: user interface ]======|=====|==%
+% | | | %
+% `-> commutative-diagrams.ramma <-------' | %
+% commutative-diagrams.mandyas <-----------' %
+% %
+%==================================================%
+
+% Given the graph above, these suffice to encompass the whole library:
+
+\usetikzlibrary[commutative-diagrams.diorthono]
+\usetikzlibrary[commutative-diagrams.ramma]
+\usetikzlibrary[commutative-diagrams.mandyas]
diff --git a/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.diorthono.code.tex b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.diorthono.code.tex
new file mode 100644
index 0000000000..4a79abdbcc
--- /dev/null
+++ b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.diorthono.code.tex
@@ -0,0 +1,78 @@
+%
+% CoDi: Commutative Diagrams for TeX
+% Copyright (c) 2015-2020 Paolo Brasolin <paolo.brasolin@gmail.com>
+% SPDX-License-Identifier: MIT
+%
+% This file is part of CoDi 1.0.0, released on 2020/06/06 under MIT license.
+%
+
+% διορθώνω • (diorthóno)
+% 1. I correct
+% 2. I mend
+% 3. I repair
+
+% Diorthono is a collection of bugfixes.
+
+% Save catcode of @ to restore it at EOF.
+\edef\kDAct{\catcode`@=\the\catcode`@\relax}
+\catcode`@=11\relax
+
+% The following code patches \pgfpathcurvebetweentime.
+% See http://tex.stackexchange.com/a/271024/82186 for reference.
+% Original fix by Mark Wibrow.
+\def\pgf@@pathcurvebetweentime#1#2#3#4#5#6{%
+ \pgfmathparse{#1}%
+ \let\pgf@time@s=\pgfmathresult%
+ \pgfmathparse{#2}%
+ \let\pgf@time@t=\pgfmathresult%
+ \ifdim\pgf@time@s pt>\pgf@time@t pt\relax%
+ \pgfmathsetmacro\pgf@time@s{1-#1}%
+ \pgfmathsetmacro\pgf@time@t{1-#2}%
+ \pgf@@@pathcurvebetweentime{#6}{#5}{#4}{#3}%
+ \else%
+ \pgf@@@pathcurvebetweentime{#3}{#4}{#5}{#6}%
+ \fi%
+}
+\def\pgf@@@pathcurvebetweentime#1#2#3#4{%
+\begingroup%
+ % Get the curve Q from curve P for time 0 to t
+ \pgfextract@process\Pa{#1}%
+ \pgfextract@process\Pb{#2}%
+ \pgfextract@process\Pc{#3}%
+ \pgfextract@process\Pd{#4}%
+ % Qa = Pa
+ \pgfextract@process\Qa{\Pa}%
+ % Qb = Pa + t*(Pb-Pa).
+ \pgfextract@process\Qb{%
+ \pgfpointadd{\Pa}{\pgfpointscale{\pgf@time@t}{\pgfpointdiff{\Pa}{\Pb}}}%
+ }%
+ % Qc = Qb + t*((Pb + t*(Pc-Pb)) - Qb)
+ \pgfextract@process\Qc{%
+ \pgfpointadd{\Qb}{\pgfpointscale{\pgf@time@t}{\pgfpointdiff{\Qb}{\pgfpointadd{\Pb}{\pgfpointscale{\pgf@time@t}{\pgfpointdiff{\Pb}{\Pc}}}}}}%
+ }%
+ % Qd = (1-t)^3*Pa + 3*t(1-t)^2*Pb + 3*t^2(1-t)*Pc + t^3*Pd.
+ \pgfextract@process\Qd{\pgfpointcurveattime{\pgf@time@t}{\Pa}{\Pb}{\Pc}{\Pd}}%
+ %
+ % Now get the curve R from the reversed curve Q for time 0 to 1-s/t
+ \pgfmathdivide@{\pgf@time@s}{\pgf@time@t}%
+ \pgfmathadd@{-\pgfmathresult}{1.0}%
+ \let\pgf@time@s=\pgfmathresult%
+ % Rd = Qd
+ \pgfextract@process\Rd{\Qd}%
+ % Rc = Qd + s*(Qc-Qd).
+ \pgfextract@process\Rc{%
+ \pgfpointadd{\Qd}{\pgfpointscale{\pgf@time@s}{\pgfpointdiff{\Qd}{\Qc}}}%
+ }%
+ % Rb = Rc + s*((Qc + s*(Qb-Qc)) - Rc)
+ \pgfextract@process\Rb{%
+ \pgfpointadd{\Rc}{\pgfpointscale{\pgf@time@s}{\pgfpointdiff{\Rc}{\pgfpointadd{\Qc}{\pgfpointscale{\pgf@time@s}{\pgfpointdiff{\Qc}{\Qb}}}}}}%
+ }%
+ % Ra = (1-s)^3*Qd + 3*s(1-s)^2*Qc + 3*s^2(1-s)*Qb + s^3*Qa.
+ \pgfextract@process\Ra{\pgfpointcurveattime{\pgf@time@s}{\Qd}{\Qc}{\Qb}{\Qa}}%
+ \ifpgf@ignoremoveto\else\pgfpathmoveto{\Ra}\fi%
+ \pgfpathcurveto{\Rb}{\Rc}{\Rd}%
+\endgroup%
+}
+
+% Restore catcode of @.
+\kDAct
diff --git a/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.ektropi.code.tex b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.ektropi.code.tex
new file mode 100644
index 0000000000..3a698436c4
--- /dev/null
+++ b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.ektropi.code.tex
@@ -0,0 +1,66 @@
+%
+% CoDi: Commutative Diagrams for TeX
+% Copyright (c) 2015-2020 Paolo Brasolin <paolo.brasolin@gmail.com>
+% SPDX-License-Identifier: MIT
+%
+% This file is part of CoDi 1.0.0, released on 2020/06/06 under MIT license.
+%
+
+% εκτροπή • (ektropí)
+% 1. diversion
+% 2. deflection
+% 3. aberration
+
+% Ektropi is a mechanism to hijack the /tikz/.unknown handler.
+% It allows the addition of maximum priority paths in the key finding algorithm.
+% The diversions are globally scoped, cumulative and removable.
+
+\usetikzlibrary{commutative-diagrams.koinos}
+
+\kDStoreCatcodeOf @
+\catcode`@=11
+
+%==[ handler restoring procedure ]==============================================
+
+% The default handler's code is backed up as a token list at load time.
+% NOTE: this has strong implications on loading order!
+
+\newtoks\kDEktropiDefaultToksBackup
+
+\expandafter\expandafter
+\expandafter\kDEktropiDefaultToksBackup
+\expandafter\expandafter
+\expandafter{\csname pgfk@/tikz/.unknown/.@body\endcsname}
+
+\def\kDEktropiRestore{
+ % Restore handler body.
+ \def\kDAct{\pgfkeyssetvalue{/tikz/.unknown/.@body}}
+ \expandafter\kDAct\expandafter{\the\kDEktropiDefaultToksBackup}
+ % Restore handler macro.
+ % NOTE: #s are doubled since we're inside \kDAct helper.
+ \def\kDAct{\long\def\kDAct####1\pgfeov}
+ \expandafter\kDAct\expandafter{\the\kDEktropiDefaultToksBackup}
+ \pgfkeyslet{/tikz/.unknown/.@cmd}\kDAct
+}
+
+% This key is the user interface. Self explanatory.
+\pgfkeys{/ektropi/restore/.code={\kDEktropiRestore}}
+
+%==[ handler hacking procedure ]================================================
+
+% This key is the user interface. It wraps the /tikz/.unknown handler code
+% with a conditional that executes it only if the unknown key retrieval
+% fails inside the path passed to /ektropi/add.
+\pgfkeys{/ektropi/add/.style={
+ /tikz/.unknown/.add code=
+ {
+ \let\tikz@key\pgfkeyscurrentname
+ \pgfkeys{#1/\tikz@key/.try={##1}}
+ \ifpgfkeyssuccess\else
+ }{
+ \fi
+ }
+ }
+}
+
+\kDRestoreCatcodeOf @
diff --git a/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.katharizo.code.tex b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.katharizo.code.tex
new file mode 100644
index 0000000000..ef3c4ea0fc
--- /dev/null
+++ b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.katharizo.code.tex
@@ -0,0 +1,136 @@
+%
+% CoDi: Commutative Diagrams for TeX
+% Copyright (c) 2015-2020 Paolo Brasolin <paolo.brasolin@gmail.com>
+% SPDX-License-Identifier: MIT
+%
+% This file is part of CoDi 1.0.0, released on 2020/06/06 under MIT license.
+%
+
+% καθαρίζω • (katharízo)
+% 1. clean, wash
+% 2. peel, descale
+% 3. (slang) kill
+
+% Katharizo is a detokenization/sanitation mechanism.
+% It produces "safe" strings from tokens.
+
+% ,-- input input hook
+% `-> expander ---. performs expansion according to
+% ,---[expand]----' macro expansion configuration
+% `-> expanded ---. pre-sanitation hook
+% ,-- sanitizer <-' performs detokenization and sanitation according to
+% `---[replace]---. character replacement configuration
+% ,-- sanitized <-' pre-output hook
+% `-> output output hook
+
+%==[ input stage ]==============================================================
+
+\pgfqkeys{/katharizo/input}{
+ .forward to=/katharizo/expander
+}
+
+%==[ expansion stage ]==========================================================
+
+\pgfqkeys{/katharizo/expand}{.is choice,
+ once/.style={/katharizo/expander/.style={/katharizo/expanded/.expand once={##1}}},
+ full/.style={/katharizo/expander/.style={/katharizo/expanded/.expanded={##1}}},
+ none/.style={/katharizo/expander/.style={/katharizo/expanded={##1}}},
+ none % default is no expansion
+}
+
+\pgfqkeys{/katharizo/expanded}{
+ .forward to=/katharizo/sanitizer
+}
+
+%==[ sanitation stage ]=========================================================
+
+\pgfqkeys{/katharizo}{
+ replace charcode/.code args={#1 with #2}{%
+ % TODO: would a \string be of any use? or at least a stringification?
+ \pgfkeys{/katharizo/replacements/characters/#1/.initial={#2}}%
+ },
+ remove charcode/.style={/katharizo/replace charcode={{#1} with {}}},
+ remove charcodes/.style args={#1}{%
+ /katharizo/remove charcodes loop={#1 \kD},
+ },
+ remove charcodes loop/.code args={#1 #2\kD}{%
+ % \message{|||#1|#2|||}
+ \ifx\relax#1\else\pgfkeys{/katharizo/remove charcode={#1}}\fi
+ \ifx\relax#2\else\pgfkeys{/katharizo/remove charcodes loop={#2\kD}}\fi
+ },
+ replace character/.code args={#1 with #2}{%
+ \edef\kDFoo{\number`#1}% TODO: can I inline this?
+ % TODO: would a \string be of any use? or at least a stringification?
+ \pgfkeys{/katharizo/replacements/characters/\kDFoo/.initial={#2}}%
+ },
+ remove character/.style={/katharizo/replace character={{#1} with {}}},
+ remove characters/.code args={#1#2}{%
+ \ifx\relax#1\else\pgfkeys{/katharizo/remove character={#1}}\fi
+ \ifx\relax#2\else\pgfkeys{/katharizo/remove characters={#2}}\fi
+ },
+ remove characters={(),.:},
+ remove charcode=92,% \ backslash
+}
+
+\pgfqkeys{/katharizo}{
+ sanitizer/.code={
+ % TODO: token replacement routine? Would that be useful?
+ \kDKatharizoStringify#1\kD
+ \expandafter\kDKatharizoSanitize\the\kDKatharizoStringified\kD
+ \pgfkeysalso{/katharizo/sanitized/.expanded=\the\kDKatharizoSanitized}
+ % \message{^^J:::\the\kDKatharizoSanitized:::^^J}
+ }
+}
+
+\pgfqkeys{/katharizo/sanitized}{
+ .forward to=/katharizo/output
+}
+
+%==[ output stage ]=============================================================
+
+% NOTE: this must be defined/hooked before calling input
+\pgfqkeys{/katharizo/output}{
+ .code={}
+}
+
+\newtoks\kDKatharizoStringified
+
+\def\kDKatharizoStringify#1\kD{
+ \def\kDFoo{#1}
+ \edef\kDFoo{\meaning\kDFoo}
+ \def\kDAct##1:->##2\kD{##2}
+ \edef\kDFoo{\expandafter\kDAct\kDFoo\kD}
+ \kDKatharizoStringified\expandafter{\kDFoo}
+}
+
+\newtoks\kDKatharizoSanitized
+
+\def\kDKatharizoSanitize#1\kD{
+ \pgfkeysifdefined{/katharizo/replacements/characters/32}%
+ {\edef\kDKatharizoSSpace{\pgfkeysvalueof{/katharizo/replacements/characters/32}}}%
+ {\edef\kDKatharizoSSpace{\space}}%
+ \def\kDKatharizoSAppendSpace
+ {\edef\kDAct{\noexpand\kDKatharizoSanitized={\the\kDKatharizoSanitized\kDKatharizoSSpace}}\kDAct}
+ \kDKatharizoSanitized={}
+ \kDKatharizoSString#1 \kD}% NOTE: the whitespace is a mandatory string terminator
+
+\def\kDKatharizoSString#1 #2\kD{%
+ \ifx\relax#1\else % if string head word is not empty
+ \kDKatharizoSWord#1\kD % parse string head word
+ \if#2\space\else % if string tail is not the space terminator
+ \ifx\relax#2\else % if string tail is not empty
+ \kDKatharizoSAppendSpace\fi\fi\fi % append space substitute to output
+ \ifx\relax#2\else % if string tail is not empty
+ \kDKatharizoSString#2\kD\fi} % recurse on string tail
+
+\def\kDKatharizoSWord#1#2\kD{%
+ \kDKatharizoSCharacter#1\kD % parse word head character
+ \ifx\relax#2\else % if word tail is not empty
+ \kDKatharizoSWord#2\kD\fi} % recurse on word tail
+
+\def\kDKatharizoSCharacter#1\kD{%
+ \pgfkeysifdefined{/katharizo/replacements/characters/\number`#1}%
+ {\edef\kDFoo{\pgfkeysvalueof{/katharizo/replacements/characters/\number`#1}}}%
+ {\edef\kDFoo{#1}}%
+ \edef\kDAct{\noexpand\kDKatharizoSanitized={\the\kDKatharizoSanitized\kDFoo}}%
+ \kDAct}
diff --git a/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.koinos.code.tex b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.koinos.code.tex
new file mode 100644
index 0000000000..c2b378f38a
--- /dev/null
+++ b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.koinos.code.tex
@@ -0,0 +1,168 @@
+%
+% CoDi: Commutative Diagrams for TeX
+% Copyright (c) 2015-2020 Paolo Brasolin <paolo.brasolin@gmail.com>
+% SPDX-License-Identifier: MIT
+%
+% This file is part of CoDi 1.0.0, released on 2020/06/06 under MIT license.
+%
+
+% κοινός • (koinós)
+% 1. shared
+% 2. common
+% 3. public
+
+% Koinos implements or aliases commonplace macros.
+
+%==[ catcode manipulation ]=====================================================
+
+\newcount\kDEscapecharCounter
+
+\def\kDEscapecharDisable{\kDEscapecharCounter\escapechar \escapechar=-1}
+\def\kDEscapecharEnable{\escapechar\kDEscapecharCounter}
+
+\def\kDStoreCatcodeOf#1%
+ {\kDEscapecharDisable
+ \expandafter\edef\csname kDRestoreCatcodeOf\string#1\endcsname{\catcode`\string#1=\the\catcode\expandafter`\string#1}%
+ % NOTE: setting a default catcode is disabled; might come in handy someday, though.
+ % \catcode\expandafter`\string#1=12\relax
+ \kDEscapecharEnable}
+
+\def\kDRestoreCatcodeOf#1%
+ {\kDEscapecharDisable
+ \csname kDRestoreCatcodeOf\string#1\endcsname
+ \kDEscapecharEnable}
+
+%==[ forward checks and gobbling ]==============================================
+
+% This macro is the blank space token.
+\bgroup
+\def\:{\global\let\kDBlankSpace= }\:
+\egroup
+
+% Save catcode of @ to restore it later.
+\kDStoreCatcodeOf @
+\catcode`@=11\relax
+
+% The next two macros both implement token gobbling.
+
+% This "hard" version gobbles any token, ignoring whitespace.
+\let\kDGobbleHardTok\pgfutil@gobble
+
+% This "soft" version gobbles only whitespace.
+% NOTE: this is just the identity macro. Fun fact.
+\def\kDGobbleSoftTok#1{#1}
+
+% The next two macros both implement the following logical condition:
+% if next token is #1 then #2 else #3
+
+% This "hard" version ignores whitespace.
+\let\kDIfNextHardCh\pgfutil@ifnextchar
+
+% This "soft" version does not ignore whitespace.
+\long\def\kDIfNextSoftCh#1#2#3{%
+ \let\kDINCToken= #1% <- MEMO: this space is crucial
+ \def\kDINCTrue{#2}\def\kDINCFalse{#3}%
+ \futurelet\kDINCTok\kDINC}
+
+\def\kDINC{\ifx\kDINCTok\kDINCToken\let\kDINCFalse\kDINCTrue\fi\kDINCFalse}
+
+% Restore catcode of @.
+\kDRestoreCatcodeOf @
+
+%==[ token lists parsing and manipulation ]=====================================
+
+% This macro appends token list #1 to token list #2.
+\def\kDAppend#1#2{\edef\kDAct{\noexpand#2={\the#2\the#1}}\kDAct}
+
+% This macro tokenizes the stream into \kDOptTok
+% until a group preceeding a ';' character is found;
+% then it puts the group into \kDGrpTok and gobbles the ';'.
+\def\kDFetchOptAndGrpThen#1%
+ {\kDOptTok={}\kDGrpTok={}\kDFetchTilGrpThen{#1}}
+
+\newtoks\kDOptTok
+\newtoks\kDGrpTok
+
+\def\kDFetchGrpThen#1#2{%
+ \def\kDExit{#1}%
+ \def\kDLoop{\kDFetchTilGrpThen{#1}}%
+ \kDTmpTok={{#2}}%
+ \kDIfNextHardCh;
+ {\kDGrpTok\the\kDTmpTok\expandafter\kDExit\kDGobbleHardTok}
+ {\kDAppend\kDTmpTok\kDOptTok\kDLoop}}
+
+\newtoks\kDTmpTok
+
+\def\kDFetchTilGrpThen#1#2#{%
+ \kDTmpTok={#2}%
+ \kDAppend\kDTmpTok\kDOptTok
+ \kDFetchGrpThen{#1}}
+
+% This macro removes trailing whitespace from token list #1.
+\def\kDTrimTrailingSpace#1{%
+ \kDDetectTrailingSpace#1
+ \ifkDDTSHasTrail
+ \def\kDRTS##1 \kD{#1={##1}}%
+ \edef\kDRTSAct{\noexpand\kDRTS\the#1\noexpand\kD}
+ \kDRTSAct
+ \fi}
+
+\def\kDDetectTrailingSpace#1{%
+ \kDDTSPrevSpacefalse
+ \edef\kDAct{\noexpand\kDDTSGob\the#1\noexpand\kD}%
+ \kDAct}
+
+\newif\ifkDDTSHasTrail
+
+\def\kDDTSGob%
+ {\kDIfNextSoftCh\kD
+ {\message{A}\ifkDDTSPrevSpace\kDDTSHasTrailtrue\else\kDDTSHasTrailfalse\fi\kDGobbleHardTok}
+ {\message{B}\kDIfNextSoftCh\kDBlankSpace
+ {\message{Y}\kDDTSPrevSpacetrue\expandafter\kDDTSGob\kDGobbleSoftTok}
+ {\message{N}\kDDTSPrevSpacefalse\expandafter\kDDTSGob\kDGobbleHardTok}}}
+
+\newif\ifkDDTSPrevSpace
+
+% This macro removes leading whitespace from token list #1.
+\def\kDTrimLeadingSpace#1{%
+ \def\kDAct##1\kD{#1={##1}}%
+ \expandafter\kDGobbleSpaceThen
+ \expandafter\kDAct\the#1\kD}
+
+\def\kDGobbleSpaceThen#1%
+ {\kDIfNextHardCh\bgroup
+ {\kDGSGroupThen#1}
+ {\kDGSOtherThen#1}}
+
+\def\kDGSGroupThen#1#2{#1{#2}}
+
+\def\kDGSOtherThen#1#2{#1#2}
+
+%==[ environment checks ]=======================================================
+
+\newif\ifConTeXt
+% Trick stolen from iftex. The second line is expanded inside the group so
+% the global scope isn't polluted by \csname defining the token.
+\begingroup\expandafter\expandafter\expandafter\endgroup\expandafter
+ \ifx\csname starttext\endcsname\relax\ConTeXtfalse\else\ConTeXttrue\fi
+
+%==[ dumping, debugging and testing ]===========================================
+
+% macros for dumping, debugging and testing
+% TODO: not sure I want to depend on these being in the sourcecode instead of
+% some external package integrated with a TeX unit testing suite.
+% I'll work in that direction.
+
+\newif\ifkDDumping
+\kDDumpingfalse
+
+\newwrite\kDDumpFile
+
+\def\kDDumpOpen%
+{\ifkDDumping\immediate\openout\kDDumpFile=\jobname.yml\fi}
+
+\def\kDDump#1%
+{\ifkDDumping\immediate\write\kDDumpFile{#1}\fi}
+
+\def\kDDumpClose%
+{\ifkDDumping\closeout\kDDumpFile\fi}
diff --git a/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.mandyas.code.tex b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.mandyas.code.tex
new file mode 100644
index 0000000000..2d43ef5d55
--- /dev/null
+++ b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.mandyas.code.tex
@@ -0,0 +1,319 @@
+%
+% CoDi: Commutative Diagrams for TeX
+% Copyright (c) 2015-2020 Paolo Brasolin <paolo.brasolin@gmail.com>
+% SPDX-License-Identifier: MIT
+%
+% This file is part of CoDi 1.0.0, released on 2020/06/06 under MIT license.
+%
+
+% μανδύας • (mandýas)
+% 1. cloak
+% 2. mantle
+% 3. dolman
+
+% Mandias defines the aesthetics aspect of the user level functionality,
+% together with some baseline configuration.
+
+\usetikzlibrary[calc]
+
+% \usetikzlibrary[decorations.pathreplacing]
+% \usetikzlibrary{decorations.pathmorphing}
+% \usetikzlibrary[decorations.markings]
+% \usetikzlibrary[arrows.meta]
+
+\pgfqkeys{/codi}{
+%==[ universal styles ]=========================================================
+ every diagram/.append style={},
+ every layout/.append style={
+ /codi/every object/.append style={shape=codi baseline centered rectangle},
+ square,
+ },
+ every object/.append style={},
+ every arrow/.append style={
+ >=stealth,
+ },
+ every label/.append style={
+ auto,
+ inner sep=0.5ex,
+ font=\everymath\expandafter{\the\everymath\scriptstyle}
+ },
+%==[ arrow styles ]=============================================================
+ /codi/arrows/.cd,
+ crossing over/clearance/.initial=0.5ex,
+ crossing over/color/.initial=white,
+ crossing over/.style={
+ /tikz/preaction={
+ -,
+ draw=\pgfkeysvalueof{/codi/arrows/crossing over/color},
+ line width=\pgfkeysvalueof{/codi/arrows/crossing over/clearance},
+ },
+ },
+ shove/.style={
+ /tikz/transform canvas={
+ /tikz/shift={($(\tikztostart)!#1!-90:(\tikztotarget)-(\tikztostart)$)}
+ }
+ },
+ slide/.style={
+ /tikz/transform canvas={
+ /tikz/shift={($(\tikztostart)!#1!0:(\tikztotarget)-(\tikztostart)$)}
+ }
+ },
+%==[ label styles ]=============================================================
+ /codi/labels/.cd,
+ mid/.style={
+ /tikz/fill=white,
+ /tikz/shape=circle,
+ /tikz/anchor=center,
+ /tikz/inner sep=.25ex
+ },
+%=[ objects styles ]============================================================
+ /codi/objects/.cd,
+ % TODO: reflect on these styles
+ % tetragonal/.style 2 args={
+ % /tikz/node distance=#2 and #1
+ % },
+ % square/.style={
+ % /codi/objects/rectangular={#1}{#1}
+ % },
+ % golden/.style={
+ % /codi/objects/rectangular={#1}{0.618*#1}
+ % },
+ % % comb/.style={
+ % % /codi/objects/rectangular={#1}{sqrt(3/4)*#1},
+ % % },
+ % % comb/.default=4em,
+ % square/.default=4em,
+ % golden/.default=4em,
+%=[ lattice styles ]============================================================
+ /codi/layouts/.cd,
+ hexagonal/.code args={#1side #2 angle #3}{
+ \pgfkeys{/codi/layouts/#1hexagonal=side {#2} angle {#3}},
+ },
+ horizontal hexagonal/.style args={side #1 angle #2}{
+ /codi/layouts/tetragonal=base {#1} height {tan(#2)*#1*0.5},
+ /tikz/every odd row/.append style={/tikz/xshift=(#1)*0.5},
+ },
+ vertical hexagonal/.style args={side #1 angle #2}{
+ /codi/layouts/tetragonal=base {tan(#2)*#1*0.5} height {#1},
+ /tikz/every odd column/.append style={/tikz/yshift=-1*(#1)*0.5},
+ },
+ hexagonal/.default=horizontal side 4.5em angle 60,
+ %
+ tetragonal/.style args={base #1 height #2}{
+ /tikz/column sep={{#1},between origins},
+ /tikz/row sep={{#2},between origins},
+ },
+ tetragonal/.default=base 4.5em height 2.8em,
+ %
+ square/.style={
+ /codi/layouts/tetragonal=base {#1} height {#1},
+ },
+ golden/.style={
+ /codi/layouts/tetragonal=base {#1} height {0.618*#1},
+ },
+ square/.default=4.5em,
+ golden/.default=4.5em,
+%=[ diagram styles ]============================================================
+ /codi/diagrams/.cd,
+ grid/.style 2 args={
+ /tikz/x={#1},
+ /tikz/y={#2},
+ /tikz/on grid,
+ },
+ metric/.style 2 args={
+ % NOTE: {1 and 1}{1} is infty-norm, unit circle is unit square
+ % NOTE: {2}{0.5} is 1-norm, circle of radius 2 is rhombus circumscribing base hexagon
+ /tikz/node distance={#1},
+ % TODO: implement control to allow for explicit units on single factor specs
+ /tikz/above left/.code={\tikz@lib@place@handle@{##1}{south east}{-1}{1}{north west}{#2}},
+ /tikz/above right/.code={\tikz@lib@place@handle@{##1}{south west}{1}{1}{north east}{#2}},
+ /tikz/below left/.code={\tikz@lib@place@handle@{##1}{north east}{-1}{-1}{south west}{#2}},
+ /tikz/below right/.code={\tikz@lib@place@handle@{##1}{north west}{1}{-1}{south east}{#2}},
+ },
+ %
+ hexagonal/.code args={#1side #2 angle #3}{
+ \pgfkeys{/codi/diagrams/#1hexagonal=side #2 angle #3}
+ },
+ horizontal hexagonal/.style args={side #1 angle #2}{
+ /codi/every layout/.append style={/codi/layouts/hexagonal=horizontal side {#1} angle {#2}},
+ /codi/diagrams/grid={#1*0.5}{#1*tan(#2)*0.5},
+ /codi/diagrams/metric={2}{0.5},
+ },
+ vertical hexagonal/.style args={side #1 angle #2}{
+ /codi/every layout/.append style={/codi/layouts/hexagonal=vertical side {#1} angle {#2}},
+ /codi/diagrams/grid={#1*tan(#2)*0.5}{#1*0.5},
+ /codi/diagrams/metric={2}{0.5},
+ },
+ hexagonal/.default=horizontal side 4.5em angle 60,
+ %
+ tetragonal/.style args={base #1 height #2}{
+ /codi/every layout/.append style={/codi/layouts/tetragonal=base {#1} height {#2}},
+ /codi/diagrams/grid={#1}{#2},
+ /codi/diagrams/metric={1 and 1}{1},
+ },
+ tetragonal/.default=base 4.5em height 2.8em,
+ %
+ square/.style={
+ /codi/every layout/.append style={/codi/layouts/square=#1},
+ /codi/diagrams/tetragonal=base {#1} height {#1},
+ },
+ golden/.style={
+ /codi/every layout/.append style={/codi/layouts/golden=#1},
+ /codi/diagrams/tetragonal=base {#1} height {0.618*#1},
+ },
+ square/.default=4.5em,
+ golden/.default=4.5em,
+}
+
+%==[ baseline centered rectangle shape ]========================================
+
+% The math formula axis height is recovered and stored as a pgf function.
+
+% NOTE: the LuaTeX version is needed just by ConTeXt
+\pgfutil@ifluatex
+ \directlua{tex.enableprimitives('kD', {'Umathaxis'})}
+ \pgfmathdeclarefunction{kD_math_formula_axis_height}{0}{%
+ \begingroup%
+ $\relax$% update fontdimens
+ % See TeX by Topic §23.5 for details.
+ \pgfmathreturn\the\kDUmathaxis\textstyle%
+ \endgroup}
+\else% if using (pdf)tex
+ \pgfmathdeclarefunction{kD_math_formula_axis_height}{0}{%
+ \begingroup%
+ $\relax$% update fontdimens
+ % See TeX by Topic §23.5 for details.
+ \pgfmathreturn\the\fontdimen22\textfont2%
+ \endgroup}
+\fi
+
+\pgfqkeys{/codi/baseline centered rectangle}{
+ center raise/.initial=kD_math_formula_axis_height
+}
+
+% Then the shape is defined by inheritance.
+
+\pgfdeclareshape{codi baseline centered rectangle} {
+ % Inherit the rectangle shape.
+ \inheritsavedanchors[from={rectangle}]
+ \inheritanchor[from={rectangle}]{base}
+ \inheritanchor[from={rectangle}]{north}
+ \inheritanchor[from={rectangle}]{south}
+ \inheritanchor[from={rectangle}]{base west}
+ \inheritanchor[from={rectangle}]{north west}
+ \inheritanchor[from={rectangle}]{south west}
+ \inheritanchor[from={rectangle}]{base east}
+ \inheritanchor[from={rectangle}]{north east}
+ \inheritanchor[from={rectangle}]{south east}
+ \inheritanchor[from={rectangle}]{mid}
+ \inheritanchor[from={rectangle}]{mid west}
+ \inheritanchor[from={rectangle}]{mid east}
+ \inheritbackgroundpath[from={rectangle}]
+ % Redefine west, center and east anchors
+ % setting their y coordinates to center raise.
+ \anchor{center}{\pgf@anchor@rectangle@center\pgfmathsetlength\pgf@y%
+ {\pgfkeysvalueof{/codi/baseline centered rectangle/center raise}}}
+ \anchor{west}{\pgf@anchor@rectangle@west\pgfmathsetlength\pgf@y%
+ {\pgfkeysvalueof{/codi/baseline centered rectangle/center raise}}}
+ \anchor{east}{\pgf@anchor@rectangle@east\pgfmathsetlength\pgf@y%
+ {\pgfkeysvalueof{/codi/baseline centered rectangle/center raise}}}
+ % Save the original anchors as alternate "real" versions.
+ \anchor{real center}{\pgf@anchor@rectangle@center}
+ \anchor{real west}{\pgf@anchor@rectangle@west}
+ \anchor{real east}{\pgf@anchor@rectangle@east}
+ % Redefine the border anchor calculation.
+ \anchorborder{%
+ % (x,y) = target
+ % let tempdima = center raise
+ \pgfmathsetlength\pgfutil@tempdima%
+ {\pgfkeysvalueof{/codi/baseline centered rectangle/center raise}}%
+ % let b = (x,y) = target
+ \pgf@xb=\pgf@x%
+ \pgf@yb=\pgf@y%
+ % let (x,y) = south west
+ \southwest%
+ % let a = (x,y) = south west
+ \pgf@xa=\pgf@x%
+ \pgf@ya=\pgf@y%
+ % let (x,y) = north east
+ \northeast%
+ % let (x,y) = (x,y) - a = north east - south west = (width, height)
+ \advance\pgf@x by-\pgf@xa%
+ \advance\pgf@y by-\pgf@ya%
+ % let c = (x,y)/2 = (width, height)/2 = (width/2, height/2)
+ \pgf@xc=.5\pgf@x%
+ \pgf@yc=.5\pgf@y%
+ % let a = a + c = south west + (width/2, height/2) = center
+ \advance\pgf@xa by\pgf@xc%
+ \advance\pgf@ya by\pgf@yc%
+ % if by = target y > 0
+ \ifdim\pgf@yb>0pt%
+ % let (x,y) = north east
+ \northeast%
+ % let cy = y = north east y
+ \pgf@yc=\pgf@y%
+ % let cy = cy - center raise = north east y - center raise
+ \advance\pgf@yc by-\pgfutil@tempdima%
+ \else%
+ % let (x,y) = south west
+ \southwest%
+ % let cy = y = - south west y
+ \pgf@yc=-\pgf@y%
+ % let cy = cy + center raise = - south west y + center raise
+ \advance\pgf@yc by\pgfutil@tempdima%
+ \fi
+ \edef\pgf@marshal{%
+ % calculate the intersection of the half line from the origin
+ \noexpand\pgfpointborderrectangle
+ % passing through target
+ {\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}
+ % and the rectangle centered on the origin
+ % whose upper right corner is
+ % (width/2, +north east y - center raise) if target y > 0
+ % (width/2, -south west y + center raise) if target y < 0
+ {\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}%
+ }%
+ % let (x,y) = the intersection
+ \pgf@process{\pgf@marshal}%
+ % let x = x + ax = width/2 + center x
+ \advance\pgf@x by\pgf@xa%
+ % let y = y + tempdima = ±(ne/sw y - center raise) + center raise
+ \advance\pgf@y by\pgfutil@tempdima%
+ % that is, y = + north east y if target y > 0
+ % y = - south west y + 2 * center raise if target y < 0
+ %
+ % NOTE: in essence, we're just compensating for the redefinition
+ % of ne/sw anchors that shifted them by cr below the real center.
+ % ┏━━━━━━┯━━━━━━┓ ╮╮
+ % ┃ │ ┃ ││ + ney - cr
+ % ╭╭ ┠──────┼──────┨ ╮│╯ y > 0
+ % - swy + cr │╰╭ ┣━━━━━━┿━━━━━━┫ ╯╯ ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
+ % ╰ ╰ ┗━━━━━━┷━━━━━━┛ y < 0
+ }%
+}%
+
+%==[ prompter ]=================================================================
+
+% This key is meant for visual assistance with the node labeling automation.
+
+\pgfqkeys{/codi}{
+ prompter label/.style={
+ /tikz/.cd,
+ inner sep=0sp,
+ font=\ttfamily\bfseries\tiny,
+ line width=1pt,
+ draw=violet,
+ fill=violet,
+ text=white,
+ overlay,
+ label anchor/.style={tikz@label@post/.append style={anchor=##1}},
+ label anchor=north east,
+ label position=south east
+ },
+ prompter pinner/.style={
+ /tikz/draw=violet,
+ /tikz/line width=1sp,
+ /tikz/label={[/codi/prompter label]:#1},
+ },
+ prompter/.style={/bapto/output/.forward to=/codi/prompter pinner}
+}
diff --git a/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.mitra.code.tex b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.mitra.code.tex
new file mode 100644
index 0000000000..211ade2f4c
--- /dev/null
+++ b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.mitra.code.tex
@@ -0,0 +1,207 @@
+%
+% CoDi: Commutative Diagrams for TeX
+% Copyright (c) 2015-2020 Paolo Brasolin <paolo.brasolin@gmail.com>
+% SPDX-License-Identifier: MIT
+%
+% This file is part of CoDi 1.0.0, released on 2020/06/06 under MIT license.
+%
+
+% μήτρα • (mítra)
+% 1. womb
+% 2. matrix
+% 3. mold
+
+% Mitra is an alternative parsing mechanism for TiKz matrices of nodes.
+% It couples with ozos to ensure the node contents always pass through the TikZ key.
+
+\usetikzlibrary{matrix}
+\usetikzlibrary{commutative-diagrams.koinos}
+
+%==[ TikZ/pgf layer ]===========================================================
+
+\pgfkeys{
+ /mitra/every node/.style={},
+ /mitra/every matrix/.style={
+ /tikz/matrix,
+ /tikz/cells={
+ /tikz/anchor=base
+ }
+ },
+ % NOTE: the alias key *cannot* be put along with global node styles
+ % because of execution order.
+ /mitra/matrix coordinates alias/.style={
+ /tikz/alias=\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn
+ }
+}
+
+%==[ main macro ]===============================================================
+
+\def\kDMitra
+ {\kDMitraFetchMatrixThen
+ {\kDMitraParseMatrixTableThen
+ \kDMitraOutput}}
+
+% General purpose scratch register.
+\newtoks\kDMitraTmpTok
+
+%==[ fetching routine ]=========================================================
+
+% I use the general one implemented by koinos.
+\let\kDMitraFetchMatrixThen\kDFetchOptAndGrpThen
+
+%==[ parsing routine: /table ]==================================================
+
+\newtoks\kDMitraMatOutTok
+
+\def\kDMitraParseMatrixTableThen#1{%
+ \kDMitraMatOutTok={}%
+ \expandafter\kDMitraParseTable\the\kDGrpTok\kD
+ #1}
+
+\def\kDMitraParseTable
+ {\kDMitraParseAllRowsThen\relax}
+
+\def\kDMitraParseAllRowsThen#1{%
+ \def\kDExit{#1}%
+ \kDIfNextHardCh\kD
+ {\expandafter\kDExit\kDGobbleHardTok}%
+ {\kDMitraParseOneRowThen{\kDMitraParseAllRowsThen{#1}}}}
+
+%==[ parsing routine: /table/row ]==============================================
+
+\def\kDMitraParseOneRowThen#1%
+ {\kDMitraMarkRowEndBefore
+ {\kDMitraParseAllColsThen
+ {\kDMitraParseRowEndThen
+ {#1}}}}
+
+\kDStoreCatcodeOf &
+\ifConTeXt\catcode`&=12\else\catcode`&=4\fi
+\def\kDMitraMarkRowEndBefore#1#2\\{#1#2&\kD\\}
+\kDRestoreCatcodeOf &
+
+\def\kDMitraParseAllColsThen#1{%
+ \def\kDExit{#1}%
+ \kDIfNextHardCh\kD
+ {\expandafter\kDExit\kDGobbleHardTok}%
+ {\kDMitraParseOneColThen{\kDMitraParseAllColsThen{#1}}}}
+
+\def\kDMitraParseRowEndThen#1%
+ {\kDMitraFetchRowEndThen
+ {\kDMitraPrintRowEndThen
+ {#1}}}
+
+\def\kDMitraFetchRowEndThen#1\\{\kDMitraMaybeFetchRowOptionsThen{#1}}
+
+\newtoks\kDMitraRowOptTok
+
+\def\kDMitraPrintRowEndThen#1{%
+ \edef\kDAct{\noexpand\kDMitraTmpTok={\noexpand\\\the\kDMitraRowOptTok}}%
+ \kDAct
+ \kDAppend\kDMitraTmpTok\kDMitraMatOutTok
+ #1}
+
+\def\kDMitraMaybeFetchRowOptionsThen#1{%
+ \kDMitraRowOptTok={}%
+ \kDIfNextHardCh[%
+ {\kDMitraFetchRowOptionsThen{#1}}%
+ {#1}}
+
+\def\kDMitraFetchRowOptionsThen#1[#2]{\kDMitraRowOptTok={[#2]}#1}
+
+%==[ parsing routine: /table/row/column ]=======================================
+
+\def\kDMitraParseOneColThen#1%
+ {\kDMitraParseCellThen
+ {\kDMitraParseColEndThen
+ {#1}}}
+
+\def\kDMitraParseColEndThen#1%
+ {\kDMitraMaybeFetchColOptionsThen
+ {\kDMitraMaybePrintColEndThen
+ {#1}}}
+
+\newtoks\kDMitraColOptTok
+
+\def\kDMitraMaybeFetchColOptionsThen#1{%
+ \kDMitraColOptTok={}%
+ \kDIfNextHardCh[%
+ {\kDMitraFetchColOptionsThen{#1}}%
+ {#1}}
+
+\def\kDMitraFetchColOptionsThen#1[#2]{\kDMitraColOptTok={[#2]}#1}
+
+\def\kDMitraMaybePrintColEndThen#1{%
+ \kDIfNextHardCh\kD
+ {#1}%
+ {% NOTE: we use \pgfmatrixnextcell instead of & to avoid catcode juggling
+ \edef\kDAct{\noexpand\kDMitraTmpTok={\noexpand\pgfmatrixnextcell\the\kDMitraColOptTok}}%
+ \kDAct
+ \kDAppend\kDMitraTmpTok\kDMitraMatOutTok
+ #1%
+ }}
+
+%==[ parsing routine: /table/row/column/cell ]==================================
+
+\def\kDMitraParseCellThen#1%
+ {\kDMitraMaybeFetchCellOptionsThen
+ {\kDMitraFetchCellContentThen
+ {\kDMitraPrintCellThen
+ {#1}}}}
+
+\newtoks\kDMitraCelOptTok
+
+\def\kDMitraMaybeFetchCellOptionsThen#1{%
+ \kDMitraCelOptTok={}%
+ \kDIfNextHardCh|%
+ {\kDMitraFetchCellOptionsThen{#1}}
+ {#1}}
+
+\def\kDMitraFetchCellOptionsThen#1|#2|{\kDMitraCelOptTok={#2}#1}
+
+\newtoks\kDMitraCelCntTok
+
+\kDStoreCatcodeOf &
+\ifConTeXt\catcode`&=12\else\catcode`&=4\fi
+\def\kDMitraFetchCellContentThen#1#2&{%
+ \kDMitraCelCntTok={#2}%
+ \kDTrimLeadingSpace\kDMitraCelCntTok
+ \kDTrimTrailingSpace\kDMitraCelCntTok
+ #1}
+\kDRestoreCatcodeOf &
+
+\def\kDMitraMaybeDoCellThen#1{%
+ \kDIfNextHardCh\kD
+ {#1}%
+ {\kDMitraParseOneColThen{#1}}}
+
+\def\kDMitraPrintCellThen#1{%
+ \edef\kDAct{%
+ \noexpand\kDMitraTmpTok={%
+ \noexpand\node
+ [/mitra/every node]
+ \the\kDMitraCelOptTok
+ [node contents={\the\kDMitraCelCntTok},/mitra/matrix coordinates alias];
+ \kDMitraMaybeDumpCell}}%
+ \kDAct
+ \kDAppend\kDMitraTmpTok\kDMitraMatOutTok
+ #1}
+
+%==[ dumping routine ]==========================================================
+
+\def\kDMitraMaybeDumpCell{\noexpand\pgfextra{%
+ \noexpand\kDDump{'\noexpand\the\noexpand\pgfmatrixcurrentrow-\noexpand\the\noexpand\pgfmatrixcurrentcolumn':}%
+ \noexpand\kDDump{\space\space options: '\the\kDMitraCelOptTok'}%
+ \noexpand\kDDump{\space\space content: '\the\kDMitraCelCntTok'}}}
+
+%==[ output routine ]===========================================================
+
+\def\kDMitraOutput{%
+ \edef\kDAct{%
+ \noexpand\kDMitraTmpTok={%
+ \noexpand\matrix
+ [/mitra/every matrix]%
+ \the\kDOptTok
+ {\the\kDMitraMatOutTok};}}%
+ \kDAct
+ \the\kDMitraTmpTok}
diff --git a/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.ozos.code.tex b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.ozos.code.tex
new file mode 100644
index 0000000000..07d375cc43
--- /dev/null
+++ b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.ozos.code.tex
@@ -0,0 +1,58 @@
+%
+% CoDi: Commutative Diagrams for TeX
+% Copyright (c) 2015-2020 Paolo Brasolin <paolo.brasolin@gmail.com>
+% SPDX-License-Identifier: MIT
+%
+% This file is part of CoDi 1.0.0, released on 2020/06/06 under MIT license.
+%
+
+% όζος • (ózos)
+% 1. node
+% 2. nodule
+% 3. gnarl
+
+% Ozos is an alternative parsing mechanism for TiKz nodes.
+% It implements the following transformation
+% \kDOzos ... {CONTENTS}; ---> \node ... [node contents={CONTENTS}];
+% to ensure the node contents always pass through the TikZ key.
+
+\usetikzlibrary{commutative-diagrams.koinos}
+
+%==[ TikZ/pgf layer ]===========================================================
+
+\pgfkeys{/ozos/every node/.style={}}
+
+%==[ main macro ]===============================================================
+
+\def\kDOzos%
+ {\kDOzosFetchThen
+ {\kDOzosMaybeDumpThen
+ \kDOzosOutput}}
+
+%==[ fetching routine ]=========================================================
+
+% I use the general one implemented by koinos.
+\let\kDOzosFetchThen\kDFetchOptAndGrpThen
+
+%==[ parsing routine ]==========================================================
+
+% Trivially solved by fetching.
+
+%==[ dumping routine ]==========================================================
+
+\def\kDOzosMaybeDumpThen#1{%
+ \kDDump{options: '\the\kDOptTok'}%
+ \kDDump{content: '\the\kDGrpTok'}%
+ #1}
+
+%==[ output routine ]===========================================================
+
+\def\kDOzosOutput{
+ \edef\kDAct{
+ \noexpand\node
+ [/ozos/every node]
+ \the\kDOptTok
+ [/tikz/node contents={\the\kDGrpTok}];
+ }
+ \kDAct
+}
diff --git a/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.ramma.code.tex b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.ramma.code.tex
new file mode 100644
index 0000000000..1854abb67e
--- /dev/null
+++ b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.ramma.code.tex
@@ -0,0 +1,158 @@
+%
+% CoDi: Commutative Diagrams for TeX
+% Copyright (c) 2015-2020 Paolo Brasolin <paolo.brasolin@gmail.com>
+% SPDX-License-Identifier: MIT
+%
+% This file is part of CoDi 1.0.0, released on 2020/06/06 under MIT license.
+%
+
+% ράμμα • (rámma)
+% 1. suture
+% 2. catgut
+% 3. stitch
+
+% Ramma ties together the lower level libraries to define
+% the user level functionality. NOTE: strictly no aesthetics, see mandyas.
+
+\usetikzlibrary[commutative-diagrams.bapto]
+\usetikzlibrary[commutative-diagrams.ektropi]
+\usetikzlibrary[commutative-diagrams.katharizo]
+\usetikzlibrary[commutative-diagrams.koinos]
+\usetikzlibrary[commutative-diagrams.ozos]
+\usetikzlibrary[commutative-diagrams.mitra]
+\usetikzlibrary[commutative-diagrams.velos]
+
+%==[ core concept ]=============================================================
+
+\pgfqkeys{/codi}{% TODO: is this the best scope to put the key into?
+ self naming/.style={
+ /tikz/node contents/.forward to=/bapto/input,
+ /bapto/trigger/.forward to=/katharizo/input,
+ /katharizo/output/.forward to=/bapto/dispatcher
+ }
+}
+
+%==[ baseline setup ]===========================================================
+
+% Some mischief with handlers and baseline math/labeling functionality.
+
+\pgfqkeys{/codi}{
+ .search also=/bapto,
+ .search also=/katharizo,
+ every thing/.style={
+ /ektropi/restore,
+ /ektropi/add=/codi,
+ /ektropi/add=/bapto,
+ /ektropi/add=/katharizo
+ },
+ every diagram/.style={% NOTE: restore hopefully unnecessary
+ /codi/every thing,
+ /ektropi/add=/codi/diagrams
+ },
+ every layout/.style={% NOTE: restore actually unnecessary
+ /codi/every thing,
+ /ektropi/add=/codi/layouts,
+ /mitra/every node/.append style={/codi/every object}
+ },
+ every object/.style={% NOTE: needed when inside matrices
+ /codi/every thing,
+ /ektropi/add=/codi/objects,
+ execute at begin node=$,%
+ execute at end node=$,%
+ /codi/self naming
+ },
+ every arrow/.style={% NOTE: restore unnecessary
+ /codi/every thing,
+ /ektropi/add=/codi/arrows
+ },
+ every label/.style={% NOTE: restore needed because inside edge
+ /codi/every thing,
+ /ektropi/add=/codi/labels,
+ execute at begin node=$,%
+ execute at end node=$,%
+ /codi/self naming
+ }
+}
+
+% The user level keys are bound to the underlying parsers.
+
+\pgfkeys{
+ /mitra/every matrix/.append style=/codi/every layout,
+ /ozos/every node/.append style=/codi/every object,
+ /velos/every path/.append style={
+ /tikz/every edge/.append style=/codi/every arrow,
+ /tikz/every edge quotes/.append style=/codi/every label
+ }
+}
+
+% I merge the macro syntax for objects and matrices. Convenient!
+
+\newif\ifkDRammaObjIsMatrix
+
+\def\kDRammaObjDecideWhetherIsMatrixThen#1{%
+ \def\kDRammaObjDWIM{\kDRammaObjDWIMSightThen{\kDRammaObjDWIMGobThen{#1}}}%
+ \expandafter\kDRammaObjDWIM\the\kDGrpTok\\\kD}
+
+\def\kDRammaObjDWIMSightThen#1#2\\%
+ {\kDIfNextHardCh\kD
+ {\kDRammaObjIsMatrixfalse#1}%
+ {\kDRammaObjIsMatrixtrue#1}}
+
+\def\kDRammaObjDWIMGobThen#1#2\kD{#1}
+
+\def\kDRammaObjOutput
+ {\ifkDRammaObjIsMatrix
+ \kDMitraParseMatrixTableThen\kDMitraOutput\else
+ \kDOzosOutput\fi}
+
+\def\kDRammaObj
+ {\kDFetchOptAndGrpThen
+ {\kDRammaObjDecideWhetherIsMatrixThen
+ \kDRammaObjOutput}}
+
+% Just an identity.
+\let\kDRammaMor\kDVelos
+
+%==[ TikZ/pgf layer ]===========================================================
+
+% I envelope the CoDi main macros in a simple key for maximal flexibility.
+
+\tikzset{
+ codi/.code={%
+ \ifConTeXt\catcode`\|=12\fi% TODO: is it sufficient? investigate
+ \let\obj\kDRammaObj
+ \let\mor\kDRammaMor
+ },
+ codi/.append style={/codi/every diagram}
+}
+
+%==[ main macro ]===============================================================
+
+\def\kDRamma
+ {\kDRammaMaybeFetchOptionsThen
+ \kDRammaOutput}
+
+\let\kDRammaOpen\kDRamma
+\let\kDRammaShut\endtikzpicture
+
+%==[ fetching routine ]=========================================================
+
+\newtoks\kDRammaOptTok
+\newtoks\kDRammaTmpTok
+
+\def\kDRammaMaybeFetchOptionsThen#1{%
+ \kDRammaOptTok={}%
+ \kDIfNextHardCh[%
+ {\kDRammaFetchOptionsThen{#1}}%
+ {#1}}
+
+\def\kDRammaFetchOptionsThen#1[#2]{\kDRammaOptTok={#2}#1}
+
+%==[ output routine ]===========================================================
+
+\def\kDRammaOutput{%
+ \edef\kDAct{%
+ \noexpand\kDRammaTmpTok={%
+ \noexpand\tikzpicture[codi, \the\kDRammaOptTok]}}%
+ \kDAct
+ \the\kDRammaTmpTok}
diff --git a/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.velos.code.tex b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.velos.code.tex
new file mode 100644
index 0000000000..5072b97d7c
--- /dev/null
+++ b/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.velos.code.tex
@@ -0,0 +1,280 @@
+%
+% CoDi: Commutative Diagrams for TeX
+% Copyright (c) 2015-2020 Paolo Brasolin <paolo.brasolin@gmail.com>
+% SPDX-License-Identifier: MIT
+%
+% This file is part of CoDi 1.0.0, released on 2020/06/06 under MIT license.
+%
+
+% βέλος • (vélos)
+% 1. arrow
+% 2. dart
+% 3. shaft
+
+% Velos is a parsing mechanism for arrow chains.
+
+\usetikzlibrary{commutative-diagrams.koinos}
+
+%==[ TikZ/pgf layer ]===========================================================
+
+\pgfkeys{
+ % NOTE: there might be some way to work w/ quotes library, but it's safer and
+ % easier to just have a custom handler mounted in the maximally local scope
+ % and avoid any conflict a priori.
+ /velos/install quote handler/.style={
+ /handlers/first char syntax=true,
+ /handlers/first char syntax/the character "/.initial=\kDVelosQuoteHandler
+ % node quotes mean={node contents={#1}},
+ % edge quotes mean={node contents={#1}}
+ },
+ /velos/every path/.style={
+ /velos/install quote handler
+ }
+}
+
+\def\kDVelosQuoteHandler#1%
+ {\pgfkeysalso{/tikz/node contents/.expand once={\kDVelosUnquote#1}}}
+
+\def\kDVelosUnquote"#1"{#1}
+
+%==[ global options ]===========================================================
+
+\newtoks\kDVelosTemp
+
+\newtoks\kDVelosGlobalLabelOptions
+\newtoks\kDVelosGlobalEdgeOptions
+
+\newif\ifkDVelosGOAfterColon
+
+\def\kDVelosFetchGlobalOptionsThen#1{%
+ \kDVelosGOAfterColonfalse
+ \kDVelosGlobalLabelOptions={}%
+ \kDVelosGlobalEdgeOptions={}%
+ \kDVelosGOMaybeFetchThen{\kDVelosGOThinkThen{#1}}}
+
+\def\kDVelosGOMaybeFetchThen#1{%
+ \kDVelosTemp={}%
+ \kDIfNextHardCh[%
+ {\kDVelosGOFetchThen{#1}}%
+ {#1}}
+
+\def\kDVelosGOFetchThen#1[#2]{%
+ \kDVelosTemp={#2}%
+ #1}
+
+\def\kDVelosGOThinkThen#1{%
+ \def\kDVelosGOLoop{\kDVelosGOThinkThen{#1}}%
+ \def\kDVelosGOBreak{#1}%
+ \kDIfNextHardCh:%
+ {%
+ \kDVelosGOAfterColontrue
+ \kDVelosGlobalLabelOptions\expandafter{\the\kDVelosTemp}%
+ \expandafter\kDVelosGOMaybeFetchThen\expandafter\kDVelosGOLoop\kDGobbleHardTok
+ }{%
+ \ifkDVelosGOAfterColon
+ \kDVelosGlobalEdgeOptions\expandafter{\the\kDVelosTemp}\else
+ \kDVelosGlobalLabelOptions\expandafter{\the\kDVelosTemp}\fi
+ \kDVelosGOBreak
+ }}
+
+%==[ first edge ]===============================================================
+
+\def\kDVelosDoFirstEdgeThen#1%
+ {\kDVelosFetchFirstSourceThen
+ {\kDVelosFetchFirstEdgeThen
+ {\kDVelosDrawFetchedEdgeThen
+ {#1}}}}
+
+\newtoks\kDVelosSource
+\newtoks\kDVelosCurFstSrc
+\newtoks\kDVelosPrvFstSrc
+
+\def\kDVelosFetchFirstSourceThen#1%
+ {\kDIfNextHardCh(%
+ {\kDVelosFFSBracketsThen{#1}}%
+ {\kDVelosFFSTillOverThen{#1}}}
+
+\def\kDVelosFFSBracketsThen#1(#2){%
+ \kDVelosSource={#2}%
+ \kDVelosCurFstSrc={#2}%
+ #1}
+
+\def\kDVelosFFSTillOverThen#1#2 {% <- mind the space!
+ \kDVelosSource={#2}%
+ \kDVelosCurFstSrc={#2}%
+ #1}
+
+\def\kDVelosFetchFirstEdgeThen#1%
+ {\kDVelosFetchEdgeThen
+ {\kDVelosFetchTargetThen
+ {#1}}}
+
+%==[ chained edges ]============================================================
+
+\newtoks\kDVelosEdge
+
+\def\kDVelosFetchEdgeThen#1{%
+ \kDVelosEdge={}%
+ \kDVelosFEThen{\kDVelosFEThinkThen{#1}}}
+
+\def\kDVelosFEThen#1%
+ {\kDIfNextHardCh[%
+ {\kDVelosFEKeysListThen{#1}}%
+ {\kDIfNextHardCh"%
+ {\kDVelosFEEnquotedThen{#1}}%
+ {\kDVelosFETillOverThen{#1}}}}
+
+\newif\ifkDVelosTempIsKeysList
+
+\def\kDVelosFEEnquotedThen#1"#2"{%
+ \kDVelosTempIsKeysListfalse
+ \kDVelosTemp={#2}%
+ #1}
+
+\def\kDVelosFEKeysListThen#1[#2]{%
+ \kDVelosTempIsKeysListtrue
+ \kDVelosTemp={#2}%
+ #1}
+
+\def\kDVelosFETillOverThen#1{%
+ \kDVelosTempIsKeysListfalse
+ \kDVelosTemp={}%
+ \kDVelosFETOThen{#1}}
+
+\def\kDVelosFETOThen#1%
+ {\kDIfNextSoftCh\kDBlankSpace
+ {#1}%
+ {\kDIfNextHardCh:%
+ {#1}
+ {\kDVelosFEAppendThen{\kDVelosFETOThen{#1}}}}}
+
+\def\kDVelosFEAppendThen#1#2{%
+ \kDVelosTemp=\expandafter{\the\kDVelosTemp#2}%
+ #1}
+
+\def\kDVelosFEEdgePrepend#1{%
+ \edef\Act{\noexpand\kDVelosEdge={#1,\the\kDVelosEdge}}%
+ \Act}
+
+\def\kDVelosFEEdgePrependNode#1%
+ {\kDVelosFEEdgePrepend{edge node={node[every edge quotes][/velos/install quote handler,#1]}}}
+
+\def\kDVelosFEThinkThen#1{%
+ \def\kDVelosFELoop{\kDVelosFEThinkThen{#1}}%
+ \def\kDVelosFEBreak{#1}%
+ \kDIfNextHardCh[%
+ {%
+ \kDVelosFEEdgePrependNode{\the\kDVelosTemp}%
+ \kDVelosFEThen\kDVelosFELoop
+ }{%
+ \kDIfNextHardCh:%
+ {%
+ \ifkDVelosTempIsKeysList
+ \kDVelosFEEdgePrependNode{\the\kDVelosTemp}\else
+ \kDVelosFEEdgePrependNode{"\the\kDVelosTemp"}\fi
+ \expandafter\kDVelosFEThen\expandafter\kDVelosFELoop\kDGobbleHardTok
+ }{%
+ \kDVelosFEEdgePrepend{\the\kDVelosTemp}%
+ \kDVelosFEBreak
+ }%
+ }}
+
+%==[ target ]===================================================================
+
+\newtoks\kDVelosTarget
+\newtoks\kDVelosCurLstTar
+\newtoks\kDVelosPrvLstTar
+
+\def\kDVelosFetchTargetThen#1%
+ {\kDIfNextHardCh(%
+ {\kDVelosFTBracketsThen{#1}}%
+ {\kDVelosFTTillOverThen{#1}}}
+
+\def\kDVelosFTBracketsThen#1(#2){%
+ \kDVelosTarget={#2}%
+ \kDVelosCurLstTar={#2}%
+ #1}
+
+\def\kDVelosFTTillOverThen#1{%
+ \kDVelosTarget={}%
+ \kDVelosFTTOThen{#1}}
+
+\def\kDVelosFTTOThen#1{%
+ \def\kDVelosFTTOLoop%
+ {\kDVelosFTTOThen{#1}}%
+ \def\kDVelosFTTOExit{%
+ \kDVelosCurLstTar\expandafter{\the\kDVelosTarget}%
+ #1}%
+ \kDIfNextSoftCh\kDBlankSpace
+ {\kDVelosFTTOExit}%
+ {\kDIfNextHardCh;%
+ {\kDVelosFTTOExit}%
+ {\kDVelosFTAppendThen\kDVelosFTTOLoop}}}
+
+\def\kDVelosFTAppendThen#1#2{%
+ \kDVelosTarget=\expandafter{\the\kDVelosTarget#2}%
+ #1}
+
+%==[ rendering/dereferencing ]==================================================
+
+\def\kDVelosAlias{*}
+\def\kDVelosSaila{+}
+
+\newtoks\kDVelosDerefSrc
+\newtoks\kDVelosDerefTar
+
+\def\kDVelosDrawFetchedEdgeThen#1{
+ \edef\cS{\the\kDVelosSource}%
+ \kDVelosDerefSrc\expandafter{\the\kDVelosSource}%
+ \ifx\cS\kDVelosAlias\kDVelosDerefSrc\expandafter{\the\kDVelosPrvFstSrc}\fi
+ \ifx\cS\kDVelosSaila\kDVelosDerefSrc\expandafter{\the\kDVelosPrvLstTar}\fi
+ \edef\cT{\the\kDVelosTarget}%
+ \kDVelosDerefTar\expandafter{\the\kDVelosTarget}%
+ \ifx\cT\kDVelosAlias\kDVelosDerefTar\expandafter{\the\kDVelosPrvLstTar}\fi
+ \ifx\cT\kDVelosSaila\kDVelosDerefTar\expandafter{\the\kDVelosPrvFstSrc}\fi
+ \edef\Act{%
+ \noexpand\path
+ [/velos/every path]%
+ [%
+ /tikz/every edge/.append style=%
+ {\the\kDVelosGlobalEdgeOptions},%
+ /tikz/every edge quotes/.append style=%
+ {auto,\the\kDVelosGlobalLabelOptions},%
+ ]%
+ (\the\kDVelosDerefSrc)%
+ edge[\the\kDVelosEdge]%
+ (\the\kDVelosDerefTar);}%
+ \Act%
+ #1}
+
+%==[ high level ]===============================================================
+
+\def\kDVelos%
+ {\kDVelosFetchGlobalOptionsThen
+ {\kDVelosDoFirstEdgeThen
+ \kDVelosMaybeChainEdge}}
+
+\def\kDVelosMaybeChainEdge{%
+ \kDIfNextHardCh;%
+ {%
+ \edef\cS{\the\kDVelosCurFstSrc}%
+ \ifx\cS\kDVelosAlias
+ \kDVelosCurFstSrc\expandafter{\the\kDVelosPrvFstSrc}%
+ \else\ifx\cS\kDVelosSaila
+ \kDVelosCurFstSrc\expandafter{\the\kDVelosPrvLstTar}%
+ \fi\fi
+ \edef\cT{\the\kDVelosCurLstTar}%
+ \ifx\cT\kDVelosAlias
+ \kDVelosCurLstTar\expandafter{\the\kDVelosPrvLstTar}%
+ \else\ifx\cT\kDVelosSaila
+ \kDVelosCurLstTar\expandafter{\the\kDVelosPrvFstSrc}%
+ \fi\fi
+ \kDVelosPrvFstSrc\expandafter{\the\kDVelosCurFstSrc}%
+ \kDVelosPrvLstTar\expandafter{\the\kDVelosCurLstTar}%
+ }{%
+ \kDVelosSource\expandafter{\the\kDVelosTarget}
+ \kDVelosFetchEdgeThen
+ {\kDVelosFetchTargetThen
+ {\kDVelosDrawFetchedEdgeThen
+ \kDVelosMaybeChainEdge}}%
+ }}
diff --git a/graphics/pstricks/contrib/pst-func/Changes b/graphics/pstricks/contrib/pst-func/Changes
index cd9eec4c30..32534e1f7f 100644
--- a/graphics/pstricks/contrib/pst-func/Changes
+++ b/graphics/pstricks/contrib/pst-func/Changes
@@ -1,4 +1,6 @@
..... pst-func.tex
+0.95 2020-06-06 - another two more polynomial functions
+0.94 2020-01-01 - small fixes
0.93 2019-05-17 - fix for missing end in a local dictionary (\psBinomialX)
0.92 2018-12-13 - allow algebraic mode for \pscumIntegral
0.91 2018-11-15 - new algorithm for sin/cos integral to prevent problems
diff --git a/graphics/pstricks/contrib/pst-func/README.md b/graphics/pstricks/contrib/pst-func/README.md
index 3297389d3e..d7afcc5c61 100644
--- a/graphics/pstricks/contrib/pst-func/README.md
+++ b/graphics/pstricks/contrib/pst-func/README.md
@@ -6,6 +6,8 @@
- psBernstein (with envelope option)
- psFourier
- psBessel
+- psLagrange
+- psLegendre
- psSi and pssi (integral sin)
- psCi and \psci (integral cosin)
- psIntegral
@@ -45,3 +47,5 @@ with pdftex, use the sequence latex->dvips->ps2pdf or
pdflatex with package auto-pst-pdf or xelatex.
%% $Id: README 897 2014-03-21 08:06:41Z herbert $
+
+Bugs: hvoss@tug.org \ No newline at end of file
diff --git a/graphics/pstricks/contrib/pst-func/doc/pst-func-doc.pdf b/graphics/pstricks/contrib/pst-func/doc/pst-func-doc.pdf
index e3f65b7c0c..740e2568d6 100644
--- a/graphics/pstricks/contrib/pst-func/doc/pst-func-doc.pdf
+++ b/graphics/pstricks/contrib/pst-func/doc/pst-func-doc.pdf
Binary files differ
diff --git a/graphics/pstricks/contrib/pst-func/doc/pst-func-doc.tex b/graphics/pstricks/contrib/pst-func/doc/pst-func-doc.tex
index bf8628902f..cf3819048b 100644
--- a/graphics/pstricks/contrib/pst-func/doc/pst-func-doc.tex
+++ b/graphics/pstricks/contrib/pst-func/doc/pst-func-doc.tex
@@ -1,4 +1,4 @@
-%% $Id: pst-func-doc.tex 861 2018-12-13 20:40:06Z herbert $
+%% $Id: pst-func-doc.tex 1184 2020-06-06 18:36:57Z herbert $
\documentclass[fontsize=11pt,english,BCOR=10mm,DIV=12,bibliography=totoc,parskip=false,
headings=small, headinclude=false,footinclude=false,oneside]{pst-doc}
\usepackage{pst-func}
@@ -607,6 +607,68 @@ which plots the envelope curve instead of the Bernstein polynomial.
\clearpage
+
+
+\subsection{Laguerre Polynomial}
+It is defined as
+\[
+L_n(x)=\sum_{k=0}^n\frac{(-1)^k}{k!}\binom{n}{k}x^k
+\]
+
+\begin{LTXexample}
+\psset{xunit=1.5}
+\begin{pspicture}(-1,-4)(6,6)
+\psaxes{->}(0,0)(-1,-4)(5,6)
+\psset{yMaxValue=5,plotpoints=100,linewidth=1pt}
+\psLaguerre[n=0,linecolor=red](-1,5)\uput[0](5,1){$L_0$}
+\psLaguerre[n=1,linecolor=green](-1,5)\uput[0](4,-2.5){$L_1$}
+\psLaguerre[n=2,linecolor=blue](-1,5)\uput[0](4.5,2){$L_2$}
+\psLaguerre[n=3,linecolor=yellow](-1,5)\uput[0](5,2.5){$L_3$}
+\psLaguerre[n=4,linecolor=brown](-1,5)\uput[0](5,-1){$L_4$}
+\end{pspicture}
+\end{LTXexample}
+
+
+\psset{unit=1cm}
+
+\clearpage
+
+
+\subsection{Legendre Polynomial}
+It is defined as an orthogonal system
+\[
+\int\limits_{-1}^{+1}P_m(x)(P_n(x)\mathrm dx=0, \text{ with } n\ne m
+\]
+
+For the computatíon we use a recursive definition:
+
+\begin{align*}
+P_0(x) &= 1\\
+P_{1}(x) &= x\\
+n\cdot P_{n}(x) &= (2n-1)x\cdot P_{n-1}(x)-(n-1)P_{n-2}(x)
+\end{align*}
+
+
+\begin{LTXexample}
+\psset{xunit=3,yunit=2}
+\begin{pspicture}[showgrid](-2,-2)(2,2)
+\psaxes[labels=none]{->}(0,0)(-2,-2)(2,2)
+\psset{yMaxValue=1.9,yMinValue=-2,plotpoints=200,linewidth=1.5pt}
+\psLegendre[n=0,linecolor=red](-2,2)\uput[0](2,1){\textcolor{red}{$L_0$}}
+\psLegendre[n=1,linecolor=green](-2,2)\uput[0](2,2){\textcolor{green}{$L_1$}}
+\psLegendre[n=2,linecolor=blue](-2,2)\uput[0](1.3,1.8){\textcolor{blue}{$L_2$}}
+\psLegendre[n=3,linecolor=yellow](-2,2)\uput*[0](-1,-1.8){\textcolor{yellow}{$L_3$}}
+\psLegendre[n=4,linecolor=brown](-2,2)\uput*[0](-1,2){\textcolor{brown}{$L_4$}}
+\end{pspicture}
+\end{LTXexample}
+
+
+\psset{unit=1cm}
+
+
+
+
+\clearpage
\section{Calculating the zeros of a function or the the intermediate point of two function}
\begin{BDef}
@@ -1136,8 +1198,6 @@ way, at the cost of some reduction in graphics resolution.
\end{LTXexample}
\clearpage
-
-\clearpage
\section{Modfied Bessel function of first order}
The modified Bessel function of first order is defined as
%
@@ -1166,6 +1226,9 @@ is preset to 0, it shows $I_0$.
\end{LTXexample}
\clearpage
+
+
+
\section{\Lcs{psSi}, \Lcs{pssi} and \Lcs{psCi}}
The integral sin and cosin are defined as
%
diff --git a/graphics/pstricks/contrib/pst-func/tex/pst-func.tex b/graphics/pstricks/contrib/pst-func/tex/pst-func.tex
index 0bef36090b..c581b1e49f 100644
--- a/graphics/pstricks/contrib/pst-func/tex/pst-func.tex
+++ b/graphics/pstricks/contrib/pst-func/tex/pst-func.tex
@@ -1,4 +1,4 @@
-%% $Id: pst-func.tex 861 2018-12-13 20:40:06Z herbert $
+%% $Id: pst-func.tex 1184 2020-06-06 18:36:57Z herbert $
%%
%% This is file `pst-func.tex',
%%
@@ -31,8 +31,8 @@
% interface to the `xkeyval' package
\pst@addfams{pst-func}
%
-\def\fileversion{0.93}
-\def\filedate{2019/05/17}
+\def\fileversion{0.95}
+\def\filedate{2020/06/06}
\message{`PST-func' v\fileversion, \filedate\space (hv)}
%
\pstheader{pst-func.pro}
@@ -268,6 +268,48 @@
}%
}\ignorespaces}
%
+\define@key[psset]{pst-func}{n}[1]{\def\psk@func@n{#1 }}
+\psset[pst-func]{n=0}
+\def\psLaguerre{\@ifnextchar[{\psLaguerre@i}{\psLaguerre@i[]}}%% hv 20200111
+\def\psLaguerre@i[#1](#2,#3){{%%% n
+ \pst@killglue%
+ \psplot[#1]{#2}{#3}{%
+ /L_n 1 def
+ 0 1 \psk@func@n {
+ /k_i ED
+ -1 k_i exp k_i factorial div
+ \psk@func@n k_i MoverN mul
+ x k_i exp mul L_n add
+ /L_n ED
+ } for
+ x \pst@number\psxunit mul L_n
+ %dup == %\pst@number\psyunit div
+ }%
+}\ignorespaces}
+%
+\def\psLegendre{\@ifnextchar[{\psLegendre@i}{\psLegendre@i[]}}%% hv 20200115
+\def\psLegendre@i[#1](#2,#3){{%%% n
+ \pst@killglue%
+ \psplot[#1]{#2}{#3}{%
+ /P_n 0 def
+ \psk@func@n 0 eq { /P_1 1 def }{ \psk@func@n 1 eq { /P_1 x def }
+ { /P_0 1 def
+ /P_1 x def
+ 2 1 \psk@func@n {
+ /k_i ED
+ k_i dup add 1 sub x mul P_1 mul % (2n-1)*x*P_1
+ k_i 1 sub P_0 mul sub % − ( n−1 ) P_{n-2}(x)
+ k_i div
+ /P_0 P_1 def
+ /P_1 ED
+ } for
+%n Pn ( x ) = ( 2n − 1 ) P_{n−1}(x) − ( n−1 ) P_{n-2}(x)
+ } ifelse } ifelse
+ x \pst@number\psxunit mul P_1
+ %dup == %\pst@number\psyunit div
+ }%
+}\ignorespaces}
+%
\define@key[psset]{pst-func}{sigma}[0.5]{\def\psk@sigma{#1 }}
\define@key[psset]{pst-func}{mue}[0]{\def\psk@mue{#1 }}
\define@key[psset]{pst-func}{nue}[1]{\def\psk@nue{#1 }}