texlive[61764] Master/texmf-dist: mandi (27jan22)

commits+karl at tug.org commits+karl at tug.org
Thu Jan 27 22:41:20 CET 2022


Revision: 61764
          http://tug.org/svn/texlive?view=revision&revision=61764
Author:   karl
Date:     2022-01-27 22:41:19 +0100 (Thu, 27 Jan 2022)
Log Message:
-----------
mandi (27jan22)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/mandi/README.md
    trunk/Master/texmf-dist/doc/latex/mandi/mandi.pdf
    trunk/Master/texmf-dist/source/latex/mandi/mandi.dtx
    trunk/Master/texmf-dist/source/latex/mandi/mandi.ins
    trunk/Master/texmf-dist/source/latex/mandi/mandiexp.dtx
    trunk/Master/texmf-dist/source/latex/mandi/mandistudent.dtx
    trunk/Master/texmf-dist/tex/latex/mandi/mandi.sty
    trunk/Master/texmf-dist/tex/latex/mandi/mandiexp.sty
    trunk/Master/texmf-dist/tex/latex/mandi/mandistudent.sty

Modified: trunk/Master/texmf-dist/doc/latex/mandi/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/mandi/README.md	2022-01-27 21:41:00 UTC (rev 61763)
+++ trunk/Master/texmf-dist/doc/latex/mandi/README.md	2022-01-27 21:41:19 UTC (rev 61764)
@@ -1,10 +1,10 @@
-mandi provides commands for introductory physics. To install, open a command
+`mandi` provides commands for introductory physics. To install, open a command
 line  and  type  the  following,  repeating 2-4 until there are no warnings:
 
-1. lualatex mandi.ins  (can also use latex)
-2. lualatex mandi.dtx  (lualatex is required)
-3. makeindex -s gind.ist -o mandi.ind mandi.idx
-4. makeindex -s gglo.ist -o mandi.gls mandi.glo
+1. `lualatex mandi.ins`  (can also use latex)
+2. `lualatex mandi.dtx`  (lualatex is required)
+3. `makeindex -s gind.ist -o mandi.ind mandi.idx`
+4. `makeindex -s gglo.ist -o mandi.gls mandi.glo`
 
-Move the *.sty files into a directory searched by TeX.
-The vdemo.py file is not needed.
+Move the `*.sty` files into a directory searched by TeX.
+The `vdemo.py` file is not needed and can be deleted.

Modified: trunk/Master/texmf-dist/doc/latex/mandi/mandi.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/source/latex/mandi/mandi.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/mandi/mandi.dtx	2022-01-27 21:41:00 UTC (rev 61763)
+++ trunk/Master/texmf-dist/source/latex/mandi/mandi.dtx	2022-01-27 21:41:19 UTC (rev 61764)
@@ -1,7 +1,7 @@
 % \iffalse meta-comment
 % !TEX program = lualatexmk
 %
-% Copyright (C) 2021 by Paul J. Heafner <heafnerj at gmail.com>
+% Copyright (C) 2021,2022 by Paul J. Heafner <heafnerj at gmail.com>
 % ---------------------------------------------------------------------------
 % This  work may be  distributed and/or modified  under the conditions of the 
 % LaTeX Project Public  License, either  version 1.3  of this  license or (at 
@@ -53,7 +53,14 @@
 %
 %<*driver>
 \ProvidesFile{mandi.dtx}
-\documentclass[10pt]{ltxdoc}
+% As of 2021-12-02 ltxdoc.cls picks up ltxdoc.cfg and sets
+% the default paper size to a4paper rather than letter. 
+% This can be changed in a local ltxdoc.cfg file but it is 
+% easier to just use the article class and the doc package 
+% instead and force letterpaper size.
+% \documentclass[10pt]{ltxdoc}
+\documentclass[10pt,letterpaper]{article}
+\usepackage{doc}
 \PassOptionsToPackage{listings,documentation}{tcolorbox} % prevent option clash
 \usepackage{\jobname}                                    % load mandi.sty
 \usepackage{mandistudent}                                % load mandistudent.sty
@@ -79,12 +86,6 @@
       colback = gray!10!white,sidebyside,lefthand ratio = 0.5,center},%
   listing style = vpython,%
 }%
