From 45e1b786144b8ef0a70a235f8a1a89e90a752d8f Mon Sep 17 00:00:00 2001
From: Ralph Amissah <ralph@amissah.com>
Date: Thu, 12 Jan 2017 20:51:12 -0500
Subject: 0.11.0 improved message passing, using templates

---
 src/sdp.d                        | 199 +++++++------
 src/sdp/ao_abstract_doc_source.d | 591 ++++++++++++++++++++++-----------------
 src/sdp/ao_defaults.d            | 198 ++++++++++++-
 src/sdp/ao_object_setter.d       |   5 +-
 src/sdp/ao_output_debugs.d       | 120 +++-----
 src/sdp/ao_read_config_files.d   |   9 +-
 src/sdp/ao_read_source_files.d   |  11 +-
 src/sdp/ao_rgx.d                 |   1 +
 src/sdp/output_epub.d            | 364 ++++++++++++++++++++++++
 src/sdp/output_html.d            | 429 ++++++++++++++--------------
 src/sdp/output_hub.d             |  65 +++--
 src/sdp/output_xhtmls.d          | 259 +++++++++++++++++
 src/sdp/source_sisupod.d         |  43 +++
 13 files changed, 1616 insertions(+), 678 deletions(-)
 create mode 100644 src/sdp/output_epub.d
 create mode 100644 src/sdp/output_xhtmls.d
 create mode 100644 src/sdp/source_sisupod.d

(limited to 'src')

diff --git a/src/sdp.d b/src/sdp.d
index 5ec249b..cf8af49 100755
--- a/src/sdp.d
+++ b/src/sdp.d
@@ -4,18 +4,21 @@
 +/
 /+ sdp: sisu document parser, see http://sisudoc.org +/
 import
-  compile_time_info,          // sdp/compile_time_info.d
-  ao_abstract_doc_source,     // sdp/ao_abstract_doc_source.d
-  ao_conf_make_meta,          // sdp/ao_conf_make_meta.d
-  ao_conf_make_meta_native,   // sdp/ao_conf_make_meta_native.d
-  ao_conf_make_meta_sdlang,   // sdp/ao_conf_make_meta_sdlang.d
-  ao_defaults,                // sdp/ao_defaults.d
-  ao_output_debugs,           // sdp/ao_output_debugs.d
-  ao_read_config_files,       // sdp/ao_read_config_files.d
-  ao_read_source_files,       // sdp/ao_read_source_files.d
-  ao_rgx,                     // sdp/ao_rgx.d
-  output_hub,                 // output_hub.d
-  output_html;                // output_html.d
+  compile_time_info,
+  ao_abstract_doc_source,
+  ao_conf_make_meta,
+  ao_conf_make_meta_native,
+  ao_conf_make_meta_sdlang,
+  ao_defaults,
+  ao_output_debugs,
+  ao_read_config_files,
+  ao_read_source_files,
+  ao_rgx,
+  output_hub,
+  output_epub,
+  output_html,
+  output_xhtmls,
+  source_sisupod;
 /+ sdlang http://sdlang.org +/
 import sdlang;                            // sdlang.d
 /+ std +/
@@ -29,6 +32,7 @@ private import
   std.process,
   std.stdio,
   std.file,
+  std.path,
   std.range,
   std.regex,
   std.string,
@@ -88,13 +92,15 @@ void main(string[] args) {
       );
     }
   }
