Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


SSL GAPDoc2HTML.gi   Sprache: unbekannt

 
Spracherkennung für: .gi vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

#############################################################################
##
#W  GAPDoc2HTML.gi                 GAPDoc                        Frank Lübeck
##
##
#Y  Copyright (C)  2000,  Frank Lübeck,  Lehrstuhl D für Mathematik,  
#Y  RWTH Aachen
##
##  The  files GAPDoc2HTML.g{d,i}  contain  a  conversion program  which
##  produces from a  GAPDoc XML-document an HTML version for reading the
##  document with a Web-browser.
##  

##  REMARKS:
##  
##  We add to all  nodes of the parse tree an entry  .root which points to
##  the document root.  The toc-, index- and  bib-information is collected
##  in the root.
##  
##  The set  of elements  is partitioned  into two  subsets -  those which
##  contain whole paragraphs and those which don't.
##  
##  The     handler    of   a   paragraph     containing    element   (see
##  GAPDoc2HTMLProcs.ParEls below)  gets a  list as  argument to  which it
##  adds entries pairwise:   the first of such a   pair is  the  paragraph
##  counter (like [3,2,1,5] meaning Chap.3,   Sec.2, Subsec.1, Par.5)  and
##  the second is the formatted text of this paragraph.
##  
##  Some   handlers  of paragraph   containing  elements do the formatting
##  themselves (e.g., .List), the others are handled in the main recursion
##  function `GAPDoc2HTMLContent'.
##  
##  We produce  a full version of  the document in HTML  format, including
##  title  page,  abstract and  other  front  matter, table  of  contents,
##  bibliography (via  BibTeX-data files) and  index. For this we  have to
##  process a document twice (similar to LaTeX).
##  

##  Small utility to throw away SGML markup
BindGlobal("FilterSGMLMarkup", function(str)
  local p2, p1, res;
  p2 := Position(str, '<');
  if p2 = fail then
    return str;
  fi;
  p1 := 0;
  res := "";
  while p2 <> fail do
    Append(res, str{[p1+1..p2-1]});
    p1 := Position(str, '>', p2);
    if p1 = fail then
      return res;
    fi;
    p2 := Position(str, '<', p1);
    if p2 = fail then
      Append(res, str{[p1+1..Length(str)]});
      return res;
    fi;
  od;
end);

    

InstallValue(GAPDoc2HTMLProcs, rec());

##  Some text attributes ([begin, end] pairs)
GAPDoc2HTMLProcs.TextAttr := rec();
GAPDoc2HTMLProcs.TextAttr.Heading := ["<span class=\"Heading\">", "</span>"];

GAPDoc2HTMLProcs.TextAttr.Func := ["<code class=\"func\">", "</code>"];
GAPDoc2HTMLProcs.TextAttr.Arg := ["<var class=\"Arg\">", "</var>"];
GAPDoc2HTMLProcs.TextAttr.Example := ["<div class=\"Example\">", "</div>"];
GAPDoc2HTMLProcs.TextAttr.Package := ["<strong class=\"pkg\">", "</strong>"];
GAPDoc2HTMLProcs.TextAttr.URL := ["<span class=\"URL\">", "</span>"];
GAPDoc2HTMLProcs.TextAttr.Mark := ["<strong class=\"Mark\">", "</strong>"];

GAPDoc2HTMLProcs.TextAttr.K := ["<code class=\"keyw\">", "</code>"];
GAPDoc2HTMLProcs.TextAttr.C := ["<code class=\"code\">", "</code>"];
GAPDoc2HTMLProcs.TextAttr.F := ["<code class=\"file\">", "</code>"];
GAPDoc2HTMLProcs.TextAttr.I := ["<code class=\"i\">", "</code>"];
GAPDoc2HTMLProcs.TextAttr.B := ["<strong class=\"button\">", "</strong>"];
GAPDoc2HTMLProcs.TextAttr.Emph := ["<em>", "</em>"];
GAPDoc2HTMLProcs.TextAttr.Ref := ["<span class=\"RefLink\">", "</span>"];
GAPDoc2HTMLProcs.TextAttr.M := ["<span class=\"SimpleMath\">", "</span>"];
GAPDoc2HTMLProcs.TextAttr.Math := ["<span class=\"Math\">", "</span>"];
GAPDoc2HTMLProcs.TextAttr.GAPprompt := 
                                ["<span class=\"GAPprompt\">", "</span>"];
GAPDoc2HTMLProcs.TextAttr.GAPbrkprompt := 
                                ["<span class=\"GAPbrkprompt\">", "</span>"];
GAPDoc2HTMLProcs.TextAttr.GAPinput := 
                                ["<span class=\"GAPinput\">", "</span>"];

# like in Text converter, but a heading and an address are not a paragraph here
GAPDoc2HTMLProcs.ParEls := 
[ "Display", "Example", "Log", "Listing", "List", "Enum", "Item", "Table", 
  "TitlePage", "Abstract", "Copyright", "Acknowledgements",
  "Colophon", "TableOfContents", "Bibliography", "TheIndex",
  "Subsection", "ManSection", "Description", "Returns", "Section",
  "Chapter", "Appendix", "Body", "Book", "WHOLEDOCUMENT", "Attr", "Fam",
  "Filt", "Func", "InfoClass", "Meth", "Oper", "Constr", "Prop", "Var", "Verb"];

##  arg: a list of strings
##  for now only ??????
SetGapDocHTMLOptions := function(arg)    
  local   gdp;
  gdp := GAPDoc2HTMLProcs;
  return;  
end;

GAPDoc2HTMLProcs.Head1 := "\
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
\n\
<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n\
         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\
