<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">% \iffalse meta-comment
%
% This file is part of the package lipsum for use with LaTeX2e.
%
% Function: Access to 150 paragraphs of the well known Lorem Ipsum dummy text.
%
% This program may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3
% of this license or (at your option) any later version.
% The latest version of this license is in
%   http://www.latex-project.org/lppl.txt
% and version 1.3 or later is part of all distributions of LaTeX
% version 2005/12/01 or later.
%
% Please send error reports and suggestions for improvements to
%    https://github.com/PhelypeOleinik/lipsum
%
\def\lipsumversion{2.7}
\def\lipsumdate{2021-09-20}
%&lt;*driver&gt;
\ProvidesFile{lipsum.dtx}%
  [\lipsumdate\space v\lipsumversion\space
   Access to 150 of Lorem Ipsum dummy text]
\documentclass{l3doc}
\usepackage{xcolor}
\usepackage{booktabs}
\usepackage{tabularx}
\usepackage{enumitem}
\usepackage{tikz}
\usetikzlibrary{positioning}
\usepackage[a4paper,
  top=2cm, left=8.8cm, right=2cm, bottom=3cm,
  marginparwidth=6.3cm, marginparsep=.5cm,
]{geometry}
\newlength\fullmargin
\setlength\fullmargin\marginparwidth
\addtolength\fullmargin\marginparsep
\usepackage{mdframed}
\mdfdefinestyle{expl}{%
  backgroundcolor=black!5!white,
  linewidth=0pt,
  middlelinewidth=0pt
}
\newmdenv[style=expl]{explbox}