-% Redefine tcolorbox's \tcbdocnew and \tcbdocupdated defaults.
-\renewcommand*{\tcbdocnew}[1]
-  {\textcolor{green!50!black}{\sffamily\bfseries N} #1}
-\renewcommand*{\tcbdocupdated}[1]
-  {\textcolor{blue!75!black}{\sffamily\bfseries U} #1}
-\hypersetup{colorlinks=true}                      % colored links; no borders
 
 %  See https://tex.stackexchange.com/q/156383/218142
 \newcommand*{\pkg}[1]{\textsf{#1}}                    % typeset package names
@@ -91,33 +92,66 @@
 \newcommand*{\mandi}{\textsf{mandi}}                  % typeset mandi
 \newcommand*{\mandistudent}{\textsf{mandistudent}}    % typeset mandistudent
 \newcommand*{\mandiexp}{\textsf{mandiexp}}            % typeset mandiexp
-\newcommand*{\GlowScript}{\texttt{GlowScript}}        % typeset GlowScript
-\newcommand*{\GlowScriptorg}{\texttt{GlowScript.org}} % typeset GlowScript.org
+\newcommand*{\WebVPython}{\texttt{Web VPython}}       % typeset Web VPython
+\newcommand*{\WebVPythonorg}{\texttt{WebVPython.org}} % typeset WebVPython.org
 \newcommand*{\VPython}{\texttt{VPython}}              % typeset VPython
 \newcommand*{\VPythonorg}{\texttt{VPython.org}}       % typeset VPython.org
-\newcommand*{\gsurl}{glowscript.org}                  % GlowScript URL
+\newcommand*{\gsurl}{webvpython.org}                  % Web VPython URL
 \newcommand*{\vpurl}{vpython.org}                     % VPython URL
 \newcommand*{\lualatex}{Lua\LaTeX}                    % typeset LuaLaTeX
 
+%%%%% Some local hacks to make things better.
+% Redefine tcolorbox's \tcbdocnew and \tcbdocupdated defaults.
+\renewcommand*{\tcbdocnew}[1]
+  {\textcolor{green!50!black}{\sffamily\bfseries N} #1}
+\renewcommand*{\tcbdocupdated}[1]
+  {\textcolor{blue!75!black}{\sffamily\bfseries U} #1}
+\hypersetup{colorlinks=true}                      % colored links; no borders
+
 % A customized internal hyperref tool to mimic that in tcolorbox.
 % In fact, I borrowed it from tcolorbox.
-\NewDocumentCommand{\setplace}{ s m }{%
-  \IfBooleanTF {#1}%
-    {\phantomsection}%
-    {}%
-  \label{#2}%    
-}%
-\NewDocumentCommand{\linktoplace}{ m m }{%
-  \hyperref[#1]{\texttt{#2}%
-    \ifnum\getpagerefnumber{#1}=\thepage\relax%
-    \else%
-      %\textsuperscript{\ding{213}\,{P.}\,\pageref*{#1}}%
-      % Changed with tcolorbox 4.51
-      \textsuperscript{{\fontfamily{pzd}\fontencoding{U}\fontseries{m}\fontshape{n}\selectfont\char213}
-        \,{P.}\,\pageref*{#1}}%
-    \fi%
+\NewDocumentCommand{\setplace}{ s m }%
+  {%
+    \IfBooleanTF {#1}%
+      {\phantomsection}%
+      {}%
+    \label{#2}%    
   }%
+\NewDocumentCommand{\linktoplace}{ m m }%
+  {%
+    \hyperref[#1]{\texttt{#2}%
+      \ifnum\getpagerefnumber{#1}=\thepage\relax%
+      \else%
+        %\textsuperscript{\ding{213}\,{P.}\,\pageref*{#1}}%
+        % Changed with tcolorbox 4.51
+        \textsuperscript{{\fontfamily{pzd}\fontencoding{U}\fontseries{m}\fontshape{n}\selectfont\char213}
+          \,{P.}\,\pageref*{#1}}%
+      \fi%
+    }%
+  }%
+
+% Clean up the Change History entries to get rid of General:
+% and add dates.
+%  See https://tex.stackexchange.com/a/283894/218142
+\renewcommand{\generalname}{} % gets rid of General
+\makeatletter
+\renewcommand*{\changes@}[3]{%
+ \protected at edef\@tempa{%
+  \noexpand\glossary{#1 (#2)\levelchar
+   \ifx\saved at macroname\@empty
+    \space\actualchar\generalname
+   \else
+    \expandafter\@gobble\saved at macroname
+    \actualchar
+    \string\verb\quotechar*\verbatimchar\saved at macroname\verbatimchar
+   \fi
+   #3}}% gets rid of colon and adjusts spacing
+ \@tempa
+ \endgroup
+ \@esphack
 }%
+\makeatother
+%%%%% End local hacks.
 
 % We need a new command for in-line listings to prevent overfull boxes.
 % Anything in |...| will be in small plain text.
@@ -142,7 +176,7 @@
 % \IndexPrologue{\section{Index}Page numbers refer to page where the 
 %   corresponding entry is documented and/or referenced.}
 % 
-% \CheckSum{2171}
+% \CheckSum{2156}
 %
 % \CharacterTable
 %  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
@@ -184,21 +218,21 @@
 %   \phantomsection
 %   \addcontentsline{toc}{section}{Acknowledgements}
 %   \section*{Acknowledgements}
-%   To all of the students who have learned \LaTeX\ in my introductory
+%   To all of the students who have learned \LaTeXe\ in my introductory
 %   physics courses over the years, I say a heartfelt thank you. You
 %   have contributed directly to the state of this software and to its
 %   use in introductory physics courses and to innovating how physics
 %   is taught.
 %
-%   I also acknowledge the \LaTeX\ developers who inhabit the
+%   I also acknowledge the \LaTeXe\ developers who inhabit the
 %   \href{https://tex.stackexchange.com/}{\TeX\ StackExchange} site. 
 %   Entering a new culture is daunting for anyone, especially for
-%   newcomers. The \LaTeX\ development culture is no exception. We all
+%   newcomers; the \LaTeXe\ development culture is no exception. We all
 %   share a passion for creating beautiful documents and I have learned
-%   much over the past year that improved my ability to do just that.
-%   There are too many of you to list individually, and I would surely 
-%   accidentally omit some were I to try. Collectively, I thank you all
-%   for your patience and advice.
+%   much over the summers of 2020 and 2021 that improved my ability to 
+%   do just that. There are too many of you to list individually, and I 
+%   would surely accidentally omit some were I to try. Collectively, I 
+%   thank you all for your patience and advice.
 %   \newpage
 %   \phantomsection
 %   \addcontentsline{toc}{section}{Change History}
@@ -205,8 +239,8 @@
 %   \PrintChanges
 %   \newpage
 %   \phantomsection
-%   \addcontentsline{toc}{section}{List of \texttt{GlowScript} Programs}
-%   \listofglowscriptprograms
+%   \addcontentsline{toc}{section}{List of \texttt{Web VPython} Programs}
+%   \listofwebvpythonprograms
 %   \phantomsection
 %   \addcontentsline{toc}{section}{List of \texttt{VPython} Programs}
 %   \listofvpythonprograms
@@ -215,9 +249,12 @@
 %   \listoffigures
 % \restoregeometry
 %
-% \changes{v3.0.0}{2021-08-22}{\mandi\ initial release}
-% \changes{v3.0.0}{2021-08-22}{\mandistudent\ initial release}
-% \changes{v3.0.0}{2021-08-22}{\mandiexp\ initial release}
+% \changes{v3.0.0}{2021-08-22}{\linktoplace{sec:mandipkg}{mandi} Initial release}
+% \changes{v3.0.0}{2021-08-22}{\linktoplace{sec:mandistudentpkg}{mandistudent} Initial release}
+% \changes{v3.0.0}{2021-08-22}{\linktoplace{sec:mandiexppkg}{mandiexp} Initial release}
+% \changes{v3.0.1}{2021-08-24}{\linktoplace{sec:mandipkg}{mandi} Minor doc changes}
+% \changes{v3.0.1}{2021-08-24}{\linktoplace{sec:mandistudentpkg}{mandistudent} Minor doc changes}
+% \changes{v3.0.1}{2021-08-24}{\linktoplace{sec:mandiexppkg}{mandiexp} Minor doc changes}
 %
 % \section{Introduction}
 %
@@ -249,10 +286,21 @@
 % as well as new, users is to treat this as a brand new experience. I think
 % the most important thing to keep in mind is that I assume users, 
 % expecially new users, will have a relatively recent TeX distribution 
-% (like TeX Live) that includes a recently updated \LaTeX\ kernel. If users
+% (like TeX Live) that includes a recently updated \LaTeXe\ kernel. If users
 % report that this is a major problem, I can provide some degree of
-% backwards compatibility.
+% backwards compatibility. However, I use a fully updated TeX Live distribution.
 % 
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandipkg}{mandi} Added GitHub links to code}
+% \section{Code Availability}
+% The \mandi\ source repository's \texttt{main} branch is at 
+% \url{https://github.com/heafnerj/mandi}. This code will usually coincide
+% with that found on \href{https://ctan.org/pkg/mandi}{CTAN}. The very latest
+% build can be found on the \texttt{dev} branch found at
+% \url{https://github.com/heafnerj/mandi/tree/dev}. Students and other academic
+% academic users should probably get the \texttt{dev} branch code since it is
+% stable and may contain improvements over the \texttt{main} branch code.
+%
 % \newpage
 % \section{Student/Instructor Quick Guide}
 %
@@ -266,7 +314,7 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{dispExample*}{lefthand ratio=0.80}
+\begin{dispExample*}{lefthand ratio = 0.80}
   \( \vec{p} \) or \( \vec*{p} \)                                         \\
   \( \vec{p}_{\symup{final}} \) or \( \vec*{p}_{\symup{final}} \)         \\
   \( \magnitude{\vec{p}} \) or \( \magnitude*{\vec{p}_{\symup{final}}} \) \\
@@ -306,7 +354,7 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{dispExample*}{lefthand ratio=0.70}
+\begin{dispExample*}{lefthand ratio = 0.70}
   \( \vacuumpermittivitymathsymbol = \vacuumpermittivity \)
 \end{dispExample*}
 %\iffalse
@@ -314,12 +362,12 @@
 %\fi
 %
 % Use \refCom{mivector} to typeset symbolic vectors with components.
-% Use the aliases \refCom{direction} to typeset a direction or unit 
+% Use the alias \refCom{direction} to typeset a direction or unit 
 % vector.
 %\iffalse
 %<*example>
 %\fi
-\begin{dispExample*}{sidebyside=false}
+\begin{dispExample*}{sidebyside = false}
   \( \mivector{\slot,\slot,\slot} \) or \( \mivector{p_x,p_y,p_z} \) \\
   \( \direction{\frac{1}{\sqrt{3}},\frac{1}{\sqrt{3}},\frac{1}{\sqrt{3}}} \) or
 \end{dispExample*}
@@ -329,8 +377,8 @@
 %
 % Use \refEnv{physicsproblem} and \refEnv{parts} and \refCom{problempart} 
 % for problems. For step-by-step mathematical solutions use
-% \refEnv{physicssolution}. Use \refEnv{glowscriptblock} to typeset  
-% \href{https://\gsurl}{\GlowScript} programs. Use \refCom{vpythonfile} to 
+% \refEnv{physicssolution}. Use \refEnv{webvpythonblock} to typeset  
+% \href{https://\gsurl}{\WebVPython} programs. Use \refCom{vpythonfile} to 
 % typeset \href{https://\vpurl}{VPython} program files. 
 %
 % \newpage
@@ -341,7 +389,7 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{dispListing*}{sidebyside=false,listing only}
+\begin{dispListing*}{sidebyside = false,listing only}
   \usepackage[options]{mandi}
 \end{dispListing*}
 %\iffalse
@@ -354,7 +402,7 @@
 \begin{docCommand}{mandiversion}{}
   Typesets the current version and build date.
 \end{docCommand}
-\begin{dispExample*}{sidebyside=false}
+\begin{dispExample*}{sidebyside = false}
   The version is \mandiversion\ and is a stable build.
 \end{dispExample*}
 %\iffalse
@@ -391,7 +439,7 @@
 %</example>
 %\fi
 %
-% \subsection{The \texttt{mandisetup} Command}
+% \subsection{The \texttt{\small mandisetup} Command}
 % 
 %\iffalse
 %<*example>
@@ -401,14 +449,14 @@
   can be done in the preamble or inside the 
   |\begin{document}...\end{document}| environment.
 \end{docCommand}
-\begin{dispListing*}{sidebyside=false,listing only}
+\begin{dispListing*}{sidebyside = false,listing only}
   \mandisetup{units=base}
 \end{dispListing*}
-\begin{dispListing*}{sidebyside=false,listing only}
+\begin{dispListing*}{sidebyside = false,listing only}
   \mandisetup{preciseconstants}
 \end{dispListing*}
-\begin{dispListing*}{sidebyside=false,listing only}
-  \mandisetup{preciseconstants=false}
+\begin{dispListing*}{sidebyside = false,listing only}
+  \mandisetup{preciseconstants = false}
 \end{dispListing*}
 %\iffalse
 %</example>
@@ -442,11 +490,11 @@
     {%
       doc new = 2021-02-24,%
       doc name = momentumvector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectormomentum,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
   Command for momentum and its vector variants. The default units will depend 
@@ -455,7 +503,7 @@
   take more than three components. Note the other variants for the quantity's 
   value and units.
 \end{docCommands}
-\begin{dispExample*}{lefthand ratio=0.60}
+\begin{dispExample*}{lefthand ratio = 0.60}
   \( \momentum{5} \)                         \\
   \( \momentumvalue{5} \)                    \\
   \( \momentumbaseunits{5} \)                \\
@@ -496,7 +544,7 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{docCommand}[doc new = 2021-02-16]{checkquantity}{\marg{name}}
+\begin{docCommand}[doc updated = 2022-01-27]{checkquantity}{\marg{name}}
   Command to check and typeset the command, base units, 
   derived units, and alternate units of a defined physical 
   quantity.
@@ -527,11 +575,11 @@
     {%
       doc new = 2021-02-24,%
       doc name = accelerationvector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectoracceleration,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -548,11 +596,11 @@
     {%
       doc new = 2021-02-24,%
       doc name = angularaccelerationvector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectorangularacceleration,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -569,11 +617,11 @@
     {%
       doc new = 2021-02-24,%
       doc name = angularimpulsevector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {% 
       doc name = vectorangularimpulse,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -587,11 +635,11 @@
     {%
       doc new = 2021-02-24,%
       doc name = angularmomentumvector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectorangularmomentum,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -605,11 +653,11 @@
     {%
       doc new = 2021-02-24,%
       doc name = angularvelocityvector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectorangularvelocity,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -638,11 +686,11 @@
     {%
       doc new = 2021-02-24,%
       doc name = cmagneticfieldvector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectorcmagneticfield,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -668,11 +716,11 @@
     {%
       doc new = 2021-02-24,%
       doc name = currentdensityvector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectorcurrentdensity,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -689,11 +737,11 @@
     },%
     {%
       doc name = directionvector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectordirection,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -707,11 +755,11 @@
     {%
       doc new = 2021-02-24,%
       doc name = displacementvector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectordisplacement,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -728,10 +776,10 @@
     {%
       doc new = 2021-02-24,%
       doc name = electricdipolemomentvector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     { doc name = vectorelectricdipolemoment,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -745,11 +793,11 @@
     {%
       doc new = 2021-02-24,%
       doc name = electricfieldvector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectorelectricfield,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -793,11 +841,11 @@
     {%
       doc new = 2021-02-24,%
       doc name = energyfluxvector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectorenergyflux,% 
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -814,11 +862,11 @@
     {%
       doc new = 2021-02-24,%
       doc name = forcevector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectorforce,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -835,11 +883,11 @@
     {%
       doc new = 2021-02-24,%
       doc name = gravitationalfieldvector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectorgravitationalfield,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -859,11 +907,11 @@
     {%
       doc new = 2021-02-24,%
       doc name = impulsevector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectorimpulse,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -880,6 +928,9 @@
 \begin{docCommand}{linearmassdensity}{\marg{magnitude}}
 \end{docCommand}
 \checkquantity{linearmassdensity}
+\begin{docCommand}[doc new = 2022-01-27]{lorentzfactor}{\marg{magnitude}}
+\end{docCommand}
+\checkquantity{lorentzfactor}
 \begin{docCommand}[doc updated = 2021-05-02]{luminousintensity}{\marg{magnitude}}
 \end{docCommand}
 \checkquantity{luminousintensity}
@@ -895,11 +946,11 @@
     {%
       doc new = 2021-02-24,%
       doc name = magneticdipolemomentvector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectormagneticdipolemoment,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -913,11 +964,11 @@
     {%
       doc new = 2021-02-24,%
       doc name = magneticfieldvector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectormagneticfield,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -945,12 +996,12 @@
       doc new = 2021-02-24,%
       doc name = momentumvector,%
       doc label = momentumvectordemo,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectormomentum,%
       doc label = vectormomentumdemo,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}} },%
+      doc parameter = \marg{\( c_1,\dots,c_n \)} },%
   }%
 \end{docCommands}
 \checkquantity{momentum}
@@ -963,11 +1014,11 @@
     {%
       doc new = 2021-02-24,%
       doc name = momentumfluxvector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {% 
       doc name = vectormomentumflux,% 
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -999,11 +1050,11 @@
     {%
       doc new = 2021-02-24,%
       doc name = poyntingvector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectorpoynting,% 
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -1053,11 +1104,11 @@
     {%
       doc new = 2021-02-24,%
       doc name = torquevector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectortorque,% 
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -1071,12 +1122,17 @@
     {%
       doc new = 2021-02-24,%
       doc name = velocityvector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectorvelocity,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
+  }%
+\end{docCommands}
+\checkquantity{velocity}
+\begin{docCommands}
+  {%
     {%
       doc name = velocityc,%
       doc parameter = \marg{magnitude},%
@@ -1084,15 +1140,14 @@
     {%
       doc new = 2021-02-24,%
       doc name = velocitycvector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectorvelocityc,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
-\checkquantity{velocity}
 \checkquantity{velocityc}
 \begin{docCommand}{volume}{\marg{magnitude}}
 \end{docCommand}
@@ -1115,11 +1170,11 @@
     {%
       doc new = 2021-02-24,%
       doc name = wavenumbervector,%
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
     {%
       doc name = vectorwavenumber,% 
-      doc parameter = \marg{\ensuremath{c_1,\dots,c_n}},%
+      doc parameter = \marg{\( c_1,\dots,c_n \)},%
     },%
   }%
 \end{docCommands}
@@ -1148,7 +1203,7 @@
       doc name = newscalarquantity,%
     },%
     {%
-      doc new=2021-02-21,%
+      doc new = 2021-02-21,%
       doc name = renewscalarquantity,%
     },%
   }%
@@ -1175,7 +1230,7 @@
       doc name = newvectorquantity,%
     },%
     {%
-      doc new=2021-02-21,%
+      doc new = 2021-02-21,%
       doc name = renewvectorquantity,%
     },%
   }%
@@ -1349,10 +1404,10 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{docCommand}[doc updated = 2021-02-26]{checkconstant}{\marg{name}}
-  Command to check and typeset the constant's name, base units, derived 
-  units, alternate units, mathematical symbol, approximate value, and 
-  precise value.
+\begin{docCommand}[doc updated = 2022-01-27]{checkconstant}{\marg{name}}
+  Command to check and typeset the constant's name, mathematical symbol, 
+  approximate value, precise value, base units, derived units, and 
+  alternate units.
 \end{docCommand}
 %\iffalse
 %</example>
@@ -1360,14 +1415,14 @@
 %
 % \subsubsection{Predefined Physical Constants}
 %
-% Every other defined physical constant can be treated similarly. Just 
-% replace |oofpez| with the constant's name. Unfortunately, there is no 
-% universal agreement on the names of every constant so don't fret if 
-% the names used here vary from other sources. Here are all the physical 
-% constants, with all their units, defined in \mandi. 
-% The constants \refCom{coulombconstant} and \refCom{biotsavartconstant} are 
-% defined as semantic aliases for, respectively, \refCom{oofpez} and 
-% \refCom{mzofp}.
+% Every other defined physical constant can be treated similarly to
+% \refCom{oofpez}. Just replace |oofpez| with the constant's name. 
+% Unfortunately, there is no universal agreement on the names of every 
+% constant so don't fret if the names used here vary from other sources. 
+% Here are all the physical constants, with all their units, defined in 
+% \mandi. The constants \refCom{coulombconstant} and 
+% \refCom{biotsavartconstant} are defined as semantic aliases for, 
+% respectively, \refCom{oofpez} and \refCom{mzofp}.
 %
 %\iffalse
 %<*example>
@@ -1504,7 +1559,7 @@
       doc name = newphysicalconstant,%
     },%
     {%
-      doc new=2021-02-21,%
+      doc new = 2021-02-21,%
       doc name = renewphysicalconstant,%
     },%
   }%
@@ -1820,6 +1875,19 @@
 %\iffalse
 %<*example>
 %\fi
+\begin{docCommand}[doc new = 2022-01-27,]{hbar}{}%
+  A better glyph for Planck's constant over \( 2\pi \).
+\end{docCommand}
+\begin{dispExample}
+ \( \hbar \)
+\end{dispExample}
+%\iffalse
+%</example>
+%\fi
+%
+%\iffalse
+%<*example>
+%\fi
 \begin{docCommands}[%
     doc parameter = \marg{number},%
   ]%
@@ -1848,22 +1916,23 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{docCommand}{mivector}{%
-    \oarg{delimiter}\marg{\ensuremath{c_1,\dots,c_n}}\oarg{units}
+\begin{docCommand}[doc updated = 2022-01-27]{mivector}{%
+    \oarg{delimiter}\marg{\( c_1,\dots,c_n \)}\oarg{units}
   }%
   Typesets a vector as either numeric or symbolic components with an 
-  optional unit (for numerical components only). There can be more 
-  than three components. The delimiter used in the list of components 
-  can be specified; the default is a comma. The notation mirrors that of 
+  optional unit (for numerical components only). There must be more
+  than one component, and there can be more than three components. 
+  The delimiter used in the list of components can be specified; 
+  the default is a comma. The notation mirrors that of 
   \emph{Matter \& Interactions}.
 \end{docCommand}
-\begin{dispExample*}{lefthand ratio=0.65}
-  \( \mivector{p_0,p_1,p_2,p_3} \)                        \\
-  \( \mivector{\gamma m v_x,\gamma m v_y,\gamma m v_z} \) \\
-  \( \mivector{\frac{Q_1Q_2}{x^2},0,0} \)                 \\
-  \( \mivector{-1,0,0} \)                                 \\
-  \( \mivector{-1,0,0}[\velocityonlyderivedunits] \)      \\
-  \( \mivector{-1,0,0}[\meter\per\second] \)              \\
+\begin{dispExample*}{lefthand ratio = 0.70}
+  \( \mivector{p_0,p_1,p_2,p_3} \)                               \\
+  \( \mivector{\gamma mc,\gamma mv_x,\gamma mv_y,\gamma mv_z} \) \\
+  \( \mivector{\frac{Q_1Q_2}{x^2},0,0} \)                        \\
+  \( \mivector{-1,0,0} \)                                        \\
+  \( \mivector{-1,0,0}[\velocityonlyderivedunits] \)             \\
+  \( \mivector{-1,0,0}[\meter\per\second] \)                     \\
   \( \velocity{\mivector{-1,0,0}} \)
 \end{dispExample*}
 %\iffalse
@@ -1883,11 +1952,13 @@
 % |\makeatother|. This simplifies defining internal commands (with |@| 
 % in the name) that are not for the user to know about.
 %
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandipkg}{mandi} Code formatted for better readability}
 %    \begin{macrocode}
-\def\mandi at version{3.0.0}
-\def\mandi at date{2021-08-22}
+\def\mandi at version{3.1.0}
+\def\mandi at date{2022-01-27}
 \NeedsTeXFormat{LaTeX2e}[2020-02-02]
-\DeclareRelease{v3.0.0}{2021-08-22}{mandi.sty}
+\DeclareRelease{v3.1.0}{2022-01-27}{mandi.sty}
 \DeclareCurrentRelease{v\mandi at version}{\mandi at date}
 \ProvidesPackage{mandi}
   [\mandi at date\space v\mandi at version\space Macros for physical quantities]
@@ -1902,16 +1973,24 @@
 % Load third party packages, documenting why each one is needed.
 %
 %    \begin{macrocode}
-\RequirePackage{pgfopts}      % needed for key-value interface
-\RequirePackage{array}        % needed for \checkquantity and \checkconstant
-\RequirePackage{iftex}        % needed for requiring LuaLaTeX
-\RequirePackage{unicode-math} % needed for Unicode support
-\RequireLuaTeX                % require this engine
+\RequirePackage{pgfopts}        % needed for key-value interface
+\RequirePackage{array}          % needed for \checkquantity and \checkconstant
+\RequirePackage{iftex}          % needed for requiring LuaLaTeX
+\RequirePackage{unicode-math}   % needed for Unicode support
 %    \end{macrocode}
 %
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandipkg}{mandi} \pkg{xparse} is loaded for older formats}
+%    \begin{macrocode}
+\IfFormatAtLeastTF {2020-10-01} % load xparse if necessary
+  {}%
+  {\RequirePackage{xparse}}%
+\RequireLuaTeX                  % require this engine
+%    \end{macrocode}
+%
 % Parts of the unit engine have been rewritten with 
 % \href{https://www.ctan.org/pkg/xparse}{\pkg{xparse}} for both clarity 
-% and power. Note that \pkg{xparse} is now part of the \LaTeX\ kernel. 
+% and power. Note that \pkg{xparse} is now part of the \LaTeXe\ kernel. 
 % Other parts have been rewriten in 
 % \href{https://www.ctan.org/pkg/expl}{\pkg{expl}} with a look to the 
 % future.
@@ -1981,6 +2060,8 @@
 % First, define the keys. The key handlers require certain commands defined 
 % by the unit engine.
 %
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandipkg}{mandi} Unknown package options handled safely}
 %    \begin{macrocode}
 \newif\ifusingpreciseconstants
 \pgfkeys{%
@@ -1995,6 +2076,10 @@
   units/alternate/.style={/mandi/options/buffered at units=alternate},%
   units/base/.style={/mandi/options/buffered at units=base},%
   units/derived/.style={/mandi/options/buffered at units=derived},%
+  .unknown/.code={%
+    \typeout{}%
+    \typeout{mandi: You used unknown option '\pgfkeyscurrentname'.}%
+  },%
 }%
 %    \end{macrocode}
 %
@@ -2037,14 +2122,16 @@
 % when called with new options. A new banner is written to the console.
 %
 %    \begin{macrocode}
-\NewDocumentCommand{\mandisetup}{ m }{%
-  \IfValueT{#1}{%
-    \pgfqkeys{/mandi/options}{#1}
-    \typeout{}%
-    \typeout{mandi: mandisetup options...}
-    \mandi at do@setup
+\NewDocumentCommand{\mandisetup}{ m }%
+  {%
+    \IfValueT{#1}%
+      {%
+        \pgfqkeys{/mandi/options}{#1}
+        \typeout{}%
+        \typeout{mandi: mandisetup options...}
+        \mandi at do@setup
+      }%
   }%
-}%
 %    \end{macrocode}
 %
 % Define units and related constructs to be used with the unit engine. 
@@ -2053,6 +2140,8 @@
 % \href{https://ctan.org/pkg/siunits}{\pkg{SIunits}} package. 
 % We make use of |\symup{...}| from the \pkg{unicode-math} package.
 %
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandipkg}{mandi} Added a negative space to \refCom{lightspeed}}
 %    \begin{macrocode}
 \NewDocumentCommand{\per}{}{/}
 \NewDocumentCommand{\usk}{}{\cdot}
@@ -2072,7 +2161,7 @@
 \NewDocumentCommand{\kev}{}{\kiloelectronvolt}
 \NewDocumentCommand{\kiloelectronvolt}{}{\symup{keV}}
 \NewDocumentCommand{\kilogram}{}{\symup{kg}}
-\NewDocumentCommand{\lightspeed}{}{\symup{c}}
+\NewDocumentCommand{\lightspeed}{}{\!\symup{c}}
 \NewDocumentCommand{\megaelectronvolt}{}{\symup{MeV}}
 \NewDocumentCommand{\meter}{}{\symup{m}}
 \NewDocumentCommand{\metre}{}{\meter}
@@ -2102,23 +2191,25 @@
 \NewDocumentCommand{\xtento}{ m }{\times\tento{#1}}
 %    \end{macrocode}
 %
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandipkg}{mandi} \LaTeX3 code now conforms to formatting standards}
 %    \begin{macrocode}
 \ExplSyntaxOn
-\cs_new:Npn \mandi_newscalarquantity #1#2#3#4
-{%
-  \cs_new:cpn {#1} ##1 {\unit{##1}{\mandi at selectunits{#2}{#3}{#4}}}% 
-  \cs_new:cpn {#1value} ##1 {##1}%
-  \cs_new:cpn {#1baseunits} ##1 {\unit{##1}{\mandi at selectbaseunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {#1derivedunits} ##1 {\unit{##1}{\mandi at selectderivedunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {#1alternateunits} ##1 {\unit{##1}{\mandi at selectalternateunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {#1onlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}%
-  \cs_new:cpn {#1onlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}%
-  \cs_new:cpn {#1onlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}%
-}%
-\NewDocumentCommand{\newscalarquantity}{ m m O{#2} O{#2} }%
-{%
-  \mandi_newscalarquantity { #1 }{ #2 }{ #3 }{ #4 }%
-}%
+\cs_new:Npn \__mandi_newscalarquantity:nnnn #1#2#3#4
+  {
+    \cs_new:cpn {#1} ##1 {\unit{##1}{\mandi at selectunits{#2}{#3}{#4}}}
+    \cs_new:cpn {#1value} ##1 {##1}
+    \cs_new:cpn {#1baseunits} ##1 {\unit{##1}{\mandi at selectbaseunits{#2}{#3}{#4}}}
+    \cs_new:cpn {#1derivedunits} ##1 {\unit{##1}{\mandi at selectderivedunits{#2}{#3}{#4}}}
+    \cs_new:cpn {#1alternateunits} ##1 {\unit{##1}{\mandi at selectalternateunits{#2}{#3}{#4}}}
+    \cs_new:cpn {#1onlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}
+    \cs_new:cpn {#1onlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}
+    \cs_new:cpn {#1onlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}
+  }
+\NewDocumentCommand{\newscalarquantity}{ m m O{#2} O{#2} }
+  {
+    \__mandi_newscalarquantity:nnnn { #1 }{ #2 }{ #3 }{ #4 }
+  }
 \ExplSyntaxOff
 %    \end{macrocode}
 %
@@ -2126,21 +2217,21 @@
 %
 %    \begin{macrocode}
 \ExplSyntaxOn
-\cs_new:Npn \mandi_renewscalarquantity #1#2#3#4
-{%
-  \cs_set:cpn {#1} ##1 {\unit{##1}{\mandi at selectunits{#2}{#3}{#4}}}% 
-  \cs_set:cpn {#1value} ##1 {##1}%
-  \cs_set:cpn {#1baseunits} ##1 {\unit{##1}{\mandi at selectbaseunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {#1derivedunits} ##1 {\unit{##1}{\mandi at selectderivedunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {#1alternateunits} ##1 {\unit{##1}{\mandi at selectalternateunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {#1onlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}%
-  \cs_set:cpn {#1onlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}%
-  \cs_set:cpn {#1onlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}%
-}%
-\NewDocumentCommand{\renewscalarquantity}{ m m O{#2} O{#2} }%
-{%
-  \mandi_renewscalarquantity { #1 }{ #2 }{ #3 }{ #4 }%
-}%
+\cs_new:Npn \__mandi_renewscalarquantity:nnnn #1#2#3#4
+  {
+    \cs_set:cpn {#1} ##1 {\unit{##1}{\mandi at selectunits{#2}{#3}{#4}}}
+    \cs_set:cpn {#1value} ##1 {##1}
+    \cs_set:cpn {#1baseunits} ##1 {\unit{##1}{\mandi at selectbaseunits{#2}{#3}{#4}}}
+    \cs_set:cpn {#1derivedunits} ##1 {\unit{##1}{\mandi at selectderivedunits{#2}{#3}{#4}}}
+    \cs_set:cpn {#1alternateunits} ##1 {\unit{##1}{\mandi at selectalternateunits{#2}{#3}{#4}}}
+    \cs_set:cpn {#1onlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}
+    \cs_set:cpn {#1onlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}
+    \cs_set:cpn {#1onlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}
+  }
+\NewDocumentCommand{\renewscalarquantity}{ m m O{#2} O{#2} }
+  {
+    \__mandi_renewscalarquantity:nnnn { #1 }{ #2 }{ #3 }{ #4 }
+  }
 \ExplSyntaxOff
 %    \end{macrocode}
 %
@@ -2148,30 +2239,30 @@
 %
 %    \begin{macrocode}
 \ExplSyntaxOn
-\cs_new:Npn \mandi_newvectorquantity #1#2#3#4
-{%
-  \mandi_newscalarquantity { #1 }{ #2 }{ #3 }{ #4 }%
-  \cs_new:cpn {vector#1} ##1 {\unit{\mivector{##1}}{\mandi at selectunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {#1vector} ##1 {\unit{\mivector{##1}}{\mandi at selectunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {vector#1value} ##1 {\mivector{##1}}%
-  \cs_new:cpn {#1vectorvalue} ##1 {\mivector{##1}}%
-  \cs_new:cpn {vector#1baseunits} ##1 {\unit{\mivector{##1}}{\mandi at selectbaseunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {#1vectorbaseunits} ##1 {\unit{\mivector{##1}}{\mandi at selectbaseunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {vector#1derivedunits} ##1 {\unit{\mivector{##1}}{\mandi at selectderivedunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {#1vectorderivedunits} ##1 {\unit{\mivector{##1}}{\mandi at selectderivedunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {vector#1alternateunits} ##1 {\unit{\mivector{##1}}{\mandi at selectalternateunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {#1vectoralternateunits} ##1 {\unit{\mivector{##1}}{\mandi at selectalternateunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {vector#1onlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}%
-  \cs_new:cpn {#1vectoronlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}%
-  \cs_new:cpn {vector#1onlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}%
-  \cs_new:cpn {#1vectoronlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}%
-  \cs_new:cpn {vector#1onlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}%
-  \cs_new:cpn {#1vectoronlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}%
-}%
-\NewDocumentCommand{\newvectorquantity}{ m m O{#2} O{#2} }%
-{%
-  \mandi_newvectorquantity { #1 }{ #2 }{ #3 }{ #4 }%
-}%
+\cs_new:Npn \__mandi_newvectorquantity:nnnn #1#2#3#4
+  {
+    \__mandi_newscalarquantity:nnnn { #1 }{ #2 }{ #3 }{ #4 }
+    \cs_new:cpn {vector#1} ##1 {\unit{\mivector{##1}}{\mandi at selectunits{#2}{#3}{#4}}}
+    \cs_new:cpn {#1vector} ##1 {\unit{\mivector{##1}}{\mandi at selectunits{#2}{#3}{#4}}}
+    \cs_new:cpn {vector#1value} ##1 {\mivector{##1}}
+    \cs_new:cpn {#1vectorvalue} ##1 {\mivector{##1}}
+    \cs_new:cpn {vector#1baseunits} ##1 {\unit{\mivector{##1}}{\mandi at selectbaseunits{#2}{#3}{#4}}}
+    \cs_new:cpn {#1vectorbaseunits} ##1 {\unit{\mivector{##1}}{\mandi at selectbaseunits{#2}{#3}{#4}}}
+    \cs_new:cpn {vector#1derivedunits} ##1 {\unit{\mivector{##1}}{\mandi at selectderivedunits{#2}{#3}{#4}}}
+    \cs_new:cpn {#1vectorderivedunits} ##1 {\unit{\mivector{##1}}{\mandi at selectderivedunits{#2}{#3}{#4}}}
+    \cs_new:cpn {vector#1alternateunits} ##1 {\unit{\mivector{##1}}{\mandi at selectalternateunits{#2}{#3}{#4}}}
+    \cs_new:cpn {#1vectoralternateunits} ##1 {\unit{\mivector{##1}}{\mandi at selectalternateunits{#2}{#3}{#4}}}
+    \cs_new:cpn {vector#1onlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}
+    \cs_new:cpn {#1vectoronlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}
+    \cs_new:cpn {vector#1onlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}
+    \cs_new:cpn {#1vectoronlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}
+    \cs_new:cpn {vector#1onlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}
+    \cs_new:cpn {#1vectoronlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}
+  }
+\NewDocumentCommand{\newvectorquantity}{ m m O{#2} O{#2} }
+  {
+    \__mandi_newvectorquantity:nnnn { #1 }{ #2 }{ #3 }{ #4 }
+  }
 \ExplSyntaxOff
 %    \end{macrocode}
 %
@@ -2179,30 +2270,30 @@
 %
 %    \begin{macrocode}
 \ExplSyntaxOn
-\cs_new:Npn \mandi_renewvectorquantity #1#2#3#4
-{%
-  \mandi_renewscalarquantity { #1 }{ #2 }{ #3 }{ #4 }%
-  \cs_set:cpn {vector#1} ##1 {\unit{\mivector{##1}}{\mandi at selectunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {#1vector} ##1 {\unit{\mivector{##1}}{\mandi at selectunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {vector#1value} ##1 {\mivector{##1}}%
-  \cs_set:cpn {#1vectorvalue} ##1 {\mivector{##1}}%
-  \cs_set:cpn {vector#1baseunits} ##1 {\unit{\mivector{##1}}{\mandi at selectbaseunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {#1vectorbaseunits} ##1 {\unit{\mivector{##1}}{\mandi at selectbaseunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {vector#1derivedunits} ##1 {\unit{\mivector{##1}}{\mandi at selectderivedunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {#1vectorderivedunits} ##1 {\unit{\mivector{##1}}{\mandi at selectderivedunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {vector#1alternateunits} ##1 {\unit{\mivector{##1}}{\mandi at selectalternateunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {#1vectoralternateunits} ##1 {\unit{\mivector{##1}}{\mandi at selectalternateunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {vector#1onlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}%
-  \cs_set:cpn {#1vectoronlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}%
-  \cs_set:cpn {vector#1onlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}%
-  \cs_set:cpn {#1vectoronlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}%
-  \cs_set:cpn {vector#1onlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}%
-  \cs_set:cpn {#1vectoronlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}%
-}%
-\NewDocumentCommand{\renewvectorquantity}{ m m O{#2} O{#2} }%
-{%
-  \mandi_renewvectorquantity { #1 }{ #2 }{ #3 }{ #4 }%
-}%
+\cs_new:Npn \__mandi_renewvectorquantity:nnnn #1#2#3#4
+  {
+    \__mandi_renewscalarquantity:nnnn { #1 }{ #2 }{ #3 }{ #4 }
+    \cs_set:cpn {vector#1} ##1 {\unit{\mivector{##1}}{\mandi at selectunits{#2}{#3}{#4}}}
+    \cs_set:cpn {#1vector} ##1 {\unit{\mivector{##1}}{\mandi at selectunits{#2}{#3}{#4}}}
+    \cs_set:cpn {vector#1value} ##1 {\mivector{##1}}
+    \cs_set:cpn {#1vectorvalue} ##1 {\mivector{##1}}
+    \cs_set:cpn {vector#1baseunits} ##1 {\unit{\mivector{##1}}{\mandi at selectbaseunits{#2}{#3}{#4}}}
+    \cs_set:cpn {#1vectorbaseunits} ##1 {\unit{\mivector{##1}}{\mandi at selectbaseunits{#2}{#3}{#4}}}
+    \cs_set:cpn {vector#1derivedunits} ##1 {\unit{\mivector{##1}}{\mandi at selectderivedunits{#2}{#3}{#4}}}
+    \cs_set:cpn {#1vectorderivedunits} ##1 {\unit{\mivector{##1}}{\mandi at selectderivedunits{#2}{#3}{#4}}}
+    \cs_set:cpn {vector#1alternateunits} ##1 {\unit{\mivector{##1}}{\mandi at selectalternateunits{#2}{#3}{#4}}}
+    \cs_set:cpn {#1vectoralternateunits} ##1 {\unit{\mivector{##1}}{\mandi at selectalternateunits{#2}{#3}{#4}}}
+    \cs_set:cpn {vector#1onlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}
+    \cs_set:cpn {#1vectoronlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}
+    \cs_set:cpn {vector#1onlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}
+    \cs_set:cpn {#1vectoronlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}
+    \cs_set:cpn {vector#1onlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}
+    \cs_set:cpn {#1vectoronlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}
+  }
+\NewDocumentCommand{\renewvectorquantity}{ m m O{#2} O{#2} }
+  {
+    \__mandi_renewvectorquantity:nnnn { #1 }{ #2 }{ #3 }{ #4 }
+  }
 \ExplSyntaxOff
 %    \end{macrocode}
 %
@@ -2210,26 +2301,26 @@
 %
 %    \begin{macrocode}
 \ExplSyntaxOn
-\cs_new:Npn \mandi_newphysicalconstant #1#2#3#4#5#6#7
-{%
-  \cs_new:cpn {#1} {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectunits{#5}{#6}{#7}}}%
-  \cs_new:cpn {#1mathsymbol} {#2}%
-  \cs_new:cpn {#1approximatevalue} {#3}%
-  \cs_new:cpn {#1precisevalue} {#4}%
-  \cs_new:cpn {#1baseunits} 
-    {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectbaseunits{#5}{#6}{#7}}}%
-  \cs_new:cpn {#1derivedunits} 
-    {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectderivedunits{#5}{#6}{#7}}}%
-  \cs_new:cpn {#1alternateunits} 
-    {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectalternateunits{#5}{#6}{#7}}}%
-  \cs_new:cpn {#1onlybaseunits} {\mandi at selectbaseunits{#5}{#6}{#7}}%
-  \cs_new:cpn {#1onlyderivedunits} {\mandi at selectderivedunits{#5}{#6}{#7}}%
-  \cs_new:cpn {#1onlyalternateunits} {\mandi at selectalternateunits{#5}{#6}{#7}}%
-}%
-\NewDocumentCommand{\newphysicalconstant}{ m m m m m O{#5} O{#5} }%
-{%
-  \mandi_newphysicalconstant { #1 }{ #2 }{ #3 }{ #4 }{ #5 }{ #6 }{ #7 }%
-}%
+\cs_new:Npn \__mandi_newphysicalconstant:nnnnnnn #1#2#3#4#5#6#7
+  {
+    \cs_new:cpn {#1} {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectunits{#5}{#6}{#7}}}
+    \cs_new:cpn {#1mathsymbol} {#2}
+    \cs_new:cpn {#1approximatevalue} {#3}
+    \cs_new:cpn {#1precisevalue} {#4}
+    \cs_new:cpn {#1baseunits} 
+      {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectbaseunits{#5}{#6}{#7}}}
+    \cs_new:cpn {#1derivedunits} 
+      {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectderivedunits{#5}{#6}{#7}}}
+    \cs_new:cpn {#1alternateunits} 
+      {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectalternateunits{#5}{#6}{#7}}}
+    \cs_new:cpn {#1onlybaseunits} {\mandi at selectbaseunits{#5}{#6}{#7}}
+    \cs_new:cpn {#1onlyderivedunits} {\mandi at selectderivedunits{#5}{#6}{#7}}
+    \cs_new:cpn {#1onlyalternateunits} {\mandi at selectalternateunits{#5}{#6}{#7}}
+  }
+\NewDocumentCommand{\newphysicalconstant}{ m m m m m O{#5} O{#5} }
+  {
+    \__mandi_newphysicalconstant:nnnnnnn { #1 }{ #2 }{ #3 }{ #4 }{ #5 }{ #6 }{ #7 }
+  }
 \ExplSyntaxOff
 %    \end{macrocode}
 %
@@ -2237,26 +2328,26 @@
 %
 %    \begin{macrocode}
 \ExplSyntaxOn
-\cs_new:Npn \mandi_renewphysicalconstant #1#2#3#4#5#6#7
-{%
-  \cs_set:cpn {#1} {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectunits{#5}{#6}{#7}}}%
-  \cs_set:cpn {#1mathsymbol} {#2}%
-  \cs_set:cpn {#1approximatevalue} {#3}%
-  \cs_set:cpn {#1precisevalue} {#4}%
-  \cs_set:cpn {#1baseunits} 
-    {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectbaseunits{#5}{#6}{#7}}}%
-  \cs_set:cpn {#1derivedunits} 
-    {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectderivedunits{#5}{#6}{#7}}}%
-  \cs_set:cpn {#1alternateunits} 
-    {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectalternateunits{#5}{#6}{#7}}}%
-  \cs_set:cpn {#1onlybaseunits} {\mandi at selectbaseunits{#5}{#6}{#7}}%
-  \cs_set:cpn {#1onlyderivedunits} {\mandi at selectderivedunits{#5}{#6}{#7}}%
-  \cs_set:cpn {#1onlyalternateunits} {\mandi at selectalternateunits{#5}{#6}{#7}}%
-}%
-\NewDocumentCommand{\renewphysicalconstant}{ m m m m m O{#5} O{#5} }%
-{%
-  \mandi_renewphysicalconstant { #1 }{ #2 }{ #3 }{ #4 }{ #5 }{ #6 }{ #7 }%
-}%
+\cs_new:Npn \__mandi_renewphysicalconstant:nnnnnnn #1#2#3#4#5#6#7
+  {
+    \cs_set:cpn {#1} {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectunits{#5}{#6}{#7}}}
+    \cs_set:cpn {#1mathsymbol} {#2}
+    \cs_set:cpn {#1approximatevalue} {#3}
+    \cs_set:cpn {#1precisevalue} {#4}
+    \cs_set:cpn {#1baseunits} 
+      {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectbaseunits{#5}{#6}{#7}}}
+    \cs_set:cpn {#1derivedunits} 
+      {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectderivedunits{#5}{#6}{#7}}}
+    \cs_set:cpn {#1alternateunits} 
+      {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectalternateunits{#5}{#6}{#7}}}
+    \cs_set:cpn {#1onlybaseunits} {\mandi at selectbaseunits{#5}{#6}{#7}}
+    \cs_set:cpn {#1onlyderivedunits} {\mandi at selectderivedunits{#5}{#6}{#7}}
+    \cs_set:cpn {#1onlyalternateunits} {\mandi at selectalternateunits{#5}{#6}{#7}}
+  }
+\NewDocumentCommand{\renewphysicalconstant}{ m m m m m O{#5} O{#5} }
+  {
+    \__mandi_renewphysicalconstant:nnnnnnn { #1 }{ #2 }{ #3 }{ #4 }{ #5 }{ #6 }{ #7 }
+  }
 \ExplSyntaxOff
 %    \end{macrocode}
 %
@@ -2290,14 +2381,14 @@
 %    [\kilogram\usk\meter\tothetwo\per(\second\usk\radian)]%
 %    [\newton\usk\meter\usk\second\per\radian]%
 %\else
-  \newvectorquantity{angularimpulse}%
-    {\kilogram\usk\meter\tothetwo\usk\second\inverse}%
-    [\kilogram\usk\meter\tothetwo\per\second]% % also \joule\usk\second
-    [\kilogram\usk\meter\tothetwo\per\second]% % also \newton\usk\meter\usk\second
-  \newvectorquantity{angularmomentum}%
-    {\kilogram\usk\meter\tothetwo\usk\second\inverse}%
-    [\kilogram\usk\meter\tothetwo\per\second]% % also \joule\usk\second
-    [\kilogram\usk\meter\tothetwo\per\second]% % also \newton\usk\meter\usk\second
+\newvectorquantity{angularimpulse}%
+  {\kilogram\usk\meter\tothetwo\usk\second\inverse}%
+  [\kilogram\usk\meter\tothetwo\per\second]% % also \joule\usk\second
+  [\kilogram\usk\meter\tothetwo\per\second]% % also \newton\usk\meter\usk\second
+\newvectorquantity{angularmomentum}%
+  {\kilogram\usk\meter\tothetwo\usk\second\inverse}%
+  [\kilogram\usk\meter\tothetwo\per\second]% % also \joule\usk\second
+  [\kilogram\usk\meter\tothetwo\per\second]% % also \newton\usk\meter\usk\second
 %\fi
 \newvectorquantity{angularvelocity}%
   {\radian\usk\second\inverse}%
@@ -2439,6 +2530,13 @@
   {\kilogram\usk\meter\inverse}%
   [\kilogram\per\meter]%
   [\kilogram\per\meter]%
+%    \end{macrocode}
+%
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandipkg}{mandi} Added \refCom{lorentzfactor}}
+%    \begin{macrocode}
+\newscalarquantity{lorentzfactor}%
+  {}%
 \newscalarquantity{luminousintensity}%
   {\candela}%
 \newscalarquantity{magneticcharge}%
@@ -2584,53 +2682,70 @@
   [\newton\per\meter\tothetwo]%
 %    \end{macrocode}
 %
+% We need a better glyph for Planck's constant over \( 2\pi \).
+%
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandipkg}{mandi} Added \refCom{hbar}}
+%    \begin{macrocode}
+\AtBeginDocument{%
+  \DeclareRobustCommand{\hbar}{{\mathpalette\hbar@\relax\symup{h}}}%
+}%
+\newcommand*{\hbar@}[2]{%
+  \makebox[0pt][l]{\raisebox{-0.07\height}{\(\m at th#1\mkern-2mu\mathchar"AF\)}}%
+  % optional line to make the bar thicker; must use -0.11
+  \makebox[0pt][l]{\raisebox{-0.11\height}{\(\m at th#1\mkern-2mu\mathchar"AF\)}}%
+}%
+%    \end{macrocode}
+%
 % Define physical constants for introductory physics, again alphabetically
 % for convenience.
 %
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandipkg}{mandi} Constants' values now use only \cs{times}}
 %    \begin{macrocode}
 \newphysicalconstant{avogadro}%
   {\symup{N_A}}%
-  {6\timestento{23}}{6.02214076\timestento{23}}% % exact 2019 value
+  {6\times10^{23}}{6.02214076\times10^{23}}% % exact 2019 value
   {\mole\inverse}%
   [\per\mole]%
   [\per\mole]%
 \newphysicalconstant{biotsavartconstant}% % alias for \mzofp
   {\symup{\frac{\mu_o}{4\pi}}}%
-  {\tento{-7}}{\tento{-7}}%
+  {10^{-7}}{10^{-7}}%
   {\kilogram\usk\meter\usk\ampere\totheinversetwo\usk\second\totheinversetwo}%
   [\henry\per\meter]%
   [\tesla\usk\meter\per\ampere]%
 \newphysicalconstant{bohrradius}%
   {\symup{a_o}}%
-  {5.3\timestento{-11}}{5.29177210903\timestento{-11}}%
+  {5.3\times10^{-11}}{5.29177210903\times10^{-11}}%
   {\meter}%
 \newphysicalconstant{boltzmann}%
   {\symup{k_B}}%
-  {1.4\timestento{-23}}{1.380649\timestento{-23}}% % exact 2019 value
+  {1.4\times10^{-23}}{1.380649\times10^{-23}}% % exact 2019 value
   {\kilogram\usk\meter\tothetwo\usk\second\totheinversetwo\usk\kelvin\inverse}%
   [\joule\per\kelvin]%
   [\joule\per\kelvin]%
 \newphysicalconstant{coulombconstant}% % alias for \oofpez
   {\symup{\frac{1}{4\pi\epsilon_o}}}%
-  {9\timestento{9}}{8.9875517923\timestento{9}}%
+  {9\times10^{9}}{8.9875517923\times10^{9}}%
   {\kilogram\usk\meter\tothethree\usk\ampere\totheinversetwo\usk\second\totheinversefour}%
   [\meter\per\farad]%
   [\newton\usk\meter\tothetwo\per\coulomb\tothetwo]%
 \newphysicalconstant{earthmass}%
   {\symup{M_{Earth}}}%
-  {6.0\timestento{24}}{5.9722\timestento{24}}%
+  {6.0\times10^{24}}{5.9722\times10^{24}}%
   {\kilogram}%
 \newphysicalconstant{earthmoondistance}%
   {\symup{d_{EM}}}%
-  {3.8\timestento{8}}{3.81550\timestento{8}}%
+  {3.8\times10^{8}}{3.81550\times10^{8}}%
   {\meter}%
 \newphysicalconstant{earthradius}%
   {\symup{R_{Earth}}}%
-  {6.4\timestento{6}}{6.3781\timestento{6}}%
+  {6.4\times10^{6}}{6.3781\times10^{6}}%
   {\meter}%
 \newphysicalconstant{earthsundistance}%
   {\symup{d_{ES}}}%
-  {1.5\timestento{11}}{1.496\timestento{11}}%
+  {1.5\times10^{11}}{1.496\times10^{11}}%
   {\meter}%
 \newphysicalconstant{electroncharge}%
   {\symup{q_e}}%
@@ -2646,59 +2761,59 @@
   [\coulomb]%
 \newphysicalconstant{electronmass}%
   {\symup{m_e}}%
-  {9.1\timestento{-31}}{9.1093837015\timestento{-31}}%
+  {9.1\times10^{-31}}{9.1093837015\times10^{-31}}%
   {\kilogram}%
 \newphysicalconstant{elementarycharge}%
   {\symup{e}}%
-  {1.6\timestento{-19}}{1.602176634\timestento{-19}}% % exact 2019 value
+  {1.6\times10^{-19}}{1.602176634\times10^{-19}}% % exact 2019 value
   {\ampere\usk\second}%
   [\coulomb]%
   [\coulomb]%
 \newphysicalconstant{finestructure}%
   {\symup{\alpha}}%
-  {\frac{1}{137}}{7.2973525693\timestento{-3}}%
+  {\frac{1}{137}}{7.2973525693\times10^{-3}}%
   {}%
 \newphysicalconstant{hydrogenmass}%
   {\symup{m_H}}%
-  {1.7\timestento{-27}}{1.6737236\timestento{-27}}%
+  {1.7\times10^{-27}}{1.6737236\times10^{-27}}%
   {\kilogram}%
 \newphysicalconstant{moonearthdistance}%
   {\symup{d_{ME}}}%
-  {3.8\timestento{8}}{3.81550\timestento{8}}%
+  {3.8\times10^{8}}{3.81550\times10^{8}}%
   {\meter}%
 \newphysicalconstant{moonmass}%
   {\symup{M_{Moon}}}%
-  {7.3\timestento{22}}{7.342\timestento{22}}%
+  {7.3\times10^{22}}{7.342\times10^{22}}%
   {\kilogram}%
 \newphysicalconstant{moonradius}%
   {\symup{R_{Moon}}}%
-  {1.7\timestento{6}}{1.7371\timestento{6}}%
+  {1.7\times10^{6}}{1.7371\times10^{6}}%
   {\meter}%
 \newphysicalconstant{mzofp}%
   {\symup{\frac{\mu_o}{4\pi}}}%
-  {\tento{-7}}{\tento{-7}}%
+  {10^{-7}}{10^{-7}}%
   {\kilogram\usk\meter\usk\ampere\totheinversetwo\usk\second\totheinversetwo}%
   [\henry\per\meter]%
   [\tesla\usk\meter\per\ampere]%
 \newphysicalconstant{neutronmass}%
   {\symup{m_n}}%
-  {1.7\timestento{-27}}{1.67492749804\timestento{-27}}%
+  {1.7\times10^{-27}}{1.67492749804\times10^{-27}}%
   {\kilogram}%
 \newphysicalconstant{oofpez}%
   {\symup{\frac{1}{4\pi\epsilon_o}}}%
-  {9\timestento{9}}{8.9875517923\timestento{9}}%
+  {9\times10^{9}}{8.9875517923\times10^{9}}%
   {\kilogram\usk\meter\tothethree\usk\ampere\totheinversetwo\usk\second\totheinversefour}%
   [\meter\per\farad]%
   [\newton\usk\meter\tothetwo\per\coulomb\tothetwo]%
 \newphysicalconstant{oofpezcs}%
   {\symup{\frac{1}{4\pi\epsilon_o c^2}}}%
-  {\tento{-7}}{\tento{-7}}%
+  {10^{-7}}{10^{-7}}%
   {\kilogram\usk\meter\usk\ampere\totheinversetwo\usk\second\totheinversetwo}%
   [\tesla\usk\meter\tothetwo]%
   [\newton\usk\second\tothetwo\per\coulomb\tothetwo]%
 \newphysicalconstant{planck}%
   {\symup{h}}%
-  {6.6\timestento{-34}}{6.62607015\timestento{-34}}% % exact 2019 value
+  {6.6\times10^{-34}}{6.62607015\times10^{-34}}% % exact 2019 value
   {\kilogram\usk\meter\tothetwo\usk\second\inverse}%
   [\joule\usk\second]%
   [\joule\usk\second]%
@@ -2705,18 +2820,17 @@
 %    \end{macrocode}
 %
 % See \url{https://tex.stackexchange.com/a/448565/218142}.
-% 
 %
 %    \begin{macrocode}
 \newphysicalconstant{planckbar}%
-  {\symup{\lower0.18ex\hbox{\mathchar"AF}\mkern-7mu h}}%
-  {1.1\timestento{-34}}{1.054571817\timestento{-34}}%
+  {\hbar}%
+  {1.1\times10^{-34}}{1.054571817\times10^{-34}}%
   {\kilogram\usk\meter\tothetwo\usk\second\inverse}%
   [\joule\usk\second]%
   [\joule\usk\second]
 \newphysicalconstant{planckc}%
   {\symup{hc}}%
-  {2.0\timestento{-25}}{1.98644586\timestento{-25}}%
+  {2.0\times10^{-25}}{1.98644586\times10^{-25}}%
   {\kilogram\usk\meter\tothethree\usk\second\totheinversetwo}%
   [\joule\usk\meter]%
   [\joule\usk\meter]%
@@ -2734,35 +2848,35 @@
   [\coulomb]%
 \newphysicalconstant{protonmass}%
   {\symup{m_p}}%
-  {1.7\timestento{-27}}{1.672621898\timestento{-27}}%
+  {1.7\times10^{-27}}{1.672621898\times10^{-27}}%
   {\kilogram}%
 \newphysicalconstant{rydberg}%
   {\symup{R_{\infty}}}%
-  {1.1\timestento{7}}{1.0973731568160\timestento{7}}%
+  {1.1\times10^{7}}{1.0973731568160\times10^{7}}%
   {\meter\inverse}%
 \newphysicalconstant{speedoflight}%
   {\symup{c}}%
-  {3\timestento{8}}{2.99792458\timestento{8}}% % exact value
+  {3\times10^{8}}{2.99792458\times10^{8}}% % exact value
   {\meter\usk\second\inverse}%
   [\meter\per\second]%
   [\meter\per\second]
 \newphysicalconstant{stefanboltzmann}%
   {\symup{\sigma}}%
-  {5.7\timestento{-8}}{5.670374\timestento{-8}}%
+  {5.7\times10^{-8}}{5.670374\times10^{-8}}%
   {\kilogram\usk\second\totheinversethree\usk\kelvin\totheinversefour}%
   [\watt\per\meter\tothetwo\usk\kelvin\tothefour]%
   [\watt\per\meter\tothetwo\usk\kelvin\tothefour]
 \newphysicalconstant{sunearthdistance}%
   {\symup{d_{SE}}}%
-  {1.5\timestento{11}}{1.496\timestento{11}}%
+  {1.5\times10^{11}}{1.496\times10^{11}}%
   {\meter}%
 \newphysicalconstant{sunmass}%
   {\symup{M_{Sun}}}%
-  {2.0\timestento{30}}{1.98855\timestento{30}}%
+  {2.0\times10^{30}}{1.98855\times10^{30}}%
   {\kilogram}%
 \newphysicalconstant{sunradius}%
   {\symup{R_{Sun}}}%
-  {7.0\timestento{8}}{6.957\timestento{8}}%
+  {7.0\times10^{8}}{6.957\times10^{8}}%
   {\meter}%
 \newphysicalconstant{surfacegravfield}%
   {\symup{g}}%
@@ -2772,19 +2886,19 @@
   [\newton\per\kilogram]%
 \newphysicalconstant{universalgrav}%
   {\symup{G}}%
-  {6.7\timestento{-11}}{6.67430\timestento{-11}}%
+  {6.7\times10^{-11}}{6.67430\times10^{-11}}%
   {\meter\tothethree\usk\kilogram\inverse\usk\second\totheinversetwo}%
   [\newton\usk\meter\tothetwo\per\kilogram\tothetwo]% % also \joule\usk\meter\per\kilogram\tothetwo
   [\newton\usk\meter\tothetwo\per\kilogram\tothetwo]%
 \newphysicalconstant{vacuumpermeability}%
   {\symup{\mu_o}}%
-  {4\pi\timestento{-7}}{4\pi\timestento{-7}}% % as of 2018 no longer 4\pi\timestento{-7}
+  {4\pi\times10^{-7}}{4\pi\times10^{-7}}% % as of 2018 no longer 4\pi\times10^{-7}
   {\kilogram\usk\meter\usk\ampere\totheinversetwo\usk\second\totheinversetwo}%
   [\henry\per\meter]%
   [\tesla\usk\meter\per\ampere]%
 \newphysicalconstant{vacuumpermittivity}%
   {\symup{\epsilon_o}}%
-  {9\timestento{-12}}{8.854187817\timestento{-12}}%
+  {9\times10^{-12}}{8.854187817\times10^{-12}}%
   {\ampere\tothetwo\usk\second\tothefour\usk\kilogram\inverse\usk\meter\totheinversethree}%
   [\farad\per\meter]%
   [\coulomb\tothetwo\per\newton\usk\meter\tothetwo]%
@@ -2793,94 +2907,84 @@
 % Diagnostic commands to provide sanity checks on commands that 
 % represent physical quantities and constants.
 %
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandipkg}{mandi} Improved \refCom{checkquantity}}
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandipkg}{mandi} Improved \refCom{checkconstant}}
 %    \begin{macrocode}
 \ExplSyntaxOn
-\NewDocumentCommand{\checkquantity}{ m }%
-{%
-  % Works for both scalar and vector quantities (without vector in the name!).
-  \begin{center}
-    \begin{tabular}{%
-        >{\bfseries\small}
-        p{0.5\linewidth} 
-        p{0.1\linewidth} 
-        p{0.1\linewidth} 
-        p{0.1\linewidth}
-      }%
-      name & & & \tabularnewline
-      \ttfamily\footnotesize{\token_to_str:c {#1}} & & & \tabularnewline
-    \end{tabular}~ % This nonbreaking space is important!
-    \begin{tabular}{%
-        >{\bfseries\small}p{0.25\linewidth} 
-        >{\bfseries\small}p{0.25\linewidth} 
-        >{\bfseries\small}p{0.25\linewidth}
-      }%
-      base & derived & alternate \tabularnewline
-      \footnotesize{\( \use:c {#1onlybaseunits}      \)} & 
-      \footnotesize{\( \use:c {#1onlyderivedunits}   \)} &
-      \footnotesize{\( \use:c {#1onlyalternateunits} \)}
-    \end{tabular}
-  \end{center}
-}%
-\NewDocumentCommand{\checkconstant}{ m }%
-{%
-  \begin{center}
-    \begin{tabular}{%
-        >{\bfseries\small}
-        p{0.5\linewidth} 
-        p{0.1\linewidth} 
-        p{0.1\linewidth} 
-        p{0.1\linewidth}
-      }%
-      name & & & \tabularnewline
-      \ttfamily\footnotesize{\token_to_str:c {#1}} & & & \tabularnewline
-    \end{tabular}~ % This nonbreaking space is important!
-    \begin{tabular}{%
-        >{\bfseries\small}p{0.25\linewidth} 
-        >{\bfseries\small}p{0.25\linewidth} 
-        >{\bfseries\small}p{0.25\linewidth}
-      }%
-      symbol & approximate & precise \tabularnewline
-      \footnotesize{\( \use:c {#1mathsymbol}       \)} &
-      \footnotesize{\( \use:c {#1approximatevalue} \)} &
-      \footnotesize{\( \use:c {#1precisevalue}     \)}
-    \end{tabular}~ % This nonbreaking space is important!
-    \begin{tabular}{%
-        >{\bfseries\small}p{0.25\linewidth} 
-        >{\bfseries\small}p{0.25\linewidth} 
-        >{\bfseries\small}p{0.25\linewidth}
-      }%
-      base & derived & alternate \tabularnewline
-      \footnotesize{\( \use:c {#1onlybaseunits}      \)} &
-      \footnotesize{\( \use:c {#1onlyderivedunits}   \)} &
-      \footnotesize{\( \use:c {#1onlyalternateunits} \)}
-    \end{tabular}
-  \end{center}
-}%
+\NewDocumentCommand{\@aux}{ m }
+  {
+    \use:c { #1 }
+  }
+\NewDocumentCommand{\@auy}{ m }
+  {
+    \normalfont\ttfamily\token_to_str:c { #1 }
+  }
 \ExplSyntaxOff
+\newcolumntype{M}{>{\(}p{0.25\linewidth}<{\)}}
+\NewDocumentCommand{\checkquantity}{ m }
+  {%
+    \begin{center}
+      \begin{tabular}{MMM}
+        \textbf{command}       & \multicolumn{2}{l}{\@auy{#1}}                             \tabularnewline
+        \text{\textbf{base}}   & \text{\textbf{derived}}     & \text{\textbf{alternate}}   \tabularnewline
+        \@aux{#1onlybaseunits} & \@aux{#1onlyderivedunits}   & \@aux{#1onlyalternateunits} \tabularnewline
+      \end{tabular}
+    \end{center}
+  }%
+\NewDocumentCommand{\checkconstant}{ m }
+  {%
+    \begin{center}
+      \begin{tabular}{MMM}
+        \textbf{command}       & \multicolumn{2}{l}{\@auy{#1}}                             \tabularnewline
+        \text{\textbf{symbol}} & \text{\textbf{approximate}} & \text{\textbf{precise}}     \tabularnewline
+        \@aux{#1mathsymbol}    & \@aux{#1approximatevalue}   & \@aux{#1precisevalue}       \tabularnewline
+        \text{\textbf{base}}   & \text{\textbf{derived}}     & \text{\textbf{alternate}}   \tabularnewline
+        \@aux{#1onlybaseunits} & \@aux{#1onlyderivedunits}   & \@aux{#1onlyalternateunits} \tabularnewline
+      \end{tabular}
+    \end{center}
+  }%
 %    \end{macrocode}
 %
-% \refCom{mivector} is a workhorse command.
-% Orginal code provided by |@egreg|.\newline
+% \refCom{mivector} is a workhorse command.\newline
 % See \url{https://tex.stackexchange.com/a/39054/218142}.
-% 
 %
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandipkg}{mandi} \refCom{mivector} now
+%     requires more than one component}
 %    \begin{macrocode}
 \ExplSyntaxOn
-\NewDocumentCommand{\mivector}{ O{,} m o }%
- {%
-   \mi_vector:nn { #1 } { #2 }%
-   \IfValueT{#3}{\,{#3}}%
- }%
-\seq_new:N \l__mi_list_seq
-\cs_new_protected:Npn \mi_vector:nn #1 #2
-{%
-  \ensuremath{%
-    \seq_set_split:Nnn \l__mi_list_seq { , } { #2 }
-    \int_compare:nF { \seq_count:N \l__mi_list_seq = 1 } { \left\langle }
-    \seq_use:Nnnn \l__mi_list_seq { #1 } { #1 } { #1 }
-    \int_compare:nF { \seq_count:N \l__mi_list_seq = 1 } { \right\rangle }
-  }%
-}%
+\NewDocumentCommand{\mivector}{ O{,} m o }
+  {
+    \__mandi_vector:nn { #1 } { #2 }
+    \IfValueT{#3}{\,{#3}}
+  }
+\seq_new:N \l__mandi_list_seq
+\cs_new_protected:Npn \__mandi_vector:nn #1#2
+  {
+      \seq_set_split:Nnn \l__mandi_list_seq { , } { #2 }
+      \int_compare:nT { \seq_count:N \l__mandi_list_seq = 1 } 
+       { 
+         \msg_new:nnnn { mandi } { onecomponent } 
+           { 
+             More~than~one~component~expected.       \iow_newline:
+             You~provided~one~component~to~a~command \iow_newline:
+             that~expects~a~vector.~Either~you~don't \iow_newline:
+             need~a~vector~here~or~you~didn't~supply \iow_newline:
+             all~the~components.
+           }
+           { 
+             Decide~whether~or~not~you~really~need~a~vector~command~here. \iow_newline:
+             \msg_see_documentation_text:n { mandi }
+           } 
+         \msg_fatal:nn { mandi } { onecomponent }
+         
+       }
+      \left\langle
+        \seq_use:Nnnn \l__mandi_list_seq { #1 } { #1 } { #1 }
+      \right\rangle
+  }
 \ExplSyntaxOff
 %    \end{macrocode}
 % \restoregeometry

Modified: trunk/Master/texmf-dist/source/latex/mandi/mandi.ins
===================================================================
--- trunk/Master/texmf-dist/source/latex/mandi/mandi.ins	2022-01-27 21:41:00 UTC (rev 61763)
+++ trunk/Master/texmf-dist/source/latex/mandi/mandi.ins	2022-01-27 21:41:19 UTC (rev 61764)
@@ -6,7 +6,7 @@
 %%
 %% mandi.dtx  (with options: `install')
 %% 
-%%  Copyright (C) 2021 by Paul J. Heafner <heafnerj at gmail.com>
+%%  Copyright (C) 2021,2022 by Paul J. Heafner <heafnerj at gmail.com>
 %%  ---------------------------------------------------------------------------
 %%  This  work may be  distributed and/or modified  under the conditions of the
 %%  LaTeX Project Public  License, either  version 1.3  of this  license or (at
@@ -29,7 +29,7 @@
 %%  and includes the derived files  mandi.sty
 %%                                  mandistudent.sty
 %%                                  mandiexp.sty
-%%                                  vdemo.py
+%%                                  vdemo.py (not needed)
 %%  ---------------------------------------------------------------------------
 %% 
 \input docstrip.tex
@@ -38,7 +38,7 @@
 \usedir{tex/latex/mandi}
 \preamble
 
- Copyright (C) 2021 by Paul J. Heafner <heafnerj at gmail.com>
+ Copyright (C) 2021,2022 by Paul J. Heafner <heafnerj at gmail.com>
  ---------------------------------------------------------------------------
  This  work may be  distributed and/or modified  under the conditions of the
  LaTeX Project Public  License, either  version 1.3  of this  license or (at
@@ -61,7 +61,7 @@
  and includes the derived files  mandi.sty
                                  mandistudent.sty
                                  mandiexp.sty
-                                 vdemo.py
+                                 vdemo.py (not needed)
  ---------------------------------------------------------------------------
 
 \endpreamble
@@ -82,7 +82,7 @@
 \Msg{*   3. makeindex -s gind.ist -o mandi.ind mandi.idx         *}
 \Msg{*   4. makeindex -s gglo.ist -o mandi.gls mandi.glo         *}
 \Msg{* Move the *.sty files into a directory searched by TeX.    *}
-\Msg{* The vdemo.py file is not needed.                          *}
+\Msg{* The vdemo.py file can be deleted.                         *}
 \Msg{*                                                           *}
 \Msg{*************************************************************}
 \endbatchfile

Modified: trunk/Master/texmf-dist/source/latex/mandi/mandiexp.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/mandi/mandiexp.dtx	2022-01-27 21:41:00 UTC (rev 61763)
+++ trunk/Master/texmf-dist/source/latex/mandi/mandiexp.dtx	2022-01-27 21:41:19 UTC (rev 61764)
@@ -1,7 +1,7 @@
 % \iffalse meta-comment
 % !TEX program = lualatexmk
 %
-% Copyright (C) 2021 by Paul J. Heafner <heafnerj at gmail.com>
+% Copyright (C) 2021,2022 by Paul J. Heafner <heafnerj at gmail.com>
 % ---------------------------------------------------------------------------
 % This  work may be  distributed and/or modified  under the conditions of the 
 % LaTeX Project Public  License, either  version 1.3  of this  license or (at 
@@ -65,7 +65,7 @@
 %</driver>
 % \fi
 %
-% \CheckSum{215}
+% \CheckSum{225}
 %
 % \CharacterTable
 %  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
@@ -104,7 +104,7 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{dispListing*}{sidebyside=false,listing only}
+\begin{dispListing*}{sidebyside = false,listing only}
   \usepackage{mandiexp}
 \end{dispListing*}
 %\iffalse
@@ -117,7 +117,7 @@
 \begin{docCommand}{mandiexpversion}{}
   Typesets the current version and build date.
 \end{docCommand}
-\begin{dispExample*}{sidebyside=false}
+\begin{dispExample*}{sidebyside = false}
   The version is \mandiexpversion\ and is a stable build.
 \end{dispExample*}
 %\iffalse
@@ -313,7 +313,7 @@
       doc description = {update form, arrow vectors},%
     },%
   }%
-  Variants of command for typesetting the angularmomentum principle.
+  Variants of command for typesetting the angular momentum principle.
   Use starred variants to get arrow notation for vectors.
 \end{docCommands}
 \begin{dispExample}
@@ -339,10 +339,10 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{docCommand}[doc new=2021-02-13]{energyof}{\marg{label}\oarg{label}}
+\begin{docCommand}[doc new = 2021-02-13]{energyof}{\marg{label}\oarg{label}}
     Generic symbol for the energy of some entity.
 \end{docCommand}
-\begin{dispExample*}{lefthand ratio=0.6}
+\begin{dispExample*}{lefthand ratio = 0.6}
   \( \energyof{\symup{electron}} \) \\
   \( \energyof{\symup{electron}}[\symup{final}] \)
 \end{dispExample*}
@@ -353,7 +353,7 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{docCommand}[doc new=2021-02-13]{systemenergy}{\oarg{label}}
+\begin{docCommand}[doc new = 2021-02-13]{systemenergy}{\oarg{label}}
     Symbol for system energy.
 \end{docCommand}
 \begin{dispExample}
@@ -367,7 +367,7 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{docCommand}[doc new=2021-02-13]{particleenergy}{\oarg{label}}
+\begin{docCommand}[doc new = 2021-02-13]{particleenergy}{\oarg{label}}
     Symbol for particle energy.
 \end{docCommand}
 \begin{dispExample}
@@ -381,7 +381,7 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{docCommand}[doc new=2021-02-13]{restenergy}{\oarg{label}}
+\begin{docCommand}[doc new = 2021-02-13]{restenergy}{\oarg{label}}
     Symbol for rest energy.
 \end{docCommand}
 \begin{dispExample}
@@ -395,7 +395,7 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{docCommand}[doc new=2021-02-13]{internalenergy}{\oarg{label}}
+\begin{docCommand}[doc new = 2021-02-13]{internalenergy}{\oarg{label}}
     Symbol for internal energy.
 \end{docCommand}
 \begin{dispExample}
@@ -409,7 +409,7 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{docCommand}[doc new=2021-02-13]{chemicalenergy}{\oarg{label}}
+\begin{docCommand}[doc new = 2021-02-13]{chemicalenergy}{\oarg{label}}
     Symbol for chemical energy.
 \end{docCommand}
 \begin{dispExample}
@@ -423,7 +423,7 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{docCommand}[doc new=2021-02-13]{thermalenergy}{\oarg{label}}
+\begin{docCommand}[doc new = 2021-02-13]{thermalenergy}{\oarg{label}}
     Symbol for thermal energy.
 \end{docCommand}
 \begin{dispExample}
@@ -437,7 +437,7 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{docCommand}[doc new=2021-02-13]{photonenergy}{\oarg{label}}
+\begin{docCommand}[doc new = 2021-02-13]{photonenergy}{\oarg{label}}
     Symbol for photon energy.
 \end{docCommand}
 \begin{dispExample}
@@ -452,7 +452,7 @@
 %<*example>
 %\fi
 \begin{docCommands}[%
-  doc new=2021-02-13,%
+  doc new = 2021-02-13,%
   doc parameter = \oarg{label},%
   ]%
   {%
@@ -466,7 +466,7 @@
   Symbol for translational kinetic energy.
   The starred variant gives \(E\) notation.
 \end{docCommands}
-\begin{dispExample*}{lefthand ratio=0.6}
+\begin{dispExample*}{lefthand ratio = 0.6}
   \( \translationalkineticenergy \)                  \\
   \( \translationalkineticenergy[\symup{initial}] \) \\
   \( \translationalkineticenergy* \)                 \\
@@ -480,7 +480,7 @@
 %<*example>
 %\fi
 \begin{docCommands}[%
-  doc new=2021-02-13,%
+  doc new = 2021-02-13,%
   doc parameter = \oarg{label},%
   ]%
   {%
@@ -494,7 +494,7 @@
   Symbol for rotational kinetic energy.
   The starred variant gives \(E\) notation.
 \end{docCommands}
-\begin{dispExample*}{lefthand ratio=0.6}
+\begin{dispExample*}{lefthand ratio = 0.6}
   \( \rotationalkineticenergy \)                  \\
   \( \rotationalkineticenergy[\symup{initial}] \) \\
   \( \rotationalkineticenergy* \)                 \\
@@ -508,7 +508,7 @@
 %<*example>
 %\fi
 \begin{docCommands}[%
-  doc new=2021-02-13,%
+  doc new = 2021-02-13,%
   doc parameter = \oarg{label},%
   ]%
   {%
@@ -522,7 +522,7 @@
   Symbol for vibrational kinetic energy.
   The starred variant gives \(E\) notation.
 \end{docCommands}
-\begin{dispExample*}{lefthand ratio=0.6}
+\begin{dispExample*}{lefthand ratio = 0.6}
   \( \vibrationalkineticenergy \)                  \\
   \( \vibrationalkineticenergy[\symup{initial}] \) \\
   \( \vibrationalkineticenergy* \)                 \\
@@ -535,11 +535,11 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{docCommand}[doc new=2021-02-13]{gravitationalpotentialenergy}
+\begin{docCommand}[doc new = 2021-02-13]{gravitationalpotentialenergy}
   {\oarg{label}}
     Symbol for gravitational potential energy.
 \end{docCommand}
-\begin{dispExample*}{lefthand ratio=0.6}
+\begin{dispExample*}{lefthand ratio = 0.6}
   \( \gravitationalpotentialenergy \) \\
   \( \gravitationalpotentialenergy[\symup{final}] \)
 \end{dispExample*}
@@ -550,10 +550,10 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{docCommand}[doc new=2021-02-13]{electricpotentialenergy}{\oarg{label}}
+\begin{docCommand}[doc new = 2021-02-13]{electricpotentialenergy}{\oarg{label}}
     Symbol for electric potential energy.
 \end{docCommand}
-\begin{dispExample*}{lefthand ratio=0.6}
+\begin{dispExample*}{lefthand ratio = 0.6}
   \( \electricpotentialenergy \) \\
   \( \electricpotentialenergy[\symup{final}] \)
 \end{dispExample*}
@@ -564,10 +564,10 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{docCommand}[doc new=2021-02-13]{springpotentialenergy}{\oarg{label}}
+\begin{docCommand}[doc new = 2021-02-13]{springpotentialenergy}{\oarg{label}}
     Symbol for spring potential energy.
 \end{docCommand}
-\begin{dispExample*}{lefthand ratio=0.6}
+\begin{dispExample*}{lefthand ratio = 0.6}
   \( \springpotentialenergy \) \\
   \( \springpotentialenergy[\symup{final}] \)
 \end{dispExample*}
@@ -588,12 +588,16 @@
 % |\makeatother|. This simplifies defining internal commands, with |@| 
 % in the name, that are not for the user to know about.
 %
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandiexppkg}{mandiexp} Version number works}
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandiexppkg}{mandiexp} Code formatted for better readability}
 %    \begin{macrocode}
-\def\mandiexp at version{\mandi at version}
-\def\mandiexp at date{\mandi at date}
+\def\mandiexp at version{3.1.0}
+\def\mandiexp at date{2022-01-27}
 \NeedsTeXFormat{LaTeX2e}[2020-02-02]
-\DeclareRelease{v3.0.0}{2021-08-22}{mandiexp.sty}
-\DeclareCurrentRelease{v\mandi at version}{\mandi at date}
+\DeclareRelease{v3.1.0}{2022-01-27}{mandiexp.sty}
+\DeclareCurrentRelease{v\mandiexp at version}{\mandiexp at date}
 \ProvidesPackage{mandiexp}
   [\mandiexp at date\space v\mandiexp at version\space Macros for Matter & Interactions]
 %    \end{macrocode}
@@ -606,7 +610,17 @@
 %
 %    \begin{macrocode}
 \RequirePackage{mandi}
+%    \end{macrocode}
 %
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandiexppkg}{mandiexp} \pkg{xparse} is loaded for older formats}
+%    \begin{macrocode}
+\IfFormatAtLeastTF {2020-10-01} % load xparse if necessary
+  {}%
+  {\RequirePackage{xparse}}%
+%    \end{macrocode}
+%
+%    \begin{macrocode}
 \typeout{}%
 \typeout{mandiexp: You are using mandiexp \mandiexpversion.}
 \typeout{mandiexp: This package requires LuaLaTeX.}%
@@ -614,168 +628,301 @@
 %
 % Commands specific to Matter & Interactions
 % The momentum principle
-\NewDocumentCommand{\lhsmomentumprinciple}{ s }{%
-  \Delta
-  \IfBooleanTF{#1}%
-    {\vec*{p}}%
-    {\vec{p}}%
-  _{\symup{sys}}%
-}%
-\NewDocumentCommand{\rhsmomentumprinciple}{ s }{%
-  \IfBooleanTF{#1}%
-    {\vec*{F}}%
-    {\vec{F}}%
-  _{\symup{sys,net}}\,\Delta t%
-}%
-\NewDocumentCommand{\lhsmomentumprincipleupdate}{ s }{%
-  \IfBooleanTF{#1}%
-    {\vec*{p}}%
-    {\vec{p}}%
-  _{\symup{sys,final}}%
-}%
-\NewDocumentCommand{\rhsmomentumprincipleupdate}{ s }{%
-  \IfBooleanTF{#1}%
-    {\vec*{p}}%
-    {\vec{p}}%
-  _{\symup{sys,initial}}+%
-  \IfBooleanTF{#1}%
-    {\vec*{F}}%
-    {\vec{F}}%
-  _{\symup{sys,net}}\,\Delta t%
-}%
-\NewDocumentCommand{\momentumprinciple}{ s }{%
-  \IfBooleanTF{#1}%
-    {\lhsmomentumprinciple* = \rhsmomentumprinciple*}%
-    {\lhsmomentumprinciple = \rhsmomentumprinciple}%
-}%
-\NewDocumentCommand{\momentumprincipleupdate}{ s }{%
-  \IfBooleanTF{#1}%
-    {\lhsmomentumprincipleupdate* = \rhsmomentumprincipleupdate*}%
-    {\lhsmomentumprincipleupdate = \rhsmomentumprincipleupdate}%
-}%
+\NewDocumentCommand{\lhsmomentumprinciple}{ s }%
+  {%
+    \Delta
+    \IfBooleanTF{#1}%
+      {%
+        \vec*{p}
+      }%
+      {%
+        \vec{p}%
+      }%
+    \sb{\symup{sys}}%
+  }%
+\NewDocumentCommand{\rhsmomentumprinciple}{ s }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        \vec*{F}%
+      }%
+      {%
+        \vec{F}%
+      }%
+    \sb{\symup{sys,net}}\,\Delta t%
+  }%
+\NewDocumentCommand{\lhsmomentumprincipleupdate}{ s }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        \vec*{p}%
+      }%
+      {%
+        \vec{p}%
+      }%
+    \sb{\symup{sys,final}}%
+  }%
+\NewDocumentCommand{\rhsmomentumprincipleupdate}{ s }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        \vec*{p}%
+      }%
+      {%
+        \vec{p}%
+      }%
+    \sb{\symup{sys,initial}}+%
+    \IfBooleanTF{#1}%
+      {%
+        \vec*{F}%
+      }%
+      {%
+        \vec{F}%
+      }%
+    \sb{\symup{sys,net}}\,\Delta t%
+  }%
+\NewDocumentCommand{\momentumprinciple}{ s }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        \lhsmomentumprinciple* = \rhsmomentumprinciple*%
+      }%
+      {%
+        \lhsmomentumprinciple = \rhsmomentumprinciple%
+      }%
+  }%
+\NewDocumentCommand{\momentumprincipleupdate}{ s }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        \lhsmomentumprincipleupdate* = \rhsmomentumprincipleupdate*%
+      }%
+      {%
+        \lhsmomentumprincipleupdate = \rhsmomentumprincipleupdate%
+      }%
+  }%
 % The momentum principle
-\NewDocumentCommand{\lhsenergyprinciple}{}{%
-  \Delta E_{\symup{sys}}%
-}%
-\NewDocumentCommand{\rhsenergyprinciple}{ O{} }{%
-  W_{\symup{ext}}#1%
-}%
-\NewDocumentCommand{\lhsenergyprincipleupdate}{}{%
-  E_{\symup{sys,final}}%
-}%
-\NewDocumentCommand{\rhsenergyprincipleupdate}{ O{} }{%
-  E_{\symup{sys,initial}}+%
-  W_{\symup{ext}}#1%
-}%
-\NewDocumentCommand{\energyprinciple}{ O{} }{%
-  \lhsenergyprinciple = \rhsenergyprinciple[#1]%
-}%
-\NewDocumentCommand{\energyprincipleupdate}{ O{} }{%
-  \lhsenergyprincipleupdate = \rhsenergyprincipleupdate[#1]%
-}%
+\NewDocumentCommand{\lhsenergyprinciple}{}%
+  {%
+    \Delta E_{\symup{sys}}%
+  }%
+\NewDocumentCommand{\rhsenergyprinciple}{ O{} }%
+  {%
+    W_{\symup{ext}}#1%
+  }%
+\NewDocumentCommand{\lhsenergyprincipleupdate}{}%
+  {%
+    E_{\symup{sys,final}}%
+  }%
+\NewDocumentCommand{\rhsenergyprincipleupdate}{ O{} }%
+  {%
+    E_{\symup{sys,initial}}+%
+    W_{\symup{ext}}#1%
+  }%
+\NewDocumentCommand{\energyprinciple}{ O{} }%
+  {%
+    \lhsenergyprinciple = \rhsenergyprinciple[#1]%
+  }%
+\NewDocumentCommand{\energyprincipleupdate}{ O{} }%
+  {%
+    \lhsenergyprincipleupdate = \rhsenergyprincipleupdate[#1]%
+  }%
 % The angular momentum principle
-\NewDocumentCommand{\lhsangularmomentumprinciple}{ s }{%
-  \Delta
-  \IfBooleanTF{#1}%
-    {\vec*{L}}%
-    {\vec{L}}%
-  _{A\symup{,sys,net}}%
-}%
-\NewDocumentCommand{\rhsangularmomentumprinciple}{ s }{%
-  \IfBooleanTF{#1}%
-    {\vec*{\tau}}%
-    {\vec{\tau}}%
-  _{A\symup{,sys,net}}\,\Delta t%
-}%
-\NewDocumentCommand{\lhsangularmomentumprincipleupdate}{ s }{%
-  \IfBooleanTF{#1}%
-    {\vec*{L}}%
-    {\vec{L}}%
-  _{A,\symup{sys,final}}%
-}%
-\NewDocumentCommand{\rhsangularmomentumprincipleupdate}{ s }{%
-  \IfBooleanTF{#1}%
-    {\vec*{L}}%
-    {\vec{L}}%
-  _{A\symup{,sys,initial}}+%
-  \IfBooleanTF{#1}%
-    {\vec*{\tau}}%
-    {\vec{\tau}}%
-  _{A\symup{,sys,net}}\,\Delta t%
-}%
-\NewDocumentCommand{\angularmomentumprinciple}{ s }{%
-  \IfBooleanTF{#1}%
-    {\lhsangularmomentumprinciple* = \rhsangularmomentumprinciple*}%
-    {\lhsangularmomentumprinciple = \rhsangularmomentumprinciple}%
-}%
-\NewDocumentCommand{\angularmomentumprincipleupdate}{ s }{%
-  \IfBooleanTF{#1}%
-    {\lhsangularmomentumprincipleupdate* = \rhsangularmomentumprincipleupdate*}%
-    {\lhsangularmomentumprincipleupdate = \rhsangularmomentumprincipleupdate}%
-}%
-\NewDocumentCommand{\energyof}{ m o }{%
-  E_{#1\IfValueT{#2}{,#2}}%
-}%
-\NewDocumentCommand{\systemenergy}{ o }{%
-  E_{\symup{sys}\IfValueT{#1}{,#1}}%
-}%
-\NewDocumentCommand{\particleenergy}{ o }{%
-  E_{\symup{particle}\IfValueT{#1}{,#1}}%
-}%
-\NewDocumentCommand{\restenergy}{ o }{%
-  E_{\symup{rest}\IfValueT{#1}{,#1}}%
-}%
-\NewDocumentCommand{\internalenergy}{ o }{%
-  E_{\symup{internal}\IfValueT{#1}{,#1}}%
-}%
-\NewDocumentCommand{\chemicalenergy}{ o }{%
-  E_{\symup{chem}\IfValueT{#1}{,#1}}%
-}%
-\NewDocumentCommand{\thermalenergy}{ o }{%
-  E_{\symup{therm}\IfValueT{#1}{,#1}}%
-}%
-\NewDocumentCommand{\photonenergy}{ o }{%
-  E_{\symup{photon}\IfValueT{#1}{,#1}}%
-}%
-\NewDocumentCommand{\translationalkineticenergy}{ s d[] }{%
-% d[] must be used because of the way consecutive optional
-%  arguments are handled. See xparse docs for details.
-%  See https://tex.stackexchange.com/a/569011/218142
-  \IfBooleanTF{#1}%
-  {E_\bgroup \symup{K}}%
-  {K_\bgroup\symup{trans}}%
-       \IfValueT{#2}{,#2}%
-     \egroup%
-}%
-\NewDocumentCommand{\rotationalkineticenergy}{ s d[] }{%
-% d[] must be used because of the way consecutive optional
-%  arguments are handled. See xparse docs for details.
-%  See https://tex.stackexchange.com/a/569011/218142
-  \IfBooleanTF{#1}%
-  {E_\bgroup}%
-  {K_\bgroup}%
-       \symup{rot}\IfValueT{#2}{,#2}%
-     \egroup%
-}%
-\NewDocumentCommand{\vibrationalkineticenergy}{ s d[] }{%
-% d[] must be used because of the way consecutive optional
-%  arguments are handled. See xparse docs for details.
-%  See https://tex.stackexchange.com/a/569011/218142
-  \IfBooleanTF{#1}%
-  {E_\bgroup}%
-  {K_\bgroup}%
-       \symup{vib}\IfValueT{#2}{,#2}%
-     \egroup%
-}%
-\NewDocumentCommand{\gravitationalpotentialenergy}{ o }{%
-  U_{\symup{g}\IfValueT{#1}{,#1}}%
-}%
-\NewDocumentCommand{\electricpotentialenergy}{ o }{%
-  U_{\symup{e}\IfValueT{#1}{,#1}}%
-}%
-\NewDocumentCommand{\springpotentialenergy}{ o }{%
-  U_{\symup{s}\IfValueT{#1}{,#1}}%
-}%
+\NewDocumentCommand{\lhsangularmomentumprinciple}{ s }%
+  {%
+    \Delta%
+    \IfBooleanTF{#1}%
+      {%
+        \vec*{L}%
+      }%
+      {%
+        \vec{L}%
+      }%
+    \sb{A\symup{,sys,net}}%
+  }%
+\NewDocumentCommand{\rhsangularmomentumprinciple}{ s }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        \vec*{\tau}%
+      }%
+      {%
+        \vec{\tau}%
+      }%
+    \sb{A\symup{,sys,net}}\,\Delta t%
+  }%
+\NewDocumentCommand{\lhsangularmomentumprincipleupdate}{ s }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        \vec*{L}%
+      }%
+      {%
+        \vec{L}%
+      }%
+    \sb{A,\symup{sys,final}}%
+  }%
+\NewDocumentCommand{\rhsangularmomentumprincipleupdate}{ s }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        \vec*{L}%
+      }%
+      {%
+        \vec{L}%
+      }%
+    \sb{A\symup{,sys,initial}}+%
+    \IfBooleanTF{#1}%
+      {%
+        \vec*{\tau}%
+      }%
+      {%
+        \vec{\tau}%
+      }%
+    \sb{A\symup{,sys,net}}\,\Delta t%
+  }%
+\NewDocumentCommand{\angularmomentumprinciple}{ s }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        \lhsangularmomentumprinciple* = \rhsangularmomentumprinciple*%
+      }%
+      {%
+        \lhsangularmomentumprinciple = \rhsangularmomentumprinciple%
+      }%
+  }%
+\NewDocumentCommand{\angularmomentumprincipleupdate}{ s }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        \lhsangularmomentumprincipleupdate* = \rhsangularmomentumprincipleupdate*%
+      }%
+      {%
+        \lhsangularmomentumprincipleupdate = \rhsangularmomentumprincipleupdate%
+      }%
+  }%
+\NewDocumentCommand{\energyof}{ m o }%
+  {%
+    E_{#1%
+        \IfValueT{#2}%
+          {,#2}%
+      }%
+  }%
+\NewDocumentCommand{\systemenergy}{ o }%
+  {%
+    E_{\symup{sys}%
+        \IfValueT{#1}%
+          {,#1}%
+      }%
+  }%
+\NewDocumentCommand{\particleenergy}{ o }%
+  {%
+    E_{\symup{particle}%
+        \IfValueT{#1}%
+          {,#1}%
+      }%
+  }%
+\NewDocumentCommand{\restenergy}{ o }%
+  {%
+    E_{\symup{rest}%
+        \IfValueT{#1}%
+          {,#1}%
+      }%
+  }%
+\NewDocumentCommand{\internalenergy}{ o }%
+  {%
+    E_{\symup{internal}%
+        \IfValueT{#1}%
+          {,#1}%
+      }%
+  }%
+\NewDocumentCommand{\chemicalenergy}{ o }%
+  {%
+    E_{\symup{chem}%
+        \IfValueT{#1}%
+          {,#1}%
+      }%
+  }%
+\NewDocumentCommand{\thermalenergy}{ o }%
+  {%
+    E_{\symup{therm}%
+        \IfValueT{#1}%
+          {,#1}%
+      }%
+  }%
+\NewDocumentCommand{\photonenergy}{ o }%
+  {%
+    E_{\symup{photon}%
+        \IfValueT{#1}%
+          {,#1}%
+      }%
+  }%
+\NewDocumentCommand{\translationalkineticenergy}{ s d[] }%
+  {%
+    % d[] must be used because of the way consecutive optional
+    %  arguments are handled. See xparse docs for details.
+    %  See https://tex.stackexchange.com/a/569011/218142
+    \IfBooleanTF{#1}%
+      {%
+        E_\bgroup \symup{K}%
+      }%
+      {%
+        K_\bgroup\symup{trans}%
+      }%
+            \IfValueT{#2}{,#2}%
+          \egroup%
+  }%
+\NewDocumentCommand{\rotationalkineticenergy}{ s d[] }%
+  {%
+    % d[] must be used because of the way consecutive optional
+    %  arguments are handled. See xparse docs for details.
+    %  See https://tex.stackexchange.com/a/569011/218142
+    \IfBooleanTF{#1}%
+      {%
+        E_\bgroup%
+      }%
+      {%
+        K_\bgroup%
+      }%
+            \symup{rot}\IfValueT{#2}{,#2}%
+          \egroup%
+  }%
+\NewDocumentCommand{\vibrationalkineticenergy}{ s d[] }%
+  {%
+    % d[] must be used because of the way consecutive optional
+    %  arguments are handled. See xparse docs for details.
+    %  See https://tex.stackexchange.com/a/569011/218142
+    \IfBooleanTF{#1}%
+      {%
+        E_\bgroup%
+      }%
+      {%
+        K_\bgroup%
+      }%
+            \symup{vib}\IfValueT{#2}{,#2}%
+          \egroup%
+  }%
+\NewDocumentCommand{\gravitationalpotentialenergy}{ o }%
+  {%
+    U_{\symup{g}%
+        \IfValueT{#1}%
+          {,#1}%
+    }%
+  }%
+\NewDocumentCommand{\electricpotentialenergy}{ o }%
+  {%
+    U_{\symup{e}%
+        \IfValueT{#1}%
+          {,#1}%
+      }%
+  }%
+\NewDocumentCommand{\springpotentialenergy}{ o }%
+  {%
+    U_{\symup{s}%
+        \IfValueT{#1}%
+          {,#1}%
+      }%
+  }%
 %    \end{macrocode}
 %
 % \restoregeometry

Modified: trunk/Master/texmf-dist/source/latex/mandi/mandistudent.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/mandi/mandistudent.dtx	2022-01-27 21:41:00 UTC (rev 61763)
+++ trunk/Master/texmf-dist/source/latex/mandi/mandistudent.dtx	2022-01-27 21:41:19 UTC (rev 61764)
@@ -1,7 +1,7 @@
 % \iffalse meta-comment
 % !TEX program = lualatexmk
 %
-% Copyright (C) 2021 by Paul J. Heafner <heafnerj at gmail.com>
+% Copyright (C) 2021,2022 by Paul J. Heafner <heafnerj at gmail.com>
 % ---------------------------------------------------------------------------
 % This  work may be  distributed and/or modified  under the conditions of the 
 % LaTeX Project Public  License, either  version 1.3  of this  license or (at 
@@ -111,7 +111,7 @@
 %</driver>
 % \fi
 %
-% \CheckSum{706}
+% \CheckSum{745}
 %
 % \CharacterTable
 %  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
@@ -147,7 +147,7 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{dispListing*}{sidebyside=false,listing only}
+\begin{dispListing*}{sidebyside = false,listing only}
   \usepackage{mandistudent}
 \end{dispListing*}
 %\iffalse
@@ -160,7 +160,7 @@
 \begin{docCommand}{mandistudentversion}{}
   Typesets the current version and build date.
 \end{docCommand}
-\begin{dispExample*}{sidebyside=false}
+\begin{dispExample*}{sidebyside = false}
   The version is \mandistudentversion\ and is a stable build.
 \end{dispExample*}
 %\iffalse
@@ -173,6 +173,7 @@
 %<*example>
 %\fi
 \begin{docCommands}[%
+    doc updated = 2021-09-18,%
     doc parameter = \marg{symbol}\oarg{labels},%
   ]%
   {%
@@ -192,16 +193,21 @@
   |\symup{...}| for proper typesetting. The starred variant gives arrow 
   notation whereas without the star you get boldface notation. Subscript 
   and superscript labels can be arbitrarily mixed, and order doesn't matter.
-  This command redefines the default \LaTeX\ |\vec| command.
+  This command redefines the default \LaTeXe |\vec| command.
 \end{docCommands}
-\begin{dispExample*}{lefthand ratio=0.6}
-  \( \vec{p} \)                                \\
-  \( \vec{p}_{2} \)                            \\
-  \( \vec{p}^{\symup{ball}} \)                 \\
-  \( \vec{p}_{\symup{final}} \)                \\
-  \( \vec{p}^{\symup{ball}}_{\symup{final}} \) \\
-  \( \vec{p}^{\symup{final}}_{\symup{ball}} \) \\
-  \( \vec*{p} \)
+\begin{dispExample*}{lefthand ratio = 0.6}
+  \( \vec{p} \)                                 \\
+  \( \vec{p}_{2} \)                             \\
+  \( \vec{p}^{\symup{ball}} \)                  \\
+  \( \vec{p}_{\symup{final}} \)                 \\
+  \( \vec{p}^{\symup{ball}}_{\symup{final}} \)  \\
+  \( \vec{p}^{\symup{final}}_{\symup{ball}} \)  \\
+  \( \vec*{p} \)                                \\
+  \( \vec*{p}_{2} \)                            \\
+  \( \vec*{p}^{\symup{ball}} \)                 \\
+  \( \vec*{p}_{\symup{final}} \)                \\
+  \( \vec*{p}^{\symup{ball}}_{\symup{final}} \) \\
+  \( \vec*{p}^{\symup{final}}_{\symup{ball}} \)
 \end{dispExample*}
 %\iffalse
 %</example>
@@ -211,6 +217,7 @@
 %<*example>
 %\fi
 \begin{docCommands}[%
+    doc updated = 2021-09-18,%
     doc parameter = \marg{symbol}\oarg{labels},%
   ]%
   {%
@@ -226,14 +233,19 @@
   Powerful and intelligent command for typesetting the direction of 
   a vector. The options are the same as those for \refCom{vec}.
 \end{docCommands}
-\begin{dispExample*}{lefthand ratio=0.65}
-  \( \dirvec{p} \)                                \\
-  \( \dirvec{p}_{2} \)                            \\
-  \( \dirvec{p}^{\symup{ball}} \)                 \\
-  \( \dirvec{p}_{\symup{final}} \)                \\
-  \( \dirvec{p}^{\symup{ball}}_{\symup{final}} \) \\
-  \( \dirvec{p}^{\symup{final}}_{\symup{ball}} \) \\
-  \( \dirvec*{p} \)
+\begin{dispExample*}{lefthand ratio = 0.65}
+  \( \dirvec{p} \)                                 \\
+  \( \dirvec{p}_{2} \)                             \\
+  \( \dirvec{p}^{\symup{ball}} \)                  \\
+  \( \dirvec{p}_{\symup{final}} \)                 \\
+  \( \dirvec{p}^{\symup{ball}}_{\symup{final}} \)  \\
+  \( \dirvec{p}^{\symup{final}}_{\symup{ball}} \)  \\
+  \( \dirvec*{p} \)                                \\ 
+  \( \dirvec*{p}_{2} \)                            \\
+  \( \dirvec*{p}^{\symup{ball}} \)                 \\
+  \( \dirvec*{p}_{\symup{final}} \)                \\
+  \( \dirvec*{p}^{\symup{ball}}_{\symup{final}} \) \\
+  \( \dirvec*{p}^{\symup{final}}_{\symup{ball}} \) 
 \end{dispExample*}
 %\iffalse
 %</example>
@@ -445,7 +457,7 @@
   Commands for geometric relationships, mainly
   intended for subscripts.
 \end{docCommands}
-\begin{dispExample*}{lefthand ratio=0.6}
+\begin{dispExample*}{lefthand ratio = 0.6}
  \( \vec{F}_{\parallelto} + \vec{F}_{\perpendicularto} \)
 \end{dispExample*}
 %\iffalse
@@ -480,16 +492,16 @@
   begin on a new page. See the examples for how to handle single and 
   multiple part problems.
 \end{docEnvironments}
-\begin{docCommand}[doc new = 2012-02-03]{problempart}{}
+\begin{docCommand}[doc new = 2021-02-03]{problempart}{}
   Denotes a part of a problem within a \refEnv{parts}
   environment.
 \end{docCommand}
-\begin{dispExample*}{sidebyside=false}
+\begin{dispExample*}{sidebyside = false}
   \begin{physicsproblem}{Problem 1}
     This is a physics problem with no parts.
   \end{physicsproblem}
 \end{dispExample*}
-\begin{dispExample*}{sidebyside=false}
+\begin{dispExample*}{sidebyside = false}
   \begin{physicsproblem}{Problem 2}
     This is a physics problem with multiple parts.
     The list is vertical.
@@ -500,7 +512,7 @@
     \end{parts}
   \end{physicsproblem}
 \end{dispExample*}
-\begin{dispExample*}{sidebyside=false}
+\begin{dispExample*}{sidebyside = false}
   \begin{physicsproblem*}{Problem 3}
     This is a physics problem with multiple parts.
     The list is in-line.
@@ -555,7 +567,7 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{docCommand}[doc updated = 2012-02-26]{reason}{\marg{reason}}
+\begin{docCommand}[doc updated = 2021-02-26]{reason}{\marg{reason}}
   Provides an annotation in a step-by-step solution.
   Keep reasons short and to the point. Wrap mathematical
   content in math mode. 
@@ -583,7 +595,7 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{dispListing*}{sidebyside=false,listing only}
+\begin{dispListing*}{sidebyside = false,listing only}
   \begin{physicsproblem}{Combined Problem and Solution}
     This is an interesting physics problem.
     \begin{physicssolution}
@@ -591,7 +603,7 @@
     \end{physicssolution}
   \end{physicsproblem}
 \end{dispListing*}
-\begin{dispListing*}{sidebyside=false,listing only}
+\begin{dispListing*}{sidebyside = false,listing only}
   \begin{physicsproblem}{Combined Multipart Problem with Solutions}
     This is a physics problem with multiple parts.
     \begin{parts}
@@ -617,7 +629,7 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{docCommand}[doc new=2021-02-06]{hilite}{%
+\begin{docCommand}[doc new = 2021-02-06]{hilite}{%
     \oarg{color}\marg{target}\oarg{shape}
   }%
   Hilites the desired target, which can be an entire mathematical expression 
@@ -624,7 +636,7 @@
   or a part thereof. The default color is magenta and the default shape is a
   rectangle.
 \end{docCommand} 
-\begin{dispListing*}{sidebyside=false,listing only}
+\begin{dispListing*}{sidebyside = false,listing only}
   \begin{align*}
     (\Delta s)^2 &= -(\Delta t)^2 + (\Delta x)^2 + (\Delta y)^2 + 
                      (\Delta z)^2 \\
@@ -656,7 +668,7 @@
                     (\Delta y)^{\hilite[blue!50]{2}[circle]} +
                     (\Delta z)^{\hilite[violet!45]{2}[circle]}
   \end{align*}
-\begin{dispListing*}{sidebyside=false,listing only}
+\begin{dispListing*}{sidebyside = false,listing only}
   \begin{align*}
     \Delta\vec{p} &= \vec{F}_{\sumup{net}}\Delta t \\
     \hilite[orange]{\Delta\vec{p}}[circle] &= \vec{F}_{\symup{net}}\Delta t \\
@@ -688,7 +700,7 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{docCommand}[doc updated = 2021-02-26]{image}{%
+\begin{docCommand}[doc updated = 2021-09-18]{image}{%
     \oarg{options}\marg{caption}\marg{label}\marg{image}
   }%
   Simplified interface for importing an image. The images are treated 
@@ -695,7 +707,7 @@
   as floats, so they may not appear at the most logically intuitive 
   place.
 \end{docCommand}
-\begin{dispListing*}{sidebyside=false,listing only,verbatim ignore percent}
+\begin{dispListing*}{sidebyside = false,listing only,verbatim ignore percent}
   \image[scale=0.20]{example-image-1x1}
     {Image shown 20 percent actual size.}{reffig1}
 \end{dispListing*}
@@ -705,13 +717,13 @@
   Figure \ref{reffig1} is nice. 
   It's captioned \nameref{reffig1} and is on page \pageref{reffig1}.
 \end{dispExample*}
-\begin{dispListing*}{sidebyside=false,listing only,verbatim ignore percent}
+\begin{dispListing*}{sidebyside = false,listing only,verbatim ignore percent}
   \image[scale=0.20,angle=45]{example-image-1x1}
   {Image shown 20 percent actual size and rotated.}{reffig1}
 \end{dispListing*}
 \image[scale=0.20,angle=45]{example-image-1x1}
 {Image shown 20 percent actual size and rotated.}{reffig2}
-\begin{dispExample*}{sidebyside=false}
+\begin{dispExample*}{sidebyside = false}
   Figure \ref{reffig2} is nice. 
   It's captioned \nameref{reffig2} and is on page \pageref{reffig2}.
 \end{dispExample*}
@@ -729,7 +741,7 @@
 %<*example>
 %\fi
 \begin{docCommands}[%
-    doc parameter = \oarg{delimiter}\marg{\ensuremath{c_1,\dots,c_n}},%
+    doc parameter = \oarg{delimiter}\marg{\( c_1,\dots,c_n \)},%
   ]%
   {%
     {%
@@ -867,11 +879,14 @@
 %</example>
 %\fi
 %
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandistudentpkg}{mandistudent} \cs{diff} renamed to 
+%    \refCom{df} for compatibility with the \pkg{numerica} package}
 %\iffalse
 %<*example>
 %\fi
-\begin{docCommand}[doc new=2021-04-06]{diff}{}%
-  Intelligent differential (exterior derivative)
+\begin{docCommand}[doc updated = 2022-01-27]{df}{}%
+  Intelligent differential and exterior derivative
   operator.
 \end{docCommand}
 \begin{dispExample}
@@ -879,10 +894,10 @@
    \int x\,dx 
  \]
  \[
-   \int x\,\diff{x}
+   \int x\,\df{x}
  \]
  \[
-   \int x\,\diff*{x} 
+   \int x\,\df*{x} 
  \]
 \end{dispExample}
 %\iffalse
@@ -889,9 +904,15 @@
 %</example>
 %\fi
 %
-% \subsection{\GlowScript\ and \VPython\ Program Listings}
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandistudentpkg}{mandistudent} All instances of 
+%    \texttt{GlowScript} have been changed to \texttt{Web VPython}}
+% \subsection{\WebVPython\ and \VPython\ Program Listings}
 %
-% \href{https://\gsurl}{\GlowScript}\footnote{\href{https://\gsurl}{https://\gsurl}} 
+% \href{https://\gsurl}{\WebVPython}
+% \footnote{On November 9, 2021 \texttt{GlowScript} was renamed to 
+% \WebVPython. The website was changed to
+% \href{https://\gsurl}{https://\gsurl}.}
 % and 
 % \href{https://\vpurl}{VPython}\footnote{\href{https://\vpurl}{https://\vpurl}} 
 % are programming environments (both use \href{https://www.python.org}{Python})
@@ -899,25 +920,39 @@
 % for modeling physical systems. \mandi\ makes including code listings
 % very simple for students.
 %
-% \subsection{The \texttt{\small glowscriptblock} Environment}
+% \subsection{The \texttt{\small webvpythonblock} Environment}
 %
 %\iffalse
 %<*example>
 %\fi
-\begin{docEnvironment}[%
-      doc updated = 2021-02-26,doclang/environment content=GlowScript code%
-    ]%
-  {glowscriptblock}{\oarg{options}(\meta{link})\marg{caption}}
+\begin{docEnvironments}[%
+    doc parameter = {\oarg{options}(\meta{link})\marg{caption}},% 
+    doclang/environment content=WebVPython code,%
+  ]%
+  {%
+    {%
+      doc updated = 2022-01-27,%
+      doc name = webvpythonblock,%    
+      doc description = now includes a QR code,%
+    },%
+    {%
+      doc new = 2022-01-27,%
+      doc name = webvpythonblock*,%
+      doc description = use this variant to omit QR code,%
+    },%
+  }%
   Code placed here is nicely formatted and optionally linked to its source on 
-  \href{https://\gsurl}{\GlowScriptorg}. Clicking anywhere in the code window 
-  will open the link in the default browser. A caption is mandatory, and a 
-  label is internally generated. The listing always begins on a new page. A 
-  URL shortening utility is recommended to keep the URL from getting unruly. 
-  For convenience, |https://| is automatically prepended to the URL and can 
-  thus be omitted. The program must exist in a public, not private, folder.
-\end{docEnvironment}
-\begin{dispListing*}{sidebyside=false}
-\begin{glowscriptblock}(tinyurl.com/y3lnqyn3){A \texttt{GlowScript} Program}
+  \href{https://\gsurl}{\WebVPythonorg}, which must be in a public (not private)
+  folder. Clicking anywhere in the code window will open the link in the default 
+  browser. A caption is mandatory, and a label is internally generated. The 
+  listing always begins on a new page. A URL shortening utility is recommended 
+  to keep the URL from getting unruly. For convenience, |https://| is 
+  automatically prepended to the URL and can thus be omitted. The |#| character 
+  in a URL should not cause problems. The default URL is that of the \WebVPython\ 
+  home page.
+\end{docEnvironments}
+\begin{dispListing*}{sidebyside = false}
+\begin{webvpythonblock}(tinyurl.com/y3lnqyn3){A \texttt{Web VPython} Program With QR Code}
 GlowScript 3.0 vpython
 
 scene.width = 400
@@ -961,9 +996,9 @@
     ball.pos = ball.pos + (pball / mball) * deltat
     spring.axis = ball.pos - ceiling.pos
     t = t + deltat
-\end{glowscriptblock}
+\end{webvpythonblock}
 \end{dispListing*}
-\begin{glowscriptblock}(tinyurl.com/y3lnqyn3){A \texttt{GlowScript} Program}
+\begin{webvpythonblock}(tinyurl.com/y3lnqyn3){A \texttt{Web VPython} Program With QR Code}
 GlowScript 3.0 vpython
 
 scene.width = 400
@@ -1007,18 +1042,128 @@
     ball.pos = ball.pos + (pball / mball) * deltat
     spring.axis = ball.pos - ceiling.pos
     t = t + deltat
-\end{glowscriptblock}
+\end{webvpythonblock}
+%  
 %\iffalse
 %</example>
 %\fi
 %
+% \newpage
+% Here is how one would reference this program elsewhere. Notice the 
+% references are numbered sequentially within the document.
+%
 %\iffalse
 %<*example>
 %\fi
-\begin{dispExample*}{sidebyside=false}
-  \GlowScript\ program \ref{gs:1} is nice. 
+\begin{dispExample*}{sidebyside = false}
+  \WebVPython\ program \ref{gs:1} is nice. 
   It's called \nameref{gs:1} and is on page \pageref{gs:1}.
 \end{dispExample*}
+%\iffalse
+%</example>
+%\fi
+%
+% \newpage
+%
+%\iffalse
+%<*example>
+%\fi
+\begin{dispListing*}{sidebyside = false}
+\begin{webvpythonblock*}(tinyurl.com/y3lnqyn3){A \texttt{Web VPython} Program Without QR Code}
+GlowScript 3.0 vpython
+
+scene.width = 400
+scene.height = 760
+# constants and data
+g = 9.8       # m/s^2
+mball = 0.03  # kg
+Lo = 0.26     # m
+ks = 1.8      # N/m
+deltat = 0.01 # s
+
+# objects (origin is at ceiling)
+ceiling = box(pos=vector(0,0,0), length=0.2, height=0.01, 
+              width=0.2)
+ball = sphere(pos=vector(0,-0.3,0),radius=0.025,
+              color=color.orange)
+spring = helix(pos=ceiling.pos, axis=ball.pos-ceiling.pos,
+               color=color.cyan,thickness=0.003,coils=40,
+               radius=0.010)
+
+# initial values
+pball = mball * vector(0,0,0)      # kg m/s
+Fgrav = mball * g * vector(0,-1,0) # N
+t = 0
+
+# improve the display
+scene.autoscale = False        # turn off automatic camera zoom
+scene.center = vector(0,-Lo,0) # move camera down
+scene.waitfor('click')         # wait for a mouse click
+
+# initial calculation loop
+# calculation loop
+while t < 10:
+    rate(100)
+    # we need the stretch
+    s = mag(ball.pos) - Lo
+    # we need the spring force
+    Fspring = ks * s * -norm(spring.axis)
+    Fnet = Fgrav + Fspring
+    pball = pball + Fnet * deltat
+    ball.pos = ball.pos + (pball / mball) * deltat
+    spring.axis = ball.pos - ceiling.pos
+    t = t + deltat
+\end{webvpythonblock*}
+\end{dispListing*}
+\begin{webvpythonblock*}(tinyurl.com/y3lnqyn3){A \texttt{Web VPython} Program Without QR Code}
+GlowScript 3.0 vpython
+
+scene.width = 400
+scene.height = 760
+# constants and data
+g = 9.8       # m/s^2
+mball = 0.03  # kg
+Lo = 0.26     # m
+ks = 1.8      # N/m
+deltat = 0.01 # s
+
+# objects (origin is at ceiling)
+ceiling = box(pos=vector(0,0,0), length=0.2, height=0.01, 
+              width=0.2)
+ball = sphere(pos=vector(0,-0.3,0),radius=0.025,
+              color=color.orange)
+spring = helix(pos=ceiling.pos, axis=ball.pos-ceiling.pos,
+               color=color.cyan,thickness=0.003,coils=40,
+               radius=0.010)
+
+# initial values
+pball = mball * vector(0,0,0)      # kg m/s
+Fgrav = mball * g * vector(0,-1,0) # N
+t = 0
+
+# improve the display
+scene.autoscale = False        # turn off automatic camera zoom
+scene.center = vector(0,-Lo,0) # move camera down
+scene.waitfor('click')         # wait for a mouse click
+
+# initial calculation loop
+# calculation loop
+while t < 10:
+    rate(100)
+    # we need the stretch
+    s = mag(ball.pos) - Lo
+    # we need the spring force
+    Fspring = ks * s * -norm(spring.axis)
+    Fnet = Fgrav + Fspring
+    pball = pball + Fnet * deltat
+    ball.pos = ball.pos + (pball / mball) * deltat
+    spring.axis = ball.pos - ceiling.pos
+    t = t + deltat
+\end{webvpythonblock*}
+\begin{dispExample*}{sidebyside = false}
+  \WebVPython\ program \ref{gs:2} is nice. 
+  It's called \nameref{gs:2} and is on page \pageref{gs:2}.
+\end{dispExample*}
 %  
 %\iffalse
 %</example>
@@ -1029,22 +1174,20 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{docCommand}[doc updated = 2021-02-26]{vpythonfile}
-  {\oarg{options}\marg{file}\marg{caption}}
-  Command to load and typeset a \VPython\ program. The file is read from 
+\begin{docCommand}[doc updated = 2022-01-27]{vpythonfile}
+  {\oarg{options}(\meta{link})\marg{file}\marg{caption}}
+  Command to load and typeset a \VPython\ program, read from local file
   \marg{file}. Clicking anywhere in the code window can optionally open 
   a link, passed as an option, in the default browser. A caption is mandatory, 
   and a label is internally generated. The listing always begins on a new page. 
   A URL shortening utility is recommended to keep the URL from getting unruly. 
   For convenience, |https://| is automatically prepended to the URL and can 
-  thus be omitted.
+  thus be omitted. The default URL is that of the \VPython\ home page.
 \end{docCommand}
-\begin{dispListing*}{sidebyside=false}
-\vpythonfile[hyperurl interior = https://vpython.org]{vdemo.py}
-  {A \VPython\ Program}
+\begin{dispListing*}{sidebyside = false}
+\vpythonfile{vdemo.py}{A \VPython\ Program}
 \end{dispListing*}
-\vpythonfile[hyperurl interior = https://vpython.org]{vdemo.py}
-  {A \VPython\ Program}
+\vpythonfile{vdemo.py}{A \VPython\ Program}
 %\iffalse
 %</example>
 %\fi
@@ -1052,7 +1195,7 @@
 %\iffalse
 %<*example>
 %\fi
-\begin{dispExample*}{sidebyside=false}
+\begin{dispExample*}{sidebyside = false}
   \VPython\ program \ref{vp:1} is nice. 
   It's called \nameref{vp:1} and is on page \pageref{vp:1}.
 \end{dispExample*}
@@ -1061,7 +1204,7 @@
 %</example>
 %\fi
 %
-% \subsection{The \texttt{\small glowscriptinline} and 
+% \subsection{The \texttt{\small webvpythoninline} and 
 %   \texttt{\small vpythoninline} Commands}
 %
 %\iffalse
@@ -1072,8 +1215,8 @@
   ]%
   {%
     {%
-      doc name = glowscriptinline,%
-      doc parameter = \marg{GlowScript code},%
+      doc name = webvpythoninline,%
+      doc parameter = \marg{Web VPython code},%
     },%
     {%
       doc name = vpythoninline,%
@@ -1083,8 +1226,8 @@
   Typesets a small, in-line snippet of code. The snippet should be
   less than one line long.
 \end{docCommands}
-\begin{dispExample*}{sidebyside=false}
-  \GlowScript\ programs begin with \glowscriptinline{GlowScript 3.0 VPython}
+\begin{dispExample*}{sidebyside = false}
+  \WebVPython\ programs begin with \webvpythoninline{GlowScript 3.0 VPython}
   and \VPython\ programs begin with \vpythoninline{from vpython import *}. 
 \end{dispExample*}
 %\iffalse
@@ -1104,12 +1247,16 @@
 % |\makeatother|. This simplifies defining internal commands, with |@| 
 % in the name, that are not for the user to know about.
 %
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandistudentpkg}{mandistudent} Version number works}
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandistudentpkg}{mandistudent} Code formatted for better readability}
 %    \begin{macrocode}
-\def\mandistudent at version{\mandi at version}
-\def\mandistudent at date{\mandi at date}
+\def\mandistudent at version{3.1.0}
+\def\mandistudent at date{2022-01-27}
 \NeedsTeXFormat{LaTeX2e}[2020-02-02]
-\DeclareRelease{v3.0.0}{2021-08-22}{mandistudent.sty}
-\DeclareCurrentRelease{v\mandi at version}{\mandi at date}
+\DeclareRelease{v3.1.0}{2022-01-27}{mandistudent.sty}
+\DeclareCurrentRelease{v\mandistudent at version}{\mandistudent at date}
 \ProvidesPackage{mandistudent}
   [\mandistudent at date\space v\mandistudent at version\space Macros for introductory physics]
 %    \end{macrocode}
@@ -1133,11 +1280,22 @@
 \RequirePackage{mandi}
 \RequirePackage{mathtools}           % needed for paired delimiters; extends amsmath
 \RequirePackage{nicematrix}          % needed for column and row vectors
+\RequirePackage{qrcode}              % needed for QR codes in webvpythonblock
+\qrset{height=1.5cm}                 % set default size of QR code
 \RequirePackage[most]{tcolorbox}     % needed for program listings
 \RequirePackage{tensor}              % needed for index notation
 \RequirePackage{tikz}                % needed for \hilite
 \usetikzlibrary{shapes,fit,tikzmark} % needed for \hilite
 \RequirePackage{unicode-math}        % needed for Unicode support
+%    \end{macrocode}
+%
+%
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandistudentpkg}{mandistudent} \pkg{xparse} is loaded for older formats}
+%    \begin{macrocode}
+\IfFormatAtLeastTF {2020-10-01}      % load xparse if necessary
+  {}%
+  {\RequirePackage{xparse}}%
 \RequirePackage{hyperref}            % load last
 \RequireLuaTeX                       % require this engine
 %    \end{macrocode}
@@ -1146,7 +1304,7 @@
 % The \href{https://www.ctan.org/pkg/unicode-math}{\pkg{unicode-math}} package 
 % loads the \href{https://www.ctan.org/pkg/fontspec}{\pkg{fontspec}} and 
 % \href{https://www.ctan.org/pkg/xparse}{\pkg{xparse}}
-% packages. Note that \pkg{xparse} is now part of the \LaTeX\ kernel.
+% packages. Note that \pkg{xparse} is now part of the \LaTeXe\ kernel.
 % Because \pkg{unicode-math} is required, all documents using \mandi\ must
 % be compiled with an engine that supports Unicode. We recommend \lualatex.
 %
@@ -1153,6 +1311,7 @@
 %    \begin{macrocode}
 \unimathsetup{math-style=ISO}
 \unimathsetup{warnings-off={mathtools-colon,mathtools-overbracket}}
+%    \end{macrocode}
 %
 % Use normal math letters from Latin Modern Math for familiarity with 
 % textbooks.
@@ -1162,7 +1321,7 @@
   {Latin Modern Math}    % default math font; better J
 %    \end{macrocode}
 %
-% Borrow from GeX Gyre DejaVu Math for vectors and tensors to get single-storey g.
+% Borrow from TeX Gyre DejaVu Math for vectors and tensors to get single-storey g.
 %
 %    \begin{macrocode}
 \setmathfont[Scale=MatchLowercase,range={sfit/{latin},bfsfit/{latin}}]
@@ -1169,12 +1328,13 @@
   {TeX Gyre DejaVu Math} % single-storey lowercase g
 %    \end{macrocode}
 %
-% Borrow from GeX Gyre DejaVu Math to get single-storey g.
+% Borrow from TeX Gyre DejaVu Math to get single-storey g.
 %
 %    \begin{macrocode}
 \setmathfont[Scale=MatchLowercase,range={sfup/{latin},bfsfup/{latin}}]
   {TeX Gyre DejaVu Math} % single-storey lowercase g
 %    \end{macrocode}
+%
 % Borrow |mathscr| and |mathbfscr| from XITS Math.\newline
 % See \url{https://tex.stackexchange.com/a/120073/218142}.
 %
@@ -1282,7 +1442,7 @@
 %    \end{macrocode}
 %
 % Tweak the \href{https://www.ctan.org/pkg/esvect}{\pkg{esvect}} package 
-% fonts to get the correct font size. Code provided by |@egreg|.\newline
+% fonts to get the correct font size.\newline
 % See \url{https://tex.stackexchange.com/a/566676}.
 %
 %    \begin{macrocode}
@@ -1318,23 +1478,32 @@
 % See \url{https://tex.stackexchange.com/q/554706/218142}.\newline
 % See also \url{https://tex.stackexchange.com/a/531037/218142}.
 %
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandistudentpkg}{mandistudent} \refCom{vec}%
+%    no longer adds \cs{scriptspace} when no sub/superscript is given}
 %    \begin{macrocode}
-\RenewDocumentCommand{\vec}{ s m e{_^} }{%
+\RenewDocumentCommand{\vec}{ s m e{_^} }%
+  {%
     % Note the \, used to make superscript look better.
-    \IfBooleanTF {#1}
-      {\vv{#2}%      % * gives an arrow
-         % Use \sp{} primitive for superscript.
-         % Adjust superscript for the arrow.
-         \sp{\IfValueT{#4}{\,#4}\vphantom{\smash[t]{\big|}}}
-      }%         
-      {\symbfit{#2}  % no * gives us bold
-         % Use \sp{} primitive for superscript.
-         % No superscript adjustment needed.
-         \sp{\IfValueT{#4}{#4}\vphantom{\smash[t]{\big|}}}
-      }% 
-    % Use \sb{} primitive for subscript.
-    \sb{\IfValueT{#3}{#3}\vphantom{\smash[b]{|}}}
-}%
+    \IfBooleanTF{#1}
+      {%
+        \vv{#2}%      % * gives an arrow
+        % Use \sp{} primitive for superscript.
+        % Adjust superscript for the arrow.
+        \IfValueT{#4}%
+          {\sp{\,#4\vphantom{\smash[t]{\big|}}}}
+      }%
+      {%
+        \symbfit{#2}  % no * gives us bold
+        % Use \sp{} primitive for superscript.
+        % No superscript adjustment needed.
+        \IfValueT{#4}%
+          {\sp{#4\vphantom{\smash[t]{\big|}}}}
+      }%
+      % Use \sb{} primitive for subscript.
+    \IfValueT{#3}%
+      {\sb{#3\vphantom{\smash[b]{|}}}}
+  }%
 %    \end{macrocode}
 %
 % A command for the direction of a vector.
@@ -1343,53 +1512,68 @@
 % package.\newline
 % See \url{https://tex.stackexchange.com/a/391204/218142}.
 %
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandistudentpkg}{mandistudent} \refCom{dirvec}%
+%    no longer adds \cs{scriptspace} when no sub/superscript is given}
 %    \begin{macrocode}
-\NewDocumentCommand{\dirvec}{ s m e{_^} }{%
-    \widehat{\makebox*{\(w\)}{\ensuremath{%
-      \IfBooleanTF {#1}
-        {%
-          #2
-        }%
-        {%
-          \symbfit{#2}
-        }%
-       }%
+\NewDocumentCommand{\dirvec}{ s m e{_^} }%
+  {%
+    \widehat%
+      {%
+        \makebox*{\(w\)}%
+          {%
+            \ensuremath{%
+              \IfBooleanTF {#1}%
+                {%
+                  #2%
+                }%
+                {%
+                  \symbfit{#2}%
+                }%
+            }%
+          }%
       }%
-     }%
-    \sb{\IfValueT{#3}{#3}\vphantom{\smash[b]{|}}}
-    \sp{\IfValueT{#4}{\,#4}\vphantom{\smash[t]{\big|}}}      
-}%
+    \IfValueT{#3}%
+      {\sb{#3\vphantom{\smash[b]{|}}}}%
+    \IfValueT{#4}%
+      {\sp{\,#4\vphantom{\smash[t]{\big|}}}}%
+  }%
 %    \end{macrocode}
 %
 % The zero vector.
 %
 %    \begin{macrocode}
-\NewDocumentCommand{\zerovec}{ s }{%
-  \IfBooleanTF {#1}
-    {\vv{0}}%
-    {\symbfup{0}}%
-}%
+\NewDocumentCommand{\zerovec}{ s }%
+  {%
+    \IfBooleanTF {#1}
+      {\vv{0}}%
+      {\symbfup{0}}%
+  }%
 %    \end{macrocode}
 %
-% Notation for column and row vectors.
-% Orginal code provided by |@egreg|.\newline
+% Notation for column and row vectors.\newline
 % See \url{https://tex.stackexchange.com/a/39054/218142}.
 %
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandistudentpkg}{mandistudent} \LaTeX3 code now conforms to formatting standards}
 %    \begin{macrocode}
 \ExplSyntaxOn
-\NewDocumentCommand{\colvec}{ O{,} m }{%
-  \vector_main:nnnn { p } { \\ } { #1 } { #2 }
-}%
-\NewDocumentCommand{\rowvec}{ O{,} m }{%
-  \vector_main:nnnn { p } { & } { #1 } { #2 }
-}%
-\seq_new:N \l__vector_arg_seq
-\cs_new_protected:Npn \vector_main:nnnn #1 #2 #3 #4 {%
-  \seq_set_split:Nnn \l__vector_arg_seq { #3 } { #4 }
-  \begin{#1NiceMatrix}[r]
-    \seq_use:Nnnn \l__vector_arg_seq { #2 } { #2 } { #2 }
-  \end{#1NiceMatrix}
-}%
+\NewDocumentCommand{\colvec}{ O{,} m }
+  {
+    \__mandi_vectormain:nnnn { p } { \\ } { #1 } { #2 }
+  }
+\NewDocumentCommand{\rowvec}{ O{,} m }
+  {
+    \__mandi_vectormain:nnnn { p } { & } { #1 } { #2 }
+  }
+\seq_new:N \l__mandi_vectorarg_seq
+\cs_new_protected:Npn \__mandi_vectormain:nnnn #1#2#3#4 
+  {
+    \seq_set_split:Nnn \l__mandi_vectorarg_seq { #3 } { #4 }
+    \begin{#1NiceMatrix}[r]
+      \seq_use:Nnnn \l__mandi_vectorarg_seq { #2 } { #2 } { #2 }
+    \end{#1NiceMatrix}
+  }
 \ExplSyntaxOff
 %    \end{macrocode}
 %
@@ -1416,7 +1600,7 @@
 % Some semantic aliases. Because of the way \refCom{vec} and
 % \refCom{dirvec} are defined, I reluctantly decided not to
 % implement a |\magvec| command. It would require accounting
-% for too mamy options. So \refCom{magnitude} is the new
+% for too many options. So \refCom{magnitude} is the new
 % solution.
 %
 %    \begin{macrocode}
@@ -1429,8 +1613,10 @@
 % mainly to be subscripts.
 %
 %    \begin{macrocode}
-\NewDocumentCommand{\parallelto}{}
-  {\mkern3mu\vphantom{\perp}\vrule depth 0pt\mkern2mu\vrule depth 0pt\mkern3mu}
+\NewDocumentCommand{\parallelto}{}%
+  {%
+    \mkern3mu\vphantom{\perp}\vrule depth 0pt\mkern2mu\vrule depth 0pt\mkern3mu%
+  }%
 \NewDocumentCommand{\perpendicularto}{}{\perp}
 %    \end{macrocode}
 %
@@ -1438,17 +1624,21 @@
 % in-line lists.
 %
 %    \begin{macrocode}
-\NewDocumentEnvironment{physicsproblem}{ m }{%
-  \newpage%
-  \section*{#1}%
-  \newlist{parts}{enumerate}{2}%
-  \setlist[parts]{label=\bfseries(\alph*)}}%
+\NewDocumentEnvironment{physicsproblem}{ m }%
+  {%
+    \newpage%
+    \section*{#1}%
+    \newlist{parts}{enumerate}{2}%
+    \setlist[parts]{label=\bfseries(\alph*)}%
+  }%
   {}%
-\NewDocumentEnvironment{physicsproblem*}{ m }{%
-  \newpage%
-  \section*{#1}%
-  \newlist{parts}{enumerate*}{2}%
-  \setlist[parts]{label=\bfseries(\alph*)}}%
+\NewDocumentEnvironment{physicsproblem*}{ m }%
+  {%
+    \newpage%
+    \section*{#1}%
+    \newlist{parts}{enumerate*}{2}%
+    \setlist[parts]{label=\bfseries(\alph*)}%
+  }%
   {}%
 \NewDocumentCommand{\problempart}{}{\item}%
 %    \end{macrocode}
@@ -1456,29 +1646,34 @@
 % An environment for problem solutions.
 %
 %    \begin{macrocode}
-\NewDocumentEnvironment{physicssolution}{ +b }{%
-  % Make equation numbering consecutive through the document.
-  \begin{align}
-    #1
-  \end{align}
-}{}%
-\NewDocumentEnvironment{physicssolution*}{ +b }{%
-  % Make equation numbering consecutive through the document.
-  \begin{align*}
-    #1
-  \end{align*}
-}{}%
+\NewDocumentEnvironment{physicssolution}{ +b }%
+  {%
+    % Make equation numbering consecutive through the document.
+    \begin{align}
+      #1
+    \end{align}
+  }%
+  {}%
+\NewDocumentEnvironment{physicssolution*}{ +b }%
+  {%
+    % Make equation numbering consecutive through the document.
+    \begin{align*}
+      #1
+    \end{align*}
+  }%
+  {}%
 %    \end{macrocode}
 %
 % See \url{https://tex.stackexchange.com/q/570223/218142}.
 %
 %    \begin{macrocode}
-\NewDocumentCommand{\reason}{ O{4cm} m }
-  {&&\begin{minipage}{#1}\raggedright\small #2\end{minipage}}
+\NewDocumentCommand{\reason}{ O{4cm} m }%
+  {%
+    &&\begin{minipage}{#1}\raggedright\small #2\end{minipage}%
+  }%
 %    \end{macrocode}
 %
 % Command for highlighting parts of, or entire, mathematical expressions.\newline
-% Original code by anonymous user |@abcdefg|, modified by me.\newline
 %  See \url{https://texample.net/tikz/examples/beamer-arrows/}.\newline
 %  See also \url{https://tex.stackexchange.com/a/406084/218142}.\newline
 %  See also \url{https://tex.stackexchange.com/a/570858/218142}.\newline
@@ -1489,34 +1684,40 @@
 %
 %    \begin{macrocode}
 \newcounter{tikzhighlightnode}
-\NewDocumentCommand{\hilite}{ O{magenta!60} m O{rectangle} }{%
-  \stepcounter{tikzhighlightnode}%
-  \tikzmarknode{highlighted-node-\number\value{tikzhighlightnode}}{#2}%
-  \edef\temp{%
-    \noexpand\AddToShipoutPictureBG{%
-      \noexpand\begin{tikzpicture}[overlay,remember picture]%
-      \noexpand\iftikzmarkoncurrentpage{highlighted-node-\number\value{tikzhighlightnode}}%
-       \noexpand\node[inner sep=1.0pt,fill=#1,#3,fit=(highlighted-node-\number\value{tikzhighlightnode})]{};%
-      \noexpand\fi
-      \noexpand\end{tikzpicture}%
+\NewDocumentCommand{\hilite}{ O{magenta!60} m O{rectangle} }%
+  {%
+    \stepcounter{tikzhighlightnode}%
+    \tikzmarknode{highlighted-node-\number\value{tikzhighlightnode}}{#2}%
+    \edef\temp{%
+      \noexpand\AddToShipoutPictureBG{%
+        \noexpand\begin{tikzpicture}[overlay,remember picture]%
+        \noexpand\iftikzmarkoncurrentpage{highlighted-node-\number\value{tikzhighlightnode}}%
+         \noexpand\node[inner sep=1.0pt,fill=#1,#3,fit=(highlighted-node-\number\value{tikzhighlightnode})]{};%
+        \noexpand\fi
+        \noexpand\end{tikzpicture}%
+      }%
     }%
+    \temp%
   }%
-  \temp%
-}%
 %    \end{macrocode}
 %
-% A simplified command for importing images.
+% A simplified command for importing images.\newline
+% See \url{https://tex.stackexchange.com/a/614478/218142}.
 %
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandistudentpkg}{mandistudent} Slightly modified \refCom{image}}
 %    \begin{macrocode}
-\NewDocumentCommand{\image}{ O{scale=1} m m m }{%
-  \begin{figure}[ht!]
-    \begin{center}%
+\NewDocumentCommand{\image}{ O{scale=1} m m m }%
+  {%
+    \par
+    \begin{figure}[ht!]
+      \centering%
       \includegraphics[#1]{#2}%
-    \end{center}%
-    \caption{#3}%
-    \label{#4}%
-  \end{figure}%
-}%
+      \caption{#3}%
+      \label{#4}%
+    \end{figure}%
+    \par
+  }%
 %    \end{macrocode}
 %
 % Intelligent commands for typesetting vector and tensor symbols and 
@@ -1525,86 +1726,104 @@
 % coordinate-free.
 %
 %    \begin{macrocode}
-\NewDocumentCommand{\veccomp}{ s m }{%
-  % Consider renaming this to \vectorsym.
-  \IfBooleanTF{#1}
+\NewDocumentCommand{\veccomp}{ s m }%
   {%
-    \symnormal{#2}%
+    % Consider renaming this to \vectorsym.
+    \IfBooleanTF{#1}
+      {%
+        \symnormal{#2}%
+      }%
+      {%
+        \symbfit{#2}%
+      }%
   }%
+\NewDocumentCommand{\tencomp}{ s m }%
   {%
-    \symbfit{#2}%
+    % Consider renaming this to \tensororsym.
+    \IfBooleanTF{#1}%
+      {%
+        \symsfit{#2}%
+      }%
+      {%
+        \symbfsfit{#2}%
+      }%
   }%
-}%
-\NewDocumentCommand{\tencomp}{ s m }{%
-  % Consider renaming this to \tensororsym.
-  \IfBooleanTF{#1}
-  {%
-    \symsfit{#2}%
-  }%
-  {%
-    \symbfsfit{#2}
-  }%
-}%
 %    \end{macrocode}
 %
 % Command to typeset tensor valence.
 %
 %    \begin{macrocode}
-\NewDocumentCommand{\valence}{ s m m }{%
-  \IfBooleanTF{#1}
-    {(#2,#3)}
-    {\binom{#2}{#3}}
-}%
+\NewDocumentCommand{\valence}{ s m m }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        (#2,#3)%
+      }%
+      {%
+        \binom{#2}{#3}%
+      }%
+  }%
 %    \end{macrocode}
 %
 % Intelligent notation for contraction on pairs of slots.
 %
 %    \begin{macrocode}
-\NewDocumentCommand{\contraction}{ s m }{%
-  \IfBooleanTF{#1}
-  {\mathsf{C}}%
-  {\symbb{C}}%
-  _{#2}
-}%
+\NewDocumentCommand{\contraction}{ s m }%
+  {%
+    \IfBooleanTF{#1}
+      {%
+        \mathsf{C}%
+      }%
+      {%
+        \symbb{C}%
+      }%
+    _{#2}
+  }%
 %    \end{macrocode}
 %
 % Intelligent slot command for coordinate-free tensor notation.
 %
 %    \begin{macrocode}
-\NewDocumentCommand{\slot}{ s d[] }{%
-  % d[] must be used because of the way consecutive optional
-  %  arguments are handled. See xparse docs for details.
-  \IfBooleanTF{#1}
+\NewDocumentCommand{\slot}{ s d[] }%
   {%
-    \IfValueTF{#2}
-    {% Insert a vector, but don't show the slot.
-      \smash{\makebox[1.5em]{\ensuremath{#2}}}
+    % d[] must be used because of the way consecutive optional
+    %  arguments are handled. See xparse docs for details.
+    \IfBooleanTF{#1}
+    {%
+      \IfValueTF{#2}
+      {% Insert a vector, but don't show the slot.
+        \smash{\makebox[1.5em]{\ensuremath{#2}}}
+      }%
+      {% No vector, no slot.
+        \smash{\makebox[1.5em]{\ensuremath{}}}
+      }%
     }%
-    {% No vector, no slot.
-      \smash{\makebox[1.5em]{\ensuremath{}}}
+    {%
+      \IfValueTF{#2}
+        {% Insert a vector and show the slot.
+          \underline{\smash{\makebox[1.5em]{\ensuremath{#2}}}}
+        }%
+        {% No vector; just show the slot.
+          \underline{\smash{\makebox[1.5em]{\ensuremath{}}}}
+        }%
     }%
   }%
-  {%
-    \IfValueTF{#2}
-    {% Insert a vector and show the slot.
-      \underline{\smash{\makebox[1.5em]{\ensuremath{#2}}}}
-    }%
-    {% No vector; just show the slot.
-      \underline{\smash{\makebox[1.5em]{\ensuremath{}}}}
-    }%
-  }%
-}%
 %    \end{macrocode}
 %
 % Intelligent differential (exterior derivative) operator.
 %
 %    \begin{macrocode}
-\NewDocumentCommand{\diff}{ s }{%
-  \mathop{}\!
-  \IfBooleanTF{#1}
-  {\symbfsfup{d}}%
-  {\symsfup{d}}%
-}%
+\NewDocumentCommand{\df}{ s }%
+  {%
+    \mathop{}\!%
+    \IfBooleanTF{#1}%
+      {%
+        \symbfsfup{d}%
+      }%
+      {%
+        \symsfup{d}%
+      }%
+  }%
 %    \end{macrocode}
 %
 % Here is a clever way to color digits in program listsings thanks to
@@ -1633,144 +1852,206 @@
 \definecolor{gspeach}      {rgb}{1.00,0.90,0.71} % peach
 \definecolor{gspearl}      {rgb}{0.94,0.92,0.84} % pearl
 \definecolor{gsplum}       {rgb}{0.74,0.46,0.70} % plum
-\lstdefinestyle{vpython}{%                       % style for listings
-  backgroundcolor=\color{gsbggray},%             % background color
-  basicstyle=\colordigits\footnotesize,%         % default style
-  breakatwhitespace=true%                        % break at whitespace
-  breaklines=true,%                              % break long lines
-  captionpos=b,%                                 % position caption
-  classoffset=1,%                                % STILL DON'T UNDERSTAND THIS
-  commentstyle=\color{gsgray},%                  % font for comments
-  deletekeywords={print},%                       % delete keywords from the given language
-  emph={self,cls, at classmethod, at property},%       % words to emphasize
-  emphstyle=\color{gsorange}\itshape,%           % font for emphasis
-  escapeinside={(*@}{@*)},%                      % add LaTeX within your code
-  frame=tb,%                                     % frame style
-  framerule=2.0pt,%                              % frame thickness
-  framexleftmargin=5pt,%                         % extra frame left margin
-  %identifierstyle=\sffamily,%                    % style for identifiers
-  keywordstyle=\gsfontfamily\color{gsplum},%     % color for keywords
-  language=Python,%                              % select language
-  linewidth=\linewidth,%                         % width of listings
-  morekeywords={%                                % VPython/GlowScript specific keywords
-    __future__,abs,acos,align,ambient,angle,append,append_to_caption,%
-    append_to_title,arange,arrow,asin,astuple,atan,atan2,attach_arrow,%
-    attach_trail,autoscale,axis,background,billboard,bind,black,blue,border,%
-    bounding_box,box,bumpaxis,bumpmap,bumpmaps,camera,canvas,caption,capture,%
-    ceil,center,clear,clear_trail,click,clone,CoffeeScript,coils,color,combin,%
-    comp,compound,cone,convex,cos,cross,curve,cyan,cylinder,data,degrees,del,%
-    delete,depth,descender,diff_angle,digits,division,dot,draw_complete,%
-    ellipsoid,emissive,end_face_color,equals,explog,extrusion,faces,factorial,%
-    False,floor,follow,font,format,forward,fov,frame,gcurve,gdisplay,gdots,%
-    get_library,get_selected,ghbars,global,GlowScript,graph,graphs,green,gvbars,%
-    hat,headlength,headwidth,height,helix,hsv_to_rgb,index,interval,keydown,%
-    keyup,label,length,lights,line,linecolor,linewidth,logx,logy,lower_left,%
-    lower_right,mag,mag2,magenta,make_trail,marker_color,markers,material,%
-    max,min,mouse,mousedown,mousemove,mouseup,newball,norm,normal,objects,%
-    offset,one,opacity,orange,origin,path,pause,pi,pixel_to_world,pixels,plot,%
-    points,pos,pow,pps,print,print_function,print_options,proj,purple,pyramid,%
-    quad,radians,radius,random,rate,ray,read_local_file,readonly,red,redraw,%
-    retain,rgb_to_hsv,ring,rotate,round,scene,scroll,shaftwidth,shape,shapes,%
-    shininess,show_end_face,show_start_face,sign,sin,size,size_units,sleep,%
-    smooth,space,sphere,sqrt,start,start_face_color,stop,tan,text,textpos,%
-    texture,textures,thickness,title,trail_color,trail_object,trail_radius,%
-    trail_type,triangle,trigger,True,twist,unbind,up,upper_left,upper_right,%
-    userpan,userspin,userzoom,vec,vector,vertex,vertical_spacing,visible,%
-    visual,vpython,VPython,waitfor,white,width,world,xtitle,yellow,yoffset,%
-    ytitle%
-  },%
-  morekeywords={print,None,TypeError},%      % additional keywords
-  morestring=[b]{"""},%                      % treat triple quotes as strings
-  numbers=left,%                             % where to put line numbers
-  numbersep=10pt,%                           % how far line numbers are from code
-  numberstyle=\bfseries\tiny,%               % set to 'none' for no line numbers
-  showstringspaces=false,%                   % show spaces in strings
-  showtabs=false,%                           % show tabs within strings
-  stringstyle=\gsfontfamily\color{gsgreen},% % color for strings
-  upquote=true,%                             % how to typeset quotes
-}%
+\lstdefinestyle{vpython}%
+  {%                                            % style for listings
+    backgroundcolor=\color{gsbggray},%          % background color
+    basicstyle=\colordigits\footnotesize,%      % default style
+    breakatwhitespace=true%                     % break at whitespace
+    breaklines=true,%                           % break long lines
+    captionpos=b,%                              % position caption
+    classoffset=1,%                             % STILL DON'T UNDERSTAND THIS
+    commentstyle=\color{gsgray},%               % font for comments
+    deletekeywords={print},%                    % delete keywords from the given language
+    emph={self,cls, at classmethod, at property},%    % words to emphasize
+    emphstyle=\color{gsorange}\itshape,%        % font for emphasis
+    escapeinside={(*@}{@*)},%                    % add LaTeX within your code
+    frame=tb,%                                  % frame style
+    framerule=2.0pt,%                           % frame thickness
+    framexleftmargin=5pt,%                      % extra frame left margin
+    %identifierstyle=\sffamily,%                % style for identifiers
+    keywordstyle=\gsfontfamily\color{gsplum},%  % color for keywords
+    language=Python,%                           % select language
+    linewidth=\linewidth,%                      % width of listings
+    morekeywords={%                             % VPython/Web VPython specific keywords
+      __future__,abs,acos,align,ambient,angle,append,append_to_caption,%
+      append_to_title,arange,arrow,asin,astuple,atan,atan2,attach_arrow,%
+      attach_trail,autoscale,axis,background,billboard,bind,black,blue,border,%
+      bounding_box,box,bumpaxis,bumpmap,bumpmaps,camera,canvas,caption,capture,%
+      ceil,center,clear,clear_trail,click,clone,CoffeeScript,coils,color,combin,%
+      comp,compound,cone,convex,cos,cross,curve,cyan,cylinder,data,degrees,del,%
+      delete,depth,descender,diff_angle,digits,division,dot,draw_complete,%
+      ellipsoid,emissive,end_face_color,equals,explog,extrusion,faces,factorial,%
+      False,floor,follow,font,format,forward,fov,frame,gcurve,gdisplay,gdots,%
+      get_library,get_selected,ghbars,global,GlowScript,graph,graphs,green,gvbars,%
+      hat,headlength,headwidth,height,helix,hsv_to_rgb,index,interval,keydown,%
+      keyup,label,length,lights,line,linecolor,linewidth,logx,logy,lower_left,%
+      lower_right,mag,mag2,magenta,make_trail,marker_color,markers,material,%
+      max,min,mouse,mousedown,mousemove,mouseup,newball,norm,normal,objects,%
+      offset,one,opacity,orange,origin,path,pause,pi,pixel_to_world,pixels,plot,%
+      points,pos,pow,pps,print,print_function,print_options,proj,purple,pyramid,%
+      quad,radians,radius,random,rate,ray,read_local_file,readonly,red,redraw,%
+      retain,rgb_to_hsv,ring,rotate,round,scene,scroll,shaftwidth,shape,shapes,%
+      shininess,show_end_face,show_start_face,sign,sin,size,size_units,sleep,%
+      smooth,space,sphere,sqrt,start,start_face_color,stop,tan,text,textpos,%
+      texture,textures,thickness,title,trail_color,trail_object,trail_radius,%
+      trail_type,triangle,trigger,True,twist,unbind,up,upper_left,upper_right,%
+      userpan,userspin,userzoom,vec,vector,vertex,vertical_spacing,visible,%
+      visual,vpython,VPython,waitfor,WebVPython,white,width,world,xtitle,%
+      yellow,yoffset,ytitle%
+    },%
+    morekeywords={print,None,TypeError},%      % additional keywords
+    morestring=[b]{"""},%                      % treat triple quotes as strings
+    numbers=left,%                             % where to put line numbers
+    numbersep=10pt,%                           % how far line numbers are from code
+    numberstyle=\bfseries\tiny,%               % set to 'none' for no line numbers
+    showstringspaces=false,%                   % show spaces in strings
+    showtabs=false,%                           % show tabs within strings
+    stringstyle=\gsfontfamily\color{gsgreen},% % color for strings
+    upquote=true,%                             % how to typeset quotes
+  }%
 %    \end{macrocode}
 %
-% Introduce a new, more intelligent \refEnv{glowscriptblock} environment.
+% Introduce a new, more intelligent \refEnv{webvpythonblock} environment.\newline
+% See \url{https://tex.stackexchange.com/a/232208/218142}.
 %
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandistudentpkg}{mandistudent} URLs fixed in \refEnv{webvpythonblock}}
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandistudentpkg}{mandistudent} \refEnv{webvpythonblock} now automatically
+%    generates QR codes for program listings}
 %    \begin{macrocode}
-\NewTCBListing[auto counter,list inside=gsprogs]{glowscriptblock}
-  { O{} D(){glowscript.org} m }{%
-  breakable,%
-  center,%
-  code = \newpage,%
-  %derivpeach,%
-  enhanced,%
-  hyperurl interior = https://#2,%
-  label = {gs:\thetcbcounter},%
-  left = 8mm,%
-  list entry = \thetcbcounter~~~~~#3,%
-  listing only,%
-  listing style = vpython,%
-  nameref = {#3},%
-  title = \texttt{GlowScript} Program \thetcbcounter: #3,%
-  width = 0.9\textwidth,%
-  {#1},
-}%
+\AtBeginEnvironment{webvpythonblock}{\catcode`\#=12}
+\AtEndEnvironment{webvpythonblock}{\catcode`\#=6}
+\NewTCBListing[auto counter,list inside=gsprogs]{webvpythonblock}{ O{} D(){webvpython.org} m }%
+  {%
+    breakable,%
+    center,%
+    code = \newpage,%
+    %derivpeach,%
+    enhanced,%
+    hyperurl interior = https://#2,%
+    label = {gs:\thetcbcounter},%
+    left = 8mm,%
+    list entry = \thetcbcounter~~~~~#3,%
+    listing only,%
+    listing style = vpython,%
+    nameref = {#3},%
+    title = \begin{minipage}{1.5cm}%
+              \protect\qrcode*{https://#2}%
+            \end{minipage}\hspace{5mm}%
+            \begin{minipage}{0.7\textwidth}%
+              \texttt{Web VPython} Program \thetcbcounter: #3%
+            \end{minipage},%
+    width = 0.9\textwidth,%
+    {#1},
+  }%
 %    \end{macrocode}
 %
-% A new command for generating a list of \GlowScript\ programs.
+% Here is a variant that omits the QR code.
 %
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandistudentpkg}{mandistudent} \refEnv{webvpythonblock*} is a variant
+%    of \refEnv{webvpythonblock} that omits the QR code}
 %    \begin{macrocode}
-\NewDocumentCommand{\listofglowscriptprograms}{}{\tcblistof[\section*]{gsprogs}
-  {List of \texttt{GlowScript} Programs}}%
+\AtBeginEnvironment{webvpythonblock*}{\catcode`\#=12}
+\AtEndEnvironment{webvpythonblock*}{\catcode`\#=6}
+\NewTCBListing[use counter from=webvpythonblock,list inside=gsprogs]
+  {webvpythonblock*}{ O{} D(){webvpython.org} m }%
+    {%
+      breakable,%
+      center,%
+      code = \newpage,%
+      %derivpeach,%
+      enhanced,%
+      hyperurl interior = https://#2,%
+      label = {gs:\thetcbcounter},%
+      left = 8mm,%
+      list entry = \thetcbcounter~~~~~#3,%
+      listing only,%
+      listing style = vpython,%
+      nameref = {#3},%
+      title =   \texttt{Web VPython} Program \thetcbcounter: #3,%
+      width = 0.9\textwidth,%
+      {#1},
+    }%
 %    \end{macrocode}
 %
-% Introduce a new, more intelligent \refCom{vpythonfile} command.
+% A new command for generating a list of \WebVPython\ programs.
 %
 %    \begin{macrocode}
-\NewTCBInputListing[auto counter,list inside=vpprogs]{\vpythonfile}
-  { O{} m m }{%
-  breakable,%
-  center,%
-  code = \newpage,%
-  %derivgray,%
-  enhanced,%
-  hyperurl interior = https://,%
-  label = {vp:\thetcbcounter},%
-  left = 8mm,%
-  list entry = \thetcbcounter~~~~~#3,%
-  listing file = {#2},%
-  listing only,%
-  listing style = vpython,%
-  nameref = {#3},%
-  title = \texttt{VPython} Program \thetcbcounter: #3,%
-  width = 0.9\textwidth,%
-  {#1},%
-}%
+\NewDocumentCommand{\listofwebvpythonprograms}{}%
+  {%
+    \tcblistof[\section*]{gsprogs}{List of \texttt{Web VPython} Programs}%
+  }%
 %    \end{macrocode}
 %
+% Introduce a new, more intelligent \refCom{vpythonfile} command.\newline
+% See \url{https://tex.stackexchange.com/q/616205/218142}.
+% 
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandistudentpkg}{mandistudent} URLs fixed in \refCom{vpythonfile}}
+% \changes{v3.1.0}{2022-01-27}
+%   {\linktoplace{sec:mandistudentpkg}{mandistudent} Default URL for \refCom{vpythonfile}
+%    is now \vpurl}
+%    \begin{macrocode}
+\newcommand*{\vpythonfile}{\catcode`\#=12 \vpythonfile at auxA}
+\NewDocumentCommand{\vpythonfile at auxA}{ O{} D(){vpython.org} m m }%
+  {%
+    \vpythonfile at auxB[#1](#2){#3}{#4}%
+    \catcode`\#=6
+  }%
+\NewTCBInputListing[auto counter,list inside=vpprogs]
+  {\vpythonfile at auxB}{ O{} D(){vpython.org} m m }%
+    {%
+      breakable,%
+      center,%
+      code = \newpage,%
+      %derivgray,%
+      enhanced,%
+      hyperurl interior = https://#2,%
+      label = {vp:\thetcbcounter},%
+      left = 8mm,%
+      list entry = \thetcbcounter~~~~~#4,%
+      listing file = {#3},%
+      listing only,%
+      listing style = vpython,%
+      nameref = {#4},%
+      title = \texttt{VPython} Program \thetcbcounter: #4,%
+      width = 0.9\textwidth,%
+      {#1},%
+    }%
+%    \end{macrocode}
+%
 %  A new command for generating a list of \VPython\ programs.
 %
 %    \begin{macrocode}
-\NewDocumentCommand{\listofvpythonprograms}{}{\tcblistof[\section*]{vpprogs}
-  {List of \texttt{VPython} Programs}}%
+\NewDocumentCommand{\listofvpythonprograms}{}%
+  {%
+    \tcblistof[\section*]{vpprogs}{List of \texttt{VPython} Programs}%
+  }%
 %    \end{macrocode}
 %
-% Introduce a new \refCom{glowscriptinline} command.
+% Introduce a new \refCom{webvpythoninline} command.
 %
 %    \begin{macrocode}
-\DeclareTotalTCBox{\glowscriptinline}{ m }{%
-  bottom = 0pt,%
-  bottomrule = 0.0mm,%
-  boxsep = 1.0mm,%
-  colback = gsbggray,%
-  colframe = gsbggray,%
-  left = 0pt,%
-  leftrule = 0.0mm,%
-  nobeforeafter,%
-  right = 0pt,%
-  rightrule = 0.0mm,%
-  sharp corners,%
-  tcbox raise base,%
-  top = 0pt,%
-  toprule = 0.0mm,%
-}{\lstinline[style = vpython]{#1}}%
+\DeclareTotalTCBox{\webvpythoninline}{ m }%
+  {%
+    bottom = 0pt,%
+    bottomrule = 0.0mm,%
+    boxsep = 1.0mm,%
+    colback = gsbggray,%
+    colframe = gsbggray,%
+    left = 0pt,%
+    leftrule = 0.0mm,%
+    nobeforeafter,%
+    right = 0pt,%
+    rightrule = 0.0mm,%
+    sharp corners,%
+    tcbox raise base,%
+    top = 0pt,%
+    toprule = 0.0mm,%
+  }%
+  {\lstinline[style = vpython]{#1}}%
 %    \end{macrocode}
 %
 % Define \refCom{vpythoninline}, a semantic alias for \VPython\ 
@@ -1777,7 +2058,7 @@
 % in-line listings.
 %
 %    \begin{macrocode}
-\NewDocumentCommand{\vpythoninline}{}{\glowscriptinline}%
+\NewDocumentCommand{\vpythoninline}{}{\webvpythoninline}%
 %    \end{macrocode}
 %
 % \restoregeometry

Modified: trunk/Master/texmf-dist/tex/latex/mandi/mandi.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/mandi/mandi.sty	2022-01-27 21:41:00 UTC (rev 61763)
+++ trunk/Master/texmf-dist/tex/latex/mandi/mandi.sty	2022-01-27 21:41:19 UTC (rev 61764)
@@ -6,7 +6,7 @@
 %%
 %% mandi.dtx  (with options: `package')
 %% 
-%%  Copyright (C) 2021 by Paul J. Heafner <heafnerj at gmail.com>
+%%  Copyright (C) 2021,2022 by Paul J. Heafner <heafnerj at gmail.com>
 %%  ---------------------------------------------------------------------------
 %%  This  work may be  distributed and/or modified  under the conditions of the
 %%  LaTeX Project Public  License, either  version 1.3  of this  license or (at
@@ -29,22 +29,25 @@
 %%  and includes the derived files  mandi.sty
 %%                                  mandistudent.sty
 %%                                  mandiexp.sty
-%%                                  vdemo.py
+%%                                  vdemo.py (not needed)
 %%  ---------------------------------------------------------------------------
 %% 
-\def\mandi at version{3.0.0}
-\def\mandi at date{2021-08-22}
+\def\mandi at version{3.1.0}
+\def\mandi at date{2022-01-27}
 \NeedsTeXFormat{LaTeX2e}[2020-02-02]
-\DeclareRelease{v3.0.0}{2021-08-22}{mandi.sty}
+\DeclareRelease{v3.1.0}{2022-01-27}{mandi.sty}
 \DeclareCurrentRelease{v\mandi at version}{\mandi at date}
 \ProvidesPackage{mandi}
   [\mandi at date\space v\mandi at version\space Macros for physical quantities]
 \newcommand*{\mandiversion}{v\mandi at version\space dated \mandi at date}
-\RequirePackage{pgfopts}      % needed for key-value interface
-\RequirePackage{array}        % needed for \checkquantity and \checkconstant
-\RequirePackage{iftex}        % needed for requiring LuaLaTeX
-\RequirePackage{unicode-math} % needed for Unicode support
-\RequireLuaTeX                % require this engine
+\RequirePackage{pgfopts}        % needed for key-value interface
+\RequirePackage{array}          % needed for \checkquantity and \checkconstant
+\RequirePackage{iftex}          % needed for requiring LuaLaTeX
+\RequirePackage{unicode-math}   % needed for Unicode support
+\IfFormatAtLeastTF {2020-10-01} % load xparse if necessary
+  {}%
+  {\RequirePackage{xparse}}%
+\RequireLuaTeX                  % require this engine
 \newcommand*{\mandi at selectunits}{}
 \newcommand*{\mandi at selectprecision}{}
 \newcommand*{\mandi at selectapproximate}[2]{#1}    % really \@firstoftwo
@@ -85,6 +88,10 @@
   units/alternate/.style={/mandi/options/buffered at units=alternate},%
   units/base/.style={/mandi/options/buffered at units=base},%
   units/derived/.style={/mandi/options/buffered at units=derived},%
+  .unknown/.code={%
+    \typeout{}%
+    \typeout{mandi: You used unknown option '\pgfkeyscurrentname'.}%
+  },%
 }%
 \ProcessPgfPackageOptions{/mandi/options}
 \typeout{}%
@@ -104,14 +111,16 @@
   \typeout{}%
 }%
 \mandi at do@setup
-\NewDocumentCommand{\mandisetup}{ m }{%
-  \IfValueT{#1}{%
-    \pgfqkeys{/mandi/options}{#1}
-    \typeout{}%
-    \typeout{mandi: mandisetup options...}
-    \mandi at do@setup
+\NewDocumentCommand{\mandisetup}{ m }%
+  {%
+    \IfValueT{#1}%
+      {%
+        \pgfqkeys{/mandi/options}{#1}
+        \typeout{}%
+        \typeout{mandi: mandisetup options...}
+        \mandi at do@setup
+      }%
   }%
-}%
 \NewDocumentCommand{\per}{}{/}
 \NewDocumentCommand{\usk}{}{\cdot}
 \NewDocumentCommand{\unit}{ m m }{{#1}{\,#2}}
@@ -130,7 +139,7 @@
 \NewDocumentCommand{\kev}{}{\kiloelectronvolt}
 \NewDocumentCommand{\kiloelectronvolt}{}{\symup{keV}}
 \NewDocumentCommand{\kilogram}{}{\symup{kg}}
-\NewDocumentCommand{\lightspeed}{}{\symup{c}}
+\NewDocumentCommand{\lightspeed}{}{\!\symup{c}}
 \NewDocumentCommand{\megaelectronvolt}{}{\symup{MeV}}
 \NewDocumentCommand{\meter}{}{\symup{m}}
 \NewDocumentCommand{\metre}{}{\meter}
@@ -159,134 +168,134 @@
 \NewDocumentCommand{\timestento}{ m }{\times\tento{#1}}
 \NewDocumentCommand{\xtento}{ m }{\times\tento{#1}}
 \ExplSyntaxOn
-\cs_new:Npn \mandi_newscalarquantity #1#2#3#4
-{%
-  \cs_new:cpn {#1} ##1 {\unit{##1}{\mandi at selectunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {#1value} ##1 {##1}%
-  \cs_new:cpn {#1baseunits} ##1 {\unit{##1}{\mandi at selectbaseunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {#1derivedunits} ##1 {\unit{##1}{\mandi at selectderivedunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {#1alternateunits} ##1 {\unit{##1}{\mandi at selectalternateunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {#1onlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}%
-  \cs_new:cpn {#1onlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}%
-  \cs_new:cpn {#1onlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}%
-}%
-\NewDocumentCommand{\newscalarquantity}{ m m O{#2} O{#2} }%
-{%
-  \mandi_newscalarquantity { #1 }{ #2 }{ #3 }{ #4 }%
-}%
+\cs_new:Npn \__mandi_newscalarquantity:nnnn #1#2#3#4
+  {
+    \cs_new:cpn {#1} ##1 {\unit{##1}{\mandi at selectunits{#2}{#3}{#4}}}
+    \cs_new:cpn {#1value} ##1 {##1}
+    \cs_new:cpn {#1baseunits} ##1 {\unit{##1}{\mandi at selectbaseunits{#2}{#3}{#4}}}
+    \cs_new:cpn {#1derivedunits} ##1 {\unit{##1}{\mandi at selectderivedunits{#2}{#3}{#4}}}
+    \cs_new:cpn {#1alternateunits} ##1 {\unit{##1}{\mandi at selectalternateunits{#2}{#3}{#4}}}
+    \cs_new:cpn {#1onlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}
+    \cs_new:cpn {#1onlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}
+    \cs_new:cpn {#1onlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}
+  }
+\NewDocumentCommand{\newscalarquantity}{ m m O{#2} O{#2} }
+  {
+    \__mandi_newscalarquantity:nnnn { #1 }{ #2 }{ #3 }{ #4 }
+  }
 \ExplSyntaxOff
 \ExplSyntaxOn
-\cs_new:Npn \mandi_renewscalarquantity #1#2#3#4
-{%
-  \cs_set:cpn {#1} ##1 {\unit{##1}{\mandi at selectunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {#1value} ##1 {##1}%
-  \cs_set:cpn {#1baseunits} ##1 {\unit{##1}{\mandi at selectbaseunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {#1derivedunits} ##1 {\unit{##1}{\mandi at selectderivedunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {#1alternateunits} ##1 {\unit{##1}{\mandi at selectalternateunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {#1onlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}%
-  \cs_set:cpn {#1onlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}%
-  \cs_set:cpn {#1onlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}%
-}%
-\NewDocumentCommand{\renewscalarquantity}{ m m O{#2} O{#2} }%
-{%
-  \mandi_renewscalarquantity { #1 }{ #2 }{ #3 }{ #4 }%
-}%
+\cs_new:Npn \__mandi_renewscalarquantity:nnnn #1#2#3#4
+  {
+    \cs_set:cpn {#1} ##1 {\unit{##1}{\mandi at selectunits{#2}{#3}{#4}}}
+    \cs_set:cpn {#1value} ##1 {##1}
+    \cs_set:cpn {#1baseunits} ##1 {\unit{##1}{\mandi at selectbaseunits{#2}{#3}{#4}}}
+    \cs_set:cpn {#1derivedunits} ##1 {\unit{##1}{\mandi at selectderivedunits{#2}{#3}{#4}}}
+    \cs_set:cpn {#1alternateunits} ##1 {\unit{##1}{\mandi at selectalternateunits{#2}{#3}{#4}}}
+    \cs_set:cpn {#1onlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}
+    \cs_set:cpn {#1onlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}
+    \cs_set:cpn {#1onlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}
+  }
+\NewDocumentCommand{\renewscalarquantity}{ m m O{#2} O{#2} }
+  {
+    \__mandi_renewscalarquantity:nnnn { #1 }{ #2 }{ #3 }{ #4 }
+  }
 \ExplSyntaxOff
 \ExplSyntaxOn
-\cs_new:Npn \mandi_newvectorquantity #1#2#3#4
-{%
-  \mandi_newscalarquantity { #1 }{ #2 }{ #3 }{ #4 }%
-  \cs_new:cpn {vector#1} ##1 {\unit{\mivector{##1}}{\mandi at selectunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {#1vector} ##1 {\unit{\mivector{##1}}{\mandi at selectunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {vector#1value} ##1 {\mivector{##1}}%
-  \cs_new:cpn {#1vectorvalue} ##1 {\mivector{##1}}%
-  \cs_new:cpn {vector#1baseunits} ##1 {\unit{\mivector{##1}}{\mandi at selectbaseunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {#1vectorbaseunits} ##1 {\unit{\mivector{##1}}{\mandi at selectbaseunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {vector#1derivedunits} ##1 {\unit{\mivector{##1}}{\mandi at selectderivedunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {#1vectorderivedunits} ##1 {\unit{\mivector{##1}}{\mandi at selectderivedunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {vector#1alternateunits} ##1 {\unit{\mivector{##1}}{\mandi at selectalternateunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {#1vectoralternateunits} ##1 {\unit{\mivector{##1}}{\mandi at selectalternateunits{#2}{#3}{#4}}}%
-  \cs_new:cpn {vector#1onlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}%
-  \cs_new:cpn {#1vectoronlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}%
-  \cs_new:cpn {vector#1onlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}%
-  \cs_new:cpn {#1vectoronlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}%
-  \cs_new:cpn {vector#1onlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}%
-  \cs_new:cpn {#1vectoronlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}%
-}%
-\NewDocumentCommand{\newvectorquantity}{ m m O{#2} O{#2} }%
-{%
-  \mandi_newvectorquantity { #1 }{ #2 }{ #3 }{ #4 }%
-}%
+\cs_new:Npn \__mandi_newvectorquantity:nnnn #1#2#3#4
+  {
+    \__mandi_newscalarquantity:nnnn { #1 }{ #2 }{ #3 }{ #4 }
+    \cs_new:cpn {vector#1} ##1 {\unit{\mivector{##1}}{\mandi at selectunits{#2}{#3}{#4}}}
+    \cs_new:cpn {#1vector} ##1 {\unit{\mivector{##1}}{\mandi at selectunits{#2}{#3}{#4}}}
+    \cs_new:cpn {vector#1value} ##1 {\mivector{##1}}
+    \cs_new:cpn {#1vectorvalue} ##1 {\mivector{##1}}
+    \cs_new:cpn {vector#1baseunits} ##1 {\unit{\mivector{##1}}{\mandi at selectbaseunits{#2}{#3}{#4}}}
+    \cs_new:cpn {#1vectorbaseunits} ##1 {\unit{\mivector{##1}}{\mandi at selectbaseunits{#2}{#3}{#4}}}
+    \cs_new:cpn {vector#1derivedunits} ##1 {\unit{\mivector{##1}}{\mandi at selectderivedunits{#2}{#3}{#4}}}
+    \cs_new:cpn {#1vectorderivedunits} ##1 {\unit{\mivector{##1}}{\mandi at selectderivedunits{#2}{#3}{#4}}}
+    \cs_new:cpn {vector#1alternateunits} ##1 {\unit{\mivector{##1}}{\mandi at selectalternateunits{#2}{#3}{#4}}}
+    \cs_new:cpn {#1vectoralternateunits} ##1 {\unit{\mivector{##1}}{\mandi at selectalternateunits{#2}{#3}{#4}}}
+    \cs_new:cpn {vector#1onlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}
+    \cs_new:cpn {#1vectoronlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}
+    \cs_new:cpn {vector#1onlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}
+    \cs_new:cpn {#1vectoronlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}
+    \cs_new:cpn {vector#1onlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}
+    \cs_new:cpn {#1vectoronlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}
+  }
+\NewDocumentCommand{\newvectorquantity}{ m m O{#2} O{#2} }
+  {
+    \__mandi_newvectorquantity:nnnn { #1 }{ #2 }{ #3 }{ #4 }
+  }
 \ExplSyntaxOff
 \ExplSyntaxOn
-\cs_new:Npn \mandi_renewvectorquantity #1#2#3#4
-{%
-  \mandi_renewscalarquantity { #1 }{ #2 }{ #3 }{ #4 }%
-  \cs_set:cpn {vector#1} ##1 {\unit{\mivector{##1}}{\mandi at selectunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {#1vector} ##1 {\unit{\mivector{##1}}{\mandi at selectunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {vector#1value} ##1 {\mivector{##1}}%
-  \cs_set:cpn {#1vectorvalue} ##1 {\mivector{##1}}%
-  \cs_set:cpn {vector#1baseunits} ##1 {\unit{\mivector{##1}}{\mandi at selectbaseunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {#1vectorbaseunits} ##1 {\unit{\mivector{##1}}{\mandi at selectbaseunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {vector#1derivedunits} ##1 {\unit{\mivector{##1}}{\mandi at selectderivedunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {#1vectorderivedunits} ##1 {\unit{\mivector{##1}}{\mandi at selectderivedunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {vector#1alternateunits} ##1 {\unit{\mivector{##1}}{\mandi at selectalternateunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {#1vectoralternateunits} ##1 {\unit{\mivector{##1}}{\mandi at selectalternateunits{#2}{#3}{#4}}}%
-  \cs_set:cpn {vector#1onlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}%
-  \cs_set:cpn {#1vectoronlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}%
-  \cs_set:cpn {vector#1onlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}%
-  \cs_set:cpn {#1vectoronlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}%
-  \cs_set:cpn {vector#1onlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}%
-  \cs_set:cpn {#1vectoronlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}%
-}%
-\NewDocumentCommand{\renewvectorquantity}{ m m O{#2} O{#2} }%
-{%
-  \mandi_renewvectorquantity { #1 }{ #2 }{ #3 }{ #4 }%
-}%
+\cs_new:Npn \__mandi_renewvectorquantity:nnnn #1#2#3#4
+  {
+    \__mandi_renewscalarquantity:nnnn { #1 }{ #2 }{ #3 }{ #4 }
+    \cs_set:cpn {vector#1} ##1 {\unit{\mivector{##1}}{\mandi at selectunits{#2}{#3}{#4}}}
+    \cs_set:cpn {#1vector} ##1 {\unit{\mivector{##1}}{\mandi at selectunits{#2}{#3}{#4}}}
+    \cs_set:cpn {vector#1value} ##1 {\mivector{##1}}
+    \cs_set:cpn {#1vectorvalue} ##1 {\mivector{##1}}
+    \cs_set:cpn {vector#1baseunits} ##1 {\unit{\mivector{##1}}{\mandi at selectbaseunits{#2}{#3}{#4}}}
+    \cs_set:cpn {#1vectorbaseunits} ##1 {\unit{\mivector{##1}}{\mandi at selectbaseunits{#2}{#3}{#4}}}
+    \cs_set:cpn {vector#1derivedunits} ##1 {\unit{\mivector{##1}}{\mandi at selectderivedunits{#2}{#3}{#4}}}
+    \cs_set:cpn {#1vectorderivedunits} ##1 {\unit{\mivector{##1}}{\mandi at selectderivedunits{#2}{#3}{#4}}}
+    \cs_set:cpn {vector#1alternateunits} ##1 {\unit{\mivector{##1}}{\mandi at selectalternateunits{#2}{#3}{#4}}}
+    \cs_set:cpn {#1vectoralternateunits} ##1 {\unit{\mivector{##1}}{\mandi at selectalternateunits{#2}{#3}{#4}}}
+    \cs_set:cpn {vector#1onlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}
+    \cs_set:cpn {#1vectoronlybaseunits} {\mandi at selectbaseunits{#2}{#3}{#4}}
+    \cs_set:cpn {vector#1onlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}
+    \cs_set:cpn {#1vectoronlyderivedunits} {\mandi at selectderivedunits{#2}{#3}{#4}}
+    \cs_set:cpn {vector#1onlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}
+    \cs_set:cpn {#1vectoronlyalternateunits} {\mandi at selectalternateunits{#2}{#3}{#4}}
+  }
+\NewDocumentCommand{\renewvectorquantity}{ m m O{#2} O{#2} }
+  {
+    \__mandi_renewvectorquantity:nnnn { #1 }{ #2 }{ #3 }{ #4 }
+  }
 \ExplSyntaxOff
 \ExplSyntaxOn
-\cs_new:Npn \mandi_newphysicalconstant #1#2#3#4#5#6#7
-{%
-  \cs_new:cpn {#1} {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectunits{#5}{#6}{#7}}}%
-  \cs_new:cpn {#1mathsymbol} {#2}%
-  \cs_new:cpn {#1approximatevalue} {#3}%
-  \cs_new:cpn {#1precisevalue} {#4}%
-  \cs_new:cpn {#1baseunits}
-    {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectbaseunits{#5}{#6}{#7}}}%
-  \cs_new:cpn {#1derivedunits}
-    {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectderivedunits{#5}{#6}{#7}}}%
-  \cs_new:cpn {#1alternateunits}
-    {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectalternateunits{#5}{#6}{#7}}}%
-  \cs_new:cpn {#1onlybaseunits} {\mandi at selectbaseunits{#5}{#6}{#7}}%
-  \cs_new:cpn {#1onlyderivedunits} {\mandi at selectderivedunits{#5}{#6}{#7}}%
-  \cs_new:cpn {#1onlyalternateunits} {\mandi at selectalternateunits{#5}{#6}{#7}}%
-}%
-\NewDocumentCommand{\newphysicalconstant}{ m m m m m O{#5} O{#5} }%
-{%
-  \mandi_newphysicalconstant { #1 }{ #2 }{ #3 }{ #4 }{ #5 }{ #6 }{ #7 }%
-}%
+\cs_new:Npn \__mandi_newphysicalconstant:nnnnnnn #1#2#3#4#5#6#7
+  {
+    \cs_new:cpn {#1} {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectunits{#5}{#6}{#7}}}
+    \cs_new:cpn {#1mathsymbol} {#2}
+    \cs_new:cpn {#1approximatevalue} {#3}
+    \cs_new:cpn {#1precisevalue} {#4}
+    \cs_new:cpn {#1baseunits}
+      {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectbaseunits{#5}{#6}{#7}}}
+    \cs_new:cpn {#1derivedunits}
+      {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectderivedunits{#5}{#6}{#7}}}
+    \cs_new:cpn {#1alternateunits}
+      {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectalternateunits{#5}{#6}{#7}}}
+    \cs_new:cpn {#1onlybaseunits} {\mandi at selectbaseunits{#5}{#6}{#7}}
+    \cs_new:cpn {#1onlyderivedunits} {\mandi at selectderivedunits{#5}{#6}{#7}}
+    \cs_new:cpn {#1onlyalternateunits} {\mandi at selectalternateunits{#5}{#6}{#7}}
+  }
+\NewDocumentCommand{\newphysicalconstant}{ m m m m m O{#5} O{#5} }
+  {
+    \__mandi_newphysicalconstant:nnnnnnn { #1 }{ #2 }{ #3 }{ #4 }{ #5 }{ #6 }{ #7 }
+  }
 \ExplSyntaxOff
 \ExplSyntaxOn
-\cs_new:Npn \mandi_renewphysicalconstant #1#2#3#4#5#6#7
-{%
-  \cs_set:cpn {#1} {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectunits{#5}{#6}{#7}}}%
-  \cs_set:cpn {#1mathsymbol} {#2}%
-  \cs_set:cpn {#1approximatevalue} {#3}%
-  \cs_set:cpn {#1precisevalue} {#4}%
-  \cs_set:cpn {#1baseunits}
-    {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectbaseunits{#5}{#6}{#7}}}%
-  \cs_set:cpn {#1derivedunits}
-    {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectderivedunits{#5}{#6}{#7}}}%
-  \cs_set:cpn {#1alternateunits}
-    {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectalternateunits{#5}{#6}{#7}}}%
-  \cs_set:cpn {#1onlybaseunits} {\mandi at selectbaseunits{#5}{#6}{#7}}%
-  \cs_set:cpn {#1onlyderivedunits} {\mandi at selectderivedunits{#5}{#6}{#7}}%
-  \cs_set:cpn {#1onlyalternateunits} {\mandi at selectalternateunits{#5}{#6}{#7}}%
-}%
-\NewDocumentCommand{\renewphysicalconstant}{ m m m m m O{#5} O{#5} }%
-{%
-  \mandi_renewphysicalconstant { #1 }{ #2 }{ #3 }{ #4 }{ #5 }{ #6 }{ #7 }%
-}%
+\cs_new:Npn \__mandi_renewphysicalconstant:nnnnnnn #1#2#3#4#5#6#7
+  {
+    \cs_set:cpn {#1} {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectunits{#5}{#6}{#7}}}
+    \cs_set:cpn {#1mathsymbol} {#2}
+    \cs_set:cpn {#1approximatevalue} {#3}
+    \cs_set:cpn {#1precisevalue} {#4}
+    \cs_set:cpn {#1baseunits}
+      {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectbaseunits{#5}{#6}{#7}}}
+    \cs_set:cpn {#1derivedunits}
+      {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectderivedunits{#5}{#6}{#7}}}
+    \cs_set:cpn {#1alternateunits}
+      {\unit{\mandi at selectprecision{#3}{#4}}{\mandi at selectalternateunits{#5}{#6}{#7}}}
+    \cs_set:cpn {#1onlybaseunits} {\mandi at selectbaseunits{#5}{#6}{#7}}
+    \cs_set:cpn {#1onlyderivedunits} {\mandi at selectderivedunits{#5}{#6}{#7}}
+    \cs_set:cpn {#1onlyalternateunits} {\mandi at selectalternateunits{#5}{#6}{#7}}
+  }
+\NewDocumentCommand{\renewphysicalconstant}{ m m m m m O{#5} O{#5} }
+  {
+    \__mandi_renewphysicalconstant:nnnnnnn { #1 }{ #2 }{ #3 }{ #4 }{ #5 }{ #6 }{ #7 }
+  }
 \ExplSyntaxOff
 \newvectorquantity{acceleration}%
   {\meter\usk\second\totheinversetwo}%
@@ -302,14 +311,14 @@
   {\radian\usk\second\inverse}%
   [\radian\per\second]%
   [\radian\per\second]%
-  \newvectorquantity{angularimpulse}%
-    {\kilogram\usk\meter\tothetwo\usk\second\inverse}%
-    [\kilogram\usk\meter\tothetwo\per\second]% % also \joule\usk\second
-    [\kilogram\usk\meter\tothetwo\per\second]% % also \newton\usk\meter\usk\second
-  \newvectorquantity{angularmomentum}%
-    {\kilogram\usk\meter\tothetwo\usk\second\inverse}%
-    [\kilogram\usk\meter\tothetwo\per\second]% % also \joule\usk\second
-    [\kilogram\usk\meter\tothetwo\per\second]% % also \newton\usk\meter\usk\second
+\newvectorquantity{angularimpulse}%
+  {\kilogram\usk\meter\tothetwo\usk\second\inverse}%
+  [\kilogram\usk\meter\tothetwo\per\second]% % also \joule\usk\second
+  [\kilogram\usk\meter\tothetwo\per\second]% % also \newton\usk\meter\usk\second
+\newvectorquantity{angularmomentum}%
+  {\kilogram\usk\meter\tothetwo\usk\second\inverse}%
+  [\kilogram\usk\meter\tothetwo\per\second]% % also \joule\usk\second
+  [\kilogram\usk\meter\tothetwo\per\second]% % also \newton\usk\meter\usk\second
 \newvectorquantity{angularvelocity}%
   {\radian\usk\second\inverse}%
   [\radian\per\second]%
@@ -450,6 +459,8 @@
   {\kilogram\usk\meter\inverse}%
   [\kilogram\per\meter]%
   [\kilogram\per\meter]%
+\newscalarquantity{lorentzfactor}%
+  {}%
 \newscalarquantity{luminousintensity}%
   {\candela}%
 \newscalarquantity{magneticcharge}%
@@ -586,49 +597,57 @@
   {\kilogram\usk\meter\inverse\usk\second\totheinversetwo}%
   [\pascal]%
   [\newton\per\meter\tothetwo]%
+\AtBeginDocument{%
+  \DeclareRobustCommand{\hbar}{{\mathpalette\hbar@\relax\symup{h}}}%
+}%
+\newcommand*{\hbar@}[2]{%
+  \makebox[0pt][l]{\raisebox{-0.07\height}{\(\m at th#1\mkern-2mu\mathchar"AF\)}}%
+  % optional line to make the bar thicker; must use -0.11
+  \makebox[0pt][l]{\raisebox{-0.11\height}{\(\m at th#1\mkern-2mu\mathchar"AF\)}}%
+}%
 \newphysicalconstant{avogadro}%
   {\symup{N_A}}%
-  {6\timestento{23}}{6.02214076\timestento{23}}% % exact 2019 value
+  {6\times10^{23}}{6.02214076\times10^{23}}% % exact 2019 value
   {\mole\inverse}%
   [\per\mole]%
   [\per\mole]%
 \newphysicalconstant{biotsavartconstant}% % alias for \mzofp
   {\symup{\frac{\mu_o}{4\pi}}}%
-  {\tento{-7}}{\tento{-7}}%
+  {10^{-7}}{10^{-7}}%
   {\kilogram\usk\meter\usk\ampere\totheinversetwo\usk\second\totheinversetwo}%
   [\henry\per\meter]%
   [\tesla\usk\meter\per\ampere]%
 \newphysicalconstant{bohrradius}%
   {\symup{a_o}}%
-  {5.3\timestento{-11}}{5.29177210903\timestento{-11}}%
+  {5.3\times10^{-11}}{5.29177210903\times10^{-11}}%
   {\meter}%
 \newphysicalconstant{boltzmann}%
   {\symup{k_B}}%
-  {1.4\timestento{-23}}{1.380649\timestento{-23}}% % exact 2019 value
+  {1.4\times10^{-23}}{1.380649\times10^{-23}}% % exact 2019 value
   {\kilogram\usk\meter\tothetwo\usk\second\totheinversetwo\usk\kelvin\inverse}%
   [\joule\per\kelvin]%
   [\joule\per\kelvin]%
 \newphysicalconstant{coulombconstant}% % alias for \oofpez
   {\symup{\frac{1}{4\pi\epsilon_o}}}%
-  {9\timestento{9}}{8.9875517923\timestento{9}}%
+  {9\times10^{9}}{8.9875517923\times10^{9}}%
   {\kilogram\usk\meter\tothethree\usk\ampere\totheinversetwo\usk\second\totheinversefour}%
   [\meter\per\farad]%
   [\newton\usk\meter\tothetwo\per\coulomb\tothetwo]%
 \newphysicalconstant{earthmass}%
   {\symup{M_{Earth}}}%
-  {6.0\timestento{24}}{5.9722\timestento{24}}%
+  {6.0\times10^{24}}{5.9722\times10^{24}}%
   {\kilogram}%
 \newphysicalconstant{earthmoondistance}%
   {\symup{d_{EM}}}%
-  {3.8\timestento{8}}{3.81550\timestento{8}}%
+  {3.8\times10^{8}}{3.81550\times10^{8}}%
   {\meter}%
 \newphysicalconstant{earthradius}%
   {\symup{R_{Earth}}}%
-  {6.4\timestento{6}}{6.3781\timestento{6}}%
+  {6.4\times10^{6}}{6.3781\times10^{6}}%
   {\meter}%
 \newphysicalconstant{earthsundistance}%
   {\symup{d_{ES}}}%
-  {1.5\timestento{11}}{1.496\timestento{11}}%
+  {1.5\times10^{11}}{1.496\times10^{11}}%
   {\meter}%
 \newphysicalconstant{electroncharge}%
   {\symup{q_e}}%
@@ -644,71 +663,71 @@
   [\coulomb]%
 \newphysicalconstant{electronmass}%
   {\symup{m_e}}%
-  {9.1\timestento{-31}}{9.1093837015\timestento{-31}}%
+  {9.1\times10^{-31}}{9.1093837015\times10^{-31}}%
   {\kilogram}%
 \newphysicalconstant{elementarycharge}%
   {\symup{e}}%
-  {1.6\timestento{-19}}{1.602176634\timestento{-19}}% % exact 2019 value
+  {1.6\times10^{-19}}{1.602176634\times10^{-19}}% % exact 2019 value
   {\ampere\usk\second}%
   [\coulomb]%
   [\coulomb]%
 \newphysicalconstant{finestructure}%
   {\symup{\alpha}}%
-  {\frac{1}{137}}{7.2973525693\timestento{-3}}%
+  {\frac{1}{137}}{7.2973525693\times10^{-3}}%
   {}%
 \newphysicalconstant{hydrogenmass}%
   {\symup{m_H}}%
-  {1.7\timestento{-27}}{1.6737236\timestento{-27}}%
+  {1.7\times10^{-27}}{1.6737236\times10^{-27}}%
   {\kilogram}%
 \newphysicalconstant{moonearthdistance}%
   {\symup{d_{ME}}}%
-  {3.8\timestento{8}}{3.81550\timestento{8}}%
+  {3.8\times10^{8}}{3.81550\times10^{8}}%
   {\meter}%
 \newphysicalconstant{moonmass}%
   {\symup{M_{Moon}}}%
-  {7.3\timestento{22}}{7.342\timestento{22}}%
+  {7.3\times10^{22}}{7.342\times10^{22}}%
   {\kilogram}%
 \newphysicalconstant{moonradius}%
   {\symup{R_{Moon}}}%
-  {1.7\timestento{6}}{1.7371\timestento{6}}%
+  {1.7\times10^{6}}{1.7371\times10^{6}}%
   {\meter}%
 \newphysicalconstant{mzofp}%
   {\symup{\frac{\mu_o}{4\pi}}}%
-  {\tento{-7}}{\tento{-7}}%
+  {10^{-7}}{10^{-7}}%
   {\kilogram\usk\meter\usk\ampere\totheinversetwo\usk\second\totheinversetwo}%
   [\henry\per\meter]%
   [\tesla\usk\meter\per\ampere]%
 \newphysicalconstant{neutronmass}%
   {\symup{m_n}}%
-  {1.7\timestento{-27}}{1.67492749804\timestento{-27}}%
+  {1.7\times10^{-27}}{1.67492749804\times10^{-27}}%
   {\kilogram}%
 \newphysicalconstant{oofpez}%
   {\symup{\frac{1}{4\pi\epsilon_o}}}%
-  {9\timestento{9}}{8.9875517923\timestento{9}}%
+  {9\times10^{9}}{8.9875517923\times10^{9}}%
   {\kilogram\usk\meter\tothethree\usk\ampere\totheinversetwo\usk\second\totheinversefour}%
   [\meter\per\farad]%
   [\newton\usk\meter\tothetwo\per\coulomb\tothetwo]%
 \newphysicalconstant{oofpezcs}%
   {\symup{\frac{1}{4\pi\epsilon_o c^2}}}%
-  {\tento{-7}}{\tento{-7}}%
+  {10^{-7}}{10^{-7}}%
   {\kilogram\usk\meter\usk\ampere\totheinversetwo\usk\second\totheinversetwo}%
   [\tesla\usk\meter\tothetwo]%
   [\newton\usk\second\tothetwo\per\coulomb\tothetwo]%
 \newphysicalconstant{planck}%
   {\symup{h}}%
-  {6.6\timestento{-34}}{6.62607015\timestento{-34}}% % exact 2019 value
+  {6.6\times10^{-34}}{6.62607015\times10^{-34}}% % exact 2019 value
   {\kilogram\usk\meter\tothetwo\usk\second\inverse}%
   [\joule\usk\second]%
   [\joule\usk\second]%
 \newphysicalconstant{planckbar}%
-  {\symup{\lower0.18ex\hbox{\mathchar"AF}\mkern-7mu h}}%
-  {1.1\timestento{-34}}{1.054571817\timestento{-34}}%
+  {\hbar}%
+  {1.1\times10^{-34}}{1.054571817\times10^{-34}}%
   {\kilogram\usk\meter\tothetwo\usk\second\inverse}%
   [\joule\usk\second]%
   [\joule\usk\second]
 \newphysicalconstant{planckc}%
   {\symup{hc}}%
-  {2.0\timestento{-25}}{1.98644586\timestento{-25}}%
+  {2.0\times10^{-25}}{1.98644586\times10^{-25}}%
   {\kilogram\usk\meter\tothethree\usk\second\totheinversetwo}%
   [\joule\usk\meter]%
   [\joule\usk\meter]%
@@ -726,35 +745,35 @@
   [\coulomb]%
 \newphysicalconstant{protonmass}%
   {\symup{m_p}}%
-  {1.7\timestento{-27}}{1.672621898\timestento{-27}}%
+  {1.7\times10^{-27}}{1.672621898\times10^{-27}}%
   {\kilogram}%
 \newphysicalconstant{rydberg}%
   {\symup{R_{\infty}}}%
-  {1.1\timestento{7}}{1.0973731568160\timestento{7}}%
+  {1.1\times10^{7}}{1.0973731568160\times10^{7}}%
   {\meter\inverse}%
 \newphysicalconstant{speedoflight}%
   {\symup{c}}%
-  {3\timestento{8}}{2.99792458\timestento{8}}% % exact value
+  {3\times10^{8}}{2.99792458\times10^{8}}% % exact value
   {\meter\usk\second\inverse}%
   [\meter\per\second]%
   [\meter\per\second]
 \newphysicalconstant{stefanboltzmann}%
   {\symup{\sigma}}%
-  {5.7\timestento{-8}}{5.670374\timestento{-8}}%
+  {5.7\times10^{-8}}{5.670374\times10^{-8}}%
   {\kilogram\usk\second\totheinversethree\usk\kelvin\totheinversefour}%
   [\watt\per\meter\tothetwo\usk\kelvin\tothefour]%
   [\watt\per\meter\tothetwo\usk\kelvin\tothefour]
 \newphysicalconstant{sunearthdistance}%
   {\symup{d_{SE}}}%
-  {1.5\timestento{11}}{1.496\timestento{11}}%
+  {1.5\times10^{11}}{1.496\times10^{11}}%
   {\meter}%
 \newphysicalconstant{sunmass}%
   {\symup{M_{Sun}}}%
-  {2.0\timestento{30}}{1.98855\timestento{30}}%
+  {2.0\times10^{30}}{1.98855\times10^{30}}%
   {\kilogram}%
 \newphysicalconstant{sunradius}%
   {\symup{R_{Sun}}}%
-  {7.0\timestento{8}}{6.957\timestento{8}}%
+  {7.0\times10^{8}}{6.957\times10^{8}}%
   {\meter}%
 \newphysicalconstant{surfacegravfield}%
   {\symup{g}}%
@@ -764,101 +783,86 @@
   [\newton\per\kilogram]%
 \newphysicalconstant{universalgrav}%
   {\symup{G}}%
-  {6.7\timestento{-11}}{6.67430\timestento{-11}}%
+  {6.7\times10^{-11}}{6.67430\times10^{-11}}%
   {\meter\tothethree\usk\kilogram\inverse\usk\second\totheinversetwo}%
   [\newton\usk\meter\tothetwo\per\kilogram\tothetwo]% % also \joule\usk\meter\per\kilogram\tothetwo
   [\newton\usk\meter\tothetwo\per\kilogram\tothetwo]%
 \newphysicalconstant{vacuumpermeability}%
   {\symup{\mu_o}}%
-  {4\pi\timestento{-7}}{4\pi\timestento{-7}}% % as of 2018 no longer 4\pi\timestento{-7}
+  {4\pi\times10^{-7}}{4\pi\times10^{-7}}% % as of 2018 no longer 4\pi\times10^{-7}
   {\kilogram\usk\meter\usk\ampere\totheinversetwo\usk\second\totheinversetwo}%
   [\henry\per\meter]%
   [\tesla\usk\meter\per\ampere]%
 \newphysicalconstant{vacuumpermittivity}%
   {\symup{\epsilon_o}}%
-  {9\timestento{-12}}{8.854187817\timestento{-12}}%
+  {9\times10^{-12}}{8.854187817\times10^{-12}}%
   {\ampere\tothetwo\usk\second\tothefour\usk\kilogram\inverse\usk\meter\totheinversethree}%
   [\farad\per\meter]%
   [\coulomb\tothetwo\per\newton\usk\meter\tothetwo]%
 \ExplSyntaxOn
-\NewDocumentCommand{\checkquantity}{ m }%
-{%
-  % Works for both scalar and vector quantities (without vector in the name!).
-  \begin{center}
-    \begin{tabular}{%
-        >{\bfseries\small}
-        p{0.5\linewidth}
-        p{0.1\linewidth}
-        p{0.1\linewidth}
-        p{0.1\linewidth}
-      }%
-      name & & & \tabularnewline
-      \ttfamily\footnotesize{\token_to_str:c {#1}} & & & \tabularnewline
-    \end{tabular}~ % This nonbreaking space is important!
-    \begin{tabular}{%
-        >{\bfseries\small}p{0.25\linewidth}
-        >{\bfseries\small}p{0.25\linewidth}
-        >{\bfseries\small}p{0.25\linewidth}
-      }%
-      base & derived & alternate \tabularnewline
-      \footnotesize{\( \use:c {#1onlybaseunits}      \)} &
-      \footnotesize{\( \use:c {#1onlyderivedunits}   \)} &
-      \footnotesize{\( \use:c {#1onlyalternateunits} \)}
-    \end{tabular}
-  \end{center}
-}%
-\NewDocumentCommand{\checkconstant}{ m }%
-{%
-  \begin{center}
-    \begin{tabular}{%
-        >{\bfseries\small}
-        p{0.5\linewidth}
-        p{0.1\linewidth}
-        p{0.1\linewidth}
-        p{0.1\linewidth}
-      }%
-      name & & & \tabularnewline
-      \ttfamily\footnotesize{\token_to_str:c {#1}} & & & \tabularnewline
-    \end{tabular}~ % This nonbreaking space is important!
-    \begin{tabular}{%
-        >{\bfseries\small}p{0.25\linewidth}
-        >{\bfseries\small}p{0.25\linewidth}
-        >{\bfseries\small}p{0.25\linewidth}
-      }%
-      symbol & approximate & precise \tabularnewline
-      \footnotesize{\( \use:c {#1mathsymbol}       \)} &
-      \footnotesize{\( \use:c {#1approximatevalue} \)} &
-      \footnotesize{\( \use:c {#1precisevalue}     \)}
-    \end{tabular}~ % This nonbreaking space is important!
-    \begin{tabular}{%
-        >{\bfseries\small}p{0.25\linewidth}
-        >{\bfseries\small}p{0.25\linewidth}
-        >{\bfseries\small}p{0.25\linewidth}
-      }%
-      base & derived & alternate \tabularnewline
-      \footnotesize{\( \use:c {#1onlybaseunits}      \)} &
-      \footnotesize{\( \use:c {#1onlyderivedunits}   \)} &
-      \footnotesize{\( \use:c {#1onlyalternateunits} \)}
-    \end{tabular}
-  \end{center}
-}%
+\NewDocumentCommand{\@aux}{ m }
+  {
+    \use:c { #1 }
+  }
+\NewDocumentCommand{\@auy}{ m }
+  {
+    \normalfont\ttfamily\token_to_str:c { #1 }
+  }
 \ExplSyntaxOff
+\newcolumntype{M}{>{\(}p{0.25\linewidth}<{\)}}
+\NewDocumentCommand{\checkquantity}{ m }
+  {%
+    \begin{center}
+      \begin{tabular}{MMM}
+        \textbf{command}       & \multicolumn{2}{l}{\@auy{#1}}                             \tabularnewline
+        \text{\textbf{base}}   & \text{\textbf{derived}}     & \text{\textbf{alternate}}   \tabularnewline
+        \@aux{#1onlybaseunits} & \@aux{#1onlyderivedunits}   & \@aux{#1onlyalternateunits} \tabularnewline
+      \end{tabular}
+    \end{center}
+  }%
+\NewDocumentCommand{\checkconstant}{ m }
+  {%
+    \begin{center}
+      \begin{tabular}{MMM}
+        \textbf{command}       & \multicolumn{2}{l}{\@auy{#1}}                             \tabularnewline
+        \text{\textbf{symbol}} & \text{\textbf{approximate}} & \text{\textbf{precise}}     \tabularnewline
+        \@aux{#1mathsymbol}    & \@aux{#1approximatevalue}   & \@aux{#1precisevalue}       \tabularnewline
+        \text{\textbf{base}}   & \text{\textbf{derived}}     & \text{\textbf{alternate}}   \tabularnewline
+        \@aux{#1onlybaseunits} & \@aux{#1onlyderivedunits}   & \@aux{#1onlyalternateunits} \tabularnewline
+      \end{tabular}
+    \end{center}
+  }%
 \ExplSyntaxOn
-\NewDocumentCommand{\mivector}{ O{,} m o }%
- {%
-   \mi_vector:nn { #1 } { #2 }%
-   \IfValueT{#3}{\,{#3}}%
- }%
-\seq_new:N \l__mi_list_seq
-\cs_new_protected:Npn \mi_vector:nn #1 #2
-{%
-  \ensuremath{%
-    \seq_set_split:Nnn \l__mi_list_seq { , } { #2 }
-    \int_compare:nF { \seq_count:N \l__mi_list_seq = 1 } { \left\langle }
-    \seq_use:Nnnn \l__mi_list_seq { #1 } { #1 } { #1 }
-    \int_compare:nF { \seq_count:N \l__mi_list_seq = 1 } { \right\rangle }
-  }%
-}%
+\NewDocumentCommand{\mivector}{ O{,} m o }
+  {
+    \__mandi_vector:nn { #1 } { #2 }
+    \IfValueT{#3}{\,{#3}}
+  }
+\seq_new:N \l__mandi_list_seq
+\cs_new_protected:Npn \__mandi_vector:nn #1#2
+  {
+      \seq_set_split:Nnn \l__mandi_list_seq { , } { #2 }
+      \int_compare:nT { \seq_count:N \l__mandi_list_seq = 1 }
+       {
+         \msg_new:nnnn { mandi } { onecomponent }
+           {
+             More~than~one~component~expected.       \iow_newline:
+             You~provided~one~component~to~a~command \iow_newline:
+             that~expects~a~vector.~Either~you~don't \iow_newline:
+             need~a~vector~here~or~you~didn't~supply \iow_newline:
+             all~the~components.
+           }
+           {
+             Decide~whether~or~not~you~really~need~a~vector~command~here. \iow_newline:
+             \msg_see_documentation_text:n { mandi }
+           }
+         \msg_fatal:nn { mandi } { onecomponent }
+
+       }
+      \left\langle
+        \seq_use:Nnnn \l__mandi_list_seq { #1 } { #1 } { #1 }
+      \right\rangle
+  }
 \ExplSyntaxOff
 \endinput
 %%

Modified: trunk/Master/texmf-dist/tex/latex/mandi/mandiexp.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/mandi/mandiexp.sty	2022-01-27 21:41:00 UTC (rev 61763)
+++ trunk/Master/texmf-dist/tex/latex/mandi/mandiexp.sty	2022-01-27 21:41:19 UTC (rev 61764)
@@ -6,7 +6,7 @@
 %%
 %% mandiexp.dtx  (with options: `package')
 %% 
-%%  Copyright (C) 2021 by Paul J. Heafner <heafnerj at gmail.com>
+%%  Copyright (C) 2021,2022 by Paul J. Heafner <heafnerj at gmail.com>
 %%  ---------------------------------------------------------------------------
 %%  This  work may be  distributed and/or modified  under the conditions of the
 %%  LaTeX Project Public  License, either  version 1.3  of this  license or (at
@@ -29,173 +29,318 @@
 %%  and includes the derived files  mandi.sty
 %%                                  mandistudent.sty
 %%                                  mandiexp.sty
-%%                                  vdemo.py
+%%                                  vdemo.py (not needed)
 %%  ---------------------------------------------------------------------------
 %% 
-\def\mandiexp at version{\mandi at version}
-\def\mandiexp at date{\mandi at date}
+\def\mandiexp at version{3.1.0}
+\def\mandiexp at date{2022-01-27}
 \NeedsTeXFormat{LaTeX2e}[2020-02-02]
-\DeclareRelease{v3.0.0}{2021-08-22}{mandiexp.sty}
-\DeclareCurrentRelease{v\mandi at version}{\mandi at date}
+\DeclareRelease{v3.1.0}{2022-01-27}{mandiexp.sty}
+\DeclareCurrentRelease{v\mandiexp at version}{\mandiexp at date}
 \ProvidesPackage{mandiexp}
   [\mandiexp at date\space v\mandiexp at version\space Macros for Matter & Interactions]
 \newcommand*{\mandiexpversion}{v\mandiexp at version\space dated \mandiexp at date}
 \RequirePackage{mandi}
+\IfFormatAtLeastTF {2020-10-01} % load xparse if necessary
+  {}%
+  {\RequirePackage{xparse}}%
 \typeout{}%
 \typeout{mandiexp: You are using mandiexp \mandiexpversion.}
 \typeout{mandiexp: This package requires LuaLaTeX.}%
 \typeout{}%
-\NewDocumentCommand{\lhsmomentumprinciple}{ s }{%
-  \Delta
-  \IfBooleanTF{#1}%
-    {\vec*{p}}%
-    {\vec{p}}%
-  _{\symup{sys}}%
-}%
-\NewDocumentCommand{\rhsmomentumprinciple}{ s }{%
-  \IfBooleanTF{#1}%
-    {\vec*{F}}%
-    {\vec{F}}%
-  _{\symup{sys,net}}\,\Delta t%
-}%
-\NewDocumentCommand{\lhsmomentumprincipleupdate}{ s }{%
-  \IfBooleanTF{#1}%
-    {\vec*{p}}%
-    {\vec{p}}%
-  _{\symup{sys,final}}%
-}%
-\NewDocumentCommand{\rhsmomentumprincipleupdate}{ s }{%
-  \IfBooleanTF{#1}%
-    {\vec*{p}}%
-    {\vec{p}}%
-  _{\symup{sys,initial}}+%
-  \IfBooleanTF{#1}%
-    {\vec*{F}}%
-    {\vec{F}}%
-  _{\symup{sys,net}}\,\Delta t%
-}%
-\NewDocumentCommand{\momentumprinciple}{ s }{%
-  \IfBooleanTF{#1}%
-    {\lhsmomentumprinciple* = \rhsmomentumprinciple*}%
-    {\lhsmomentumprinciple = \rhsmomentumprinciple}%
-}%
-\NewDocumentCommand{\momentumprincipleupdate}{ s }{%
-  \IfBooleanTF{#1}%
-    {\lhsmomentumprincipleupdate* = \rhsmomentumprincipleupdate*}%
-    {\lhsmomentumprincipleupdate = \rhsmomentumprincipleupdate}%
-}%
-\NewDocumentCommand{\lhsenergyprinciple}{}{%
-  \Delta E_{\symup{sys}}%
-}%
-\NewDocumentCommand{\rhsenergyprinciple}{ O{} }{%
-  W_{\symup{ext}}#1%
-}%
-\NewDocumentCommand{\lhsenergyprincipleupdate}{}{%
-  E_{\symup{sys,final}}%
-}%
-\NewDocumentCommand{\rhsenergyprincipleupdate}{ O{} }{%
-  E_{\symup{sys,initial}}+%
-  W_{\symup{ext}}#1%
-}%
-\NewDocumentCommand{\energyprinciple}{ O{} }{%
-  \lhsenergyprinciple = \rhsenergyprinciple[#1]%
-}%
-\NewDocumentCommand{\energyprincipleupdate}{ O{} }{%
-  \lhsenergyprincipleupdate = \rhsenergyprincipleupdate[#1]%
-}%
-\NewDocumentCommand{\lhsangularmomentumprinciple}{ s }{%
-  \Delta
-  \IfBooleanTF{#1}%
-    {\vec*{L}}%
-    {\vec{L}}%
-  _{A\symup{,sys,net}}%
-}%
-\NewDocumentCommand{\rhsangularmomentumprinciple}{ s }{%
-  \IfBooleanTF{#1}%
-    {\vec*{\tau}}%
-    {\vec{\tau}}%
-  _{A\symup{,sys,net}}\,\Delta t%
-}%
-\NewDocumentCommand{\lhsangularmomentumprincipleupdate}{ s }{%
-  \IfBooleanTF{#1}%
-    {\vec*{L}}%
-    {\vec{L}}%
-  _{A,\symup{sys,final}}%
-}%
-\NewDocumentCommand{\rhsangularmomentumprincipleupdate}{ s }{%
-  \IfBooleanTF{#1}%
-    {\vec*{L}}%
-    {\vec{L}}%
-  _{A\symup{,sys,initial}}+%
-  \IfBooleanTF{#1}%
-    {\vec*{\tau}}%
-    {\vec{\tau}}%
-  _{A\symup{,sys,net}}\,\Delta t%
-}%
-\NewDocumentCommand{\angularmomentumprinciple}{ s }{%
-  \IfBooleanTF{#1}%
-    {\lhsangularmomentumprinciple* = \rhsangularmomentumprinciple*}%
-    {\lhsangularmomentumprinciple = \rhsangularmomentumprinciple}%
-}%
-\NewDocumentCommand{\angularmomentumprincipleupdate}{ s }{%
-  \IfBooleanTF{#1}%
-    {\lhsangularmomentumprincipleupdate* = \rhsangularmomentumprincipleupdate*}%
-    {\lhsangularmomentumprincipleupdate = \rhsangularmomentumprincipleupdate}%
-}%
-\NewDocumentCommand{\energyof}{ m o }{%
-  E_{#1\IfValueT{#2}{,#2}}%
-}%
-\NewDocumentCommand{\systemenergy}{ o }{%
-  E_{\symup{sys}\IfValueT{#1}{,#1}}%
-}%
-\NewDocumentCommand{\particleenergy}{ o }{%
-  E_{\symup{particle}\IfValueT{#1}{,#1}}%
-}%
-\NewDocumentCommand{\restenergy}{ o }{%
-  E_{\symup{rest}\IfValueT{#1}{,#1}}%
-}%
-\NewDocumentCommand{\internalenergy}{ o }{%
-  E_{\symup{internal}\IfValueT{#1}{,#1}}%
-}%
-\NewDocumentCommand{\chemicalenergy}{ o }{%
-  E_{\symup{chem}\IfValueT{#1}{,#1}}%
-}%
-\NewDocumentCommand{\thermalenergy}{ o }{%
-  E_{\symup{therm}\IfValueT{#1}{,#1}}%
-}%
-\NewDocumentCommand{\photonenergy}{ o }{%
-  E_{\symup{photon}\IfValueT{#1}{,#1}}%
-}%
-\NewDocumentCommand{\translationalkineticenergy}{ s d[] }{%
-  \IfBooleanTF{#1}%
-  {E_\bgroup \symup{K}}%
-  {K_\bgroup\symup{trans}}%
-       \IfValueT{#2}{,#2}%
-     \egroup%
-}%
-\NewDocumentCommand{\rotationalkineticenergy}{ s d[] }{%
-  \IfBooleanTF{#1}%
-  {E_\bgroup}%
-  {K_\bgroup}%
-       \symup{rot}\IfValueT{#2}{,#2}%
-     \egroup%
-}%
-\NewDocumentCommand{\vibrationalkineticenergy}{ s d[] }{%
-  \IfBooleanTF{#1}%
-  {E_\bgroup}%
-  {K_\bgroup}%
-       \symup{vib}\IfValueT{#2}{,#2}%
-     \egroup%
-}%
-\NewDocumentCommand{\gravitationalpotentialenergy}{ o }{%
-  U_{\symup{g}\IfValueT{#1}{,#1}}%
-}%
-\NewDocumentCommand{\electricpotentialenergy}{ o }{%
-  U_{\symup{e}\IfValueT{#1}{,#1}}%
-}%
-\NewDocumentCommand{\springpotentialenergy}{ o }{%
-  U_{\symup{s}\IfValueT{#1}{,#1}}%
-}%
+\NewDocumentCommand{\lhsmomentumprinciple}{ s }%
+  {%
+    \Delta
+    \IfBooleanTF{#1}%
+      {%
+        \vec*{p}
+      }%
+      {%
+        \vec{p}%
+      }%
+    \sb{\symup{sys}}%
+  }%
+\NewDocumentCommand{\rhsmomentumprinciple}{ s }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        \vec*{F}%
+      }%
+      {%
+        \vec{F}%
+      }%
+    \sb{\symup{sys,net}}\,\Delta t%
+  }%
+\NewDocumentCommand{\lhsmomentumprincipleupdate}{ s }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        \vec*{p}%
+      }%
+      {%
+        \vec{p}%
+      }%
+    \sb{\symup{sys,final}}%
+  }%
+\NewDocumentCommand{\rhsmomentumprincipleupdate}{ s }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        \vec*{p}%
+      }%
+      {%
+        \vec{p}%
+      }%
+    \sb{\symup{sys,initial}}+%
+    \IfBooleanTF{#1}%
+      {%
+        \vec*{F}%
+      }%
+      {%
+        \vec{F}%
+      }%
+    \sb{\symup{sys,net}}\,\Delta t%
+  }%
+\NewDocumentCommand{\momentumprinciple}{ s }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        \lhsmomentumprinciple* = \rhsmomentumprinciple*%
+      }%
+      {%
+        \lhsmomentumprinciple = \rhsmomentumprinciple%
+      }%
+  }%
+\NewDocumentCommand{\momentumprincipleupdate}{ s }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        \lhsmomentumprincipleupdate* = \rhsmomentumprincipleupdate*%
+      }%
+      {%
+        \lhsmomentumprincipleupdate = \rhsmomentumprincipleupdate%
+      }%
+  }%
+\NewDocumentCommand{\lhsenergyprinciple}{}%
+  {%
+    \Delta E_{\symup{sys}}%
+  }%
+\NewDocumentCommand{\rhsenergyprinciple}{ O{} }%
+  {%
+    W_{\symup{ext}}#1%
+  }%
+\NewDocumentCommand{\lhsenergyprincipleupdate}{}%
+  {%
+    E_{\symup{sys,final}}%
+  }%
+\NewDocumentCommand{\rhsenergyprincipleupdate}{ O{} }%
+  {%
+    E_{\symup{sys,initial}}+%
+    W_{\symup{ext}}#1%
+  }%
+\NewDocumentCommand{\energyprinciple}{ O{} }%
+  {%
+    \lhsenergyprinciple = \rhsenergyprinciple[#1]%
+  }%
+\NewDocumentCommand{\energyprincipleupdate}{ O{} }%
+  {%
+    \lhsenergyprincipleupdate = \rhsenergyprincipleupdate[#1]%
+  }%
+\NewDocumentCommand{\lhsangularmomentumprinciple}{ s }%
+  {%
+    \Delta%
+    \IfBooleanTF{#1}%
+      {%
+        \vec*{L}%
+      }%
+      {%
+        \vec{L}%
+      }%
+    \sb{A\symup{,sys,net}}%
+  }%
+\NewDocumentCommand{\rhsangularmomentumprinciple}{ s }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        \vec*{\tau}%
+      }%
+      {%
+        \vec{\tau}%
+      }%
+    \sb{A\symup{,sys,net}}\,\Delta t%
+  }%
+\NewDocumentCommand{\lhsangularmomentumprincipleupdate}{ s }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        \vec*{L}%
+      }%
+      {%
+        \vec{L}%
+      }%
+    \sb{A,\symup{sys,final}}%
+  }%
+\NewDocumentCommand{\rhsangularmomentumprincipleupdate}{ s }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        \vec*{L}%
+      }%
+      {%
+        \vec{L}%
+      }%
+    \sb{A\symup{,sys,initial}}+%
+    \IfBooleanTF{#1}%
+      {%
+        \vec*{\tau}%
+      }%
+      {%
+        \vec{\tau}%
+      }%
+    \sb{A\symup{,sys,net}}\,\Delta t%
+  }%
+\NewDocumentCommand{\angularmomentumprinciple}{ s }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        \lhsangularmomentumprinciple* = \rhsangularmomentumprinciple*%
+      }%
+      {%
+        \lhsangularmomentumprinciple = \rhsangularmomentumprinciple%
+      }%
+  }%
+\NewDocumentCommand{\angularmomentumprincipleupdate}{ s }%
+  {%
+    \IfBooleanTF{#1}%
+      {%
+        \lhsangularmomentumprincipleupdate* = \rhsangularmomentumprincipleupdate*%
+      }%
+      {%
+        \lhsangularmomentumprincipleupdate = \rhsangularmomentumprincipleupdate%
+      }%
+  }%
+\NewDocumentCommand{\energyof}{ m o }%
+  {%
+    E_{#1%
+        \IfValueT{#2}%
+          {,#2}%
+      }%
+  }%
+\NewDocumentCommand{\systemenergy}{ o }%
+  {%
+    E_{\symup{sys}%
+        \IfValueT{#1}%
+          {,#1}%
+      }%
+  }%
+\NewDocumentCommand{\particleenergy}{ o }%
+  {%
+    E_{\symup{particle}%
+        \IfValueT{#1}%
+          {,#1}%
+      }%
+  }%
+\NewDocumentCommand{\restenergy}{ o }%
+  {%
+    E_{\symup{rest}%
+        \IfValueT{#1}%
+          {,#1}%
+      }%
+  }%
+\NewDocumentCommand{\internalenergy}{ o }%
+  {%
+    E_{\symup{internal}%
+        \IfValueT{#1}%
+          {,#1}%
+      }%
+  }%
+\NewDocumentCommand{\chemicalenergy}{ o }%
+  {%
+    E_{\symup{chem}%
+        \IfValueT{#1}%
+          {,#1}%
+      }%
+  }%
+\NewDocumentCommand{\thermalenergy}{ o }%
+  {%
+    E_{\symup{therm}%
+        \IfValueT{#1}%
+          {,#1}%
+      }%
+  }%
+\NewDocumentCommand{\photonenergy}{ o }%
+  {%
+    E_{\symup{photon}%
+        \IfValueT{#1}%
+          {,#1}%
+      }%
+  }%
+\NewDocumentCommand{\translationalkineticenergy}{ s d[] }%
+  {%
+    % d[] must be used because of the way consecutive optional
+    %  arguments are handled. See xparse docs for details.
+    %  See https://tex.stackexchange.com/a/569011/218142
+    \IfBooleanTF{#1}%
+      {%
+        E_\bgroup \symup{K}%
+      }%
+      {%
+        K_\bgroup\symup{trans}%
+      }%
+            \IfValueT{#2}{,#2}%
+          \egroup%
+  }%
+\NewDocumentCommand{\rotationalkineticenergy}{ s d[] }%
+  {%
+    % d[] must be used because of the way consecutive optional
+    %  arguments are handled. See xparse docs for details.
+    %  See https://tex.stackexchange.com/a/569011/218142
+    \IfBooleanTF{#1}%
+      {%
+        E_\bgroup%
+      }%
+      {%
+        K_\bgroup%
+      }%
+            \symup{rot}\IfValueT{#2}{,#2}%
+          \egroup%
+  }%
+\NewDocumentCommand{\vibrationalkineticenergy}{ s d[] }%
+  {%
+    % d[] must be used because of the way consecutive optional
+    %  arguments are handled. See xparse docs for details.
+    %  See https://tex.stackexchange.com/a/569011/218142
+    \IfBooleanTF{#1}%
+      {%
+        E_\bgroup%
+      }%
+      {%
+        K_\bgroup%
+      }%
+            \symup{vib}\IfValueT{#2}{,#2}%
+          \egroup%
+  }%
+\NewDocumentCommand{\gravitationalpotentialenergy}{ o }%
+  {%
+    U_{\symup{g}%
+        \IfValueT{#1}%
+          {,#1}%
+    }%
+  }%
+\NewDocumentCommand{\electricpotentialenergy}{ o }%
+  {%
+    U_{\symup{e}%
+        \IfValueT{#1}%
+          {,#1}%
+      }%
+  }%
+\NewDocumentCommand{\springpotentialenergy}{ o }%
+  {%
+    U_{\symup{s}%
+        \IfValueT{#1}%
+          {,#1}%
+      }%
+  }%
 \endinput
 %%
 %% End of file `mandiexp.sty'.

Modified: trunk/Master/texmf-dist/tex/latex/mandi/mandistudent.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/mandi/mandistudent.sty	2022-01-27 21:41:00 UTC (rev 61763)
+++ trunk/Master/texmf-dist/tex/latex/mandi/mandistudent.sty	2022-01-27 21:41:19 UTC (rev 61764)
@@ -6,7 +6,7 @@
 %%
 %% mandistudent.dtx  (with options: `package')
 %% 
-%%  Copyright (C) 2021 by Paul J. Heafner <heafnerj at gmail.com>
+%%  Copyright (C) 2021,2022 by Paul J. Heafner <heafnerj at gmail.com>
 %%  ---------------------------------------------------------------------------
 %%  This  work may be  distributed and/or modified  under the conditions of the
 %%  LaTeX Project Public  License, either  version 1.3  of this  license or (at
@@ -29,14 +29,14 @@
 %%  and includes the derived files  mandi.sty
 %%                                  mandistudent.sty
 %%                                  mandiexp.sty
-%%                                  vdemo.py
+%%                                  vdemo.py (not needed)
 %%  ---------------------------------------------------------------------------
 %% 
-\def\mandistudent at version{\mandi at version}
-\def\mandistudent at date{\mandi at date}
+\def\mandistudent at version{3.1.0}
+\def\mandistudent at date{2022-01-27}
 \NeedsTeXFormat{LaTeX2e}[2020-02-02]
-\DeclareRelease{v3.0.0}{2021-08-22}{mandistudent.sty}
-\DeclareCurrentRelease{v\mandi at version}{\mandi at date}
+\DeclareRelease{v3.1.0}{2022-01-27}{mandistudent.sty}
+\DeclareCurrentRelease{v\mandistudent at version}{\mandistudent at date}
 \ProvidesPackage{mandistudent}
   [\mandistudent at date\space v\mandistudent at version\space Macros for introductory physics]
 \newcommand*{\mandistudentversion}{v\mandistudent at version\space dated \mandistudent at date}
@@ -50,11 +50,16 @@
 \RequirePackage{mandi}
 \RequirePackage{mathtools}           % needed for paired delimiters; extends amsmath
 \RequirePackage{nicematrix}          % needed for column and row vectors
+\RequirePackage{qrcode}              % needed for QR codes in webvpythonblock
+\qrset{height=1.5cm}                 % set default size of QR code
 \RequirePackage[most]{tcolorbox}     % needed for program listings
 \RequirePackage{tensor}              % needed for index notation
 \RequirePackage{tikz}                % needed for \hilite
 \usetikzlibrary{shapes,fit,tikzmark} % needed for \hilite
 \RequirePackage{unicode-math}        % needed for Unicode support
+\IfFormatAtLeastTF {2020-10-01}      % load xparse if necessary
+  {}%
+  {\RequirePackage{xparse}}%
 \RequirePackage{hyperref}            % load last
 \RequireLuaTeX                       % require this engine
 \unimathsetup{math-style=ISO}
@@ -166,56 +171,73 @@
 \typeout{mandistudent: This package changes the default math font(s).}%
 \typeout{mandistudent: This package redefines the \protect\vec\space command.}%
 \typeout{}%
-\RenewDocumentCommand{\vec}{ s m e{_^} }{%
+\RenewDocumentCommand{\vec}{ s m e{_^} }%
+  {%
     % Note the \, used to make superscript look better.
-    \IfBooleanTF {#1}
-      {\vv{#2}%      % * gives an arrow
-         % Use \sp{} primitive for superscript.
-         % Adjust superscript for the arrow.
-         \sp{\IfValueT{#4}{\,#4}\vphantom{\smash[t]{\big|}}}
+    \IfBooleanTF{#1}
+      {%
+        \vv{#2}%      % * gives an arrow
+        % Use \sp{} primitive for superscript.
+        % Adjust superscript for the arrow.
+        \IfValueT{#4}%
+          {\sp{\,#4\vphantom{\smash[t]{\big|}}}}
       }%
-      {\symbfit{#2}  % no * gives us bold
-         % Use \sp{} primitive for superscript.
-         % No superscript adjustment needed.
-         \sp{\IfValueT{#4}{#4}\vphantom{\smash[t]{\big|}}}
+      {%
+        \symbfit{#2}  % no * gives us bold
+        % Use \sp{} primitive for superscript.
+        % No superscript adjustment needed.
+        \IfValueT{#4}%
+          {\sp{#4\vphantom{\smash[t]{\big|}}}}
       }%
-    % Use \sb{} primitive for subscript.
-    \sb{\IfValueT{#3}{#3}\vphantom{\smash[b]{|}}}
-}%
-\NewDocumentCommand{\dirvec}{ s m e{_^} }{%
-    \widehat{\makebox*{\(w\)}{\ensuremath{%
-      \IfBooleanTF {#1}
-        {%
-          #2
-        }%
-        {%
-          \symbfit{#2}
-        }%
-       }%
+      % Use \sb{} primitive for subscript.
+    \IfValueT{#3}%
+      {\sb{#3\vphantom{\smash[b]{|}}}}
+  }%
+\NewDocumentCommand{\dirvec}{ s m e{_^} }%
+  {%
+    \widehat%
+      {%
+        \makebox*{\(w\)}%
+          {%
+            \ensuremath{%
+              \IfBooleanTF {#1}%
+                {%
+                  #2%
+                }%
+                {%
+                  \symbfit{#2}%
+                }%
+            }%
+          }%
       }%
-     }%
-    \sb{\IfValueT{#3}{#3}\vphantom{\smash[b]{|}}}
-    \sp{\IfValueT{#4}{\,#4}\vphantom{\smash[t]{\big|}}}
-}%
-\NewDocumentCommand{\zerovec}{ s }{%
-  \IfBooleanTF {#1}
-    {\vv{0}}%
-    {\symbfup{0}}%
-}%
+    \IfValueT{#3}%
+      {\sb{#3\vphantom{\smash[b]{|}}}}%
+    \IfValueT{#4}%
+      {\sp{\,#4\vphantom{\smash[t]{\big|}}}}%
+  }%
+\NewDocumentCommand{\zerovec}{ s }%
+  {%
+    \IfBooleanTF {#1}
+      {\vv{0}}%
+      {\symbfup{0}}%
+  }%
 \ExplSyntaxOn
-\NewDocumentCommand{\colvec}{ O{,} m }{%
-  \vector_main:nnnn { p } { \\ } { #1 } { #2 }
-}%
-\NewDocumentCommand{\rowvec}{ O{,} m }{%
-  \vector_main:nnnn { p } { & } { #1 } { #2 }
-}%
-\seq_new:N \l__vector_arg_seq
-\cs_new_protected:Npn \vector_main:nnnn #1 #2 #3 #4 {%
-  \seq_set_split:Nnn \l__vector_arg_seq { #3 } { #4 }
-  \begin{#1NiceMatrix}[r]
-    \seq_use:Nnnn \l__vector_arg_seq { #2 } { #2 } { #2 }
-  \end{#1NiceMatrix}
-}%
+\NewDocumentCommand{\colvec}{ O{,} m }
+  {
+    \__mandi_vectormain:nnnn { p } { \\ } { #1 } { #2 }
+  }
+\NewDocumentCommand{\rowvec}{ O{,} m }
+  {
+    \__mandi_vectormain:nnnn { p } { & } { #1 } { #2 }
+  }
+\seq_new:N \l__mandi_vectorarg_seq
+\cs_new_protected:Npn \__mandi_vectormain:nnnn #1#2#3#4
+  {
+    \seq_set_split:Nnn \l__mandi_vectorarg_seq { #3 } { #4 }
+    \begin{#1NiceMatrix}[r]
+      \seq_use:Nnnn \l__mandi_vectorarg_seq { #2 } { #2 } { #2 }
+    \end{#1NiceMatrix}
+  }
 \ExplSyntaxOff
 \NewDocumentCommand{\changein}{}{\Delta}
 \DeclarePairedDelimiterX{\doublebars}[1]{\lVert}{\rVert}{\ifblank{#1}{\:\cdot\:}{#1}}
@@ -227,120 +249,153 @@
 \NewDocumentCommand{\magnitude}{}{\doublebars}
 \NewDocumentCommand{\norm}{}{\doublebars}
 \NewDocumentCommand{\absolutevalue}{}{\singlebars}
-\NewDocumentCommand{\parallelto}{}
-  {\mkern3mu\vphantom{\perp}\vrule depth 0pt\mkern2mu\vrule depth 0pt\mkern3mu}
+\NewDocumentCommand{\parallelto}{}%
+  {%
+    \mkern3mu\vphantom{\perp}\vrule depth 0pt\mkern2mu\vrule depth 0pt\mkern3mu%
+  }%
 \NewDocumentCommand{\perpendicularto}{}{\perp}
-\NewDocumentEnvironment{physicsproblem}{ m }{%
-  \newpage%
-  \section*{#1}%
-  \newlist{parts}{enumerate}{2}%
-  \setlist[parts]{label=\bfseries(\alph*)}}%
+\NewDocumentEnvironment{physicsproblem}{ m }%
+  {%
+    \newpage%
+    \section*{#1}%
+    \newlist{parts}{enumerate}{2}%
+    \setlist[parts]{label=\bfseries(\alph*)}%
+  }%
   {}%
-\NewDocumentEnvironment{physicsproblem*}{ m }{%
-  \newpage%
-  \section*{#1}%
-  \newlist{parts}{enumerate*}{2}%
-  \setlist[parts]{label=\bfseries(\alph*)}}%
+\NewDocumentEnvironment{physicsproblem*}{ m }%
+  {%
+    \newpage%
+    \section*{#1}%
+    \newlist{parts}{enumerate*}{2}%
+    \setlist[parts]{label=\bfseries(\alph*)}%
+  }%
   {}%
 \NewDocumentCommand{\problempart}{}{\item}%
-\NewDocumentEnvironment{physicssolution}{ +b }{%
-  % Make equation numbering consecutive through the document.
-  \begin{align}
-    #1
-  \end{align}
-}{}%
-\NewDocumentEnvironment{physicssolution*}{ +b }{%
-  % Make equation numbering consecutive through the document.
-  \begin{align*}
-    #1
-  \end{align*}
-}{}%
-\NewDocumentCommand{\reason}{ O{4cm} m }
-  {&&\begin{minipage}{#1}\raggedright\small #2\end{minipage}}
+\NewDocumentEnvironment{physicssolution}{ +b }%
+  {%
+    % Make equation numbering consecutive through the document.
+    \begin{align}
+      #1
+    \end{align}
+  }%
+  {}%
+\NewDocumentEnvironment{physicssolution*}{ +b }%
+  {%
+    % Make equation numbering consecutive through the document.
+    \begin{align*}
+      #1
+    \end{align*}
+  }%
+  {}%
+\NewDocumentCommand{\reason}{ O{4cm} m }%
+  {%
+    &&\begin{minipage}{#1}\raggedright\small #2\end{minipage}%
+  }%
 \newcounter{tikzhighlightnode}
-\NewDocumentCommand{\hilite}{ O{magenta!60} m O{rectangle} }{%
-  \stepcounter{tikzhighlightnode}%
-  \tikzmarknode{highlighted-node-\number\value{tikzhighlightnode}}{#2}%
-  \edef\temp{%
-    \noexpand\AddToShipoutPictureBG{%
-      \noexpand\begin{tikzpicture}[overlay,remember picture]%
-      \noexpand\iftikzmarkoncurrentpage{highlighted-node-\number\value{tikzhighlightnode}}%
-       \noexpand\node[inner sep=1.0pt,fill=#1,#3,fit=(highlighted-node-\number\value{tikzhighlightnode})]{};%
-      \noexpand\fi
-      \noexpand\end{tikzpicture}%
+\NewDocumentCommand{\hilite}{ O{magenta!60} m O{rectangle} }%
+  {%
+    \stepcounter{tikzhighlightnode}%
+    \tikzmarknode{highlighted-node-\number\value{tikzhighlightnode}}{#2}%
+    \edef\temp{%
+      \noexpand\AddToShipoutPictureBG{%
+        \noexpand\begin{tikzpicture}[overlay,remember picture]%
+        \noexpand\iftikzmarkoncurrentpage{highlighted-node-\number\value{tikzhighlightnode}}%
+         \noexpand\node[inner sep=1.0pt,fill=#1,#3,fit=(highlighted-node-\number\value{tikzhighlightnode})]{};%
+        \noexpand\fi
+        \noexpand\end{tikzpicture}%
+      }%
     }%
+    \temp%
   }%
-  \temp%
-}%
-\NewDocumentCommand{\image}{ O{scale=1} m m m }{%
-  \begin{figure}[ht!]
-    \begin{center}%
+\NewDocumentCommand{\image}{ O{scale=1} m m m }%
+  {%
+    \par
+    \begin{figure}[ht!]
+      \centering%
       \includegraphics[#1]{#2}%
-    \end{center}%
-    \caption{#3}%
-    \label{#4}%
-  \end{figure}%
-}%
-\NewDocumentCommand{\veccomp}{ s m }{%
-  % Consider renaming this to \vectorsym.
-  \IfBooleanTF{#1}
+      \caption{#3}%
+      \label{#4}%
+    \end{figure}%
+    \par
+  }%
+\NewDocumentCommand{\veccomp}{ s m }%
   {%
-    \symnormal{#2}%
+    % Consider renaming this to \vectorsym.
+    \IfBooleanTF{#1}
+      {%
+        \symnormal{#2}%
+      }%
+      {%
+        \symbfit{#2}%
+      }%
   }%
+\NewDocumentCommand{\tencomp}{ s m }%
   {%
-    \symbfit{#2}%
+    % Consider renaming this to \tensororsym.
+    \IfBooleanTF{#1}%
+      {%
+        \symsfit{#2}%
+      }%
+      {%
+        \symbfsfit{#2}%
+      }%
   }%
-}%
-\NewDocumentCommand{\tencomp}{ s m }{%
-  % Consider renaming this to \tensororsym.
-  \IfBooleanTF{#1}
+\NewDocumentCommand{\valence}{ s m m }%
   {%
-    \symsfit{#2}%
+    \IfBooleanTF{#1}%
+      {%
+        (#2,#3)%
+      }%
+      {%
+        \binom{#2}{#3}%
+      }%
   }%
+\NewDocumentCommand{\contraction}{ s m }%
   {%
-    \symbfsfit{#2}
+    \IfBooleanTF{#1}
+      {%
+        \mathsf{C}%
+      }%
+      {%
+        \symbb{C}%
+      }%
+    _{#2}
   }%
-}%
-\NewDocumentCommand{\valence}{ s m m }{%
-  \IfBooleanTF{#1}
-    {(#2,#3)}
-    {\binom{#2}{#3}}
-}%
-\NewDocumentCommand{\contraction}{ s m }{%
-  \IfBooleanTF{#1}
-  {\mathsf{C}}%
-  {\symbb{C}}%
-  _{#2}
-}%
-\NewDocumentCommand{\slot}{ s d[] }{%
-  % d[] must be used because of the way consecutive optional
-  %  arguments are handled. See xparse docs for details.
-  \IfBooleanTF{#1}
+\NewDocumentCommand{\slot}{ s d[] }%
   {%
-    \IfValueTF{#2}
-    {% Insert a vector, but don't show the slot.
-      \smash{\makebox[1.5em]{\ensuremath{#2}}}
+    % d[] must be used because of the way consecutive optional
+    %  arguments are handled. See xparse docs for details.
+    \IfBooleanTF{#1}
+    {%
+      \IfValueTF{#2}
+      {% Insert a vector, but don't show the slot.
+        \smash{\makebox[1.5em]{\ensuremath{#2}}}
+      }%
+      {% No vector, no slot.
+        \smash{\makebox[1.5em]{\ensuremath{}}}
+      }%
     }%
-    {% No vector, no slot.
-      \smash{\makebox[1.5em]{\ensuremath{}}}
+    {%
+      \IfValueTF{#2}
+        {% Insert a vector and show the slot.
+          \underline{\smash{\makebox[1.5em]{\ensuremath{#2}}}}
+        }%
+        {% No vector; just show the slot.
+          \underline{\smash{\makebox[1.5em]{\ensuremath{}}}}
+        }%
     }%
   }%
+\NewDocumentCommand{\df}{ s }%
   {%
-    \IfValueTF{#2}
-    {% Insert a vector and show the slot.
-      \underline{\smash{\makebox[1.5em]{\ensuremath{#2}}}}
-    }%
-    {% No vector; just show the slot.
-      \underline{\smash{\makebox[1.5em]{\ensuremath{}}}}
-    }%
+    \mathop{}\!%
+    \IfBooleanTF{#1}%
+      {%
+        \symbfsfup{d}%
+      }%
+      {%
+        \symsfup{d}%
+      }%
   }%
-}%
-\NewDocumentCommand{\diff}{ s }{%
-  \mathop{}\!
-  \IfBooleanTF{#1}
-  {\symbfsfup{d}}%
-  {\symsfup{d}}%
-}%
 \directlua{%
  luaotfload.add_colorscheme("colordigits",
    {["8000FF"] = {"one","two","three","four","five","six","seven","eight","nine","zero"}})
@@ -354,120 +409,162 @@
 \definecolor{gspeach}      {rgb}{1.00,0.90,0.71} % peach
 \definecolor{gspearl}      {rgb}{0.94,0.92,0.84} % pearl
 \definecolor{gsplum}       {rgb}{0.74,0.46,0.70} % plum
-\lstdefinestyle{vpython}{%                       % style for listings
-  backgroundcolor=\color{gsbggray},%             % background color
-  basicstyle=\colordigits\footnotesize,%         % default style
-  breakatwhitespace=true%                        % break at whitespace
-  breaklines=true,%                              % break long lines
-  captionpos=b,%                                 % position caption
-  classoffset=1,%                                % STILL DON'T UNDERSTAND THIS
-  commentstyle=\color{gsgray},%                  % font for comments
-  deletekeywords={print},%                       % delete keywords from the given language
-  emph={self,cls, at classmethod, at property},%       % words to emphasize
-  emphstyle=\color{gsorange}\itshape,%           % font for emphasis
-  escapeinside={(*@}{@*)},%                      % add LaTeX within your code
-  frame=tb,%                                     % frame style
-  framerule=2.0pt,%                              % frame thickness
-  framexleftmargin=5pt,%                         % extra frame left margin
-  %identifierstyle=\sffamily,%                    % style for identifiers
-  keywordstyle=\gsfontfamily\color{gsplum},%     % color for keywords
-  language=Python,%                              % select language
-  linewidth=\linewidth,%                         % width of listings
-  morekeywords={%                                % VPython/GlowScript specific keywords
-    __future__,abs,acos,align,ambient,angle,append,append_to_caption,%
-    append_to_title,arange,arrow,asin,astuple,atan,atan2,attach_arrow,%
-    attach_trail,autoscale,axis,background,billboard,bind,black,blue,border,%
-    bounding_box,box,bumpaxis,bumpmap,bumpmaps,camera,canvas,caption,capture,%
-    ceil,center,clear,clear_trail,click,clone,CoffeeScript,coils,color,combin,%
-    comp,compound,cone,convex,cos,cross,curve,cyan,cylinder,data,degrees,del,%
-    delete,depth,descender,diff_angle,digits,division,dot,draw_complete,%
-    ellipsoid,emissive,end_face_color,equals,explog,extrusion,faces,factorial,%
-    False,floor,follow,font,format,forward,fov,frame,gcurve,gdisplay,gdots,%
-    get_library,get_selected,ghbars,global,GlowScript,graph,graphs,green,gvbars,%
-    hat,headlength,headwidth,height,helix,hsv_to_rgb,index,interval,keydown,%
-    keyup,label,length,lights,line,linecolor,linewidth,logx,logy,lower_left,%
-    lower_right,mag,mag2,magenta,make_trail,marker_color,markers,material,%
-    max,min,mouse,mousedown,mousemove,mouseup,newball,norm,normal,objects,%
-    offset,one,opacity,orange,origin,path,pause,pi,pixel_to_world,pixels,plot,%
-    points,pos,pow,pps,print,print_function,print_options,proj,purple,pyramid,%
-    quad,radians,radius,random,rate,ray,read_local_file,readonly,red,redraw,%
-    retain,rgb_to_hsv,ring,rotate,round,scene,scroll,shaftwidth,shape,shapes,%
-    shininess,show_end_face,show_start_face,sign,sin,size,size_units,sleep,%
-    smooth,space,sphere,sqrt,start,start_face_color,stop,tan,text,textpos,%
-    texture,textures,thickness,title,trail_color,trail_object,trail_radius,%
-    trail_type,triangle,trigger,True,twist,unbind,up,upper_left,upper_right,%
-    userpan,userspin,userzoom,vec,vector,vertex,vertical_spacing,visible,%
-    visual,vpython,VPython,waitfor,white,width,world,xtitle,yellow,yoffset,%
-    ytitle%
-  },%
-  morekeywords={print,None,TypeError},%      % additional keywords
-  morestring=[b]{"""},%                      % treat triple quotes as strings
-  numbers=left,%                             % where to put line numbers
-  numbersep=10pt,%                           % how far line numbers are from code
-  numberstyle=\bfseries\tiny,%               % set to 'none' for no line numbers
-  showstringspaces=false,%                   % show spaces in strings
-  showtabs=false,%                           % show tabs within strings
-  stringstyle=\gsfontfamily\color{gsgreen},% % color for strings
-  upquote=true,%                             % how to typeset quotes
-}%
-\NewTCBListing[auto counter,list inside=gsprogs]{glowscriptblock}
-  { O{} D(){glowscript.org} m }{%
-  breakable,%
-  center,%
-  code = \newpage,%
-  %derivpeach,%
-  enhanced,%
-  hyperurl interior = https://#2,%
-  label = {gs:\thetcbcounter},%
-  left = 8mm,%
-  list entry = \thetcbcounter~~~~~#3,%
-  listing only,%
-  listing style = vpython,%
-  nameref = {#3},%
-  title = \texttt{GlowScript} Program \thetcbcounter: #3,%
-  width = 0.9\textwidth,%
-  {#1},
-}%
-\NewDocumentCommand{\listofglowscriptprograms}{}{\tcblistof[\section*]{gsprogs}
-  {List of \texttt{GlowScript} Programs}}%
-\NewTCBInputListing[auto counter,list inside=vpprogs]{\vpythonfile}
-  { O{} m m }{%
-  breakable,%
-  center,%
-  code = \newpage,%
-  %derivgray,%
-  enhanced,%
-  hyperurl interior = https://,%
-  label = {vp:\thetcbcounter},%
-  left = 8mm,%
-  list entry = \thetcbcounter~~~~~#3,%
-  listing file = {#2},%
-  listing only,%
-  listing style = vpython,%
-  nameref = {#3},%
-  title = \texttt{VPython} Program \thetcbcounter: #3,%
-  width = 0.9\textwidth,%
-  {#1},%
-}%
-\NewDocumentCommand{\listofvpythonprograms}{}{\tcblistof[\section*]{vpprogs}
-  {List of \texttt{VPython} Programs}}%
-\DeclareTotalTCBox{\glowscriptinline}{ m }{%
-  bottom = 0pt,%
-  bottomrule = 0.0mm,%
-  boxsep = 1.0mm,%
-  colback = gsbggray,%
-  colframe = gsbggray,%
-  left = 0pt,%
-  leftrule = 0.0mm,%
-  nobeforeafter,%
-  right = 0pt,%
-  rightrule = 0.0mm,%
-  sharp corners,%
-  tcbox raise base,%
-  top = 0pt,%
-  toprule = 0.0mm,%
-}{\lstinline[style = vpython]{#1}}%
-\NewDocumentCommand{\vpythoninline}{}{\glowscriptinline}%
+\lstdefinestyle{vpython}%
+  {%                                            % style for listings
+    backgroundcolor=\color{gsbggray},%          % background color
+    basicstyle=\colordigits\footnotesize,%      % default style
+    breakatwhitespace=true%                     % break at whitespace
+    breaklines=true,%                           % break long lines
+    captionpos=b,%                              % position caption
+    classoffset=1,%                             % STILL DON'T UNDERSTAND THIS
+    commentstyle=\color{gsgray},%               % font for comments
+    deletekeywords={print},%                    % delete keywords from the given language
+    emph={self,cls, at classmethod, at property},%    % words to emphasize
+    emphstyle=\color{gsorange}\itshape,%        % font for emphasis
+    escapeinside={(*@}{@*)},%                    % add LaTeX within your code
+    frame=tb,%                                  % frame style
+    framerule=2.0pt,%                           % frame thickness
+    framexleftmargin=5pt,%                      % extra frame left margin
+    %identifierstyle=\sffamily,%                % style for identifiers
+    keywordstyle=\gsfontfamily\color{gsplum},%  % color for keywords
+    language=Python,%                           % select language
+    linewidth=\linewidth,%                      % width of listings
+    morekeywords={%                             % VPython/Web VPython specific keywords
+      __future__,abs,acos,align,ambient,angle,append,append_to_caption,%
+      append_to_title,arange,arrow,asin,astuple,atan,atan2,attach_arrow,%
+      attach_trail,autoscale,axis,background,billboard,bind,black,blue,border,%
+      bounding_box,box,bumpaxis,bumpmap,bumpmaps,camera,canvas,caption,capture,%
+      ceil,center,clear,clear_trail,click,clone,CoffeeScript,coils,color,combin,%
+      comp,compound,cone,convex,cos,cross,curve,cyan,cylinder,data,degrees,del,%
+      delete,depth,descender,diff_angle,digits,division,dot,draw_complete,%
+      ellipsoid,emissive,end_face_color,equals,explog,extrusion,faces,factorial,%
+      False,floor,follow,font,format,forward,fov,frame,gcurve,gdisplay,gdots,%
+      get_library,get_selected,ghbars,global,GlowScript,graph,graphs,green,gvbars,%
+      hat,headlength,headwidth,height,helix,hsv_to_rgb,index,interval,keydown,%
+      keyup,label,length,lights,line,linecolor,linewidth,logx,logy,lower_left,%
+      lower_right,mag,mag2,magenta,make_trail,marker_color,markers,material,%
+      max,min,mouse,mousedown,mousemove,mouseup,newball,norm,normal,objects,%
+      offset,one,opacity,orange,origin,path,pause,pi,pixel_to_world,pixels,plot,%
+      points,pos,pow,pps,print,print_function,print_options,proj,purple,pyramid,%
+      quad,radians,radius,random,rate,ray,read_local_file,readonly,red,redraw,%
+      retain,rgb_to_hsv,ring,rotate,round,scene,scroll,shaftwidth,shape,shapes,%
+      shininess,show_end_face,show_start_face,sign,sin,size,size_units,sleep,%
+      smooth,space,sphere,sqrt,start,start_face_color,stop,tan,text,textpos,%
+      texture,textures,thickness,title,trail_color,trail_object,trail_radius,%
+      trail_type,triangle,trigger,True,twist,unbind,up,upper_left,upper_right,%
+      userpan,userspin,userzoom,vec,vector,vertex,vertical_spacing,visible,%
+      visual,vpython,VPython,waitfor,WebVPython,white,width,world,xtitle,%
+      yellow,yoffset,ytitle%
+    },%
+    morekeywords={print,None,TypeError},%      % additional keywords
+    morestring=[b]{"""},%                      % treat triple quotes as strings
+    numbers=left,%                             % where to put line numbers
+    numbersep=10pt,%                           % how far line numbers are from code
+    numberstyle=\bfseries\tiny,%               % set to 'none' for no line numbers
+    showstringspaces=false,%                   % show spaces in strings
+    showtabs=false,%                           % show tabs within strings
+    stringstyle=\gsfontfamily\color{gsgreen},% % color for strings
+    upquote=true,%                             % how to typeset quotes
+  }%
+\AtBeginEnvironment{webvpythonblock}{\catcode`\#=12}
+\AtEndEnvironment{webvpythonblock}{\catcode`\#=6}
+\NewTCBListing[auto counter,list inside=gsprogs]{webvpythonblock}{ O{} D(){webvpython.org} m }%
+  {%
+    breakable,%
+    center,%
+    code = \newpage,%
+    %derivpeach,%
+    enhanced,%
+    hyperurl interior = https://#2,%
+    label = {gs:\thetcbcounter},%
+    left = 8mm,%
+    list entry = \thetcbcounter~~~~~#3,%
+    listing only,%
+    listing style = vpython,%
+    nameref = {#3},%
+    title = \begin{minipage}{1.5cm}%
+              \protect\qrcode*{https://#2}%
+            \end{minipage}\hspace{5mm}%
+            \begin{minipage}{0.7\textwidth}%
+              \texttt{Web VPython} Program \thetcbcounter: #3%
+            \end{minipage},%
+    width = 0.9\textwidth,%
+    {#1},
+  }%
+\AtBeginEnvironment{webvpythonblock*}{\catcode`\#=12}
+\AtEndEnvironment{webvpythonblock*}{\catcode`\#=6}
+\NewTCBListing[use counter from=webvpythonblock,list inside=gsprogs]
+  {webvpythonblock*}{ O{} D(){webvpython.org} m }%
+    {%
+      breakable,%
+      center,%
+      code = \newpage,%
+      %derivpeach,%
+      enhanced,%
+      hyperurl interior = https://#2,%
+      label = {gs:\thetcbcounter},%
+      left = 8mm,%
+      list entry = \thetcbcounter~~~~~#3,%
+      listing only,%
+      listing style = vpython,%
+      nameref = {#3},%
+      title =   \texttt{Web VPython} Program \thetcbcounter: #3,%
+      width = 0.9\textwidth,%
+      {#1},
+    }%
+\NewDocumentCommand{\listofwebvpythonprograms}{}%
+  {%
+    \tcblistof[\section*]{gsprogs}{List of \texttt{Web VPython} Programs}%
+  }%
+\newcommand*{\vpythonfile}{\catcode`\#=12 \vpythonfile at auxA}
+\NewDocumentCommand{\vpythonfile at auxA}{ O{} D(){vpython.org} m m }%
+  {%
+    \vpythonfile at auxB[#1](#2){#3}{#4}%
+    \catcode`\#=6
+  }%
+\NewTCBInputListing[auto counter,list inside=vpprogs]
+  {\vpythonfile at auxB}{ O{} D(){vpython.org} m m }%
+    {%
+      breakable,%
+      center,%
+      code = \newpage,%
+      %derivgray,%
+      enhanced,%
+      hyperurl interior = https://#2,%
+      label = {vp:\thetcbcounter},%
+      left = 8mm,%
+      list entry = \thetcbcounter~~~~~#4,%
+      listing file = {#3},%
+      listing only,%
+      listing style = vpython,%
+      nameref = {#4},%
+      title = \texttt{VPython} Program \thetcbcounter: #4,%
+      width = 0.9\textwidth,%
+      {#1},%
+    }%
+\NewDocumentCommand{\listofvpythonprograms}{}%
+  {%
+    \tcblistof[\section*]{vpprogs}{List of \texttt{VPython} Programs}%
+  }%
+\DeclareTotalTCBox{\webvpythoninline}{ m }%
+  {%
+    bottom = 0pt,%
+    bottomrule = 0.0mm,%
+    boxsep = 1.0mm,%
+    colback = gsbggray,%
+    colframe = gsbggray,%
+    left = 0pt,%
+    leftrule = 0.0mm,%
+    nobeforeafter,%
+    right = 0pt,%
+    rightrule = 0.0mm,%
+    sharp corners,%
+    tcbox raise base,%
+    top = 0pt,%
+    toprule = 0.0mm,%
+  }%
+  {\lstinline[style = vpython]{#1}}%
+\NewDocumentCommand{\vpythoninline}{}{\webvpythoninline}%
 \endinput
 %%
 %% End of file `mandistudent.sty'.



More information about the tex-live-commits mailing list.