\n\
<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n\
<head>\n\
<title>GAP (";

GAPDoc2HTMLProcs.MathJaxURL := "https://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js?config=TeX-AMS-MML_HTMLorMML";

GAPDoc2HTMLProcs.Head1MathJax := "\
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
\n\
<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n\
         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\
\n\
<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n\
<head>\n\
<script type=\"text/javascript\"\n\
  src=\"MATHJAXURL\">\n\
</script>\n\
<title>GAP (";

GAPDoc2HTMLProcs.Head1Trans := "\
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
\n\
<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n\
         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\
\n\
<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n\
<head>\n\
<title>GAP (";

GAPDoc2HTMLProcs.Head1MML := "\
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<?xml-stylesheet type=\"text/xsl\" href=\"mathml.xsl\"?>\n\
\n\
<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN\"\n\
       \"http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd\" [\n\
       <!ENTITY mathml \"https://www.w3.org/1998/Math/MathML\">\n\
       ] >\n\
\n\
<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n\
<head>\n\
<link rel=\"stylesheet\" type=\"text/css\" href=\"mathml.css\" />\n\
<title>GAP (";

GAPDoc2HTMLProcs.Head2 := "\
</title>\n\
<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\" />\n\
<meta name=\"generator\" content=\"GAPDoc2HTML\" />\n\
<link rel=\"stylesheet\" type=\"text/css\" href=\"manual.css\" />\n\
<script src=\"manual.js\" type=\"text/javascript\"></script>\n\
<script type=\"text/javascript\">overwriteStyle();</script>\n\
</head>\n<body onload=\"jscontent()\">\n";

GAPDoc2HTMLProcs.Tail := "\n\
<hr />\n\
<p class=\"foot\">generated by <a \
href=\"https://www.math.rwth-aachen.de/~Frank.Luebeck/GAPDoc\">GAPDoc2HTML\
</a></p>\
\n</body>\n</html>\n";  

GAPDoc2HTMLProcs.PutFilesTogether := function(l, r)
  local   files,  n,  tt,  i, chnrs, chlink, prev, next, toplink;
  
  chnrs := Set(List([2,4..Length(l)], i-> l[i-1][1]));
  chnrs := Concatenation(Filtered(chnrs, a-> not a in ["Bib", "Ind"]),
                         Filtered(chnrs, a-> a in ["Bib", "Ind"]));
  chlink := Concatenation("\n<div class=\"chlinktop\"><span class=\"chlink1\">",
            GAPDocTexts.d.GotoChapter, ": </span>");
  for n in chnrs do
    Append(chlink, Concatenation("<a href=\"chap", String(n), 
           GAPDoc2HTMLProcs.ext, "\">"));
    if n = 0 then
      Append(chlink, GAPDocTexts.d.Top);
    else
      Append(chlink, String(n));
    fi;
    Append(chlink,"</a>  ");
  od;
  Append(chlink, "</div>\n");
  
  toplink := Concatenation( " <a href=\"chap0", GAPDoc2HTMLProcs.ext, 
             "\">[", GAPDocTexts.d.TopofBook, "]</a>   ",
             "<a href=\"chap0", GAPDoc2HTMLProcs.ext, "#contents",
             "\">[", GAPDocTexts.d.Contents, "]</a>   " );
  prev := [];
  next := [];
  for i in [1..Length(chnrs)] do
    if i > 1 then
      Add(prev, Concatenation(" <a href=\"chap", String(chnrs[i-1]),
                  GAPDoc2HTMLProcs.ext, "\">[", GAPDocTexts.d.PreviousChapter,
                  "]</a>   "));
    else
      Add(prev, "");
    fi;
    if i < Length(chnrs) then
      Add(next, Concatenation(" <a href=\"chap", String(chnrs[i+1]),
                        GAPDoc2HTMLProcs.ext, "\">[", GAPDocTexts.d.NextChapter,
                        "]</a>   "));
    else
      Add(next, "");
    fi;
  od;
  # putting the paragraphs together (one string (file) for each chapter)
  files := rec();
  for i in [1..Length(chnrs)] do
    n := chnrs[i];
    if r.root.mathmode = "MathML" then
      # this MathML is no longer documented
      files.(n) := rec(text := 
                   ShallowCopy(GAPDoc2HTMLProcs.Head1MML), ssnr := []);
    elif r.root.mathmode = "Tth" then
      files.(n) := rec(text :=
                   ShallowCopy(GAPDoc2HTMLProcs.Head1Trans), ssnr := []);
    elif r.root.mathmode = "MathJax" then
      files.(n) := rec(text := SubstitutionSublist(
                               GAPDoc2HTMLProcs.Head1MathJax, "MATHJAXURL", 
                               GAPDoc2HTMLProcs.MathJaxURL), ssnr := []);
    else
      files.(n) := rec(text := ShallowCopy(GAPDoc2HTMLProcs.Head1), ssnr := []);
    fi;
    tt := Concatenation(r.bookname, ") - ");
    if n=0 then
      Append(tt, GAPDocTexts.d.Contents);
    elif IsInt(n) then
      Append(tt, Concatenation(GAPDocTexts.d.Chapter, " ", String(n), ": ", 
             FilterSGMLMarkup(r.chaptitle.(n))));
    elif n="Bib" then
      Append(tt, GAPDocTexts.d.References);
    elif n="Ind" then
      Append(tt, GAPDocTexts.d.Index);
    else
      Append(tt, Concatenation(GAPDocTexts.d.Appendix, " ", n, ": ", 
             FilterSGMLMarkup(r.chaptitle.(n))));
    fi;
    Append(files.(n).text, tt);
    Append(files.(n).text, GAPDoc2HTMLProcs.Head2);
    # allow for chapter-wise CSS config
    files.(n).text := SubstitutionSublist(files.(n).text, "<body", 
                        Concatenation("<body class=\"chap", String(n), "\" "));
    Append(files.(n).text, Concatenation("\n", chlink));
    Append(files.(n).text, Concatenation(
           "\n<div class=\"chlinkprevnexttop\">",
           toplink, prev[i], next[i], "</div>\n\n"));
    if IsBound(r.root.LinkToMathJax) then
      # cross link to same chapter with MathJax enabled
      Append(files.(n).text,
                Concatenation("<p id=\"mathjaxlink\" ",
                "class=\"pcenter\"><a href=\"chap",
                String(n), "_mj.html\">[MathJax on]</a></p>\n"));
    elif r.root.mathmode = "MathJax" then
      # cross link to non-MathJax version
      Append(files.(n).text,
                Concatenation("<p id=\"mathjaxlink\" ",
                "class=\"pcenter\"><a href=\"chap",
                String(n), ".html\">[MathJax off]</a></p>\n"));
    else
      # we still want the hook for the [Style] link
      Append(files.(n).text, 
                Concatenation("<p id=\"mathjaxlink\" ",
                "class=\"pcenter\"></p>\n"));
    fi;
  od;
  for i in [2,4..Length(l)] do
    n := files.(l[i-1][1]);
    if Length(n.ssnr)=0 or l[i-1]{[1..3]} <> n.ssnr[Length(n.ssnr)] then
      Add(n.ssnr, l[i-1]{[1..3]});
      tt := GAPDoc2HTMLProcs.SectionLabel(r, l[i-1], "Subsection")[2];
      Append(n.text, Concatenation("<p><a id=\"", tt, "\" name=\"", tt, 
                                   "\"></a></p>\n"));
    fi;

    Append(n.text, l[i]);
  od;
  
  for i in [1..Length(chnrs)] do
    n := chnrs[i];
    Append(files.(n).text, Concatenation(
           "\n<div class=\"chlinkprevnextbot\">",
           toplink, prev[i], next[i], "</div>\n\n"));
    Append(files.(n).text,  SubstitutionSublist(chlink, "chlinktop",
                                                      "chlinkbot", false));
    Append(files.(n).text, GAPDoc2HTMLProcs.Tail);
  od;
  # finally tell result the file extensions
  files.ext := GAPDoc2HTMLProcs.ext;
  return files;
end;

##  
##  <#GAPDoc Label="GAPDoc2HTML">
##  <ManSection >
##  <Func Arg="tree[, bibpath[, gaproot]][, mtrans]" Name="GAPDoc2HTML" />
##  <Returns>record  containing  HTML  files  as  strings  and  other
##  information</Returns>
##  <Description>
##  <Index Key="MathJax"><Package>MathJax</Package></Index>
##  The   argument  <A>tree</A>   for   this  function   is  a   tree
##  describing  a   &GAPDoc;  XML   document  as  returned   by  <Ref
##  Func="ParseTreeXMLString"  /> (probably  also  checked with  <Ref
##  Func="CheckAndCleanGapDocTree"  />).   Without  an  <A>mtrans</A>
##  argument this function  produces an HTML version  of the document
##  which can  be read  with any  Web-browser and  also be  used with
##  &GAP;'s online help (see <Ref BookName="Ref" Func="SetHelpViewer"
##  />).  It  includes  title  page,  bibliography,  and  index.  The
##  bibliography is made from &BibTeX; databases. Their location must
##  be given with the argument <A>bibpath</A> (as string or directory
##  object, if not given the current directory is used). If the third
##  argument <A>gaproot</A> is given and is a string then this string
##  is  interpreted as relative  path to &GAP;'s main root directory.
##  Reference-URLs to external HTML-books  which begin with the &GAP;
##  root path  are then  rewritten to start  with the  given relative
##  path.  This  makes  the HTML-documentation  portable  provided  a
##  package is  installed in some  standard location below  the &GAP;
##  root.<P/>
##  
##  The  output is  a  record  with one  component  for each  chapter
##  (with  names   <C>"0"</C>,  <C>"1"</C>,  ...,   <C>"Bib"</C>, and
##  <C>"Ind"</C>).  Each  such  component   is again  a  record  with
##  the following components: 
##  
##  <List >
##  <Mark><C>text</C></Mark>
##  <Item>the text of an HTML file containing the whole chapter (as a
##  string)</Item>
##  <Mark><C>ssnr</C></Mark>
##  <Item>list of subsection numbers in  this chapter (like <C>[3, 2,
##  1]</C>  for  chapter 3,  section 2,  subsection 1)
##  </Item>
##  </List>
##  
##  <Emph>Standard output format without</Emph> <A>mtrans</A> 
##  <Emph>argument</Emph><P/>
##  
##  The   HTML   code   produced   with   this   converter   conforms
##  to   the  W3C   specification   <Q>XHTML   1.0  strict</Q>,   see
##  <URL>https://www.w3.org/TR/xhtml1</URL>.  First, this means  that
##  the   HTML   files   are   valid   XML   files.   Secondly,   the
##  extension  <Q>strict</Q>   says  in  particular  that   the  code
##  doesn't  contain  any explicit  font  or  color information.<P/>
##  
##  Mathematical  formulae  are  handled  as in  the  text  converter
##  <Ref  Func="GAPDoc2Text"/>.  We don't  want  to  assume that  the
##  browser can  use symbol  fonts. Some &GAP;  users like  to browse
##  the  online  help  with   <C>lynx</C>,  see  <Ref  BookName="Ref"
##  Func="SetHelpViewer"  />, which  runs  inside  the same  terminal
##  windows as &GAP;.<P/>
##  
##  To view the generated files in graphical browsers, stylesheet files
##  with layout configuration should be copied into the directory
##  with the generated HTML files, see <Ref Subsect="StyleSheets"/>.
##  <P/>
##  
##  <Label Name="mtransarg"/>
##  <Emph>Output format with</Emph> <A>mtrans</A> argument <P/>
##  
##  Currently, there  are three variants of  this converter available
##  which handle mathematical formulae differently. They are accessed
##  via the optional last <A>mtrans</A> argument.<P/>
##  
##  If  <A>mtrans</A>   is  set  to  <C>"MathJax"</C>   the  formulae
##  are  essentially  translated  as  for  &LaTeX;  documents  (there
##  is  no  processing  of   <C><M></C>  elements  as  decribed
##  in  <Ref   Subsect="M"/>).  Inline  formulae  are   delimited  by
##  <C>\(</C>  and  <C>\)</C>  and displayed  formulae  by  <C>\[</C>
##  and    <C>\]</C>.   With    <Package>MathJax</Package>   webpages
##  can   contain   nicely    formatted   scalable   and   searchable
##  formulae.   The  resulting   files  link   by  default   to  <URL
##  Text="https://www.jsdelivr.com/">https://www.jsdelivr.com/</URL>
##  to  get the  <Package>MathJax</Package>  script  and fonts.  This
##  means  that  they  can  only  be  used on computers with internet
##  access.   An  alternative   URL   can  be   set  by   overwriting
##  <C>GAPDoc2HTMLProcs.MathJaxURL</C>   before   building  the  HTML
##  version   of   a   manual.   This  way   a   local   installation
##  of   <Package>MathJax</Package>   could   be   used.   See   <URL
##  Text="https://www.mathjax.org/">https://www.mathjax.org/</URL> 
##  for more details.<P/>
##  
##  The following  possibilities for <A>mtrans</A> are  still supported,
##  but since the <Package>MathJax</Package> approach seems much better,
##  their use is deprecated.<P/>
##  
##  If  the  argument <A>mtrans</A>  is  set  to <C>"Tth"</C>  it  is
##  assumed that you  have installed the &LaTeX;  to HTML translation
##  program <C>tth</C>. This is used to translate the contents of the
##  <C>M</C>,  <C>Math</C>  and  <C>Display</C>  elements  into  HTML
##  code.  Note that  the resulting  code is  not compliant  with any
##  standard.  Formally  it  is  <Q>XHTML  1.0  Transitional</Q>,  it
##  contains  explicit  font  specifications and  the  characters  of
##  mathematical  symbols  are  included  via  their  position  in  a
##  <Q>Symbol</Q>  font. Some  graphical browsers  can be  configured
##  to  display  this  in  a  useful  manner,  check  <URL  Text="the
##  Tth homepage">http://hutchinson.belmont.ma.us/tth/</URL> for more
##  details.<P/>
##  
##  This  function works  by  running recursively  through the  document
##  tree   and   calling   a   handler  function   for   each   &GAPDoc;
##  XML   element.  Many   of  these   handler  functions   (usually  in
##  <C>GAPDoc2TextProcs.<ElementName></C>)  are  not  difficult to
##  understand (the  greatest complications are some  commands for index
##  entries, labels  or the  output of page  number information).  So it
##  should be easy to adjust certain details to your own taste by slight
##  modifications of the program. <P/>
##  
##  The result  of this converter  can be  written to files  with the
##  command <Ref Func="GAPDoc2HTMLPrintHTMLFiles" />.<P/>
##  
##  There are two user preferences for reading the HTML manuals produced by
##  &GAPDoc;. A user can choose among several style files which determine the
##  appearance of the manual pages with 
##  <C>SetUserPreference("GAPDoc", "HTMLStyle", [...]);</C> where the list in 
##  the third argument are arguments for <Ref Func="SetGAPDocHTMLStyle"/>.
##  The second preference is set by 
##  <C>SetUserPreference("GAPDoc", "UseMathJax", ...);</C> where the third
##  argument is <K>true</K> or <K>false</K> (default). If this is set to
##  <K>true</K>, the &GAP; help system displays the <Package>MathJax</Package>
##  version of the HTML manuals.
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##  
##  <#GAPDoc Label="HTMLStyleSheets">
##  <Subsection Label="StyleSheets">
##  <Heading>Stylesheet files</Heading>
##  <Index>CSS stylesheets</Index>
##  
##  For graphical  browsers the layout  of the generated HTML manuals  can be
##  highly  configured  by  cascading stylesheet  (CSS)  and  javascript
##  files. Such files are provided in the <F>styles</F> directory of the
##  &GAPDoc; package.<P/>
##  
##  We recommend that these files  are copied into each manual directory
##  (such  that each  of  them  is selfcontained).  There  is a  utility
##  function  <Ref  Func="CopyHTMLStyleFiles"  /> which  does  this.  Of
##  course, these files  may be changed or new styles  may be added. New
##  styles  may  also be  sent  to  the  &GAPDoc; authors  for  possible
##  inclusion in future versions.<P/>
##  
##  The  generated   HTML  files refer to  the   file  <F>manual.css</F>
##  which   conforms   to   the   W3C   specification   CSS   2.0,   see
##  <URL>https://www.w3.org/TR/REC-CSS2</URL>, and  the javascript  file
##  <F>manual.js</F> (only in browsers  which support CSS or javascript,
##  respectively;  but   the  HTML  files  are   also  readable  without
##  any  of  them).  To  add  a style  <C>mystyle</C>  one  or  both  of
##  <F>mystyle.css</F> and <F>mystyle.js</F> must be provided; these can
##  overwrite  default settings  and add  new javascript  functions. For
##  more details see the comments in <F>manual.js</F>.<P/>
##  </Subsection>
##  <ManSection >
##  <Func Arg="dir" Name="CopyHTMLStyleFiles" />
##  <Returns>nothing</Returns>
##  <Description>
##  This utility function copies  the <F>*.css</F> and <F>*.js</F> files
##  from the  <F>styles</F> directory of  the &GAPDoc; package  into the
##  directory
##  <A>dir</A>.
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##  
##  the basic call, used recursively with a result r from GetElement 
##  and a string str or list l to which the output should be appended
# arg: r[, bibpath]    (then a list is returned, only for whole document)
# or:  r, str          (then the output is appended to string or list str)
InstallGlobalFunction(GAPDoc2HTML, function(arg)
  local   r,  str,  linelength,  name;
  r := arg[1];
  # first check for the mode
  if arg[Length(arg)] in ["MathML", "Tth", "MathJax"] then
    r.mathmode := arg[Length(arg)];
    arg := arg{[1..Length(arg)-1]};
  else
    r.mathmode := "Text";
  fi;
  
  if Length(arg) > 1 then
    str := arg[2];
  else 
    str := [];
  fi;
  if r.name = "WHOLEDOCUMENT" then
    # choose different file name conventions such that these
    # conversions can coexist
    if r.mathmode = "MathML" then
      GAPDoc2HTMLProcs.ext := "_mml.xml";
    elif r.mathmode = "Tth" then
      GAPDoc2HTMLProcs.ext := "_sym.html";
    elif r.mathmode = "MathJax" then
      GAPDoc2HTMLProcs.ext := "_mj.html";
    else
      GAPDoc2HTMLProcs.ext := ".html";
    fi;
    if IsDirectory(str) then
      r.bibpath := str;
    else
      if Length(str) = 0 then
        str := ".";
      fi;
      r.bibpath := Directory(str);
    fi;
    str := [];
    if Length(arg) > 2 and IsString(arg[3]) then
      GAPDoc2HTMLProcs.RelPath := arg[3];
      GAPInfo.MainRootPath := Filtered(GAPInfo.RootPaths, a->
                            Filename([Directory(a)], "lib/init.g")<>fail)[1];
    else
      Unbind(GAPDoc2HTMLProcs.RelPath);
    fi;
  fi;

  name := r.name;
  if not IsBound(GAPDoc2HTMLProcs.(name)) then
    Info(InfoGAPDoc, 1, "#W WARNING: Don't know how to process element ", name, 
          " ---- ignored\n");
  else
    GAPDoc2HTMLProcs.(r.name)(r, str);
  fi;
  
  if r.name ="WHOLEDOCUMENT" then
    # put final record together and return it
    return GAPDoc2HTMLProcs.PutFilesTogether(str, r);
  fi;

  return str;
end);

##  recursion through the tree and collecting paragraphs
BindGlobal("GAPDoc2HTMLContent", function(r, l)
  local par, cont, i, count, s, a;
  
  # utility: append counter and formatted paragraph to l
  par := function(s)
    if Length(s)>0 then
      s := NormalizedWhitespace(s);
      if Length(s)>0 then
        Add(l, count);
        Add(l, Concatenation("<p>", s, "</p>\n\n"));
      fi;
    fi;
  end;
  
  # if not containing paragraphs, then l is string to append to
  if not r.name in GAPDoc2HTMLProcs.ParEls then
    for a in r.content do
      GAPDoc2HTML(a, l);
    od;
    return;
  fi;
  
  # otherwise we have to collect text and paragraphs
  cont := r.content;
  # checking for alternatives
  i := 1;
  while i < Length(cont) do
    if cont[i].name = "Alt" and GAPDoc2HTMLProcs.AltYes(cont[i]) then
      cont := Concatenation(cont{[1..i-1]}, cont[i].content,
              cont{[i+1..Length(cont)]});
    else
      i := i + 1;
    fi;
  od;
  count := r.count;
  s := "";
  for a in cont do
    if a.count <> count  then
      par(s);
      count := a.count;
      s := "";
    fi;
    if a.name in GAPDoc2HTMLProcs.ParEls then
      # recursively collect paragraphs
      GAPDoc2HTML(a, l);
    else 
      # collect text for current paragraph
      GAPDoc2HTML(a, s);
    fi;
  od;
  if Length(s)>0 then
    par(s);
  fi;
end);

  
##  write head and foot of HTML file.
GAPDoc2HTMLProcs.WHOLEDOCUMENT := function(r, par)
  local i, pi, t, el, remdiv, math, pos, pos1, str, dat, datbt, bib, b, 
        keys, need, labels, tmp, j, diff, text, a, k, l, ind, opts;
  
  ##  add paragraph numbers to all nodes of the document
  AddParagraphNumbersGapDocTree(r);
  
  if not IsBound(r.six) then
    Info(InfoGAPDoc, 1, "#W WARNING: Using labels from section numbers, \n",
      "#W consider running the converter for the text version first!\n");
  fi;
  
  ##  add a link .root to the root of the document to all nodes
  ##  (then we can collect information about indexing and so on 
  ##  there)
  AddRootParseTree(r);
  r.index := [];
  r.toc := "";
  r.labels := rec();
  r.labeltexts := rec();
  if not IsBound(r.bibkeys) then
    r.bibkeys := [];
  fi;
  r.chaptitle := rec();
  r.chapsectlinks := rec();
  
  ##  checking for processing instructions before the book starts
  ##  example:  <?HTML option1="value1" ?>
  i := 1;
  pi := rec();
  while not r.content[i].name = "Book" do
    if r.content[i].name = "XMLPI" then
      t := r.content[i].content;
      if Length(t) > 4 and t{[1..5]} = "HTML " then
        el := GetSTag(Concatenation("<", t, ">"), 2);
        for a in NamesOfComponents(el.attributes) do
          pi.(a) := el.attributes.(a);
        od;
      fi;
    fi;
    i := i+1;
  od;
  
  # setup for external conversion of maths (MathML with ttm, tth, ...)
  if r.mathmode in ["MathML", "Tth"] then
    r.ConvInput := "";
    r.MathCount := 0;
  fi;
  
  ##  Now the actual work starts, we give the processing instructions found
  ##  so far to the Book handler.
  ##  We call the Book handler twice and produce index, bibliography, toc
  ##  in between.
  Info(InfoGAPDoc, 1, "#I First run, collecting cross references, ",
        "index, toc, bib and so on . . .\n");
  # with this flag we avoid unresolved references warnings in first run
  GAPDoc2HTMLProcs.FirstRun := true;
  GAPDoc2HTMLProcs.Book(r.content[i], [], pi);
  GAPDoc2HTMLProcs.FirstRun := false;
  
  # now the toc is ready
  Info(InfoGAPDoc, 1, "#I Table of contents complete.\n");
  r.toctext := r.toc;
  r.chapsectlinkstext := r.chapsectlinks;
  
  # utility to remove <div> tags
  remdiv := function(s)
    local pos, pos1;
    pos := PositionSublist(s, "<div");
    while pos <> fail do
      pos1 := Position(s, '>', pos);
      s := Concatenation(s{[1..pos-1]}, s{[pos1+1..Length(s)]});
      pos := PositionSublist(s, "<div");
    od;
    pos := PositionSublist(s, "</div");
    while pos <> fail do
      pos1 := Position(s, '>', pos);
      s := Concatenation(s{[1..pos-1]}, s{[pos1+1..Length(s)]});
      pos := PositionSublist(s, "</div");
    od;
    return s;
  end;

  # MathML or Tth translation
  if r.mathmode in ["MathML", "Tth"] then
    Info(InfoGAPDoc, 1, "#I   translating formulae with \c");
    FileString("tempCONV.tex", r.ConvInput);
    if r.mathmode = "MathML" then
      Info(InfoGAPDoc, 1, "ttm.\n");
      Exec("rm -f tempCONV.html; ttm -L -r tempCONV.tex > tempCONV.html");
    elif r.mathmode = "Tth" then
      Info(InfoGAPDoc, 1, "tth.\n");
      Exec("rm -f tempCONV.html; tth -w2 -r -u tempCONV.tex > tempCONV.html");
    fi; 
    math := StringFile("tempCONV.html");
    # correct the <var> tags
    math := SubstitutionSublist(math, "< var >", "<var>");
    math := SubstitutionSublist(math, "< /var >", "</var>");
    math := SubstitutionSublist(math, 
                  "<mo><</mo><mi>var</mi><mo>></mo>", "<var>");
    math := SubstitutionSublist(math, 
                  "<mo><</mo><mo>/</mo><mi>var</mi><mo>></mo>", "</var>");
    r.MathList := [];
    pos := PositionSublist(math, "TeXFormulaeDelim");
    while pos <> fail do
      pos1 := PositionSublist(math, "TeXFormulaeDelim", pos);
      if pos1 <> fail then
        Add(r.MathList, remdiv(math{[pos+16..pos1-1]}));
      else
        Add(r.MathList, remdiv(math{[pos+16..Length(math)]}));
      fi;
      pos := pos1;
    od;
  fi;
  
  # .index has entries of form [sorttext, subsorttext, numbertext, 
  # entrytext, url[, subtext]]
  Info(InfoGAPDoc, 1, "#I Producing the index . . .\n");
  SortBy(r.index, a-> [a[1],STRING_LOWER(a[2]),
                       List(SplitString(a[3],".-",""), Int)]);
  str := "";
  ind := r.index;
  k := 1;
  while k <= Length(ind) do
    if k > 1 and ind[k][4] = ind[k-1][4] then
      Append(str, "    ");
    else
      Append(str, ind[k][4]);
    fi;
    if IsBound(ind[k][6]) then
      if k = 1 or ind[k][4] <> ind[k-1][4] then
        Append(str, ", ");
      fi;
      Append(str, ind[k][6]);
    elif Length(ind[k][2]) > 0 then
      if k = 1 or ind[k][4] <> ind[k-1][4] then
        Append(str, ", ");
      fi;
      Append(str, ind[k][2]);
    fi;
    l := k;
    while l <= Length(ind) and ind[l][4] = ind[k][4] and
          ((IsBound(ind[k][6]) and IsBound(ind[l][6])
            and ind[k][6] = ind[l][6]) or
           (not IsBound(ind[k][6]) and not IsBound(ind[l][6])
           and ind[k][2] = ind[l][2]))  do
      Append(str, Concatenation("  <a href=\"", ind[l][5], "\">",
                              ind[l][3], "</a>  "));
      l := l+1;
    od;
    Append(str, "<br />\n");
    k := l;
  od;
  r.indextext := str;
  
  if Length(r.bibkeys) > 0 then
    GAPDocAddBibData(r);
    Info(InfoGAPDoc, 1, "#I Writing bibliography . . .\n");
    if r.root.mathmode = "MathJax" then
      opts := rec(MathJax := true);
    else
      opts := rec();
    fi;
    need := List(r.bibentries, a-> RecBibXMLEntry(a, "HTML", r.bibstrings,
            opts));
    # copy the unique labels
    for a in [1..Length(need)] do
      need[a].key := r.biblabels[a];
    od;
    text := "";
    for a in need do
      # an anchor for links from the citations
      Append(text, Concatenation("\n<p><a id=\"biB", a.Label, 
                        "\" name=\"biB", a.Label, "\"></a></p>\n")); 
      Append(text, StringBibAsHTML(a, false)); 
    od;
    r.bibtext := text;
  fi;
  
  # second run
  r.index := [];
  Info(InfoGAPDoc, 1, "#I Second run through document . . .\n");
  GAPDoc2HTMLProcs.Book(r.content[i], par, pi);
  
  for a in ["MathList", "MathCount", "index", "toc"] do
    Unbind(r.(a));
  od;
  ##  remove the links to the root  ???
##    RemoveRootParseTree(r);
end;

##  comments and processing instructions are in general ignored
GAPDoc2HTMLProcs.XMLPI := function(r, str)
  return;
end;
GAPDoc2HTMLProcs.XMLCOMMENT := function(r, str)
  return;
end;

# two utilities for attribute values like labels or text with special
# XML (or LaTeX) characters which gets printed
GAPDoc2HTMLProcs.EscapeAttrVal := function(str)
  str := SubstitutionSublist(str, "&", "&");
  str := SubstitutionSublist(str, "<", "<");
  str := SubstitutionSublist(str, ">", ">");
  # for MathJax
  str := SubstitutionSublist(str, "\\[", "<span>\\</span>[");
  str := SubstitutionSublist(str, "\\]", "<span>\\</span>]");
  str := SubstitutionSublist(str, "\\(", "<span>\\</span>(");
  str := SubstitutionSublist(str, "\\)", "<span>\\</span>)");
  return str;
end;

# do nothing with Ignore
GAPDoc2HTMLProcs.Ignore := function(arg)
end;

# just process content 
GAPDoc2HTMLProcs.Book := function(r, par, pi)
  # copy the name of the book to the root
  r.root.bookname := r.attributes.Name;
  GAPDoc2HTMLContent(r, par);
end;

##  Body is sectioning element
GAPDoc2HTMLProcs.Body := GAPDoc2HTMLContent;

##  the title page,  the most complicated looking function
GAPDoc2HTMLProcs.TitlePage := function(r, par)
  local   strn,  l,  s,  a,  aa,  cont,  ss;
    
  strn := "<div class=\"pcenter\">\n";
  # title
  l := Filtered(r.content, a-> a.name = "Title");
  s := "";
  GAPDoc2HTMLContent(l[1], s);
  s := Concatenation("\n<h1>", NormalizedWhitespace(s), "</h1>\n\n"); 
  Append(strn, s);
  
  # subtitle
  l := Filtered(r.content, a-> a.name = "Subtitle");
  if Length(l)>0 then
    s := "";
    GAPDoc2HTMLContent(l[1], s);
    s := Concatenation("\n<h2>", NormalizedWhitespace(s), "</h2>\n\n"); 
    Append(strn, s);
  fi;
  
  # version
  l := Filtered(r.content, a-> a.name = "Version");
  if Length(l)>0 then
    s := "<p>";
    GAPDoc2HTMLContent(l[1], s);
    while Length(s)>0 and s[Length(s)] in  WHITESPACE do
      Unbind(s[Length(s)]);
    od;
    Append(s, "</p>\n\n");
    Append(strn, s);
  fi;

  # date
  l := Filtered(r.content, a-> a.name = "Date");
  if Length(l)>0 then
    s := "<p>";
    GAPDoc2HTMLContent(l[1], s);
    Append(strn, s);
    Append(strn, "</p>\n\n");
  fi;
  Append(strn, "</div>\n");

  # an extra comment
  l := Filtered(r.content, a-> a.name = "TitleComment");
  if Length(l) > 0 then
    s := "<p>";
    GAPDoc2HTMLContent(l[1], s);
    Append(s, "</p>\n");
    Append(strn, s);
  fi;

  # author name(s)
  l := Filtered(r.content, a-> a.name = "Author");
  for a in l do
    s := "<p><b>";
    aa := ShallowCopy(a);
    aa.content := Filtered(a.content, 
                  b-> not b.name in ["Email", "Homepage", "Address"]);
    GAPDoc2HTMLContent(aa, s);
    Append(strn, s);
    Append(strn, "</b>\n");
    cont := List(a.content, b-> b.name);
    if "Email" in cont then
      s := "";
      GAPDoc2HTML(a.content[Position(cont, "Email")], s);
      s := NormalizedWhitespace(s);
      Append(strn, Concatenation("<br />", GAPDocTexts.d.Email, ": ", s, "\n"));
    fi;
    if "Homepage" in cont then
      s := "";
      GAPDoc2HTML(a.content[Position(cont, "Homepage")], s);
      s := NormalizedWhitespace(s);
      Append(strn, Concatenation("<br />", GAPDocTexts.d.Homepage, 
                                 ": ", s, "\n"));
    fi;
    if "Address" in cont then
      s := "";
      GAPDoc2HTMLContent(a.content[Position(cont, "Address")], s);
      s := NormalizedWhitespace(s);
      Append(strn, Concatenation("<br />", GAPDocTexts.d.Address, 
                                 ": <br />", s, "\n"));
    fi;
    Append(strn, "</p>");
  od;
  Append(strn, "\n\n");
  
  Add(par, r.count);
  Add(par, strn);
  
  # an Address element in title page
  l := Filtered(r.content, a-> a.name = "Address");
  if Length(l) > 0 then
    s := "";
    GAPDoc2HTMLContent(l[1], s);
    s := NormalizedWhitespace(s);
    Append(strn, Concatenation("<p><b>", GAPDocTexts.d.Address, 
                               ":</b><br />\n", s, "</p>\n"));
  fi;
  
  # abstract, copyright page, acknowledgements, colophon
  for ss in ["Abstract", "Copyright", "Acknowledgements", "Colophon" ] do
    l := Filtered(r.content, a-> a.name = ss);
    if Length(l)>0 then
      Add(par, l[1].count);
      Add(par, Concatenation("<h3>", GAPDocTexts.d.(ss), "</h3>\n"));
      GAPDoc2HTMLContent(l[1], par);
    fi;
  od;
end;

##  these produce text for an URL
##  arg:  r, str[, pre]
GAPDoc2HTMLProcs.Link := GAPDoc2HTMLContent;
GAPDoc2HTMLProcs.LinkText := GAPDoc2HTMLContent;
GAPDoc2HTMLProcs.URL := function(arg)
  local r, str, pre, rr, txt, s;
  r := arg[1];
  str := arg[2];
  if Length(arg)>2 then
    pre := arg[3];
  else
    pre := "";
  fi;
  rr := First(r.content, a-> a.name = "LinkText");
  if rr <> fail then
    txt := "";
    GAPDoc2HTML(rr, txt);
    rr := First(r.content, a-> a.name = "Link");
    if rr = fail then
      Info(InfoGAPDoc, 1, "#W missing <Link> element for text ", txt, "\n");
      s := "MISSINGLINK";
    else
      s := "";
      GAPDoc2HTMLContent(rr, s);
    fi;
  else
    s := "";
    GAPDoc2HTMLContent(r, s);
    if IsBound(r.attributes.Text) then
      txt := r.attributes.Text;
    else
      txt := s;
    fi;
  fi;
  Append(str, Concatenation(GAPDoc2HTMLProcs.TextAttr.URL[1], 
                    "<a href=\"", pre, s, "\">", txt, "</a>"));
  Append(str, GAPDoc2HTMLProcs.TextAttr.URL[2]);
end;

GAPDoc2HTMLProcs.Homepage := GAPDoc2HTMLProcs.URL;

GAPDoc2HTMLProcs.Email := function(r, str)
  # we add the `mailto:' phrase
  GAPDoc2HTMLProcs.URL(r, str, "mailto:");
end;

##  utility: generate a chapter or (sub)section-number string 
GAPDoc2HTMLProcs.SectionNumber := function(count, sect)
  local   res;
  res := "";
  if IsString(count[1]) or count[1]>0 then
    Append(res, String(count[1]));
  fi;
  if sect="Chapter" or sect="Appendix" then
    return res;
  fi;
  Add(res, '.');
  if count[2]>0 then
    Append(res, String(count[2]));
  fi;
  if sect="Section" then
    return res;
  fi;
  if count[3]>0 then
    Append(res, Concatenation("-", String(count[3])));
  fi;
  return res;
end;

##  utility: generate a chapter or (sub)section-number string 
GAPDoc2HTMLProcs.SectionLabel := function(r, count, sect)
  local   res, a;
  if IsString(count[1]) or count[1]>0 then
    res := Concatenation("chap", String(count[1]), GAPDoc2HTMLProcs.ext);
  else
    res := Concatenation("chap0", GAPDoc2HTMLProcs.ext);
  fi;
  res := [res, ""];
  if not IsBound(r.root.six) then
    if sect="Chapter" then
      return res;
    fi;
    Append(res[2], Concatenation("s", String(count[2])));
    Append(res[2], Concatenation("ss", String(count[3])));
    return res;
  else
##      a := First(r.root.six, a-> a[3] = count{[1..3]});
    a := PositionSet(r.root.sixcount, count{[1..3]});
    if a <> fail then
      a := r.root.six[r.root.sixindex[a]];
    fi;
    if a = fail or not IsBound(a[7]) then
      return GAPDoc2HTMLProcs.SectionLabel(rec(root:=rec()), count, sect);
    else
      Append(res[2], a[7]);
      return res;
    fi;
  fi;
end;

##  the sectioning commands are just translated and labels are
##  generated, if given as attribute  
GAPDoc2HTMLProcs.ChapSect := function(r, par, sect)
  local   num, posh, s, ind, strn, lab, lb, types, nrs, hord, a, pos, l, i;
  
  types := ["Chapter", "Appendix", "Section", "Subsection"];
  nrs := ["3", "3", "4", "5"];
  hord := nrs[Position(types, sect)];
    
  Add(par, r.count);
  # if available, start with links to sections in chapter/appendix
  if sect in ["Chapter", "Appendix"] then
    if IsBound(r.root.chapsectlinkstext) and 
       IsBound(r.root.chapsectlinkstext.(r.count[1])) then
      Add(par, r.root.chapsectlinkstext.(r.count[1]));
    fi;
  fi;
  if par[Length(par)] = r.count then
    Add(par, "");
  fi;

  # section number as string
  num := GAPDoc2HTMLProcs.SectionNumber(r.count, sect);
  # and as anchor
  lab := GAPDoc2HTMLProcs.SectionLabel(r, r.count, "Subsection");
  lab := Concatenation(lab[1], "#", lab[2]);
  
  # the heading
  posh := Position(List(r.content, a-> a.name), "Heading");
  if posh <> fail then      
    s := "";
    # first the .six entry
    GAPDoc2HTMLProcs.Heading1(r.content[posh], s);
    if hord = "3" then
      r.root.chaptitle.(r.count[1]) := s;
    fi;
    
    # label entry, if present
    if IsBound(r.attributes.Label) then
      lb := NormalizedWhitespace(r.attributes.Label);
      r.root.labels.(lb) := [num, lab];
      r.root.labeltexts.(lb) := s;
    fi;
  
    # the heading text
    Append(par[Length(par)], 
       Concatenation("\n<h", hord, ">", num, " ", s, "</h", hord, ">\n\n"));
    
    # table of contents entry
    s := Concatenation( num, " ", s);
    if sect in ["Chapter", "Appendix"] then
      if r.count[1] >= 1 then
        ind := "<div class=\"ContChap\">";
      fi;
    elif sect="Section" then 
      ind := "";
      if r.count[2] >= 1 then
        Append(ind, "<div class=\"ContSect\">");
      fi;
      Append(ind, "<span class=\"tocline\"><span class=\"nocss\"> </span>");
    elif sect="Subsection" then
      ind := "<span class=\"ContSS\"><br /><span class=\"nocss\">  </span>";
    else
      ind := "";
    fi;
    Append(r.root.toc, Concatenation(ind, "<a href=\"", 
                                        lab, "\">", s, "</a>\n"));
    if sect="Section" then
      Append(r.root.toc, "</span>\n<div class=\"ContSSBlock\">\n");
    fi;
  fi;
  
  # the actual content
  GAPDoc2HTMLContent(r, par);

  # possibly close <div> or <span> in content
  if posh <> fail then      
    if sect in ["Chapter", "Appendix" ] then
      Append(r.root.toc, "</div>\n");
    elif sect="Section" then
      # remove last line if no subsections
      l := Length(r.root.toc);
      if r.root.toc{[l-25..l]} = "<div class=\"ContSSBlock\">\n" then
        for i in [0..25] do Unbind(r.root.toc[l-i]); od;
        Append(r.root.toc, "</div>\n");
      else
        Append(r.root.toc, "</div></div>\n");
      fi;
    elif sect="Subsection" then
      Append(r.root.toc, "</span>\n");
    fi;
  fi;
  # if in chapter, also use the section links in top of page
  if sect in ["Chapter", "Appendix"] then
    a := Reversed(r.root.toc);
    pos := PositionSublist(a, Reversed("<div class=\"ContChap\">"));
    a := Reversed(a{[1..pos-1]});
    r.root.chapsectlinks.(r.count[1]) := Concatenation(
                                         "<div class=\"ChapSects\">", a);
  fi;
end;


##  this really produces the content of the heading
GAPDoc2HTMLProcs.Heading1 := function(r, str)
  GAPDoc2HTMLProcs.WrapAttr(r, str, "Heading");
end;
##  and this ignores the heading (for simpler recursion)
GAPDoc2HTMLProcs.Heading := function(r, str)
end;

GAPDoc2HTMLProcs.Chapter := function(r, par)
  GAPDoc2HTMLProcs.ChapSect(r, par, "Chapter");
end;

GAPDoc2HTMLProcs.Appendix := function(r, par)
  GAPDoc2HTMLProcs.ChapSect(r, par, "Appendix");
end;

GAPDoc2HTMLProcs.Section := function(r, par)
  GAPDoc2HTMLProcs.ChapSect(r, par, "Section");
end;

GAPDoc2HTMLProcs.Subsection := function(r, par)
  GAPDoc2HTMLProcs.ChapSect(r, par, "Subsection");
end;

##  table of contents, just puts "TOC" in first run
GAPDoc2HTMLProcs.TableOfContents := function(r, par)
  Add(par, r.count);
  if IsBound(r.root.toctext) then
    Add(par, Concatenation("\n<div class=\"contents\">\n<h3>",
          GAPDocTexts.d.Contents, 
          "<a id=\"contents\" name=\"contents\"></a></h3>\n\n",
          r.root.toctext, "<br />\n</div>\n"));
  else
    Add(par,"<p>TOC\n-----------</p>\n\n");
  fi;
end;

##  bibliography, just "BIB" in first run, store databases in root
GAPDoc2HTMLProcs.Bibliography := function(r, par)
  local   s;
  # add references to TOC
  Append(r.root.toc, Concatenation("<div class=\"ContChap\"><a href=\"chapBib",
                        GAPDoc2HTMLProcs.ext, "\"><span class=\"Heading\">", 
                        GAPDocTexts.d.References, "</span></a></div>\n")); 
  r.root.bibdata := r.attributes.Databases;
  if IsBound(r.attributes.Style) then
    r.root.bibstyle := r.attributes.Style;
  fi;
  Add(par, r.count);
  if IsBound(r.root.bibtext) then
    Add(par, Concatenation("\n<h3>", GAPDocTexts.d.References, "</h3>\n\n", 
            r.root.bibtext, "<p> </p>\n\n"));
  else
    Add(par,"<p>BIB\n-----------</p>\n");
  fi;
end;

GAPDoc2HTMLProcs.PCDATAFILTER := function(r, str)
  local s, a;
  s := r.content;
  if not IsBound(r.HTML) and (Position(s, '<') <> fail or 
       Position(s, '&') <> fail or Position(s, '>') <> fail) then
    for a in s do 
      if a='<' then
        Append(str, "<");
      elif a='&' then
        Append(str, "&");
      elif a='>' then
        Append(str, ">");
      else
        Add(str, a);
      fi;
    od;
  else
    Append(str, s);
  fi;
end;
# and without filter (e.g., for collecting formulae  
GAPDoc2HTMLProcs.PCDATANOFILTER := function(r, str)
  Append(str, r.content);
end;

GAPDoc2HTMLProcs.PCDATAFILTER;
## default is with filter
GAPDoc2HTMLProcs.PCDATA := GAPDoc2HTMLProcs.PCDATAFILTER;

##  end of paragraph (end with double newline)
GAPDoc2HTMLProcs.P := function(r, str)
# nothing to do, the "<p>" are added in main loop (GAPDoc2HTML)
end;

GAPDoc2HTMLProcs.Br := function(r, str)
  Append(str, "<br />\n");
end;

##  wrapping text attributes
GAPDoc2HTMLProcs.WrapAttr := function(r, str, a)
  local   s,  tt;
  s := "";
  GAPDoc2HTMLContent(r, s);
  tt := GAPDoc2HTMLProcs.TextAttr.(a);
  Append(str, Concatenation(tt[1], s, tt[2]));
end;

##  GAP keywords 
GAPDoc2HTMLProcs.K := function(r, str)
  GAPDoc2HTMLProcs.WrapAttr(r, str, "K");
end;

##  buttons 
GAPDoc2HTMLProcs.B := function(r, str)
  GAPDoc2HTMLProcs.WrapAttr(r, str, "B");
end;

##  verbatim GAP code
GAPDoc2HTMLProcs.C := function(r, str)
  GAPDoc2HTMLProcs.WrapAttr(r, str, "C");
end;

##  file names
GAPDoc2HTMLProcs.F := function(r, str)
  GAPDoc2HTMLProcs.WrapAttr(r, str, "F");
end;

##  argument names (same as Arg)
GAPDoc2HTMLProcs.A := function(r, str)
  GAPDoc2HTMLProcs.WrapAttr(r, str, "Arg");
end;

GAPDoc2HTMLProcs.MathConvHelper := function(r, str, db, de)
  local s, x;
  if IsBound(r.root.MathList) then
    # conversion already available
    r.root.MathCount := r.root.MathCount + 1;
    Append(str, r.root.MathList[r.root.MathCount]);
  else 
    # add to input for converter
    if IsString(r.content) then
      s := r.content;
    else
      s := "";
      GAPDoc2HTMLProcs.PCDATA := GAPDoc2HTMLProcs.PCDATANOFILTER;
      for x in r.content do 
        GAPDoc2HTML(x, s);
      od;
      GAPDoc2HTMLProcs.PCDATA := GAPDoc2HTMLProcs.PCDATAFILTER;
    fi;
    s := Concatenation("TeXFormulaeDelim", db, s, de);
    Append(r.root.ConvInput, s);
    Append(str, "FORMULA");
  fi;
end;
  

##  simple maths, here we try to substitute TeX command to something which
##  looks ok in text mode
GAPDoc2HTMLProcs.M := function(r, str)
  local s, ss, save;
  if r.root.mathmode in ["MathML", "Tth"] then
    GAPDoc2HTMLProcs.MathConvHelper(r, str, "$", "$");
    return;
  fi;
  s := "";
  GAPDoc2HTMLProcs.PCDATA := GAPDoc2HTMLProcs.PCDATANOFILTER;
  # a hack, since we want to allow <A> in formulae
  save := GAPDoc2HTMLProcs.TextAttr.Arg;
  GAPDoc2HTMLProcs.TextAttr.Arg := ["TEXTaTTRvARBEGIN", "TEXTaTTRvAREND"];
  GAPDoc2HTMLContent(r, s);
  GAPDoc2HTMLProcs.TextAttr.Arg := save;
  GAPDoc2HTMLProcs.PCDATA := GAPDoc2HTMLProcs.PCDATAFILTER;
  ss := "";
  if r.root.mathmode = "MathJax" then
    s := Concatenation("\\(",s,"\\)");
    GAPDoc2HTMLProcs.PCDATAFILTER(rec(content := s), ss);
    ss := SubstitutionSublist(ss, "TEXTaTTRvARBEGIN", "\\textit{");
    ss := SubstitutionSublist(ss, "TEXTaTTRvAREND", "}");
  else
    s := TextM(s);
    GAPDoc2HTMLProcs.PCDATAFILTER(rec(content := s), ss);
    ss := SubstitutionSublist(ss, "TEXTaTTRvARBEGIN", save[1]);
    ss := SubstitutionSublist(ss, "TEXTaTTRvAREND", save[2]);
  fi;
  Append(str, WrapTextAttribute(ss, GAPDoc2HTMLProcs.TextAttr.M));
end;

##  in HTML this is shown in TeX format
GAPDoc2HTMLProcs.Math := function(r, str)
  local s;
  if r.root.mathmode in ["MathML", "Tth"] then
    GAPDoc2HTMLProcs.MathConvHelper(r, str, "$", "$");
    return;
  fi;
  if r.root.mathmode = "MathJax" then
    s := "";
    GAPDoc2HTMLProcs.M(r, s);
    Append(str, s);
    return;
  fi;
  s := "";
  GAPDoc2HTMLContent(r, s);
  Append(str, WrapTextAttribute(s, GAPDoc2HTMLProcs.TextAttr.Math));
end;

##  displayed maths (also in TeX format, but centered paragraph in itself)
GAPDoc2HTMLProcs.Display := function(r, par)
  local   s, a, str;
  if r.root.mathmode in ["MathML", "Tth"] then
    str := "";
    GAPDoc2HTMLProcs.MathConvHelper(r, str, "\n\\[", "\\]\n\n");
    Add(par, r.count);
    Add(par, Concatenation("<table class=\"display\"><tr>",
             "<td class=\"display\">",
             str, "</td></tr></table>\n"));
    return;
  fi;
  s := "";
  for a in r.content do
    GAPDoc2HTML(a, s);
  od;
  if r.root.mathmode = "MathJax" then
    Add(par, r.count);
    Add(par, Concatenation("<p class=\"center\">\\[", 
                            s, "\\]</p>\n\n"));
    return;
  fi;
  if IsBound(r.attributes.Mode) and r.attributes.Mode = "M" then
    s := TextM(s);
  fi;
  s := Concatenation("<p class=\"pcenter\">", s, "</p>\n\n");
  Add(par, r.count);
  Add(par, s);
end;

##  emphazised text
GAPDoc2HTMLProcs.Emph := function(r, str)
  GAPDoc2HTMLProcs.WrapAttr(r, str, "Emph");
end;

##  quoted text
GAPDoc2HTMLProcs.Q := function(r, str)
  Append(str, "<q>");
  GAPDoc2HTMLContent(r, str);
  Append(str, "</q>");
end;

##  Package names
GAPDoc2HTMLProcs.Package := function(r, str)
  GAPDoc2HTMLProcs.WrapAttr(r, str, "Package");
end;

##  menu items
GAPDoc2HTMLProcs.I := function(r, str)
  GAPDoc2HTMLProcs.WrapAttr(r, str, "I");
end;

GAPDoc2HTMLProcs.AddColorPromptMarkup := function(cont)
  local patt, batt, iatt, res, pos, s, rows;
  patt := GAPDoc2HTMLProcs.TextAttr.GAPprompt;
  batt := GAPDoc2HTMLProcs.TextAttr.GAPbrkprompt;
  iatt := GAPDoc2HTMLProcs.TextAttr.GAPinput;
  res := "";
  rows := SplitString(cont, "\n", "");
  for s in rows do
    if Length(s) > 7 and s{[1..8]} = "gap> " then
      Append(res, Concatenation(WrapTextAttribute("gap>", patt),
                       " ", WrapTextAttribute(s{[9..Length(s)]}, iatt)));
    elif Length(s) > 4 and s{[1..5]} = "> " then
      Append(res, Concatenation(WrapTextAttribute(">", patt),
                       " ", WrapTextAttribute(s{[6..Length(s)]}, iatt)));
    elif Length(s) > 2 and s{[1..3]} = "brk" then
      pos := Position(s, ' ');
      if pos <> fail then
        Append(res, Concatenation(WrapTextAttribute(s{[1..pos-1]}, batt),
                        " ", WrapTextAttribute(s{[pos+1..Length(s)]}, iatt)));
      else
        Append(res, WrapTextAttribute(s, batt));
      fi;
    else
      Append(res, WrapTextAttribute(s, ["",""]));
    fi;
    Add(res, '\n');
  od;
  if Length(cont) > 0 and cont[Length(cont)] <> '\n' then
    Unbind(res[Length(res)]);
  fi;
  return res;
end;

GAPDoc2HTMLProcs.ExampleLike := function(r, par, label, colorpr)
  local   str,  cont,  a,  s;
  str := "\n<div class=\"example\"><pre>";
  cont := "";
  for a in r.content do 
    # here we try to avoid reformatting
    if IsString(a.content) then
      GAPDoc2HTMLProcs.PCDATA(a, cont); 
    else
      s := "";
      GAPDoc2HTML(a, s);
      Append(cont, s);
    fi;
  od;
  if colorpr then
    cont := GAPDoc2HTMLProcs.AddColorPromptMarkup(cont);
  fi;
  Append(str, cont);
  Append(str, "</pre></div>\n\n");
  Add(par, r.count);
  Add(par, str);
end;

##  log of session and GAP code is typeset the same way as <Example>
GAPDoc2HTMLProcs.Example := function(r, par)
  GAPDoc2HTMLProcs.ExampleLike(r, par, "Example", true);
end;
GAPDoc2HTMLProcs.Log := function(r, par)
  GAPDoc2HTMLProcs.ExampleLike(r, par, "Log", true);
end;
GAPDoc2HTMLProcs.Listing := function(r, par)
  GAPDoc2HTMLProcs.ExampleLike(r, par, "Code", true);
end;

GAPDoc2HTMLProcs.Verb := function(r, par)
  local   str,  cont,  a,  s;
  str := "\n<pre class=\"normal\">\n";
  cont := "";
  for a in r.content do 
    # here we try to avoid reformatting
    if IsString(a.content) then
      GAPDoc2HTMLProcs.PCDATA(a, cont); 
    else
      s := "";
      GAPDoc2HTML(a, s);
      Append(cont, s);
    fi;
  od;
  Append(str, cont);
  Append(str, "\n</pre>\n\n");
  Add(par, r.count);
  Add(par, str);
end;

##  explicit labels
GAPDoc2HTMLProcs.Label := function(r, str)
  local num,  lab, lb;
  num := GAPDoc2HTMLProcs.SectionNumber(r.count, "Subsection");
  lab := GAPDoc2HTMLProcs.SectionLabel(r, r.count, "Subsection"); 
  lb := NormalizedWhitespace(r.attributes.Name);
  r.root.labels.(lb) := [num, Concatenation(lab[1],"#",lab[2])];
end;

##  citations
GAPDoc2HTMLProcs.Cite := function(r, str)
  local   key,  pos;
  key := r.attributes.Key;
  pos := Position(r.root.bibkeys, key);
  if pos = fail then
    Add(r.root.bibkeys, key);
    Append(str, Concatenation("[?", key, "?]"));
  elif  not IsBound(r.root.biblabels) then
    Append(str, Concatenation("[?", key, "?]"));
  else
    # here we include a link to the corresponding entry in bibliography 
    Append(str, Concatenation("<a href=\"chapBib", GAPDoc2HTMLProcs.ext,
                              "#biB", key, "\">[", r.root.biblabels[pos]));
    if IsBound(r.attributes.Where) then
      Append(str, ", ");
      Append(str, r.attributes.Where);
    fi;
    Append(str, "]</a>");
  fi;
end;

##  explicit index entries
GAPDoc2HTMLProcs.Subkey := GAPDoc2HTMLContent;
GAPDoc2HTMLProcs.Index := function(r, str)
  local s, sub, entry, url, a;
  
  s := "";
  sub := "";
  for a in r.content do
    if a.name = "Subkey" then
      GAPDoc2HTML(a, sub);
    else
      GAPDoc2HTML(a, s);
    fi;
  od;
  NormalizeWhitespace(s);
  NormalizeWhitespace(sub);
  if IsBound(r.attributes.Key) then
    entry := [STRING_LOWER(r.attributes.Key)];
  else
    entry := [STRING_LOWER(s)];
  fi;
  if IsBound(r.attributes.Subkey) then
    Add(entry, r.attributes.Subkey);
  else
    Add(entry, sub);
  fi;
  Add(entry, GAPDoc2HTMLProcs.SectionNumber(r.count, "Subsection"));
  Add(entry, s);
  url := GAPDoc2HTMLProcs.SectionLabel(r, r.count, "Subsection");
  Add(entry, Concatenation(url[1],"#",url[2]));
  if Length(sub) > 0 then
    Add(entry, sub);
  fi;
  Add(r.root.index, entry);
end;

##  helper to add markup to the args
GAPDoc2HTMLProcs.WrapArgs := function(argstr)
  local res, noletter, c;
  res := "";
  noletter := true;
  for c in argstr do
    if noletter then
      if not c in ", []" then
        noletter := false;
        Append(res, GAPDoc2HTMLProcs.TextAttr.Arg[1]);
      fi;
    elif c in ", []" then
      noletter := true;
      Append(res, GAPDoc2HTMLProcs.TextAttr.Arg[2]);
    fi;
    Add(res, c);
  od;
  if not noletter then
    Append(res, GAPDoc2HTMLProcs.TextAttr.Arg[2]);
  fi;
  return res;
end;

##  this produces an implicit index entry and a label entry
GAPDoc2HTMLProcs.LikeFunc := function(r, par, typ)
  local   attr,  s,  name,  lab, url;
  attr := GAPDoc2HTMLProcs.TextAttr.Func;
  name := GAPDoc2HTMLProcs.EscapeAttrVal(r.attributes.Name);
  s := Concatenation(attr[1], "‣ ", name, attr[2]);
  if IsBound(r.attributes.Arg) then
    Append(s, Concatenation("( ", GAPDoc2HTMLProcs.WrapArgs(
              GAPDoc2HTMLProcs.EscapeAttrVal(
              NormalizedArgList(r.attributes.Arg))), " )"));
  fi;
  # index entry
  attr := GAPDoc2HTMLProcs.TextAttr.Func;
  url := GAPDoc2HTMLProcs.SectionLabel(r, r.count, "Subsection");
  url := Concatenation(url[1],"#",url[2]);
  if IsBound(r.attributes.Label) then
    lab := NormalizedWhitespace(r.attributes.Label);
  else
    lab := "";
  fi;
  Add(r.root.index, [STRING_LOWER(r.attributes.Name), lab, 
          GAPDoc2HTMLProcs.SectionNumber(r.count, "Subsection"), 
          Concatenation(attr[1], name, attr[2]),
          url]);
  # label (if not given, the default is the Name)
  if IsBound(r.attributes.Label) then
    if IsBound(r.attributes.Name) then
      lab := Concatenation(r.attributes.Name, " (", 
             NormalizedWhitespace(r.attributes.Label), ")");
    else
      lab := r.attributes.Label;
    fi;
  else
    lab := r.attributes.Name;  
  fi;
  GAPDoc2HTMLProcs.Label(rec(count := r.count, attributes := rec(Name
                                             := lab), root := r.root), par); 
  # adding  hint about the type of the variable  
  s := Concatenation("<div class=\"func\"><table class=\"func\" ", 
               "width=\"100%\">", 
               "<tr><td class=\"tdleft\">", s,
               "</td><td class=\"tdright\">( ", typ, 
               " )</td></tr></table></div>\n");
  Add(par, r.count);
  Add(par, s);
end;

GAPDoc2HTMLProcs.Func := function(r, str)
  GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Func);
end;

GAPDoc2HTMLProcs.Oper := function(r, str)
  GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Oper);