-  bool[string] opt_action_bool = [
+  bool[string] _opt_action_bool = [
     "assertions"         : false,
     "concordance"        : false,
     "digest"             : false,
     "docbook"            : false,
     "epub"               : false,
     "html"               : false,
+    "html_seg"           : false,
+    "html_scroll"        : false,
     "manifest"           : false,
     "ocn"                : true,
     "odt"                : false,
@@ -121,38 +127,40 @@ void main(string[] args) {
   ];
   auto helpInfo = getopt(args,
     std.getopt.config.passThrough,
-    "assert",             "--assert set optional assertions on",                        &opt_action_bool["assertions"],
-    "concordance",        "--concordance file for document",                            &opt_action_bool["concordance"],
-    "digest",             "--digest hash digest for each object",                       &opt_action_bool["digest"],
-    "docbook",            "--docbook process docbook output",                           &opt_action_bool["docbook"],
-    "epub",               "--epub process epub output",                                 &opt_action_bool["epub"],
-    "html",               "--html process html output",                                 &opt_action_bool["html"],
-    "manifest",           "--manifest process manifest output",                         &opt_action_bool["manifest"],
-    "ocn",                "--ocn object cite numbers (default)",                        &opt_action_bool["ocn"],
-    "odf",                "--odf process odf:odt output",                               &opt_action_bool["odt"],
-    "odt",                "--odt process odf:odt output",                               &opt_action_bool["odt"],
-    "pdf",                "--pdf process pdf output",                                   &opt_action_bool["pdf"],
-    "pg",                 "--pg process postgresql output",                             &opt_action_bool["postgresql"],
-    "postgresql",         "--postgresql process postgresql output",                     &opt_action_bool["postgresql"],
-    "qrcode",             "--qrcode with document metadata",                            &opt_action_bool["qrcode"],
-    "sisupod",            "--sisupod sisupod source content bundled",                   &opt_action_bool["sisupod"],
-    "source",             "--source markup source text content",                        &opt_action_bool["source"],
-    "sqlite",             "--sqlite process sqlite output",                             &opt_action_bool["sqlite"],
-    "text",               "--text process text output",                                 &opt_action_bool["text"],
-    "txt",                "--txt process text output",                                  &opt_action_bool["text"],
-    "verbose|v",          "--verbose output to terminal",                               &opt_action_bool["verbose"],
-    "xhtml",              "--xhtml process xhtml output",                               &opt_action_bool["xhtml"],
-    "xml-dom",            "--xml-dom process xml dom output",                           &opt_action_bool["xml_dom"],
-    "xml-sax",            "--xml-sax process xml sax output",                           &opt_action_bool["xml_sax"],
-    "section-toc",        "--section-toc process table of contents (default)",          &opt_action_bool["section_toc"],
-    "section-body",       "--section-body process document body (default)",             &opt_action_bool["section_body"],
-    "section-endnotes",   "--section-endnotes process document endnotes (default)",     &opt_action_bool["section_endnotes"],
-    "section-glossary",   "--section-glossary process document glossary (default)",     &opt_action_bool["section_glossary"],
-    "section-biblio",     "--section-biblio process document biblio (default)",         &opt_action_bool["section_biblio"],
-    "section-bookindex",  "--section-bookindex process document bookindex (default)",   &opt_action_bool["section_bookindex"],
-    "section-blurb",      "--section-blurb process document blurb (default)",           &opt_action_bool["section_blurb"],
-    "backmatter",         "--section-backmatter process document backmatter (default)", &opt_action_bool["backmatter"],
-    "skip_output",        "--skip-output",                                              &opt_action_bool["skip_output"],
+    "assert",             "--assert set optional assertions on",                        &_opt_action_bool["assertions"],
+    "concordance",        "--concordance file for document",                            &_opt_action_bool["concordance"],
+    "digest",             "--digest hash digest for each object",                       &_opt_action_bool["digest"],
+    "docbook",            "--docbook process docbook output",                           &_opt_action_bool["docbook"],
+    "epub",               "--epub process epub output",                                 &_opt_action_bool["epub"],
+    "html",               "--html process html output",                                 &_opt_action_bool["html"],
+    "html_seg",           "--html-seg process html output",                             &_opt_action_bool["html_seg"],
+    "html_scroll",        "--html-seg process html output",                             &_opt_action_bool["html_scroll"],
+    "manifest",           "--manifest process manifest output",                         &_opt_action_bool["manifest"],
+    "ocn",                "--ocn object cite numbers (default)",                        &_opt_action_bool["ocn"],
+    "odf",                "--odf process odf:odt output",                               &_opt_action_bool["odt"],
+    "odt",                "--odt process odf:odt output",                               &_opt_action_bool["odt"],
+    "pdf",                "--pdf process pdf output",                                   &_opt_action_bool["pdf"],
+    "pg",                 "--pg process postgresql output",                             &_opt_action_bool["postgresql"],
+    "postgresql",         "--postgresql process postgresql output",                     &_opt_action_bool["postgresql"],
+    "qrcode",             "--qrcode with document metadata",                            &_opt_action_bool["qrcode"],
+    "sisupod",            "--sisupod sisupod source content bundled",                   &_opt_action_bool["sisupod"],
+    "source",             "--source markup source text content",                        &_opt_action_bool["source"],
+    "sqlite",             "--sqlite process sqlite output",                             &_opt_action_bool["sqlite"],
+    "text",               "--text process text output",                                 &_opt_action_bool["text"],
+    "txt",                "--txt process text output",                                  &_opt_action_bool["text"],
+    "verbose|v",          "--verbose output to terminal",                               &_opt_action_bool["verbose"],
+    "xhtml",              "--xhtml process xhtml output",                               &_opt_action_bool["xhtml"],
+    "xml-dom",            "--xml-dom process xml dom output",                           &_opt_action_bool["xml_dom"],
+    "xml-sax",            "--xml-sax process xml sax output",                           &_opt_action_bool["xml_sax"],
+    "section-toc",        "--section-toc process table of contents (default)",          &_opt_action_bool["section_toc"],
+    "section-body",       "--section-body process document body (default)",             &_opt_action_bool["section_body"],
+    "section-endnotes",   "--section-endnotes process document endnotes (default)",     &_opt_action_bool["section_endnotes"],
+    "section-glossary",   "--section-glossary process document glossary (default)",     &_opt_action_bool["section_glossary"],
+    "section-biblio",     "--section-biblio process document biblio (default)",         &_opt_action_bool["section_biblio"],
+    "section-bookindex",  "--section-bookindex process document bookindex (default)",   &_opt_action_bool["section_bookindex"],
+    "section-blurb",      "--section-blurb process document blurb (default)",           &_opt_action_bool["section_blurb"],
+    "backmatter",         "--section-backmatter process document backmatter (default)", &_opt_action_bool["backmatter"],
+    "skip_output",        "--skip-output",                                              &_opt_action_bool["skip_output"],
   );
   if (helpInfo.helpWanted) {
     defaultGetoptPrinter("Some information about the program.", helpInfo.options);
@@ -210,70 +218,89 @@ void main(string[] args) {
       /+ ↓ split header into make and meta +/
       auto header_make_and_meta_tuple = head.headerContentAA(header, conf_doc_make_aa);
       static assert(!isTypeTuple!(header_make_and_meta_tuple));
-      string[string][string] dochead_make = header_make_and_meta_tuple[0];
-      string[string][string] dochead_meta = header_make_and_meta_tuple[1];
+      string[string][string] _dochead_make = header_make_and_meta_tuple[0];
+      string[string][string] _dochead_meta = header_make_and_meta_tuple[1];
       /+ ↓ document abstraction: process document, return abstraction as tuple +/
-      auto t = abs.abstract_doc_source(content_body, dochead_make, dochead_meta, opt_action_bool);
+      auto t = abs.abstract_doc_source(content_body, _dochead_make, _dochead_meta, _opt_action_bool);
       static assert(!isTypeTuple!(t));
-      auto doc_ao_contents = t[0]; // head ~ toc ~ contents ~ endnotes_seg ~ glossary ~ bibliography ~ bookindex ~blurb;
-      auto doc_html_segnames = t[1];
+      auto doc_abstraction = t[0]; // head ~ toc ~ contents ~ endnotes_seg ~ glossary ~ bibliography ~ bookindex ~blurb;
+      string[] doc_html_segnames = t[1];
       string[][string] document_section_keys_sequenced = [
-        "seg": ["head", "toc_seg", "body",],
+        "seg":    ["head", "toc_seg", "body",],
         "scroll": ["head", "toc_scroll", "body",]
       ];
-      if (doc_ao_contents["endnotes_seg"].length > 1) {
-        document_section_keys_sequenced["seg"] ~= "endnotes_seg";
+      if (doc_abstraction["endnotes"].length > 1) {
+        document_section_keys_sequenced["seg"]    ~= "endnotes";
+        document_section_keys_sequenced["scroll"] ~= "endnotes";
       }
-      if (doc_ao_contents["endnotes_scroll"].length > 1) {
-        document_section_keys_sequenced["scroll"] ~= "endnotes_scroll";
-      }
-      if (doc_ao_contents["glossary"].length > 1) {
-        document_section_keys_sequenced["seg"] ~= "glossary";
+      if (doc_abstraction["glossary"].length > 1) {
+        document_section_keys_sequenced["seg"]    ~= "glossary";
         document_section_keys_sequenced["scroll"] ~= "glossary";
       }
-      if (doc_ao_contents["bibliography"].length > 1) {
-        document_section_keys_sequenced["seg"] ~= "bibliography";
+      if (doc_abstraction["bibliography"].length > 1) {
+        document_section_keys_sequenced["seg"]    ~= "bibliography";
         document_section_keys_sequenced["scroll"] ~= "bibliography";
       }
-      if (doc_ao_contents["bookindex_seg"].length > 1) {
-        document_section_keys_sequenced["seg"] ~= "bookindex_seg";
+      if (doc_abstraction["bookindex_seg"].length > 1) {
+        document_section_keys_sequenced["seg"]    ~= "bookindex_seg";
       }
-      if (doc_ao_contents["bookindex_scroll"].length > 1) {
+      if (doc_abstraction["bookindex_scroll"].length > 1) {
         document_section_keys_sequenced["scroll"] ~= "bookindex_scroll";
       }
-      if (doc_ao_contents["blurb"].length > 1) {
-        document_section_keys_sequenced["seg"] ~= "blurb";
+      if (doc_abstraction["blurb"].length > 1) {
+        document_section_keys_sequenced["seg"]    ~= "blurb";
         document_section_keys_sequenced["scroll"] ~= "blurb";
       }
-      if ((opt_action_bool["html"])
-      || (opt_action_bool["html_scroll"])
-      || (opt_action_bool["html_seg"])
-      || (opt_action_bool["epub"])) {
-        document_section_keys_sequenced["seg"] ~= "tail";
+      if ((_opt_action_bool["html"])
+      || (_opt_action_bool["html_scroll"])
+      || (_opt_action_bool["html_seg"])
+      || (_opt_action_bool["epub"])) {
+        document_section_keys_sequenced["seg"]    ~= "tail";
         document_section_keys_sequenced["scroll"] ~= "tail";
       }
+      struct DocumentMatters {
+        string[] keys_seq_seg() {
+          string[] _k = document_section_keys_sequenced["seg"];
+          return _k;
+        }
+        string[] keys_seq_scroll() {
+          string[] _k = document_section_keys_sequenced["scroll"];
+          return _k;
+        }
+        string[] segnames() {
+          string[] _k = doc_html_segnames;
+          return _k;
+        }
+        auto dochead_make() {
+          string[string][string] _k = _dochead_make;
+          return _k;
+        }
+        auto dochead_meta() {
+          string[string][string] _k = _dochead_meta;
+          return _k;
+        }
+        auto source_filename() {
+          string _k = fn_src;
+          return _k;
+        }
+        auto opt_action_bool() {
+          bool[string] _k = _opt_action_bool;
+          return _k;
+        }
+      }
+      auto doc_matters = DocumentMatters();
       /+ ↓ debugs +/
       debug(checkdoc) {
         dbg.abstract_doc_source_debugs(
-          doc_ao_contents,
-          document_section_keys_sequenced,
-          doc_html_segnames,
-          dochead_make,
-          dochead_meta,
-          fn_src,
-          opt_action_bool
+          doc_abstraction,
+          doc_matters,
         );
       }
       /+ ↓ output hub +/
-      if (!(opt_action_bool["skip_output"])) {
+      if (!(_opt_action_bool["skip_output"])) {
         output.hub(
-          doc_ao_contents,
-          document_section_keys_sequenced,
-          doc_html_segnames,
-          dochead_make,
-          dochead_meta,
-          fn_src,
-          opt_action_bool
+          doc_abstraction,
+          doc_matters,
         );
       }
       scope(exit) {
@@ -285,7 +312,7 @@ void main(string[] args) {
         }
         destroy(content_body);
         destroy(t);
-        destroy(doc_ao_contents);
+        destroy(doc_abstraction);
         destroy(doc_html_segnames);
         destroy(fn_src);
       }
diff --git a/src/sdp/ao_abstract_doc_source.d b/src/sdp/ao_abstract_doc_source.d
index c11ee4a..ec1536e 100644
--- a/src/sdp/ao_abstract_doc_source.d
+++ b/src/sdp/ao_abstract_doc_source.d
@@ -23,7 +23,9 @@ template SiSUdocAbstraction() {
     string[string] an_object, processing;
     string an_object_key;
     string[] anchor_tags;
+    string anchor_tag_;
     string segment_anchor_tag_that_object_belongs_to;
+    string segment_anchor_tag_that_object_belongs_to_uri;
     auto note_section = NotesSection();
     /+ enum +/
     enum State { off, on }
@@ -68,6 +70,58 @@ template SiSUdocAbstraction() {
     int[] dom_collapsed = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
     int[] dom_collapsed_buffer = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
     enum DomTags { none, open, close, close_and_open, open_still, }
+    void heading_ancestors(O)(
+      auto ref O         obj,
+      ref string[]       lv_ancestors,
+    ) {
+      switch (obj.heading_lev_markup) {
+      case 0:
+        lv_ancestors[0] = to!string(obj.text);
+        foreach(k; 1..8) {                               // 1 .. 7 ?
+          lv_ancestors[k] = "";
+        }
+        goto default;
+      case 1:
+        lv_ancestors[1] = to!string(obj.text);
+        foreach(k; 2..8) {
+          lv_ancestors[k] = "";
+        }
+        goto default;
+      case 2:
+        lv_ancestors[2] = to!string(obj.text);
+        foreach(k; 3..8) {
+          lv_ancestors[k] = "";
+        }
+        goto default;
+      case 3:
+        lv_ancestors[3] = to!string(obj.text);
+        foreach(k; 4..8) {
+          lv_ancestors[k] = "";
+        }
+        goto default;
+      case 4:
+        lv_ancestors[4] = to!string(obj.text);
+        foreach(k; 5..8) {
+          lv_ancestors[k] = "";
+        }
+        goto default;
+      case 5:
+        lv_ancestors[5] = to!string(obj.text);
+        foreach(k; 6..8) {
+          lv_ancestors[k] = "";
+        }
+        goto default;
+      case 6:
+        lv_ancestors[6] = to!string(obj.text);
+        lv_ancestors[7] = "";
+        goto default;
+      case 7:
+        lv_ancestors[7] = to!string(obj.text);
+        goto default;
+      default:
+        obj.heading_ancestors_text = lv_ancestors.dup;
+      }
+    }
     auto dom_set_markup_tags(int[] dom, int lev) {
       foreach (i; 0 .. 8) {
         if (i < lev) {
@@ -197,6 +251,7 @@ template SiSUdocAbstraction() {
         "start" : "",
         "end"   : ""
       ];
+      string[] lv_ancestors = [ "", "", "", "", "", "", "", "", ];
       int[string] lv = [
         "lv" : State.off,
         "h0" : State.off,
@@ -654,9 +709,16 @@ template SiSUdocAbstraction() {
                 anchor_tags = substantive_object_and_anchor_tags_tuple[1];
                 if (to!int(an_object["lev_markup_number"]) == 4) {
                   segment_anchor_tag_that_object_belongs_to = anchor_tags[0];
+                  segment_anchor_tag_that_object_belongs_to_uri = anchor_tags[0] ~ ".fnSuffix";
+                  anchor_tag_ = anchor_tags[0];
+                } else if (to!int(an_object["lev_markup_number"]) > 4) {
+                  segment_anchor_tag_that_object_belongs_to = anchor_tag_;
+                  segment_anchor_tag_that_object_belongs_to_uri = anchor_tag_ ~ ".fnSuffix#" ~ to!string(obj_cite_number);
                 } else if (to!int(an_object["lev_markup_number"]) < 4) {
                   segment_anchor_tag_that_object_belongs_to = "";
+                  segment_anchor_tag_that_object_belongs_to_uri = "";
                 }
+                /+ (incrementally build toc) table of contents here! +/
                 _anchor_tag=to!string(obj_cite_number);
                 the_table_of_contents_section = obj_im.table_of_contents_gather_headings(
                   an_object,
@@ -681,6 +743,7 @@ template SiSUdocAbstraction() {
                     obj_cite_number,                              // int
                     cntr,                                         // int
                     heading_ptr,                                  // int
+                    lv_ancestors,                                 // string[]
                     an_object["is"],                              // string
                     html_segnames_ptr,                            // int
                   );
@@ -801,9 +864,9 @@ template SiSUdocAbstraction() {
         writefln(
           "%s %s",
           __LINE__,
-          the_endnotes_section["seg"].length
+          the_endnotes_section.length
         );
-        foreach (o; the_endnotes_section["seg"]) {
+        foreach (o; the_endnotes_section) {
           writeln(o);
         }
       }
@@ -965,9 +1028,9 @@ template SiSUdocAbstraction() {
       comp_obj_toc.indent_hang           = indent["hang_position"];
       comp_obj_toc.indent_base           = indent["base_position"];
       comp_obj_toc.bullet                = false;
-      if (the_endnotes_section["seg"].length > 1) {
+      if (the_endnotes_section.length > 1) {
         toc_txt_ = format(
-          "{ %s }../%s.fn_suffix",
+          "{ %s }../%s.fnSuffix",
           "Endnotes",
           "endnotes",            // segment_anchor_tag_that_object_belongs_to
         );
@@ -975,19 +1038,9 @@ template SiSUdocAbstraction() {
         comp_obj_toc.text                       = to!string(toc_txt_).strip;
         the_table_of_contents_section["seg"]    ~= comp_obj_toc;
       }
-      if (the_endnotes_section["scroll"].length > 1) {
-        toc_txt_ = format(
-          "{ %s }#%s",
-          "Endnotes",
-          "endnotes",            // _anchor_tag
-        );
-        toc_txt_= munge.url_links(toc_txt_);
-        comp_obj_toc.text                       = to!string(toc_txt_).strip;
-        the_table_of_contents_section["scroll"] ~= comp_obj_toc;
-      }
       if (the_glossary_section.length > 1) {
         toc_txt_ = format(
-          "{ %s }../%s.fn_suffixs",
+          "{ %s }../%s.fnSuffixs",
           "Glossary",
           "glossary",  // segment_anchor_tag_that_object_belongs_to
         );
@@ -1005,7 +1058,7 @@ template SiSUdocAbstraction() {
       }
       if (the_bibliography_section.length > 1){
         toc_txt_ = format(
-          "{ %s }../%s.fn_suffix",
+          "{ %s }../%s.fnSuffix",
           "Bibliography",
           "bibliography",        // segment_anchor_tag_that_object_belongs_to
         );
@@ -1024,7 +1077,7 @@ template SiSUdocAbstraction() {
       }
       if (the_bookindex_section["seg"].length > 1) {
         toc_txt_ = format(
-          "{ %s }../%s.fn_suffix",
+          "{ %s }../%s.fnSuffix",
           "Book Index",
           "bookindex",          // segment_anchor_tag_that_object_belongs_to
         );
@@ -1044,7 +1097,7 @@ template SiSUdocAbstraction() {
       }
       if (the_blurb_section.length > 1) {
         toc_txt_ = format(
-          "{ %s }../%s.fn_suffix",
+          "{ %s }../%s.fnSuffix",
           "Blurb",
           "blurb",                // segment_anchor_tag_that_object_belongs_to
         );
@@ -1070,18 +1123,22 @@ template SiSUdocAbstraction() {
           writeln(mkup.indent_by_spaces_provided(toc_linked_heading.indent_hang), toc_linked_heading.text);
         }
       }
+      debug(tocscroll) {
+        writefln(
+          "%s %s",
+          __LINE__,
+          the_table_of_contents_section["seg"].length
+        );
+        foreach (toc_linked_heading; the_table_of_contents_section["scroll"]) {
+          writeln(mkup.indent_by_spaces_provided(toc_linked_heading.indent_hang), toc_linked_heading.text);
+        }
+      }
       the_document_head_section ~= the_document_body_section[0];
       the_document_body_section=the_document_body_section[1..$];
-      if (the_endnotes_section["scroll"].length > 1) {
+      if (the_endnotes_section.length > 1) {
         html_segnames ~= "endnotes";
         html_segnames_ptr = html_segnames_ptr_cntr;
-        foreach (ref section; the_endnotes_section["scroll"]) {
-          if (section.heading_lev_markup == 4) {
-            section.ptr_html_segnames = html_segnames_ptr;
-            break;
-          }
-        }
-        foreach (ref section; the_endnotes_section["seg"]) {
+        foreach (ref section; the_endnotes_section) {
           if (section.heading_lev_markup == 4) {
             section.ptr_html_segnames = html_segnames_ptr;
             break;
@@ -1139,227 +1196,251 @@ template SiSUdocAbstraction() {
         }
         html_segnames_ptr_cntr++;
       }
-      if ((opt_action_bool["html"])
-      || (opt_action_bool["html_scroll"])
-      || (opt_action_bool["html_seg"])
-      || (opt_action_bool["epub"])) {
-        foreach (ref obj; the_document_head_section) {
+      foreach (ref obj; the_document_head_section) {
+        if (obj.is_a == "heading") {
+          debug(dom) {
+            writeln(obj.text);
+          }
+          if ((opt_action_bool["html"])
+          || (opt_action_bool["html_scroll"])
+          || (opt_action_bool["html_seg"])
+          || (opt_action_bool["epub"])) {
+            obj.dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup).dup;
+            obj.dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed).dup;
+          }
+          heading_ancestors(obj, lv_ancestors);
+        }
+      }
+      if (the_table_of_contents_section["scroll"].length > 1) {
+        dom_markedup_buffer = dom_markedup.dup;
+        dom_collapsed_buffer = dom_collapsed.dup;
+        foreach (ref obj; the_table_of_contents_section["scroll"]) {
           if (obj.is_a == "heading") {
             debug(dom) {
-              writeln(obj.text);
+            // writeln(obj.text);
+            }
+            if (obj.heading_lev_markup == 4) {
+              obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+              assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
             }
-            dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
-            obj.dom_markedup = dom_markedup.dup;
-            dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
-            obj.dom_collapsed = dom_collapsed.dup;
+            if ((opt_action_bool["html"])
+            || (opt_action_bool["html_scroll"])
+            || (opt_action_bool["html_seg"])
+            || (opt_action_bool["epub"])) {
+              obj.dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup).dup;
+              obj.dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed).dup;
+            }
+            heading_ancestors(obj, lv_ancestors);
           }
         }
-        if (the_table_of_contents_section["scroll"].length > 1) {
-          dom_markedup_buffer = dom_markedup.dup;
-          dom_collapsed_buffer = dom_collapsed.dup;
-          foreach (ref obj; the_table_of_contents_section["scroll"]) {
-            if (obj.is_a == "heading") {
-              debug(dom) {
-              // writeln(obj.text);
-              }
-              if (obj.heading_lev_markup == 4) {
-                obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
-                assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
-              }
-              dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
-              obj.dom_markedup = dom_markedup.dup;
-              dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
-              obj.dom_collapsed = dom_collapsed.dup;
+        dom_markedup = dom_markedup_buffer.dup;
+        dom_collapsed = dom_collapsed_buffer.dup;
+        foreach (ref obj; the_table_of_contents_section["seg"]) {
+          if (obj.is_a == "heading") {
+            debug(dom) {
+              writeln(obj.text);
+            }
+            if (obj.heading_lev_markup == 4) {
+              obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
+              assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
             }
+            if ((opt_action_bool["html"])
+            || (opt_action_bool["html_scroll"])
+            || (opt_action_bool["html_seg"])
+            || (opt_action_bool["epub"])) {
+              obj.dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup).dup;
+              obj.dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed).dup;
+            }
+            heading_ancestors(obj, lv_ancestors);
           }
-          dom_markedup = dom_markedup_buffer.dup;
-          dom_collapsed = dom_collapsed_buffer.dup;
-          foreach (ref obj; the_table_of_contents_section["seg"]) {
-            if (obj.is_a == "heading") {
-              debug(dom) {
-                writeln(obj.text);
-              }
-              if (obj.heading_lev_markup == 4) {
+        }
+      }
+      /+ multiple 1~ levels, loop through document body +/
+      if (the_document_body_section.length > 1) {
+        foreach (ref obj; the_document_body_section) {
+          if (obj.is_a == "heading") {
+            debug(dom) {
+              writeln(obj.text);
+            }
+            if (obj.heading_lev_markup == 4) {
+              obj.lev4_subtoc = lev4_subtoc[obj.segment_anchor_tag];
+              obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+              if (html_segnames.length > obj.ptr_html_segnames + 1) {
                 obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
-                assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
               }
-              dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
-              obj.dom_markedup = dom_markedup.dup;
-              dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
-              obj.dom_collapsed = dom_collapsed.dup;
+              assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
             }
+            if ((opt_action_bool["html"])
+            || (opt_action_bool["html_scroll"])
+            || (opt_action_bool["html_seg"])
+            || (opt_action_bool["epub"])) {
+              obj.dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup).dup;
+              obj.dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed).dup;
+            }
+            heading_ancestors(obj, lv_ancestors);
           }
         }
-        /+ multiple 1~ levels, loop through document body +/
-        if (the_document_body_section.length > 1) {
-          foreach (ref obj; the_document_body_section) {
-            if (obj.is_a == "heading") {
-              debug(dom) {
-                writeln(obj.text);
-              }
-              if (obj.heading_lev_markup == 4) {
-                obj.lev4_subtoc = lev4_subtoc[obj.segment_anchor_tag];
-                obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
-                if (html_segnames.length > obj.ptr_html_segnames + 1) {
-                  obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
-                }
-                assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+      }
+      /+ optional only one 1~ level +/
+      if (the_endnotes_section.length > 1) {
+        dom_markedup_buffer = dom_markedup.dup;
+        dom_collapsed_buffer = dom_collapsed.dup;
+        dom_markedup = dom_markedup_buffer.dup;
+        dom_collapsed = dom_collapsed_buffer.dup;
+        foreach (ref obj; the_endnotes_section) {
+          if (obj.is_a == "heading") {
+            debug(dom) {
+              writeln(obj.text);
+            }
+            if (obj.heading_lev_markup == 4) {
+              obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+              if (html_segnames.length > obj.ptr_html_segnames + 1) {
+                obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
               }
-              dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
-              obj.dom_markedup = dom_markedup.dup;
-              dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
-              obj.dom_collapsed = dom_collapsed.dup;
+              assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
             }
+            if ((opt_action_bool["html"])
+            || (opt_action_bool["html_scroll"])
+            || (opt_action_bool["html_seg"])
+            || (opt_action_bool["epub"])) {
+              obj.dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup).dup;
+              obj.dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed).dup;
+            }
+            heading_ancestors(obj, lv_ancestors);
           }
         }
-        /+ optional only one 1~ level +/
-        if (the_endnotes_section["scroll"].length > 1) {
-          dom_markedup_buffer = dom_markedup.dup;
-          dom_collapsed_buffer = dom_collapsed.dup;
-          foreach (ref obj; the_endnotes_section["scroll"]) {
-            if (obj.is_a == "heading") {
-              debug(dom) {
-              }
-              if (obj.heading_lev_markup == 4) {
-                obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
-                if (html_segnames.length > obj.ptr_html_segnames + 1) {
-                  obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
-                }
-                assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
-              }
-              dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
-              obj.dom_markedup = dom_markedup.dup;
-              dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
-              obj.dom_collapsed = dom_collapsed.dup;
+      }
+      /+ optional only one 1~ level +/
+      if (the_glossary_section.length > 1) {
+        foreach (ref obj; the_glossary_section) {
+          if (obj.is_a == "heading") {
+            debug(dom) {
+              writeln(obj.text);
             }
-          }
-          dom_markedup = dom_markedup_buffer.dup;
-          dom_collapsed = dom_collapsed_buffer.dup;
-          foreach (ref obj; the_endnotes_section["seg"]) {
-            if (obj.is_a == "heading") {
-              debug(dom) {
-                writeln(obj.text);
-              }
-              if (obj.heading_lev_markup == 4) {
-                obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
-                if (html_segnames.length > obj.ptr_html_segnames + 1) {
-                  obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
-                }
-                assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+            if (obj.heading_lev_markup == 4) {
+              obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+              if (html_segnames.length > obj.ptr_html_segnames + 1) {
+                obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
               }
-              dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
-              obj.dom_markedup = dom_markedup.dup;
-              dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
-              obj.dom_collapsed = dom_collapsed.dup;
+              assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+            }
+            if ((opt_action_bool["html"])
+            || (opt_action_bool["html_scroll"])
+            || (opt_action_bool["html_seg"])
+            || (opt_action_bool["epub"])) {
+              obj.dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup).dup;
+              obj.dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed).dup;
             }
+            heading_ancestors(obj, lv_ancestors);
           }
         }
-        /+ optional only one 1~ level +/
-        if (the_glossary_section.length > 1) {
-          foreach (ref obj; the_glossary_section) {
-            if (obj.is_a == "heading") {
-              debug(dom) {
-                writeln(obj.text);
-              }
-              if (obj.heading_lev_markup == 4) {
-                obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
-                if (html_segnames.length > obj.ptr_html_segnames + 1) {
-                  obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
-                }
-                assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+      }
+      /+ optional only one 1~ level +/
+      if (the_bibliography_section.length > 1) {
+        foreach (ref obj; the_bibliography_section) {
+          if (obj.is_a == "heading") {
+            debug(dom) {
+              writeln(obj.text);
+            }
+            if (obj.heading_lev_markup == 4) {
+              obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+              if (html_segnames.length > obj.ptr_html_segnames + 1) {
+                obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
               }
-              dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
-              obj.dom_markedup = dom_markedup.dup;
-              dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
-              obj.dom_collapsed = dom_collapsed.dup;
+              assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+            }
+            if ((opt_action_bool["html"])
+            || (opt_action_bool["html_scroll"])
+            || (opt_action_bool["html_seg"])
+            || (opt_action_bool["epub"])) {
+              obj.dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup).dup;
+              obj.dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed).dup;
             }
+            heading_ancestors(obj, lv_ancestors);
           }
         }
-        /+ optional only one 1~ level +/
-        if (the_bibliography_section.length > 1) {
-          foreach (ref obj; the_bibliography_section) {
-            if (obj.is_a == "heading") {
-              debug(dom) {
-                writeln(obj.text);
-              }
-              if (obj.heading_lev_markup == 4) {
-                obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
-                if (html_segnames.length > obj.ptr_html_segnames + 1) {
-                  obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
-                }
-                assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+      }
+      /+ optional only one 1~ level +/
+      if (the_bookindex_section["scroll"].length > 1) {
+        dom_markedup_buffer = dom_markedup.dup;
+        dom_collapsed_buffer = dom_collapsed.dup;
+        foreach (ref obj; the_bookindex_section["scroll"]) {
+          if (obj.is_a == "heading") {
+            debug(dom) {
+            // writeln(obj.text);
+            }
+            if (obj.heading_lev_markup == 4) {
+              obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+              if (html_segnames.length > obj.ptr_html_segnames + 1) {
+                obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
               }
-              dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
-              obj.dom_markedup = dom_markedup.dup;
-              dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
-              obj.dom_collapsed = dom_collapsed.dup;
+              assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+            }
+            if ((opt_action_bool["html"])
+            || (opt_action_bool["html_scroll"])
+            || (opt_action_bool["html_seg"])
+            || (opt_action_bool["epub"])) {
+              obj.dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup).dup;
+              obj.dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed).dup;
             }
+            heading_ancestors(obj, lv_ancestors);
           }
         }
-        /+ optional only one 1~ level +/
-        if (the_bookindex_section["scroll"].length > 1) {
-          dom_markedup_buffer = dom_markedup.dup;
-          dom_collapsed_buffer = dom_collapsed.dup;
-          foreach (ref obj; the_bookindex_section["scroll"]) {
-            if (obj.is_a == "heading") {
-              debug(dom) {
-              // writeln(obj.text);
-              }
-              if (obj.heading_lev_markup == 4) {
-                obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
-                if (html_segnames.length > obj.ptr_html_segnames + 1) {
-                  obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
-                }
-                assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
-              }
-              dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
-              obj.dom_markedup = dom_markedup.dup;
-              dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
-              obj.dom_collapsed = dom_collapsed.dup;
+        dom_markedup = dom_markedup_buffer.dup;
+        dom_collapsed = dom_collapsed_buffer.dup;
+        foreach (ref obj; the_bookindex_section["seg"]) {
+          if (obj.is_a == "heading") {
+            debug(dom) {
+              writeln(obj.text);
             }
-          }
-          dom_markedup = dom_markedup_buffer.dup;
-          dom_collapsed = dom_collapsed_buffer.dup;
-          foreach (ref obj; the_bookindex_section["seg"]) {
-            if (obj.is_a == "heading") {
-              debug(dom) {
-                writeln(obj.text);
-              }
-              if (obj.heading_lev_markup == 4) {
-                obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
-                if (html_segnames.length > obj.ptr_html_segnames + 1) {
-                  obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
-                }
-                assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+            if (obj.heading_lev_markup == 4) {
+              obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+              if (html_segnames.length > obj.ptr_html_segnames + 1) {
+                obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
               }
-              dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
-              obj.dom_markedup = dom_markedup.dup;
-              dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
-              obj.dom_collapsed = dom_collapsed.dup;
+              assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
             }
+            if ((opt_action_bool["html"])
+            || (opt_action_bool["html_scroll"])
+            || (opt_action_bool["html_seg"])
+            || (opt_action_bool["epub"])) {
+              obj.dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup).dup;
+              obj.dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed).dup;
+            }
+            heading_ancestors(obj, lv_ancestors);
           }
         }
-        /+ optional only one 1~ level +/
-        if (the_blurb_section.length > 1) {
-          foreach (ref obj; the_blurb_section) {
-            if (obj.is_a == "heading") {
-              debug(dom) {
-                writeln(obj.text);
-              }
-              if (obj.heading_lev_markup == 4) {
-                obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
-                if (html_segnames.length > obj.ptr_html_segnames + 1) {
-                  obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
-                }
-                assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+      }
+      /+ optional only one 1~ level +/
+      if (the_blurb_section.length > 1) {
+        foreach (ref obj; the_blurb_section) {
+          if (obj.is_a == "heading") {
+            debug(dom) {
+              writeln(obj.text);
+            }
+            if (obj.heading_lev_markup == 4) {
+              obj.segname_prev = html_segnames[obj.ptr_html_segnames - 1];
+              if (html_segnames.length > obj.ptr_html_segnames + 1) {
+                obj.segname_next = html_segnames[obj.ptr_html_segnames + 1];
               }
-              dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup);
-              obj.dom_markedup = dom_markedup.dup;
-              dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed);
-              obj.dom_collapsed = dom_collapsed.dup;
+              assert(obj.segment_anchor_tag == html_segnames[obj.ptr_html_segnames]);
+            }
+            if ((opt_action_bool["html"])
+            || (opt_action_bool["html_scroll"])
+            || (opt_action_bool["html_seg"])
+            || (opt_action_bool["epub"])) {
+              obj.dom_markedup = dom_set_markup_tags(dom_markedup, obj.heading_lev_markup).dup;
+              obj.dom_collapsed = dom_set_collapsed_tags(dom_collapsed, obj.heading_lev_collapsed).dup;
             }
+            heading_ancestors(obj, lv_ancestors);
           }
         }
+        /+ TODO
+          - note create/insert heading object sole purpose eof close all open tags
+            sort out:
+            - obj.dom_markedup = dom_markedup;
+            - obj.dom_collapsed = dom_collapsed;
+        +/
         dom_markedup = dom_set_markup_tags(dom_markedup, 0);
         dom_collapsed = dom_set_collapsed_tags(dom_collapsed, 0);
         comp_obj_heading_                       = comp_obj_heading_.init;
@@ -1386,8 +1467,7 @@ template SiSUdocAbstraction() {
         /+ substantive/body: +/
         "body":             the_document_body_section,
         /+ backmatter: +/
-        "endnotes_seg":     the_endnotes_section["seg"],
-        "endnotes_scroll":  the_endnotes_section["scroll"],
+        "endnotes":         the_endnotes_section,
         "glossary":         the_glossary_section,
         "bibliography":     the_bibliography_section,
         "bookindex_scroll": the_bookindex_section["scroll"],
@@ -3112,7 +3192,7 @@ template SiSUdocAbstraction() {
             "hang_position" : 0,
             "base_position" : 0,
           ];
-          toc_txt_ = "{ Table of Contents }../toc.fn_suffix";
+          toc_txt_ = "{ Table of Contents }../toc.fnSuffix";
           toc_txt_= munge.url_links(toc_txt_);
           comp_obj_toc.indent_hang             = indent["hang_position"];
           comp_obj_toc.indent_base             = indent["base_position"];
@@ -3136,7 +3216,7 @@ template SiSUdocAbstraction() {
           break;
         case 4:
           toc_txt_ = format(
-            "{ %s }../%s.fn_suffix",
+            "{ %s }../%s.fnSuffix",
             heading_toc_,
             segment_anchor_tag_that_object_belongs_to,
           );
@@ -3153,12 +3233,12 @@ template SiSUdocAbstraction() {
           break;
         case 5: .. case 7:
           toc_txt_ = format(
-            "{ %s }../%s.fn_suffix#%s",
+            "{ %s }../%s.fnSuffix#%s",
             heading_toc_,
             segment_anchor_tag_that_object_belongs_to,
             _anchor_tag,
           );
-          subtoc_txt_ = format(                         // 5 .. 7
+          subtoc_txt_ = format(
             "{ %s }#%s",
             heading_toc_,
             _anchor_tag,
@@ -3772,7 +3852,7 @@ template SiSUdocAbstraction() {
               bi_tmp_scroll ~= munge.url_links(" {" ~ ref_ ~ "}#" ~ go ~ ", ");
               bi_tmp_seg ~= (segment_anchor_tag_that_object_belongs_to.empty)
               ? munge.url_links(" {" ~ ref_ ~ "}#" ~ go ~ ", ")
-              : munge.url_links(" {" ~ ref_ ~ "}../" ~ segment_anchor_tag_that_object_belongs_to ~ ".fn_suffix#" ~ go ~ ", ");
+              : munge.url_links(" {" ~ ref_ ~ "}../" ~ segment_anchor_tag_that_object_belongs_to ~ ".fnSuffix#" ~ go ~ ", ");
             }
             bi_tmp_scroll ~= " \\\\\n    ";
             bi_tmp_seg ~= " \\\\\n    ";
@@ -3789,7 +3869,7 @@ template SiSUdocAbstraction() {
                 bi_tmp_scroll ~= munge.url_links(" {" ~ ref_ ~ "}#" ~ go ~ ", ");
                 bi_tmp_seg ~= (segment_anchor_tag_that_object_belongs_to.empty)
                 ? munge.url_links(" {" ~ ref_ ~ "}#" ~ go ~ ", ")
-                : munge.url_links(" {" ~ ref_ ~ "}../" ~ segment_anchor_tag_that_object_belongs_to ~ ".fn_suffix#" ~ go ~ ", ");
+                : munge.url_links(" {" ~ ref_ ~ "}../" ~ segment_anchor_tag_that_object_belongs_to ~ ".fnSuffix#" ~ go ~ ", ");
               }
               bi_tmp_scroll ~= " \\\\\n    ";
               bi_tmp_seg ~= " \\\\\n    ";
@@ -3867,25 +3947,21 @@ template SiSUdocAbstraction() {
         ) {
           debug(endnotes_build) {
             writeln(
-              "{^{", m.captures[1], ".}^}../", segment_anchor_tag_that_object_belongs_to, ".fn_suffix#noteref_\n  ", m.captures[1], " ",
+              "{^{", m.captures[1], ".}^}../", segment_anchor_tag_that_object_belongs_to, ".fnSuffix#noteref_\n  ", m.captures[1], " ",
               m.captures[2]); // sometimes need segment name (segmented html & epub)
           }
           // TODO NEXT you need anchor for segments at this point ->
           object_notes["anchor"] ~= "#note_" ~ m.captures[1] ~ "』";
-          object_notes["seg"] ~= (segment_anchor_tag_that_object_belongs_to.empty)
+          object_notes["notes"] ~= (segment_anchor_tag_that_object_belongs_to.empty)
           ? (munge.url_links(
               "{^{" ~ m.captures[1] ~ ".}^}#noteref_" ~
               m.captures[1]) ~ " " ~ m.captures[2] ~ "』"
             )
           : (munge.url_links(
-              "{^{" ~ m.captures[1] ~ ".}^}../" ~ segment_anchor_tag_that_object_belongs_to ~ ".fn_suffix#noteref_" ~
+              "{^{" ~ m.captures[1] ~ ".}^}../" ~
+              segment_anchor_tag_that_object_belongs_to ~ ".fnSuffix#noteref_" ~
               m.captures[1]) ~ " " ~ m.captures[2] ~ "』"
             );
-          object_notes["scroll"] ~=
-            munge.url_links(
-              "{^{" ~ m.captures[1] ~ ".}^}#noteref_" ~
-              m.captures[1]
-            ) ~ " " ~ m.captures[2] ~ "』";
         }
         return object_notes;
       }
@@ -3895,12 +3971,10 @@ template SiSUdocAbstraction() {
       body {
         string[][string] endnotes_;
         if (object_notes.length > 1) {
-          endnotes_["seg"] = (split(object_notes["seg"], rgx.break_string))[0..$-1];
-          endnotes_["scroll"] = (split(object_notes["scroll"], rgx.break_string))[0..$-1];
+          endnotes_["notes"] = (split(object_notes["notes"], rgx.break_string))[0..$-1];
           endnotes_["anchor"] = (split(object_notes["anchor"], rgx.break_string))[0..$-1];
         } else {
-          endnotes_["seg"] = [];
-          endnotes_["scroll"] = [];
+          endnotes_["notes"] = [];
           endnotes_["anchor"] = [];
         }
         return endnotes_;
@@ -3913,14 +3987,14 @@ template SiSUdocAbstraction() {
       }
       body {
         mixin SiSUnode;
-        ObjGenericComposite[][string] the_endnotes_section;
+        ObjGenericComposite[] the_endnotes_section;
         auto endnotes_ = gathered_notes();
         string type_is;
         string lev, lev_markup_number, lev_collapsed_number;
         string attrib;
         int[string] indent;
         ObjGenericComposite comp_obj_heading_;
-        if ((endnotes_["seg"].length > 0)
+        if ((endnotes_["notes"].length > 0)
         && (opt_action_bool["backmatter"] && opt_action_bool["section_endnotes"])) {
           comp_obj_heading_                       = comp_obj_heading_.init;
           comp_obj_heading_.use                   = "backmatter";
@@ -3934,8 +4008,7 @@ template SiSUdocAbstraction() {
           comp_obj_heading_.heading_lev_collapsed = 1;
           comp_obj_heading_.parent_ocn            = 1;
           comp_obj_heading_.parent_lev_markup     = 0;
-          the_endnotes_section["seg"]             ~= comp_obj_heading_;
-          the_endnotes_section["scroll"]          ~= comp_obj_heading_;
+          the_endnotes_section                    ~= comp_obj_heading_;
           ++obj_cite_number;
           ++mkn;
           comp_obj_heading_                       = comp_obj_heading_.init;
@@ -3952,8 +4025,7 @@ template SiSUdocAbstraction() {
           comp_obj_heading_.parent_ocn            = 1;
           comp_obj_heading_.parent_lev_markup     = 0;
           comp_obj_heading_.anchor_tags           = ["endnotes"];
-          the_endnotes_section["seg"]             ~= comp_obj_heading_;
-          the_endnotes_section["scroll"]          ~= comp_obj_heading_;
+          the_endnotes_section                    ~= comp_obj_heading_;
           ++obj_cite_number;
           ++mkn;
         } else {
@@ -3969,8 +4041,7 @@ template SiSUdocAbstraction() {
           comp_obj_heading_.heading_lev_collapsed = 1;
           comp_obj_heading_.parent_ocn            = 1;
           comp_obj_heading_.parent_lev_markup     = 0;
-          the_endnotes_section["seg"]             ~= comp_obj_heading_;
-          the_endnotes_section["scroll"]          ~= comp_obj_heading_;
+          the_endnotes_section                    ~= comp_obj_heading_;
         }
         if (opt_action_bool["backmatter"] && opt_action_bool["section_endnotes"]) {
           ObjGenericComposite comp_obj_endnote_;
@@ -3983,21 +4054,13 @@ template SiSUdocAbstraction() {
           comp_obj_endnote_.indent_hang           = 0;
           comp_obj_endnote_.indent_base           = 0;
           comp_obj_endnote_.bullet                = false;
-          foreach (i, endnote; endnotes_["seg"]) {
-            auto     m                            = (matchFirst(endnote, rgx.note_ref));
-            string   notenumber                   = to!string(m.captures[1]);
-            string   anchor_tag                   = "note_" ~ notenumber;
-            comp_obj_endnote_.anchor_tags         ~= [ endnotes_["anchor"][i] ]; // fix
-            comp_obj_endnote_.text                = endnote.strip;
-            the_endnotes_section["seg"]           ~= comp_obj_endnote_;
-          }
-          foreach (i, endnote; endnotes_["scroll"]) {
+          foreach (i, endnote; endnotes_["notes"]) {
             auto     m                            = (matchFirst(endnote, rgx.note_ref));
             string   notenumber                   = to!string(m.captures[1]);
             string   anchor_tag                   = "note_" ~ notenumber;
             comp_obj_endnote_.anchor_tags         ~= [ endnotes_["anchor"][i] ]; // fix
             comp_obj_endnote_.text                = endnote.strip;
-            the_endnotes_section["scroll"]        ~= comp_obj_endnote_;
+            the_endnotes_section                  ~= comp_obj_endnote_;
           }
         }
         auto t = tuple(the_endnotes_section, obj_cite_number);
@@ -4150,6 +4213,7 @@ template SiSUdocAbstraction() {
         int    obj_cite_number_,
         int    cntr_,
         int    ptr_,
+        string[] lv_ancestors,
         string is_,
         int    html_segnames_ptr,
       )
@@ -4251,22 +4315,23 @@ template SiSUdocAbstraction() {
           break;
         }
         ObjGenericComposite _comp_obj_heading_;
-        _comp_obj_heading_                       = _comp_obj_heading_.init;
-        _comp_obj_heading_.use                   = "body";
-        _comp_obj_heading_.is_of                 = "para";
-        _comp_obj_heading_.is_a                  = "heading";
-        _comp_obj_heading_.text                  = to!string(_text).strip;
-        _comp_obj_heading_.ocn                   = obj_cite_number_;
-        _comp_obj_heading_.obj_cite_number       = (obj_cite_number==0) ? "" : to!string(obj_cite_number);
-        _comp_obj_heading_.segment_anchor_tag    = to!string(segment_anchor_tag);
-        _comp_obj_heading_.marked_up_level       = lev;
-        _comp_obj_heading_.heading_lev_markup    = (!(lev_markup_number.empty) ? to!int(lev_markup_number) : 0);
-        _comp_obj_heading_.heading_lev_collapsed = (!(lev_collapsed_number.empty) ? to!int(lev_collapsed_number) : 0);
-        _comp_obj_heading_.parent_ocn            = p_["obj_cite_number"];
-        _comp_obj_heading_.parent_lev_markup     = p_["lev_markup_number"];
-        _comp_obj_heading_.ptr_doc_object        = cntr_;
-        _comp_obj_heading_.ptr_html_segnames     = ((lev_markup_number == "4") ? html_segnames_ptr : 0);
-        _comp_obj_heading_.ptr_heading           = ptr_;
+        _comp_obj_heading_                           = _comp_obj_heading_.init;
+        _comp_obj_heading_.use                       = "body";
+        _comp_obj_heading_.is_of                     = "para";
+        _comp_obj_heading_.is_a                      = "heading";   //    _node_heading_.is_a                = is_; // check whether needed, constant???
+        _comp_obj_heading_.text                      = to!string(_text).strip;
+        _comp_obj_heading_.ocn                       = obj_cite_number_;
+        _comp_obj_heading_.obj_cite_number           = (obj_cite_number==0) ? "" : to!string(obj_cite_number);
+        _comp_obj_heading_.segment_anchor_tag        = to!string(segment_anchor_tag);
+        _comp_obj_heading_.marked_up_level           = lev;
+        _comp_obj_heading_.heading_lev_markup        = (!(lev_markup_number.empty) ? to!int(lev_markup_number) : 0);
+        _comp_obj_heading_.heading_lev_collapsed     = (!(lev_collapsed_number.empty) ? to!int(lev_collapsed_number) : 0);
+        _comp_obj_heading_.parent_ocn                = p_["obj_cite_number"];
+        _comp_obj_heading_.parent_lev_markup         = p_["lev_markup_number"];
+        _comp_obj_heading_.heading_ancestors_text    = lv_ancestors;
+        _comp_obj_heading_.ptr_doc_object            = cntr_;
+        _comp_obj_heading_.ptr_html_segnames         = ((lev_markup_number == "4") ? html_segnames_ptr : 0);
+        _comp_obj_heading_.ptr_heading               = ptr_;
         debug(node) {
           if (match(lev_markup_number, rgx.levels_numbered_headings)) {
             writeln("* ", to!string(_node));
diff --git a/src/sdp/ao_defaults.d b/src/sdp/ao_defaults.d
index 1dd9300..c80933c 100644
--- a/src/sdp/ao_defaults.d
+++ b/src/sdp/ao_defaults.d
@@ -238,11 +238,11 @@ template SiSUregisters() {
   }`;
 }
 /+
-/+
-  unify internal representation of header info for native & sdlang document headers
-  represent either using struct, hashes or possibly json
-  sdp internal representation should be identical for native & sdlang variants
-+/
+  /+
+    unify internal representation of header info for native & sdlang document headers
+    represent either using struct, hashes or possibly json
+    sdp internal representation should be identical for native & sdlang variants
+  +/
 header.
   ├── make                         // make instructions
   │   ├── bold
@@ -311,6 +311,93 @@ header.
 
 61 leaves
 +/
+template SiSUlanguageCodes() {
+  /+ language codes +/
+  struct Lang {
+    string[string][string] codes() {
+      auto _lang_codes = [
+        "am":    [ "c": "am",    "n": "Amharic",           "t": "Amharic",                   "xlp": "amharic"      ],
+        "bg":    [ "c": "bg",    "n": "Bulgarian",         "t": "Български (Bəlgarski)",     "xlp": "bulgarian"    ],
+        "bn":    [ "c": "bn",    "n": "Bengali",           "t": "Bengali",                   "xlp": "bengali"      ],
+        "br":    [ "c": "br",    "n": "Breton",            "t": "Breton",                    "xlp": "breton"       ],
+        "ca":    [ "c": "ca",    "n": "Catalan",           "t": "catalan",                   "xlp": "catalan"      ],
+        "cs":    [ "c": "cs",    "n": "Czech",             "t": "česky",                     "xlp": "czech"        ],
+        "cy":    [ "c": "cy",    "n": "Welsh",             "t": "Welsh",                     "xlp": "welsh"        ],
+        "da":    [ "c": "da",    "n": "Danish",            "t": "dansk",                     "xlp": "danish"       ],
+        "de":    [ "c": "de",    "n": "German",            "t": "Deutsch",                   "xlp": "german"       ],
+        "el":    [ "c": "el",    "n": "Greek",             "t": "Ελληνικά (Ellinika)",       "xlp": "greek"        ],
+        "en":    [ "c": "en",    "n": "English",           "t": "English",                   "xlp": "english"      ],
+        "eo":    [ "c": "eo",    "n": "Esperanto",         "t": "Esperanto",                 "xlp": "esperanto"    ],
+        "es":    [ "c": "es",    "n": "Spanish",           "t": "español",                   "xlp": "spanish"      ],
+        "et":    [ "c": "et",    "n": "Estonian",          "t": "Estonian",                  "xlp": "estonian"     ],
+        "eu":    [ "c": "eu",    "n": "Basque",            "t": "basque",                    "xlp": "basque"       ],
+        "fi":    [ "c": "fi",    "n": "Finnish",           "t": "suomi",                     "xlp": "finnish"      ],
+        "fr":    [ "c": "fr",    "n": "French",            "t": "français",                  "xlp": "french"       ],
+        "ga":    [ "c": "ga",    "n": "Irish",             "t": "Irish",                     "xlp": "irish"        ],
+        "gl":    [ "c": "gl",    "n": "Galician",          "t": "Galician",                  "xlp": "galician"     ],
+        "he":    [ "c": "he",    "n": "Hebrew",            "t": "Hebrew",                    "xlp": "hebrew"       ],
+        "hi":    [ "c": "hi",    "n": "Hindi",             "t": "Hindi",                     "xlp": "hindi"        ],
+        "hr":    [ "c": "hr",    "n": "Croatian",          "t": "Croatian",                  "xlp": "croatian"     ],
+        "hy":    [ "c": "hy",    "n": "Armenian",          "t": "Armenian",                  "xlp": "armenian"     ],
+        "ia":    [ "c": "ia",    "n": "Interlingua",       "t": "Interlingua",               "xlp": "interlingua"  ],
+        "is":    [ "c": "is",    "n": "Icelandic",         "t": "Icelandic",                 "xlp": "icelandic"    ],
+        "it":    [ "c": "it",    "n": "Italian",           "t": "Italiano",                  "xlp": "italian"      ],
+        "ja":    [ "c": "ja",    "n": "Japanese",          "t": "日本語 (Nihongo)",         "xlp": "japanese"      ],
+        "ko":    [ "c": "ko",    "n": "Korean",            "t": "Korean",                    "xlp": "korean"       ],
+        "la":    [ "c": "la",    "n": "Latin",             "t": "Latin",                     "xlp": "latin"        ],
+        "lo":    [ "c": "lo",    "n": "Lao",               "t": "Lao",                       "xlp": "lao"          ],
+        "lt":    [ "c": "lt",    "n": "Lithuanian",        "t": "Lithuanian",                "xlp": "lithuanian"   ],
+        "lv":    [ "c": "lv",    "n": "Latvian",           "t": "Latvian",                   "xlp": "latvian"      ],
+        "ml":    [ "c": "ml",    "n": "Malayalam",         "t": "Malayalam",                 "xlp": "malayalam"    ],
+        "mr":    [ "c": "mr",    "n": "Marathi",           "t": "Marathi",                   "xlp": "marathi"      ],
+        "nl":    [ "c": "nl",    "n": "Dutch",             "t": "Nederlands",                "xlp": "dutch"        ],
+        "no":    [ "c": "no",    "n": "Norwegian",         "t": "norsk",                     "xlp": "norsk"        ],
+        "nn":    [ "c": "nn",    "n": "Norwegian Nynorsk", "t": "nynorsk",                   "xlp": "nynorsk"      ],
+        "oc":    [ "c": "oc",    "n": "Occitan",           "t": "Occitan",                   "xlp": "occitan"      ],
+        "pl":    [ "c": "pl",    "n": "Polish",            "t": "polski",                    "xlp": "polish"       ],
+        "pt":    [ "c": "pt",    "n": "Portuguese",        "t": "Português",                 "xlp": "portuges"     ],
+        "pt_BR": [ "c": "pt_BR", "n": "Portuguese Brazil", "t": "Brazilian Português",       "xlp": "brazilian"    ],
+        "ro":    [ "c": "ro",    "n": "Romanian",          "t": "română",                    "xlp": "romanian"     ],
+        "ru":    [ "c": "ru",    "n": "Russian",           "t": "Русский (Russkij)",         "xlp": "russian"      ],
+        "sa":    [ "c": "sa",    "n": "Sanskrit",          "t": "Sanskrit",                  "xlp": "sanskrit"     ],
+        "se":    [ "c": "se",    "n": "Sami",              "t": "Samin",                     "xlp": "samin"        ],
+        "sk":    [ "c": "sk",    "n": "Slovak",            "t": "slovensky",                 "xlp": "slovak"       ],
+        "sl":    [ "c": "sl",    "n": "Slovenian",         "t": "Slovenian",                 "xlp": "slovenian"    ],
+        "sq":    [ "c": "sq",    "n": "Albanian",          "t": "Albanian",                  "xlp": "albanian"     ],
+        "sr":    [ "c": "sr",    "n": "Serbian",           "t": "Serbian",                   "xlp": "serbian"      ],
+        "sv":    [ "c": "sv",    "n": "Swedish",           "t": "svenska",                   "xlp": "swedish"      ],
+        "ta":    [ "c": "ta",    "n": "Tamil",             "t": "Tamil",                     "xlp": "tamil"        ],
+        "te":    [ "c": "te",    "n": "Telugu",            "t": "Telugu",                    "xlp": "telugu"       ],
+        "th":    [ "c": "th",    "n": "Thai",              "t": "Thai",                      "xlp": "thai"         ],
+        "tk":    [ "c": "tk",    "n": "Turkmen",           "t": "Turkmen",                   "xlp": "turkmen"      ],
+        "tr":    [ "c": "tr",    "n": "Turkish",           "t": "Türkçe",                    "xlp": "turkish"      ],
+        "uk":    [ "c": "uk",    "n": "Ukranian",          "t": "українська (ukrajins\"ka)", "xlp": "ukrainian"    ],
+        "ur":    [ "c": "ur",    "n": "Urdu",              "t": "Urdu",                      "xlp": "urdu"         ],
+        "us":    [ "c": "en",    "n": "English (American)","t": "English",                   "xlp": "english"      ],
+        "vi":    [ "c": "vi",    "n": "Vietnamese",        "t": "Vietnamese",                "xlp": "vietnamese"   ],
+        "zh":    [ "c": "zh",    "n": "Chinese",           "t": "中文",                     "xlp": "chinese"       ],
+        "en":    [ "c": "en",    "n": "English",           "t": "English",                   "xlp": "english"      ],
+        "xx":    [ "c": "xx",    "n": "Default",           "t": "English",                   "xlp": "english"      ],
+      ];
+      return _lang_codes;
+    }
+    string[] code_arr_ptr() {
+      auto _lang_codes = ["am", "bg", "bn", "br", "ca", "cs", "cy", "da", "de", "el", "en", "eo", "es", "et", "eu", "fi", "fr", "ga", "gl", "he", "hi", "hr", "hy", "ia", "is", "it", "ja", "ko", "la", "lo", "lt", "lv", "ml", "mr", "nl", "no", "nn", "oc", "pl", "pt", "pt_BR", "ro", "ru", "sa", "se", "sk", "sl", "sq", "sr", "sv", "ta", "te", "th", "tk", "tr", "uk", "ur", "us", "vi", "zh", "en", "xx",];
+      return _lang_codes;
+    }
+    string[] code_arr() {
+      auto _lang_codes = ["am", "bg", "bn", "br", "ca", "cs", "cy", "da", "de", "el", "en", "eo", "es", "et", "eu", "fi", "fr", "ga", "gl", "he", "hi", "hr", "hy", "ia", "is", "it", "ja", "ko", "la", "lo", "lt", "lv", "ml", "mr", "nl", "no", "nn", "oc", "pl", "pt", "pt_BR", "ro", "ru", "sa", "se", "sk", "sl", "sq", "sr", "sv", "ta", "te", "th", "tk", "tr", "uk", "ur", "vi", "zh"];
+      return _lang_codes;
+    }
+    auto codes_() {
+      // return join(code_arr,"|");
+      return "(" ~ join(code_arr,"|") ~ ")";
+    }
+    auto codes_regex() {
+      return regex(codes_);
+    }
+  }
+}
 /+ regex flags +/
 template SiSUrgxInitFlags() {
   int[string] flags_type_init() {
@@ -425,6 +512,107 @@ template SiSUbiblio() {
     "id"                               : ""
   }`; // is: book, article, magazine, newspaper, blog, other
 }
+template SiSUpaths() {
+  string _base_filename(string fn_src) {
+    string _fn_base = "";
+    if (extension(fn_src) == ".sst") {
+      _fn_base = baseName(fn_src, ".sst");
+    } else if (extension(fn_src) == ".ssm") {
+      _fn_base = baseName(fn_src, ".ssm");
+    }
+    return _fn_base;
+  }
+  struct DirPaths {
+    string base_filename(string fn_src) {
+      return _base_filename(fn_src);
+    }
+  }
+  struct SiSUpodPaths {
+    string base_filename(string fn_src) {
+      return _base_filename(fn_src);
+    }
+    string base(string fn_src) {
+      return chainPath("sisupod", _base_filename(fn_src)).array;
+    }
+    string doc(string fn_src) {
+      return chainPath(base(fn_src), "doc").array;
+    }
+    string doc_lng(string fn_src, string lng) {
+      return chainPath(doc(fn_src), lng).array;
+    }
+    string image(string fn_src) {
+      return chainPath(base(fn_src), "image").array;
+    }
+    string conf(string fn_src) {
+      return chainPath(base(fn_src), "conf").array;
+    }
+    string css(string fn_src) {
+      return chainPath(base(fn_src), "css").array;
+    }
+    string fn_doc(string fn_src, string lng) {
+      return chainPath((doc_lng(fn_src, lng)), baseName(fn_src)).array;
+    }
+  }
+  struct HtmlPaths {
+    string base_filename(string fn_src) {
+      return _base_filename(fn_src);
+    }
+    string base() {
+      return chainPath("en", "html").array;
+    }
+    string seg(string fn_src) {
+      return chainPath(base, _base_filename(fn_src)).array;
+    }
+    string fn_scroll(string fn_src) {
+      return chainPath(base, _base_filename(fn_src) ~ ".html").array;
+    }
+    string fn_seg(string fn_src, string seg_filename) {
+      return chainPath(seg(fn_src), seg_filename ~ ".html").array;
+    }
+    // string fn_css(string fn_src) {
+    //   // // return chainPath(seg(fn_src), "html.css").array;
+    // }
+  }
+  struct EpubPaths {
+    string base_filename(string fn_src) {
+      return _base_filename(fn_src);
+    }
+    string base() {
+      return chainPath("en", "epub").array;
+    }
+    string doc(string fn_src) {
+      return chainPath(base, _base_filename(fn_src)).array;
+      // return chainPath(base, base_fn).array;
+    }
+    string doc_meta_inf(string fn_src) {
+      return chainPath(doc(fn_src), "META-INF").array;
+    }
+    string doc_oebps(string fn_src) {
+      return chainPath(doc(fn_src), "OEBPS").array;
+    }
+    string doc_oebps_css(string fn_src) {
+      return chainPath(doc_oebps(fn_src), "css").array;
+    }
+    string doc_oebps_image(string fn_src) {
+      return chainPath(doc_oebps(fn_src), "image").array;
+    }
+    string fn_mimetypes(string fn_src) {
+      return chainPath(doc(fn_src), "mimetypes").array;
+    }
+    string fn_dmi_container_xml(string fn_src) {
+      return chainPath(doc_meta_inf(fn_src), "container.xml").array;
+    }
+    string fn_oebps_toc_ncx(string fn_src) {
+      return chainPath(doc_oebps(fn_src), "toc.ncx").array;
+    }
+    string fn_oebps_content_opf(string fn_src) {
+      return chainPath(doc_oebps(fn_src), "content.opf").array;
+    }
+    string fn_oebps_content_xhtml(string fn_src, string seg_filename) {
+      return chainPath(doc_oebps(fn_src), seg_filename ~ ".xhtml").array;
+    }
+  }
+}
 template InternalMarkup() {
   struct InlineMarkup {
     auto en_a_o = "【";      auto en_a_c = "】";   // endnote en_a_o: '~{'; en_a_c: '}~';
diff --git a/src/sdp/ao_object_setter.d b/src/sdp/ao_object_setter.d
index 1f10b66..d52474a 100644
--- a/src/sdp/ao_object_setter.d
+++ b/src/sdp/ao_object_setter.d
@@ -40,6 +40,7 @@ template ObjectSetter() {
     int                    heading_lev_collapsed        = 9;
     int[]                  heading_closes_lev_collapsed = [];
     int[]                  heading_closes_lev_markup    = [];
+    string[]               heading_ancestors_text       = [ "", "", "", "", "", "", "", "", ];
     int                    heading_array_ptr            = 0;
     int                    ptr_doc_object               = 0;
     int                    ptr_html_segnames            = 0;
@@ -48,8 +49,8 @@ template ObjectSetter() {
     int                    heading_array_ptr_segments   = 0;
     string[]               lev4_subtoc                  = [];
     string[string][string] node;
-    int[]                  dom_markedup                          = [ 0, 0, 0, 0, 0, 0, 0, 0,];
-    int[]                  dom_collapsed                         = [ 0, 0, 0, 0, 0, 0, 0, 0,];
+    int[]                  dom_markedup                 = [ 0, 0, 0, 0, 0, 0, 0, 0,];
+    int[]                  dom_collapsed                = [ 0, 0, 0, 0, 0, 0, 0, 0,];
   }
   struct TheObjects {
     ObjGenericComposite[] oca;
diff --git a/src/sdp/ao_output_debugs.d b/src/sdp/ao_output_debugs.d
index 35e250c..8b22f28 100644
--- a/src/sdp/ao_output_debugs.d
+++ b/src/sdp/ao_output_debugs.d
@@ -3,14 +3,9 @@
 +/
 template SiSUoutputDebugs() {
   struct SDPoutputDebugs {
-    auto abstract_doc_source_debugs(S)(
+    auto abstract_doc_source_debugs(S,T)(
       auto ref const S         contents,
-      string[][string]         document_section_keys_sequenced,
-      string[]                 html_segnames,
-      string[string][string]   dochead_make,
-      string[string][string]   dochead_meta,
-      string                   fn_src,
-      bool[string]             opt_action_bool
+      auto ref T               doc_matters,
     ) {
       mixin RgxInit;
       mixin InternalMarkup;
@@ -24,7 +19,7 @@ template SiSUoutputDebugs() {
           __FILE__,
           __LINE__,
         );
-        foreach (key; document_section_keys_sequenced["seg"]) {
+        foreach (key; doc_matters.keys_seq_seg) {
           foreach (obj; contents[key]) {
             if (obj.use != "empty") {
               if (obj.is_a == "heading") {
@@ -58,16 +53,15 @@ template SiSUoutputDebugs() {
           }
         }
       }
-      void out_segnames(S)(
+      void out_segnames(S,T)(
         auto ref const S         contents,
-        string[]                 keys,
-        string[]                 html_segnames,
+        auto ref T               doc_matters,
       ) {
-        foreach (key; keys) {
+        foreach (key; doc_matters.keys_seq_seg) {
           if (contents[key].length > 1) {
             foreach (obj; contents[key]) {
               if (obj.heading_lev_markup == 4) {
-                writeln(obj.ptr_html_segnames, ". (", html_segnames[obj.ptr_html_segnames], ") -> ",  obj.text);
+                writeln(obj.ptr_html_segnames, ". (", doc_matters.segnames[obj.ptr_html_segnames], ") -> ",  obj.text);
               }
             }
           }
@@ -144,26 +138,8 @@ template SiSUoutputDebugs() {
         out_toc(contents, key);
       }
       debug(segnames) {
-        key="toc_scroll";
         writeln(__LINE__);
-        string[] keys;
-        keys ~= [ "toc_seg", "body" ];
-        if (contents["endnotes_seg"].length > 1) {
-          keys ~= "endnotes_seg";
-        }
-        if (contents["glossary"].length > 1) {
-          keys ~= "glossary";
-        }
-        if (contents["bibliography"].length > 1) {
-          keys ~= "bibliography";
-        }
-        if (contents["bookindex_seg"].length > 1) {
-          keys ~= "bookindex_seg";
-        }
-        if (contents["blurb"].length > 1) {
-          keys ~= "blurb";
-        }
-        out_segnames(contents, keys, html_segnames);
+        out_segnames(contents, doc_matters);
       }
       debug(section_body) {
         key="body";
@@ -180,7 +156,7 @@ template SiSUoutputDebugs() {
       }
       debug(dom) {
         enum DomTags { none, open, close, close_and_open, open_still, }
-        foreach (sect; document_section_keys_sequenced["seg"]) {
+        foreach (sect; doc_matters.keys_seq_seg) {
           foreach (obj; contents[sect]) {
             if (obj.is_a == "heading") {
               foreach_reverse (k; 0 .. 7) {
@@ -203,7 +179,7 @@ template SiSUoutputDebugs() {
           }
         }
         writeln("--------------------");
-        foreach (sect; document_section_keys_sequenced["seg"]) {
+        foreach (sect; doc_matters.keys_seq_seg) {
           foreach (obj; contents[sect]) {
             if (obj.is_a == "heading") {
               foreach_reverse (k; 0 .. 7) {
@@ -227,15 +203,11 @@ template SiSUoutputDebugs() {
         }
       }
       debug(section_endnotes) {
-        key="endnotes_seg";
+        key="endnotes";
         out_endnotes(contents, key);
       }
       debug(section_endnotes_seg) {
-        key="endnotes_seg";
-        out_endnotes(contents, key);
-      }
-      debug(section_endnotes_scroll) {
-        key="endnotes_scroll";
+        key="endnotes";
         out_endnotes(contents, key);
       }
       debug(section_glossary) {
@@ -311,19 +283,19 @@ template SiSUoutputDebugs() {
         writefln(
           "%s\n%s\n%s",
           "document header, metadata & make instructions:",
-          dochead_meta,
+          doc_matters.dochead_meta,
           ptr_head_main,
         );
         foreach (main_header; ptr_head_main) {
           switch (main_header) {
           case "make":
             foreach (sub_header; ptr_head_sub_make) {
-              if (to!string(dochead_meta[main_header][sub_header]).length > 2) {
+              if (to!string(doc_matters.dochead_meta[main_header][sub_header]).length > 2) {
                 writefln(
                   "%s:%s: %s",
                   main_header,
                   sub_header,
-                  dochead_meta[main_header][sub_header]
+                  doc_matters.dochead_meta[main_header][sub_header]
                 );
               }
             }
@@ -337,115 +309,115 @@ template SiSUoutputDebugs() {
         writefln(
           "%s\n%s\n%s",
           "document header, metadata & make instructions:",
-          dochead_meta,
+          doc_matters.dochead_meta,
           ptr_head_main,
         );
         foreach (main_header; ptr_head_main) {
           switch (main_header) {
           case "creator":
             foreach (sub_header; ptr_head_sub_creator) {
-              if (to!string(dochead_meta[main_header][sub_header]).length > 2) {
+              if (to!string(doc_matters.dochead_meta[main_header][sub_header]).length > 2) {
                 writefln(
                   "%s:%s: %s",
                   main_header,
                   sub_header,
-                  dochead_meta[main_header][sub_header]
+                  doc_matters.dochead_meta[main_header][sub_header]
                 );
               }
             }
             break;
           case "title":
             foreach (sub_header; ptr_head_sub_title) {
-              if (to!string(dochead_meta[main_header][sub_header]).length > 2) {
+              if (to!string(doc_matters.dochead_meta[main_header][sub_header]).length > 2) {
                 writefln(
                   "%s:%s: %s",
                   main_header,
                   sub_header,
-                  dochead_meta[main_header][sub_header]
+                  doc_matters.dochead_meta[main_header][sub_header]
                 );
               }
             }
             break;
           case "rights":
             foreach (sub_header; ptr_head_sub_rights) {
-              if (to!string(dochead_meta[main_header][sub_header]).length > 2) {
+              if (to!string(doc_matters.dochead_meta[main_header][sub_header]).length > 2) {
                 writefln(
                   "%s:%s: %s",
                   main_header,
                   sub_header,
-                  dochead_meta[main_header][sub_header]
+                  doc_matters.dochead_meta[main_header][sub_header]
                 );
               }
             }
             break;
           case "date":
             foreach (sub_header; ptr_head_sub_date) {
-              if (to!string(dochead_meta[main_header][sub_header]).length > 2) {
+              if (to!string(doc_matters.dochead_meta[main_header][sub_header]).length > 2) {
                 writefln(
                   "%s:%s: %s",
                   main_header,
                   sub_header,
-                  dochead_meta[main_header][sub_header]
+                  doc_matters.dochead_meta[main_header][sub_header]
                 );
               }
             }
             break;
           case "original":
             foreach (sub_header; ptr_head_sub_original) {
-              if (to!string(dochead_meta[main_header][sub_header]).length > 2) {
+              if (to!string(doc_matters.dochead_meta[main_header][sub_header]).length > 2) {
                 writefln(
                   "%s:%s: %s",
                   main_header,
                   sub_header,
-                  dochead_meta[main_header][sub_header]
+                  doc_matters.dochead_meta[main_header][sub_header]
                 );
               }
             }
             break;
           case "classify":
             foreach (sub_header; ptr_head_sub_classify) {
-              if (to!string(dochead_meta[main_header][sub_header]).length > 2) {
+              if (to!string(doc_matters.dochead_meta[main_header][sub_header]).length > 2) {
                 writefln(
                   "%s:%s: %s",
                   main_header,
                   sub_header,
-                  dochead_meta[main_header][sub_header]
+                  doc_matters.dochead_meta[main_header][sub_header]
                 );
               }
             }
             break;
           case "identifier":
             foreach (sub_header; ptr_head_sub_identifier) {
-              if (to!string(dochead_meta[main_header][sub_header]).length > 2) {
+              if (to!string(doc_matters.dochead_meta[main_header][sub_header]).length > 2) {
                 writefln(
                   "%s:%s: %s",
                   main_header,
                   sub_header,
-                  dochead_meta[main_header][sub_header]
+                  doc_matters.dochead_meta[main_header][sub_header]
                 );
               }
             }
             break;
           case "notes":
             foreach (sub_header; ptr_head_sub_notes) {
-              if (to!string(dochead_meta[main_header][sub_header]).length > 2) {
+              if (to!string(doc_matters.dochead_meta[main_header][sub_header]).length > 2) {
                 writefln(
                   "%s:%s: %s",
                   main_header,
                   sub_header,
-                  dochead_meta[main_header][sub_header]
+                  doc_matters.dochead_meta[main_header][sub_header]
                 );
               }
             }
             break;
           case "publisher":
             foreach (sub_header; ptr_head_sub_publisher) {
-              if (to!string(dochead_meta[main_header][sub_header]).length > 2) {
+              if (to!string(doc_matters.dochead_meta[main_header][sub_header]).length > 2) {
                 writefln(
                   "%s:%s: %s",
                   main_header,
                   sub_header,
-                  dochead_meta[main_header][sub_header]
+                  doc_matters.dochead_meta[main_header][sub_header]
                 );
               }
             }
@@ -462,7 +434,7 @@ template SiSUoutputDebugs() {
           __FILE__,
           __LINE__,
         );
-        foreach (k; document_section_keys_sequenced["seg"]) {
+        foreach (k; doc_matters.keys_seq_seg) {
           foreach (obj; contents[k]) {
             if (obj.is_a == "heading") {
               writefln(
@@ -478,7 +450,7 @@ template SiSUoutputDebugs() {
         }
       }
       debug(heading) {                         // heading
-        foreach (k; document_section_keys_sequenced["seg"]) {
+        foreach (k; doc_matters.keys_seq_seg) {
           foreach (o; contents[k]) {
             if (o.is_a == "heading") {
               writefln(
@@ -503,7 +475,7 @@ template SiSUoutputDebugs() {
             __FILE__,
             __LINE__,
           );
-          foreach (k; document_section_keys_sequenced["seg"]) {
+          foreach (k; doc_matters.keys_seq_seg) {
             foreach (obj; contents[k]) {
               if (obj.is_a == "heading") {
                 writefln(
@@ -518,7 +490,7 @@ template SiSUoutputDebugs() {
           }
         }
         debug(checkdoc) {
-          foreach (k; document_section_keys_sequenced["seg"]) {
+          foreach (k; doc_matters.keys_seq_seg) {
             foreach (obj; contents[k]) {
               if (obj.use != "empty") {
                 if (!empty(obj.obj_cite_number)) {
@@ -531,9 +503,9 @@ template SiSUoutputDebugs() {
         writefln(
           "%s\n\"%s\", %s\n%s\n%s\n%s%10d\n%s%10d\n%s%10d\n%s%10d\n%s%10d\n%s%10d\n%s%10d\n%s%10d\n(%s: %s)",
           "---------------------------------",
-          dochead_meta["title"]["full"],
-          dochead_meta["creator"]["author"],
-          fn_src,
+          doc_matters.dochead_meta["title"]["full"],
+          doc_matters.dochead_meta["creator"]["author"],
+          doc_matters.source_filename,
           "---------------------------------",
           "length toc array:      ",
           to!int(contents["toc_seg"].length),
@@ -542,8 +514,8 @@ template SiSUoutputDebugs() {
           "last obj_cite_number:  ",
           to!int(check["last_obj_cite_number"]),
           "length endnotes:       ",
-          (contents["endnotes_seg"].length > 1)
-          ? (to!int(contents["endnotes_seg"].length))
+          (contents["endnotes"].length > 1)
+          ? (to!int(contents["endnotes"].length))
           : 0,
           "length glossary:       ",
           (contents["glossary"].length > 1)
@@ -565,8 +537,8 @@ template SiSUoutputDebugs() {
           __LINE__,
         );
         debug(checkdoc) {
-          if (auto mfn=match(fn_src, rgx.src_fn)) {
-            if (opt_action_bool["assertions"]) {
+          if (auto mfn=match(doc_matters.source_filename, rgx.src_fn)) {
+            if (doc_matters.opt_action_bool["assertions"]) {
               switch (mfn.captures[2]) {
               // live manual:
               case "live-manual.ssm":
@@ -685,7 +657,7 @@ template SiSUoutputDebugs() {
                 // error in bookindex ... (ch7 ... building the cc machine, an extra semi colon)
                 break;
               default:
-                writeln(fn_src);
+                writeln(doc_matters.source_filename);
                 break;
               }
             }
diff --git a/src/sdp/ao_read_config_files.d b/src/sdp/ao_read_config_files.d
index 34b858b..6308df2 100644
--- a/src/sdp/ao_read_config_files.d
+++ b/src/sdp/ao_read_config_files.d
@@ -13,10 +13,13 @@ template SiSUconfigIn() {
   struct ConfigIn {
     private import std.file;
     final private string readInConfigFile(string conf_sdl) {
+      string dot_pwd = chainPath(to!string(environment["PWD"]), ".sisu").array;
+      string underscore_pwd = chainPath(to!string(environment["PWD"]), "_sisu").array;
+      string dot_home = chainPath(to!string(environment["HOME"]), ".sisu").array;
       string[] possible_config_path_locations = [
-        environment["PWD"] ~ "/.sisu",
-        environment["PWD"] ~ "/_sisu",
-        environment["HOME"] ~ "/.sisu",
+        dot_pwd,
+        underscore_pwd,
+        dot_home,
         "/etc/sisu"
       ];
       string config_file_str;
diff --git a/src/sdp/ao_read_source_files.d b/src/sdp/ao_read_source_files.d
index 5ff0ec1..a2bf75d 100644
--- a/src/sdp/ao_read_source_files.d
+++ b/src/sdp/ao_read_source_files.d
@@ -43,7 +43,7 @@ template SiSUmarkupRaw() {
   private
   struct MarkupRawUnit {
     private import std.file;
-    final private string readInMarkupSource(in string fn_src) {
+    final private string readInMarkupSource(in char[] fn_src) {
       enforce(
         exists(fn_src)!=0,
         "file not found"
@@ -102,7 +102,10 @@ template SiSUmarkupRaw() {
       );
       return t;
     }
-    final char[][] getInsertMarkupSourceContentRawLineArray(in string fn_src, Regex!(char) rgx_file) {
+    final char[][] getInsertMarkupSourceContentRawLineArray(
+      in char[] fn_src,
+      Regex!(char) rgx_file
+    ) {
       enforce(
         match(fn_src, rgx_file),
         "not a sisu markup filename"
@@ -166,7 +169,7 @@ template SiSUmarkupRaw() {
           auto insert_fn = m.captures[2];
           auto insert_sub_pth = m.captures[1];
           auto fn_src_insert =
-            to!string(markup_src_file_path ~ insert_sub_pth ~ insert_fn);
+            chainPath(markup_src_file_path, insert_sub_pth ~ insert_fn).array;
           auto raw = MarkupRawUnit();
           auto markup_sourcesubfile_insert_content =
             raw.getInsertMarkupSourceContentRawLineArray(fn_src_insert, rgx.src_fn_find_inserts);
@@ -227,7 +230,7 @@ template SiSUmarkupRaw() {
           auto insert_fn = m.captures[2];
           auto insert_sub_pth = m.captures[1];
           auto fn_src_insert =
-            to!string(markup_src_file_path ~ insert_sub_pth ~ insert_fn);
+            chainPath(markup_src_file_path, insert_sub_pth ~ insert_fn).array;
           auto raw = MarkupRawUnit();
           /+ TODO +/
           if (auto ma = match(line, rgx.src_fn_text)) {
diff --git a/src/sdp/ao_rgx.d b/src/sdp/ao_rgx.d
index 6534cdd..6641d6a 100644
--- a/src/sdp/ao_rgx.d
+++ b/src/sdp/ao_rgx.d
@@ -3,6 +3,7 @@
 +/
 template RgxInit() {
   struct Rgx {
+    mixin SiSUlanguageCodes;
     /+ misc +/
     static true_dollar                                    = ctRegex!(`\$`, "gm");
     static flag_action                                    = ctRegex!(`^(--[a-z][a-z0-9-]+)$`);
diff --git a/src/sdp/output_epub.d b/src/sdp/output_epub.d
new file mode 100644
index 0000000..90f0ca4
--- /dev/null
+++ b/src/sdp/output_epub.d
@@ -0,0 +1,364 @@
+template SiSUoutputEPub() {
+  struct SDPoutputEPub {
+    mixin InternalMarkup;
+    mixin SiSUoutputXHTMLs;
+    string epub_mimetypes() {
+      string o;
+      o = format(q"¶application/epub+zip¶");
+      return o;
+    }
+    string epub_container_xml() {
+      string o;
+      o = format(q"¶<?xml version='1.0' encoding='utf-8'?>
+    <container version="1.0"
+      xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
+      <rootfiles>
+        <rootfile full-path="OEBPS/content.opf"
+          media-type="application/oebps-package+xml" />
+      </rootfiles>
+    </container>¶");
+      return o;
+    }
+    string epub_oebps_content(
+      // string[string][string]   dochead_meta,
+    ) {
+      // string[] toc;
+      // int counter = 0;
+      string uuid = "18275d951861c77f78acd05672c9906924c59f18a2e0ba06dad95959693e9bd8"; // TODO shared elsewhere
+      string content = format(q"¶<?xml version='1.0' encoding='utf-8'?>
+    <?xml version='1.0' encoding='utf-8'?>
+    <package xmlns="http://www.idpf.org/2007/opf" version="2.0" unique-identifier="EPB-UUID">
+      <opf:metadata
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xmlns:opf="http://www.idpf.org/2007/opf"
+        xmlns:dcterms="http://purl.org/dc/terms/"
+        xmlns:dc="http://purl.org/dc/elements/1.1/"
+        unique-identifier="urn:uuid:%s" version="2.0">
+        <dc:title>%s</dc:title>
+        <dc:creator opf:file-as="%s" opf:role="aut">%s</dc:creator>
+        <dc:language>en</dc:language>
+        <dc:date opf:event="published">%s</dc:date>
+        <dc:rights>Copyright: %s</dc:rights>
+        <dc:identifier opf:scheme="URI">ox/current/en/epub/sisu_markup.epub</dc:identifier>
+        <dc:identifier id="bookid">urn:uuid:%s</dc:identifier>
+        <!-- <dc:identifier id="EPB-UUID">urn:uuid:%s</dc:identifier> -->
+      </opf:metadata>
+      <manifest>
+        <!-- NCX -->
+        <item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml" />
+        <!-- CSS Style Sheets -->
+        <item id="main-css" href="css/xhtml.css" media-type="text/css" />¶",
+        uuid,
+        doc_matters.dochead_meta["title"]["full"],                                                               // title
+        (doc_matters.dochead_meta["creator"]["author"].empty) ? "" : " by " ~ doc_matters.dochead_meta["creator"]["author"], // author
+        (doc_matters.dochead_meta["creator"]["author"].empty) ? "" : " by " ~ doc_matters.dochead_meta["creator"]["author"], // author
+        (doc_matters.dochead_meta["date"]["published"].empty) ? "" : " by " ~ doc_matters.dochead_meta["date"]["published"],  // date
+        (doc_matters.dochead_meta["rights"]["copyright"].empty) ? "" : " by " ~ doc_matters.dochead_meta["rights"]["copyright"],  // rights
+        uuid,
+        uuid,
+      );
+      foreach (sect; doc_matters.keys_seq_seg) {
+        foreach (obj; contents[sect]) {
+        }
+      }
+      return content;
+    }
+    string epub_oebps_toc() {
+      int counter = 0;
+      string uuid = "18275d951861c77f78acd05672c9906924c59f18a2e0ba06dad95959693e9bd8"; // TODO shared elsewhere
+      auto markup = InlineMarkup();
+      enum DomTags { none, open, close, close_and_open, open_still, }
+      string toc = format(q"¶<?xml version='1.0' encoding='utf-8'?>
+    <ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
+      <head>
+        <!-- four required metadata items (for all NCX documents,
+          (including the relaxed constraints of OPS 2.0) -->
+        <title>%s%s</title>
+        <link href="css/xhtml.css" rel="stylesheet" type="text/css" id="main-css" />
+        <meta name="dtb:uid" content="urn:uuid:%s" />
+        <!-- <meta name="epub-creator" content="SiSU http://www.jus.uio.no/sisu (this copy)" /> -->
+        <meta name="dtb:depth" content="%s" />
+        <meta name="dtb:totalPageCount" content="0" />
+        <meta name="dtb:maxPageNumber" content="0" />
+      </head>
+      <docTitle>
+        <text>%s</text>
+      </docTitle>
+      <docAuthor>
+        <text>%s</text>
+      </docAuthor>
+      <navMap>¶",
+        doc_matters.dochead_meta["title"]["full"],                                                               // title
+        (doc_matters.dochead_meta["creator"]["author"].empty) ? "" : " by " ~ doc_matters.dochead_meta["creator"]["author"], // author
+        uuid,                                                                                        // uuid
+        "3",                                                                                         // content depth
+        doc_matters.dochead_meta["title"]["full"],                                                               // title
+        (doc_matters.dochead_meta["creator"]["author"].empty) ? "" : doc_matters.dochead_meta["creator"]["author"],          // author
+      );
+      foreach (sect; doc_matters.keys_seq_seg) {
+        foreach (obj; contents[sect]) {
+          if (obj.is_a == "heading") {
+            foreach_reverse (k; 0 .. 7) {
+              switch (obj.dom_markedup[k]) {
+              case DomTags.close :
+                writeln(markup.indent_by_spaces_provided(k), "</", k, ">");
+    toc ~= "</navPoint>";
+                break;
+              case DomTags.close_and_open :
+                writeln(markup.indent_by_spaces_provided(k), "</", k, ">");
+                writeln(markup.indent_by_spaces_provided(k), "<", k, ">", obj.text);
+                ++counter;
+    toc ~= "</navPoint>";
+    toc ~= format(q"¶<navPoint class="chapter" id="navpoint" playOrder="%s">
+    <navLabel>
+      <text>%s</text>
+    </navLabel>
+    <content src="%s" />¶",
+    counter,
+    obj.text,
+    obj.segment_anchor_tag,   // lev < 4 [no link]; lev == 4 [filename] markup.xhtml; lev > 4 [filename#ocn] (links done in segment_anchor_tag)
+    );
+                break;
+              case DomTags.open :
+                writeln(markup.indent_by_spaces_provided(k), "<", k, ">", obj.text);
+                ++counter;
+    toc ~= format(q"¶<navPoint class="chapter" id="navpoint" playOrder="%s">
+    <navLabel>
+      <text>%s</text>
+    </navLabel>
+    <content src="%s" />¶",
+    counter,
+    obj.text,
+    obj.segment_anchor_tag,   // lev < 4 [no link]; lev == 4 [filename] markup.xhtml; lev > 4 [filename#ocn] (fix links in segment_anchor_tag)
+    );
+                break;
+              default :
+                break;
+              }
+            }
+          }
+        }
+      }
+      toc ~= format(q"¶  </navMap>
+    </ncx>¶");
+      return toc;
+    }
+    
+    void doc_content(C,T)(
+      auto ref const C         contents,
+      auto ref T               doc_matters,
+    ) {
+      auto xhtml_format = SDPoutputXHTMLs();
+      auto rgx = Rgx();
+      // string[] toc;
+      string[][string] doc_epub;
+      string[] doc;
+      string segment_filename;
+      string[] seg_filenames;
+      string[] top_level_headings = ["","","",""];
+      auto mimetypes = epub_mimetypes;
+      auto meta_inf_container_xml = epub_container_xml;
+      auto oebps_toc_ncx = epub_oebps_toc;
+      auto oebps_content_opf = epub_oebps_content;
+      foreach (part; doc_matters.keys_seq_seg) {
+        foreach (obj; contents[part]) {
+          if (obj.is_a == "heading") {
+            switch (obj.heading_lev_markup) {
+            // case 0:
+            //   break;
+            case 0: .. case 3:
+              /+ fill buffer, and replace with new levels from 1 to 3 +/
+              switch (obj.heading_lev_markup) {
+              case 0:
+                top_level_headings[0] = "";
+                top_level_headings[1] = "";
+                top_level_headings[2] = "";
+                top_level_headings[3] = "";
+                goto default;
+              case 1:
+                top_level_headings[1] = "";
+                top_level_headings[2] = "";
+                top_level_headings[3] = "";
+                goto default;
+              case 2:
+                top_level_headings[2] = "";
+                top_level_headings[3] = "";
+                goto default;
+              case 3:
+                top_level_headings[3] = "";
+                goto default;
+              default:
+                top_level_headings[obj.heading_lev_markup] = xhtml_format.heading(obj);
+                break;
+              }
+              break;
+            case 4:
+              seg_filenames ~= obj.segment_anchor_tag;
+              segment_filename = obj.segment_anchor_tag;
+              doc_epub[segment_filename] ~= xhtml_format.seg_head(doc_matters.dochead_meta);
+              foreach (top_level_heading; top_level_headings) {
+                // writeln(top_level_heading);
+                doc_epub[segment_filename] ~= top_level_heading;
+              }
+              doc_epub[segment_filename] ~= xhtml_format.heading(obj);
+              break;
+            case 5: .. case 7:
+              doc_epub[segment_filename] ~= xhtml_format.heading(obj);
+              break;
+            default:
+              writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
+              break;
+            }
+          } else if (obj.use == "frontmatter") {
+            switch (obj.is_of) {
+            case "para":
+              switch (obj.is_a) {
+              case "toc":
+                  doc_epub[segment_filename] ~= xhtml_format.toc(obj);
+              //   doc_epub ~= xhtml_toc(obj);
+              break;
+              default:
+                // writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
+                break;
+              }
+              break;
+            default:
+              // writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
+              break;
+            }
+          } else if (obj.use == "body") {
+            switch (obj.is_of) {
+            case "para":
+              switch (obj.is_a) {
+              case "para":
+                doc_epub[segment_filename] ~= xhtml_format.para(obj);
+                break;
+              default:
+                // writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
+                break;
+              }
+              break;
+            case "block":
+              switch (obj.is_a) {
+              case "poem":                        // double check why both poem & verse
+                break;
+              case "verse":
+                doc_epub[segment_filename] ~= xhtml_format.nugget(obj);
+                // doc_epub ~= xhtml_verse(obj);
+                break;
+              case "group":
+                doc_epub[segment_filename] ~= xhtml_format.nugget(obj);
+                // doc_epub ~= xhtml_group(obj);
+                break;
+              case "block":
+                doc_epub[segment_filename] ~= xhtml_format.nugget(obj);
+                // doc_epub ~= xhtml_block(obj);
+                break;
+              case "quote":
+                doc_epub[segment_filename] ~= xhtml_format.nugget(obj);
+                // doc_epub ~= xhtml_quote(obj);
+                break;
+              case "table":
+                doc_epub[segment_filename] ~= xhtml_format.para(obj); //
+                // doc_epub ~= xhtml_table(obj);
+                break;
+              case "code":
+                doc_epub[segment_filename] ~= xhtml_format.code(obj);
+                break;
+              default:
+                writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
+                break;
+              }
+              break;
+            default:
+              // writeln(__FILE__, ":", __LINE__, ": ", obj.is_of);
+              break;
+            }
+          } else if (obj.use == "backmatter") {
+            switch (obj.is_of) {
+            case "para":
+              switch (obj.is_a) {
+              case "endnote":
+                doc_epub[segment_filename] ~= xhtml_format.endnote(obj);
+                break;
+              case "glossary":
+                doc_epub[segment_filename] ~= xhtml_format.para(obj);
+                break;
+              case "bibliography":
+                doc_epub[segment_filename] ~= xhtml_format.para(obj);
+                break;
+              case "bookindex":
+                doc_epub[segment_filename] ~= xhtml_format.para(obj);
+                break;
+              case "blurb":
+                doc_epub[segment_filename] ~= xhtml_format.para(obj);
+                break;
+              default:
+                // writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
+                break;
+              }
+              break;
+            default:
+              writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
+              break;
+            }
+          }
+        }
+      }
+      writeln(doc_matters.keys_seq_seg);
+      epub_write_output_files(
+        doc_matters.source_filename,
+        seg_filenames,
+        doc_epub,
+        mimetypes,
+        meta_inf_container_xml,
+        oebps_toc_ncx,
+        oebps_content_opf,
+      );
+    }
+    void epub_write_output_files(
+      string fn_src,
+      string[] seg_filenames,
+      string[][string] doc_epub,
+      string mimetypes,
+      string meta_inf_container_xml,
+      string oebps_toc_ncx,
+      string oebps_content_opf,
+    ) {
+      mixin SiSUpaths;
+      auto pth_epub = EpubPaths();
+      // doc = xhtml_format.scroll_head ~ doc_epub ~  xhtml_format.tail;
+      auto xhtml_format = SDPoutputXHTMLs();
+      try {
+        mkdirRecurse(pth_epub.doc_meta_inf(fn_src));
+        mkdirRecurse(pth_epub.doc_oebps_css(fn_src));
+        mkdirRecurse(pth_epub.doc_oebps_image(fn_src));
+        /+ OEBPS/[segments].xhtml +/
+        foreach (seg_filename; seg_filenames) {
+          auto f = File(pth_epub.fn_oebps_content_xhtml(fn_src, seg_filename), "w");
+          /+ // f.writeln(seg_head); // not needed built and inserted earlier +/
+          foreach (docseg; doc_epub[seg_filename]) {
+            f.writeln(docseg);
+          }
+          f.writeln(xhtml_format.tail); // needed for each lev4
+        }
+        /+ mimetypes +/
+        auto f = File(pth_epub.fn_mimetypes(fn_src), "w");
+        f.writeln(mimetypes);
+        /+  META-INF/container.xml +/
+        f = File(pth_epub.fn_dmi_container_xml(fn_src), "w");
+        f.writeln(meta_inf_container_xml);
+        /+ OEBPS/toc.ncx +/
+        f = File(pth_epub.fn_oebps_toc_ncx(fn_src), "w");
+        f.writeln(oebps_toc_ncx);
+        /+ OEBPS/content.opf +/
+        f = File(pth_epub.fn_oebps_content_opf(fn_src), "w");
+        f.writeln(oebps_content_opf);
+      }
+      catch (ErrnoException ex) {
+        // Handle error
+      }
+    }
+    
+  }
+}
diff --git a/src/sdp/output_html.d b/src/sdp/output_html.d
index 0390799..1975958 100644
--- a/src/sdp/output_html.d
+++ b/src/sdp/output_html.d
@@ -1,215 +1,43 @@
 template SiSUoutputHTML() {
   struct SDPoutputHTML {
-    string _html_anchor_tags(const(string[]) anchor_tags) {
-      string tags="";
-      if (anchor_tags.length > 0) {
-        foreach (tag; anchor_tags) {
-          if (!(tag.empty)) {
-            tags ~= "<a name=\"" ~ tag ~ "\"></a>";
-          }
+    mixin SiSUoutputXHTMLs;
+    
+    void scroll_write_output_file(
+      string fn_src,
+      string[] doc,
+    ) {
+      mixin SiSUpaths;
+      auto pth_html = HtmlPaths();
+      try {
+        mkdirRecurse(pth_html.base);
+        auto f = File(pth_html.fn_scroll(fn_src), "w");
+        foreach (o; doc) {
+          f.writeln(o);
         }
       }
-      return tags;
-    }
-    auto html_heading(O)(
-      auto ref const O         obj,
-    ) {
-      auto tags = _html_anchor_tags(obj.anchor_tags);
-      string o;
-      if (obj.obj_cite_number.empty) {
-        o = format(q"¶<br><hr /><br>
-      <div class="substance">
-        <h%s class="%s">%s
-          %s
-        </h%s>
-      </div>¶",
-          obj.heading_lev_markup,
-          obj.is_a,
-          tags,
-          obj.text,
-          obj.heading_lev_markup,
-        );
-      } else {
-        o = format(q"¶<br><hr /><br>
-      <div class="substance">
-        <label class="ocn"><a href="#%s" class="lnkocn">%s</a></label>
-        <h%s class="%s" id="%s"><a name="%s"></a>%s
-          %s
-        </h%s>
-      </div>¶",
-        obj.obj_cite_number,
-        obj.obj_cite_number,
-        obj.heading_lev_markup,
-        obj.is_a,
-        obj.obj_cite_number,
-        obj.obj_cite_number,
-        tags,
-        obj.text,
-        obj.heading_lev_markup,
-        );
-      }
-      return o;
-    }
-    auto html_para(O)(
-      auto ref const O         obj,
-    ) {
-      auto tags = _html_anchor_tags(obj.anchor_tags);
-      string o;
-      if (obj.obj_cite_number.empty) {
-        o = format(q"¶  <div class="substance">
-      <p class="%s" indent="h%si%s">%s
-        %s
-      </p>
-    </div>¶",
-          obj.is_a,
-          obj.indent_hang,
-          obj.indent_base,
-          tags,
-          obj.text
-        );
-      } else {
-        o = format(q"¶  <div class="substance">
-      <label class="ocn"><a href="#%s" class="lnkocn">%s</a></label>
-      <p class="%s" indent="h%si%s" id="%s">%s
-        %s
-      </p>
-    </div>¶",
-          obj.obj_cite_number,
-          obj.obj_cite_number,
-          obj.is_a,
-          obj.indent_hang,
-          obj.indent_base,
-          obj.obj_cite_number,
-          tags,
-          obj.text
-        );
-      }
-      return o;
-    }
-    auto html_nugget(O)(
-      auto ref const O         obj,
-    ) {
-      string o;
-      if (obj.obj_cite_number.empty) {
-        o = format(q"¶  <div class="substance">
-      <p class="%s">
-        %s
-      </p>
-    </div>¶",
-          obj.is_a,
-          obj.text
-        );
-      } else {
-        o = format(q"¶  <div class="substance">
-      <label class="ocn"><a href="#%s" class="lnkocn">%s</a></label>
-      <p class="%s" id="%s">
-        %s
-      </p>
-    </div>¶",
-          obj.obj_cite_number,
-          obj.obj_cite_number,
-          obj.is_a,
-          obj.obj_cite_number,
-          obj.text
-        );
-      }
-      return o;
-    }
-    auto scroll_head_html() {
-      string o;
-      o = format(q"¶<!DOCTYPE html>
-    <html>
-    <head>
-      <meta charset="utf-8">
-      <title>
-        %s%s
-      </title>
-    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
-      <meta name="dc.title" content="Title" />
-      <meta name="dc.author" content="Author" />
-      <meta name="dc.publisher" content="SiSU http://www.jus.uio.no/sisu (this copy)" />
-      <meta name="dc.date" content="year" />
-      <meta name="dc.date.created" content="year" />
-      <meta name="dc.date.issued" content="year" />
-      <meta name="dc.date.available" content="year" />
-      <meta name="dc.date.valid" content="year" />
-      <meta name="dc.date.modified" content="year" />
-      <meta name="dc.language" content="US" />
-      <meta name="dc.rights" content="Copyright: Copyright (C) year holder />
-      <meta name="generator" content="sdp [SiSU 7.1.8 of 2016w08/5 (2016-02-26)] (n*x and D)" />
-        <link rel="generator" href="http://www.sisudoc.org/" />
-      <link rel="shortcut icon" href="../_sisu/image/rb7.ico" />
-      <link href="../../_sisu/css/html.css" rel="stylesheet">
-      <link href="../../../_sisu/css/html.css" rel="stylesheet">
-    </head>
-    <body lang="en">
-    <a name="top" id="top"></a>¶",
-    dochead_meta["title"]["full"],
-    (dochead_meta["creator"]["author"].empty) ? "" : ", " ~ dochead_meta["creator"]["author"],
-    );
-      return o;
-    }
-    auto html_toc(O)(
-      auto ref const O         obj,
-    ) {
-      string o;
-      o = format(q"¶  <div class="substance">
-      <p class="%s" indent="h%si%s">
-        %s
-      </p>
-    </div>¶",
-      obj.is_a,
-      obj.indent_hang,
-      obj.indent_base,
-      obj.text
-      );
-      return o;
-    }
-    auto html_endnote(O)(
-      auto ref const O         obj,
-    ) {
-      string o;
-      o = format(q"¶    <p class="%s" indent="h%si%s">
-      %s
-    </p>¶",
-        obj.is_a,
-        obj.indent_hang,
-        obj.indent_base,
-        obj.text
-      );
-      return o;
-    }
-    auto scroll_tail_html() {
-      string o;
-      o = format(q"¶  <a name="bottom" id="bottom"></a>
-      <a name="end" id="end"></a>
-    </div>
-    </body>
-    </html>¶");
-      return o;
+      catch (ErrnoException ex) {
+        // Handle error
+      }
     }
-    void scroll(C)(
+    void scroll(C,T)(
       auto ref const C         contents,
-      string[][string]         document_section_keys_sequenced,
-      string[string][string]   dochead_make,
-      string[string][string]   dochead_meta,
-      string                   fn_src,
-      bool[string]             opt_action_bool
+      auto ref T               doc_matters,
     ) {
+      auto xhtml_format = SDPoutputXHTMLs();
       auto rgx = Rgx();
-      string[] body_html;
+      string[] doc_html;
       string[] doc;
-      foreach (part; document_section_keys_sequenced["scroll"]) {
+      foreach (part; doc_matters.keys_seq_scroll) {
         foreach (obj; contents[part]) {
           if (obj.use == "frontmatter") {
             switch (obj.is_of) {
             case "para":
               switch (obj.is_a) {
               case "heading":
-                body_html ~= html_heading(obj);
+                doc_html ~= xhtml_format.heading(obj);
                 break;
               case "toc":
-                body_html ~= html_toc(obj);
+                doc_html ~= xhtml_format.toc(obj);
                 break;
               default:
                 writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
@@ -225,10 +53,10 @@ template SiSUoutputHTML() {
             case "para":
               switch (obj.is_a) {
               case "heading":
-                body_html ~= html_heading(obj);
+                doc_html ~= xhtml_format.heading(obj);
                 break;
               case "para":
-                body_html ~= html_para(obj);
+                doc_html ~= xhtml_format.para(obj);
                 break;
               default:
                 writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
@@ -240,22 +68,22 @@ template SiSUoutputHTML() {
               case "poem":
                 break;
               case "verse":
-                body_html ~= html_nugget(obj);
+                doc_html ~= xhtml_format.nugget(obj);
                 break;
               case "group":
-                body_html ~= html_nugget(obj);
+                doc_html ~= xhtml_format.nugget(obj);
                 break;
               case "block":
-                body_html ~= html_nugget(obj);
+                doc_html ~= xhtml_format.nugget(obj);
                 break;
               case "quote":
-                body_html ~= html_nugget(obj);
+                doc_html ~= xhtml_format.nugget(obj);
                 break;
               case "table":
-                body_html ~= html_para(obj); //
+                doc_html ~= xhtml_format.para(obj); //
                 break;
               case "code":
-                body_html ~= html_nugget(obj);
+                doc_html ~= xhtml_format.code(obj);
                 break;
               default:
                 writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
@@ -271,22 +99,22 @@ template SiSUoutputHTML() {
             case "para":
               switch (obj.is_a) {
               case "heading":
-                body_html ~= html_heading(obj);
+                doc_html ~= xhtml_format.heading(obj);
                 break;
               case "endnote":
-                body_html ~= html_endnote(obj);
+                doc_html ~= xhtml_format.endnote(obj);
                 break;
               case "glossary":
-                body_html ~= html_para(obj);
+                doc_html ~= xhtml_format.para(obj);
                 break;
               case "bibliography":
-                body_html ~= html_para(obj);
+                doc_html ~= xhtml_format.para(obj);
                 break;
               case "bookindex":
-                body_html ~= html_para(obj);
+                doc_html ~= xhtml_format.para(obj);
                 break;
               case "blurb":
-                body_html ~= html_para(obj);
+                doc_html ~= xhtml_format.para(obj);
                 break;
               default:
                 writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
@@ -300,23 +128,185 @@ template SiSUoutputHTML() {
           }
         }
       }
-      doc = scroll_head_html ~ body_html ~ scroll_tail_html;
+      doc = xhtml_format.scroll_head(doc_matters.dochead_meta) ~ doc_html ~ xhtml_format.tail;
+      scroll_write_output_file(doc_matters.source_filename, doc);
+    }
+    void seg_write_output_files(
+      string fn_src,
+      string[] seg_filenames,
+      string[][string] doc_html,
+    ) {
+      mixin SiSUpaths;
+      auto pth_html = HtmlPaths();
+      auto xhtml_format = SDPoutputXHTMLs();
       auto m = matchFirst(fn_src, rgx.src_fn);
-      auto fn = m["fn_base"] ~ ".html";
-      auto pth_html = "en/html";
-      auto pth_seg = pth_html ~ "/" ~ m["fn_base"];
-      auto pth_html_fn = pth_html ~ "/" ~ fn;
       try {
-        mkdirRecurse(pth_seg);
-        auto f = File(pth_html_fn, "w");
-        foreach (o; doc) {
-          f.writeln(o);
+        mkdirRecurse(pth_html.seg(fn_src));
+        foreach (seg_filename; seg_filenames) {
+          // writeln(__LINE__, ": ", fn);
+          auto f = File(pth_html.fn_seg(fn_src, seg_filename), "w");
+          /+ // f.writeln(seg_head); // not needed built and inserted earlier +/
+          foreach (docseg; doc_html[seg_filename]) {
+            f.writeln(docseg);
+          }
+          f.writeln(xhtml_format.tail); // needed for each lev4
         }
       }
       catch (ErrnoException ex) {
         // Handle error
       }
     }
+    void seg(C,T)(
+      auto ref const C         contents,
+      auto ref T               doc_matters,
+    ) {
+      auto xhtml_format = SDPoutputXHTMLs();
+      auto rgx = Rgx();
+      string[][string] doc_html;
+      string[] doc;
+      string segment_filename;
+      string[] seg_filenames;
+      string[] top_level_headings = ["","","",""];
+      foreach (part; doc_matters.keys_seq_seg) {
+        foreach (obj; contents[part]) {
+          if (obj.is_a == "heading") {                            // all headings: frontmatter, body & backmatter
+            switch (obj.heading_lev_markup) {
+            case 0: .. case 3:
+              /+ fill buffer, and replace with new levels from 1 to 3 +/
+              switch (obj.heading_lev_markup) {
+              case 0:
+                top_level_headings[0] = "";
+                top_level_headings[1] = "";
+                top_level_headings[2] = "";
+                top_level_headings[3] = "";
+                goto default;
+              case 1:
+                top_level_headings[1] = "";
+                top_level_headings[2] = "";
+                top_level_headings[3] = "";
+                goto default;
+              case 2:
+                top_level_headings[2] = "";
+                top_level_headings[3] = "";
+                goto default;
+              case 3:
+                top_level_headings[3] = "";
+                goto default;
+              default:
+                top_level_headings[obj.heading_lev_markup] = xhtml_format.heading(obj); // should probably have different css tagging (fontsize etc)
+                break;
+              }
+              break;
+            case 4:
+              seg_filenames ~= obj.segment_anchor_tag;
+              segment_filename = obj.segment_anchor_tag;
+              doc_html[segment_filename] ~= xhtml_format.seg_head(doc_matters.dochead_meta); // consider placing seg_head here as can more easily populate it with lev4 info
+              foreach (top_level_heading; top_level_headings) {
+                // writeln(top_level_heading);
+                doc_html[segment_filename] ~= top_level_heading;
+              }
+              doc_html[segment_filename] ~= xhtml_format.heading(obj);
+              break;
+            case 5: .. case 7:
+              doc_html[segment_filename] ~= xhtml_format.heading(obj);
+              break;
+            default:
+              writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
+              break;
+            }
+          } else if (obj.use == "frontmatter") {
+            switch (obj.is_of) {
+            case "para":
+              switch (obj.is_a) {
+              case "toc":
+                  doc_html[segment_filename] ~= xhtml_format.toc(obj);
+              break;
+              default:
+                // writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
+                break;
+              }
+              break;
+            default:
+              // writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
+              break;
+            }
+          } else if (obj.use == "body") {
+            switch (obj.is_of) {
+            case "para":
+              switch (obj.is_a) {
+              case "para":
+                doc_html[segment_filename] ~= xhtml_format.para(obj);
+                break;
+              default:
+                // writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
+                break;
+              }
+              break;
+            case "block":
+              switch (obj.is_a) {
+              case "poem":                        // double check why both poem & verse
+                break;
+              case "verse":
+                doc_html[segment_filename] ~= xhtml_format.nugget(obj);
+                break;
+              case "group":
+                doc_html[segment_filename] ~= xhtml_format.nugget(obj);
+                break;
+              case "block":
+                doc_html[segment_filename] ~= xhtml_format.nugget(obj);
+                break;
+              case "quote":
+                doc_html[segment_filename] ~= xhtml_format.nugget(obj);
+                break;
+              case "table":
+                doc_html[segment_filename] ~= xhtml_format.para(obj); //
+                break;
+              case "code":
+                doc_html[segment_filename] ~= xhtml_format.code(obj);
+                break;
+              default:
+                writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
+                break;
+              }
+              break;
+            default:
+              // writeln(__FILE__, ":", __LINE__, ": ", obj.is_of);
+              break;
+            }
+          } else if (obj.use == "backmatter") {
+            switch (obj.is_of) {
+            case "para":
+              switch (obj.is_a) {
+              case "endnote":
+                doc_html[segment_filename] ~= xhtml_format.endnote(obj);
+                break;
+              case "glossary":
+                doc_html[segment_filename] ~= xhtml_format.para(obj);
+                break;
+              case "bibliography":
+                doc_html[segment_filename] ~= xhtml_format.para(obj);
+                break;
+              case "bookindex":
+                doc_html[segment_filename] ~= xhtml_format.para(obj);
+                break;
+              case "blurb":
+                doc_html[segment_filename] ~= xhtml_format.para(obj);
+                break;
+              default:
+                // writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
+                break;
+              }
+              break;
+            default:
+              writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
+              break;
+            }
+          }
+        }
+      }
+      writeln(doc_matters.keys_seq_seg);
+      seg_write_output_files(doc_matters.source_filename, seg_filenames, doc_html);
+    }
     auto html_css() {
       string css;
       css="/* SiSU css default stylesheet */
@@ -1612,6 +1602,9 @@ template SiSUoutputHTML() {
         mkdirRecurse(pth_css);
         auto f = File(pth_css_fn, "w");
         f.writeln(html_css);
+        // foreach (o; doc) {
+        //   f.writeln(o);
+        // }
       }
       catch (ErrnoException ex) {
         // Handle error
diff --git a/src/sdp/output_hub.d b/src/sdp/output_hub.d
index 7235619..bcf0154 100644
--- a/src/sdp/output_hub.d
+++ b/src/sdp/output_hub.d
@@ -4,51 +4,70 @@
 +/
 template SiSUoutputHub() {
   struct SDPoutput {
-    void hub(S)(
+    void hub(S,T)(
       auto ref const S         contents,
-      string[][string]         document_section_keys_sequenced,
-      string[]                 html_segnames,
-      string[string][string]   dochead_make,
-      string[string][string]   dochead_meta,
-      string                   fn_src,
-      bool[string]             opt_action_bool
+      auto ref T               doc_matters,
     ) {
       auto rgx = Rgx();
-      if (opt_action_bool["source"]) {
-        writeln("sisupod source");
+      if (doc_matters.opt_action_bool["source"]) {
+        writeln("source");
       }
-      if (opt_action_bool["sisupod"]) {
+      if (doc_matters.opt_action_bool["sisupod"]) {
+        mixin SiSUpod;
+        auto sisupod=SDPsisupod();
+        sisupod.sisupod_assemble(doc_matters.source_filename);
         writeln("sisupod source");
       }
-      if (opt_action_bool["text"]) {
+      if (doc_matters.opt_action_bool["text"]) {
         writeln("text processing");
       }
-      if (opt_action_bool["html"]) {
+      if (doc_matters.opt_action_bool["html"]) {
+        mixin SiSUoutputHTML;
+        auto html=SDPoutputHTML();
+        html.css_write;
+        html.scroll(
+          contents,
+          doc_matters,
+        );
+        html.seg(
+          contents,
+          doc_matters,
+        );
+      } else if(doc_matters.opt_action_bool["html_seg"]) {
+        mixin SiSUoutputHTML;
+        auto html=SDPoutputHTML();
+        html.css_write;
+        html.seg(
+          contents,
+          doc_matters,
+        );
+      } else if(doc_matters.opt_action_bool["html_scroll"]) {
         mixin SiSUoutputHTML;
         auto html=SDPoutputHTML();
         html.css_write;
         html.scroll(
           contents,
-          document_section_keys_sequenced,
-          dochead_make,
-          dochead_meta,
-          fn_src,
-          opt_action_bool
+          doc_matters,
         );
       }
-      if (opt_action_bool["epub"]) {
-        writeln("epub processing");
+      if (doc_matters.opt_action_bool["epub"]) {
+        mixin SiSUoutputEPub;
+        auto epub=SDPoutputEPub();
+        epub.doc_content(         // consolidate
+          contents,
+          doc_matters,
+        );
       }
-      if (opt_action_bool["pdf"]) {
+      if (doc_matters.opt_action_bool["pdf"]) {
         writeln("pdf processing");
       }
-      if (opt_action_bool["odt"]) {
+      if (doc_matters.opt_action_bool["odt"]) {
         writeln("odt processing");
       }
-      if (opt_action_bool["sqlite"]) {
+      if (doc_matters.opt_action_bool["sqlite"]) {
         writeln("sqlite processing");
       }
-      if (opt_action_bool["postgresql"]) {
+      if (doc_matters.opt_action_bool["postgresql"]) {
         writeln("pgsql processing");
       }
     }
diff --git a/src/sdp/output_xhtmls.d b/src/sdp/output_xhtmls.d
new file mode 100644
index 0000000..7838cbe
--- /dev/null
+++ b/src/sdp/output_xhtmls.d
@@ -0,0 +1,259 @@
+template SiSUoutputXHTMLs() {
+  struct SDPoutputXHTMLs {
+    string _xhtml_anchor_tags(const(string[]) anchor_tags) {
+      string tags="";
+      if (anchor_tags.length > 0) {
+        foreach (tag; anchor_tags) {
+          if (!(tag.empty)) {
+            tags ~= "<a name=\"" ~ tag ~ "\"></a>";
+          }
+        }
+      }
+      return tags;
+    }
+    auto scroll_head(
+      string[string][string]   dochead_meta,
+    ) {
+      string o;
+      o = format(q"¶<!DOCTYPE html>
+    <html>
+    <head>
+      <meta charset="utf-8">
+      <title>
+        %s%s
+      </title>
+    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+      <meta name="dc.title" content="Title" />
+      <meta name="dc.author" content="Author" />
+      <meta name="dc.publisher" content="SiSU http://www.jus.uio.no/sisu (this copy)" />
+      <meta name="dc.date" content="year" />
+      <meta name="dc.date.created" content="year" />
+      <meta name="dc.date.issued" content="year" />
+      <meta name="dc.date.available" content="year" />
+      <meta name="dc.date.valid" content="year" />
+      <meta name="dc.date.modified" content="year" />
+      <meta name="dc.language" content="US" />
+      <meta name="dc.rights" content="Copyright: Copyright (C) year holder />
+      <meta name="generator" content="sdp [SiSU 7.1.8 of 2016w08/5 (2016-02-26)] (n*x and D)" />
+        <link rel="generator" href="http://www.sisudoc.org/" />
+      <link rel="shortcut icon" href="../_sisu/image/rb7.ico" />
+      <link href="../../_sisu/css/html.css" rel="stylesheet">
+      <link href="../../../_sisu/css/html.css" rel="stylesheet">
+    </head>
+    <body lang="en">
+    <a name="top" id="top"></a>¶",
+    dochead_meta["title"]["full"],
+    (dochead_meta["creator"]["author"].empty) ? "" : ", " ~ dochead_meta["creator"]["author"],
+    );
+      return o;
+    }
+    auto seg_head(
+      string[string][string]   dochead_meta,
+    ) {
+      string o;
+      o = format(q"¶<!DOCTYPE html>
+    <html>
+    <head>
+      <meta charset="utf-8">
+      <title>
+        %s%s
+      </title>
+    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+      <meta name="dc.title" content="Title" />
+      <meta name="dc.author" content="Author" />
+      <meta name="dc.publisher" content="SiSU http://www.jus.uio.no/sisu (this copy)" />
+      <meta name="dc.date" content="year" />
+      <meta name="dc.date.created" content="year" />
+      <meta name="dc.date.issued" content="year" />
+      <meta name="dc.date.available" content="year" />
+      <meta name="dc.date.valid" content="year" />
+      <meta name="dc.date.modified" content="year" />
+      <meta name="dc.language" content="US" />
+      <meta name="dc.rights" content="Copyright: Copyright (C) year holder />
+      <meta name="generator" content="sdp [SiSU 7.1.8 of 2016w08/5 (2016-02-26)] (n*x and D)" />
+        <link rel="generator" href="http://www.sisudoc.org/" />
+      <link rel="shortcut icon" href="../_sisu/image/rb7.ico" />
+      <link href="../../_sisu/css/html.css" rel="stylesheet">
+      <link href="../../../_sisu/css/html.css" rel="stylesheet">
+    </head>
+    <body lang="en">
+    <a name="top" id="top"></a>¶",
+    dochead_meta["title"]["full"],
+    (dochead_meta["creator"]["author"].empty) ? "" : ", " ~ dochead_meta["creator"]["author"],
+    );
+      return o;
+    }
+    auto tail() {
+      string o;
+      o = format(q"¶  <a name="bottom" id="bottom"></a>
+      <a name="end" id="end"></a>
+    </div>
+    </body>
+    </html>¶");
+      return o;
+    }
+    auto toc(O)(
+      auto ref const O         obj,
+    ) {
+      string o;
+      o = format(q"¶  <div class="substance">
+      <p class="%s" indent="h%si%s">
+        %s
+      </p>
+    </div>¶",
+      obj.is_a,
+      obj.indent_hang,
+      obj.indent_base,
+      obj.text
+      );
+      return o;
+    }
+    auto heading(O)(
+      auto ref const O         obj,
+    ) {
+      auto tags = _xhtml_anchor_tags(obj.anchor_tags);
+      string o;
+      if (obj.obj_cite_number.empty) {
+        o = format(q"¶<br><hr /><br>
+      <div class="substance">
+        <h%s class="%s">%s
+          %s
+        </h%s>
+      </div>¶",
+          obj.heading_lev_markup,
+          obj.is_a,
+          tags,
+          obj.text,
+          obj.heading_lev_markup,
+        );
+      } else {
+        o = format(q"¶<br><hr /><br>
+      <div class="substance">
+        <label class="ocn"><a href="#%s" class="lnkocn">%s</a></label>
+        <h%s class="%s" id="%s"><a name="%s"></a>%s
+          %s
+        </h%s>
+      </div>¶",
+        obj.obj_cite_number,
+        obj.obj_cite_number,
+        obj.heading_lev_markup,
+        obj.is_a,
+        obj.obj_cite_number,
+        obj.obj_cite_number,
+        tags,
+        obj.text,
+        obj.heading_lev_markup,
+        );
+      }
+      return o;
+    }
+    auto para(O)(
+      auto ref const O         obj,
+    ) {
+      auto tags = _xhtml_anchor_tags(obj.anchor_tags);
+      string o;
+      if (obj.obj_cite_number.empty) {
+        o = format(q"¶  <div class="substance">
+      <p class="%s" indent="h%si%s">%s
+        %s
+      </p>
+    </div>¶",
+          obj.is_a,
+          obj.indent_hang,
+          obj.indent_base,
+          tags,
+          obj.text
+        );
+      } else {
+        o = format(q"¶  <div class="substance">
+      <label class="ocn"><a href="#%s" class="lnkocn">%s</a></label>
+      <p class="%s" indent="h%si%s" id="%s">%s
+        %s
+      </p>
+    </div>¶",
+          obj.obj_cite_number,
+          obj.obj_cite_number,
+          obj.is_a,
+          obj.indent_hang,
+          obj.indent_base,
+          obj.obj_cite_number,
+          tags,
+          obj.text
+        );
+      }
+      return o;
+    }
+    auto nugget(O)(
+      auto ref const O         obj,
+    ) {
+      string o;
+      if (obj.obj_cite_number.empty) {
+        o = format(q"¶  <div class="substance">
+      <p class="%s">
+        %s
+      </p>
+    </div>¶",
+          obj.is_a,
+          obj.text
+        );
+      } else {
+        o = format(q"¶  <div class="substance">
+      <label class="ocn"><a href="#%s" class="lnkocn">%s</a></label>
+      <p class="%s" id="%s">
+        %s
+      </p>
+    </div>¶",
+          obj.obj_cite_number,
+          obj.obj_cite_number,
+          obj.is_a,
+          obj.obj_cite_number,
+          obj.text
+        );
+      }
+      return o;
+    }
+    auto endnote(O)(
+      auto ref const O         obj,
+    ) {
+      string o;
+      o = format(q"¶    <p class="%s" indent="h%si%s">
+      %s
+    </p>¶",
+        obj.is_a,
+        obj.indent_hang,
+        obj.indent_base,
+        obj.text
+      );
+      return o;
+    }
+    auto code(O)(
+      auto ref const O         obj,
+    ) {
+      string o;
+      if (obj.obj_cite_number.empty) {
+          o = format(q"¶  <div class="substance">
+        <p class="%s">
+%s
+      </p>
+    </div>¶",
+          obj.is_a,
+          obj.text
+        );
+      } else {
+        o = format(q"¶  <div class="substance">
+      <label class="ocn"><a href="#%s" class="lnkocn">%s</a></label>
+      <p class="%s" id="%s">
+%s
+      </p>
+    </div>¶",
+          obj.obj_cite_number,
+          obj.obj_cite_number,
+          obj.is_a,
+          obj.obj_cite_number,
+          obj.text
+        );
+      }
+      return o;
+    }
+  }
+}
diff --git a/src/sdp/source_sisupod.d b/src/sdp/source_sisupod.d
new file mode 100644
index 0000000..dc54b21
--- /dev/null
+++ b/src/sdp/source_sisupod.d
@@ -0,0 +1,43 @@
+template SiSUpod() {
+  struct SDPsisupod {
+    
+    void sisupod_assemble(
+      string fn_src,
+    ) {
+      mixin SiSUpaths;
+      auto pth_sisupod = SiSUpodPaths();
+      mixin SiSUlanguageCodes;
+      auto lang = Lang();
+      /+
+        dir structure
+        /tmp/_sisu_processing_/ralph/en/sisupod
+          ├── doc
+          │   └── en
+          └── image
+    
+        - create directory structure
+    
+      +/
+      assert (match(fn_src, rgx.src_fn));
+      try {
+        /+ create directory structure +/
+        mkdirRecurse(pth_sisupod.doc(fn_src));
+        mkdirRecurse(pth_sisupod.conf(fn_src));
+        mkdirRecurse(pth_sisupod.css(fn_src));
+        mkdirRecurse(pth_sisupod.image(fn_src));
+        /+ copy relevant files +/
+        auto f_out = pth_sisupod.fn_doc(fn_src, "en"); // you need fn without path and then to insert back language code for output sub-directory
+        debug(sisupod) {
+          writeln(__LINE__, ": ", fn_src, " -> ", f_out);
+        }
+        mkdirRecurse(pth_sisupod.doc_lng(fn_src, "en")); // need to extract language code directories (from directory structure or filenames & have a default)
+        copy(fn_src, f_out);
+      }
+      catch (ErrnoException ex) {
+        // Handle error
+      }
+    }
+    
+    
+  }
+}
-- 
cgit v1.2.3