% \iffalse meta-comment
%
%% File: tagpdf.dtx
%
% Copyright (C) 2019-2023 Ulrike Fischer
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
% license or (at your option) any later version.  The latest version
% of this license is in the file
%
%    https://www.latex-project.org/lppl.txt
%
% This file is part of the "tagpdf bundle" (The Work in LPPL)
% and all files in that bundle must be distributed together.
%
% -----------------------------------------------------------------------
%
% The development version of the bundle can be found at
%
%    https://github.com/u-fischer/tagpdf
%
% for those people who are interested.
%
% \fi
% \begin{documentation}
% \begin{function}{\ref_value:nnn}
% This is a temporary definition which will have to
% move to l3ref. It allows to locally set a default value if the label or the attribute
% doesn't exist. See issue \#4 in Accessible-xref.
% \begin{syntax}
% \cs{ref_value:nnn}\Arg{label}\Arg{attribute}\Arg{fallback default}
% \end{syntax}
% \end{function}
%
% \begin{function}{ \tag_stop_group_begin:, \tag_stop_group_end:,
%  \tag_stop:, \tag_start: }
% We need commands to stop tagging in some places.
% There simply switches the two local booleans. The grouping commands
% can be used to group the effect.
% \end{function}
%
% \begin{function}{\tag_stop:n, \tag_start:n }%
% \begin{syntax}
% \cs{tag_stop:n}\Arg{label}
% \cs{tag_start:n}\Arg{label}\\
% \end{syntax}
% This commands are intended as a pair. The start command
% will only restart tagging if the previous stop command
% with the same label actually stopped tagging.
% \end{function}
%
% \begin{function}{activate-space (setup-key)}
%  |activate-space| activates the additional parsing needed for
%  interword spaces. It is not documented, the parsing is currently
%  implicitly activated by the known key |interwordspace|, as the code will
%  perhaps move to some other place, now that it is better separated.
% \end{function}
%
% \begin{function}{activate-mc (setup-key),
%    activate-tree (setup-key),
%    activate-struct (setup-key),
%    activate-all (setup-key)}
% Keys to activate the various tagging steps
% \end{function}
%\begin{function}{no-struct-dest (setup-key)}
% The key allows to suppress the creation of structure destinations
% \end{function}
%
% \begin{function}{log (setup-key)}
% The |log| takes currently the values |none|, |v|, |vv|, |vvv|, |all|.
% More details are in \texttt{tagpdf-checks}.
% \end{function}
%
% \begin{function}{tagunmarked (setup-key)}
% This key allows to set if (in luamode) unmarked text should be
% marked up as artifact. The initial value is true.
% \end{function}
%
% \begin{function}{tabsorder (setup-key)}
% This sets the tabsorder on a page. The values are |row|, |column|, |structure| (default)
% or |none|. Currently this is set more or less globally. More finer control can be
% added if needed.
% \end{function}
%
% \begin{function}{tagstruct,tagstructobj,tagabspage,tagmcabs,tagmcid}
% These are attributes used by the label/ref system.
% \end{function}
% \end{documentation}
% \begin{implementation}
% \section{Initialization and test if pdfmanagement is active.}
%    \begin{macrocode}
%<@@=tag>
%<*package>
\ProvidesExplPackage {tagpdf} {2023-03-07} {0.98e}
  { A package to experiment with pdf tagging }

\bool_if:nF
  {
    \bool_lazy_and_p:nn
      {\cs_if_exist_p:N \pdfmanagement_if_active_p:}
      { \pdfmanagement_if_active_p: }
  }
  {  %error for now, perhaps warning later.
    \PackageError{tagpdf}
     {
       PDF~resource~management~is~no~active!\MessageBreak
       tagpdf~will~no~work.
     }
     {
       Activate~it~with \MessageBreak
       \string\RequirePackage{pdfmanagement-testphase}\MessageBreak
       \string\DocumentMetadata{<options>}\MessageBreak
       before~\string\documentclass
     }
  }
%</package>
%    \end{macrocode}
%<*debug>
%    \begin{macrocode}
\ProvidesExplPackage {tagpdf-debug} {2023-03-07} {0.98e}
  { debug code for tagpdf }