end;

GAPDoc2HTMLProcs.Constr := function(r, str)
  GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Constr);
end;

GAPDoc2HTMLProcs.Meth := function(r, str)
  GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Meth);
end;

GAPDoc2HTMLProcs.Filt := function(r, str)
  # r.attributes.Type could be "representation", "category", ...
  if IsBound(r.attributes.Type) then
    GAPDoc2HTMLProcs.LikeFunc(r, str, LowercaseString(r.attributes.Type));
  else
    GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Filt);
  fi;
end;

GAPDoc2HTMLProcs.Prop := function(r, str)
  GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Prop);
end;

GAPDoc2HTMLProcs.Attr := function(r, str)
  GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Attr);
end;

GAPDoc2HTMLProcs.Var := function(r, str)
  GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Var);
end;

GAPDoc2HTMLProcs.Fam := function(r, str)
  GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Fam);
end;

GAPDoc2HTMLProcs.InfoClass := function(r, str)
  GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.InfoClass);
end;

##  using the HelpData(.., .., "ref") interface
GAPDoc2HTMLProcs.ResolveExternalRef := function(bookname,  label, nr)
  local info, match, res;
  info := HELP_BOOK_INFO(bookname);
  if info = fail then
    return fail;
  fi;
  match := Concatenation(HELP_GET_MATCHES(info, SIMPLE_STRING(label), true));
  if Length(match) < nr then
    return fail;
  fi;
  res := GetHelpDataRef(info, match[nr][2]);
  res[1] := SubstitutionSublist(res[1], " (not loaded): ", ": ", "one");
  return res;