\usepackage{lipsum,multicol}
\usepackage{multirow}
\usepackage[latin, english]{babel}
\makeatletter
\newcommand\@subtitle{}
\newcommand\subtitle[1]{%
  \renewcommand\@subtitle{#1}}
  \renewcommand\maketitle[1]{%
  \noindent
  \hspace{-\fullmargin}%
  \begin{minipage}{\textwidth+\fullmargin}
    \renewcommand\thefootnote{\fnsymbol{footnote}}
    \let\thanks\footnote
    {
      \centering
      {\LARGE \@title}\\[.8\baselineskip]
      {\LARGE \@subtitle}\\[2\baselineskip]
      {\Large \@author}\\[\baselineskip]
      {\Large \@date}\\[\baselineskip]
    }
    \ifx\\#1\\\else
      \begin{multicols}{2}[%
        \subsection*{\hfill\abstractname\hfill\null}]
        \setlength{\columnsep}{.5cm}%
        #1
      \end{multicols}
    \fi
  \end{minipage}}
\makeatother
\newenvironment{wide}
  {\hspace{-.75\fullmargin}%
   \begin{minipage}{\textwidth+.75\fullmargin}}
  {\end{minipage}}
\newcommand\opt[1]{\textsf{#1}} % l3doc does not have some markup for package options...
\newcommand\lips{\emph{Lorem ipsum\ldots}}
\renewcommand\topfraction{.85}
\renewcommand\textfraction{.15}
\renewcommand\floatpagefraction{.85}
\emergencystretch 2em
\newcommand\secref[1]{(see section~\ref{#1})}
\usepackage{hyperref}
\def\ghissue#1{%
  \texttt{\##1}\footnote{%
    \url{https://github.com/PhelypeOleinik/lipsum/issues/#1}}}
\begin{document}
  \DocInput{lipsum.dtx}
\end{document}
%&lt;/driver&gt;
%&lt;*package&gt;
\NeedsTeXFormat{LaTeX2e}
\RequirePackage{l3keys2e}
\@ifundefined{NewDocumentCommand}
  {\RequirePackage{xparse}}{}
\ProvidesExplPackage {lipsum} {\lipsumdate} {\lipsumversion}
  {150 paragraphs of Lorem Ipsum dummy text}
%&lt;/package&gt;
% \fi
%
% \title{\pkg{lipsum}}
% \subtitle{Access to 150 paragraphs of Lorem Ipsum dummy
% text\thanks{Version: \lipsumversion}^^A
% \thanks{Since March 2021, Phelype Oleinik maintains this package
%   (\href{mailto:phelype.oleinik@latex-project.org}
%        {phelype.oleinik\meta{at}latex-project.org}).}}
% \author{Patrick Happel\thanks{patrick.happel@rub.de}}
% \date{\today}
% \RecordChanges
% \changes{v1.0}{2004/05/15}{First release}
% \changes{v1.1}{2011/02/08}{Added support for typesetting dummy text without
% paragraphs in between.}
% \changes{v1.2}{2011/04/14}{Bug fix (thanks to  Florent Chervet and Ulrike
% Fischer for reporting).}
% \changes{v1.3}{2014/07/19}{Introduced some improvements and provided some
% new macros (thanks to tex.stackexchange user egreg).}
% \changes{v1.3a}{2017/08/10}{Fixed a type in the documentation (thanks to
% Vincent BelaĂŻche). This version never made its way on CTAN due to some
% version naming conflicts. Since the change here was only in the
% documentation, I first didn't want it to be 1.3a and later had no time to
% update it properly.}
% \changes{v2.0}{2018/11/07}{Added the possibility to fetch a number of sentences from the
% lipsum paragraphs (thanks to Frank Mittelbach).}
% \changes{v2.0}{2018/11/07}{Rewritten code in \pkg{expl3} syntax.}
% \changes{v2.1}{2018/11/18}{Changed defaults, now nothing is typeset at the
% end of any list.}
% \changes{v2.1a}{2018/11/24}{Added forgotten ins-file to CTAN. This requires
% a new version number.}
% \changes{v2.2}{2018/12/25}{replaced \cs{tex_par:D} by \cs{par} to avoid
% incompatibilities with \LaTeX2e's |list|-environment. Thanks to Karl Hagen
% for reporting. See \url{ttps://github.com/patta42/lipsum/issues/12}.}
% \changes{v2.3}{2021/03/03}{Remove dependency on an \pkg{xparse} internal
%   macro.  \pkg{lipsum}'s new home at
%   \url{https://github.com/PhelypeOleinik/lipsum}}
% \changes{v2.4}{2021/06/03}{Major changes documented in \texttt{CHANGELOG.md}.}
%
% \maketitle{\pkg{lipsum} is a \LaTeX{} package that produces dummy text
% to be used in test documents or examples. The paragraphs are taken with
% permission from \url{https://www.lipsum.com/}, thanks to James Wilson for
% this work. Furthermore, the following people contributed to \pkg{lipsum} by
% suggesting improvements, correcting bugs or finding typos in the
% documentation: Florent Chervet, Ulrike Fischer, Vincent BelaĂŻche, Enrico
% Gregorio, Frank Mittelbach, Karl Hagen.
%
% Please, file bug reports, typos in the documentation or
% feature requests as an issue on
% \url{https://github.com/PhelypeOleinik/lipsum/issues}.}
%
% \begin{documentation}
%
% \section{Introduction}
%
% To load the package, write
% \begin{verbatim}
%     \usepackage{lipsum}
% \end{verbatim}
% in the preamble of your document. Probably the most important macro
% provided by this package is \DescribeMacro{\lipsum}\cs{lipsum}, which
% typesets the \emph{Lorem ipsum} paragraphs. The first optional
% argument allows to specify the range of the paragraphs. For example,
% \verb|\lipsum[4-57]| typesets the paragraphs 4 to 57 and accordingly,
% \verb|\lipsum[23]| typesets the 23\textsuperscript{rd} paragraph.
% Using \cs{lipsum} without its optional argument typesets the
% paragraphs 1--7 of \lips
%
% As of version 2.0, \cs{lipsum} has a second optional argument which allows
% selecting a range of sentences from the paragraphs. To get the sentences
% four to eight from paragraphs three to nine, use |\lipsum[3-9][4-8]|.
% The sentences are counted from the first sentence of the first selected
% paragraph.  In the previous example, sentence number~1 is the first
% sentence of paragraph number~3.
%
% \subsection{Foreword to Version 2.4}
% \label{sec:foreword2.4}
%
% Version~2.4 received another almost complete rewrite focussing on the
% internal structure of the package, and some minor fixes (see the
% \texttt{CHANGELOG} for more details).
%
% The package now ships with a new dummy text, in pseudo-Czech, provided
% by OndĹ™ej Macek.  To select this text, load the package with
% |\usepackage[text=lipsum-cs]{lipsum}| or use
% \cs{setlipsum}|{text=lipsum-cs}|.
%
% The dummy texts now have a language metadata which is used to select
% the proper hyphenation patterns to the dummy text.  For compatibility
% with old documents you can load \pkg{lipsum} with
% |\usepackage[auto-lang=false]{lipsum}| or, as above, use
% \cs{setlipsum}|{auto-lang=false}|.
%
% Finally, as demonstrated above, a new macro \cs{setlipsum} was added
% to change package options anywhere in the document, so you may change,
% for example, the dummy text printed by \cs{lipsum} on-the-fly by using
% \cs{setlipsum}|{text=|\meta{name}|}| \secref{sec:other-texts} for a
% list of available texts). In general, a key-val syntax was added which
% will eventually replace the command-based syntax for package settings.
% For the time being, both versions are available.
%
% \subsection{Foreword to Version 2.0}\label{sec:foreword2.0}
%
% Version 2.0 of \pkg{lipsum} is a complete (well, nearly complete)  rewrite
% of the code in \pkg{expl3}
% syntax. I have never used \pkg{expl3} before and thus the code might be too
% complicated, might use wrong or badly chosen data types or weird function
% names. I am happy to receive comments on this.
%
% Due the complete rewrite, some internals have changed which might impact
% older documents. Since, however, I guess that \pkg{lipsum} is not used for
% documents with true, important, content, I think potentially breaking up old
% documents is not a big issue here. The changes are:
% \begin{itemize}
% \item The package option \opt{nopar} now uses a \cs{space} as terminator,
% instead of \cs{relax}.
% \item The commands \cs{UnpackLipsum} and \cs{UnpackLipsum*} are no longer
% available. The effect of \cs{UnpackLipsum} now is default for
% \cs{unpacklipsum} (or \cs{unpacklipsum*}, depending on the package
% option). The effect of \cs{UnpackLipsum*} can be mimicked by using
% \cs{LipsumProtect}\Arg{command}, as in the following example:
% \begin{explbox}
% \begin{verbatim}
% \documentclass{article}
% \usepackage{lipsum,xcolor}
% \newcommand\foo{}
% \SetLipsumParListItemEnd{\LipsumProtect{\foo}}
%
% \begin{document}
% \renewcommand\foo{\color{.!75!red}}
%   { \lipsumexp }
%
% \newcounter{mycnt}\setcounter{mycnt}{1}
% \renewcommand\foo{%
%   (\themycnt)\stepcounter{mycnt}}
% \lipsumexp
% \end{document}
% \end{verbatim}
% \end{explbox}
% \item The internal macros \cs{lips@i}, \cs{lips@ii}, \cs{lips@iii}, \ldots,
%   \cs{lips@cl} are no longer available.
% \item All other internal macros (with one exception) are no longer available,
%   too.
% \end{itemize}
%
% \subsection{Foreword to version 2.2}
%
% As of version 2.2, \pkg{lipsum} provides a simple interface to define other
% texts to be used as output of the \cs{lipsum}-family of commands. This was
% heavily inspired by an issue raised by
% \emph{svenper} on
% github\footnote{\url{https://github.com/patta42/lipsum/issues/13}}. However,
% the implementation of this interface might not match the needs of everyone
% who wants to provide a dummy text in another language. Comments and
% suggestions on this are very welcome.
%
% Please note that the documentation still only refers to the
% \emph{Lorem ipsum} text.
%
% \section{Usage}
%
% \pkg{lipsum} was intended to quickly provide a way to fill a page or two to
% analyze the page
% layout\footnote{\url{https://groups.google.com/d/topic/de.comp.text.tex/oPeLOjkrLfk}}.
% While it has grown in the meanwhile and now provides some more advanced
% features, it still is only intended to quickly provide text. If you want more
% features, look at the \pkg{blindtext}-package.
%
% \subsection{Package Options}
% \label{sec:pkg-opt}
%
% \pkg{lipsum} outputs a range of paragraphs taken from the \lips\ dummy
% text. The package options control mainly the behaviour of the
% \cs{lipsum} and \cs{unpacklipsum} commands, and can be set at
% load-time with \cs{usepackage}|[|\meta{option}|]{lipsum}|, or later in
% the document by using \cs{setlipsum}|{|\meta{option}|}|.
%
% \begingroup
%   \RenewDocumentCommand \item { r[] e= d() }
%     {\par\medskip\noindent\llap
%       {\smash{\begin{tabular}{@{}l@{}}\toprule
%         \opt{#1}\\\bottomrule\end{tabular}}~~}%^^A
%      \IfValueT{#2}{=~~\!\meta{#2}\hfill
%        \IfValueT{#3}{\quad(default: \texttt{#3})}\null
%        \newline}\ignorespaces}
%
% \item[nopar]={boolean}(false)
%   Changes the initial default separator between each paragraph of
%   \cs{lipsum} from \cs{par} to \cs{space}, and the other way around
%   for \cs{lipsum*}.
% \item[text]={name}(lipsum)
%   Selects the dummy text \meta{name} that is used by \cs{lipsum} and
%   \cs{unpacklipsum} \secref{sec:other-texts}.
% \item[language]={lang}(latin)
%   Sets the language to be used by \cs{lipsum} to typeset the currently
%   active dummy text \secref{sec:hyphenation}.  Changing the dummy text
%   with the \opt{text} option will also change the current
%   \opt{language}.
% \item[auto-lang]={boolean}(true)
%   Turns on/off automatic language switching.  This changed since
%   version 2.3, in which this option (didn't exist thus) was |false| by
%   default.  See section~\ref{sec:hyphenation} for more details.
% \item[default-range]={p_i\texttt{-}p_f}(1-7)
%   Sets the default range of paragraphs produced by \cs{lipsum} when no
%   optional argument is provided.  The value to \opt{default-range}
%   obeys the \meta{range} syntax described in
%   section~\ref{sec:range-syntax}.  If no value is given to
%   \opt{default-range} (that is, \cs{setlipsum}|{default-range}|), then
%   the default is reset to |1-7|.
%
% \endgroup
%
% \medskip
%
% Besides these options, there are still ones that can be passed to the
% package to influence the paragraph and sentence separators and other
% such things.  These options are detailed in
% section~\ref{sec:separators}.
%
%^^A Besides the listed options, there are still options that can be
%^^A passed to the package to influence the paragraph and sentence
%^^A separators and other things like that.  The options for paragraphs
%^^A are:
%^^A \AddToHookNext{env/multicols/before}
%^^A   {\setlength{\multicolsep}{0.5\multicolsep}}
%^^A \begin{multicols}{2}
%^^A   \ttfamily \setlist{nosep}
%^^A   \begin{itemize}
%^^A     \item par-before
%^^A     \item par-begin
%^^A     \item par-sep
%^^A     \item par-end
%^^A     \item par-after
%^^A   \end{itemize}
%^^A   \begin{itemize}
%^^A     \item par-before*
%^^A     \item par-begin*
%^^A     \item par-sep*
%^^A     \item par-end*
%^^A     \item par-after*
%^^A   \end{itemize}
%^^A \end{multicols}
%^^A and for sentences, the same group with |sentence| instead of |par|
%^^A in their name.  These options are detailed in
%^^A section~\ref{sec:separators}.
%
% \subsection{User Commands}
%
% \begin{function}{\lipsum}
%   \begin{syntax}
%     \cs{lipsum}\meta{*}\oarg{par range}\oarg{sentence range}
%   \end{syntax}
%   \cs{lipsum} outputs the \meta{par range} from the
%   currently active dummy text.  If \meta{par range} is not given
%   or is empty, the \opt{default-range} (initially |1-7|) is output.
%   ^^A
%   If a \meta{sentence range} is given, the selected paragraphs are
%   split into sentences, numbered starting from~1, and the specified
%   range of sentences is taken out from those paragraphs.
%   ^^A
%   If the \meta{*} version is used, a different set of separators is
%   inserted around the paragraphs or sentences.
%
%   \cs{lipsum} changes the active language to that of the dummy text
%   for typesetting, so the proper hyphenation patterns are used.
%   See section~\ref{sec:hyphenation}.
%   ^^A
%   Section~\ref{sec:range-syntax} explains the syntax of ranges, and
%   section~\ref{sec:separators} explains the separators added around
%   the pieces of text.
% \end{function}
%
% \begin{function}{\unpacklipsum,\lipsumexp}
%   \begin{syntax}
%     \cs{unpacklipsum}\meta{*}\oarg{par range}\oarg{sentence range}
%     \ldots
%     \cs{lipsumexp}
%   \end{syntax}
%   \cs{unpacklipsum} selects the paragraphs and/or sentences exactly as
%   described for \cs{lipsum}, but instead of outputting them, it saves
%   the selected text in the \cs{lipsumexp} macro. Additionally,
%   \cs{unpacklipsum} \ldots\cs{lipsumexp} is not completely equivalent
%   to \cs{lipsum} because it doesn't change languages as \cs{lipsum}
%   does.
% \end{function}
%
% \begin{function}{\setlipsum}
%   \begin{syntax}
%     \cs{setlipsum}\Arg{key-val list}
%   \end{syntax}
%   Applies the \meta{key-val list} of options to the package.  The
%   options are described in section~\ref{sec:pkg-opt} and in
%   section~\ref{sec:separators}.
% \end{function}
%
% \subsection{Other commands}
%
% These commands exist for necessity or backwards comatibility, and
% should normally not be needed in user documents.
%
% \begin{function}{\SetLipsumText}
%   \begin{syntax}
%     \cs{SetLipsumDefault}\Arg{name}
%   \end{syntax}
%   Loads the dummy text \meta{name} \secref{sec:other-texts}.
%   This command does the same as option \opt{text}, but it is
%   kept for backwards compatibility.
% \end{function}
%
% \begin{function}{\SetLipsumDefault}
%   \begin{syntax}
%     \cs{SetLipsumDefault}\Arg{range}
%   \end{syntax}
%   Sets the default range for \cs{lipsum} and \cs{unpacklipsum}.
%   This command does the same as option \opt{default-range}, but it is
%   kept for backwards compatibility.
% \end{function}
%
% \section{General remarks on behaviour}
%
% Here are some topics that are general considerations about the
% behaviour of \pkg{lipsum} and its commands.  These are technicalities
% that most end users don't care too much about, unless you are trying
% to do something beyond the usual ``print me some dummy text''.
%
% \subsection{Syntax of paragraph and sentence ranges}
% \label{sec:range-syntax}
%
% A \meta{range} argument can either be blank, a single integer, or a
% proper integer range.  If the \meta{range} argument is blank, the
% commands behave as if the argument was not given at all.  For example,
% |\lipsum[]| behaves exaclty like |\lipsum| and outputs the default
% paragraph range.  Note that |\lipsum[][2-5]| does \textbf{not} behave
% as |\lipsum[2-5]|, but behaves as |\lipsum[1-7][2-5]| (assuming
% |default=range=1-7|), because the default value is then taken for the
% first argument.  If the \meta{range} argument is an integer, then only
% a single paragraph/sentence is selected.
%
% If the argument contains a |-| (\textsc{ascii}~45), it is interpreted
% as a \emph{proper} range \meta{n_i}|-|\meta{n_f}.  In a proper range,
% if \meta{n_i} is blank, it is taken to be the start of the possible
% range, and in the same way, if \meta{n_f} is empty it is taken to be
% the end of the possible range.  That is, |\lipsum[-9]| is the same as
% |\lipsum[1-9]|, and |\lipsum[5-]| is the same (assuming the standard
% 150-paragraph dummy text) as |\lipsum[5-150]|, and similarly,
% |\lipsum[-]| is the same as |\lipsum[1-150]|.
%
% Only one |-| is allowed in a range, so if more than one |-| is given,
% an error is raised and no paragraphs/sentences are output.  No
% paragraphs or sentences will be output also in case one of the ranges
% is reversed, so |\lipsum[2-1]| returns no paragraphs, as does
% |\lipsum[][2-1]| output no sentences, for example.  Note that
% ``returning no paragraphs/sentences'' is not ``the output is empty'':
% that is mostly true, except that the |-before| and |-after| separators
% are still output \secref{sec:separators}.
%
% Finally, if a range spans more paragraphs or sentences than what the
% dummy text actually provides, the range is truncated so that it fits
% the available text.  If the range in the argument does not intersect
% with the range provided by the dummy text, no paragraphs or sentences
% are output.
%
% \subsection{Hyphenation patterns}
% \label{sec:hyphenation}
%
% Since version~2.4, the command \cs{lipsum} automatically changes the
% hyphenation patterns when typesetting a dummy text, so that
% line-breaking looks better \secref{sec:foreword2.4}.  This feature is
% on by default, so if you need the old behaviour you have to explicitly
% disable automatic language switching with
% |\setlipsum{auto-lang=false}|.
%
% The language is defined individually for each dummy text
% \secref{sec:other-texts}, but you may change it for the current dummy
% text by using |\setlipsum{language=|\meta{lang}|}|.  If you load
% another dummy text (for example with the \opt{text} option), then the
% option \opt{language} is also changed according to the dummy text
% loaded \secref{sec:other-texts}.
%
% \subsection{Paragraph and sentence separators}
% \label{sec:separators}
%
% As may be clear by now, \pkg{lipsum} has two modes of operation:
% sentence output, and paragraph output, selected by providing or not
% providing the second optional argument to \cs{lipsum}.  In each mode,
% the dummy text is separated into chunks (paragraphs or sentences),
% which are counted, and then output accordingly.
%
% When \cs{lipsum} (or \cs{unpacklipsum}) is used with a single (or no)
% optional argument, then a range of paragraphs is output, along with
% some ``separators'' (in the lack of a better name) between paragraphs,
% around each paragraph, and before and after the whole output.
% A schematic (very colorful, because I couldn't find a better visual)
% representation of the output is:
%
% \begin{function}{
%     par-before,
%     par-begin,
%     par-sep,
%     par-end,
%     par-after,
%     sentence-before,
%     sentence-begin,
%     sentence-sep,
%     sentence-end,
%     sentence-after,
%   }
% \noindent
% \begin{tikzpicture}[x=0.703cm,
%     item/.style={
%       draw,
%       rounded corners=2mm,
%       minimum width=2.2cm,
%       execute at begin node=\strut,
%       rotate=54,
%       font=\footnotesize,
%     },
%   ]
%   \def\sep#1{\texttt{par-\textbf{#1}}\null}
%   \node [item,fill=red!40  ] at (0 ,0) {\sep{before}};
%   \node [item,fill=red!20  ] at (1 ,0) {\sep{begin }};
%   \node [item,fill=red!20  ] at (2 ,0) {\meta{paragraph}};
%   \node [item,fill=red!20  ] at (3 ,0) {\sep{end \  }};
%   \node [item,shading=axis,left color=red!30,right color=green!30,
%            shading angle=54] at (4 ,0) {\sep{sep \  }};
%   \node [item,fill=green!20] at (5 ,0) {\sep{begin }};
%   \node [item,fill=green!20] at (6 ,0) {\meta{paragraph}};
%   \node [item,fill=green!20] at (7 ,0) {\sep{end \  }};
%   \node [item,shading=axis,left color=green!30,right color=blue!30,
%            shading angle=54] at (8 ,0) {\sep{sep \  }};
%   \node [item,fill=blue!20 ] at (9 ,0) {\sep{begin }};
%   \node [item,fill=blue!20 ] at (10,0) {\meta{paragraph}};
%   \node [item,fill=blue!20 ] at (11,0) {\sep{end \  }};
%   \node [item,fill=blue!40 ] at (12,0) {\sep{after\ }};
% \end{tikzpicture}
%
% When \cs{lipsum} is called, the first thing it outputs is the
% \opt{par-before} tokens.  These tokens are output unconditionally,
% regardless of how many (if any) paragraph is output.
%
% Then, before each paragraph in the range, \cs{lipsum} outputs the
% \opt{par-begin} tokens, and then the actual text of the
% \meta{paragraph}, and then the \opt{par-end} tokens.  These tokens are
% output conditionally, if the paragraph text is output.  If more than
% one paragraph is output, then the \opt{par-sep} tokens are inserted
% between the \opt{par-end} of one paragraph and the \opt{par-begin} of
% the paragraph that follows.
%
% \end{function}
%
% Finally, at the end, the \opt{par-after} tokens are inserted
% unconditionally at the end, same as for \opt{par-before}.
%
% As mentioned before, in case of an error parsing the range, the output
% will be no paragraphs, but the \opt{par-before} and \opt{par-after}
% tokens are still output.
%
% The explanation above is equally valid for the starred variants.  If
% \cs{lipsum}|*| is used, the \opt{par-before*} tokens are
% inserted, and so on.  It is also true for sentences (starred or
% otherwise), replacing |par| in the option names by |sentence|, so when
% you use, for example, |\lipsum[][1-9]|, the \opt{sentence-before}
% tokens will be unconditionally inserted, and so on.
%
% Note that, when \cs{lipsum} is used in sentence-mode (for example,
% with |\lipsum[1-3][1-9]|), only the |sentence-...| tokens are inserted
% in the output, regardless of how many paragraphs those sentences were
% collected from. In the same way, if paragraph-mode is being used, only
% |par-...| tokens are inserted.
%
% \subsubsection{Deprecated command-based syntax}
%
% Older versions of \pkg{lipsum} (from 2.0 to 2.3) provided~10 CamelCase
% commands for changing the separators, but the syntax was rather
% cumbersome to use, so the keyval syntax presented thus far was
% introduced in the hopes of making things a bit easier.  The old
% commands will still exist for some time in the package, but with a
% deprecation warning.  Changing to the keyval syntax is advised, so
% here is a correspondence table between the old and new syntaxes:
%
% \begin{center}
%   \ttfamily \makeatletter
%   \definecolor{a}{HTML}{E0211A}\colorlet{a}{a!60!black}
%   \definecolor{b}{HTML}{5970D5}\colorlet{b}{b!60!black}
%   \protected@edef\x#1#2{\string\SetLipsum
%     {\color{a}#1}List{\color{b}#2}}%
%   \def\y#1#2{{\color{a}#1}-{\color{b}#2}}
%   \begin{tabular}{@{}ll@{}}
%     \toprule
%       \textrm{Old command}      &amp; \textrm{New key name} \\
%     \midrule
%       \x{Par}{Start}              &amp; \y{par}{before}      \\
%       \x{Par}{ItemStart}          &amp; \y{par}{begin}       \\
%       \x{Par}{ItemSeparator}      &amp; \y{par}{sep}         \\
%       \x{Par}{ItemEnd}            &amp; \y{par}{end}         \\
%       \x{Par}{End}                &amp; \y{par}{after}       \\
%       \x{Sentence}{Start}         &amp; \y{sentence}{before} \\
%       \x{Sentence}{ItemStart}     &amp; \y{sentence}{begin}  \\
%       \x{Sentence}{ItemSeparator} &amp; \y{sentence}{sep}    \\
%       \x{Sentence}{ItemEnd}       &amp; \y{sentence}{end}    \\
%       \x{Sentence}{End}           &amp; \y{sentence}{after}  \\
%     \bottomrule
%   \end{tabular}
% \end{center}
%
% Additionally, the command-based interface provided shortcuts
% |\SetLipsum|\meta{Thing}|List|(|Item|)|Surrounders|, which are
% equivalent to just using the commands
% |\SetLipsum|\meta{Thing}|List|(|Item|)|Start| then |\...End|.  These
% don't provide any functionality, other than requiring a little less
% typing, so no key-val alternative was implemented.
% The |\...|\meta{Thing}|...Surrounders| commands should be replaced by
% \meta{thing}|-before| and \meta{thing}|-after|, and the
% |\...|\meta{Thing}|...ItemSurrounders| commands should be replaced by
% \meta{thing}|-begin| and \meta{thing}|-end|, as in the correspondence
% table below:
%
% \begin{center}
%   \ttfamily \makeatletter
%   \definecolor{a}{HTML}{E0211A}\colorlet{a}{a!60!black}
%   \definecolor{b}{HTML}{5970D5}\colorlet{b}{b!60!black}
%   \protected@edef\x#1#2{\string\SetLipsum
%     {\color{a}#1}List{\color{b}#2}Surrounders%^^A
%      \kern .5\tabcolsep \xleaders\hbox{\vrule
%          width 2pt height \dimexpr .5ex+.4pt\relax depth -.5ex
%          \kern 2pt}%
%        \hskip 0pt plus 1filll \kern -.5\tabcolsep
%      \raise.5ex\rlap{\kern.5\tabcolsep
%        \vrule width \tabcolsep height 0.4pt depth 0pt
%        \kern-0.5\tabcolsep
%        \smash{\vrule depth \normalbaselineskip width 0.4pt
%          \raise-\normalbaselineskip
%            \hbox{\vrule width .5\tabcolsep height 0.4pt depth 0pt}}}}%
%   \def\y#1#2{{\color{a}#1}-{\color{b}#2}}
%   \begin{tabular}{@{}ll@{}}
%     \toprule
%       \textrm{Old command} &amp; \textrm{New key names} \\
%     \midrule
%       \x{Par}{}          &amp; \y{par}{}before      \\
%                          &amp; \y{par}{}after       \\
%       \x{Par}{Item}      &amp; \y{par}{begin}       \\
%                          &amp; \y{par}{end}         \\
%       \x{Sentence}{}     &amp; \y{sentence}{}before \\
%                          &amp; \y{sentence}{}after  \\
%       \x{Sentence}{Item} &amp; \y{sentence}{begin}  \\
%                          &amp; \y{sentence}{end}    \\
%     \bottomrule
%   \end{tabular}
% \end{center}
%
% \section{Loading and defining dummy texts}
% \label{sec:other-texts}
%
% Starting with \pkg{lipsum} v2.2, a simple interface is provided to
% define and load other texts for the output of \cs{lipsum} and friends.
% This interface can, for example, be used to implement dummy texts in
% different languages without re-coding the logic implemented by
% \pkg{lipsum}.
%
% \begin{function}{\NewLipsumPar}
%   \begin{syntax}
%     \cs{NewLipsumPar}\Arg{paragraph}
%   \end{syntax}
%   In order to provide a new text that will be used by \pkg{lipsum},
%   define the text by using a set of \cs{NewLipsumPar}\Arg{paragraph}
%   commands in a file with the ending |.ltd.tex| (|ltd| means
%   \emph{lipsum text definition}\footnotemark{}) to a location where
%   your \TeX{} system will find it. The \meta{paragraph}-argument is a
%   single paragraph of the new text. Thus, the first occurence of
%   \cs{NewLipsumPar} defines the first paragraph, the second occurence
%   the second paragraph and so on.
% \end{function}
% \footnotetext{To avoid name clashes with files using general languages
% as names, I chose to introduce the |.ltd.tex| file ending. I did not
% find a file with this ending in my |texmf|-tree, so I guess it is
% safe.}
%
% \begin{function}{\SetLipsumLanguage}
%   \begin{syntax}
%     \cs{SetLipsumLanguage}\Arg{lang}
%   \end{syntax}
%   Additionally, tell \pkg{lipsum} the language of the dummy text using
%   \cs{SetLipsumLanguage}\Arg{lang} somewhere in the |.ltd.tex| file.
% \end{function}
%
% \medskip
%
% To specify the new text as output for \cs{lipsum} and friends, use
% \cs{setlipsum}|{|\opt{text}|=|\meta{name}|}|, where \meta{name} is the
% name of the file without the ending |.ltd.tex|, as given in the table
% below.  When a new dummy text is loaded, the previous one is cleared,
% and the language is changed as well, according to the table.
%
% \begin{table}[ht]
% \begin{wide}
% \begin{tabularx}{\textwidth}{lllX}
%   \toprule
%     File (\texttt{.ltd.tex}) &amp; Language &amp; Source &amp; Description \\
%   \midrule
%     \texttt{lipsum} &amp; Latin
%       &amp; James Wilson
%         &amp; Contains the standard \emph{Lorem ipsum} dummy text,
%           obtained from \url{https://www.lipsum.com} (default). \\
%     \texttt{cicero} &amp; Latin
%       &amp; GH user \href{https://github.com/svenper}{svenper}
%         &amp; Contains the speech by Cicero which inspired the \lips{}
%           dummy text. \\
%     \texttt{lipsum-cs} &amp; Czech
%       &amp; OndĹ™ej Macek
%         &amp; Lipsum dummy text in the Czech language, obtained from
%           Petr StanĂ­ÄŤek's website:
%             \url{https://www.wellstyled.com/tools/dummy-cz}. \\
%   \bottomrule
% \end{tabularx}
% \end{wide}
% \end{table}
%
% \subsection{Guidelines on providing new dummy texts}
%
% \cs{SetLipsumText} more or less just uses an \cs{input} or, to be more
% precise, the \LaTeX3-variant \cs{file_input:n}, to load the |.ltd.tex|
% file. This means, that the file is not necessarily loaded in the
% preamble of the document and thus the contents of the file underlie
% the respective restrictions.
%
% Should you want a new dummy text, create an issue in the GitHub
% repository\footnote{\url{https://github.com/PhelypeOleinik/lipsum}}
% with the source for the dummy text.
%
% Should you prefer to distribute the dummy text as a separate package,
% make sure that the text follows the layout of \pkg{lipsum}'s dummy
% texts, so that everything works correctly.  The dummy text definition
% file should contain a line with \cs{SetLipsumLanguage}, and then as
% many \cs{NewLipsumPar} entries as there are paragraphs in the dummy
% text.  Make sure that the file has the |.ltd.tex| extension, and
% everything should work smoothly.
%
% \end{documentation}
%
% \clearpage
% \newgeometry{left=5cm,right=2cm}
%
% \begin{implementation}
%
% \section{\pkg{lipsum} Implementation}
%
%    \begin{macrocode}
%&lt;*package&gt;
%&lt;@@=lipsum&gt;
%    \end{macrocode}
%
% \subsection{Variables}
%
% \begin{variable}{\g_@@_par_int}
%   Stores the number of paragraphs in the current text.
%    \begin{macrocode}
\int_new:N \g_@@_par_int
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\g_@@_language_tl}
%   Stores the language of the dummy text for hyphenation patterns.
%    \begin{macrocode}
\tl_new:N \g_@@_language_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}[int]{\g_lipsum_default_range_tl}
%   The default range for lipsum paragraphs.
%    \begin{macrocode}
\tl_new:N \g_lipsum_default_range_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_output_tl}
%   This variables is used to store the token list containing the
%   selected output.
%    \begin{macrocode}
\tl_new:N \l_@@_output_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\g_@@_text_str}
%   Holds the current text loaded for the output of \cs{lipsum} and
%   friends. Used to avoid loading the same text definition if it is
%   already used.
%    \begin{macrocode}
\str_new:N \g_@@_text_str
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_sep_set_str}
%   Holds the name of the active separator token set.  By default it is
%   empty to use the default separator set (empty).
%    \begin{macrocode}
\str_new:N \l_@@_sep_set_str
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_autolang_bool}
%   Boolean whether to change hyphenation patterns according to the
%   dummy text language.
%    \begin{macrocode}
\bool_new:N \l_@@_autolang_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\q_@@_mark,\s_@@}
%   Quark and scan mark used throughout the package.
%    \begin{macrocode}
\quark_new:N \q_@@_mark
\scan_new:N \s_@@
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_tmpa_str,\l_@@_a_int,\l_@@_b_int}
%   Scratch variables.
%    \begin{macrocode}
\str_new:N \l_@@_tmpa_str
\int_new:N \l_@@_a_int
\int_new:N \l_@@_b_int
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\@@_tmp:w}
%   Scratch macro.
%    \begin{macrocode}
\cs_new_eq:NN \@@_tmp:w ?
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\l_@@_&lt;thing&gt;_&lt;place&gt;_&lt;version&gt;_tl}
%   \csname @gobble\endcsname{
%     \l_@@_par_end_nostar_tl,
%     \l_@@_par_end_star_tl,
%     \l_@@_par_end__tl,
%     \l_@@_par_itemend_nostar_tl,
%     \l_@@_par_itemend_star_tl,
%     \l_@@_par_itemend__tl,
%     \l_@@_par_itemseparator_nostar_tl,
%     \l_@@_par_itemseparator_star_tl,
%     \l_@@_par_itemseparator__tl,
%     \l_@@_par_itemstart_nostar_tl,
%     \l_@@_par_itemstart_star_tl,
%     \l_@@_par_itemstart__tl,
%     \l_@@_par_start_nostar_tl,
%     \l_@@_par_start_star_tl,
%     \l_@@_par_start__tl,
%     \l_@@_sentence_end_nostar_tl,
%     \l_@@_sentence_end_star_tl,
%     \l_@@_sentence_end__tl,
%     \l_@@_sentence_itemend_nostar_tl,
%     \l_@@_sentence_itemend_star_tl,
%     \l_@@_sentence_itemend__tl,
%     \l_@@_sentence_itemseparator_nostar_tl,
%     \l_@@_sentence_itemseparator_star_tl,
%     \l_@@_sentence_itemseparator__tl,
%     \l_@@_sentence_itemstart_nostar_tl,
%     \l_@@_sentence_itemstart_star_tl,
%     \l_@@_sentence_itemstart__tl,
%     \l_@@_sentence_start_nostar_tl,
%     \l_@@_sentence_start_star_tl,
%     \l_@@_sentence_start__tl,
%   }
%   These variables store the separators and delimiters added around the
%   paragraphs and sentences, in the starred or nonstarred variants, as
%   well as the generic version for runtime usage.
%    \begin{macrocode}
\clist_map_inline:nn { start, itemstart, itemseparator, itemend, end }
  {
    \clist_map_inline:nn { par, sentence }
      {
        \clist_map_inline:nn { { }, star, nostar }
          { \tl_new:c { l_@@_##1_#1_####1_tl } }
      }
    \tl_new:c { l_@@_par_#1_parsepar_tl }
  }
\tl_set:Nn \l_@@_par_itemseparator_parsepar_tl { ~ }
%    \end{macrocode}
% \end{variable}
%
% \subsection{Developer interface}
%
% \begin{macro}{\@@_parse_par_range:nNN,\@@_parse_par_range:eNN}
% \begin{macro}{\@@_parse_sentence_range:nNN,\@@_parse_sentence_range:eNN}
% \begin{macro}{\@@_parse_range_arg:nNNn,\@@_parse_range_arg:wnNNn}
% \begin{macro}{\@@_int_set:Nnn}
%   Parses an argument that may be a single integer or an integer range
%   separated by a |-|, and stores them into the integer registers |#2|
%   and |#3|.  If a number is blank, zero is used.  If only a single
%   number is given, |#3| is set equal to |#2|.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_par_range:nNN #1 #2 #3
  {
    \tl_if_blank:nTF {#1}
      { \exp_args:NV \@@_parse_range_arg:nNNn \g_lipsum_default_range_tl }
      { \@@_parse_range_arg:nNNn {#1} }
          #2 #3 { \g_@@_par_int }
  }
\cs_new_protected:Npn \@@_parse_sentence_range:nNN #1 #2 #3
  { \@@_parse_range_arg:nNNn {#1} #2 #3 { \c_max_int } }
\cs_new_protected:Npn \@@_parse_range_arg:nNNn #1
  {
    \exp_last_unbraced:No \@@_parse_range_arg:wnNNn
      \tl_to_str:n { #1 - - } \s_@@ {#1}
  }
\cs_new_protected:Npn \@@_parse_range_arg:wnNNn
    #1 - #2 - #3 \s_@@ #4 #5#6 #7
  {
    \str_if_eq:nnTF {#3} { - }
      {
        \@@_int_set:Nnn #5 {#1} { 1 }
        \@@_int_set:Nnn #6 {#2} {#7}
      }
      {
        \tl_if_empty:nTF {#3}
          {
            \@@_int_set:Nnn #5 {#1} { \ERROR }
            \int_set_eq:NN #6 #5
          }
          {
            \msg_error:nnn { lipsum } { invalid-range } {#4}
            \@@_parse_range_arg:nNNn { 2 - 1 } #5 #6 {#7}
          }
      }
  }
\cs_new_protected:Npn \@@_int_set:Nnn #1 #2 #3
  { \int_set:Nn #1 { \tl_if_blank:nT {#2} {#3} #2 } }
\cs_generate_variant:Nn \@@_parse_par_range:nNN { e }
\cs_generate_variant:Nn \@@_parse_sentence_range:nNN { e }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_sep_item:nn}
%   A shorthand to leave an (\cs{undexpanded}) token list.
%    \begin{macrocode}
\cs_new:Npn \@@_sep_item:nn #1 #2
  { \exp_not:v { l_@@_#1_#2_ \l_@@_sep_set_str _tl } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\lipsum_get_range:nn}
% \begin{macro}{
%     \@@_build_list:nn,
%     \@@_build_list_aux:n,
%     \@@_get_paragraph:ww,
%     \@@_get_paragraph_end:w,
%   }
%   Expands to the paragraphs between \meta{number_1} and
%   \meta{number_2} with the proper delimiters added.  Text is returned
%   in \cs{exp_not:n}, so this macro can be safely used in an \cs{edef}.
%    \begin{macrocode}
\cs_new:Npn \lipsum_get_range:nn #1 #2
  {
    \@@_sep_item:nn { par } { start }
    \use:e
      {
        \exp_not:N \@@_get_paragraph:ww
        \@@_build_list:nn {#1} {#2}
        \exp_not:N \q_@@_mark ;
        \exp_not:N \q_@@_mark ; \s_@@
      }
    \@@_sep_item:nn { par } { end }
  }
\cs_new:Npn \@@_build_list:nn #1 #2
  {
    \int_step_function:nnN
      { \int_max:nn {#1} { 1 } }
      { \int_min:nn {#2} { \g_@@_par_int } }
      \@@_build_list_aux:n
  }
\cs_new:Npn \@@_build_list_aux:n #1 { #1 ; }
\cs_new:Npn \@@_get_paragraph:ww #1 ; #2 ;
  {
    \if_meaning:w \q_@@_mark #2
      \if_meaning:w \q_@@_mark #1
        \@@_get_paragraph_end:w
      \else:
        \lipsum_get_paragraph:n {#1}
      \fi:
    \else:
      \lipsum_get_paragraph:n {#1}
      \@@_sep_item:nn { par } { itemseparator }
    \fi:
    \@@_get_paragraph:ww #2 ;
  }
\cs_new:Npn \@@_get_paragraph_end:w #1 \s_@@ { \fi: \fi: }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[int]{\lipsum_get_paragraph:n}
%   Expands to the paragraph \meta{number} with the proper delimiters
%   added.  Text is returned in \cs{exp_not:n}, so this macro can be
%   safely used in an \cs{edef}.
%    \begin{macrocode}
\cs_new:Npn \lipsum_get_paragraph:n #1
  {
    \@@_sep_item:nn { par } { itemstart }
    \@@_unexpanded_par:n {#1}
    \@@_sep_item:nn { par } { itemend }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_unexpanded_par:n}
%   Expands to the paragraph \meta{number} wrapped in \cs{exp_not:n}.
%   If \meta{number} is out of range, it expands to nothing.
%    \begin{macrocode}
\cs_new:Npn \@@_unexpanded_par:n #1
  {
    \bool_lazy_and:nnT
        { \int_compare_p:nNn { 0 } &lt; {#1} }
        { \int_compare_p:nNn {#1}  &lt; { \g_@@_par_int + 1 } }
      { \exp_not:v { g_@@_par_#1_tl } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\lipsum_get_sentences:nnn,\lipsum_get_sentences:nnV}
% \begin{macro}{\@@_get_sentences:nnnw,\@@_get_sentences_end:w}
%   Expands to the sentences numbered between \meta{number_1} and
%   \meta{number_2}, inclusive, contained in the \meta{text}, and adding
%   the proper separators.
%    \begin{macrocode}
\cs_new:Npn \lipsum_get_sentences:nnn #1 #2 #3
  {
    \@@_sep_item:nn { sentence } { start }
    \exp_args:Ne \use_ii_i:nn { { \int_max:nn {#1} { 1 } } }
      { \@@_get_sentences:nnnw { 1 } } {#2}
      #3 ~ \q_@@_mark .~ \s_@@
    \@@_sep_item:nn { sentence } { end }
  }
\cs_new:Npn \@@_get_sentences:nnnw #1 #2 #3 #4 .~
  {
    \int_compare:nNnT {#1} &gt; {#3} { \@@_get_sentences_end:w }
    \use:nn { \if_meaning:w \q_@@_mark } #4
      \exp_after:wN \@@_get_sentences_end:w
    \else:
      \int_compare:nNnF {#1} &lt; {#2}
        {
          \int_compare:nNnF {#1} = {#2}
            { \@@_sep_item:nn { sentence } { itemseparator } }
          \@@_sep_item:nn { sentence } { itemstart }
          \exp_not:n { #4 . }
          \@@_sep_item:nn { sentence } { itemend }
        }
    \fi:
    \exp_args:Nf \@@_get_sentences:nnnw { \int_eval:n { #1 + 1 } }
      {#2} {#3}
  }
\cs_new:Npn \@@_get_sentences_end:w #1 \s_@@ { }
\cs_generate_variant:Nn \lipsum_get_sentences:nnn { nnV }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{User- and developer-level commands}
%
% \begin{macro}[int]{\LipsumPar}
%   Macro to typeset a single paragraph of \lips\ Was not officially
%   available in version prior to 2.0.
%   \begin{arguments}
%     \item Number of the paragraph to typeset.
%   \end{arguments}
% Implemented as follows:
%    \begin{macrocode}
\NewDocumentCommand \LipsumPar { m }
  {
    \@@_deprecated:n { LipsumPar }
    \@@_unexpanded_par:n {#1} \par
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Tokens surrounding the \lips\ content}
%
% \begin{macro}{\@@_element_set:nnn}
%   A general macro for setting starred/non-starred versions of several
%   elements used between chunks of dummy text. Arguments are:
%   \begin{arguments}
%     \item Element name;
%     \item Boolean true or false if the |*| variant was used;
%     \item Value to set the element to.
%   \end{arguments}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_element_set:nnn #1 #2 #3
  { \tl_set:cn { l_@@_ #1 _ \IfBooleanF {#2} { no } star _tl } {#3} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_deprecated:n}
%   Warns about deprecated commands and destroys itself.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_deprecated:n #1
  {
    \msg_warning:nnn { lipsum } { cmd-deprecated } {#1}
    \cs_gset_eq:NN \@@_deprecated:n \use_none:n
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{
%     \SetLipsumParListStart,
%     \SetLipsumParListEnd,
%     \SetLipsumParListSurrounders,
%     \SetLipsumParListItemSeparator,
%     \SetLipsumParListItemStart,
%     \SetLipsumParListItemEnd,
%     \SetLipsumParListItemSurrounders,
%     \SetLipsumSentenceListStart,
%     \SetLipsumSentenceListEnd,
%     \SetLipsumSentenceListSurrounders,
%     \SetLipsumSentenceListItemSeparator,
%     \SetLipsumSentenceListItemStart,
%     \SetLipsumSentenceListItemEnd,
%     \SetLipsumSentenceListItemSurrounders,
%   }
%   A dirty loop to quickly define the old command-based user-interface.
%    \begin{macrocode}
\cs_set_protected:Npn \@@_tmp:w #1 #2 #3 #4
  {
    \str_set:Nx \l_@@_tmpa_str
      { #2 \tl_if_empty:nTF {#4} {#3} { start } }
    \use:e
      {
        \NewDocumentCommand \exp_not:c { SetLipsum #1 List #2 #3 }
            { s +m \tl_if_empty:nF {#4} { +m } }
          {
            \@@_deprecated:n { SetLipsum #1 List #2 #3 }
            \@@_element_set:nnn
              { \exp_args:Ne \str_lowercase:n { #1_\l_@@_tmpa_str } }
              {##1} {##2}
            \tl_if_empty:nT {#4} { \use_none:nnnn }
            \@@_element_set:nnn { \str_lowercase:n { #1_#2 #4 } }
              {##1} {##3}
          }
      }
  }
\clist_map_inline:nn { Par, Sentence }
  {
    \clist_map_inline:nn
      { { Start } { }, { End } { }, { Surrounders } { end } }
      { \@@_tmp:w {#1} { Item } ##1 \@@_tmp:w {#1} { } ##1 }
    \@@_tmp:w {#1} { Item } { Separator } { }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\SetLipsumDefault}
%   Command to change the default range used by \cs{lipsum} and friends.
%   \begin{arguments}
%     \item[\meta{range}] Range to be used as default.
%   \end{arguments}
% Implemented as:
%    \begin{macrocode}
\NewDocumentCommand \SetLipsumDefault { m }
  {
    \@@_parse_par_range:eNN {#1} \l_@@_a_int \l_@@_b_int
    \tl_gset:Nx \g_lipsum_default_range_tl
      { \int_use:N \l_@@_a_int - \int_use:N \l_@@_b_int }
  }
%    \end{macrocode}
% \end{macro}
%
% The following macros are considered to be user-level commands and thus
% all lower-case.
%
% \begin{macro}{\lipsum}
%   \begin{arguments}
%     \item Range-like string that specifies the number of the
%       paragraphs taken from \lips\ If omitted, the value set by
%       \cs{SetLipsumDefault} is used, which defaults to |1-7|.
%     \item Sentences to be typeset from the range selected by
%       \meta{paragraph range}. If sentences outside the number of
%       sentences in \meta{paragraph range} are specified, only existing
%       sentences are typeset.
%   \end{arguments}
%   The difference between \cs{lipsum} and \cs{lipsum*} is the token(s)
%   that are inserted after each paragraph (only if called without the
%   second optional argument).
%
%   \cs{lipsum} and \cs{unpacklipsum} have the same interface and do
%   almost the same thing, so both are implemented using a common macro
%   \cs{@@_do:nnnn} that does the heavy-lifting, and at the end
%   executes the code in |#4|.
%    \begin{macrocode}
\NewDocumentCommand \lipsum { s O { \g_lipsum_default_range_tl } o }
  {
    \@@_do:nnnn {#1} {#2} {#3}
      {
        \@@_set_hyphens:
        \tl_use:N ##1
        \@@_restore_hyphens:
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\unpacklipsum,\lipsumexp}
%   This command does the same as \cs{lipsum}, but instead of
%   typesetting the paragraphs or sentences, it stores the expanded
%   content in the \cs{lipsumexp} token list. The tokens between items
%   of the list, set, for example, by using the package option
%   \opt{space} or by using the \cs{SetLipsum...List} commands, are
%   |x|-expanded.
%    \begin{macrocode}
\NewDocumentCommand \unpacklipsum { s O { \g_lipsum_default_range_tl } o }
  { \@@_do:nnnn {#1} {#2} {#3} { \tl_gset_eq:NN \lipsumexp ##1 } }
\cs_new_eq:NN \lipsumexp \prg_do_nothing:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_do:nnnn}
% \begin{macro}{\@@_do:N}
%   This is the main macro for \cs{lipsum} and \cs{unpacklipsum}.
%   It parses the paragraph range, sets the sentence/paragraph
%   separators, then acts accordingly if a sentence range was provided.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_do:nnnn #1 #2 #3 #4
  {
    \cs_set_protected:Npn \@@_do:N ##1 {#4}
    \@@_parse_par_range:eNN {#2} \l_@@_a_int \l_@@_b_int
    \str_set_eq:NN \l_@@_tmpa_str \l_@@_sep_set_str
    \str_set:Nx \l_@@_sep_set_str { \IfBooleanF {#1} { no } star }
    \bool_lazy_or:nnTF
        { \tl_if_novalue_p:n {#3} }
        { \tl_if_blank_p:n {#3} }
      {
        \tl_set:Nx \l_@@_output_tl
          { \lipsum_get_range:nn { \l_@@_a_int } { \l_@@_b_int } }
      }
      {
        \str_set:Nn \l_@@_sep_set_str { parsepar }
        \tl_set:Nx \l_@@_output_tl
          { \lipsum_get_range:nn { \l_@@_a_int } { \l_@@_b_int } }
        \str_set:Nx \l_@@_sep_set_str { \IfBooleanF {#1} { no } star }
        \@@_parse_sentence_range:eNN {#3} \l_@@_a_int \l_@@_b_int
        \tl_set:Nx \l_@@_output_tl
          {
            \lipsum_get_sentences:nnV { \l_@@_a_int } { \l_@@_b_int }
              \l_@@_output_tl
          }
      }
    \str_set_eq:NN \l_@@_sep_set_str \l_@@_tmpa_str
    \@@_do:N \l_@@_output_tl
  }
\cs_new_eq:NN \@@_do:N ?
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_set_hyphens:,\@@_restore_hyphens:}
%   Selects the hyphenation patterns for the language of the dummy text,
%   using \cs{hyphenrules} if that's defined.  If \cs{hyphenrules}
%   doesn't exist try setting hyphenation with \cs{@@_set_hyphens_raw:}.
%   Each \cs[no-index]{@@_set_hyphens_\meta{method}:} function
%   appropriately redefines \cs{@@_restore_hypehens:} to reset the
%   hyphenation patterns.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_set_hyphens:
  {
    \bool_if:NTF \l_@@_autolang_bool
      { \use:n } { \use_none:n }
      {
        \cs_if_exist:NTF \hyphenrules
          {
            \cs_if_exist:cTF { ver@polyglossia.sty }
              { \@@_set_hyphens_polyglossia: }
              { \@@_set_hyphens_babel: }
          }
          { \@@_set_hyphens_raw: }
      }
  }
\cs_new_protected:Npn \@@_restore_hyphens:
  { \prg_do_nothing: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_set_hyphens_babel:}
%   \pkg{babel} makes things pretty simple.  We just check if
%   \cs[no-index]{l@\meta{lang}} is defined, and if so, use
%   \cs{hyphenrules} to set it, and once more to reset in
%   \cs{@@_restore_hyphens:}.  \cs{hyphenrules} is actually an
%   environment, but in \pkg{babel} its \cs[no-index]{end} part does
%   nothing, and its effect can be undone by just using another
%   \cs{hyphenrules} on top of it.
%
%   If the language is not defined, the language either doesn't exist at
%   all, or we are using Lua\TeX.  Both cases are handled by
%   \cs{@@_lang_not_available:}.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_set_hyphens_babel:
  {
    \cs_if_exist:cTF { l@ \g_@@_language_tl }
      {
        \exp_args:NV \hyphenrules \g_@@_language_tl
        \cs_set_protected:Npx \@@_restore_hyphens:
          { \exp_not:N \hyphenrules { \languagename } }
      }
      { \@@_lang_not_available: }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_set_hyphens_polyglossia:}
%   \pkg{polyglossia} less friendly.  We also check if the language is
%   loaded (looking at \cs[no-index]{\meta{lang}@loaded}), and if it
%   is, load it with the \env{hyphenrules} environment.  Here we can't
%   use the command form, as the \cs[no-index]{end} part is not a no-op.
%   This also means that an extra group is added around the dummy text,
%   which causes issue \ghissue{1} when used with \pkg{wrapfig}, for
%   example.  But not too much we can do about that for now.
%
%   In case the language is not loaded, fall back to
%   \cs{@@_set_hyphens_raw:} for a final attempt before giving up.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_set_hyphens_polyglossia:
  {
    \cs_if_exist:cTF { \g_@@_language_tl @loaded }
      {
        \exp_args:NnV \begin{hyphenrules} \g_@@_language_tl
        \cs_set_protected:Npn \@@_restore_hyphens:
          { \end{hyphenrules} }
      }
      { \@@_set_hyphens_raw: }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_set_hyphens_raw:}
%   If nothing else is available, try setting the language using
%   \cs{language}\meta{number}.  This is always available,
%   except with Lua\TeX, which loads languages on-the-fly.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_set_hyphens_raw:
  {
    \cs_if_exist:cTF { l@ \g_@@_language_tl }
      {
        \use:x
          {
            \language \use:c { l@ \g_@@_language_tl }
            \cs_set_protected:Npn \@@_restore_hyphens:
              { \language \int_eval:n { \language } \scan_stop: }
          }
      }
      { \@@_lang_not_available: }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_lang_not_available:}
%   If the requested language is for some reason unavailable, warn the
%   user, then fall back to the current language.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_lang_not_available:
  {
    \msg_warning:nnx { lipsum } { missing-language }
      { \g_@@_language_tl }
    \tl_gset_eq:NN \g_@@_language_tl \languagename
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\NewLipsumPar}
%   Developer-Level macro to add a paragraph to the dummy text used by
%   \cs{lipsum} and related commands. To specify a new dummy text, see
%   section~\ref{sec:other-texts}.
%    \begin{macrocode}
\cs_new_protected:Npn \NewLipsumPar #1
  {
    \int_gincr:N \g_@@_par_int
    \tl_gclear_new:c { g_@@_par_ \int_use:N \g_@@_par_int _tl }
    \tl_gset:cn { g_@@_par_ \int_use:N \g_@@_par_int _tl } {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\SetLipsumText}
%   Used to select and load the text output by \cs{lipsum} and friends.
%   See the section on loading and defining new outputs for \cs{lipsum}
%   (section~\ref{sec:other-texts}). It first checks whether the
%   requested text is already loaded, and if not, it loads the
%   corresponding lipsum text definition file, and clears remaining
%   paragraphs from the previous text, in case their lengths differ.
%    \begin{macrocode}
\NewDocumentCommand \SetLipsumText { m }
  {
    \str_if_eq:VnF \g_@@_text_str {#1}
      {
        \tl_gset:Nn \g_@@_language_tl { english }
        \int_gzero:N \g_@@_par_int
        \file_input:n { #1.ltd }
        \str_gset:Nn \g_@@_text_str {#1}
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\SetLipsumLanguage}
%   This macro sets the language for hyphenation patterns of the dummy
%   text.  When a new lipsum text is read, this is reset.
%    \begin{macrocode}
\NewDocumentCommand \SetLipsumLanguage { m }
  { \tl_gset:Nn \g_@@_language_tl {#1} }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Package options and defaults}
%
% \begin{macro}[int]{
%     \LipsumRestoreParList,
%     \LipsumRestoreSentenceList,
%     \LipsumRestoreAll,
%   }
% \begin{macro}{\@@_delim_restore:nnn}
% \begin{macro}{\@@_restore_par_list:,\@@_restore_sentence_list:}
%   These are some auxiliaries for the package options and for setting
%   up the default behaviour.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_delim_restore:nnn #1 #2 #3
  {
    \keys_set:nn { lipsum }
      {
        #1-before  = , #1-begin  = , #1-end  = , #1-after  = ,
        #1-before* = , #1-begin* = , #1-end* = , #1-after* = ,
        #1-sep = {#2}, #1-sep* = {#3}
      }
  }
\cs_new_protected:Nn \@@_restore_sentence_list:
  { \@@_delim_restore:nnn { sentence } { ~ } { ~ } }
\cs_new_eq:NN \@@_restore_par_list: ?
\cs_new_protected:Npn \LipsumRestoreParList
  {
    \@@_deprecated:n { LipsumRestoreParList }
    \@@_restore_par_list:
  }
\cs_new_protected:Npn \LipsumRestoreSentenceList
  {
    \@@_deprecated:n { LipsumRestoreSentenceList }
    \@@_restore_sentence_list:
  }
\cs_new_protected:Npn \LipsumRestoreAll
  {
    \@@_deprecated:n { LipsumRestoreAll }
    \@@_restore_par_list: \@@_restore_sentence_list:
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\setlipsum}
%   Here are the options available at load-time and to \cs{setlipsum}.
%    \begin{macrocode}
\NewDocumentCommand \setlipsum { +m }
  { \keys_set:nn { lipsum } {#1} }
\keys_define:nn { lipsum }
  {
%    \end{macrocode}
%   \opt{nopar} is implemented as a choice key instead of a boolean so
%   we can update the separators using \cs{@@_delim_restore:nnn}.
%   It's initially false, and the default is |true| so that
%   |\usepackage[nopar]{lipsum}| works as it always did.
%    \begin{macrocode}
    nopar .choice: ,
    nopar / true .code:n =
      {
        \cs_gset_protected:Npn \@@_restore_par_list:
          { \@@_delim_restore:nnn { par } { ~ } { \par } }
      } ,
    nopar / false .code:n =
      {
        \cs_gset_protected:Nn \@@_restore_par_list:
          { \@@_delim_restore:nnn { par } { \par } { ~ } }
      } ,
    nopar .initial:n = false ,
    nopar .default:n = true  ,
%    \end{macrocode}
%   \opt{auto-lang} sets \cs{l_@@_autolang_bool}.  It is initially
%   |true|, changing the default behaviour from previous versions.
%    \begin{macrocode}
    auto-lang .bool_set:N = \l_@@_autolang_bool ,
    auto-lang .initial:n = true ,
    auto-lang .default:n = true ,
%    \end{macrocode}
%   \opt{text} just does \cs{SetLipsumText}.  The |initial| value is not
%   set here because this chunk of code is executed in \pkg{expl3}
%   syntax, then thetextloadswithoutspaces, so |\setlipsum{text=lipsum}|
%   is used later.
%    \begin{macrocode}
    text .code:n = \SetLipsumText{#1} ,
    text .value_required:n = true ,
%    \end{macrocode}
%   \opt{language} sets the language to be used when typesetting.
%    \begin{macrocode}
    language .tl_gset:N = \g_@@_language_tl ,
    language .value_required:n = true ,
%    \end{macrocode}
%   \opt{default-range} does \cs{SetLipsumDefault}, initially |1-7|, as
%   documented.  It's default is also |1-7| so that the key has two
%   meanings: \cs{setlipsum}|{default-range=|\meta{range}|}| sets the
%   range to the given value, while \cs{setlipsum}|{default-range}| sets
%   the range to the ``default default range''.  Pretty neat :)
%    \begin{macrocode}
    default-range .code:n = \SetLipsumDefault{#1} ,
    default-range .initial:n = 1-7 ,
    default-range .default:n = 1-7 ,
  }
%    \end{macrocode}
%   This chunk defines the keys \meta{thing}-\meta{place}[*], where
%   \meta{thing} is |par| or |sentence|, \meta{place} is |before|,
%   |begin|, |sep|, |end|, and |after|, which totals~10 keys, and
%   another~10 with the |*| in the name.  Each sets a token list called
%   \cs[no-index]{l_@@_\meta{thing}_\meta{place}_[no]star_tl}.
%    \begin{macrocode}
\cs_set_protected:Npn \@@_tmp:w #1 #2 #3
  {
    \keys_define:nn { lipsum }
      {
        #1-before #2 .tl_set:c = l_@@_#1_start         _#3star_tl ,
        #1-begin  #2 .tl_set:c = l_@@_#1_itemstart     _#3star_tl ,
        #1-sep    #2 .tl_set:c = l_@@_#1_itemseparator _#3star_tl ,
        #1-end    #2 .tl_set:c = l_@@_#1_itemend       _#3star_tl ,
        #1-after  #2 .tl_set:c = l_@@_#1_end           _#3star_tl ,
      }
  }
\@@_tmp:w { par } { } { no } \@@_tmp:w { sentence } { } { no }
\@@_tmp:w { par }  *  {    } \@@_tmp:w { sentence }  *  {    }
%    \end{macrocode}
% \end{macro}
%
% Now turn \cs{ExplSyntaxOff} for a while, and load the default \lips{}
% text, then process the package options, and finally turn
% \cs{ExplSyntaxOn} again.  Finally, call \cs{@@_restore_par_list:} and
% \cs{@@_restore_sentence_list:} to set the defaults
% (\cs{@@_restore_par_list:} may have been redefined by \opt{nopar}).
%    \begin{macrocode}
\ExplSyntaxOff
\setlipsum{text=lipsum}
\ProcessKeysOptions{lipsum}
\ExplSyntaxOn
\@@_restore_par_list:
\@@_restore_sentence_list:
%    \end{macrocode}
%
% \subsection{Messages}
%
% Now define the messages used throughout the package.
%    \begin{macrocode}
\msg_new:nnn { lipsum } { invalid-range }
  { Invalid~number~or~range~'#1'. }
\msg_new:nnn { lipsum } { cmd-deprecated }
  {
    Command~'\iow_char:N\\#1'~deprecated. \\
    See~the~lipsum~documentation~for~help.
  }
\msg_new:nnn { lipsum } { missing-language }
  {
    Unknown~language~'#1'.~Hyphenation~patterns~for~
    '\languagename'~will~be~used~instead.
    \sys_if_engine_luatex:T
      {
        \\ \\
        \cs_if_exist:cTF { ver@polyglossia.sty }
          {
            With~polyglossia,~you~have~to~explicitly~load~languages~
            with~\iow_char:N\\setotherlanguage{#1}~or~similar.
          }
          {
            With~LuaTeX,~lipsum~requires~babel~to~get~proper~
            hyphenation~(you~can~use~
            \iow_char:N\\usepackage[base]{babel}).
          }
      }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;/package&gt;
%    \end{macrocode}
%
% \end{implementation}
%
% \endinput
% Local Variables:
% mode: doctex
% TeX-master: t
% End:
</pre></body></html>