\@ifpackageloaded{tagpdf}{}{\PackageWarning{tagpdf-debug}{tagpdf~not~loaded,~quitting}\endinput}
%    \end{macrocode}
%</debug>
% We map the internal module name \enquote{tag} to \enquote{tagpdf} in messages.
%    \begin{macrocode}
%<*package>
\prop_gput:Nnn \g_msg_module_name_prop { tag }{ tagpdf }
%</package>
%    \end{macrocode}
% Debug mode has its special mapping:
%    \begin{macrocode}
%<*debug>
\prop_gput:Nnn \g_msg_module_type_prop { tag / debug} {}
\prop_gput:Nnn \g_msg_module_name_prop { tag / debug }{tagpdf~DEBUG}
%</debug>
%    \end{macrocode}
%\section{base package}
% To avoid to have to test everywhere if tagpdf has been loaded and is active,
% we define a base package with dummy functions
%    \begin{macrocode}
%<*base>
\ProvidesExplPackage {tagpdf-base} {2023-03-07} {0.98e}
  {part of tagpdf - provide base, no-op versions of the user commands }
%</base>
%    \end{macrocode} 
%\section{Package options}
% There are only two options to switch for luatex between generic and luamode,
% TODO try to get rid of them.
%    \begin{macrocode}
%<*package>
\bool_new:N\g_@@_mode_lua_bool  
\DeclareOption {luamode}    { \sys_if_engine_luatex:T { \bool_gset_true:N \g_@@_mode_lua_bool } }
\DeclareOption {genericmode}{ \bool_gset_false:N\g_@@_mode_lua_bool }
\ExecuteOptions{luamode}
\ProcessOptions
%    \end{macrocode}
% \section{Packages}
% We need the temporary version of l3ref until this is in the kernel.
%    \begin{macrocode}
\RequirePackage{l3ref-tmp}
%    \end{macrocode}
% To be on the safe side for now, load also the base definitions
%    \begin{macrocode}
\RequirePackage{tagpdf-base}
%</package>
%    \end{macrocode}
% The no-op version should behave a near enough to the real code as
% possible, so we define a command which a special in the relevant backends:
%    \begin{macrocode}
%<*base>
\AddToHook{begindocument}
 {
  \str_case:VnF \c_sys_backend_str
   {
    { luatex  } { \cs_new_protected:Npn \@@_whatsits: {} }
    { dvisvgm } { \cs_new_protected:Npn \@@_whatsits: {} }
   }
   {
     \cs_new_protected:Npn \@@_whatsits: {\tex_special:D {} }
   }
 }
%</base>
%    \end{macrocode}

% \subsection{a LastPage label}
% See also issue \#2 in Accessible-xref
% \begin{macro}{\@@_lastpagelabel:}
%    \begin{macrocode}
%<*package>
 \cs_new_protected:Npn \@@_lastpagelabel:
   {
     \legacy_if:nT { @filesw }
       {
         \exp_args:NNnx \exp_args:NNx\iow_now:Nn \@auxout
            {
              \token_to_str:N \newlabeldata
                {@@_LastPage}
                {
                  {abspage} { \int_use:N \g_shipout_readonly_int}
                  {tagmcabs}{ \int_use:N \c@g_@@_MCID_abs_int }
                  {tagstruct}{\int_use:N \c@g_@@_struct_abs_int }
                }
            }
       }
   }

 \AddToHook{enddocument/afterlastpage}
  {\@@_lastpagelabel:}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ref_value:nnn}