end;

##  helper for external URLs, remove GAPDocStyle part and maybe add "_mj"
GAPDoc2HTMLProcs.AdjustExtURL := function(r, url)
  local pos, pos2, res, fnam, mjnam;
  pos := PositionSublist(url, "?GAPDocStyle=");
  if pos <> fail then
    pos2 := Position(url, '#', pos);
    if pos2 = fail then
      pos2 := Length(url)+1;
    fi;
    res := url{[1..pos-1]};
    Append(res, url{[pos2..Length(url)]});
  else
    res :=url;
  fi;
  if r.root.mathmode = "MathJax" then
    pos := Position(res, '#');
    if pos <> fail then
      fnam := res{[1..pos-1]};
    else
      pos := Length(res)+1;
      fnam := res;
    fi;
    if Length(fnam) >= 5 and fnam{[Length(fnam)-4..Length(fnam)]} = ".html" then
      mjnam := Concatenation(fnam{[1..Length(fnam)-5]}, "_mj.html");
      if IsExistingFile(mjnam) then
        res := Concatenation(mjnam, res{[pos..Length(res)]});
      fi;
    fi;
  fi;
  return res;
end;

##  a try to make it somewhat shorter than for the Text and LaTeX conversions
GAPDoc2HTMLProcs.Ref := function(r, str)
  local int,  txt,  ref,  lab,  attr,  sectlike, rattr;
  
  rattr := GAPDoc2HTMLProcs.TextAttr.Ref;
  int := Difference(NamesOfComponents(r.attributes), ["BookName", "Label",
         "Style"]);
  if Length(int)>0 and int[1] <> "Text" then
    lab := r.attributes.(int[1]);
  else
    lab := "";
  fi;
  if IsBound(r.attributes.Label) then
    if Length(lab) > 0 then
      lab := Concatenation(lab, " (", r.attributes.Label, ")");
    else
      lab := r.attributes.Label;
    fi;
  fi;
  lab := NormalizedWhitespace(lab);
  if IsBound(r.attributes.BookName) then
    ref := GAPDoc2HTMLProcs.ResolveExternalRef(r.attributes.BookName, lab, 1);
    if ref <> fail and ref[6] <> fail then
      ref[6] := GAPDoc2HTMLProcs.AdjustExtURL(r, ref[6]);
      if IsBound(GAPDoc2HTMLProcs.RelPath) and 
         PositionSublist(ref[6], GAPInfo.MainRootPath) = 1 then
         ref[6] := Concatenation(GAPDoc2HTMLProcs.RelPath, "/", 
                   ref[6]{[Length(GAPInfo.MainRootPath)+1..Length(ref[6])]});
      fi;
      if IsBound(r.attributes.Style) and r.attributes.Style = "Number" then
        ref := Concatenation("<a href=\"", ref[6], "\">",rattr[1],
               r.attributes.BookName, " ", ref[2], rattr[2],"</a>");
      elif IsBound(r.attributes.Text) then
        ref := Concatenation("<a href=\"", ref[6], "\">", rattr[1], 
               r.attributes.Text, rattr[2], "</a>");
      else
        ref := Concatenation("<a href=\"", ref[6], "\">", rattr[1], 
               GAPDoc2HTMLProcs.EscapeAttrVal(ref[1]),
               rattr[2], "</a>");
      fi;
    elif ref <> fail then
      ref := Concatenation(rattr[1], ref[1], rattr[2]);
    else
      if GAPDoc2HTMLProcs.FirstRun <> true then
        Info(InfoGAPDoc, 1, "#W WARNING: non resolved reference: ",
                            r.attributes, "\n");
      fi;
      ref := Concatenation(rattr[1], "???", rattr[2]);
    fi;
  else
    if IsBound(r.root.labels.(lab)) then
      if not IsBound(r.attributes.Text) then
        ref := Concatenation("<a href=\"", r.root.labels.(lab)[2], "\">",
                             rattr[1], r.root.labels.(lab)[1], rattr[2],
                             "</a>");
      else
        ref := Concatenation("<a href=\"", r.root.labels.(lab)[2], "\">",
                             rattr[1], r.attributes.Text, rattr[2], "</a>");
      fi;
    else
      if GAPDoc2HTMLProcs.FirstRun <> true then
        Info(InfoGAPDoc, 1, "#W WARNING: non resolved reference: ",
                            r.attributes, "\n");
      fi;
      ref := Concatenation(rattr[1], "???", rattr[2]);
    fi;
  fi;
  if Length(int)>0 and int[1] in [ "Func", "Oper", "Constr", "Meth", "Filt",
                               "Prop", "Attr", "Var", "Fam", "InfoClass" ] then
    attr := GAPDoc2HTMLProcs.TextAttr.Func;
    txt := Concatenation(attr[1], 
             GAPDoc2HTMLProcs.EscapeAttrVal(r.attributes.(int[1])), attr[2]);
    # avoid reference to current subsection
    if IsBound(r.attributes.BookName) or not IsBound(r.root.labels.(lab)) 
      or GAPDoc2HTMLProcs.SectionNumber(r.count, "Subsection") <> 
                                                r.root.labels.(lab)[1] then
      Append(txt, Concatenation(" (", ref, ")"));
    fi;
  elif Length(int)>0 and 
       int[1] in [ "Sect", "Subsect", "Chap", "Appendix"] and 
       IsBound(r.attributes.Style) and
       r.attributes.Style = "Text" then
    if IsBound(r.root.labeltexts.(lab)) then
      txt := Concatenation("<a href=\"",r.root.labels.(lab)[2],
             "\">",rattr[1],r.root.labeltexts.(lab),rattr[2],"</a>");
    else
      if GAPDoc2HTMLProcs.FirstRun <> true then
        Info(InfoGAPDoc, 1, "#W WARNING: non resolved reference: ",
                            r.attributes, "\n");
      fi;
      txt := Concatenation(rattr[1], "???", rattr[2]);
    fi;
  else
    txt := ref;
  fi;
  Append(str, txt);
