summaryrefslogtreecommitdiff
path: root/macros/latex-dev/required/tools/l3sys-query.dtx
blob: d8c92adac1d2c9264dfdce53f5f4618761b455be (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
% \iffalse
%% Source File: l3sys-query.dtx
%% Copyright (C) 2024
%%
%% The LaTeX Project and any individual authors listed elsewhere
%% in this file.
%%
%% This file may be distributed under the terms of the LPPL.
%% See README for details.
%
%<*dtx>
          \ProvidesFile{l3sys-query.dtx}
%</dtx>
%<package>\ProvidesPackage{l3sys-query}
%<driver> \ProvidesFile{l3sys-query.drv}
% \fi
%         \ProvidesFile{l3sys-query.dtx}
       [2024-03-13 v1.0a LaTeX2e interface for l3sys file queries]
%
% \iffalse
%<*driver>
\documentclass{l3doc}%{ltxdoc}
\begin{document}
\DocInput{l3sys-query.dtx}
\end{document}
%</driver>
% \fi
%
% \GetFileInfo{l3sys-query.dtx}
%
% \title{\LaTeX\ document interface to the \pkg{l3sys-query} script:
% System queries for LaTeX using Lua\thanks{This file
%        has version number \fileversion, last
%        revised \filedate.}}
% \author{\LaTeX\ project}
% \date{\filedate}
%
%
% \maketitle
%
% \tableofcontents
%
% \section{Introduction}
% 
% \TeX{} engines provide only very limited access to information about the system
% they are used on: using primitives, one can for example get the size of a single
% file, but not a list of files in a given location. For most documents, this is
% not an issue as they are self-contained. However, for cases where
% \enquote{dynamic} construction of parts of a document is needed based on file
% lists or other system-dependent data, methods to obtain this from (restricted)
% shell escape are desirable.
% 
% Security considerations mean that directly querying the system shell is
% problematic for general use. Instead, \emph{restricted} shell escape may be used
% to get many details, provided a suitable tool is available to provide the
% information in a platform-neutral and security-conscious way. The Java program
% \texttt{texosquery}, written by Nicola Talbot, has been available for a number
% of years to provide this facility. As well as file system insight,
% \texttt{texosquery} also provides for example locale data and other system
% information. However, the requirement for Java means that the script is not
% automatically usable when a \TeX{} system is installed.
% 
% The \LaTeX{} team have therefore provided a Lua-based script,
% \texttt{l3sys-query}, which conforms to the security requirements of \TeX{} Live
% using Lua to obtain the system information. This means that it can be used
% \enquote{out of the box} across platforms. The facilities provided by
% \texttt{l3sys-query} are more limited than \texttt{texosquery}, partly as some
% information is available in modern \TeX{} systems using primitives, and partly
% as the aim of \texttt{l3sys-query} is to provide information where there are
% defined use cases. Requests for additional data interfaces are welcome.
%
% This package provides a document level \textit{Key-Value} interface
% to The \texttt{l3sys-query} functionality, although as a convenience
% it also summarizes the documentation for the L3 programming
% interface layer (prvided by the \pkg{l3sys} module of
% \pkg{l3kernel}, and of the command line Lua script
% \texttt{l3sys-query} which is distributed separately and provides
% the underlying functionality.
%
% 
% 
% \section{The document level key-value  interface\label{sec:kv}}
%
% This provides an interface to \texttt{l3sys-query} based on
% \pkg{l3keys} that allows the options to be specified and checked
% individually. Internally the supplied key values are used to build
% up the arguments to the commands described above in the L3
% programming layer commands described in section~\ref{sec:expl3}
%
% Results containing path separators \emph{always}
% use~|/|, irrespective of the platform in use.
% 
%
% \begin{function}
%   {\QueryWorkingDirectory}
%   \begin{syntax}
%     \cs{QueryWorkingDirectory} \Arg{result cmd}
%   \end{syntax}
%   Defines supplied command \meta{result cmd} to hold
%   the absolute path to the current working directory of the
%   \TeX\ system.
%   This is the directory (folder) from which \TeX\ was started, so usually
%   the location of the main document file.
% \end{function}
% 
% \begin{function}
%   {\QueryFiles, \QueryFilesTF}
%   \begin{syntax}
%     \cs{QueryFiles} \oarg{options} \Arg{spec} \Arg{function}
%     \cs{QueryFilesTF} \oarg{options} \Arg{spec} \Arg{function} \Arg{pre code} \Arg{empty list code}
%   \end{syntax}
%   This generates a file list  based on the \meta{spec} and \meta{options}.
%   The command then applies \meta{function}  to each item in the sequence of filenames.
%   The \meta{function} should be a macro body which will be passed the file path as |#1|.
% 
%  The TF version executes the T (\meta{pre code}) argument before iterating over the list
%  and the F (\meta{empty list code}) argument if the list is empty.
% \end{function}
% 
%  Note that this interface in mapping directly over the sequence of
%  filenames does not allow some uses which are provided by the
%  programming interface described in the following section, which allows
%  the sequence to be manipulated before being used.
% 
%  The defined keys map vey closely to the options of the
%  \texttt{l3sys-query} command which is described in
%  section~\ref{sec:lua}.
% 
%  \begin{itemize}
%  \item 
%  The keys \texttt{recursive}, \texttt{ignore-case}, \texttt{reverse}, \texttt{pattern}
%  take no values and map directly to the command line options of the same name.
% 
%  \item
%  The key \texttt{sort} accepts the values \texttt{date} and \texttt{name}.
% 
%  \item
%  The key \texttt{type} accepts \texttt{d} or \texttt{f}.
% 
%  \item
%  The key \texttt{exclude} accepts a glob (or Lua pattern) mathing
%  files to be excluded.  The package arranges that the quoting of the
%  argument is automatically added if unrestricted shell escape is
%  enabled.
% 
% \end{itemize}
% 
%  Within the main \meta{spec} argument, and the value of the \texttt{exclude} key,
%  the following characters may need special handling.
%  |~| may be used (which \texttt{kpathsea} uses to denote the users home directory).
%  |\%|, or at the top level |%|, may be used to produce a literal |%|
%  which may be especially useful if the \texttt{pattern} key is used
%  as \% is the escape character in Lua patterns.
%  
%  \subsection{Examples\label{sec:examples2e}}
%
%  \begin{itemize}
%  \item 
%  Include every |png| file in the current directory.
% \begin{verbatim}
% \QueryFiles{*.png}{\includegraphics{#1}\par}
% \end{verbatim}
%
% \item
%  Input every \TeX\ file with a filename matching \texttt{chapter[0-9].tex}.
% \begin{verbatim}
% \QueryFiles[pattern]{chapter%d.*%.tex}{\input{#1}}
% \end{verbatim}
%  \end{itemize}
%
% \section{The L3 programming layer interface\label{sec:expl3}}
% 
% \begin{function}
%   {\sys_get_query:nN, \sys_get_query:nnN, \sys_get_query:nnnN}
%   \begin{syntax}
%     \cs{sys_get_query:nN} \Arg{cmd} \Arg{tl var}
%     \cs{sys_get_query:nnN} \Arg{cmd} \Arg{spec} \Arg{tl var}
%     \cs{sys_get_query:nnnN} \Arg{cmd} \Arg{options} \Arg{spec} \Arg{tl var}
%   \end{syntax}
%   Sets the \meta{tl var} to the information returned by the
%   \texttt{l3sys-query} \meta{cmd}, potentially supplying the \meta{options}
%   and \meta{spec} to the query call. The valid \meta{cmd} names are at present
%   \begin{itemize}
%     \item \texttt{pwd} Returns the absolute path to the current working directory
%     \item \texttt{ls} Returns a directory listing, using the \meta{spec} to
%       select files and applying the \meta{options} if given
%   \end{itemize}
%   The \meta{spec} should be a file glob and will automatically be passed to
%   the script without shell expansion.
% \end{function}
% 
% \begin{function}
%   {\sys_split_query:nN, \sys_split_query:nnN, \sys_split_query:nnnN}
%   \begin{syntax}
%     \cs{sys_split_query:nN} \Arg{cmd} \Arg{seq}
%     \cs{sys_split_query:nnN} \Arg{cmd} \Arg{spec} \Arg{seq}
%     \cs{sys_split_query:nnnN} \Arg{cmd} \Arg{options} \Arg{spec} \Arg{seq}
%   \end{syntax}
%   Works as described for \cs{sys_get_query:nnnN}, but sets the \meta{seq}
%   to contain one entry for each line returned by \texttt{l3sys-query}.
% \end{function}
% 
% \section{The \texttt{l3sys-query} Lua script\label{sec:lua}}
% \subsection{The command line interface}
% 
% The command line interface to 
% \begin{center}
%   \ttfamily
%   l3sys-query \meta{cmd} [\meta{option(s)}] [\meta{args}]
% \end{center}
% where \texttt{\meta{cmd}} can be one of the following:
% \begin{itemize}[noitemsep]\ttfamily
%   \item ls
%   \item ls \meta{args}
%   \item pwd
% \end{itemize}
% The \meta{cmd} are described below. The result of the \meta{cmd} will be printed
% to the terminal in an interactive run; in normal usage, this will be piped to
% the calling \TeX{} process. Results containing path separators \emph{always}
% use~|/|, irrespective of the platform in use.
% 
% As well as these targets, the script recognizes the options
% \begin{itemize}
%   \item |--exclude| Specification for directory entries to exclude
%   \item |--ignore-case| Ignores case when sorting directory listings
%   \item |--pattern| (|-p|) Treat the \meta{args} as Lua patterns rather
%     than converting from wildcards
%   \item |--recursive| (|-r|) Enables recursive searching during directory
%     listings
%   \item |--reverse| Causes sorting to go from highest to lowest rather
%     than lowest to highest
%   \item |--sort| Sets the method used to sort entries returned by |ls|
%   \item |--type| Selects the type of entry returned by |ls|
% \end{itemize}
% The action of these options on the appropriate \meta{cmd(s)} is detailed below.
% 
% \subsubsection{\texttt{ls [\meta{args}]}}
% 
% Lists the contents of one or more directories, in a manner somewhat reminiscent
% of the Unix command |ls| or the Windows command |dir|. The exact nature of the
% output will depend on the \meta{args}, if given, along with the prevailing
% options. Note that the options names are inspired by ideas from the Unix
% commands |ls| and |find| as well as the Windows command |dir|: they therefore do
% not map directly to those of any one of the command line tools that they
% somewhat mirror.
% 
% When no \meta{args} are given, all entries in the current directory will be
% listed, one per line in the output. This will include both files and
% subdirectories. Each entry will include a path relative to the current
% directory: for files \emph{in} the current directory, this will be |./|. The
% order of results will be determined by the underlying operating system process:
% unless requested \emph{via} an option, no sorting takes place.
% 
% As standard, the \meta{args} are treated as a file/path name potentially
% including |?| and |*| as wildcards, for example |*.png| or |file?.txt|.
% \begin{verbatim}
%   l3sys-query ls '*.png'
% \end{verbatim}
% Some care is needed in preventing expansion of such wildcards by the shell or
% \texttt{texlua} process: these are detailed in Section~\ref{sec:wildcard}. In
% this section, |'| is used to indicate a character being used to suppress
% expansion: this is for example normal on macOS and Linux.
% 
% Removal of entries from the listing can be achieved using the |--exclude|
% option, which should be given with a \meta{xarg}, for example
% \begin{verbatim}
%   l3sys-query ls --exclude '*.bak' 'graphics/*'
% \end{verbatim}
% Directory entries starting |.| are traditionally hidden on Linux and macOS
% systems: these \enquote{dot} entries are excluded from the output of
% \texttt{l3sys-query}. The entries |.| and |..| for the current and parent
% directory are also excluded from the results returned by \texttt{l3sys-query} as
% they can always be assumed.
% 
% For more complex matching, the \meta{args} can be treated as a Lua pattern using
% the |--pattern| (|-p|) option; this also applies to the \meta{xarg} argument to
% the |--exclude| option. For example, the equivalent to wildcard |*.png| could be
% obtained using
% \begin{verbatim}
%   l3sys-query ls --pattern '^.*%.png$'
% \end{verbatim}
% 
% The results returned by |ls| can be sorted using the |--sort| option. This can
% be set to |none| (use the order from the file system: the default), |name| (sort
% by file name) or |date| (sort by date last modified). The sorting order can be
% reversed using |--reverse|. Sorting normally takes account of case: this can be
% suppressed with the |--ignore-case| option.
% 
% The listing can be filtered based on the type of entry using the |--type|
% option. This takes a string argument, one of |d| (directory) or |f| (file).
% 
% As standard, only the path specified as part of the \meta{args} is queried.
% However, if the |--recursive| (|-r|) option is set, the query is applied within
% all subdirectories. Subdirectories starting with~|.| (macOS and Linux hidden)
% are excluded from recursion.
% 
% For security reasons, only paths within the current working directory can be
% queried, thus for example |graphics/*.png| will list all |png| files in the
% |graphics| subdirectory, but |../graphics/*.png| will yield no output.
% 
% \subsubsection{\texttt{pwd}}
% 
% Returns the current working directory from which \texttt{l3sys-query} is run.
% From within a \TeX{} run, this will (usually) be the directory containing the
% main file, assuming a command such as
% \begin{verbatim}
%   pdflatex main.tex
% \end{verbatim}
% The \texttt{pwd} command is unaffected by any options.
% 
% \subsection{Spaces in arguments}
% 
% Since \texttt{l3sys-query} is intended primarily for use with restricted shell
% escape calls from \TeX{} processes, handling of spaces is unusual. It is not
% possible to quote spaces in such a call, so for example whilst
% \begin{verbatim}
%   l3sys-query ls "foo *"
% \end{verbatim}
% does work from the command prompt to find all files with names starting
% \verb*|foo |, it would not work \emph{via} restricted shell escape. To
% circumvent this, \texttt{l3sys-query} will collect all command line arguments
% after any \meta{options}, and combine these as a space-separated \meta{args},
% for example allowing
% \begin{verbatim}
%   l3sys-query ls foo '*'
% \end{verbatim}
% to achieve the same result as the first example. The result is that the
% \meta{args} will only every be interpreted by \texttt{l3sys-query} as a single
% argument. It also means that spaces cannot be used at the start or end of the
% argument, nor can multiple spaces appear between non-space arguments.
% 
% \subsection{Wildcard expansion handling\label{sec:wildcard}}
% 
% The handling of wildcards needs some further comment for those using
% \texttt{l3sys-query} from the command line: the \pkg{expl3} interface described
% in Section~\ref{sec:expl3} handles this aspect automatically for the user.
% 
% On macOS and Linux, the shell normally expands globs, which include the
% wildcards |*| and |?|, before passing arguments to the appropriate command.
% This can be suppressed by surrounding the argument with |'| characters, hence
% the formulation
% \begin{verbatim}
%   l3sys-query ls '*.png'
% \end{verbatim}
% earlier.
% 
% On Windows, the shell does no expansion, and thus arguments are passed as-is to
% the relevant command. As such, |'| has no special meaning here. However, to
% allow quoting of wildcards from the shell in a platform-neutral manner,
% \texttt{l3sys-query} will strip exactly one set of |'| characters around each
% argument before further processing.
% 
% It is not possible to use |"| quotes at all in the argument passed to
% \texttt{l3sys-query} from \TeX{}, as the \TeX{} system removes all |"| in
% |\input| while handling space quoting.
% 
% Restricted shell escape prevents shell expansion of wildcards entirely. On
% non-Windows systems, it does this by ensuring that each argument is |'| quoted
% to ensure further expansion. Thus a \TeX{} call such as
% \begin{verbatim}
%   \input|"l3sys-query ls '*.png'"
% \end{verbatim}
% will work if |--shell-escape| is used as the argument is passed directly to the
% shell, but in restricted shell escape will give an error such as:
% \begin{verbatim}
% ! I can't find file `"|l3sys-query ls '*.png'"'.
% \end{verbatim}
% The \LaTeX{} interfaces described above adjust the quoting used depending on the
% |shell-escape| status.
% 
% 
% \MaybeStop{}
%
% \section{The \LaTeXe\ package implementation}
%
%    \begin{macrocode}
%<*package>
%    \end{macrocode}
%
%    \begin{macrocode}
\ExplSyntaxOn
%<@@=queryfiles>
%    \end{macrocode}
%
% The package should eventually work in restricted shell escape but will do
% nothing useful if the process was started with |--no-shell-escape|.
%    \begin{macrocode}
\sys_if_shell:F{
  \PackageWarningNoLine{l3sys-query}
  {Shell ~Escape ~is ~disabled.\MessageBreak All ~queries ~will ~return ~empty ~results}
  }
%    \end{macrocode}
%
% \subsection{\cs{QueryWorkingDirectory}}
% |\QueryWorkingDirectory| is a direct call to the |pwd| command provided by \texttt{l3sys-query}.
%    \begin{macrocode}
\NewDocumentCommand\QueryWorkingDirectory {m} {
  \sys_get_query:nN {pwd} #1
}
%    \end{macrocode}
%
% \subsection{\cs{QueryFiles} and \cs{QueryFilesTF}}
%
% The declarations of these commands are done in two steps to allow catcode chanes
% before the arguments are read. This allows the use of |%| and |^^| in patterns
% at least if the command is not nested in another command argument. (|\%| may be used
% to generate |%| in all cases).
%
% Variables for saving the current definition of |\%| and |~|.
%    \begin{macrocode}
\tl_new:N\l_query_percent_tl
\tl_new:N\l_query_tilde_tl
%    \end{macrocode}
%
% Allow |%| and |^^| at the top level.
%    \begin{macrocode}
\NewDocumentCommand\QueryFiles {} {
  \group_begin:
    \char_set_catcode_other:N \%
    \char_set_catcode_other:N \^
    \QueryFiles_inner
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\char_set_catcode_active:N \~
%    \end{macrocode}
%
%    \begin{macrocode}
\NewDocumentCommand\QueryFiles_inner {O{}m}{
  \group_end:
  \tl_set:Nn\l_tmpa_tl{}
  \cs_set_eq:NN  \l_query_percent_tl \%
  \cs_set_eq:NN  \% \c_percent_str
  \cs_set_eq:NN  \l_query_tilde_tl ~
  \cs_set_eq:NN  ~ \c_tilde_str
  \keys_set:nn{QueryFiles}{#1}
  \exp_args:NnV\sys_split_query:nnnN {ls} \l_tmpa_tl {#2} \l_tmpa_seq
  \cs_set_eq:NN  \% \l_query_percent_tl
  \cs_set_eq:NN  ~ \l_query_tilde_tl
  \seq_map_inline:Nn\l_tmpa_seq
}
%    \end{macrocode}
%
% This duplicates rather than shares code so as to read the function
% and TF arguments with normal catcode regime.
% (This could probably be optimised.)
%    \begin{macrocode}
\NewDocumentCommand\QueryFilesTF {} {
  \group_begin:
    \char_set_catcode_other:N \%
    \QueryFilesTF_inner
 }
%    \end{macrocode}
%
%    \begin{macrocode}
\NewDocumentCommand\QueryFilesTF_inner {O{}m}{
  \group_end:
  \tl_set:Nn\l_tmpa_tl{}
  \cs_set_eq:NN  \l_query_percent_tl \%
  \cs_set_eq:NN  \% \c_percent_str
  \cs_set_eq:NN  \l_query_tilde_tl ~
  \cs_set_eq:NN  ~ \c_tilde_str
  \keys_set:nn{QueryFiles}{#1}
  \exp_args:NnV\sys_split_query:nnnN {ls} \l_tmpa_tl {#2} \l_tmpa_seq
  \cs_set_eq:NN  \% \l_query_percent_tl
  \cs_set_eq:NN  ~ \l_query_tilde_tl
  \seq_if_empty:NTF \l_tmpa_seq \use_iii:nnn \__queryfiles_aux:nnn
}
%    \end{macrocode}
%
%    \begin{macrocode}
\char_set_catcode_space:N \~
%    \end{macrocode}
%
%    \begin{macrocode}
\cs_new:Npn  \__queryfiles_aux:nnn #1#2#3 {
    #2
    \seq_map_inline:Nn\l_tmpa_seq {#1}
 }
%    \end{macrocode}
%
% Defining the keys. Most take no value and simply add a \texttt{l3sys-query} \texttt{-{}-}
% option to the command linebeing constructed.
%    \begin{macrocode}
\keys_define:nn {QueryFiles} {
%    \end{macrocode}
%
%    \begin{macrocode}
recursive .code:n  =\tl_put_right:Nn \l_tmpa_tl {--recursive ~ } ,
recursive .value_forbidden:n = true ,
%    \end{macrocode}
%
%    \begin{macrocode}
ignore-case .code:n  =\tl_put_right:Nn \l_tmpa_tl {--ignore-case ~ } ,
ignore-case .value_forbidden:n = true ,
%    \end{macrocode}
%
%    \begin{macrocode}
reverse .code:n  =\tl_put_right:Nn \l_tmpa_tl {--reverse ~ } ,
reverse .value_forbidden:n = true ,
%    \end{macrocode}
%
%    \begin{macrocode}
exclude .code:n  =\tl_put_right:Ne \l_tmpa_tl {
  --exclude ~
  \sys_if_shell_restricted:F'
  \exp_not:n{#1}
  \sys_if_shell_restricted:F'
  ~ } ,
exclude .value_required:n = true ,
%    \end{macrocode}
%
% The |type| key checks the supplied value is valid |d| for directories
% or |f| for files The default behaviour lists both.
%    \begin{macrocode}
type .choices:nn = {d,f}
                   {\tl_put_right:Nn \l_tmpa_tl {--type ~ #1 ~ }} ,
%    \end{macrocode}
%
% The |sort| key checks the supplied value is valid |date| or |name|.
%    \begin{macrocode}
sort .choices:nn = {date,name}
{\tl_put_right:Nn \l_tmpa_tl {--sort ~ #1 ~ }} ,
%    \end{macrocode}
%
%    \begin{macrocode}
pattern .code:n  =\tl_put_right:Nn \l_tmpa_tl {--pattern ~ } ,
pattern .value_forbidden:n = true ,
%    \end{macrocode}
%
%    \begin{macrocode}
}
%    \end{macrocode}
%
%    \begin{macrocode}
\ExplSyntaxOff
%    \end{macrocode}
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \Finale
%