% This allows to locally set a default value if the label or the attribute
% doesn't exist.
%    \begin{macrocode}
 \cs_if_exist:NF \ref_value:nnn
   {
     \cs_new:Npn \ref_value:nnn #1#2#3
       {
         \exp_args:Nee
           \__ref_value:nnn
            { \tl_to_str:n {#1} } { \tl_to_str:n {#2} } {#3}
       }
     \cs_new:Npn \__ref_value:nnn #1#2#3
       {
         \tl_if_exist:cTF { g__ref_label_ #1 _ #2 _tl }
           { \tl_use:c { g__ref_label_ #1 _ #2 _tl } }
           {
             #3
           }
       }
   }
%    \end{macrocode}
% \end{macro}

% \section{Variables}
% \begin{variable}
%  {
%    \l_@@_tmpa_tl,
%    \l_@@_tmpb_tl,
%    \l_@@_get_tmpc_tl,    
%    \l_@@_get_parent_tmpa_tl
%    \l_@@_get_parent_tmpb_tl    
%    \l_@@_tmpa_str,
%    \l_@@_tmpa_prop,
%    \l_@@_tmpa_seq,
%    \l_@@_tmpb_seq,
%    \l_@@_tmpa_clist,
%    \l_@@_tmpa_int,
%    \l_@@_tmpa_box,
%    \l_@@_tmpb_box
%  }
% A few temporary variables
%    \begin{macrocode}
\tl_new:N    \l_@@_tmpa_tl
\tl_new:N    \l_@@_tmpb_tl
\tl_new:N    \l_@@_get_tmpc_tl
\tl_new:N    \l_@@_get_parent_tmpa_tl
\tl_new:N    \l_@@_get_parent_tmpb_tl
\str_new:N   \l_@@_tmpa_str
\prop_new:N  \l_@@_tmpa_prop
\seq_new:N   \l_@@_tmpa_seq
\seq_new:N   \l_@@_tmpb_seq
\clist_new:N \l_@@_tmpa_clist
\int_new:N   \l_@@_tmpa_int
\box_new:N   \l_@@_tmpa_box
\box_new:N   \l_@@_tmpb_box
%    \end{macrocode}
% \end{variable}
% Attribute lists for the label command. We have a list for
% mc-related labels, and one for structures.
% \begin{macro}{\c_@@_refmc_clist,\c_@@_refstruct_clist}
%    \begin{macrocode}
\clist_const:Nn \c_@@_refmc_clist     {tagabspage,tagmcabs,tagmcid}
\clist_const:Nn \c_@@_refstruct_clist {tagstruct,tagstructobj}
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\l_@@_loglevel_int}
% This integer hold the log-level and so allows to
% control the messages.
% TODO: a list which log-level shows what is needed. The current behaviour
% is quite ad-hoc.
%    \begin{macrocode}
\int_new:N  \l_@@_loglevel_int
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%  {
%    \g_@@_active_space_bool,
%    \g_@@_active_mc_bool,
%    \g_@@_active_tree_bool,
%    \g_@@_active_struct_bool,
%    \g_@@_active_struct_dest_bool
%  }
% These booleans should help to control the global behaviour of tagpdf.
% Ideally it should more or less do nothing if all are false.
% The space-boolean controles the interword space code,
% the mc-boolean activates \cs{tag_mc_begin:n},
% the tree-boolean activates writing the finish code and the pdfmanagement related
% commands, the struct-boolean activates the storing of the structure data.
% In a normal document all should be active, the split is only there for
% debugging purpose.
% Structure destination will be activated automatically if pdf version 2.0 is detected,
% but with the boolean struct-dest-boolean one can suppress them.
% Also we assume currently that they are set only at begin document. But
% if some control passing over groups are needed they could be perhaps
% used in a document too.
% TODO: check if they are used everywhere as needed and as wanted.
%    \begin{macrocode}
\bool_new:N \g_@@_active_space_bool
\bool_new:N \g_@@_active_mc_bool
\bool_new:N \g_@@_active_tree_bool
\bool_new:N \g_@@_active_struct_bool
\bool_new:N \g_@@_active_struct_dest_bool
\bool_gset_true:N \g_@@_active_struct_dest_bool
%    \end{macrocode}
% \end{variable}

% \begin{variable}
%  {
%    \l_@@_active_mc_bool,
%    \l_@@_active_struct_bool
%  }
% These booleans should help to control the \emph{local} behaviour of tagpdf.
% In some cases it could e.g. be necessary to stop tagging completely.
% As local booleans they respect groups.
% TODO: check if they are used everywhere as needed and as wanted.
%    \begin{macrocode}
\bool_new:N \l_@@_active_mc_bool
\bool_set_true:N \l_@@_active_mc_bool
\bool_new:N \l_@@_active_struct_bool
\bool_set_true:N \l_@@_active_struct_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\g_@@_tagunmarked_bool}
% This boolean controls if the code should try to automatically
% tag parts not in mc-chunk. It is currently only used in luamode.
% It would be possible to used it in generic mode, but this would create
% quite a lot empty artifact mc-chunks.
%    \begin{macrocode}
\bool_new:N \g_@@_tagunmarked_bool
%    \end{macrocode}
% \end{variable}
%
% \section{Variants of l3 commands}
%     \begin{macrocode}
\prg_generate_conditional_variant:Nnn \pdf_object_if_exist:n {e}{T,F}
\cs_generate_variant:Nn \pdf_object_ref:n {e}
\cs_generate_variant:Nn \pdfannot_dict_put:nnn {nnx}
\cs_generate_variant:Nn \pdffile_embed_stream:nnn {nxx,oxx}
\cs_generate_variant:Nn \prop_gput:Nnn {Nxx,Nen}
\cs_generate_variant:Nn \prop_put:Nnn  {Nxx}
\cs_generate_variant:Nn \prop_item:Nn {No,Ne}
\cs_generate_variant:Nn \ref_label:nn { nv }
\cs_generate_variant:Nn \seq_set_split:Nnn{Nne}
\cs_generate_variant:Nn \str_set_convert:Nnnn {Nonn, Noon, Nnon }
\cs_generate_variant:Nn \clist_map_inline:nn {on}
%    \end{macrocode}

% \section{Setup label attributes}
% \begin{macro}{tagstruct,tagstructobj,tagabspage,tagmcabs,tagmcid}
% This are attributes used by the label/ref system.
% With structures we store the structure number |tagstruct|
% and the object reference |tagstructobj|.
% The second is needed to be able to reference a structure which hasn't been
% created yet. The alternative would be to create the object in such cases,
% but then we would have to check the object existence all the time.
%
% With mc-chunks we store the absolute page number |tagabspage|,
% the absolute id |tagmcabc|, and the id on the page |tagmcid|.
%    \begin{macrocode}
\ref_attribute_gset:nnnn { tagstruct } {0} { now }
  { \int_use:N \c@g_@@_struct_abs_int }
\ref_attribute_gset:nnnn { tagstructobj } {} { now }
  {
    \pdf_object_if_exist:eT {@@/struct/\int_use:N \c@g__tag_struct_abs_int}
      {
        \pdf_object_ref:e{@@/struct/\int_use:N \c@g_@@_struct_abs_int}
      }
  }
\ref_attribute_gset:nnnn { tagabspage } {0} { shipout }
  { \int_use:N \g_shipout_readonly_int }
\ref_attribute_gset:nnnn { tagmcabs } {0} { now }
  { \int_use:N \c@g_@@_MCID_abs_int }
\ref_attribute_gset:nnnn {tagmcid }  {0} { now }
  { \int_use:N \g_@@_MCID_tmp_bypage_int }
%    \end{macrocode}
% \end{macro}
%
% \section{Label commands}
% \begin{macro}{\@@_ref_label:nn}
% A version of |\ref_label:nn| to set a label
% which takes a keyword |mc| or |struct| to
% call the relevant lists.
% TODO: check if |\@bsphack| and |\@esphack| make sense here.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_ref_label:nn #1 #2 %#1 label, #2 name of list mc or struct
  {
    \@bsphack
    \ref_label:nv {#1}{c_@@_ref#2_clist}
    \@esphack
  }
\cs_generate_variant:Nn \@@_ref_label:nn {en}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\@@_ref_value:nnn}
% A local version to retrieve the value. It is a direct wrapper,
% but to keep naming consistent \ldots. It uses the variant defined temporarly
% above.
%    \begin{macrocode}
\cs_new:Npn \@@_ref_value:nnn #1 #2 #3 %#1 label, #2 attribute, #3 default
  {
    \ref_value:nnn {#1}{#2}{#3}
  }
\cs_generate_variant:Nn \@@_ref_value:nnn {enn}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_ref_value_lastpage:nn}
% A command to retrieve the lastpage label, this will be adapted when there
% is a proper, kernel lastpage label.
%    \begin{macrocode}
\cs_new:Npn \@@_ref_value_lastpage:nn #1 #2
  {
    \ref_value:nnn {@@_LastPage}{#1}{#2}
  }
%    \end{macrocode}
%\end{macro}



%\section{Commands to fill seq and prop}
% With most engines these are simply copies of the expl3 commands,
% but luatex will overwrite them, to store the data also in lua tables.
% \begin{macro}
%  {
%    \@@_prop_new:N
%    ,\@@_seq_new:N
%    ,\@@_prop_gput:Nnn
%    ,\@@_seq_gput_right:Nn
%    ,\@@_seq_item:cn
%    ,\@@_prop_item:cn
%    ,\@@_seq_show:N
%    ,\@@_prop_show:N
%  }
%    \begin{macrocode}
\cs_set_eq:NN \@@_prop_new:N        \prop_new:N
\cs_set_eq:NN \@@_seq_new:N         \seq_new:N
\cs_set_eq:NN \@@_prop_gput:Nnn     \prop_gput:Nnn
\cs_set_eq:NN \@@_seq_gput_right:Nn \seq_gput_right:Nn
\cs_set_eq:NN \@@_seq_item:cn       \seq_item:cn
\cs_set_eq:NN \@@_prop_item:cn      \prop_item:cn
\cs_set_eq:NN \@@_seq_show:N        \seq_show:N
\cs_set_eq:NN \@@_prop_show:N       \prop_show:N

\cs_generate_variant:Nn \@@_prop_gput:Nnn      { Nxn , Nxx, Nnx , cnn, cxn, cnx, cno}
\cs_generate_variant:Nn \@@_seq_gput_right:Nn  { Nx  , No, cn, cx }
\cs_generate_variant:Nn \@@_prop_new:N   { c }
\cs_generate_variant:Nn \@@_seq_new:N    { c }
\cs_generate_variant:Nn \@@_seq_show:N   { c }
\cs_generate_variant:Nn \@@_prop_show:N  { c }
%    \end{macrocode}
% \end{macro}
%
% \section{General tagging commands}
%
% \begin{macro}{\tag_stop_group_begin:,
%   \tag_stop_group_end:,
%   \tag_stop:,\tag_start:,
%   \tag_stop:n,\tag_start:n}
% We need commands to stop tagging in some places.
% This simply switches the two local booleans.
% In some cases tagging should only restart, if
% it actually was stopped before. For this it is possible
% to label a stop.
%    \begin{macrocode}
\cs_new_protected:Npn \tag_stop_group_begin:
  {
    \group_begin:
    \bool_set_false:N \l_@@_active_struct_bool
    \bool_set_false:N \l_@@_active_mc_bool
  }
\cs_set_eq:NN \tag_stop_group_end: \group_end:
\cs_set_protected:Npn \tag_stop:
  {
    \bool_set_false:N \l_@@_active_struct_bool
    \bool_set_false:N \l_@@_active_mc_bool
  }
\cs_set_protected:Npn \tag_start:
  {
    \bool_set_true:N \l_@@_active_struct_bool
    \bool_set_true:N \l_@@_active_mc_bool
  }
\prop_new:N\g_@@_state_prop
\cs_set_protected:Npn \tag_stop:n #1
  {
    \tag_if_active:TF
      {
        \bool_set_false:N \l_@@_active_struct_bool
        \bool_set_false:N \l_@@_active_mc_bool
        \prop_gput:Nnn \g_@@_state_prop { #1 }{ 1 }
      }
      {
        \prop_gremove:Nn \g_@@_state_prop { #1 }
      }
  }
\cs_set_protected:Npn \tag_start:n #1
  {
    \prop_gpop:NnN \g_@@_state_prop {#1}\l_@@_tmpa_tl
     \quark_if_no_value:NF \l_@@_tmpa_tl
      {
        \bool_set_true:N \l_@@_active_struct_bool
        \bool_set_true:N \l_@@_active_mc_bool
      }
  }
%</package>
%<*base>
\cs_new_protected:Npn \tag_stop:{}
\cs_new_protected:Npn \tag_start:{}
\cs_new_protected:Npn \tag_stop:n  #1 {}
\cs_new_protected:Npn \tag_start:n #1 {}
%</base>
%    \end{macrocode}
% \end{macro}
%
%
% \section{Keys for tagpdfsetup}

% TODO: the log-levels must be sorted
%
% \begin{macro}
%  {
%    activate-space (setup-key),
%    activate-mc (setup-key),
%    activate-tree (setup-key),
%    activate-struct (setup-key),
%    activate-all (setup-key),
%    no-struct-dest (setup-key)
%  }
%  Keys to (globally) activate tagging.
%  |activate-space| activates the additional parsing needed for
%  interword spaces. It is not documented, the parsing is currently
%  implicitly activated by the known key |interwordspace|, as the code will
%  perhaps move to some other place, now that it is better separated.
%  |no-struct-dest| allows to suppress structure destinations.
%    \begin{macrocode}
%<*package>
\keys_define:nn { @@ / setup }
  {
    activate-space  .bool_gset:N = \g_@@_active_space_bool,
    activate-mc     .bool_gset:N = \g_@@_active_mc_bool,
    activate-tree   .bool_gset:N = \g_@@_active_tree_bool,
    activate-struct .bool_gset:N = \g_@@_active_struct_bool,
    activate-all    .meta:n =
      {activate-mc={#1},activate-tree={#1},activate-struct={#1}},
    activate-all  .default:n = true,
    no-struct-dest .bool_gset_inverse:N = \g_@@_active_struct_dest_bool,
 %    \end{macrocode}
% \end{macro}
% \begin{macro}{log (setup-key)}
% The |log| takes currently the values |none|, |v|, |vv|, |vvv|, |all|.
% The description of the log levels is in tagpdf-checks.
%    \begin{macrocode}
    log             .choice:,
    log / none      .code:n = {\int_set:Nn \l_@@_loglevel_int { 0 }},
    log / v         .code:n =
      {
        \int_set:Nn \l_@@_loglevel_int { 1 }
        \cs_set_protected:Nn \@@_check_typeout_v:n { \iow_term:x {##1} }
      },
    log / vv        .code:n = {\int_set:Nn \l_@@_loglevel_int { 2 }},
    log / vvv       .code:n = {\int_set:Nn \l_@@_loglevel_int { 3 }},
    log / all       .code:n = {\int_set:Nn \l_@@_loglevel_int { 10 }},
%    \end{macrocode}
% \end{macro}
% \begin{macro}{tagunmarked (setup-key)}
% This key allows to set if (in luamode) unmarked text should be
% marked up as artifact. The initial value is true.
%    \begin{macrocode}
    tagunmarked     .bool_gset:N = \g_@@_tagunmarked_bool,
    tagunmarked     .initial:n  = true,
%    \end{macrocode}
% \end{macro}
% \begin{macro}{tabsorder (setup-key)}
% This sets the tabsorder on a page. The values are |row|, |column|, |structure| (default)
% or |none|. Currently this is set more or less globally. More finer control can be
% added if needed.
%    \begin{macrocode}
    tabsorder       .choice:,
    tabsorder / row       .code:n =
      \pdfmanagement_add:nnn { Page } {Tabs}{/R},
    tabsorder / column    .code:n =
      \pdfmanagement_add:nnn { Page } {Tabs}{/C},
    tabsorder / structure .code:n =
      \pdfmanagement_add:nnn { Page } {Tabs}{/S},
    tabsorder / none      .code:n =
      \pdfmanagement_remove:nn {Page} {Tabs},
    tabsorder       .initial:n = structure,
    uncompress      .code:n = { \pdf_uncompress:  },
  }
%    \end{macrocode}
% \end{macro}
% \section{loading of engine/more dependent code}
%    \begin{macrocode}
\sys_if_engine_luatex:T
  {
    \file_input:n {tagpdf-luatex.def}
  }
%</package>
%    \end{macrocode}
%    \begin{macrocode}
%<*mcloading>
\bool_if:NTF \g_@@_mode_lua_bool
  {
   \RequirePackage {tagpdf-mc-code-lua}
  }
  {
   \RequirePackage {tagpdf-mc-code-generic} %
  }
%</mcloading>
%<*debug>
\bool_if:NTF \g_@@_mode_lua_bool
  {
   \RequirePackage {tagpdf-debug-lua}
  }
  {
   \RequirePackage {tagpdf-debug-generic} %
  }
%</debug>
%    \end{macrocode}
% \end{implementation}
% \PrintIndex