end;

GAPDoc2HTMLProcs.Description := GAPDoc2HTMLContent;

GAPDoc2HTMLProcs.Returns := function(r, par)
  local l;
  l := [];
  GAPDoc2HTMLContent(r, l);
  if Length(l) > 0 then
    l[2] := Concatenation("<p>", GAPDocTexts.d.Returns, 
                          ": ", l[2]{[4..Length(l[2])]});
  fi;
  Append(par, l);
end;

GAPDoc2HTMLProcs.ManSection := function(r, par)
  local   strn,  funclike,  i,  num,  s,  lab, lb, ind;
  
  # if there is a Heading then handle as subsection
  if ForAny(r.content, a-> IsRecord(a) and a.name = "Heading") then
    GAPDoc2HTMLProcs.ChapSect(r, par, "Subsection");
    return;
  fi;
  strn := "";
  # function like elements
  funclike := [ "Func", "Oper", "Constr", "Meth", "Filt", "Prop", "Attr", 
                "Var", "Fam", "InfoClass" ];
  
  # heading comes from name of first function like element
  i := 1;
  while not r.content[i].name in funclike do
    i := i+1;
  od;
  
  num := GAPDoc2HTMLProcs.SectionNumber(r.count, "Subsection");
  s := Concatenation(num, " ", 
         GAPDoc2HTMLProcs.EscapeAttrVal(r.content[i].attributes.Name));
  Add(par, r.count);
  # avoid MathJax interpretation in \(, \[ outside <code>
  if '\\' in s then
    s := Concatenation("<code>",s,"</code>");
  fi;
  Add(par, Concatenation("\n<h5>", s, "</h5>\n\n"));
  
  # append to TOC as subsection
  lab := GAPDoc2HTMLProcs.SectionLabel(r, r.count, "Subsection");
  lab := Concatenation(lab[1], "#", lab[2]);
  ind := "<span class=\"ContSS\"><br /><span class=\"nocss\">  </span>";
  Append(r.root.toc, Concatenation(ind, "<a href=\"", lab, "\">", s, 
          "</a></span>\n"));

  # label entry, if present
  if IsBound(r.attributes.Label) then
    lb := NormalizedWhitespace(r.attributes.Label);
    r.root.labels.(lb) := [num, lab];
    r.root.labeltexts.(lb) := s;
  fi;

  GAPDoc2HTMLContent(r, par);
end;

GAPDoc2HTMLProcs.Mark := function(r, str)
  GAPDoc2HTMLProcs.WrapAttr(r, str, "Mark");
end;

GAPDoc2HTMLProcs.Item := function(r, str)
  GAPDoc2HTMLContent(r, str);
end;

# must do the complete formatting 
GAPDoc2HTMLProcs.List := function(r, par)
  local   s,  a,  ss, i;
  s := "\n";
  if "Mark" in List(r.content, a-> a.name) then
    # a <dl> list
    Append(s, "<dl>\n");
    for a in r.content do
      if a.name = "Mark" then
        ss := "";
        GAPDoc2HTMLProcs.Mark(a, ss);
        Append(s, Concatenation("<dt>", ss, "</dt>\n"));
      elif a.name = "Item" then
        ss := "";
        GAPDoc2HTMLProcs.Item(a, ss);
        ss := Concatenation(Filtered(ss, IsString));
        ss := Concatenation("<dd>", ss, "</dd>\n");
        Append(s, ss);
      fi;
    od;
    Append(s, "</dl>\n");
  else
    # a <ul> list
    Append(s, "<ul>\n");
    for a in r.content do
      if a.name = "Item" then
        ss := "";
        GAPDoc2HTMLProcs.Item(a, ss);
        ss := Concatenation(Filtered(ss, IsString));
        Append(s, Concatenation("<li>", ss, "</li>\n"));
      fi;
    od;
    Append(s, "</ul>\n");
  fi;
  Add(par, r.count);
  Add(par, s);
end;

##  and this is an <ol> list
GAPDoc2HTMLProcs.Enum := function(r, par)
  local   s,  i,  a,  ss,  num;
  s := "";
  # a <ul> list
  Append(s, "<ol>\n");
  for a in r.content do
    if a.name = "Item" then
      ss := "";
      GAPDoc2HTMLProcs.Item(a, ss);
      if not IsString(ss) then
        ss := Concatenation(Filtered(ss, IsString));
      fi;
      Append(s, Concatenation("<li>", ss, "</li>\n"));
    fi;
  od;
  Append(s, "</ol>\n");
  Add(par, r.count);
  Add(par, s);
end;

GAPDoc2HTMLProcs.TheIndex := function(r, par)
  local   s;
  
  # add index to TOC
  Append(r.root.toc, Concatenation("<div class=\"ContChap\"><a href=\"chapInd",
                        GAPDoc2HTMLProcs.ext, "\"><span class=\"Heading\">", 
                        GAPDocTexts.d.Index, "</span></a></div>\n")); 
  # the text, if available
  Add(par, r.count);
  if IsBound(r.root.indextext) then
    Add(par, Concatenation("\n<div class=\"index\">\n<h3>",
--> --------------------

--> maximum size reached

--> --------------------

[ Verzeichnis aufwärts0.67unsichere Verbindung  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge