-*- mode: org -*-
#+TITLE:       spine (doc_reform) object-centric document abstraction
#+DESCRIPTION: documents - structuring, publishing in multiple formats & search
#+FILETAGS:    :spine:abstraction:
#+AUTHOR:      Ralph Amissah
#+EMAIL:       [[mailto:ralph.amissah@gmail.com][ralph.amissah@gmail.com]]
#+COPYRIGHT:   Copyright (C) 2015 - 2024 Ralph Amissah
#+LANGUAGE:    en
#+STARTUP:     content hideblocks hidestars noindent entitiespretty
#+PROPERTY:    header-args  :noweb yes
#+PROPERTY:    header-args+ :exports code
#+PROPERTY:    header-args+ :results no
#+PROPERTY:    header-args+ :cache no
#+PROPERTY:    header-args+ :padline no
#+PROPERTY:    header-args+ :mkdirp yes
#+OPTIONS:     H:3 num:nil toc:t \n:t ::t |:t ^:nil -:t f:t *:t

- [[./doc-reform.org][doc-reform.org]]  [[./][org/]]

* (Object-Centric) Document Abstraction
Process markup document, create document abstraction.

** _module template_ :module:metadoc_from_src:

#+HEADER: :tangle "../src/doc_reform/meta/metadoc_from_src.d"
#+HEADER: :noweb yes
#+BEGIN_SRC d
<<doc_header_including_copyright_and_license>>
// document abstraction:
// abstraction of sisu markup for downstream processing
// metadoc_from_src.d
module doc_reform.meta.metadoc_from_src;
template docAbstraction() {
  <<docInitialize>>
  @system auto docAbstraction(CMM,Opt,Mf) (
    char[][]           markup_sourcefile_content,
    CMM                conf_make_meta,
    Opt                opt_action,
    Mf                 manifested,
    bool               _new_doc
  ) {
    <<docAbstraction>>
  } // ← closed: abstract doc source
  <<docAbstractionRelatedFunctions>>
}
template docSectKeysSeq() {
  <<docSectKeysSeq>>
}
#+END_SRC

** docInitialize

#+NAME: docInitialize
#+HEADER: :noweb yes
#+BEGIN_SRC d
// ↓ abstraction imports
import
  std.algorithm,
  std.container,
  std.file,
  std.json,
  std.path;
import
  doc_reform.meta,
  doc_reform.meta.defaults,
  doc_reform.meta.rgx,
  doc_reform.meta.metadoc_object_setter,
  doc_reform.meta.rgx;
// ↓ abstraction mixins
mixin ObjectSetter;
mixin InternalMarkup;
mixin spineRgxIn;
// initialize
ObjGenericComposite[] the_document_toc_section, the_document_head_section, the_document_body_section, the_document_endnotes_section, the_document_bibliography_section, the_document_bookindex_section, the_document_glossary_section, the_document_blurb_section, the_document_xml_dom_tail_section;
struct _theDoc {
  ObjGenericComposite[] toc;
  ObjGenericComposite[] head;
  ObjGenericComposite[] body;
  ObjGenericComposite[] bibliography;
  ObjGenericComposite[] glossary;
  ObjGenericComposite[] bookindex;
  ObjGenericComposite[] blurb;
  ObjGenericComposite[] endnotes;
}
string[string] an_object, processing, object_notes;
string an_object_key;
string[] anchor_tags;
string anchor_tag;
string anchor_tag_;
string[string] tag_in_seg;
string lev_anchor_tag;
string[string][string] tag_assoc;
string[] lv0to3_tags;
// enum
enum DocStructMarkupHeading {
  h_sect_A,
  h_sect_B,
  h_sect_C,
  h_sect_D,
  h_text_1,
  h_text_2,
  h_text_3,
  h_text_4,
  h_text_5, // extra level, drop
  content_non_header
} // header section A-D; header text 1-4
enum Status { off, on, }
enum OCNtype { ocn, non, bkidx, }
// biblio variables
string biblio_tag_name, biblio_tag_entry, st;
string[] biblio_arr_json;
string biblio_entry_str_json;
JSONValue[] bib_arr_json;
int bib_entry;
// counters
int cntr, previous_count, previous_length;
bool reset_note_numbers = true;
int[string] line_occur;
int html_segnames_ptr = 0;
int html_segnames_ptr_cntr = 0;
int verse_line, heading_ptr;
// paragraph attributes
int[string] indent;
bool bullet = true;
string content_non_header = "8";
static auto obj_im = ObjInlineMarkup();
static auto obj_att = ObjAttributes();
// ocn
struct OCNset {
  int digit;
  int object_number;
  bool off;
  string identifier;
  int bkidx;
  int type;
}
OCNset obj_cite_digits;
int obj_cite_digit_, obj_cite_digit_off, obj_cite_digit_bkidx, obj_cite_digit_type;
auto object_citation_number = OCNemitter();
struct ST_endnotes {
  ObjGenericComposite[] endnotes;
  OCNset                ocn;
}
struct ST_bookindex {
  ObjGenericComposite[] bookindex;
  OCNset                ocn;
}
struct ST_biblio_section {
  ObjGenericComposite[]  bibliography_section;
  string[string][string] tag_assoc;
}
int[] dom_structure_markedup_tags_status         = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
int[] dom_structure_markedup_tags_status_buffer  = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
int[] dom_structure_collapsed_tags_status        = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
int[] dom_structure_collapsed_tags_status_buffer = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
struct ST_ancestors {
  ObjGenericComposite[] the_document_body_section;
  ObjGenericComposite[] the_document_endnotes_section;
  ObjGenericComposite[] the_document_glossary_section;
  ObjGenericComposite[] the_document_bibliography_section;
  ObjGenericComposite[] the_document_bookindex_section;
  ObjGenericComposite[] the_document_blurb_section;
}
struct ST_segnames {
  string[][string]      segnames;
  int                   html_segnames_ptr_cntr;
  int                   html_segnames_ptr;
}
struct  ST_txtPlusHasFootnotes {
  string           obj_txt;
  bool             has_notes_reg;
  bool             has_notes_star;
  bool             has_notes_plus;
}
struct ST_txtPlusHasFootnotesUrlsImages {
  string           obj_txt;
  bool             has_notes_reg;
  bool             has_notes_star;
  bool             has_notes_plus;
  bool             has_urls;
  bool             has_images_without_dimensions;
}
struct ST_txtAndAnchorTagPlusHasFootnotesUrlsImages {
  string           obj_txt;
  string           anchor_tag;
  bool             has_notes_reg;
  bool             has_notes_star;
  bool             has_notes_plus;
  bool             has_links; // use same name
  bool             has_images_without_dimensions;
}
struct ST_the_section {
  ObjGenericComposite[]  comp_section_obj; // array: the heading has 2 members inserted, paras just 1
  uint[string]           pith;
  string[string][string] tag_assoc;        // only for headings: html & epub
}
enum DomTags { none, open, close, close_and_open, open_still, }
// book index variables
string book_idx_tmp;
string[][string][string] bookindex_unordered_hashes;
// node
ObjGenericComposite comp_obj_, comp_obj_location, comp_obj_poem_ocn, comp_obj_comment;
auto node_construct = NodeStructureMetadata();
struct ST_txt_by_line_common_reset {
  int[string]     line_occur;
  string[string]  this_object;
  uint[string]    pith;
}
struct ST_txt_by_line_block_start {
  uint[string]    pith;
  uint[string]    dochas;
  string[string]  object_number_poem;
}
struct ST_txt_by_line_block_generic {
  uint[string]    pith;
  string[string]  this_object;
}
struct ST_txt_by_line_block_poem {
  int             cntr;
  uint[string]    pith;
  string[string]  this_object;
}
struct ST_txt_by_line_block_biblio {
  uint[string]    pith;
  int             bib_entry;
  string          biblio_entry_str_json;
  string[]        biblio_arr_json;
}
struct ST_flow_book_index {
  string[string]  this_object;
  uint[string]    pith;
  string          book_idx_tmp;
}
struct ST_flow_heading_found {
  string[string]       heading_match_str;
  Regex!(char)[string] heading_match_rgx;
  uint[string]         pith;
}
struct ST_flow_heading_make_set {
  char[]          line;
  uint[string]    pith;
  string[string]  this_object;
}
struct ST_flow_para_match {
  uint[string]    pith;
  string[string]  this_object;
  string          this_object_key;
  int[string]     indent;
  bool            bullet;
  int[string]     line_occur;
}
struct ST_flow_table_array_munge {
  ObjGenericComposite table_object;
  string[][]          table_array;
}
struct ST_flow_table_of_contents_gather_headings {
  ObjGenericComposite[] the_document_toc_section;
  string[][string]      lev4_subtoc;
}
struct ST_flow_bibliography {
  JSONValue[] biblio_sorted;
  JSONValue[] bib_arr_json;
  string[]    biblio_unsorted_incomplete;
}
struct ST_flow_table_closed_make_special_notation_table {
  string[string]        this_object;
  ObjGenericComposite[] the_document_body_section;
  OCNset                obj_cite_digits;
  ObjGenericComposite   comp_obj_;
  int                   cntr;
  uint[string]          pith;
}
struct ST_flow_block_flag_line_empty {
  string[string]           this_object;
  ObjGenericComposite[]    the_document_body_section;
  string[][string][string] bookindex_unordered_hashes;
  OCNset                   obj_cite_digits;
  ObjGenericComposite      comp_obj_;
  int                      cntr;
  uint[string]             pith;
}
struct ST_flow_table_substantive_munge {
  ObjGenericComposite  table_object;
  string               table_substantive;
}
#+END_SRC

** docAbstraction
*** toc

#+NAME: docAbstraction
#+HEADER: :noweb yes
#+BEGIN_SRC d
<<docAbstractionInit>>
<<docAbstractionInitSubstitutions>>
<<docAbstractionMainLoopSrcByLine>>
<<docAbstractionPostMainLoop>>
<<docAbstractionReturnsStruct>>
#+END_SRC

*** abstraction init

#+NAME: docAbstractionInit
#+HEADER: :noweb yes
#+BEGIN_SRC d
static auto rgx = RgxI();
// ↓ abstraction init
scope(success) {
}
scope(failure) {
}
scope(exit) {
  destroy(the_document_toc_section);
  destroy(the_document_head_section);
  destroy(the_document_body_section);
  destroy(the_document_bibliography_section);
  destroy(the_document_glossary_section);
  destroy(the_document_blurb_section);
  destroy(the_document_xml_dom_tail_section);
  destroy(an_object);
  destroy(processing);
  destroy(biblio_arr_json);
  previous_length = 0;
  reset_note_numbers = true;
  lev_anchor_tag = "";
  anchor_tag = "";
}
mixin spineNode;
auto node_para_int_    = node_metadata_para_int;
auto node_para_str_    = node_metadata_para_str;
ObjGenericComposite comp_obj_;
line_occur = [
  "heading"  : 0,
  "para"     : 0,
  "glossary" : 0,
  "blurb"    : 0,
];
uint[string] dochas = [
  "inline_links"      : 0,
  "inline_notes"      : 0,
  "inline_notes_star" : 0,
  "codeblock"         : 0,
  "table"             : 0,
  "block"             : 0,
  "group"             : 0,
  "poem"              : 0,
  "quote"             : 0,
  "images"            : 0,
];
uint[string] pith = [
  "ocn"                            : 1,
  "section"                        : 0,
  "txt_is"                         : 0,
  "block_is"                       : 0,
  "block_state"                    : 0,
  "block_delim"                    : 0,
  "make_headings"                  : 0,
  "dummy_heading_status"           : 0,
  "dummy_heading_multiple_objects" : 0,
  "no_ocn_multiple_objects"        : 0,
  "verse_new"                      : 0,
];
string[string] object_number_poem = [
  "start" : "",
  "end"   : ""
];
string[] lv_ancestors_txt = [ "", "", "", "", "", "", "", "", ];
int[string] lv = [
  "lv" : eN.bi.off,
  "h0" : eN.bi.off,
  "h1" : eN.bi.off,
  "h2" : eN.bi.off,
  "h3" : eN.bi.off,
  "h4" : eN.bi.off,
  "h5" : eN.bi.off,
  "h6" : eN.bi.off,
  "h7" : eN.bi.off,
  "lev_int_collapsed" : 0,
];
int[string] collapsed_lev = [
  "h0" : eN.bi.off,
  "h1" : eN.bi.off,
  "h2" : eN.bi.off,
  "h3" : eN.bi.off,
  "h4" : eN.bi.off,
  "h5" : eN.bi.off,
  "h6" : eN.bi.off,
  "h7" : eN.bi.off
];
string[string] heading_match_str = [
  "h_A": "^(none)",
  "h_B": "^(none)",
  "h_C": "^(none)",
  "h_D": "^(none)",
  "h_1": "^(none)",
  "h_2": "^(none)",
  "h_3": "^(none)",
  "h_4": "^(none)"
];
Regex!char[string] heading_match_rgx = [
  "h_A": regex(r"^(none)"),
  "h_B": regex(r"^(none)"),
  "h_C": regex(r"^(none)"),
  "h_D": regex(r"^(none)"),
  "h_1": regex(r"^(none)"),
  "h_2": regex(r"^(none)"),
  "h_3": regex(r"^(none)"),
  "h_4": regex(r"^(none)")
];
string _anchor_tag;
string toc_txt_;
an_object["glossary_nugget"]                                   = "";
an_object["blurb_nugget"]                                      = "";
comp_obj_                                                      = set_object_heading("lev4", "frontmatter", "toc", "Table of Contents");
comp_obj_.metainfo.identifier                                  = "";
comp_obj_.metainfo.dummy_heading                               = false;
comp_obj_.metainfo.object_number_off                           = true;
comp_obj_.metainfo.object_number_type                          = 0;
comp_obj_.tags.segment_anchor_tag_epub                         = "toc";
comp_obj_.tags.anchor_tag_html                                 = comp_obj_.tags.segment_anchor_tag_epub;
comp_obj_.tags.in_segment_html                                 = comp_obj_.tags.anchor_tag_html;
comp_obj_.ptr.html_segnames                                    = html_segnames_ptr;
comp_obj_.tags.anchor_tags                                     = ["toc"];
tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"]            = comp_obj_.tags.in_segment_html;
tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub;
auto toc_head                                                  = comp_obj_;
html_segnames_ptr_cntr++;
the_document_toc_section = [toc_head];
static auto mkup = InlineMarkup();
static auto munge = ObjInlineMarkupMunge();
auto note_section = NotesSection();
auto bookindex_extract_hash = BookIndexNuggetHash();
string[][string] lev4_subtoc;
string[][string] segnames = ["html": ["toc"], "epub": ["toc"]];
int cnt1 = 1; int cnt2 = 1; int cnt3 = 1;
// abstraction init ↑
#+END_SRC

*** abstraction init substitutions

#+NAME: docAbstractionInitSubstitutions
#+HEADER: :noweb yes
#+BEGIN_SRC d
enum Substitute { match, markup, }
debug (substitutions) {
  writeln(__LINE__, ":", __FILE__, ": DEBUG substitutions:");
  if (!(conf_make_meta.make.headings.empty)) {
    writeln(conf_make_meta.make.headings);
  }
  if (conf_make_meta.make.substitute) {
    foreach(substitution_pair; conf_make_meta.make.substitute) {
       writeln("regex to match:       ", substitution_pair[Substitute.match]);
       writeln("substitution to make: ", substitution_pair[Substitute.markup]);
    }
  }
  if (conf_make_meta.make.bold) {
    writeln("regex to match:       ", conf_make_meta.make.bold[Substitute.match]);
    writeln("substitution to make: ", conf_make_meta.make.bold[Substitute.markup]);
  }
  if (conf_make_meta.make.emphasis) {
    writeln("regex to match:       ", conf_make_meta.make.emphasis[Substitute.match]);
    writeln("substitution to make: ", conf_make_meta.make.emphasis[Substitute.markup]);
  }
  if (conf_make_meta.make.italics) {
    writeln("regex to match:       ", conf_make_meta.make.italics[Substitute.match]);
    writeln("substitution to make: ", conf_make_meta.make.italics[Substitute.markup]);
  }
}
#+END_SRC

*** loop source by line (large block)

#+NAME: docAbstractionMainLoopSrcByLine
#+HEADER: :noweb yes
#+BEGIN_SRC d
auto loopMarkupSrcByLine(
  char[][]         markup_sourcefile_content,
  string[string]   an_object,
  uint[string]     pith,
) {
  struct _loopMarkupSrcByLineStruct {
    ObjGenericComposite[] toc;
    ObjGenericComposite[] body;
    ObjGenericComposite[] glossary;
    ObjGenericComposite[] blurb;
    string[string]        object_notes;
    string[][string]      segnames;
  }
  _loopMarkupSrcByLineStruct ret;
  srcDocLoopLineByLine_:
  foreach (line; markup_sourcefile_content) {
    // ↓ markup document/text line by line
    // "line" variable can be empty but should never be null
    // scope
    scope(exit) { }
    scope(failure) {
      stderr.writefln(
        "\n%s\n%s\n\n%s:%s\nFAILED while processing the file: ❮❮ %s ❯❯ on line with text:\n%s\n",
        __MODULE__, __FUNCTION__,
        __FILE__, __LINE__,
        manifested.src.filename, line,
      );
    }
    debug(source) { writeln(line); }
    debug(srclines) { if (!line.empty) { writefln("* %s", line); } }
    if (!line.empty) { pith = line._check_ocn_status_(pith); }
    if ( pith["block_is"] == eN.blk_is.code
      && pith["block_state"] == eN.blk_state.on
    ) {
      // block object: code
      {
        ST_txt_by_line_block_generic _get = line.txt_by_line_block_code(an_object, pith);
        {
          an_object = _get.this_object;
          pith      = _get.pith;
        }
      }
      continue;
    } else if (!matchFirst(line, rgx.skip_from_regular_parse)) {
      // object other than "code block" object
      // (includes regular text paragraph, headings & blocks other than code)
      // heading, glossary, blurb, poem, group, block, quote, table
      line = line.inline_markup_faces; // by text line (rather than by text object), linebreaks in para problematic
      if (line.matchFirst(rgx.heading_biblio)
      || (pith["section"] == eN.sect.bibliography
        && ((!(line.matchFirst(rgx.heading_glossary)))
        && (!(line.matchFirst(rgx.heading_blurb)))
        && (!(line.matchFirst(rgx.heading)))
        && (!(line.matchFirst(rgx.comment)))))
      ) {
        pith["section"] = eN.sect.bibliography;
        if (opt_action.backmatter && opt_action.section_biblio) {
          {
            ST_txt_by_line_block_biblio _get = line.txt_by_line_block_biblio(pith, bib_entry, biblio_entry_str_json, biblio_arr_json);
            {
              pith                  = _get.pith;
              bib_entry             = _get.bib_entry;
              biblio_entry_str_json = _get.biblio_entry_str_json;
              biblio_arr_json       = _get.biblio_arr_json;
            }
          }
          debug(bibliobuild) {
            writeln("-  ", biblio_entry_str_json);
            writeln("-> ", biblio_arr_json.length);
          }
        }
        continue;
      } else if (line.matchFirst(rgx.heading_glossary)
      || (pith["section"] == eN.sect.glossary
        && ((!(line.matchFirst(rgx.heading_biblio)))
        && (!(line.matchFirst(rgx.heading_blurb)))
        && (!(line.matchFirst(rgx.heading)))
        && (!(line.matchFirst(rgx.comment)))))
      ) {
        // within section (block object): glossary
        debug(glossary) { writeln(__LINE__); writeln(line); }
        pith["section"] = eN.sect.glossary;
        if (opt_action.backmatter && opt_action.section_glossary) {
          ST_the_section add_to_glossary_sect = line.build_the_glossary_section(pith, tag_assoc);
          the_document_glossary_section ~= add_to_glossary_sect.comp_section_obj[0];
          if (add_to_glossary_sect.comp_section_obj.length > 1) { // heading
            the_document_glossary_section ~= add_to_glossary_sect.comp_section_obj[1];
          }
          pith      = add_to_glossary_sect.pith;
          tag_assoc = add_to_glossary_sect.tag_assoc;
        }
        continue;
      } else if (line.matchFirst(rgx.heading_blurb)
      || (pith["section"] == eN.sect.blurb
        && ((!(line.matchFirst(rgx.heading_glossary)))
        && (!(line.matchFirst(rgx.heading_biblio)))
        && (!(line.matchFirst(rgx.heading)))
        && (!(line.matchFirst(rgx.comment)))))
      ) {
        pith["section"] = eN.sect.blurb;
        debug(blurb) { writeln(__LINE__); writeln(line); }
        if ((opt_action.backmatter && opt_action.section_blurb) && !(line.empty)) {
          ST_the_section add_to_blurb_sect = line.build_the_blurb_section(pith, tag_assoc, opt_action);
          the_document_blurb_section ~= add_to_blurb_sect.comp_section_obj[0];
          if (add_to_blurb_sect.comp_section_obj.length > 1) { // heading
            the_document_blurb_section ~= add_to_blurb_sect.comp_section_obj[1];
          }
          pith      = add_to_blurb_sect.pith;
          tag_assoc = add_to_blurb_sect.tag_assoc;
        }
        continue;
      } else if (pith["block_state"] == eN.blk_state.on) {
        if (pith["block_is"]    == eN.blk_is.quote) {
          line = line
            ._doc_header_and_make_substitutions_(conf_make_meta)
            ._doc_header_and_make_substitutions_fontface_(conf_make_meta);
          {
            auto _get = line.txt_by_line_block_quote(an_object, pith);
            {
              an_object = _get.this_object;
              pith      = _get.pith;
            }
          }
          continue;
        } else if (pith["block_is"]    == eN.blk_is.group) {
          line = line
            ._doc_header_and_make_substitutions_(conf_make_meta)
            ._doc_header_and_make_substitutions_fontface_(conf_make_meta)
            .replaceAll(rgx.para_delimiter, mkup.br_line_spaced ~ "$1");
          {
            auto _get = line.txt_by_line_block_group(an_object, pith);
            {
              an_object = _get.this_object;
              pith      = _get.pith;
            }
          }
          continue;
        } else if (pith["block_is"]    == eN.blk_is.block) {
          line = line
            ._doc_header_and_make_substitutions_(conf_make_meta)
            ._doc_header_and_make_substitutions_fontface_(conf_make_meta);
          if (auto m = line.match(rgx.spaces_keep)) {
            line = line
              .replaceAll(rgx.spaces_keep, (m.captures[1]).translate([ ' ' : mkup.nbsp ]));
          }
          {
            auto _get = line.txt_by_line_block_block(an_object, pith);
            {
              an_object = _get.this_object;
              pith      = _get.pith;
            }
          }
          continue;
        } else if (pith["block_is"]    == eN.blk_is.poem) {
          {
            auto _get = line.txt_by_line_block_poem(an_object, pith, cntr, object_number_poem, conf_make_meta, tag_in_seg);
            {
              an_object = _get.this_object;
              pith      = _get.pith;
              cntr      = _get.cntr;
            }
          }
          continue;
        } else if (pith["block_is"]    == eN.blk_is.table) {
          {
            auto _get = line.txt_by_line_block_table(an_object, pith, conf_make_meta);
            {
              an_object      = _get.this_object;
              pith           = _get.pith;
              conf_make_meta = _get.conf_make_meta;
            }
          }
          continue;
        }
      } else {
        // not within a block group
        assert(
          (pith["block_state"] == eN.blk_state.off)
          || (pith["block_state"] == eN.blk_state.closing),
          "block status: none or closed"
        );
        if (line.matchFirst(rgx.block_open)) {
          if (line.matchFirst(rgx.block_poem_open)) {
            // poem to verse exceptions!
            object_reset(an_object);
            processing.remove("verse");
            object_number_poem["start"] = obj_cite_digits.object_number.to!string;
          }
          {
            auto _get = line.txt_by_line_block_start(pith, dochas, object_number_poem);
            {
              pith               = _get.pith;
              dochas             = _get.dochas;
              object_number_poem = _get.object_number_poem;
            }
          }
          continue;
        } else if (!line.empty) {
          // line not empty - non blocks (headings, paragraphs) & closed blocks
          assert(!line.empty, "line tested, line not empty surely:\n  \"" ~ line ~ "\"");
          assert(
            (pith["block_state"] == eN.blk_state.off)
            || (pith["block_state"] == eN.blk_state.closing),
            "code block status: none or closed"
          );
          if (pith["block_state"] == eN.blk_state.closing) {
            debug(check) { writeln(__LINE__); writeln(line); }
            assert(
              line.matchFirst(rgx.book_index_item)
              || line.matchFirst(rgx.book_index_item_open)
              || pith["section"] == eN.sect.book_index,
              "\nblocks closed, unless followed by book index, non-matching line:\n  \""
              ~ line ~ "\""
            );
          }
          if (line.matchFirst(rgx.book_index_item)
          || line.matchFirst(rgx.book_index_item_open)
          || pith["section"] == eN.sect.book_index)  {
            { // book_index
              auto _get = line.flow_book_index_(an_object, book_idx_tmp, pith, opt_action);
              {
                an_object = _get.this_object;
                pith      = _get.pith;
                book_idx_tmp      = _get.book_idx_tmp;
              }
            }
          } else {
            // not book_index
            an_object_key = "body_nugget";
            if (auto m = line.matchFirst(rgx.comment)) {
              // matched comment
              debug(comment) { writeln(line); }
              an_object[an_object_key]                ~= line ~= "\n";
              comp_obj_comment                        = comp_obj_comment.init;
              comp_obj_comment.metainfo.is_of_part    = "comment"; // breaks flow
              comp_obj_comment.metainfo.is_of_section = "comment"; // breaks flow
              comp_obj_comment.metainfo.is_of_type    = "comment";
              comp_obj_comment.metainfo.is_a          = "comment";
              comp_obj_comment.text                   = an_object[an_object_key].strip;
              the_document_body_section               ~= comp_obj_comment;
              {
                auto _get = txt_by_line_common_reset_(line_occur, an_object, pith);
                {
                  line_occur = _get.line_occur;
                  an_object  = _get.this_object;
                  pith       = _get.pith;
                }
              }
              processing.remove("verse");
              ++cntr;
            } else if ((line_occur["para"] == eN.bi.off
              && line_occur["heading"] == eN.bi.off)
              && pith["txt_is"] == eN.txt_is.off
            ) { // heading or para but neither flag nor line exists
              if ((conf_make_meta.make.headings.length > 2)
              && (pith["make_headings"] == eN.bi.off)) {
                // heading found
                {
                  auto _get = line.flow_heading_found_(heading_match_str, conf_make_meta.make.headings, heading_match_rgx, pith);
                  {
                    heading_match_str = _get.heading_match_str;
                    heading_match_rgx = _get.heading_match_rgx;
                    pith              = _get.pith;
                  }
                }
              }
              if (pith["make_headings"] == eN.bi.on
                && (line_occur["para"] == eN.bi.off
                && line_occur["heading"] == eN.bi.off)
                && pith["txt_is"] == eN.txt_is.off
              ) {
                // heading make set
                {
                  auto _get = line.flow_heading_make_set_(line_occur, heading_match_rgx, pith);
                  {
                    line      = _get.line;
                    an_object = _get.this_object;
                    pith      = _get.pith;
                  }
                }
              }
              // TODO node info: all headings identified at this point,
              // - extract node info here??
              // - how long can it wait?
              // - should be incorporated in composite objects
              // - should happen before endnote links set (they need to be moved down?)
              if (line.matchFirst(rgx.headings)) {
                // heading match
                line = line._doc_header_and_make_substitutions_(conf_make_meta);
                {
                  auto _get = line.flow_heading_matched_(
                    an_object,
                    line_occur,
                    an_object_key,
                    lv,
                    collapsed_lev,
                    pith,
                    conf_make_meta,
                  );
                  {
                    an_object = _get.this_object;
                    pith      = _get.pith;
                  }
                }
              } else if (line_occur["para"] == eN.bi.off) {
                // para match
                an_object_key = "body_nugget";
                line = line
                  ._doc_header_and_make_substitutions_(conf_make_meta)
                  ._doc_header_and_make_substitutions_fontface_(conf_make_meta);
                {
                  auto _get = line.flow_para_match_(an_object, an_object_key, indent, bullet, pith, line_occur);
                  {
                    an_object     = _get.this_object;
                    an_object_key = _get.this_object_key;
                    pith          = _get.pith;
                    indent        = _get.indent;
                    bullet        = _get.bullet;
                    line_occur    = _get.line_occur;
                  }
                }
              }
            } else if (line_occur["heading"] > eN.bi.off) {
              // heading
              debug(heading) { writeln(line); }
              an_object[an_object_key] ~= line ~= "\n";
              ++line_occur["heading"];
            } else if (line_occur["para"] > eN.bi.off) {
              // paragraph
              debug(para) { writeln(an_object_key, "-> ", line); }
              line = line
                ._doc_header_and_make_substitutions_(conf_make_meta)
                ._doc_header_and_make_substitutions_fontface_(conf_make_meta);
              an_object[an_object_key] ~= " " ~ line;
              ++line_occur["para"];
            }
          }
        } else if (pith["block_state"] == eN.blk_state.closing) {
          // line empty, with blocks flag
          {
            auto _get = line.flow_block_flag_line_empty_(
              an_object,
              bookindex_extract_hash,
              the_document_body_section,
              bookindex_unordered_hashes,
              obj_cite_digits,
              comp_obj_,
              cntr,
              pith,
              object_number_poem,
              conf_make_meta,
              tag_in_seg,
            );
            {
              an_object                  = _get.this_object;
              the_document_body_section  = _get.the_document_body_section;
              bookindex_unordered_hashes = _get.bookindex_unordered_hashes;
              obj_cite_digits            = _get.obj_cite_digits;
              comp_obj_                  = _get.comp_obj_;
              cntr                       = _get.cntr;
              pith                       = _get.pith;
            }
          }
        } else {
          // line.empty, post contents, empty variables:
          assert(
            line.empty,
            "\nline should be empty:\n  \""
            ~ line ~ "\""
          );
          assert(
            (pith["block_state"] == eN.blk_state.off),
            "code block status: none"
          );
          if (_new_doc) {
            tag_assoc   = tag_assoc.init;
            lv0to3_tags = lv0to3_tags.init;
            tag_in_seg  = tag_in_seg.init;
          }
          if (pith["txt_is"] == eN.txt_is.heading
            && line_occur["heading"] > eN.bi.off
          ) {
            // heading object (current line empty)
            obj_cite_digits = (an_object["lev_markup_number"].to!int == 0)
            ? ocn_emit(eN.ocn.reset)
            : ocn_emit(pith["ocn"]);
            an_object["is"] = "heading";
            an_object_key = "body_nugget";
            ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_object_and_anchor_tags_struct
              = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, ((_new_doc) ? Yes._new_doc : No._new_doc));
            an_object["substantive"] = substantive_object_and_anchor_tags_struct.obj_txt;
            anchor_tag = substantive_object_and_anchor_tags_struct.anchor_tag;
            if (_new_doc) {
              cnt1 = 1;
              cnt2 = 1;
              cnt3 = 1;
              _new_doc = false;
            }
            if (
              an_object["lev_markup_number"].to!int == 4
              && (!(anchor_tag.empty)
              || (lv0to3_tags.length > 0))
            ) {
              tag_in_seg["seg_lv4"]    = anchor_tag;
              tag_in_seg["seg_lv1to4"] = anchor_tag;
              lev_anchor_tag = anchor_tag;
              tag_assoc[anchor_tag]["seg_lv4"]    = tag_in_seg["seg_lv4"];
              tag_assoc[anchor_tag]["seg_lv1to4"] = tag_in_seg["seg_lv1to4"];
              if (lv0to3_tags.length > 0) {
                // names used for html markup segments 1 to 4 (rather than epub which has separate segments for A to D)
                foreach (lv0_to_lv3_html_tag; lv0to3_tags) {
                  tag_assoc[lv0_to_lv3_html_tag]["seg_lv4"] = anchor_tag;
                }
              }
              anchor_tag_ = anchor_tag;
              lv0to3_tags = lv0to3_tags.init;
            } else if (an_object["lev_markup_number"].to!int > 4) {
              tag_in_seg["seg_lv4"]    = anchor_tag_;
              tag_in_seg["seg_lv1to4"] = anchor_tag_;
              lev_anchor_tag           = anchor_tag;
              tag_assoc[anchor_tag]["seg_lv4"] = tag_in_seg["seg_lv4"];
              tag_assoc[anchor_tag]["seg_lv1to4"] = tag_in_seg["seg_lv1to4"];
            } else if (an_object["lev_markup_number"].to!int < 4) {
              string segn;
              switch (an_object["lev_markup_number"].to!int) {
              // names used for epub markup segments A to D
              case 0:
                segn = "_the_title";
                goto default;
              case 1:
                segn = "_part_" ~ cnt1.to!string;
                ++cnt1;
                goto default;
              case 2:
                segn = "_part_" ~ cnt1.to!string ~ "_" ~ cnt2.to!string;
                ++cnt2;
                goto default;
              case 3:
                segn =  "_part_" ~ cnt1.to!string ~ "_" ~ cnt2.to!string ~ "_" ~ cnt3.to!string;
                ++cnt3;
                goto default;
              default:
                lv0to3_tags ~= obj_cite_digits.object_number.to!string;
                lv0to3_tags ~= segn;
                tag_in_seg["seg_lv4"]    = segn; // for html segname need following lv4 not yet known
                tag_in_seg["seg_lv1to4"] = segn;
                break;
              }
            }
            an_object["bookindex_nugget"]
              = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : "";
            bookindex_unordered_hashes
              = bookindex_extract_hash.bookindex_nugget_hash(an_object["bookindex_nugget"], obj_cite_digits, tag_in_seg);
            _anchor_tag                   = obj_cite_digits.identifier;
            // (incrementally build toc) table of contents here!
            {
              auto _get = obj_im.flow_table_of_contents_gather_headings(
                an_object,
                conf_make_meta,
                tag_in_seg,
                _anchor_tag,
                lev4_subtoc,
                the_document_toc_section,
              );
              {
                the_document_toc_section = _get.the_document_toc_section;
                lev4_subtoc              = _get.lev4_subtoc;
              }
            }
            if (an_object["lev_markup_number"] == "4") {
              segnames["html"] ~= tag_in_seg["seg_lv4"];
              html_segnames_ptr = html_segnames_ptr_cntr;
              html_segnames_ptr_cntr++;
            }
            if (an_object["lev_markup_number"].to!int <= 4) {
              segnames["epub"] ~= tag_in_seg["seg_lv1to4"];
            }
            auto comp_obj_ = node_construct.node_emitter_heading(
                an_object,
                tag_in_seg,
                lev_anchor_tag,
                tag_assoc,
                obj_cite_digits,                              // OCNset
                cntr,                                         // int
                heading_ptr,                                  // int
                lv_ancestors_txt,                             // string[]
                html_segnames_ptr,                            // int
                substantive_object_and_anchor_tags_struct,
              );
            ++heading_ptr;
            debug(segments) {
              writeln(an_object["lev_markup_number"]);
              writeln(tag_in_seg["seg_lv4"]);
              writeln(tag_in_seg["seg_lv1to4"]);
            }
            the_document_body_section ~= comp_obj_;
            debug(objectrelated1) { writeln(line); } // check
            {
              auto _get = txt_by_line_common_reset_(line_occur, an_object, pith);
              {
                line_occur = _get.line_occur;
                an_object  = _get.this_object;
                pith       = _get.pith;
              }
            }
            an_object.remove("lev");
            an_object.remove("lev_markup_number");
            processing.remove("verse");
            ++cntr;
          } else if (pith["txt_is"] == eN.txt_is.para
            && line_occur["para"] > eN.bi.off
          ) { // paragraph object (current line empty) - repeated character paragraph separator
            if ((an_object[an_object_key].to!string).matchFirst(rgx.repeated_character_line_separator)) {
              pith["ocn"] = eN.ocn.off;
            }
            obj_cite_digits = ocn_emit(pith["ocn"]);
            an_object["bookindex_nugget"] = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : "";
            bookindex_unordered_hashes = bookindex_extract_hash.bookindex_nugget_hash(an_object["bookindex_nugget"], obj_cite_digits, tag_in_seg);
            an_object["is"] = "para";
            auto comp_obj_ = node_construct.node_location_emitter(
                content_non_header,
                tag_in_seg,
                lev_anchor_tag,
                tag_assoc,
                obj_cite_digits,
                cntr,
                heading_ptr-1,
                an_object["is"],
              );
            ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct
              = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc);
            an_object["substantive"] = substantive_obj_misc_struct.obj_txt;
            anchor_tag = substantive_obj_misc_struct.anchor_tag;
            comp_obj_                                       = set_object_generic("body", "body", "para", "para", an_object["substantive"].to!string.strip, obj_cite_digits.object_number);
            comp_obj_.tags.html_segment_anchor_tag_is       = tag_in_seg["seg_lv4"];
            comp_obj_.tags.epub_segment_anchor_tag_is       = tag_in_seg["seg_lv1to4"];
            comp_obj_.metainfo.identifier                   = obj_cite_digits.identifier;
            comp_obj_.metainfo.object_number_off            = (obj_cite_digits.off == 0)   ? true : false; // TODO
            comp_obj_.metainfo.o_n_book_index               = obj_cite_digits.bkidx;
            comp_obj_.metainfo.object_number_type           = obj_cite_digits.type;
            comp_obj_.attrib.indent_hang                    = indent["hang_position"];
            comp_obj_.attrib.indent_base                    = indent["base_position"];
            comp_obj_.attrib.bullet                         = bullet;
            comp_obj_.tags.anchor_tags                      = [anchor_tag]; anchor_tag="";
            comp_obj_.has.inline_notes_reg                  = substantive_obj_misc_struct.has_notes_reg;
            comp_obj_.has.inline_notes_star                 = substantive_obj_misc_struct.has_notes_star;
            comp_obj_.has.inline_links                      = substantive_obj_misc_struct.has_links;
            comp_obj_.has.image_without_dimensions          = substantive_obj_misc_struct.has_images_without_dimensions;
            the_document_body_section                       ~= comp_obj_;
            tag_assoc                                           = an_object.inline_para_link_anchor(tag_in_seg, tag_assoc);
            {
              auto _get = txt_by_line_common_reset_(line_occur, an_object, pith);
              {
                line_occur = _get.line_occur;
                an_object  = _get.this_object;
                pith       = _get.pith;
              }
            }
            indent = [
              "hang_position" : 0,
              "base_position" : 0,
            ];
            bullet = false;
            processing.remove("verse");
            ++cntr;
          // } else { // could be useful to test line variable should be empty and never null
          }
        } // close else for line empty
      } // close else for not the above
    } // close after non code, other blocks or regular text
    // unless (the_document_body_section.length == 0) ?
    if (the_document_body_section.length > 0) {
      if (((the_document_body_section[$-1].metainfo.is_a == "para")
        || (the_document_body_section[$-1].metainfo.is_a == "heading")
        || (the_document_body_section[$-1].metainfo.is_a == "quote")
        || (the_document_body_section[$-1].metainfo.is_a == "group")
        || (the_document_body_section[$-1].metainfo.is_a == "block")
        || (the_document_body_section[$-1].metainfo.is_a == "verse"))
      && (the_document_body_section.length > previous_length)) {
        if ((the_document_body_section[$-1].metainfo.is_a == "heading")
        && (the_document_body_section[$-1].metainfo.heading_lev_markup < 5)) {
          pith["section"] = eN.sect.unset;
        }
        if (the_document_body_section[$-1].metainfo.is_a == "verse") {
          // scan for endnotes for whole poem (each verse in poem)
          foreach (i; previous_length .. the_document_body_section.length) {
            if (the_document_body_section[i].metainfo.is_a == "verse") {
              if ((the_document_body_section[i].text).match(
                rgx.inline_notes_al_all_note
              )) {
                object_notes = note_section.gather_notes_for_endnote_section(
                  the_document_body_section,
                  tag_in_seg,
                  (i).to!int,
                );
              }
            }
          }
        } else {
          // scan object for endnotes
          previous_length = the_document_body_section.length.to!int;
          if ((the_document_body_section[$-1].text).match(
            rgx.inline_notes_al_all_note
          )) {
            previous_count = (the_document_body_section.length -1).to!int;
            object_notes = note_section.gather_notes_for_endnote_section(
              the_document_body_section,
              tag_in_seg,
              (the_document_body_section.length-1).to!int,
            );
          }
        }
        previous_length = the_document_body_section.length.to!int;
      }
    }
  }
  ret.toc          = the_document_toc_section;
  ret.body         = the_document_body_section;
  ret.glossary     = the_document_glossary_section;
  ret.blurb        = the_document_blurb_section;
  ret.object_notes = object_notes;
  ret.segnames     = segnames;
  return ret;
}
{ // loopMarkupSrcByLine
  auto _doc_by_line = loopMarkupSrcByLine(markup_sourcefile_content, an_object, pith);
  the_document_toc_section      = _doc_by_line.toc;
  the_document_body_section     = _doc_by_line.body;
  the_document_glossary_section = _doc_by_line.glossary;
  the_document_blurb_section    = _doc_by_line.blurb;
  segnames                      = _doc_by_line.segnames;
  object_notes                  = _doc_by_line.object_notes; // endnotes, compare, not sure is used
  destroy(_doc_by_line);
}
#+END_SRC

*** post loop (consider and segment/break up further in code & org)

#+NAME: docAbstractionPostMainLoop
#+HEADER: :noweb yes
#+BEGIN_SRC d
<<docAbstractionRelatedFunctionsBackMatter>>
<<docAbstractionRelatedFunctionsEndnotes>>
<<docAbstractionRelatedFunctionsGlossary>>
<<docAbstractionRelatedFunctionsBibliography>>
<<docAbstractionRelatedFunctionsBookIndex>>
<<docAbstractionRelatedFunctionsBlurb>>
<<docAbstractionRelatedFunctionsTOCgather>>
<<docAbstractionDocHeadAndBody>>
<<docAbstractionAncestors>>
<<docAbstractionSegNames>>
<<docAbstractionSegNamesLinkedAndImages>>
<<docAbstractionEndnotes>>
<<docAbstractionGlossary>>
<<docAbstractionBibliography>>
<<docAbstractionBookIndex>>
<<docAbstractionBlurb>>
<<docAbstractionGetDecendants>>
<<docAbstractionHeadingCloseOpenTags>>
// the_dom_tail_section                      ~= comp_obj_; // remove tail for now, decide on later
<<docAbstractionTheDoc>>
<<docAbstractionDocReInit>>
<<docAbstractionDocHasParts>>
#+END_SRC

*** return structure

#+NAME: docAbstractionReturnsStruct
#+HEADER: :noweb yes
#+BEGIN_SRC d
// the doc to be returned
struct ST_docAbstraction {
  ObjGenericComposite[][string] document_the;
  DocHas_                       doc_has;
}
ST_docAbstraction ret;
{
  ret.document_the = document_the;
  ret.doc_has      = doc_has;
}
return ret;
#+END_SRC

** docAbstraction Functions (post loop)
*** Back Matter (added after end of document loop)
**** Back Matter

#+NAME: docAbstractionRelatedFunctionsBackMatter
#+HEADER: :noweb yes
#+BEGIN_SRC d
{ // EOF  backMatter
  comp_obj_                                              = set_object_heading("lev1", "backmatter", "tail", "");
  comp_obj_.metainfo.identifier                          = "";
  comp_obj_.metainfo.dummy_heading                       = false;
  comp_obj_.metainfo.object_number_off                   = false;
  comp_obj_.metainfo.object_number_type                  = 0;
  comp_obj_.tags.segment_anchor_tag_epub                 = "_part_eof";
  comp_obj_.tags.anchor_tag_html                         = comp_obj_.tags.segment_anchor_tag_epub;
  comp_obj_.tags.in_segment_html                         = "tail";
  comp_obj_.tags.anchor_tags                             = ["section_eof"];
  comp_obj_.metainfo.dom_structure_markedup_tags_status  = [ 0, 0, 0, 0, 0, 0, 0, 0];
  comp_obj_.metainfo.dom_structure_collapsed_tags_status = [ 0, 0, 0, 0, 0, 0, 0, 0];
  the_document_xml_dom_tail_section                              ~= comp_obj_;
  tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"]            = comp_obj_.tags.in_segment_html;
  tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub;
}
#+END_SRC

**** Endnotes function (add gathered endnotes)

#+NAME: docAbstractionRelatedFunctionsEndnotes
#+HEADER: :noweb yes
#+BEGIN_SRC d
// endNotes
ST_endnotes en_st = note_section.backmatter_endnote_objects(obj_cite_digits, opt_action);
{ // endnotes
  the_document_endnotes_section = en_st.endnotes;
  obj_cite_digits = en_st.ocn;
  debug(endnotes) {
    writefln("%s %s", __LINE__, the_document_endnotes_section.length);
    foreach (o; the_document_endnotes_section) { writeln(o); }
  }
}
#+END_SRC

**** Glossary function

#+NAME: docAbstractionRelatedFunctionsGlossary
#+HEADER: :noweb yes
#+BEGIN_SRC d
{ // glossary
  if (an_object["glossary_nugget"].length == 0) {
    comp_obj_                                   = set_object_heading("lev1", "empty", "empty", "(skip) there is no Glossary section");
    comp_obj_.metainfo.identifier               = "";
    comp_obj_.metainfo.dummy_heading            = true;
    comp_obj_.metainfo.object_number_off        = true;
    comp_obj_.metainfo.object_number_type       = 0;
    the_document_glossary_section               ~= comp_obj_;
  }
  debug(glossary) { foreach (gloss; the_document_glossary_section) { writeln(gloss.text); } }
}
#+END_SRC

**** Bibliography function

#+NAME: docAbstractionRelatedFunctionsBibliography
#+HEADER: :noweb yes
#+BEGIN_SRC d
{ // bibliography
  string[] biblio_unsorted_incomplete = biblio_arr_json.dup;
  ST_biblio_section biblio_section    = backmatter_make_the_bibliography_section(biblio_unsorted_incomplete, bib_arr_json);
  the_document_bibliography_section   = biblio_section.bibliography_section;
  tag_assoc                           = biblio_section.tag_assoc;
}
#+END_SRC

**** Book Index function

#+NAME: docAbstractionRelatedFunctionsBookIndex
#+HEADER: :noweb yes
#+BEGIN_SRC d
{ // bookindex
  BookIndexReportSection bi = BookIndexReportSection();
  ST_bookindex bi_st
    = bi.backmatter_bookindex_build_abstraction_section(bookindex_unordered_hashes, obj_cite_digits, opt_action);
  destroy(bookindex_unordered_hashes);
  the_document_bookindex_section = bi_st.bookindex;
  obj_cite_digits = bi_st.ocn;
  debug(bookindex) { foreach (bi_entry; the_document_bookindex_section) { writeln(bi_entry); } }
}
#+END_SRC

**** Blurb function

#+NAME: docAbstractionRelatedFunctionsBlurb
#+HEADER: :noweb yes
#+BEGIN_SRC d
{ // blurb
  if (an_object["blurb_nugget"].length == 0) {
    comp_obj_                                   = set_object_heading("lev1", "empty", "empty", "(skip) there is no Blurb section");
    comp_obj_.metainfo.identifier               = "";
    comp_obj_.metainfo.object_number_off        = true;
    comp_obj_.metainfo.object_number_type       = 0;
    comp_obj_.tags.segment_anchor_tag_epub      = "";
    comp_obj_.tags.anchor_tag_html              = "";
    comp_obj_.tags.in_segment_html              = "";
    the_document_blurb_section                  ~= comp_obj_;
  }
  debug(blurb) { foreach (blurb; the_document_blurb_section) { writeln(blurb.text); } }
}
#+END_SRC

**** TOC gather function

#+NAME: docAbstractionRelatedFunctionsTOCgather
#+HEADER: :noweb yes
#+BEGIN_SRC d
{ // toc gather backmatter
  the_document_toc_section ~= backmatter_gather_table_of_contents(the_document_endnotes_section, the_document_glossary_section, the_document_bibliography_section, the_document_bookindex_section, the_document_blurb_section); //
}
#+END_SRC

*** Doc Head and Body

#+NAME: docAbstractionDocHeadAndBody
#+HEADER: :noweb yes
#+BEGIN_SRC d
{ // document head and body
  the_document_head_section ~= the_document_body_section[0];
  the_document_body_section = the_document_body_section[1..$];
}
#+END_SRC

*** Extract
**** Ancestors

#+NAME: docAbstractionAncestors
#+HEADER: :noweb yes
#+BEGIN_SRC d
{ // document ancestors
  ST_ancestors get_ancestors;
  get_ancestors = the_document_body_section.after_doc_determine_ancestors(the_document_endnotes_section, the_document_glossary_section, the_document_bibliography_section, the_document_bookindex_section, the_document_blurb_section);
  the_document_body_section         = get_ancestors.the_document_body_section;
  the_document_endnotes_section     = get_ancestors.the_document_endnotes_section;
  the_document_glossary_section     = get_ancestors.the_document_glossary_section;
  the_document_bibliography_section = get_ancestors.the_document_bibliography_section;
  the_document_bookindex_section    = get_ancestors.the_document_bookindex_section;
  the_document_blurb_section        = get_ancestors.the_document_blurb_section;
}
#+END_SRC

**** SegNames

#+NAME: docAbstractionSegNames
#+HEADER: :noweb yes
#+BEGIN_SRC d
{ // document segnames
  ST_segnames get_segnames;
  get_segnames = the_document_body_section.after_doc_determine_segnames(the_document_endnotes_section, the_document_glossary_section, the_document_bibliography_section, the_document_bookindex_section, the_document_blurb_section, segnames, html_segnames_ptr_cntr, html_segnames_ptr); //
  segnames                          = get_segnames.segnames;
  html_segnames_ptr_cntr            = get_segnames.html_segnames_ptr_cntr;
  html_segnames_ptr                 = get_segnames.html_segnames_ptr;
}
#+END_SRC

**** SegNames with links & images

#+NAME: docAbstractionSegNamesLinkedAndImages
#+HEADER: :noweb yes
#+BEGIN_SRC d
// document head
string[] segnames_0_to_4;
foreach (ref obj; the_document_head_section) {
  if (obj.metainfo.is_a == "heading") {
    debug(dom) { writeln(obj.text); }
    if (obj.metainfo.heading_lev_markup <= 4) {
      segnames_0_to_4 ~= obj.tags.segment_anchor_tag_epub;
    }
    if (obj.metainfo.heading_lev_markup == 0) {
      // TODO second hit (of two) with same assertion failure, check, fix and reinstate
      // assert( obj.metainfo.ocn == 1,
      //   "Title OCN should be 1 not: " ~ obj.metainfo.ocn.to!string); // bug introduced 0.18.1
      obj.metainfo.ocn = 1;
      obj.metainfo.identifier = "1";
      obj.metainfo.object_number_type = OCNtype.ocn;
    }
    // dom structure (marked up & collapsed)
    if (opt_action.meta_processing_xml_dom) {
      obj = obj.obj_dom_structure_set_markup_tags(dom_structure_markedup_tags_status, obj.metainfo.heading_lev_markup);
      obj = obj.obj_dom_set_collapsed_tags(dom_structure_collapsed_tags_status, obj.metainfo.heading_lev_collapsed);
    }
    obj = obj.obj_heading_ancestors(lv_ancestors_txt);
  }
  obj = _links(obj);
}
if (the_document_toc_section.length > 1) {
  // scroll
  dom_structure_markedup_tags_status_buffer = dom_structure_markedup_tags_status.dup;
  dom_structure_collapsed_tags_status_buffer = dom_structure_collapsed_tags_status.dup;
  foreach (ref obj; the_document_toc_section) {
    if (obj.metainfo.is_a == "heading") {
      if (obj.metainfo.heading_lev_markup <= 4) {
        segnames_0_to_4 ~= obj.tags.segment_anchor_tag_epub;
        if (obj.metainfo.heading_lev_markup == 4) {
          obj.tags.segname_next = segnames["html"][obj.ptr.html_segnames + 1];
          assert(obj.tags.anchor_tag_html == segnames["html"][obj.ptr.html_segnames],
            obj.tags.anchor_tag_html ~ "!=" ~ segnames["html"][obj.ptr.html_segnames]);
        }
      }
      // dom structure (marked up & collapsed)
      if (opt_action.meta_processing_xml_dom) {
        obj = obj.obj_dom_structure_set_markup_tags(dom_structure_markedup_tags_status, obj.metainfo.heading_lev_markup);
        obj = obj.obj_dom_set_collapsed_tags(dom_structure_collapsed_tags_status, obj.metainfo.heading_lev_collapsed);
      }
      obj = obj.obj_heading_ancestors(lv_ancestors_txt);
    }
    obj = _links(obj);
  }
}
// images
string[] _images;
// multiple 1~ levels, loop through document body
if (the_document_body_section.length > 1) {
  foreach (ref obj; the_document_body_section) {
    if (!(obj.metainfo.identifier.empty)) {
      if (!(((obj.metainfo.identifier) in tag_assoc)
        && ("seg_lv4" in tag_assoc[(obj.metainfo.identifier)]))
      ) {
        tag_assoc[(obj.metainfo.identifier)]["seg_lv4"]
        = obj.tags.html_segment_anchor_tag_is;
      }
      tag_assoc[(obj.metainfo.identifier)]["seg_lv1to4"]
      = obj.tags.epub_segment_anchor_tag_is;
    }
    if (obj.metainfo.is_a == "heading") {
      debug(dom) { writeln(obj.text); }
      if (obj.metainfo.heading_lev_markup <= 4) {
        segnames_0_to_4 ~= obj.tags.segment_anchor_tag_epub;
        if (obj.metainfo.heading_lev_markup == 4) {
          obj.tags.lev4_subtoc = lev4_subtoc[obj.tags.anchor_tag_html];
          obj.tags.segname_prev = segnames["html"][obj.ptr.html_segnames - 1];
          if (segnames["html"].length > obj.ptr.html_segnames + 1) {
            obj.tags.segname_next = segnames["html"][obj.ptr.html_segnames + 1];
          }
          assert(obj.tags.anchor_tag_html == segnames["html"][obj.ptr.html_segnames],
            obj.tags.anchor_tag_html ~ "!=" ~ segnames["html"][obj.ptr.html_segnames]);
        }
      }
      // dom structure (marked up & collapsed)
      if (opt_action.meta_processing_xml_dom) {
        obj = obj.obj_dom_structure_set_markup_tags(dom_structure_markedup_tags_status, obj.metainfo.heading_lev_markup);
        obj = obj.obj_dom_set_collapsed_tags(dom_structure_collapsed_tags_status, obj.metainfo.heading_lev_collapsed);
      }
      obj = obj.obj_heading_ancestors(lv_ancestors_txt);
    } else if (obj.metainfo.is_a == "para") {
       _images ~= extract_images(obj.text);
       obj = _image_dimensions(obj, manifested);
    }
    obj = _links(obj);
  }
}
auto image_list = (_images.sort()).uniq;
#+END_SRC

*** Level 1~
**** Endnotes

#+NAME: docAbstractionEndnotes
#+HEADER: :noweb yes
#+BEGIN_SRC d
// endnotes optional only one 1~ level
if (the_document_endnotes_section.length > 1) {
  dom_structure_markedup_tags_status_buffer           = dom_structure_markedup_tags_status.dup;
  dom_structure_collapsed_tags_status_buffer          = dom_structure_collapsed_tags_status.dup;
  dom_structure_markedup_tags_status                  = dom_structure_markedup_tags_status_buffer.dup;
  dom_structure_collapsed_tags_status                 = dom_structure_collapsed_tags_status_buffer.dup;
  foreach (ref obj; the_document_endnotes_section) {
    if (obj.metainfo.is_a == "heading") {
      debug(dom) { writeln(obj.text); }
      if (obj.metainfo.heading_lev_markup == 1) {
        obj_cite_digits                               = ocn_emit(eN.ocn.on);
        obj.metainfo.ocn                              = obj_cite_digits.object_number;
        obj.metainfo.identifier                       = obj_cite_digits.identifier;
      }
      if (obj.metainfo.heading_lev_markup <= 4) {
        segnames_0_to_4 ~= obj.tags.segment_anchor_tag_epub;
        if (obj.metainfo.heading_lev_markup == 4) {
          obj.tags.segname_prev = segnames["html"][obj.ptr.html_segnames - 1];
          if (segnames["html"].length > obj.ptr.html_segnames + 1) {
            obj.tags.segname_next = segnames["html"][obj.ptr.html_segnames + 1];
          }
          assert(obj.tags.anchor_tag_html == segnames["html"][obj.ptr.html_segnames],
            obj.tags.anchor_tag_html ~ "!=" ~ segnames["html"][obj.ptr.html_segnames]);
        }
      }
      // dom structure (marked up & collapsed)
      if (opt_action.meta_processing_xml_dom) {
        obj = obj.obj_dom_structure_set_markup_tags(dom_structure_markedup_tags_status, obj.metainfo.heading_lev_markup);
        obj = obj.obj_dom_set_collapsed_tags(dom_structure_collapsed_tags_status, obj.metainfo.heading_lev_collapsed);
      }
      obj = obj.obj_heading_ancestors(lv_ancestors_txt);
    }
    obj = _links(obj);
  }
}
#+END_SRC

**** Glossary

#+NAME: docAbstractionGlossary
#+HEADER: :noweb yes
#+BEGIN_SRC d
// glossary optional only one 1~ level
if (the_document_glossary_section.length > 1) {
  foreach (ref obj; the_document_glossary_section) {
    if (obj.metainfo.is_a == "heading") {
      debug(dom) { writeln(obj.text); }
      if (obj.metainfo.heading_lev_markup == 1) {
        obj_cite_digits                               = ocn_emit(eN.ocn.on);
        obj.metainfo.ocn                              = obj_cite_digits.object_number;
        obj.metainfo.identifier                       = obj_cite_digits.identifier;
      }
      if (obj.metainfo.heading_lev_markup <= 4) {
        segnames_0_to_4 ~= obj.tags.segment_anchor_tag_epub;
        if (obj.metainfo.heading_lev_markup == 4) {
          obj.tags.segname_prev = segnames["html"][obj.ptr.html_segnames - 1];
          if (segnames["html"].length > obj.ptr.html_segnames + 1) {
            obj.tags.segname_next = segnames["html"][obj.ptr.html_segnames + 1];
          }
          assert(obj.tags.anchor_tag_html == segnames["html"][obj.ptr.html_segnames],
            obj.tags.anchor_tag_html ~ "!=" ~ segnames["html"][obj.ptr.html_segnames]);
        }
      }
      // dom structure (marked up & collapsed)
      if (opt_action.meta_processing_xml_dom) {
        obj = obj.obj_dom_structure_set_markup_tags(dom_structure_markedup_tags_status, obj.metainfo.heading_lev_markup);
        obj = obj.obj_dom_set_collapsed_tags(dom_structure_collapsed_tags_status, obj.metainfo.heading_lev_collapsed);
      }
      obj = obj.obj_heading_ancestors(lv_ancestors_txt);
    } else if (obj.metainfo.is_a == "glossary" && !(obj.text.empty)) {
      obj_cite_digits         = ocn_emit(eN.ocn.on);
      obj.metainfo.ocn        = obj_cite_digits.object_number;
      obj.metainfo.identifier = obj_cite_digits.identifier;
    }
    obj = _links(obj);
  }
}
#+END_SRC

**** Bibliography

#+NAME: docAbstractionBibliography
#+HEADER: :noweb yes
#+BEGIN_SRC d
// bibliography optional only one 1~ level
if (the_document_bibliography_section.length > 1) {
  foreach (ref obj; the_document_bibliography_section) {
    if (obj.metainfo.is_a == "heading") {
      debug(dom) { writeln(obj.text); }
      if (obj.metainfo.heading_lev_markup == 1) {
        obj_cite_digits                               = ocn_emit(eN.ocn.on);
        obj.metainfo.ocn                              = obj_cite_digits.object_number;
        obj.metainfo.identifier                       = obj_cite_digits.identifier;
      }
      if (obj.metainfo.heading_lev_markup <= 4) {
        segnames_0_to_4 ~= obj.tags.segment_anchor_tag_epub;
        if (obj.metainfo.heading_lev_markup == 4) {
          obj.tags.segname_prev = segnames["html"][obj.ptr.html_segnames - 1];
          if (segnames["html"].length > obj.ptr.html_segnames + 1) {
            obj.tags.segname_next = segnames["html"][obj.ptr.html_segnames + 1];
          }
          assert(obj.tags.anchor_tag_html == segnames["html"][obj.ptr.html_segnames],
            obj.tags.anchor_tag_html ~ "!=" ~ segnames["html"][obj.ptr.html_segnames]);
        }
      }
      // dom structure (marked up & collapsed)
      if (opt_action.meta_processing_xml_dom) {
        obj = obj.obj_dom_structure_set_markup_tags(dom_structure_markedup_tags_status, obj.metainfo.heading_lev_markup);
        obj = obj.obj_dom_set_collapsed_tags(dom_structure_collapsed_tags_status, obj.metainfo.heading_lev_collapsed);
      }
      obj = obj.obj_heading_ancestors(lv_ancestors_txt);
    } else if (obj.metainfo.is_a == "bibliography") {
      obj_cite_digits                                 = ocn_emit(eN.ocn.on);
      obj.metainfo.ocn                                = obj_cite_digits.object_number;
      obj.metainfo.identifier                         = obj_cite_digits.identifier;
    }
    obj = _links(obj);
  }
}
#+END_SRC

**** Book Index

#+NAME: docAbstractionBookIndex
#+HEADER: :noweb yes
#+BEGIN_SRC d
// book index, optional only one 1~ level
int ocn_       = obj_cite_digits.object_number;
int ocn_bkidx_ = 0;
int ocn_bidx_;
if (the_document_bookindex_section.length > 1) {                                        // scroll
  dom_structure_markedup_tags_status_buffer = dom_structure_markedup_tags_status.dup;
  dom_structure_collapsed_tags_status_buffer = dom_structure_collapsed_tags_status.dup;
  foreach (ref obj; the_document_bookindex_section) {
    if (obj.metainfo.is_a == "heading") {
      // debug(dom) { }
      if (obj.metainfo.heading_lev_markup <= 4) {
        segnames_0_to_4 ~= obj.tags.segment_anchor_tag_epub;
      }
      if (obj.metainfo.heading_lev_markup == 1) {
        obj_cite_digits                               = ocn_emit(eN.ocn.on);
        obj.metainfo.ocn                              = obj_cite_digits.object_number;
        obj.metainfo.identifier                       = obj_cite_digits.identifier;
      }
      if (obj.metainfo.heading_lev_markup <= 4) {
        if (obj.metainfo.heading_lev_markup == 4) {
          obj.tags.segname_prev = segnames["html"][obj.ptr.html_segnames - 1];
          if (segnames["html"].length > obj.ptr.html_segnames + 1) {
            obj.tags.segname_next = segnames["html"][obj.ptr.html_segnames + 1];
          }
          assert(obj.tags.anchor_tag_html == segnames["html"][obj.ptr.html_segnames],
            obj.tags.anchor_tag_html ~ "!=" ~ segnames["html"][obj.ptr.html_segnames]);
        }
      }
      // dom structure (marked up & collapsed)
      if (opt_action.meta_processing_xml_dom) {
        obj = obj.obj_dom_structure_set_markup_tags(dom_structure_markedup_tags_status, obj.metainfo.heading_lev_markup);
        obj = obj.obj_dom_set_collapsed_tags(dom_structure_collapsed_tags_status, obj.metainfo.heading_lev_collapsed);
      }
      obj = obj.obj_heading_ancestors(lv_ancestors_txt);
    } else if (obj.metainfo.is_a == "bookindex") {
      obj_cite_digits                                 = ocn_emit(eN.ocn.bkidx);
      obj.metainfo.ocn                                = obj_cite_digits.object_number;
      obj.metainfo.identifier                         = obj_cite_digits.identifier;
      obj.metainfo.o_n_book_index                     = obj_cite_digits.bkidx;
      obj.metainfo.object_number_type                 = OCNtype.bkidx;
    }
    obj = _links(obj);
  }
  // TODO assert failure, reinstate
  // assert(obj_cite_digit_bkidx == ocn_bidx_ obj_cite_digit_bkidx ~ " == ocn_" ~ ocn_ ~ "?");
}
#+END_SRC

**** Blurb

#+NAME: docAbstractionBlurb
#+HEADER: :noweb yes
#+BEGIN_SRC d
// blurb optional only one 1~ level
if (the_document_blurb_section.length > 1) {
  foreach (ref obj; the_document_blurb_section) {
    if (obj.metainfo.is_a == "heading") {
      debug(dom) { writeln(obj.text); }
      if (obj.metainfo.heading_lev_markup == 1) {
        obj_cite_digits                               = ocn_emit(eN.ocn.on);
        obj.metainfo.ocn                              = obj_cite_digits.object_number;
        obj.metainfo.identifier                       = obj_cite_digits.identifier;
      }
      if (obj.metainfo.heading_lev_markup <= 4) {
        segnames_0_to_4 ~= obj.tags.segment_anchor_tag_epub;
        if (obj.metainfo.heading_lev_markup == 4) {
          obj.tags.segname_prev = segnames["html"][obj.ptr.html_segnames - 1];
          if (segnames["html"].length > obj.ptr.html_segnames + 1) {
            obj.tags.segname_next = segnames["html"][obj.ptr.html_segnames + 1];
          }
          assert(obj.tags.anchor_tag_html == segnames["html"][obj.ptr.html_segnames],
            obj.tags.anchor_tag_html ~ "!=" ~ segnames["html"][obj.ptr.html_segnames]);
        }
      }
      // dom structure (marked up & collapsed)
      if (opt_action.meta_processing_xml_dom) {
        obj = obj.obj_dom_structure_set_markup_tags(dom_structure_markedup_tags_status, obj.metainfo.heading_lev_markup);
        obj = obj.obj_dom_set_collapsed_tags(dom_structure_collapsed_tags_status, obj.metainfo.heading_lev_collapsed);
      }
      obj = obj.obj_heading_ancestors(lv_ancestors_txt);
    } else if (obj.metainfo.is_a == "blurb") {
      obj_cite_digits                                 = ocn_emit(eN.ocn.off);
      obj.metainfo.object_number_off                  = obj_cite_digits.off;
      obj.metainfo.object_number_type                 = OCNtype.non;
    }
    obj = _links(obj);
  }
}
#+END_SRC

*** Get Decendants

#+NAME: docAbstractionGetDecendants
#+HEADER: :noweb yes
#+BEGIN_SRC d
// get decendants
if (the_document_body_section.length > 1) {
  auto pairs = after_doc_get_decendants(
    the_document_head_section ~
    the_document_body_section ~
    the_document_endnotes_section ~
    the_document_glossary_section ~
    the_document_bibliography_section ~
    the_document_bookindex_section ~
    the_document_blurb_section ~
    the_document_xml_dom_tail_section
  );
  debug(decendants_tuple) {
    pairs = pairs.sort();
    foreach (pair; pairs) { // (pair; pairs.sort())
      writeln(pair[0], "..", pair[1]);
    }
  }
  foreach (ref obj; the_document_head_section) {
    if (obj.metainfo.is_a == "heading") {
      foreach (pair; pairs) {
        if (obj.metainfo.ocn == pair[0]) {
          obj.metainfo.last_decendant_ocn = pair[1];
        }
      }
    }
  }
  if (the_document_body_section.length > 1) {
    foreach (ref obj; the_document_body_section) {
      if (obj.metainfo.is_a == "heading") {
        foreach (pair; pairs) {
          if (obj.metainfo.ocn == pair[0]) {
            obj.metainfo.last_decendant_ocn = pair[1];
          }
        }
      }
    }
  }
  if (the_document_endnotes_section.length > 1) {
    foreach (ref obj; the_document_endnotes_section) {
      if (obj.metainfo.is_a == "heading") {
        foreach (pair; pairs) {
          if (obj.metainfo.ocn == pair[0]) {
            obj.metainfo.last_decendant_ocn = pair[1];
          }
        }
      }
    }
  }
  if (the_document_glossary_section.length > 1) {
    foreach (ref obj; the_document_glossary_section) {
      if (obj.metainfo.is_a == "heading") {
        foreach (pair; pairs) {
          if (obj.metainfo.ocn == pair[0]) {
            obj.metainfo.last_decendant_ocn = pair[1];
          }
        }
      }
    }
  }
  if (the_document_bibliography_section.length > 1) {
    foreach (ref obj; the_document_bibliography_section) {
      if (obj.metainfo.is_a == "heading") {
        foreach (pair; pairs) {
          if (obj.metainfo.ocn == pair[0]) {
            obj.metainfo.last_decendant_ocn = pair[1];
          }
        }
      }
    }
  }
  if (the_document_bookindex_section.length > 1) {
    foreach (ref obj; the_document_bookindex_section) {
      if (obj.metainfo.is_a == "heading") {
        foreach (pair; pairs) {
          if (obj.metainfo.ocn == pair[0]) {
            obj.metainfo.last_decendant_ocn = pair[1];
          }
        }
      }
    }
  }
  if (the_document_blurb_section.length > 1) {
    foreach (ref obj; the_document_blurb_section) {
      if (obj.metainfo.is_a == "heading") {
        foreach (pair; pairs) {
          if (obj.metainfo.ocn == pair[0]) {
            obj.metainfo.last_decendant_ocn = pair[1];
          }
        }
      }
    }
  }
  if (the_document_xml_dom_tail_section.length > 1) {
    foreach (ref obj; the_document_xml_dom_tail_section) {
      if (obj.metainfo.is_a == "heading") {
        foreach (pair; pairs) {
          if (obj.metainfo.ocn == pair[0]) {
            obj.metainfo.last_decendant_ocn = pair[1];
          }
        }
      }
    }
  }
}
#+END_SRC

*** Heading Closes All Open Tags

#+NAME: docAbstractionHeadingCloseOpenTags
#+HEADER: :noweb yes
#+BEGIN_SRC d
// TODO
//  - note create/insert heading object sole purpose eof close all open tags
//    sort out:
//    - obj.metainfo.dom_structure_markedup_tags_status = dom_structure_markedup_tags_status;
//    - obj.metainfo.dom_structure_collapsed_tags_status = dom_structure_collapsed_tags_status;
comp_obj_                                               = set_object_heading("lev1", "empty", "empty", "");
comp_obj_.metainfo.identifier                           = "";
comp_obj_.metainfo.dummy_heading                        = true;
comp_obj_.metainfo.object_number_off                    = true;
comp_obj_.metainfo.object_number_type                   = 0;
comp_obj_.tags.segment_anchor_tag_epub                  = "";
comp_obj_.tags.anchor_tag_html                          = "";
comp_obj_.tags.in_segment_html                          = "";
comp_obj_.tags.html_segment_anchor_tag_is               = "";
comp_obj_.tags.epub_segment_anchor_tag_is               = "";
comp_obj_.metainfo.heading_lev_markup                   = 9;
comp_obj_.metainfo.heading_lev_collapsed                = 9;
comp_obj_.metainfo.parent_ocn                           = 0;
comp_obj_.metainfo.parent_lev_markup                    = 0;
comp_obj_.metainfo.dom_structure_markedup_tags_status   = dom_structure_markedup_tags_status.dup;
comp_obj_.metainfo.dom_structure_collapsed_tags_status  = dom_structure_collapsed_tags_status.dup;
comp_obj_ = comp_obj_.obj_dom_structure_set_markup_tags(dom_structure_markedup_tags_status, 0);
comp_obj_ = comp_obj_.obj_dom_set_collapsed_tags(dom_structure_collapsed_tags_status, 0);
comp_obj_ = comp_obj_.obj_heading_ancestors(lv_ancestors_txt);
#+END_SRC

*** The Doc

#+NAME: docAbstractionTheDoc
#+HEADER: :noweb yes
#+BEGIN_SRC d
// the doc
ObjGenericComposite[][string] document_the = [
  "head":             the_document_head_section,
  "toc":              the_document_toc_section,
  // substantive/body:
  "body":             the_document_body_section,
  // backmatter:
  "endnotes":         the_document_endnotes_section,
  "glossary":         the_document_glossary_section,
  "bibliography":     the_document_bibliography_section,
  "bookindex":        the_document_bookindex_section,
  "blurb":            the_document_blurb_section,
  // dom tail only
  "tail":             the_document_xml_dom_tail_section,
];
// document parts keys as needed
string[][string] document_section_keys_sequenced = [
  "scroll": ["head", "toc", "body",],
  "seg":    ["head", "toc", "body",],
  "sql":    ["head", "body",],
  "latex":  ["head", "toc", "body",]
];
if (document_the["endnotes"].length > 1) {
  document_section_keys_sequenced["scroll"] ~= "endnotes";
  document_section_keys_sequenced["seg"]    ~= "endnotes";
  document_section_keys_sequenced["latex"]  ~= "endnotes";
}
if (document_the["glossary"].length > 1) {
  document_section_keys_sequenced["scroll"] ~= "glossary";
  document_section_keys_sequenced["seg"]    ~= "glossary";
  document_section_keys_sequenced["sql"]    ~= "glossary";
  document_section_keys_sequenced["latex"]  ~= "glossary";
}
if (document_the["bibliography"].length > 1) {
  document_section_keys_sequenced["scroll"] ~= "bibliography";
  document_section_keys_sequenced["seg"]    ~= "bibliography";
  document_section_keys_sequenced["sql"]    ~= "bibliography";
  document_section_keys_sequenced["latex"]  ~= "bibliography";
}
if (document_the["bookindex"].length > 1) {
  document_section_keys_sequenced["scroll"] ~= "bookindex";
  document_section_keys_sequenced["seg"]    ~= "bookindex";
  document_section_keys_sequenced["sql"]    ~= "bookindex";
  document_section_keys_sequenced["latex"]  ~= "bookindex";
}
if (document_the["blurb"].length > 1) {
  document_section_keys_sequenced["scroll"] ~= "blurb";
  document_section_keys_sequenced["seg"]    ~= "blurb";
  document_section_keys_sequenced["sql"]    ~= "blurb";
  document_section_keys_sequenced["latex"]  ~= "blurb";
}
if ((opt_action.html)
|| (opt_action.html_scroll)
|| (opt_action.html_seg)
|| (opt_action.epub)) {
  document_section_keys_sequenced["scroll"] ~= "tail";
  document_section_keys_sequenced["seg"]    ~= "tail";
}
// segnames
string[] segnames_4                 = segnames["html"].dup;
string[] segnames_lv1to4            = segnames["epub"].dup;
debug(segnames) {
  writeln("segnames_lv4:    ", segnames_4);
  writeln("segnames_lv1to4: ", segnames_lv1to4);
}
#+END_SRC

*** Doc Re Init

#+NAME: docAbstractionDocReInit
#+HEADER: :noweb yes
#+BEGIN_SRC d
// restart
destroy(the_document_head_section);
destroy(the_document_toc_section);
destroy(the_document_body_section);
destroy(the_document_endnotes_section);
destroy(the_document_glossary_section);
destroy(the_document_bibliography_section);
destroy(the_document_bookindex_section);
destroy(the_document_blurb_section);
destroy(the_document_xml_dom_tail_section);
destroy(segnames);
destroy(bookindex_unordered_hashes);
destroy(an_object);
obj_cite_digits                             = ocn_emit(eN.ocn.reset);
biblio_arr_json                             = [];
obj_cite_digit_                             = 0;
html_segnames_ptr                           = 0;
html_segnames_ptr_cntr                      = 0;
content_non_header                          = "8";
dom_structure_markedup_tags_status          = [ 0, 0, 0, 0, 0, 0, 0, 0,];
dom_structure_markedup_tags_status_buffer   = [ 0, 0, 0, 0, 0, 0, 0, 0,];
dom_structure_collapsed_tags_status         = [ 0, 0, 0, 0, 0, 0, 0, 0,];
dom_structure_collapsed_tags_status_buffer  = [ 0, 0, 0, 0, 0, 0, 0, 0,];
lev_anchor_tag = "";
anchor_tag = "";
#+END_SRC

*** Doc Has (identify parts)

#+NAME: docAbstractionDocHasParts
#+HEADER: :noweb yes
#+BEGIN_SRC d
// identify parts
struct DocHas_ {
  uint inline_links() {
    return dochas["inline_links"];
  }
  uint inline_notes_reg() {
    return dochas["inline_notes"];
  }
  uint inline_notes_star() {
    return dochas["inline_notes_star"];
  }
  uint codeblocks() {
    return dochas["codeblock"];
  }
  uint tables() {
    return dochas["table"];
  }
  uint blocks() {
    return dochas["block"];
  }
  uint groups() {
    return dochas["group"];
  }
  uint poems() {
    return dochas["poem"];
  }
  uint quotes() {
    return dochas["quote"];
  }
  ulong images() { // TODO not ideal rethink
    return (image_list.to!string.strip("[","]").split(",").length);
  }
  auto imagelist() {
    return image_list;
  }
  auto keys_seq() {
    return docSectKeysSeq!()(document_section_keys_sequenced);
  }
  string[] segnames_lv4() {
    return segnames_4;
  }
  string[] segnames_lv_0_to_4() {
    return segnames_0_to_4;
  }
  string[string][string] tag_associations() {
    return tag_assoc;
  }
}
@safe auto doc_has() {
  return DocHas_();
}
#+END_SRC

** docAbstraction related Functions
*** docAbstraction related Functions

#+NAME: docAbstractionRelatedFunctions
#+HEADER: :noweb yes
#+BEGIN_SRC d
@safe pure ObjGenericComposite obj_heading_ancestors()(
  ObjGenericComposite  obj,
  string[]             lv_ancestors_txt,
) {
  switch (obj.metainfo.heading_lev_markup) {
  case 0:
    lv_ancestors_txt[0] = obj.text.to!string;
    foreach(k; 1..8) { lv_ancestors_txt[k] = ""; }
    goto default;
  case 1:
    lv_ancestors_txt[1] = obj.text.to!string;
    foreach(k; 2..8) { lv_ancestors_txt[k] = ""; }
    goto default;
  case 2:
    lv_ancestors_txt[2] = obj.text.to!string;
    foreach(k; 3..8) { lv_ancestors_txt[k] = ""; }
    goto default;
  case 3:
    lv_ancestors_txt[3] = obj.text.to!string;
    foreach(k; 4..8) { lv_ancestors_txt[k] = ""; }
    goto default;
  case 4:
    lv_ancestors_txt[4] = obj.text.to!string;
    foreach(k; 5..8) { lv_ancestors_txt[k] = ""; }
    goto default;
  case 5:
    lv_ancestors_txt[5] = obj.text.to!string;
    foreach(k; 6..8) { lv_ancestors_txt[k] = ""; }
    goto default;
  case 6:
    lv_ancestors_txt[6] = obj.text.to!string;
    lv_ancestors_txt[7] = "";
    goto default;
  case 7:
    lv_ancestors_txt[7] = obj.text.to!string;
    goto default;
  default:
    obj.tags.heading_ancestors_text = lv_ancestors_txt.dup;
  }
  return obj;
}
@safe pure ObjGenericComposite obj_dom_structure_set_markup_tags()(
  ObjGenericComposite  obj,
  int[]                dom,
  int                  lev
) {
  foreach (i; 0 .. 8) {
    if (i < lev) {
      if (dom[i] == DomTags.open
         || dom[i] == DomTags.close_and_open
      ) {
        dom[i] = DomTags.open_still;
      } else if (dom[i] == DomTags.close) {
        dom[i] = DomTags.none;
      }
    } else if (i == lev) {
      if (lev  == 0
        && dom[i] == DomTags.open_still
      ) {
        dom[i] = DomTags.close;
      } else if (dom[i] == DomTags.open
        || dom[i] == DomTags.open_still
        || dom[i] == DomTags.close_and_open
      ) {
        dom[i] = DomTags.close_and_open;
      } else {
        dom[i] = DomTags.open;
      }
    } else if (i > lev) {
      if (dom[i] == DomTags.close) {
        dom[i] = DomTags.none;
      } else if (dom[i] == DomTags.open
        || dom[i] == DomTags.open_still
        || dom[i] == DomTags.close_and_open
      ) {
        dom[i] = DomTags.close;
      }
    }
  }
  debug(dom_magic_numbers) { writeln("marked up: ", lev, ": ", dom); }
  obj.metainfo.dom_structure_markedup_tags_status = dom.dup;
  return obj;
}
@safe pure ObjGenericComposite obj_dom_set_collapsed_tags()(
  ObjGenericComposite  obj,
  int[]                dom,
  int                  lev
) {
  foreach (i; 0 .. 8) {
    if (i < lev) {
      if (dom[i] == DomTags.open
         || dom[i] == DomTags.close_and_open
      ) {
        dom[i] = DomTags.open_still;
      } else if (dom[i] == DomTags.close) {
        dom[i] = DomTags.none;
      }
    } else if (i == lev) {
      if (lev  == 0
        && dom[i] == DomTags.open_still
      ) {
        dom[i] = DomTags.close;
      } else if (dom[i] == DomTags.open
        || dom[i] == DomTags.open_still
        || dom[i] == DomTags.close_and_open
      ) {
        dom[i] = DomTags.close_and_open;
      } else {
        dom[i] = DomTags.open;
      }
    } else if (i > lev) {
      if (dom[i] == DomTags.close) {
        dom[i] = DomTags.none;
      } else if (dom[i] == DomTags.open
        || dom[i] == DomTags.open_still
        || dom[i] == DomTags.close_and_open
      ) {
        dom[i] = DomTags.close;
      }
    }
  }
  debug(dom_magic_numbers) { writeln("collapsed: ", lev, ": ", dom); }
  obj.metainfo.dom_structure_collapsed_tags_status = dom.dup;
  return obj;
}
@safe static  OCNset ocn_emit(int ocn_status_flag) {
  return object_citation_number.ocn_emitter(ocn_status_flag);
}
@safe auto inline_markup_faces(L)(L line) {
  static auto rgx = RgxI();
  static auto mkup = InlineMarkup();
  line = replaceAll!(m => mkup.quote_o ~ m[1] ~ mkup.quote_c)(line, rgx.within_quotes);
  line = replaceAll!(m => mkup.ff_i ~ mkup.mono ~ mkup.ff_o ~ m["text"] ~ mkup.ff_c ~ mkup.mono)(line, rgx.inline_mark_mono);
  line = replaceAll!(m => mkup.ff_i ~ mkup.cite ~ mkup.ff_o ~ m["text"] ~ mkup.ff_c ~ mkup.cite)(line, rgx.inline_mark_cite);
  foreach (regx; [rgx.inline_mark_emphasis, rgx.inline_mark_bold, rgx.inline_mark_underscore, rgx.inline_mark_italics, rgx.inline_mark_superscript, rgx.inline_mark_subscript, rgx.inline_mark_strike, rgx.inline_mark_insert]) {
    line = replaceAll!(m => mkup.ff_i ~ m["mark"] ~ mkup.ff_o ~ m["text"] ~ mkup.ff_c ~ m["mark"])(line, regx);
  }
  return line;
}
@safe static string links_and_images()(string obj_txt) {
  static auto rgx = RgxI();
  static auto mkup = InlineMarkup();
  if (obj_txt.match(rgx.smid_inline_url_generic)) {
    if (
      obj_txt.match(rgx.smid_inline_link_endnote_url_helper)
      || obj_txt.match(rgx.smid_inline_link_endnote_url_helper_punctuated)
    ) {
      obj_txt = replaceAll!(m => format("%s%s%s%s%s%s%s %s%s%s%s%s%s %s%s",
        mkup.lnk_o, m["content"].strip, mkup.lnk_c,
        mkup.url_o, m["link"], mkup.url_c,
        mkup.en_a_o,
        mkup.lnk_o, m["link"].strip, mkup.lnk_c,
        mkup.url_o, m["link"], mkup.url_c,
        mkup.en_a_c,
        m[3]
      ))(obj_txt, rgx.smid_inline_link_endnote_url_helper_punctuated);
      obj_txt = replaceAll!(m => format("%s%s%s%s%s%s%s %s%s%s%s%s%s %s",
        mkup.lnk_o, m["content"].strip, mkup.lnk_c,
        mkup.url_o, m["link"], mkup.url_c,
        mkup.en_a_o,
        mkup.lnk_o, m["link"].strip, mkup.lnk_c,
        mkup.url_o, m["link"], mkup.url_c,
        mkup.en_a_c
      ))(obj_txt, rgx.smid_inline_link_endnote_url_helper);
  } else {
      obj_txt = replaceAll!(m => format("%s%s%s%s%s%s%s",
        m["pre"],
        mkup.lnk_o, m["content"].strip, mkup.lnk_c,
        mkup.url_o, m["link"], mkup.url_c
      ))(obj_txt, rgx.smid_inline_link_markup_regular);
    }
      obj_txt = replaceAll!(m => format("%s%s%s%s%s%s%s",
        m["pre"],
        mkup.lnk_o, m["link"].strip, mkup.lnk_c,
        mkup.url_o, m["link"], mkup.url_c
      ))(obj_txt, rgx.smid_inline_link_naked_url); //
  }
  return obj_txt;
}
// ↓ abstraction struct init
@safe static auto eN() {
  struct _e {
    enum bi {
      off,
      on,
    }
    enum ocn {
      off,
      on,
      closing,
      bkidx,
      reset,
    }
    enum sect {
      unset,
      head,
      toc,
      substantive,
      bibliography,
      glossary,
      book_index,
      blurb,
    }
    enum txt_is {
      off,
      para,
      heading,
    }
    enum blk_is {
      off,
      code,
      poem,
      block,
      group,
      table,
      quote,
    }
    enum blk_state {
      off,
      on,
      closing,
    }
    enum blk_delim {
      off,
      curly,
      tic,
      curly_special,
      tic_special,
    }
  }
  return _e();
}
@safe string[string][string] inline_para_link_anchor()(
  string[string]          an_object,
  string[string]          tag_in_seg,
  string[string][string]  tag_assoc
) {
  static auto rgx = RgxI();
  if (auto m = an_object["substantive"].match(rgx.inline_link_anchor)) {
    if (m.captures[1] !in tag_assoc) {
      tag_assoc[(m.captures[1])]["seg_lv4"]    = tag_in_seg["seg_lv4"];
      tag_assoc[(m.captures[1])]["seg_lv1to4"] = tag_in_seg["seg_lv1to4"];
    } else {
      writeln("a tag named  already exists, check text line\n    ", an_object["substantive"]);
    }
  }
  return tag_assoc;
}
@system ST_txt_by_line_common_reset txt_by_line_common_reset_()(
  int[string]     line_occur,
  string[string]  an_object,
  uint[string]    pith,
) {
  line_occur["heading"]                               = eN.bi.off;
  line_occur["para"]                                  = eN.bi.off;
  pith["txt_is"]                                      = eN.txt_is.off;
  an_object                                           = an_object.object_reset;
  ST_txt_by_line_common_reset ret;
  {
    ret.line_occur  = line_occur;
    ret.this_object = an_object;
    ret.pith        = pith;
  }
  return ret;
}
ST_the_section build_the_glossary_section(
  char[]                 line,             // line is immutable, not necessary to return unchanged
  uint[string]           pith,
  string[string][string] tag_assoc,        // only for headings: html & epub
) {
  static auto rgx = RgxI();
  ObjGenericComposite comp_obj_;
  ObjGenericComposite[] add_to_current_document_section;
  indent = [
    "hang_position" : 0,
    "base_position" : 0,
  ];
  bullet = false;
  pith["txt_is"]           = eN.txt_is.para;
  line_occur["para"]       = eN.bi.off;
  an_object_key            = "glossary_nugget";
  ST_the_section ret;
  if (line.matchFirst(rgx.heading_glossary)) {
    {
      comp_obj_                                = set_object_heading("lev1", "backmatter", "glossary", "Glossary");
      comp_obj_.metainfo.identifier            = "";
      comp_obj_.metainfo.dummy_heading         = false;
      comp_obj_.metainfo.object_number_off     = false;
      comp_obj_.metainfo.object_number_type    = 0;
      comp_obj_.tags.segment_anchor_tag_epub   = "_part_glossary";
      comp_obj_.tags.anchor_tag_html           = comp_obj_.tags.segment_anchor_tag_epub;
      comp_obj_.tags.in_segment_html           = "glossary";
      comp_obj_.tags.anchor_tags               = ["section_glossary"];
      comp_obj_.metainfo.dom_structure_markedup_tags_status  = [ 1, 1, 0, 0, 0, 0, 0, 0];
      comp_obj_.metainfo.dom_structure_collapsed_tags_status = [ 1, 1, 0, 0, 0, 0, 0, 0];
      add_to_current_document_section           ~= comp_obj_; //
      tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"]            = comp_obj_.tags.in_segment_html;
      tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub;
    } {
      comp_obj_                                = set_object_heading("lev4", "backmatter", "glossary", "Glossary");
      comp_obj_.metainfo.identifier            = "";
      comp_obj_.metainfo.dummy_heading         = true;
      comp_obj_.metainfo.object_number_off     = true;
      comp_obj_.metainfo.object_number_type    = 0;
      comp_obj_.tags.segment_anchor_tag_epub   = "glossary";
      comp_obj_.tags.anchor_tag_html           = comp_obj_.tags.segment_anchor_tag_epub;
      comp_obj_.tags.in_segment_html           = comp_obj_.tags.anchor_tag_html;
      comp_obj_.metainfo.heading_lev_collapsed = 2;
      comp_obj_.tags.anchor_tags               = ["glossary"];
      add_to_current_document_section          ~= comp_obj_; //
      tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"]            = comp_obj_.tags.in_segment_html;
      tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub;
      pith["ocn"] = eN.ocn.on;
    }
    {
      ret.comp_section_obj         ~= add_to_current_document_section;
      ret.pith                     = pith;
      ret.tag_assoc                = tag_assoc; // only for headings: html & epub
    }
  } else { // para
    {
      auto _get = line.flow_para_match_(an_object, an_object_key, indent, bullet, pith, line_occur);
      {
        an_object     = _get.this_object;
        an_object_key = _get.this_object_key;
        pith          = _get.pith;
        indent        = _get.indent;
        bullet        = _get.bullet;
        line_occur    = _get.line_occur;
      }
    }
    comp_obj_                               = set_object_generic("backmatter", "glossary", "para", "glossary", links_and_images(line.to!string.strip).replaceFirst(rgx.para_attribs, ""), 0);
    comp_obj_.metainfo.identifier           = "";
    comp_obj_.metainfo.object_number_off    = true;
    comp_obj_.metainfo.object_number_type   = 0;
    comp_obj_.attrib.indent_hang            = indent["hang_position"];
    comp_obj_.attrib.indent_base            = indent["base_position"];
    comp_obj_.attrib.bullet                 = bullet;
    add_to_current_document_section         ~= comp_obj_; //
    pith["ocn"]                             = eN.ocn.on;
    {
      ret.comp_section_obj = add_to_current_document_section;
      ret.pith             = pith;
      ret.tag_assoc        = tag_assoc; // NO CHANGE here, only for headings: html & epub
    }
  }
  return ret;
}
ST_the_section build_the_blurb_section(Opt) (
  char[]                 line,             // line is immutable, not necessary to return unchanged
  uint[string]           pith,
  string[string][string] tag_assoc,        // only for headings: html & epub
  Opt                    opt_action,
) {
  static auto rgx = RgxI();
  ObjGenericComposite comp_obj_;
  ObjGenericComposite[] add_to_current_document_section;
  // assert (opt_action.backmatter && opt_action.section_blurb);
  indent = [
    "hang_position" : 0,
    "base_position" : 0,
  ];
  bullet = false;
  if (auto m = line.matchFirst(rgx.para_indent)) {
    debug(paraindent) { writeln(line); }
    indent["hang_position"] = (m["indent"]).to!int;
    indent["base_position"] = (m["indent"]).to!int;
  } else if (line.matchFirst(rgx.para_bullet)) {
    debug(parabullet) { writeln(line); }
    bullet = true;
  } else if (auto m = line.matchFirst(rgx.para_indent_hang)) {
    debug(paraindenthang) { writeln(line); }
    indent = [
      "hang_position" : (m["hang"]).to!int,
      "base_position" : (m["indent"]).to!int,
    ];
  } else if (auto m = line.matchFirst(rgx.para_bullet_indent)) {
    debug(parabulletindent) { writeln(line); }
    indent = [
      "hang_position" : (m["indent"]).to!int,
      "base_position" : (m["indent"]).to!int,
    ];
    bullet = true;
  }
  pith["txt_is"]           = eN.txt_is.para;
  line_occur["para"]       = eN.bi.off;
  an_object_key = "blurb_nugget";
  ST_the_section ret;
  if (line.matchFirst(rgx.heading_blurb)
  && (opt_action.backmatter && opt_action.section_blurb)) {
    {
      comp_obj_                                              = set_object_heading("lev1", "backmatter", "blurb", "Blurb");
      comp_obj_.metainfo.identifier                          = "";
      comp_obj_.metainfo.dummy_heading                       = false;
      comp_obj_.metainfo.object_number_off                   = false;
      comp_obj_.metainfo.object_number_type                  = 0;
      comp_obj_.tags.segment_anchor_tag_epub                 = "_part_blurb";
      comp_obj_.tags.anchor_tag_html                         = comp_obj_.tags.segment_anchor_tag_epub;
      comp_obj_.tags.in_segment_html                         = "blurb";
      comp_obj_.tags.anchor_tags                             = ["section_blurb"];
      comp_obj_.metainfo.dom_structure_markedup_tags_status  = [ 1, 1, 0, 0, 0, 0, 0, 0];
      comp_obj_.metainfo.dom_structure_collapsed_tags_status = [ 1, 1, 0, 0, 0, 0, 0, 0];
      add_to_current_document_section                                 ~= comp_obj_;
      tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"]            = comp_obj_.tags.in_segment_html;
      tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub;
    }
    {
      comp_obj_                                              = set_object_heading("lev4", "backmatter", "blurb", "Blurb");
      comp_obj_.metainfo.identifier                          = "";
      comp_obj_.metainfo.dummy_heading                       = true;
      comp_obj_.metainfo.object_number_off                   = true;
      comp_obj_.metainfo.object_number_type                  = 0;
      comp_obj_.tags.segment_anchor_tag_epub                 = "blurb";
      comp_obj_.tags.anchor_tag_html                         = comp_obj_.tags.segment_anchor_tag_epub;
      comp_obj_.tags.in_segment_html                         = comp_obj_.tags.anchor_tag_html;
      comp_obj_.metainfo.heading_lev_collapsed               = 2;
      comp_obj_.tags.anchor_tags                             = ["blurb"];
      add_to_current_document_section                                 ~= comp_obj_;
      tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"]            = comp_obj_.tags.in_segment_html;
      tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub;
    }
  } else if (line.matchFirst(rgx.headings)
  && (opt_action.backmatter && opt_action.section_blurb)) {
    comp_obj_                                              = comp_obj_.init;
    comp_obj_.metainfo.is_of_part                          = "backmatter";
    comp_obj_.metainfo.is_of_section                       = "blurb";
    comp_obj_.metainfo.is_of_type                          = "para";
    comp_obj_.metainfo.is_a                                = "heading";
    comp_obj_.text                                         = line.to!string;
    comp_obj_.metainfo.ocn                                 = 0;
    comp_obj_.metainfo.identifier                          = "";
    comp_obj_.metainfo.dummy_heading                       = false;
    comp_obj_.metainfo.object_number_off                   = true;
    comp_obj_.metainfo.object_number_type                  = 0;
    comp_obj_.tags.segment_anchor_tag_epub                 = "blurb";
    comp_obj_.tags.anchor_tag_html                         = comp_obj_.tags.segment_anchor_tag_epub;
    comp_obj_.tags.in_segment_html                         = comp_obj_.tags.anchor_tag_html;
    comp_obj_.metainfo.heading_lev_markup                  = an_object["lev_markup_number"].to!int;    // make int, remove need to conv
    comp_obj_.metainfo.heading_lev_collapsed               = an_object["lev_collapsed_number"].to!int; // make int, remove need to conv
    comp_obj_.metainfo.parent_ocn                          = 1;
    comp_obj_.metainfo.parent_lev_markup                   = 0;
    add_to_current_document_section                                 ~= comp_obj_;
    tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"]            = comp_obj_.tags.in_segment_html;
    tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub;
  } else if (!(line.empty)) {
    {
      auto _get = line.flow_para_match_(an_object, an_object_key, indent, bullet, pith, line_occur);
      {
        an_object     = _get.this_object;
        an_object_key = _get.this_object_key;
        pith          = _get.pith;
        indent        = _get.indent;
        bullet        = _get.bullet;
        line_occur    = _get.line_occur;
      }
    }
    comp_obj_                               = set_object_generic("backmatter", "blurb", "para", "blurb", links_and_images(line.to!string.strip).replaceFirst(rgx.para_attribs, ""), 0);
    comp_obj_.metainfo.identifier           = "";
    comp_obj_.metainfo.object_number_off    = true;
    comp_obj_.metainfo.object_number_type   = 0;
    comp_obj_.attrib.indent_hang            = indent["hang_position"];
    comp_obj_.attrib.indent_base            = indent["base_position"];
    comp_obj_.has.inline_links              = true;
    comp_obj_.attrib.bullet                 = bullet;
    add_to_current_document_section         ~= comp_obj_;
  }
  pith["ocn"] = eN.ocn.on;
  {
    ret.comp_section_obj = add_to_current_document_section;
    ret.pith             = pith;
    ret.tag_assoc        = tag_assoc; // NO CHANGE here, only for headings: html & epub
  }
  return ret;
}
@safe ST_txt_by_line_block_start txt_by_line_block_start()(
  char[]         line,
  uint[string]   pith,
  uint[string]   dochas,
  string[string] object_number_poem
) {
  static auto rgx = RgxI();
  if (auto m = line.matchFirst(rgx.block_curly_code_open)) {
    dochas["codeblock"]++;
    an_object["lang"]               = "";
    an_object["attrib"]             = (m["attrib"]) ? m["attrib"].to!string : "";
    an_object["syntax"]             = (m["syntax"]) ? m["syntax"].to!string : "";
    debug(codecurly) { writefln( "* [code curly] %s", line); }                              // code (curly) open
    pith["block_is"]                = eN.blk_is.code;
    pith["block_state"]             = eN.blk_state.on;
    pith["block_delim"]             = eN.blk_delim.curly;
  } else if (auto m = line.matchFirst(rgx.block_curly_poem_open)) {
    dochas["poem"]++;
    an_object["syntax"]             = "";
    an_object["attrib"]             = (m["attrib"]) ? m["attrib"].to!string : "";
    an_object["lang"]               = (m["lang"]) ? m["lang"].to!string : "";
    debug(poem) { writefln( "* [poem curly] %s", line); }                              // poem (curly) open
    object_number_poem["start"]     = obj_cite_digits.object_number.to!string;
    pith["block_is"]                = eN.blk_is.poem;
    pith["block_state"]             = eN.blk_state.on;
    pith["block_delim"]             = eN.blk_delim.curly;
    pith["verse_new"]               = eN.bi.on;
  } else if (auto m = line.matchFirst(rgx.block_curly_group_open)) {
    dochas["group"]++;
    an_object["syntax"]             = "";
    an_object["attrib"]             = (m["attrib"]) ? m["attrib"].to!string : "";
    an_object["lang"]               = (m["lang"]) ? m["lang"].to!string : "";
    debug(group) { writefln( "* [group curly] %s", line); }                             // group (curly) open
    pith["block_is"]                = eN.blk_is.group;
    pith["block_state"]             = eN.blk_state.on;
    pith["block_delim"]             = eN.blk_delim.curly;
  } else if (auto m = line.matchFirst(rgx.block_curly_block_open)) {
    dochas["block"]++;
    an_object["syntax"]             = "";
    an_object["attrib"]             = (m["attrib"]) ? m["attrib"].to!string : "";
    an_object["lang"]               = (m["lang"]) ? m["lang"].to!string : "";
    debug(block) { writefln( "* [block curly] %s", line); }
    pith["block_is"]                = eN.blk_is.block;
    pith["block_state"]             = eN.blk_state.on;
    pith["block_delim"]             = eN.blk_delim.curly;
  } else if (auto m = line.matchFirst(rgx.block_curly_quote_open)) {
    dochas["quote"]++;
    an_object["syntax"]             = "";
    an_object["attrib"]             = m["attrib"].to!string;
    an_object["lang"]               = m["lang"].to!string;
    debug(quote) { writefln( "* [quote curly] %s", line); }
    pith["block_is"]                = eN.blk_is.quote;
    pith["block_state"]             = eN.blk_state.on;
    pith["block_delim"]             = eN.blk_delim.curly;
  } else if (auto m = line.matchFirst(rgx.block_curly_table_open)) {           // curly table open
    debug(table) { writefln( "* [table curly] %s", line); }
    dochas["table"] ++;
    an_object["table_head"]         = m["attrib"].to!string;
    an_object["block_type"]         = "curly";
    pith["block_is"]                = eN.blk_is.table;
    pith["block_state"]             = eN.blk_state.on;
    pith["block_delim"]             = eN.blk_delim.curly;
  } else if (auto m = line.matchFirst(rgx.block_curly_table_special_markup)) { // table: special table block markup syntax!
    dochas["table"]++;
    an_object["table_head"]         = m["attrib"].to!string;
    an_object["block_type"]         = "special";
    pith["block_is"]                = eN.blk_is.table;
    pith["block_state"]             = eN.blk_state.on;
    pith["block_delim"]             = eN.blk_delim.curly_special;
  } else if (auto m = line.matchFirst(rgx.block_tic_code_open)) {
    dochas["codeblock"]++;
    an_object["lang"]               = "";
    an_object["attrib"]             = (m["attrib"]) ? m["attrib"].to!string : "";
    an_object["syntax"]             = (m["syntax"]) ? m["syntax"].to!string : "";
    debug(codetic) { writefln( "* [code tic] %s", line); }
    pith["block_is"]                = eN.blk_is.code;
    pith["block_state"]             = eN.blk_state.on;
    pith["block_delim"]             = eN.blk_delim.tic;
  } else if (auto m = line.matchFirst(rgx.block_tic_poem_open)) {
    dochas["poem"]++;
    an_object["syntax"]             = "";
    an_object["attrib"]             = (m["attrib"]) ? m["attrib"].to!string : "";
    an_object["lang"]               = (m["lang"]) ? m["lang"].to!string : "";
    debug(poem) { writefln( "* [poem tic] %s", line); }
    object_number_poem["start"]     = obj_cite_digits.object_number.to!string;
    pith["block_is"]                = eN.blk_is.poem;
    pith["block_state"]             = eN.blk_state.on;
    pith["block_delim"]             = eN.blk_delim.tic;
    pith["verse_new"]               = eN.bi.on;
  } else if (auto m = line.matchFirst(rgx.block_tic_group_open)) {
    dochas["group"]++;
    an_object["syntax"]             = "";
    an_object["attrib"]             = (m["attrib"]) ? m["attrib"].to!string : "";
    an_object["lang"]               = (m["lang"]) ? m["lang"].to!string : "";
    debug(group) { writefln( "* [group tic] %s", line); }
    pith["block_is"]                = eN.blk_is.group;
    pith["block_state"]             = eN.blk_state.on;
    pith["block_delim"]             = eN.blk_delim.tic;
  } else if (auto m = line.matchFirst(rgx.block_tic_block_open)) {
    dochas["block"]++;
    an_object["syntax"]             = "";
    an_object["attrib"]             = (m["attrib"]) ? m["attrib"].to!string : "";
    an_object["lang"]               = (m["lang"]) ? m["lang"].to!string : "";
    debug(block) { writefln( "* [block tic] %s", line); }
    pith["block_is"]                = eN.blk_is.block;
    pith["block_state"]             = eN.blk_state.on;
    pith["block_delim"]             = eN.blk_delim.tic;
  } else if (auto m = line.matchFirst(rgx.block_tic_quote_open)) {
    dochas["quote"]++;
    an_object["syntax"]             = "";
    an_object["attrib"]             = m["attrib"].to!string;
    an_object["lang"]               = m["lang"].to!string;
    debug(quote) { writefln( "* [quote tic] %s", line);                        // quote (tic) open
    }
    pith["block_is"]                = eN.blk_is.quote;
    pith["block_state"]             = eN.blk_state.on;
    pith["block_delim"]             = eN.blk_delim.tic;
  } else if (auto m = line.matchFirst(rgx.block_tic_table_open)) {             // tic table open
    debug(table) { writefln( "* [table tic] %s", line); }
    dochas["table"] ++;
    an_object["table_head"]         = m["attrib"].to!string;
    an_object["block_type"]         = "tic";
    pith["block_is"]                = eN.blk_is.table;
    pith["block_state"]             = eN.blk_state.on;
    pith["block_delim"]             = eN.blk_delim.tic;
  }
  ST_txt_by_line_block_start ret;
  {
    ret.pith               = pith;
    ret.dochas             = dochas;
    ret.object_number_poem = object_number_poem;
  }
  return ret;
}
@safe ST_txt_by_line_block_generic txt_by_line_block_quote()(
  char[]          line,
  string[string]  an_object,
  uint[string]    pith,
) {
  static auto rgx = RgxI();
  if (pith["block_is"] == eN.blk_is.quote){
    if (pith["block_delim"] == eN.blk_delim.curly) {
      if (line.matchFirst(rgx.block_curly_quote_close)) {
        debug(quote) { writeln(line); }
        an_object[an_object_key]    = an_object[an_object_key].stripRight;
        pith["block_is"]            = eN.blk_is.quote;
        pith["block_state"]         = eN.blk_state.closing;
        pith["block_delim"]         = eN.blk_delim.off;
      } else {
        debug(quote) { writeln(line); }
        an_object[an_object_key] ~= line ~= "\n";
      }
    } else if (pith["block_delim"] == eN.blk_delim.tic) {
      if (line.matchFirst(rgx.block_tic_close)) {
        debug(quote) { writeln(line); }
        an_object[an_object_key]    = an_object[an_object_key].stripRight;
        pith["block_is"]            = eN.blk_is.quote;
        pith["block_state"]         = eN.blk_state.closing;
        pith["block_delim"]         = eN.blk_delim.off;
      } else {
        debug(quote) { writeln(line); }
        an_object[an_object_key] ~= line ~= "\n";
      }
    }
  }
  ST_txt_by_line_block_generic ret;
  {
    ret.pith        = pith;
    ret.this_object = an_object;
  }
  return ret;
}
@safe ST_txt_by_line_block_generic txt_by_line_block_group()(
  char[]          line,
  string[string]  an_object,
  uint[string]    pith,
) {
  static auto rgx = RgxI();
  if (pith["block_is"] == eN.blk_is.group) {
    if (pith["block_delim"] == eN.blk_delim.curly) {
      if (line.matchFirst(rgx.block_curly_group_close)) {
        debug(group) { writeln(line); }
        an_object[an_object_key]    = an_object[an_object_key].stripRight;
        pith["block_is"]            = eN.blk_is.group;
        pith["block_state"]         = eN.blk_state.closing;
        pith["block_delim"]         = eN.blk_delim.off;
      } else {
        debug(group) { writeln(line); }
        an_object[an_object_key] ~= line ~= "\n";
      }
    } else if (pith["block_delim"] == eN.blk_delim.tic) {
      if (line.matchFirst(rgx.block_tic_close)) {
        debug(group) { writeln(line); }
        an_object[an_object_key]    = an_object[an_object_key].stripRight;
        pith["block_is"]            = eN.blk_is.group;
        pith["block_state"]         = eN.blk_state.closing;
        pith["block_delim"]         = eN.blk_delim.off;
      } else {
        debug(group) { writeln(line); }
        an_object[an_object_key] ~= line ~= "\n";
      }
    }
  }
  ST_txt_by_line_block_generic ret;
  {
    ret.pith        = pith;
    ret.this_object = an_object;
  }
  return ret;
}
@safe ST_txt_by_line_block_generic txt_by_line_block_block()(
  char[]          line,
  string[string]  an_object,
  uint[string]    pith,
) {
  static auto rgx = RgxI();
  if (pith["block_is"] == eN.blk_is.block) {
    if (pith["block_delim"] == eN.blk_delim.curly) {
      if (line.matchFirst(rgx.block_curly_block_close)) {
        debug(block) { writeln(line); }
        an_object[an_object_key]    = an_object[an_object_key].stripRight;
        pith["block_is"]            = eN.blk_is.block;
        pith["block_state"]         = eN.blk_state.closing;
        pith["block_delim"]         = eN.blk_delim.off;
      } else {
        debug(block) { writeln(line); }
        an_object[an_object_key] ~= line ~= "\n";
      }
    } else if (pith["block_delim"] == eN.blk_delim.tic) {
      if (line.matchFirst(rgx.block_tic_close)) {
        debug(block) { writeln(line); }
        an_object[an_object_key]    = an_object[an_object_key].stripRight;
        pith["block_is"]            = eN.blk_is.block;
        pith["block_state"]         = eN.blk_state.closing;
        pith["block_delim"]         = eN.blk_delim.off;
      } else {
        debug(block) { writeln(line); }
        an_object[an_object_key] ~= line ~= "\n";
      }
    }
  }
  ST_txt_by_line_block_generic ret;
  {
    ret.pith        = pith;
    ret.this_object = an_object;
  }
  return ret;
}
@safe ST_txt_by_line_block_poem txt_by_line_block_poem(CMM)(
  char[]          line,
  string[string]  an_object,
  uint[string]    pith,
  int             cntr,
  string[string]  object_number_poem,
  CMM             conf_make_meta,
  string[string]  tag_in_seg,
) {
  static auto rgx = RgxI();
  if (pith["block_is"] == eN.blk_is.poem) {
    if (pith["block_delim"] == eN.blk_delim.curly) {
      if (line.matchFirst(rgx.block_curly_poem_close)) {
        if (an_object_key in an_object
        || processing.length > 0) {
          an_object[an_object_key]        = "";
          debug(poem) { writefln( "* [poem curly] %s", line); }
          if (processing.length > 0) {
            an_object[an_object_key]      = processing["verse"];
          }
          debug(poem) {
            writeln(__LINE__);
            writefln( "* %s %s", obj_cite_digits.object_number, line);
          }
          if (an_object.length > 0) {
            debug(poem) { writeln( obj_cite_digits.object_number, an_object[an_object_key]); }
            an_object["is"]                                   = "verse";
            ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct
              = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc);
            an_object["substantive"]                          = substantive_obj_misc_struct.obj_txt;
            anchor_tag                                        = substantive_obj_misc_struct.anchor_tag;
            comp_obj_                                         = set_object_generic("body", "body", "block", "verse", an_object["substantive"], obj_cite_digits.object_number);
            comp_obj_.metainfo.identifier                     = obj_cite_digits.identifier;
            comp_obj_.metainfo.object_number_off              = obj_cite_digits.off;
            comp_obj_.metainfo.o_n_book_index                 = obj_cite_digits.bkidx;
            comp_obj_.metainfo.object_number_type             = obj_cite_digits.type;
            comp_obj_.tags.html_segment_anchor_tag_is         = tag_in_seg["seg_lv4"];
            comp_obj_.tags.epub_segment_anchor_tag_is         = tag_in_seg["seg_lv1to4"];
            comp_obj_.has.inline_notes_reg                    = substantive_obj_misc_struct.has_notes_reg;
            comp_obj_.has.inline_notes_star                   = substantive_obj_misc_struct.has_notes_star;
            comp_obj_.has.inline_links                        = substantive_obj_misc_struct.has_links;
            the_document_body_section                         ~= comp_obj_;
            tag_assoc                                         = an_object.inline_para_link_anchor(tag_in_seg, tag_assoc);
          }
          object_reset(an_object);
          processing.remove("verse");
          ++cntr;
        }
        object_number_poem["end"]   = obj_cite_digits.object_number.to!string;
        pith["block_is"]            = eN.blk_is.poem;
        pith["block_state"]         = eN.blk_state.closing;
        pith["block_delim"]         = eN.blk_delim.off;
      } else {
        processing["verse"] ~= line ~= "\n";
        if (pith["verse_new"] == eN.bi.on) {
          obj_cite_digits = ocn_emit(pith["ocn"]);
          pith["verse_new"]         = eN.bi.off;
        } else if (line.matchFirst(rgx.newline_eol_delimiter_only)) {
          processing["verse"]       = processing["verse"].stripRight;
          verse_line                = eN.bi.off;
          pith["verse_new"]         = eN.bi.on;
        }
        if (pith["verse_new"] == eN.bi.on) {
          verse_line = 1;
          an_object[an_object_key]  = processing["verse"];
          debug(poem) { writefln(
              "* %s curly\n%s",
              obj_cite_digits.object_number,
              an_object[an_object_key]
            );
          }
          processing.remove("verse");
          an_object["is"]                                     = "verse";
          auto comp_obj_location = node_construct.node_location_emitter(
            content_non_header,
            tag_in_seg,
            lev_anchor_tag,
            tag_assoc,
            obj_cite_digits,
            cntr,
            heading_ptr-1,
            an_object["is"]
          );
          ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct
            = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc);
          an_object["substantive"]                            = substantive_obj_misc_struct.obj_txt;
          anchor_tag                                          = substantive_obj_misc_struct.anchor_tag;
          comp_obj_                                           = set_object_generic("body", "body", "block", "verse", an_object["substantive"], obj_cite_digits.object_number);
          comp_obj_.metainfo.identifier                       = obj_cite_digits.identifier;
          comp_obj_.metainfo.object_number_off                = obj_cite_digits.off;
          comp_obj_.metainfo.o_n_book_index                   = obj_cite_digits.bkidx;
          comp_obj_.metainfo.object_number_type               = obj_cite_digits.type;
          comp_obj_.tags.html_segment_anchor_tag_is           = tag_in_seg["seg_lv4"];
          comp_obj_.tags.epub_segment_anchor_tag_is           = tag_in_seg["seg_lv1to4"];
          comp_obj_.has.inline_notes_reg                      = substantive_obj_misc_struct.has_notes_reg;
          comp_obj_.has.inline_notes_star                     = substantive_obj_misc_struct.has_notes_star;
          comp_obj_.has.inline_links                          = substantive_obj_misc_struct.has_links;
          the_document_body_section                           ~= comp_obj_;
          tag_assoc                                           = an_object.inline_para_link_anchor(tag_in_seg, tag_assoc);
          object_reset(an_object);
          processing.remove("verse");
          ++cntr;
        }
      }
    } else if (pith["block_delim"] == eN.blk_delim.tic) {
      if (auto m = line.matchFirst(rgx.block_tic_close)) {
        an_object[an_object_key] = "verse";
        debug(poem) { writefln( "* [poem tic] %s", line); }
        if (processing.length > 0) {
          an_object[an_object_key]  = processing["verse"];
        }
        if (an_object.length > 0) {
          debug(poem) { writeln(__LINE__); writeln(obj_cite_digits.object_number, line); }
          processing.remove("verse");
          an_object["is"]                                     = "verse";
          ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct
            = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc);
          an_object["substantive"]                            = substantive_obj_misc_struct.obj_txt;
          anchor_tag                                          = substantive_obj_misc_struct.anchor_tag;
          comp_obj_                                           = set_object_generic("body", "body", "block", "verse", an_object["substantive"], obj_cite_digits.object_number);
          comp_obj_.metainfo.identifier                       = obj_cite_digits.identifier;
          comp_obj_.metainfo.object_number_off                = obj_cite_digits.off;
          comp_obj_.metainfo.o_n_book_index                   = obj_cite_digits.bkidx;
          comp_obj_.metainfo.object_number_type               = obj_cite_digits.type;
          comp_obj_.tags.html_segment_anchor_tag_is           = tag_in_seg["seg_lv4"];
          comp_obj_.tags.epub_segment_anchor_tag_is           = tag_in_seg["seg_lv1to4"];
          comp_obj_.has.inline_notes_reg                      = substantive_obj_misc_struct.has_notes_reg;
          comp_obj_.has.inline_notes_star                     = substantive_obj_misc_struct.has_notes_star;
          comp_obj_.has.inline_links                          = substantive_obj_misc_struct.has_links;
          the_document_body_section                           ~= comp_obj_;
          tag_assoc                                           = an_object.inline_para_link_anchor(tag_in_seg, tag_assoc);
          object_number_poem["end"]                           = obj_cite_digits.object_number.to!string;
          object_reset(an_object);
          processing.remove("verse");
          ++cntr;
        }
        pith["block_is"]            = eN.blk_is.poem;
        pith["block_state"]         = eN.blk_state.closing;
        pith["block_delim"]         = eN.blk_delim.off;
      } else {
        processing["verse"]         ~= line ~= "\n";
        if (pith["verse_new"] == eN.bi.on) {
          obj_cite_digits           = ocn_emit(pith["ocn"]);
          pith["verse_new"]         = eN.bi.off;
        } else if (line.matchFirst(rgx.newline_eol_delimiter_only)) {
          processing["verse"]       = processing["verse"].stripRight;
          pith["verse_new"]         = eN.bi.on;
          verse_line                = eN.bi.off;
        }
        if (pith["verse_new"] == eN.bi.on) {
          verse_line = 1;
          an_object[an_object_key]  = processing["verse"];
          debug(poem) { writefln(
              "* %s tic\n%s",
              obj_cite_digits.object_number,
              an_object[an_object_key]
            );
          }
          processing.remove("verse");
          an_object["is"]                                     = "verse";
          auto comp_obj_location
            = node_construct.node_location_emitter(
              content_non_header,
              tag_in_seg,
              lev_anchor_tag,
              tag_assoc,
              obj_cite_digits,
              cntr,
              heading_ptr-1,
              an_object["is"]
            );
          ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct
            = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc);
          an_object["substantive"]                            = substantive_obj_misc_struct.obj_txt;
          anchor_tag                                          = substantive_obj_misc_struct.anchor_tag;
          comp_obj_                                           = set_object_generic("body", "body", "block", "verse", an_object["substantive"], obj_cite_digits.object_number);
          comp_obj_.metainfo.identifier                       = obj_cite_digits.identifier;
          comp_obj_.metainfo.object_number_off                = obj_cite_digits.off;
          comp_obj_.metainfo.o_n_book_index                   = obj_cite_digits.bkidx;
          comp_obj_.metainfo.object_number_type               = obj_cite_digits.type;
          comp_obj_.tags.html_segment_anchor_tag_is           = tag_in_seg["seg_lv4"];
          comp_obj_.tags.epub_segment_anchor_tag_is           = tag_in_seg["seg_lv1to4"];
          comp_obj_.has.inline_notes_reg                      = substantive_obj_misc_struct.has_notes_reg;
          comp_obj_.has.inline_notes_star                     = substantive_obj_misc_struct.has_notes_star;
          comp_obj_.has.inline_links                          = substantive_obj_misc_struct.has_links;
          the_document_body_section                           ~= comp_obj_;
          tag_assoc                                           = an_object.inline_para_link_anchor(tag_in_seg, tag_assoc);
          object_reset(an_object);
          processing.remove("verse");
          ++cntr;
        }
      }
    }
  }
  ST_txt_by_line_block_poem ret;
  {
    ret.cntr        = cntr;
    ret.pith        = pith;
    ret.this_object = an_object;
  }
  return ret;
}
@safe ST_txt_by_line_block_generic txt_by_line_block_code()(
  char[]          line,
  string[string]  an_object,
  uint[string]    pith,
) {
  static auto rgx = RgxI();
  if ( pith["block_is"] == eN.blk_is.code) {
    if (pith["block_delim"] == eN.blk_delim.curly) {
      if (line.matchFirst(rgx.block_curly_code_close)) {
        debug(codecurly) { writeln(line); }
        an_object[an_object_key] = an_object[an_object_key]
          .replaceFirst(rgx.newline_eol_delimiter_only, "")
          .stripRight;
        pith["block_is"]            = eN.blk_is.code;
        pith["block_state"]         = eN.blk_state.closing;
        pith["block_delim"]         = eN.blk_delim.off;
      } else {
        debug(codecurly) { writeln(line); }
        an_object[an_object_key] ~= line ~= "\n";
      }
    } else if (pith["block_delim"] == eN.blk_delim.tic) {
      if (line.matchFirst(rgx.block_tic_close)) {
        debug(codetic) { writeln(line); }
        an_object[an_object_key] = an_object[an_object_key]
          .replaceFirst(rgx.newline_eol_delimiter_only, "")
          .stripRight;
        pith["block_is"]            = eN.blk_is.code;
        pith["block_state"]         = eN.blk_state.closing;
        pith["block_delim"]         = eN.blk_delim.off;
      } else {
        debug(codetic) { writeln(line); }
        an_object[an_object_key] ~= line ~= "\n";
      }
    }
  }
  ST_txt_by_line_block_generic ret;
  {
    ret.pith        = pith;
    ret.this_object = an_object;
  }
  return ret;
}
@system auto txt_by_line_block_table(CMM)(
  char[]          line,
  string[string]  an_object,
  uint[string]    pith,
  CMM             conf_make_meta,
) {
  static auto rgx = RgxI();
  if (pith["block_is"] == eN.blk_is.table) {
    if (pith["block_delim"] == eN.blk_delim.curly) {
      if (line.matchFirst(rgx.block_curly_table_close)) {
        debug(table) { writeln(line); }
        pith["block_is"]            = eN.blk_is.table;
        pith["block_state"]         = eN.blk_state.closing;
        pith["block_delim"]         = eN.blk_delim.off;
      } else {
        debug(table) { writeln(line); }
        an_object[an_object_key] ~= line ~= "\n";
      }
    } else if (pith["block_delim"] == eN.blk_delim.curly_special) {
      if (line.empty) {
        pith["block_is"]            = eN.blk_is.table;
        pith["block_state"]         = eN.blk_state.off;
        pith["block_delim"]         = eN.blk_delim.off;
        {
          auto _get = line.flow_table_closed_make_special_notation_table_(
            an_object,
            the_document_body_section,
            obj_cite_digits,
            comp_obj_,
            cntr,
            pith,
            conf_make_meta,
          );
          {
            an_object                 = _get.this_object;
            the_document_body_section = _get.the_document_body_section;
            obj_cite_digits           = _get.obj_cite_digits;
            comp_obj_                 = _get.comp_obj_;
            cntr                      = _get.cntr;
            pith                      = _get.pith;
          }
        }
      } else {
        debug(table) { writeln(line); }
        an_object[an_object_key] ~= line ~= "\n";
      }
    } else if (pith["block_delim"] == eN.blk_delim.tic) {
      if (line.matchFirst(rgx.block_tic_close)) {
        debug(table) { writeln(line); }
        pith["block_is"]            = eN.blk_is.table;
        pith["block_state"]         = eN.blk_state.closing;
        pith["block_delim"]         = eN.blk_delim.off;
      } else {
        debug(table) { writeln(line); }
        an_object[an_object_key] ~= line ~= "\n";
      }
    }
  }
  struct ST_txt_by_line_block_table {
    CMM             conf_make_meta;
    uint[string]    pith;
    string[string]  this_object;
  }
  ST_txt_by_line_block_table ret;
  {
    ret.conf_make_meta = conf_make_meta,
    ret.pith           = pith;
    ret.this_object    = an_object;
  }
  return ret;
}
@system ST_txt_by_line_block_biblio txt_by_line_block_biblio(
  char[]                  line,
  uint[string] pith,
  int          bib_entry,
  string       biblio_entry_str_json,
  string[]     biblio_arr_json,
) {
  mixin spineBiblio;
  auto jsn = BibJsnStr();
  static auto rgx = RgxI();
  string biblio_tag_map()(string abr) {
    auto btm = [
      "au"        : "author_raw",
      "ed"        : "editor_raw",
      "ti"        : "fulltitle",
      "lng"       : "language",
      "jo"        : "journal",
      "vol"       : "volume",
      "edn"       : "edition",
      "yr"        : "year",
      "pl"        : "place",
      "pb"        : "publisher",
      "pub"       : "publisher",
      "pg"        : "pages",
      "pgs"       : "pages",
      "sn"        : "short_name"
    ];
    return btm[abr];
  }
  if (line.matchFirst(rgx.heading_biblio)) {
    pith["section"] = eN.sect.bibliography;
  }
  if (line.empty) {
    debug {
      debug(biblioblock) { writeln("---"); }
      debug(biblioblockinclude) { writeln(biblio_entry_str_json.length); }
    }
    if ((bib_entry == eN.bi.off)
    && (biblio_entry_str_json.empty)) {
      bib_entry = eN.bi.on;
      biblio_entry_str_json = jsn.biblio_entry_tags_jsonstr;
    } else if (!(biblio_entry_str_json.empty)) {
      bib_entry = eN.bi.off;
      if (!(biblio_entry_str_json == jsn.biblio_entry_tags_jsonstr)) {
        auto biblio_entry = parseJSON(biblio_entry_str_json);
        if (biblio_entry["fulltitle"].str.empty) {
          writeln("check problem entry (Title missing): ", biblio_entry_str_json);
        } else if ((biblio_entry["author_raw"].str.empty) && (biblio_entry["editor_raw"].str.empty)) {
          writeln("check problem entry (No author and no editor): ", biblio_entry_str_json);
        } else {
          biblio_arr_json ~= biblio_entry_str_json;
        }
        biblio_entry_str_json = jsn.biblio_entry_tags_jsonstr;
      }
    } else {
      writeln("?? 2. ERROR ", biblio_entry_str_json, "??");
      biblio_entry_str_json = "";
    }
  } else if (line.matchFirst(rgx.biblio_tags)) {
    debug(biblioblock) { writeln(line); }
    auto bt = line.match(rgx.biblio_tags);
    bib_entry = eN.bi.off;
    st = bt.captures[1].to!string;
    auto header_tag_value = (bt.captures[2]).to!string;
    JSONValue j = parseJSON(biblio_entry_str_json);
    biblio_tag_name = (st.match(rgx.biblio_abbreviations))
      ? (biblio_tag_map(st))
      : st;
    j.object[biblio_tag_name] = header_tag_value;
    debug(bibliounsortedcheckduplicates) { writeln(biblio_tag_name, ": ", header_tag_value); writeln("--"); }
    switch (biblio_tag_name) {
    case "author_raw": // author_arr author (fn sn)
      j["author_arr"]
       = header_tag_value.split(rgx.arr_delimiter);
      string tmp;
      biblioAuthorLoop:
      foreach (au; j["author_arr"].array) {
        if (auto x = au.str.match(rgx.name_delimiter)) {
          tmp ~= x.captures[2] ~ " " ~ x.captures[1] ~ ", ";
        } else {
          tmp ~= au.str;
        }
      }
      tmp = tmp.replace(rgx.trailing_comma, "");
      j["author"].str = tmp;
      goto default;
    case "editor_raw": // editor_arr editor (fn sn)
      j["editor_arr"]
        = header_tag_value.split(rgx.arr_delimiter);
      string tmp;
      biblioEditorLoop:
      foreach (ed; j["editor_arr"].array) {
        if (auto x = ed.str.match(rgx.name_delimiter)) {
          tmp ~= x.captures[2] ~ " " ~ x.captures[1] ~ ", ";
        } else {
          tmp ~= ed.str;
        }
      }
      tmp = tmp.replace(rgx.trailing_comma, "");
      j["editor"].str = tmp;
      goto default;
    case "fulltitle": // title & subtitle
      goto default;
    default:
      break;
    }
    auto s = j.toString();
    debug(biblio1) { writefln(
        "* %s: %s\n%s",
        biblio_tag_name,
        biblio_tag_entry,
        j[biblio_tag_name]
      );
    }
    if (line.match(rgx.comment)) {
      writeln("ERROR", line, "COMMENT");
      writeln("ERROR", s, "%%");
    }
    if (!(match(line, rgx.comment))) {
      debug(biblioblockinclude) { writeln(line); }
      biblio_entry_str_json = s;
    } else {
      biblio_entry_str_json = "";
    }
    header_tag_value        = "";
  }
  ST_txt_by_line_block_biblio ret;
  {
    ret.pith                  = pith;
    ret.bib_entry             = bib_entry;
    ret.biblio_entry_str_json = biblio_entry_str_json;
    ret.biblio_arr_json       = biblio_arr_json;
  }
  return ret;
}
// ↓ abstraction functions
@safe static string[string] object_reset()(string[string] an_object) {
  an_object.remove("body_nugget");
  an_object.remove("substantive");
  an_object.remove("is");
  an_object.remove("attrib");
  an_object.remove("bookindex_nugget");
  return an_object;
}
@safe static uint[string] _check_ocn_status_()(
  char[]       line,
  uint[string] pith,
) {
  static auto rgx = RgxI();
  if (!(line.empty)) {
    if (pith["no_ocn_multiple_objects"] == eN.bi.off) {
      // not multi-line object, check whether object_number is on or turned off
      if (line.matchFirst(rgx.object_number_block_marks)) {                      // switch off object_number
        if (line.matchFirst(rgx.object_number_off_block)) {
          pith["no_ocn_multiple_objects"]             = eN.bi.on;
          pith["ocn"]                                 = eN.ocn.off;
          debug(ocnoff) { writeln(line); }
        }
        if (line.matchFirst(rgx.object_number_off_block_dummy_heading)) {
          pith["no_ocn_multiple_objects"]             = eN.bi.on;
          pith["dummy_heading_multiple_objects"]      = eN.bi.on;
          pith["ocn"]                                 = eN.ocn.off;
          debug(ocnoff) { writeln(line); }
        }
      } else if (pith["no_ocn_multiple_objects"] == eN.bi.off) {
          pith["dummy_heading_status"]                = eN.bi.off;
          if (pith["dummy_heading_multiple_objects"]) {
            pith["dummy_heading_status"]              = eN.bi.on;
          }
          if (line.matchFirst(rgx.object_number_off)) {
            pith["ocn"]                               = eN.ocn.off;
          } else if (line.matchFirst(rgx.object_number_off_dummy_heading)) {
            pith["ocn"]                               = eN.ocn.off;
            pith["dummy_heading_status"]              = eN.bi.on;
          } else {
            pith["ocn"]                               = eN.ocn.on;
            pith["dummy_heading_status"]              = eN.bi.off;
          }
        } else {
          pith["ocn"] = pith["no_ocn_multiple_objects"];
        }
    } else if (pith["no_ocn_multiple_objects"] == eN.bi.on) {
      if (line.matchFirst(rgx.object_number_off_block_close)) {
        pith["no_ocn_multiple_objects"]               = eN.bi.off;
        pith["ocn"]                                   = eN.ocn.on;
        pith["dummy_heading_status"]                  = eN.bi.off;
        debug(ocnoff) { writeln(line); }
      }
    }
  }
  return pith;
}
@safe char[] _doc_header_and_make_substitutions_(CMM)(
  char[]  line,
  CMM     conf_make_meta,
) {
  enum Substitute { match, markup, }
  if (conf_make_meta.make.substitute) {
    foreach(substitution_pair; conf_make_meta.make.substitute) {
      line = line.replaceAll(
        regex("\b" ~ substitution_pair[Substitute.match]),
        substitution_pair[Substitute.markup]
      );
    }
  }
  return line;
}
@safe char[] _doc_header_and_make_substitutions_fontface_(CMM)(
  char[]  line,
  CMM     conf_make_meta,
) {
  enum Substitute { match, markup, }
  if ( conf_make_meta.make.bold) {
    line = line.replaceAll(
      regex("\b" ~ conf_make_meta.make.bold[Substitute.match]),
      conf_make_meta.make.bold[Substitute.markup]
    );
  }
  if (conf_make_meta.make.emphasis) {
    line = line.replaceAll(
      regex("\b" ~ conf_make_meta.make.emphasis[Substitute.match]),
      conf_make_meta.make.emphasis[Substitute.markup]
    );
  }
  if (conf_make_meta.make.italics) {
    line = line.replaceAll(
      regex("\b" ~ conf_make_meta.make.italics[Substitute.match]),
      conf_make_meta.make.italics[Substitute.markup]
    );
  }
  return line;
}
@system ST_flow_table_closed_make_special_notation_table flow_table_closed_make_special_notation_table_(CMM)(
  char[]                line,
  string[string]        an_object,
  ObjGenericComposite[] the_document_body_section,
  OCNset                obj_cite_digits,
  ObjGenericComposite   comp_obj_,
  int                   cntr,
  uint[string]          pith,
  CMM                   conf_make_meta
) {
  comp_obj_       = comp_obj_.init;
  obj_cite_digits = ocn_emit(pith["ocn"]);
  auto comp_obj_location = node_construct.node_location_emitter(
      content_non_header,
      tag_in_seg,
      lev_anchor_tag,
      tag_assoc,
      obj_cite_digits,
      cntr,
      heading_ptr-1,
      "table"
    );
  an_object["is"]                                             = "table";
  ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct
    = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, "body_nugget", conf_make_meta, No._new_doc);
  an_object["substantive"]                                    = substantive_obj_misc_struct.obj_txt;
  comp_obj_.metainfo.ocn                                      = obj_cite_digits.object_number;
  comp_obj_.metainfo.identifier                               = obj_cite_digits.identifier;
  comp_obj_.metainfo.object_number_off                        = obj_cite_digits.off;
  comp_obj_.tags.html_segment_anchor_tag_is                   = tag_in_seg["seg_lv4"];
  comp_obj_.tags.epub_segment_anchor_tag_is                   = tag_in_seg["seg_lv1to4"];
  comp_obj_.metainfo.o_n_book_index                           = obj_cite_digits.bkidx;
  comp_obj_.metainfo.object_number_type                       = obj_cite_digits.type;
  comp_obj_                                                   = comp_obj_.flow_table_instructions(an_object["table_head"]);
  {
    auto _get = comp_obj_.flow_table_substantive_munge_special(an_object["substantive"]);
    {
      comp_obj_           = _get.table_object;
      an_object["substantive"] = _get.table_substantive;
    }
  }
  the_document_body_section                                   ~= comp_obj_;
  object_reset(an_object);
  processing.remove("verse");
  ++cntr;
  ST_flow_table_closed_make_special_notation_table ret;
  {
    ret.this_object               = an_object;
    ret.the_document_body_section = the_document_body_section;
    ret.obj_cite_digits           = obj_cite_digits;
    ret.comp_obj_                 = comp_obj_;
    ret.cntr                      = cntr;
    ret.pith                      = pith;
  }
  return ret;
}
@system ST_flow_block_flag_line_empty flow_block_flag_line_empty_(B,CMM,Ts)(
  char[]                   line,
  string[string]           an_object,
  B                        bookindex_extract_hash,
  ObjGenericComposite[]    the_document_body_section,
  string[][string][string] bookindex_unordered_hashes,
  OCNset                   obj_cite_digits,
  ObjGenericComposite      comp_obj_,
  int                      cntr,
  uint[string]             pith,
  string[string]           object_number_poem,
  CMM                      conf_make_meta,
  Ts                       tag_in_seg,
) {
  assert(
    line.empty,
    "\nline should be empty:\n  \""
    ~ line ~ "\""
  );
  assert(
    (pith["block_state"] == eN.blk_state.closing),
    "code block status: closed"
  );
  static auto rgx = RgxI();
  if (pith["block_state"] == eN.blk_state.closing) {
    if (pith["block_is"] == eN.blk_is.quote) {
      obj_cite_digits = ocn_emit(pith["ocn"]);
      an_object["bookindex_nugget"]
        = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : "";
      bookindex_unordered_hashes
        = bookindex_extract_hash.bookindex_nugget_hash(
          an_object["bookindex_nugget"],
          obj_cite_digits,
          tag_in_seg
        );
      an_object["is"]                                         = "quote";
      auto comp_obj_location
        = node_construct.node_location_emitter(
          content_non_header,
          tag_in_seg,
          lev_anchor_tag,
          tag_assoc,
          obj_cite_digits,
          cntr,
          heading_ptr-1,
          an_object["is"]
        );
      ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct
        = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc);
      an_object["substantive"]                                = substantive_obj_misc_struct.obj_txt;
      anchor_tag                                              = substantive_obj_misc_struct.anchor_tag;
      comp_obj_                                               = set_object_generic("body", "body", "block", "quote", an_object["substantive"], obj_cite_digits.object_number);
      comp_obj_.metainfo.identifier                           = obj_cite_digits.identifier;
      comp_obj_.metainfo.object_number_off                    = obj_cite_digits.off;
      comp_obj_.metainfo.o_n_book_index                       = obj_cite_digits.bkidx;
      comp_obj_.metainfo.object_number_type                   = obj_cite_digit_type;
      comp_obj_.metainfo.lang                                 = an_object["lang"];
      comp_obj_.metainfo.attrib                               = an_object["attrib"];
      comp_obj_.tags.html_segment_anchor_tag_is               = tag_in_seg["seg_lv4"];
      comp_obj_.tags.epub_segment_anchor_tag_is               = tag_in_seg["seg_lv1to4"];
      comp_obj_.has.inline_notes_reg                          = substantive_obj_misc_struct.has_notes_reg;
      comp_obj_.has.inline_notes_star                         = substantive_obj_misc_struct.has_notes_star;
      comp_obj_.has.inline_links                              = substantive_obj_misc_struct.has_links;
      the_document_body_section                               ~= comp_obj_;
      tag_assoc                                               = an_object.inline_para_link_anchor(tag_in_seg, tag_assoc);
      pith["block_is"]                                        = eN.blk_is.quote;
      pith["block_state"]                                     = eN.blk_state.off;
      pith["block_delim"]                                     = eN.blk_delim.off;
      object_reset(an_object);
      processing.remove("verse");
      ++cntr;
    } else if (pith["block_is"] == eN.blk_is.group) {
      obj_cite_digits = ocn_emit(pith["ocn"]);
      an_object["bookindex_nugget"]
        = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : "";
      bookindex_unordered_hashes
        = bookindex_extract_hash.bookindex_nugget_hash(
          an_object["bookindex_nugget"],
          obj_cite_digits,
          tag_in_seg
        );
      an_object["is"]                                         = "group";
      auto comp_obj_location
        = node_construct.node_location_emitter(
          content_non_header,
          tag_in_seg,
          lev_anchor_tag,
          tag_assoc,
          obj_cite_digits,
          cntr,
          heading_ptr-1,
          an_object["is"]
        );
      ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct
        = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc);
      an_object["substantive"]                                = substantive_obj_misc_struct.obj_txt;
      anchor_tag                                              = substantive_obj_misc_struct.anchor_tag;
      comp_obj_                                               = set_object_generic("body", "body", "block", "group", an_object["substantive"], obj_cite_digits.object_number);
      comp_obj_.metainfo.identifier                           = obj_cite_digits.identifier;
      comp_obj_.metainfo.object_number_off                    = obj_cite_digits.off;
      comp_obj_.metainfo.o_n_book_index                       = obj_cite_digits.bkidx;
      comp_obj_.metainfo.object_number_type                   = obj_cite_digits.type;
      comp_obj_.metainfo.lang                                 = an_object["lang"];
      comp_obj_.metainfo.attrib                               = an_object["attrib"];
      comp_obj_.tags.html_segment_anchor_tag_is               = tag_in_seg["seg_lv4"];
      comp_obj_.tags.epub_segment_anchor_tag_is               = tag_in_seg["seg_lv1to4"];
      comp_obj_.has.inline_notes_reg                          = substantive_obj_misc_struct.has_notes_reg;
      comp_obj_.has.inline_notes_star                         = substantive_obj_misc_struct.has_notes_star;
      comp_obj_.has.inline_links                              = substantive_obj_misc_struct.has_links;
      the_document_body_section                               ~= comp_obj_;
      tag_assoc                                               = an_object.inline_para_link_anchor(tag_in_seg, tag_assoc);
      pith["block_is"]                                        = eN.blk_is.poem;
      pith["block_state"]                                     = eN.blk_state.off;
      pith["block_delim"]                                     = eN.blk_delim.off;
      object_reset(an_object);
      processing.remove("verse");
      ++cntr;
    } else if (pith["block_is"] == eN.blk_is.block) {
      obj_cite_digits = ocn_emit(pith["ocn"]);
      an_object["bookindex_nugget"]
        = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : "";
      bookindex_unordered_hashes
        = bookindex_extract_hash.bookindex_nugget_hash(
          an_object["bookindex_nugget"],
          obj_cite_digits,
          tag_in_seg
        );
      an_object["is"]                                         = "block";
      auto comp_obj_location
        = node_construct.node_location_emitter(
          content_non_header,
          tag_in_seg,
          lev_anchor_tag,
          tag_assoc,
          obj_cite_digits,
          cntr,
          heading_ptr-1,
          an_object["is"]
        );
      ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct
        = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc);
      an_object["substantive"]                                = substantive_obj_misc_struct.obj_txt;
      // anchor_tag                                           = substantive_obj_misc_struct.anchor_tag; // check
      comp_obj_                                               = set_object_generic("body", "body", "block", "block", an_object["substantive"], obj_cite_digits.object_number);
      comp_obj_.metainfo.identifier                           = obj_cite_digits.identifier;
      comp_obj_.metainfo.object_number_off                    = obj_cite_digits.off;
      comp_obj_.metainfo.o_n_book_index                       = obj_cite_digits.bkidx;
      comp_obj_.metainfo.object_number_type                   = obj_cite_digit_type;
      comp_obj_.metainfo.lang                                 = an_object["lang"];
      comp_obj_.metainfo.attrib                               = an_object["attrib"];
      comp_obj_.tags.html_segment_anchor_tag_is               = tag_in_seg["seg_lv4"];
      comp_obj_.tags.epub_segment_anchor_tag_is               = tag_in_seg["seg_lv1to4"];
      comp_obj_.has.inline_notes_reg                          = substantive_obj_misc_struct.has_notes_reg;
      comp_obj_.has.inline_notes_star                         = substantive_obj_misc_struct.has_notes_star;
      comp_obj_.has.inline_links                              = substantive_obj_misc_struct.has_links;
      the_document_body_section                               ~= comp_obj_;
      pith["block_is"]                                        = eN.blk_is.block;
      pith["block_state"]                                     = eN.blk_state.off;
      pith["block_delim"]                                     = eN.blk_delim.off;
      object_reset(an_object);
      processing.remove("verse");
      ++cntr;
    } else if (pith["block_is"] == eN.blk_is.poem) {
      an_object["bookindex_nugget"]
        = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : "";
      bookindex_unordered_hashes
        = bookindex_extract_hash.bookindex_nugget_hash(
          an_object["bookindex_nugget"],
          obj_cite_digits,
          tag_in_seg
        );
      an_object["is"]                                         = "verse";
      auto comp_obj_location
        = node_construct.node_location_emitter(
          content_non_header,
          tag_in_seg,
          lev_anchor_tag,
          tag_assoc,
          obj_cite_digits,
          cntr,
          heading_ptr-1,
          an_object["is"]
        );
      comp_obj_poem_ocn                                       = set_object_generic("body", "body", "block", "poem", "", obj_cite_digits.object_number);
      comp_obj_poem_ocn.metainfo.identifier                   = obj_cite_digits.identifier;
      comp_obj_poem_ocn.metainfo.object_number_off            = obj_cite_digits.off;
      comp_obj_poem_ocn.metainfo.o_n_book_index               = obj_cite_digits.bkidx;
      comp_obj_poem_ocn.metainfo.object_number_type           = obj_cite_digits.type;
      the_document_body_section                               ~= comp_obj_poem_ocn;
      pith["block_is"]                                        = eN.blk_is.poem;
      pith["block_state"]                                     = eN.blk_state.off;
      pith["block_delim"]                                     = eN.blk_delim.off;
      object_reset(an_object);
      processing.remove("verse");
    } else if (pith["block_is"] == eN.blk_is.code) {
      obj_cite_digits = ocn_emit(pith["ocn"]);
      an_object["bookindex_nugget"]
        = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : "";
      bookindex_unordered_hashes
        = bookindex_extract_hash.bookindex_nugget_hash(
          an_object["bookindex_nugget"],
          obj_cite_digits,
          tag_in_seg
        );
      an_object["is"]                                         = "code";
      auto comp_obj_location
        = node_construct.node_location_emitter(
          content_non_header,
          tag_in_seg,
          lev_anchor_tag,
          tag_assoc,
          obj_cite_digits,
          cntr,
          heading_ptr-1,
          an_object["is"]
        );
      ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct
        = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc);
      an_object["substantive"]                                = substantive_obj_misc_struct.obj_txt;
      anchor_tag                                              = substantive_obj_misc_struct.anchor_tag;
      comp_obj_                                               = set_object_generic("body", "body", "block", "code", an_object["substantive"], obj_cite_digits.object_number);
      comp_obj_.metainfo.identifier                           = obj_cite_digits.identifier;
      comp_obj_.metainfo.object_number_off                    = obj_cite_digits.off;
      comp_obj_.metainfo.o_n_book_index                       = obj_cite_digits.bkidx;
      comp_obj_.metainfo.object_number_type                   = obj_cite_digits.type;
      comp_obj_.metainfo.syntax                               = an_object["syntax"];
      comp_obj_.metainfo.attrib                               = an_object["attrib"];
      comp_obj_.code_block.linenumbers                        = (an_object["attrib"].match(rgx.code_numbering)) ? true : false;
      comp_obj_.tags.html_segment_anchor_tag_is               = tag_in_seg["seg_lv4"];
      comp_obj_.tags.epub_segment_anchor_tag_is               = tag_in_seg["seg_lv1to4"];
      comp_obj_.has.inline_notes_reg                          = substantive_obj_misc_struct.has_notes_reg;
      comp_obj_.has.inline_notes_star                         = substantive_obj_misc_struct.has_notes_star;
      comp_obj_.has.inline_links                              = substantive_obj_misc_struct.has_links;
      the_document_body_section                               ~= comp_obj_;
      pith["block_is"]                                        = eN.blk_is.code;
      pith["block_state"]                                     = eN.blk_state.off;
      pith["block_delim"]                                     = eN.blk_delim.off;
      object_reset(an_object);
      processing.remove("verse");
      ++cntr;
    } else if (pith["block_is"]    == eN.blk_is.table) {
      comp_obj_ = comp_obj_.init;
      obj_cite_digits = ocn_emit(pith["ocn"]);
      an_object["bookindex_nugget"]
        = ("bookindex_nugget" in an_object) ? an_object["bookindex_nugget"] : "";
      bookindex_unordered_hashes
        = bookindex_extract_hash.bookindex_nugget_hash(
          an_object["bookindex_nugget"],
          obj_cite_digits,
          tag_in_seg
        );
      an_object["is"]                                         = "table";
      auto comp_obj_location
        = node_construct.node_location_emitter(
          content_non_header,
          tag_in_seg,
          lev_anchor_tag,
          tag_assoc,
          obj_cite_digits,
          cntr,
          heading_ptr-1,
          an_object["is"]
        );
      ST_txtAndAnchorTagPlusHasFootnotesUrlsImages substantive_obj_misc_struct
        = obj_im.obj_inline_markup_and_anchor_tags_and_misc(an_object, an_object_key, conf_make_meta, No._new_doc);
      an_object["substantive"]                                = substantive_obj_misc_struct.obj_txt;
      comp_obj_                                               = comp_obj_.init;
      comp_obj_.metainfo.ocn                                  = obj_cite_digits.object_number;
      comp_obj_.metainfo.identifier                           = obj_cite_digits.identifier;
      comp_obj_.metainfo.object_number_off                    = obj_cite_digits.off;
      comp_obj_.tags.html_segment_anchor_tag_is               = tag_in_seg["seg_lv4"];
      comp_obj_.tags.epub_segment_anchor_tag_is               = tag_in_seg["seg_lv1to4"];
      comp_obj_.metainfo.o_n_book_index                       = obj_cite_digits.bkidx;
      comp_obj_.metainfo.object_number_type                   = obj_cite_digits.type;
      comp_obj_                                               = comp_obj_.flow_table_instructions(an_object["table_head"]);
      {
        auto _get = comp_obj_.flow_table_substantive_munge(an_object["substantive"]);
        {
          comp_obj_           = _get.table_object;
          an_object["substantive"] = _get.table_substantive;
        }
      }
      the_document_body_section                               ~= comp_obj_;
      pith["block_is"]                                        = eN.blk_is.table;
      pith["block_state"]                                     = eN.blk_state.off;
      pith["block_delim"]                                     = eN.blk_delim.off;
      object_reset(an_object);
      processing.remove("verse");
      ++cntr;
    }
  }
  ST_flow_block_flag_line_empty ret;
  {
    ret.this_object                = an_object;
    ret.the_document_body_section  = the_document_body_section;
    ret.bookindex_unordered_hashes = bookindex_unordered_hashes;
    ret.obj_cite_digits            = obj_cite_digits;
    ret.comp_obj_                  = comp_obj_; //
    ret.cntr                       = cntr;
    ret.pith                       = pith;
  }
  return ret;
}
@system ST_flow_book_index flow_book_index_(B)(
  char[]          line,
  string[string]  an_object,
  string          book_idx_tmp,
  uint[string]    pith,
  B               opt_action,
) {
  static auto rgx = RgxI();
  if (auto m = line.match(rgx.book_index_item)) {                                   // match book_index
    debug(bookindexmatch) { writefln(
        "* [bookindex] %s\n",
        m["bookindex"].to!string,
      );
    }
    an_object["bookindex_nugget"] = m.captures[1].to!string;
  } else if (auto m = line.match(rgx.book_index_item_open))  {                      // match open book_index
    pith["section"] = eN.sect.book_index;
    if (opt_action.backmatter && opt_action.section_bookindex) {
      book_idx_tmp = m.captures[1].to!string;
      debug(bookindexmatch) { writefln( "* [bookindex] %s\n", book_idx_tmp,); }
    }
  } else if (pith["section"] == eN.sect.book_index)  {                    // book_index flag set
    if (auto m = line.match(rgx.book_index_item_close))  {
      pith["section"] = eN.sect.unset;
      if (opt_action.backmatter
      && opt_action.section_bookindex) {
        an_object["bookindex_nugget"] = book_idx_tmp ~ m.captures[1].to!string;
        debug(bookindexmatch) { writefln( "* [bookindex] %s\n", book_idx_tmp,); }
      }
      book_idx_tmp = "";
    } else {
      if (opt_action.backmatter
      && opt_action.section_bookindex) {
        book_idx_tmp ~= line;
      }
    }
  }
  ST_flow_book_index ret;
  {
    ret.this_object    = an_object;
    ret.pith           = pith;
    ret.book_idx_tmp   = book_idx_tmp;
  }
  return ret;
}
@safe ST_flow_heading_found flow_heading_found_()(
  char[]                line,
  string[string]        heading_match_str,
  string[]              _make_unmarked_headings,
  Regex!(char)[string]  heading_match_rgx,
  uint[string]          pith,
) {
  static auto rgx = RgxI();
  if ((_make_unmarked_headings.length > 2)
  && (pith["make_headings"] == eN.bi.off)) {                        // headings found
    debug(headingsfound) { writeln(_make_unmarked_headings); }
    debug(headingsfound) {
      writeln(_make_unmarked_headings.length);
      writeln(_make_unmarked_headings);
    }
    switch (_make_unmarked_headings.length) {
    case 7 :
      if (!empty(_make_unmarked_headings[6])) {
        heading_match_str["h_4"]
          = "^(" ~ _make_unmarked_headings[6].to!string ~ ")";
        heading_match_rgx["h_4"]
          = regex(heading_match_str["h_4"]);
      }
      goto case;
    case 6 :
      if (!empty(_make_unmarked_headings[5])) {
        heading_match_str["h_3"]
          = "^(" ~ _make_unmarked_headings[5].to!string ~ ")";
        heading_match_rgx["h_3"]
          = regex(heading_match_str["h_3"]);
      }
      goto case;
    case 5 :
      if (!empty(_make_unmarked_headings[4])) {
        heading_match_str["h_2"]
          = "^(" ~ _make_unmarked_headings[4].to!string ~ ")";
        heading_match_rgx["h_2"]
          = regex(heading_match_str["h_2"]);
      }
      goto case;
    case 4 :
      if (!empty(_make_unmarked_headings[3])) {
        heading_match_str["h_1"]
          = "^(" ~ _make_unmarked_headings[3].to!string ~ ")";
        heading_match_rgx["h_1"]
          = regex(heading_match_str["h_1"]);
      }
      goto case;
    case 3 :
      if (!empty(_make_unmarked_headings[2])) {
        heading_match_str["h_D"]
          = "^(" ~ _make_unmarked_headings[2].to!string ~ ")";
        heading_match_rgx["h_D"]
          = regex(heading_match_str["h_D"]);
      }
      goto case;
    case 2 :
      if (!empty(_make_unmarked_headings[1])) {
        heading_match_str["h_C"]
          = "^(" ~ _make_unmarked_headings[1].to!string ~ ")";
        heading_match_rgx["h_C"]
          = regex(heading_match_str["h_C"]);
      }
      goto case;
    case 1 :
      if (!empty(_make_unmarked_headings[0])) {
        heading_match_str["h_B"]
          = "^(" ~ _make_unmarked_headings[0].to!string ~ ")";
        heading_match_rgx["h_B"]
          = regex(heading_match_str["h_B"]);
      }
      break;
    default:
      break;
    }
    pith["make_headings"] = eN.bi.on;
  }
  ST_flow_heading_found ret;
  {
    ret.heading_match_str = heading_match_str;
    ret.heading_match_rgx = heading_match_rgx;
    ret.pith              = pith;
  }
  return ret;
}
@safe ST_flow_heading_make_set flow_heading_make_set_()(
             char[]                line,
             int[string]           line_occur,
  return ref Regex!(char)[string]  heading_match_rgx,
  return ref uint[string]          pith,
) {
  if (pith["make_headings"] == eN.bi.on
    && (line_occur["para"] == eN.bi.off
    && line_occur["heading"] == eN.bi.off)
    && pith["txt_is"] == eN.txt_is.off
  ) {                             // heading make set
    if (line.matchFirst(heading_match_rgx["h_B"])) {
      line = "B~ " ~ line;
      debug(headingsfound) { writeln(line); }
    }
    if (line.matchFirst(heading_match_rgx["h_C"])) {
      line = "C~ " ~ line;
      debug(headingsfound) { writeln(line); }
    }
    if (line.matchFirst(heading_match_rgx["h_D"])) {
      line = "D~ " ~ line;
      debug(headingsfound) { writeln(line); }
    }
    if (line.matchFirst(heading_match_rgx["h_1"])) {
      line = "1~ " ~ line;
      debug(headingsfound) { writeln(line); }
    }
    if (line.matchFirst(heading_match_rgx["h_2"])) {
      line = "2~ " ~ line;
      debug(headingsfound) { writeln(line); }
    }
    if (line.matchFirst(heading_match_rgx["h_3"])) {
      line = "3~ " ~ line;
      debug(headingsfound) { writeln(line); }
    }
    if (line.matchFirst(heading_match_rgx["h_4"])) {
      line = "4~ " ~ line;
      debug(headingsfound) { writeln(line); }
    }
  }
  ST_flow_heading_make_set ret;
  {
    ret.line           = line;
    ret.pith           = pith;
    ret.this_object    = an_object;
  }
  return ret;
}
@safe auto flow_heading_matched_(CMM)(
  char[]          line,
  string[string]  an_object,
  int[string]     line_occur,
  string          an_object_key,
  int[string]     lv,
  int[string]     collapsed_lev,
  uint[string]    pith,
  CMM             conf_make_meta,
) {
  static auto rgx = RgxI();
  static auto mkup = InlineMarkup();
  if (auto m = line.match(rgx.headings)) {                                      // heading match
    ++line_occur["heading"];
    pith["txt_is"]           = eN.txt_is.heading;
    if (line.match(rgx.heading_seg_and_above)) {
      pith["section"]        = eN.sect.unset;
    }
    an_object[an_object_key] ~= line ~= "\n";
    an_object["lev"] ~= m.captures[1];
    assertions_doc_structure(an_object, an_object_key, lv); // includes most of the logic for collapsed levels
    switch (an_object["lev"]) {
    case "A":                                // Title set
      if ((an_object[an_object_key].match(rgx.variable_doc_title_author_date))
      || (an_object[an_object_key].match(rgx.variable_doc_title)
      && an_object[an_object_key].match(rgx.variable_doc_author)
      && an_object[an_object_key].match(rgx.variable_doc_date))) {
        an_object[an_object_key] = an_object[an_object_key]
          .replaceFirst(rgx.variable_doc_title_author_date,
            (conf_make_meta.meta.title_full
            ~ mkup.br_line_inline
            ~ conf_make_meta.meta.creator_author
            ~ " (" ~ (conf_make_meta.meta.date_published.replaceFirst(regex(r"(?:-00)+"),"")) ~ ")"))
          .replaceFirst(rgx.variable_doc_title,
            (conf_make_meta.meta.title_full ~ mkup.br_line_inline))
          .replaceFirst(rgx.variable_doc_author,
            conf_make_meta.meta.creator_author)
          .replaceFirst(rgx.variable_doc_date,
            " (" ~ (conf_make_meta.meta.date_published.replaceFirst(regex(r"(?:-00)+"),"")) ~ ")");
      } else if ((an_object[an_object_key].match(rgx.variable_doc_title_author))
      || (an_object[an_object_key].match(rgx.variable_doc_title)
      && an_object[an_object_key].match(rgx.variable_doc_author))) {
        an_object[an_object_key] = an_object[an_object_key]
          .replaceFirst(rgx.variable_doc_title_author_date,
            (conf_make_meta.meta.title_full
            ~ mkup.br_line_inline
            ~ conf_make_meta.meta.creator_author))
          .replaceFirst(rgx.variable_doc_title,
            (conf_make_meta.meta.title_full ~ mkup.br_line_inline))
          .replaceFirst(rgx.variable_doc_author,
            conf_make_meta.meta.creator_author);
      } else if (an_object[an_object_key].match(rgx.variable_doc_title)) {
        an_object[an_object_key] = an_object[an_object_key]
          .replaceFirst(rgx.variable_doc_title,
            conf_make_meta.meta.title_full);
      }
      collapsed_lev["h0"] = 0;
      an_object["lev_collapsed_number"]
        = collapsed_lev["h0"].to!string;
      lv["lv"] = DocStructMarkupHeading.h_sect_A;
      ++lv["h0"];
      lv["h1"] = eN.bi.off;
      lv["h2"] = eN.bi.off;
      lv["h3"] = eN.bi.off;
      lv["h4"] = eN.bi.off;
      lv["h5"] = eN.bi.off;
      lv["h6"] = eN.bi.off;
      lv["h7"] = eN.bi.off;
      goto default;
    case "B":
      collapsed_lev["h1"] = collapsed_lev["h0"] + 1;
      an_object["lev_collapsed_number"]
        = collapsed_lev["h1"].to!string;
      lv["lv"] = DocStructMarkupHeading.h_sect_B;
      ++lv["h1"];
      lv["h2"] = eN.bi.off;
      lv["h3"] = eN.bi.off;
      lv["h4"] = eN.bi.off;
      lv["h5"] = eN.bi.off;
      lv["h6"] = eN.bi.off;
      lv["h7"] = eN.bi.off;
      goto default;
    case "C":
      collapsed_lev["h2"] = collapsed_lev["h1"] + 1;
      an_object["lev_collapsed_number"]
        = collapsed_lev["h2"].to!string;
      lv["lv"] = DocStructMarkupHeading.h_sect_C;
      ++lv["h2"];
      lv["h3"] = eN.bi.off;
      lv["h4"] = eN.bi.off;
      lv["h5"] = eN.bi.off;
      lv["h6"] = eN.bi.off;
      lv["h7"] = eN.bi.off;
      goto default;
    case "D":
      collapsed_lev["h3"] = collapsed_lev["h2"] + 1;
      an_object["lev_collapsed_number"]
        = collapsed_lev["h3"].to!string;
      lv["lv"] = DocStructMarkupHeading.h_sect_D;
      ++lv["h3"];
      lv["h4"] = eN.bi.off;
      lv["h5"] = eN.bi.off;
      lv["h6"] = eN.bi.off;
      lv["h7"] = eN.bi.off;
      goto default;
    case "1":
      if (lv["h3"] > eN.bi.off) {
        collapsed_lev["h4"] = collapsed_lev["h3"] + 1;
      } else if (lv["h2"] > eN.bi.off) {
        collapsed_lev["h4"] = collapsed_lev["h2"] + 1;
      } else if (lv["h1"] > eN.bi.off) {
        collapsed_lev["h4"] = collapsed_lev["h1"] + 1;
      } else if (lv["h0"] > eN.bi.off) {
        collapsed_lev["h4"] = collapsed_lev["h0"] + 1;
      }
      an_object["lev_collapsed_number"]
        = collapsed_lev["h4"].to!string;
      lv["lv"] = DocStructMarkupHeading.h_text_1;
      ++lv["h4"];
      lv["h5"] = eN.bi.off;
      lv["h6"] = eN.bi.off;
      lv["h7"] = eN.bi.off;
      goto default;
    case "2":
      if (lv["h5"] > eN.bi.off) {
        an_object["lev_collapsed_number"]
          = collapsed_lev["h5"].to!string;
      } else if (lv["h4"] > eN.bi.off) {
        collapsed_lev["h5"] = collapsed_lev["h4"] + 1;
        an_object["lev_collapsed_number"]
          = collapsed_lev["h5"].to!string;
      }
      lv["lv"] = DocStructMarkupHeading.h_text_2;
      ++lv["h5"];
      lv["h6"] = eN.bi.off;
      lv["h7"] = eN.bi.off;
      goto default;
    case "3":
      if (lv["h6"] > eN.bi.off) {
        an_object["lev_collapsed_number"]
          = collapsed_lev["h6"].to!string;
      } else if (lv["h5"] > eN.bi.off) {
        collapsed_lev["h6"] = collapsed_lev["h5"] + 1;
        an_object["lev_collapsed_number"]
          = collapsed_lev["h6"].to!string;
      }
      lv["lv"] = DocStructMarkupHeading.h_text_3;
      ++lv["h6"];
      lv["h7"] = eN.bi.off;
      goto default;
    case "4":
      if (lv["h7"] > eN.bi.off) {
        an_object["lev_collapsed_number"]
          = collapsed_lev["h7"].to!string;
      } else if (lv["h6"] > eN.bi.off) {
        collapsed_lev["h7"] = collapsed_lev["h6"] + 1;
        an_object["lev_collapsed_number"]
          = collapsed_lev["h7"].to!string;
      }
      lv["lv"] = DocStructMarkupHeading.h_text_4;
      ++lv["h7"];
      goto default;
    default:
      an_object["lev_markup_number"] = lv["lv"].to!string;
    }
    an_object["dummy_heading_status"] = (pith["dummy_heading_status"] == eN.bi.off) ? "f" : "t";
    debug(heading) { writeln(line.strip); }
  }
  struct ST_flow_heading_matched {
    string[string]  this_object;
    int[string]     line_occur;
    string          an_object_key;
    int[string]     lv;
    int[string]     collapsed_lev;
    uint[string]    pith;
    CMM             conf_make_meta;
  }
  ST_flow_heading_matched ret;
  {
    ret.this_object    = an_object;
    ret.line_occur     = line_occur;
    ret.an_object_key  = an_object_key;
    ret.lv             = lv;
    ret.collapsed_lev  = collapsed_lev;
    ret.pith           = pith;
    ret.conf_make_meta = conf_make_meta;
  }
  return ret;
}
@safe ST_flow_para_match flow_para_match_()(
  char[]         line,
  string[string]  an_object,
  string          an_object_key,
  int[string]     indent,
  bool            bullet,
  uint[string]    pith,
  int[string]     line_occur,
) {
  static auto rgx = RgxI();
  if (line_occur["para"] == eN.bi.off) {
    line = font_faces_line(line);
    // para matches
    pith["txt_is"]           = eN.txt_is.para;
    an_object[an_object_key] ~= line;
    indent = [
      "hang_position" : 0,
      "base_position" : 0,
    ];
    bullet = false;
    if (auto m = line.matchFirst(rgx.para_indent)) {
      debug(paraindent) { writeln(line); }
      indent["hang_position"] = (m["indent"]).to!int;
      indent["base_position"] = (m["indent"]).to!int;
    } else if (line.matchFirst(rgx.para_bullet)) {
      debug(parabullet) { writeln(line); }
      bullet = true;
    } else if (auto m = line.matchFirst(rgx.para_indent_hang)) {
      debug(paraindenthang) { writeln(line); }
      indent = [
        "hang_position" : (m["hang"]).to!int,
        "base_position" : (m["indent"]).to!int,
      ];
    } else if (auto m = line.matchFirst(rgx.para_bullet_indent)) {
      debug(parabulletindent) { writeln(line); }
      indent = [
        "hang_position" : (m["indent"]).to!int,
        "base_position" : (m["indent"]).to!int,
      ];
      bullet = true;
    }
    ++line_occur["para"];
  }
  ST_flow_para_match ret;
  {
    ret.pith            = pith;
    ret.this_object     = an_object;
    ret.this_object_key = an_object_key;
    ret.indent          = indent;
    ret.bullet          = bullet;
    ret.line_occur      = line_occur;
  }
  return ret;
}
@safe char[] font_faces_line()(
  char[]  textline,
) {
  static auto rgx = RgxI();
  static auto mkup = InlineMarkup();
  if (textline.match(rgx.inline_faces_line)) {
    textline = textline
      .replaceFirst(rgx.inline_emphasis_line,
        format(q"┃%s%s%s%s%s%s%s┃",
          mkup.ff_i, mkup.emph, mkup.ff_o, "$1", mkup.ff_c, mkup.emph, "$2"))
      .replaceFirst(rgx.inline_bold_line,
        format(q"┃%s%s%s%s%s%s%s┃",
          mkup.ff_i, mkup.bold, mkup.ff_o, "$1", mkup.ff_c, mkup.bold, "$2"))
      .replaceFirst(rgx.inline_underscore_line,
        format(q"┃%s%s%s%s%s%s%s┃",
          mkup.ff_i, mkup.underscore, mkup.ff_o, "$1", mkup.ff_c, mkup.underscore, "$2"))
      .replaceFirst(rgx.inline_italics_line,
        format(q"┃%s%s%s%s%s%s%s┃",
          mkup.ff_i, mkup.italic,  mkup.ff_o, "$1", mkup.ff_c, mkup.italic, "$2"));
  }
  return textline;
}
@safe ObjGenericComposite flow_table_instructions(H)(
  ObjGenericComposite  table_object,
  H                    table_head,
) {
  static auto rgx = RgxI();
  table_object.metainfo.is_of_part        = "body";
  table_object.metainfo.is_of_section     = "body";
  table_object.metainfo.is_of_type        = "block";
  table_object.metainfo.is_a              = "table";
  table_object.has.inline_notes_reg       = false;
  table_object.has.inline_notes_star      = false;
  table_object.has.inline_links           = false;
  if (auto m = table_head.matchFirst(rgx.table_head_instructions)) {
    table_object.table.heading
      = ((m["c_heading"].length > 0) && (m["c_heading"] == "h")) ? true : false;
    table_object.table.number_of_columns
      = ((m["c_num"].length > 0) && (m["c_num"].to!int > 0)) ? m["c_num"].to!int : 0;
    foreach (cw; m["c_widths"].matchAll(rgx.table_col_widths)) {
      auto x = cw.hit.matchFirst(rgx.table_col_widths_and_alignment);
      table_object.table.column_widths ~= x["width"].to!int;
      table_object.table.column_aligns ~= (x["align"].empty) ? "" : x["align"];
    }
  }
  return table_object;
}
@safe ST_flow_table_array_munge flow_table_array_munge()(
  ObjGenericComposite  table_object,
  string[][]           table_array,
) {
  static auto rgx = RgxI();
  static auto mng = InlineMarkup();
  string _table_substantive;
  ulong col_num;
  ulong col_num_;
  ulong col_num_chk = 0;
  foreach(idx_r, row; table_array) {
    debug(table_dev) { writeln("row ", idx_r); }
    col_num_ = 0;
    if (col_num == 0
    || col_num < row.length) {
      col_num = row.length;
    }
    if (col_num_chk == 0) {
      col_num_chk = col_num;
    } else if (col_num == 1) {
      debug(table_dev) { writeln("table note: "); }
    } else if (col_num_chk != col_num) {
      debug(table_dev) { writeln("warning irregular number of columns: ", col_num_chk, " != ", col_num); }
    } else {
    }
    foreach(idx_c, col; row) {
      debug(table_dev) { write(idx_c, ", "); }
      col_num_ = idx_c;
      _table_substantive ~= col ~ mng.tc_s;
      if (idx_r == 0 && table_object.table.heading) {
      } else if (col.match(rgx.numeric_col) && idx_r == 1) { // conditions reversed to avoid: gdc compiled program run segfault
        if ((table_object.table.column_aligns.length > idx_c)
        && (table_object.table.column_aligns[idx_c].matchFirst(rgx.table_col_align_match))) {
          table_object.table.column_aligns[idx_c] = table_object.table.column_aligns[idx_c];
        } else if (table_object.table.column_aligns.length > idx_c) {
          table_object.table.column_aligns[idx_c] = "r";
        } else {
          table_object.table.column_aligns ~= "r";
        }
      } else if (idx_r == 1) {
        if ((table_object.table.column_aligns.length > idx_c)
        && (table_object.table.column_aligns[idx_c].matchFirst(rgx.table_col_align_match))) {
          table_object.table.column_aligns[idx_c] = table_object.table.column_aligns[idx_c];
        } else if (table_object.table.column_aligns.length > idx_c) {
          table_object.table.column_aligns[idx_c] = "l";
        } else {
          table_object.table.column_aligns ~= "l";
        }
      }
    }
    debug(table_dev) { writeln(""); }
    if (col_num_chk > 0 && (col_num != col_num_chk)) {
    } else if (col_num == col_num_chk){
    } else {
      col_num_chk = col_num;
    }
    _table_substantive = _table_substantive.replaceFirst(rgx.table_col_separator_nl, "\n");
  }
  if (table_object.table.number_of_columns != col_num) {
    if (table_object.table.number_of_columns == 0) {
      table_object.table.number_of_columns = (col_num).to!int;
    } else {
      debug(table_dev) { writeln(table_object.table.number_of_columns, " != ", col_num); }
    }
  }
  if (table_object.table.number_of_columns == 0
  && table_object.table.column_widths.length > 0) {
    writeln(__LINE__, " ERROR");
  }
  if (table_object.table.number_of_columns > 0
  && table_object.table.column_widths.length == 0) {
    double col_w = (100.00 / table_object.table.number_of_columns);
    foreach (i; 0..table_object.table.number_of_columns) {
      table_object.table.column_widths ~= col_w;
    }
  } else if (table_object.table.number_of_columns
  != table_object.table.column_widths.length) {
    debug(table_dev) { writeln(m.hit); } // further logic required
    if (table_object.table.number_of_columns > table_object.table.column_widths.length) {
      double col_w = (100.00 - (table_object.table.column_widths).sum)
        / (table_object.table.number_of_columns - table_object.table.column_widths.length);
      foreach (i; 0..table_object.table.column_widths.length) {
        table_object.table.column_widths ~= col_w;
      }
      foreach (i; 0..(table_object.table.number_of_columns - table_object.table.column_widths.length)) {
        table_object.table.column_widths ~= col_w;
      }
    } else if (table_object.table.number_of_columns < table_object.table.column_widths.length) {
      writeln(__LINE__, " warning, ERROR");
    }
  }
  if (table_object.table.column_widths.sum > 101
  || table_object.table.column_widths.sum < 95 ) {
    writeln("sum: ", table_object.table.column_widths.sum,
      ", array: ", table_object.table.column_widths,
      ", cols: ", table_object.table.number_of_columns);
    writeln(_table_substantive);
  }
  debug(table_res) {
    writeln("aligns: ", table_object.table.column_aligns, "\n",
      "no. of columns: ", table_object.table.number_of_columns, "\n",
      "col widths: ", table_object.table.column_widths,
        " sum: ", table_object.table.column_widths.sum, "\n",
      _table_substantive);
  }
  table_object.text = _table_substantive;
  ST_flow_table_array_munge ret;
  {
    ret.table_object      = table_object;
    ret.table_array       = table_array;
  }
  return ret;
}
@system ST_flow_table_substantive_munge flow_table_substantive_munge()(
  ObjGenericComposite  table_object,
  string               table_substantive,
) {
  static auto rgx = RgxI();
  static auto munge = ObjInlineMarkupMunge();
  string[] _table_rows = (table_substantive).split(rgx.table_row_delimiter);
  string[] _table_cols;
  string[][] _table_array;
  foreach(col; _table_rows) {
    _table_cols = col.split(rgx.table_col_delimiter);
    _table_array ~= _table_cols;
  }
  {
    auto _get = table_object.flow_table_array_munge(_table_array);
    {
      table_object = _get.table_object;
      _table_array = _get.table_array; // what do you do with this? how is this passed down?
    }
  }
  ST_flow_table_substantive_munge ret;
  {
    ret.table_object      = table_object;
    ret.table_substantive = table_substantive; // has anything been changed here?
  }
  return ret;
}
@system ST_flow_table_substantive_munge flow_table_substantive_munge_special()(
  ObjGenericComposite  table_object,
  string               table_substantive,
) {
  static auto rgx = RgxI();
  static auto munge = ObjInlineMarkupMunge();
  string[] _table_rows = (table_substantive).split(rgx.table_row_delimiter_special);
  string[] _table_cols;
  string[][] _table_array;
  foreach(col; _table_rows) {
    _table_cols = col.split(rgx.table_col_delimiter_special);
    _table_array ~= _table_cols;
  }
  {
    auto _get = table_object.flow_table_array_munge(_table_array);
    {
      table_object = _get.table_object;
      _table_array = _get.table_array;
    }
  }
  ST_flow_table_substantive_munge ret;
  {
    ret.table_object      = table_object;
    ret.table_substantive = table_substantive;
  }
  return ret;
}
// abstraction functions ↑
// ↓ abstraction function emitters
@safe pure struct OCNemitter {
  int ocn_digit, ocn_object_number, ocn_on_, ocn_off_, ocn_bkidx, ocn_bkidx_;
  string object_identifier;
  bool ocn_is_off;
  @safe auto ocn_emitter(int ocn_status_flag) {
    OCNset ocn;
    assert(ocn_status_flag <= eN.ocn.reset);
    ocn_object_number              = ocn_bkidx = 0;
    object_identifier              = "";
    ocn_is_off                     = false;
    switch(ocn_status_flag) with (eN.ocn) {
    case reset:
      ocn_digit                    = ocn_on_             = 1;
      object_identifier            = "1";
      ocn_is_off                   = false;
      ocn_off_                     = ocn_bkidx_ = 0;
      break;
    case on:
      ocn_digit                    = ocn_object_number   = ++ocn_on_;
      object_identifier            = ocn_digit.to!string;
      ocn_is_off                   = false;
      break;
    case off:
      ocn_digit                    = 0;
      ocn_off_                     = ++ocn_off_;
      object_identifier            = "a" ~ ocn_off_.to!string;
      ocn_is_off                   = true;
      break;
    case bkidx:
      ocn_bkidx                    = ++ocn_bkidx_;
      break;
    case closing: // unused?
      break;
    default:
      ocn_digit                    = 0;
    }
    assert(ocn_digit >= 0);
    ocn.digit                      = ocn_digit;
    ocn.object_number              = ocn_object_number; // difference between .object_number and .digit?
    ocn.identifier                 = object_identifier;
    ocn.off                        = ocn_is_off;
    ocn.bkidx                      = ocn_bkidx;
    ocn.type                       = ocn_status_flag;
    return ocn;
  }
  invariant() {
  }
}
@safe ObjGenericComposite set_object_heading()(
  string level,
  string part,
  string section,
  string text,
) {
  ObjGenericComposite comp_obj;
  comp_obj                                                = comp_obj.init;
  comp_obj.metainfo.is_of_part                            = part;
  comp_obj.metainfo.is_of_section                         = section;
  comp_obj.metainfo.is_of_type                            = "para";
  comp_obj.metainfo.is_a                                  = "heading";
  comp_obj.text                                           = text;
  comp_obj.metainfo.ocn                                   = 0;
  if (level == "lev1") {
    comp_obj.metainfo.heading_lev_markup                  = 1;
    comp_obj.metainfo.heading_lev_collapsed               = 1;
    comp_obj.metainfo.parent_ocn                          = 1;
    comp_obj.metainfo.parent_lev_markup                   = 0;
  } else if (level == "lev4") {
    comp_obj.metainfo.heading_lev_markup                  = 4;
    comp_obj.metainfo.heading_lev_collapsed               = 1;
    comp_obj.metainfo.parent_ocn                          = 1;
    comp_obj.metainfo.parent_lev_markup                   = 0;
    comp_obj.metainfo.dom_structure_markedup_tags_status  = [ 1, 1, 0, 0, 1, 0, 0, 0]; // KEEP
    comp_obj.metainfo.dom_structure_collapsed_tags_status = [ 1, 1, 1, 0, 0, 0, 0, 0]; // KEEP
  }
  return comp_obj;
}
@safe ObjGenericComposite set_object_generic()(
  string part,
  string section,
  string type,
  string is_a,
  string text,
  int ocn,
) {
  ObjGenericComposite comp_obj;
  comp_obj                                                = comp_obj.init;
  comp_obj.metainfo.is_of_part                            = part;
  comp_obj.metainfo.is_of_section                         = section;
  comp_obj.metainfo.is_of_type                            = type;
  comp_obj.metainfo.is_a                                  = is_a;
  comp_obj.text                                           = text;
  comp_obj.metainfo.ocn                                   = ocn;
  return comp_obj;
}
@safe static struct ObjInlineMarkupMunge {
  string[string] obj_txt;
  int n_foot, n_foot_reg, n_foot_sp_asterisk, n_foot_sp_plus;
  string asterisks_, plus_;
  string obj_txt_out, tail, note;
  static auto rgx = RgxI();
  static auto mkup = InlineMarkup();
  int stage_reset_note_numbers = true;
  private auto initialize_note_numbers() {
    n_foot                          = 0;
    n_foot_reg                      = 0;
    n_foot_sp_asterisk              = 0;
    n_foot_sp_plus                  = 0;
  }
  @safe static auto images()(string obj_txt_in) {
    static auto mng = InlineMarkup();
    // url matched
    obj_txt_in = obj_txt_in.replaceAll(rgx.inline_notes_al_special, ""); // TODO reinstate when special footnotes are implemented
    if (obj_txt_in.match(rgx.smid_image_generic)) {                            // images with and without links
      debug(images) { writeln("Image: ", obj_txt_in); }
      if (obj_txt_in.match(rgx.smid_image_with_dimensions)) {
        obj_txt_in = obj_txt_in
          .replaceAll(rgx.smid_image_with_dimensions, ("$1" ~ mkup.img ~ "$2,w$3h$4 " ~ "$5"))
          .replaceAll(rgx.smid_image_delimit, ("$1"
            ~ mkup.lnk_o ~ "$2".strip ~ mkup.lnk_c
            ~ mkup.url_o ~ mkup.url_c));
        debug(images) { writeln("IMAGE with size: ", obj_txt_in); }
      } else if (obj_txt_in.match(rgx.smid_image)) {
        obj_txt_in = obj_txt_in
          .replaceAll(rgx.smid_image, ("$1" ~ mkup.img ~ "$2,w0h0" ~ "$3"))
          .replaceAll(rgx.smid_image_delimit, ("$1"
            ~ mkup.lnk_o ~ "$2".strip ~ mkup.lnk_c
            ~ mkup.url_o ~ mkup.url_c));
        debug(images) { writeln("IMAGE: ", obj_txt_in); } // decide on representation
      }
    }
    return obj_txt_in;
  }
  @safe ST_txtPlusHasFootnotes footnotes_endnotes_markup_and_number_or_stars()(string obj_txt_in, bool reset_note_numbers) {
    // endnotes (regular)
    bool flg_notes_reg  = false;
    bool flg_notes_star = false;
    bool flg_notes_plus = false;
    obj_txt_in = obj_txt_in.replaceAll(
      rgx.inline_notes_curly,
      (mkup.en_a_o ~ " $1" ~ mkup.en_a_c)
    );
    if (!(stage_reset_note_numbers) && reset_note_numbers) {
      stage_reset_note_numbers = true;
    }
    obj_txt_out = "";
    if (obj_txt_in.match(rgx.inline_notes_al_gen)) {
      string[] _tmp_txt;
      foreach (x; obj_txt_in.split("\n")) {
        if (auto m = x.matchAll(rgx.inline_text_and_note_al_)) {
          if (stage_reset_note_numbers) {
            n_foot                  = 0;
            n_foot_reg              = 0;
            n_foot_sp_asterisk      = 0;
            n_foot_sp_plus          = 0;
          }
          stage_reset_note_numbers = false;
          foreach(n; m) {
            if (n.hit.to!string.match(rgx.inline_al_delimiter_open_symbol_star)) {
              flg_notes_star =  true;
              ++n_foot_sp_asterisk;
              asterisks_ = "*";
              n_foot = n_foot_sp_asterisk;
              _tmp_txt ~= n.hit.to!string.replaceFirst(
                rgx.inline_al_delimiter_open_symbol_star,
                (mkup.en_a_o ~ replicate(asterisks_, n_foot_sp_asterisk) ~ " ")
              );
            } else if (n.hit.to!string.match(rgx.inline_al_delimiter_open_symbol_plus)) {
              flg_notes_plus =  true;
              ++n_foot_sp_plus;
              plus_ = "*";
              n_foot = n_foot_sp_plus;
              _tmp_txt ~= n.hit.to!string.replaceFirst(
                rgx.inline_al_delimiter_open_symbol_plus,
                (mkup.en_a_o ~ replicate(plus_, n_foot_sp_plus) ~ " ")
              );
            } else if (n.hit.to!string.matchFirst(rgx.inline_al_delimiter_open_regular)) {
              string _tmp_str = n.hit.to!string;
              flg_notes_reg =  true;
              foreach (q; n.hit.to!string.matchAll(rgx.inline_al_delimiter_open_regular)) {
                ++n_foot_reg;
                n_foot = n_foot_reg;
                _tmp_str = replaceFirst!(m => mkup.en_a_o ~ n_foot.to!string ~ " ")
                  (_tmp_str, rgx.inline_al_delimiter_open_regular);
              }
              _tmp_txt ~= _tmp_str;
            } else {
              _tmp_txt ~= n.hit.to!string;
            }
          }
          obj_txt_out = _tmp_txt.join("\n");
        }
      }
    } else {
      obj_txt_out = obj_txt_in;
    }
    ST_txtPlusHasFootnotes ret;
    {
      ret.obj_txt            = obj_txt_out;
      ret.has_notes_reg      = flg_notes_reg;
      ret.has_notes_star     = flg_notes_star;
      ret.has_notes_plus     = flg_notes_plus;
    }
    return ret;
  }
  @safe private ST_txtPlusHasFootnotesUrlsImages object_notes_and_links_()(
    string obj_txt_in,
    bool reset_note_numbers = false
  ) {
    obj_txt_out = "";
    bool urls = false;
    bool images_without_dimensions = false;
    tail = "";
    // special endnotes
    obj_txt_in = obj_txt_in.replaceAll(
      rgx.inline_notes_curly_sp_asterisk,
      (mkup.en_a_o ~ "*" ~ " $1" ~ mkup.en_a_c)
    );
    obj_txt_in
      = obj_txt_in.replaceAll(
        rgx.inline_notes_curly_sp_plus,
        (mkup.en_a_o ~ "+" ~ " $1" ~ mkup.en_a_c)
      );
    // image matched
    if (obj_txt_in.match(rgx.smid_image_generic)) {
      obj_txt_in = images(obj_txt_in);
      if (obj_txt_in.match(rgx.smid_mod_image_without_dimensions)) {
        images_without_dimensions = true;
      }
    }
    // url matched
    if (obj_txt_in.match(rgx.smid_inline_url)) {
      urls = true;
      obj_txt_in = obj_txt_in.links_and_images;
    }
    if (auto m = obj_txt_in.match(rgx.para_inline_link_anchor)) {
      obj_txt_in = obj_txt_in
        .replaceAll(rgx.para_inline_link_anchor, "┃$1┃");
    }
    ST_txtPlusHasFootnotes ftn = footnotes_endnotes_markup_and_number_or_stars(obj_txt_in, reset_note_numbers);
    obj_txt_out = ftn.obj_txt;
    debug(footnotes) { writeln(obj_txt_out, tail); }
    obj_txt_out = obj_txt_out ~ tail;
    debug(footnotesdone) {
      foreach(m; matchAll(obj_txt_out, (mkup.en_a_o ~ `\s*(.+?)` ~ mkup.en_a_c))) {
        writeln(m[1]);
        writeln(m.hit);
      }
    }
    ST_txtPlusHasFootnotesUrlsImages ret;
    {
      ret.obj_txt                       = obj_txt_out;
      ret.has_notes_reg                 = ftn.has_notes_reg;
      ret.has_notes_star                = ftn.has_notes_star;
      ret.has_notes_plus                = ftn.has_notes_plus;
      ret.has_urls                      = urls;
      ret.has_images_without_dimensions = images_without_dimensions;
    }
    return ret;
  }
  @safe private ST_txtPlusHasFootnotesUrlsImages object_only_()(
    string obj_txt_in,
    bool reset_note_numbers = false
  ) {
    ST_txtPlusHasFootnotesUrlsImages ret;
    {
      ret.obj_txt                       = obj_txt_in;
      ret.has_notes_reg                 = false;
      ret.has_notes_star                = false;
      ret.has_notes_plus                = false;
      ret.has_urls                      = false;
      ret.has_images_without_dimensions = false;
    }
    return ret;
  }
  ST_txtPlusHasFootnotesUrlsImages init() {
    ST_txtPlusHasFootnotesUrlsImages ret = object_notes_and_links_("");
    return ret;
  }
  invariant() {
  }
  @safe ST_txtPlusHasFootnotesUrlsImages munge_heading()(
    string obj_txt_in,
    bool reset_note_numbers = false
  ) {
    obj_txt["munge"] = obj_txt_in
     .replaceFirst(rgx.headings, "")
     .replaceFirst(rgx.object_number_off_all, "")
     .replaceFirst(rgx.markup_inline_linebreak, mkup.br_line_inline)
     .strip;
    ST_txtPlusHasFootnotesUrlsImages ret = object_notes_and_links_(obj_txt["munge"], reset_note_numbers);
    debug(munge) { writeln(__LINE__); writeln(obj_txt_in); writeln(__LINE__); writeln(obj_txt["munge"].to!string); }
    return ret;
  }
  invariant() {
  }
  @safe ST_txtPlusHasFootnotesUrlsImages munge_para()(string obj_txt_in) {
    obj_txt["munge"] = (obj_txt_in)
      .replaceFirst(rgx.para_attribs, "")
      .replaceFirst(rgx.object_number_off_all, "")
      .replaceFirst(rgx.markup_inline_linebreak, mkup.br_line_inline);
    ST_txtPlusHasFootnotesUrlsImages ret = object_notes_and_links_(obj_txt["munge"]);
    debug(munge) { writeln(__LINE__); writeln(obj_txt_in);
      writeln(__LINE__);
      writeln(obj_txt["munge"].to!string);
    }
    return ret;
  }
  @safe ST_txtPlusHasFootnotesUrlsImages munge_quote()(string obj_txt_in) {
    ST_txtPlusHasFootnotesUrlsImages ret = object_notes_and_links_(obj_txt_in.split("\n\n").join(" \\\\\n \\\\\n"));
    return ret;
  }
  invariant() {
  }
  @safe ST_txtPlusHasFootnotesUrlsImages munge_group(string obj_txt_in) {
    ST_txtPlusHasFootnotesUrlsImages ret = object_notes_and_links_(obj_txt_in.split("\n\n").join("\n" ~ mkup.br_line_spaced ~ "\n"));
    return ret;
  }
  invariant() {
  }
  @safe ST_txtPlusHasFootnotesUrlsImages munge_block()(string obj_txt_in) {
    ST_txtPlusHasFootnotesUrlsImages ret = object_notes_and_links_(obj_txt_in);
    return ret;
  }
  invariant() {
  }
  @safe auto munge_verse()(string obj_txt_in) {
    ST_txtPlusHasFootnotesUrlsImages ret = object_notes_and_links_(obj_txt_in);
    return ret;
  }
  invariant() {
  }
  @safe ST_txtPlusHasFootnotesUrlsImages munge_code()(string obj_txt_in) {
    obj_txt_in = obj_txt_in.replaceAll(rgx.space, mkup.nbsp);
    ST_txtPlusHasFootnotesUrlsImages ret = object_only_(obj_txt_in);
    return ret;
  }
  invariant() {
  }
  @safe ST_txtPlusHasFootnotesUrlsImages munge_table()(string obj_txt_in) {
    ST_txtPlusHasFootnotesUrlsImages ret = object_notes_and_links_(obj_txt_in);
    return ret;
  }
  invariant() {
  }
  @safe ST_txtPlusHasFootnotesUrlsImages munge_comment()(string obj_txt_in) {
    ST_txtPlusHasFootnotesUrlsImages ret = object_only_(obj_txt_in);
    return ret;
  }
  invariant() {
  }
}
static struct ObjInlineMarkup {
  static auto rgx = RgxI();
  static auto munge = ObjInlineMarkupMunge();
  string[string] obj_txt;
  string anchor_tag = "";
  @safe ST_txtAndAnchorTagPlusHasFootnotesUrlsImages obj_inline_markup_and_anchor_tags_and_misc(CMM)(
    string[string]   obj_,
    string           obj_key_,
    CMM              conf_make_meta,
    Flag!"_new_doc"  _new_doc
  ) {
    obj_txt["munge"]                                = obj_[obj_key_].dup;
    obj_txt["munge"]                                = (obj_["is"].match(ctRegex!(`verse|code`)))
    ? obj_txt["munge"]
    : obj_txt["munge"].strip;
    if (_new_doc) {
      anchor_tag = "";
    }
    auto x = munge.init;
    ST_txtAndAnchorTagPlusHasFootnotesUrlsImages ret;
    ret.obj_txt                       = "";
    ret.anchor_tag                    = "";
    ret.has_notes_reg                 = false;
    ret.has_notes_star                = false;
    ret.has_notes_plus                = false;
    ret.has_links                     = false;
    ret.has_images_without_dimensions = false;
    if ((obj_["is"] == "para")
      || (obj_["is"] == "heading")
      || (obj_["is"] == "quote")
      || (obj_["is"] == "group")
      || (obj_["is"] == "block")
      || (obj_["is"] == "verse")) {
      obj_txt["munge"]                              = (obj_txt["munge"]).inline_markup_faces;
      obj_txt["munge"]                              = (obj_txt["munge"]).links_and_images;
    }
    switch (obj_["is"]) {
    case "heading":
      if (_new_doc) {
        anchor_tag                                  = "";
      }
      obj_txt["munge"] = _configured_auto_heading_numbering_and_segment_anchor_tags(obj_txt["munge"], obj_, conf_make_meta, _new_doc);
      obj_txt["munge"] = _make_segment_anchor_tags_if_none_provided(obj_txt["munge"], obj_["lev"], _new_doc);
      if (auto m = obj_txt["munge"].match(rgx.heading_anchor_tag)) {
        anchor_tag                                  = m.captures[1];
      } else if (obj_["lev"] == "1") {
        writeln("heading anchor tag missing: ", obj_txt["munge"]);
      }
      x                                             = munge.munge_heading(obj_txt["munge"], reset_note_numbers);
      reset_note_numbers = false;
      goto default;
    case "para":
      x                                             = munge.munge_para(obj_txt["munge"]);
      goto default;
    case "group":
      x                                             = munge.munge_group(obj_txt["munge"]);
      goto default;
    case "block":
      x                                             = munge.munge_block(obj_txt["munge"]);
      goto default;
    case "quote":
      x                                             = munge.munge_quote(obj_txt["munge"]);
      goto default;
    case "verse":
      x                                             = munge.munge_verse(obj_txt["munge"]);
      goto default;
    case "code":
      x                                             = munge.munge_code(obj_txt["munge"]);
      goto default;
    case "table":
      x                                             = munge.munge_table(obj_txt["munge"]);
      goto default;
    case "comment":
      x                                             = munge.munge_comment(obj_txt["munge"]);
      goto default;
    case "doc_end_reset":
      munge.initialize_note_numbers();
      break;
    default:
      // para, heading, group, block, verse
      ret.obj_txt                       = x.obj_txt;
      ret.anchor_tag                    = anchor_tag;
      ret.has_notes_reg                 = x.has_notes_reg;
      ret.has_notes_star                = x.has_notes_star;
      ret.has_notes_plus                = x.has_notes_plus;
      ret.has_links                     = x.has_urls;
      ret.has_images_without_dimensions = x.has_images_without_dimensions;
      break;
    }
    anchor_tag = "";
    return ret;
  }
  invariant() {
  }
  @safe auto _clean_heading_toc_()(
    char[] heading_toc_,
  ) {
   auto m = (cast(char[]) heading_toc_).matchFirst(rgx.heading);
   heading_toc_ = (m.post).replaceAll(rgx.inline_notes_curly_gen, "");
   return heading_toc_;
  };
  @safe ST_flow_table_of_contents_gather_headings flow_table_of_contents_gather_headings(CMM)( //
    string[string]         obj_,
    CMM                    conf_make_meta,
    string[string]         tag_in_seg,
    string                 _anchor_tag,
    string[][string]       lev4_subtoc,
    ObjGenericComposite[]  the_document_toc_section,
  ) {
    ObjGenericComposite comp_obj_;
    mixin InternalMarkup;
    static auto mkup = InlineMarkup();
    char[] heading_toc_                             = (obj_["substantive"].dup.strip.to!(char[]))
      .replaceAll(rgx.inline_notes_al, "");
    heading_toc_                                    = _clean_heading_toc_(heading_toc_);
    auto attrib = "";
    string toc_txt_, subtoc_txt_;
    int[string] indent;
    if (obj_["lev_markup_number"].to!int > 0) {
      indent = [
        "hang_position" : obj_["lev_markup_number"].to!int,
        "base_position" : obj_["lev_markup_number"].to!int,
      ];
      toc_txt_ = format("%s%s%s%s#%s%s",
        mkup.lnk_o,
        heading_toc_.strip,
        mkup.lnk_c,
        mkup.url_o,
        _anchor_tag,
        mkup.url_c,
      );
      toc_txt_= toc_txt_.links_and_images;
      comp_obj_                                  = set_object_generic("frontmatter", "toc", "para", "toc", toc_txt_.to!string.strip, 0);
      comp_obj_.metainfo.identifier              = "";
      comp_obj_.metainfo.object_number_off       = true;
      comp_obj_.metainfo.object_number_type      = 0;
      comp_obj_.metainfo.dummy_heading           = (an_object["dummy_heading_status"] == "t") ? true: false;
      comp_obj_.attrib.indent_hang               = indent["hang_position"];
      comp_obj_.attrib.indent_base               = indent["base_position"];
      comp_obj_.attrib.bullet                    = false;
      comp_obj_.has.inline_links                 = true;
      the_document_toc_section                   ~= comp_obj_;
    }
    comp_obj_                                    = comp_obj_.init;
    comp_obj_.metainfo.is_of_part                = "frontmatter";
    comp_obj_.metainfo.is_of_section             = "toc";
    comp_obj_.metainfo.is_of_type                = "para";
    comp_obj_.metainfo.is_a                      = "toc";
    comp_obj_.metainfo.ocn                       = 0;
    comp_obj_.metainfo.identifier                = "";
    comp_obj_.metainfo.object_number_off         = true;
    comp_obj_.metainfo.object_number_type        = 0;
    comp_obj_.metainfo.dummy_heading             = (an_object["dummy_heading_status"] == "t") ? true: false;
    comp_obj_.attrib.bullet                      = false;
    comp_obj_.has.inline_links                   = true;
    switch (obj_["lev_markup_number"].to!int) {
    case 0: .. case 3:
      break;
    case 4:
      lev4_subtoc[tag_in_seg["seg_lv4"]] = [];
      break;
    case 5: .. case 7:
      subtoc_txt_ = format("%s%s%s%s#%s%s",
        mkup.lnk_o,
        heading_toc_.strip,
        mkup.lnk_c,
        mkup.url_o,
        _anchor_tag,
        mkup.url_c,
      );
      lev4_subtoc[tag_in_seg["seg_lv4"]]
      ~= links_and_images(obj_["lev_markup_number"]
           ~ "~ " ~ subtoc_txt_.to!string.strip
         );
      break;
    default:
      break;
    }
    ST_flow_table_of_contents_gather_headings ret;
    {
      ret.the_document_toc_section = the_document_toc_section;
      ret.lev4_subtoc              = lev4_subtoc;
    }
    return ret;
  }
  invariant() {
  }
private:
  static int[] heading_num = [ 0, 0, 0, 0 ];
  static string heading_number_auto_composite = "";
  static string heading_number_auto_composite_segname = "";
  static bool[] auto_heading_numbering = [ true, true, true, true];
  @safe static string _configured_auto_heading_numbering_and_segment_anchor_tags(CMM)(
    string           munge_,
    string[string]   obj_,
    CMM              conf_make_meta,
    bool             _new_doc,
  ) {
    if (_new_doc) {
      heading_num                         = [ 0, 0, 0, 0 ];
      heading_number_auto_composite       = "";
      auto_heading_numbering              = [ true, true, true, true];
    }
    if (conf_make_meta.make.auto_num_top_lv) {
      if (obj_["lev_markup_number"].to!int == 0) {
        heading_num[0]                    = 0;
        heading_num[1]                    = 0;
        heading_num[2]                    = 0;
        heading_num[3]                    = 0;
        heading_number_auto_composite     = "";
      }
      // auto_num_depth minimum 0
      // (1.) default 2 (1.1.1) max 3 (1.1.1.1) implement
      if (
        conf_make_meta.make.auto_num_top_lv
        > obj_["lev_markup_number"].to!uint
      ) {
        heading_num[1]                    = 0;
        heading_num[2]                    = 0;
        heading_num[3]                    = 0;
      } else if (
        conf_make_meta.make.auto_num_top_lv
          == obj_["lev_markup_number"].to!uint
      ) {
        auto_heading_numbering[0] =
          (munge_.match(rgx.auto_heading_numbering_off_lv1)) ? false : true;
        if (auto_heading_numbering[0]) {
          heading_num[0] ++;
        }
        heading_num[1]                    = 0;
        heading_num[2]                    = 0;
        heading_num[3]                    = 0;
      } else if (
        conf_make_meta.make.auto_num_top_lv
          == (obj_["lev_markup_number"].to!uint - 1)
      ) {
        auto_heading_numbering[1] =
          (munge_.match(rgx.auto_heading_numbering_off_lv2)) ? false : true;
        if (auto_heading_numbering[0]
        && auto_heading_numbering[1]) {
          heading_num[1] ++;
        }
        heading_num[2]                    = 0;
        heading_num[3]                    = 0;
      } else if (
        conf_make_meta.make.auto_num_top_lv
          == (obj_["lev_markup_number"].to!uint - 2)
      ) {
        auto_heading_numbering[2] =
          (munge_.match(rgx.auto_heading_numbering_off_lv3)) ? false : true;
        if (auto_heading_numbering[0]
        && auto_heading_numbering[1]
        && auto_heading_numbering[2]) {
          heading_num[2] ++;
        }
        heading_num[3]                    = 0;
      } else if (
        conf_make_meta.make.auto_num_top_lv
          == (obj_["lev_markup_number"].to!uint - 3)
      ) {
        auto_heading_numbering[3] =
          (munge_.match(rgx.auto_heading_numbering_off_lv4)) ? false : true;
        if (auto_heading_numbering[0]
        && auto_heading_numbering[1]
        && auto_heading_numbering[2]
        && auto_heading_numbering[3]) {
          heading_num[3] ++;
        }
      }
      if (auto_heading_numbering[0]) {
        if (heading_num[3] > 0) {
          heading_number_auto_composite
            = (conf_make_meta.make.auto_num_depth.to!uint == 3
              && auto_heading_numbering[3])
            ? (format(q"┃%s.%s.%s.%s┃",
                heading_num[0].to!string,
                heading_num[1].to!string,
                heading_num[2].to!string,
                heading_num[3].to!string
              ))
            : "";
        } else if (heading_num[2] > 0) {
          heading_number_auto_composite
            = ((conf_make_meta.make.auto_num_depth.to!uint >= 2)
              && (conf_make_meta.make.auto_num_depth.to!uint <= 3)
              && auto_heading_numbering[2])
            ? (format(q"┃%s.%s.%s┃",
                heading_num[0].to!string,
                heading_num[1].to!string,
                heading_num[2].to!string
              ))
            : "";
        } else if (heading_num[1] > 0) {
          heading_number_auto_composite
            = ((conf_make_meta.make.auto_num_depth.to!uint >= 1)
              && (conf_make_meta.make.auto_num_depth.to!uint <= 3)
              && auto_heading_numbering[1])
            ? (format(q"┃%s.%s┃",
                heading_num[0].to!string,
                heading_num[1].to!string
              ))
            : "";
        } else if (heading_num[0] > 0
          && munge_.match(rgx.auto_heading_numbering_lv1)
        ) {
          heading_number_auto_composite
            = ((conf_make_meta.make.auto_num_depth.to!uint >= 0)
              && (conf_make_meta.make.auto_num_depth.to!uint <= 3)
              && auto_heading_numbering[0])
            ? (format(q"┃%s┃",
                heading_num[0].to!string
              ))
            : "";
        } else {
          heading_number_auto_composite = "";
        }
      }
      heading_number_auto_composite_segname =
        (heading_number_auto_composite.empty)
          ? ""
          : "seg_" ~ heading_number_auto_composite;
      debug(heading_number_auto) { writeln(heading_number_auto_composite); }
      if ((!empty(heading_number_auto_composite))
      && (obj_["lev_markup_number"].to!uint >= conf_make_meta.make.auto_num_top_lv)) {
        munge_ = munge_
        .replaceFirst(rgx.heading,
          "$1~$2 " ~ heading_number_auto_composite ~ ". ")
        .replaceFirst(rgx.heading_marker_missing_tag,
          "$1~" ~ heading_number_auto_composite_segname ~ " ");
      }
    }
    return munge_;
  }
  static int heading_num_lev1 = 0;
  @safe static string _make_segment_anchor_tags_if_none_provided()(
    string munge_,
    string lev_,
    bool   _new_doc
  ) {
    if (!(munge_.match(rgx.heading_anchor_tag))) {
      if (lev_ == "A") { // (_new_doc)
        heading_num_lev1 = 0;
      }
      if (munge_.match(rgx.heading_identify_anchor_tag)) {
        if (auto m = munge_.match(rgx.heading_extract_named_anchor_tag)) {
          munge_ = munge_.replaceFirst(
            rgx.heading_marker_missing_tag,
            "$1~" ~ m.captures[1].toLower ~ "_"  ~ m.captures[2] ~ " ");
          if (auto n = munge_.match(rgx.heading_anchor_tag_plus_colon)) {
            auto tag_remunge_ = n.captures[2]
              .replaceAll(rgx.heading_marker_tag_has_colon, "..");
            munge_ = munge_.replaceFirst(rgx.heading_anchor_tag_plus_colon, n.captures[1] ~ tag_remunge_ ~ " ");
          }
        } else if (auto m = munge_.match(rgx.heading_extract_unnamed_anchor_tag)) {
          munge_ = munge_.replaceFirst(
            rgx.heading_marker_missing_tag,
            "$1~" ~ "s" ~ m.captures[1] ~ " ");
        }
      } else if (lev_ == "1") { // (if not successful) manufacture a unique anchor tag for lev == "1"
        heading_num_lev1 ++;
        munge_ = munge_.replaceFirst(
          rgx.heading_marker_missing_tag,
          "$1~" ~ "x" ~ heading_num_lev1.to!string ~ " ");
      }
    }
    return munge_;
  }
}
struct ObjAttributes {
  string[string] _obj_attrib;
  @safe string obj_attributes()(
    string              obj_is_,
    string              obj_raw,
    ObjGenericComposite comp_obj_,
  ) {
    scope(exit) {
      destroy(obj_is_);
      destroy(obj_raw);
      destroy(comp_obj_);
    }
    _obj_attrib["json"] ="{";
    switch (obj_is_) {
    case "heading":
      _obj_attrib["json"] ~= txt_heading(obj_raw);
      break;
    case "para":
      _obj_attrib["json"] ~= txt_para_and_blocks(obj_raw)
      ~ txt_para(obj_raw);
      break;
    case "code":
      _obj_attrib["json"] ~= txt_code(obj_raw);
      break;
    case "group":
      _obj_attrib["json"] ~= txt_para_and_blocks(obj_raw)
      ~ txt_group(obj_raw);
      break;
    case "block":
      _obj_attrib["json"] ~= txt_para_and_blocks(obj_raw)
      ~ txt_block(obj_raw);
      break;
    case "verse":
      _obj_attrib["json"] ~= txt_verse(obj_raw);
      break;
    case "quote":
      _obj_attrib["json"] ~= txt_quote(obj_raw);
      break;
    case "table":
      _obj_attrib["json"] ~= txt_table(obj_raw);
      break;
    case "comment":
      _obj_attrib["json"] ~= txt_comment(obj_raw);
      break;
    default:
      _obj_attrib["json"] ~= txt_para(obj_raw);
      break;
    }
    _obj_attrib["json"] ~= " }";
    _obj_attrib["json"] = _set_additional_values_parse_as_json(_obj_attrib["json"], obj_is_, comp_obj_);
    debug(structattrib) {
      if (oa_j["is"].str() == "heading") {
        writeln(_obj_attrib["json"]);
        writeln(
          "is: ", oa_j["is"].str(),
          "; object_number: ", oa_j["object_number"].integer()
        );
      }
    }
    return _obj_attrib["json"];
  }
  invariant() {
  }
  private:
  string _obj_attributes;
  @safe string txt_para_and_blocks()(string obj_txt_in) {
    if (obj_txt_in.matchFirst(rgx.para_bullet)) {
      _obj_attributes =" \"bullet\": \"true\","
      ~ " \"indent_hang\": 0,"
      ~ " \"indent_base\": 0,";
    } else if (auto m = obj_txt_in.matchFirst(rgx.para_bullet_indent)) {
      _obj_attributes =" \"bullet\": \"true\","
      ~ " \"indent_hang\": " ~ m["indent"].to!string ~ ","
      ~ " \"indent_base\": " ~ m["indent"].to!string ~ ",";
    } else if (auto m = obj_txt_in.matchFirst(rgx.para_indent_hang)) {
      _obj_attributes =" \"bullet\": \"false\","
      ~ " \"indent_hang\": " ~ m["hang"].to!string ~ ","
      ~ " \"indent_base\": " ~ m["indent"].to!string ~ ",";
    } else if (auto m = obj_txt_in.matchFirst(rgx.para_indent)) {
      _obj_attributes =" \"bullet\": \"false\","
      ~ " \"indent_hang\": " ~ m["indent"].to!string ~ ","
      ~ " \"indent_base\": " ~ m["indent"].to!string ~ ",";
    } else {
      _obj_attributes =" \"bullet\": \"false\","
      ~ " \"indent_hang\": 0,"
      ~ " \"indent_base\": 0,";
    }
    return _obj_attributes;
  }
  @safe string txt_heading()(string obj_txt_in) {
    _obj_attributes = " \"use\": \"content\","
    ~ " \"of\": \"para\","
    ~ " \"is\": \"heading\"";
    return _obj_attributes;
  }
  invariant() {
  }
  @safe string txt_para()(string obj_txt_in) {
    _obj_attributes = " \"use\": \"content\","
    ~ " \"of\": \"para\","
    ~ " \"is\": \"para\"";
    return _obj_attributes;
  }
  invariant() {
  }
  @safe string txt_quote()(string obj_txt_in) {
    _obj_attributes = " \"use\": \"content\","
    ~ " \"of\": \"block\","
    ~ " \"is\": \"quote\"";
    return _obj_attributes;
  }
  invariant() {
  }
  @safe string txt_group()(string obj_txt_in) {
    _obj_attributes = " \"use\": \"content\","
    ~ " \"of\": \"block\","
    ~ " \"is\": \"group\"";
    return _obj_attributes;
  }
  invariant() {
  }
  @safe string txt_block()(string obj_txt_in) {
    _obj_attributes = " \"use\": \"content\","
    ~ " \"of\": \"block\","
    ~ " \"is\": \"block\"";
    return _obj_attributes;
  }
  invariant() {
  }
  @safe string txt_verse()(string obj_txt_in) {
    _obj_attributes = " \"use\": \"content\","
    ~ " \"of\": \"block\","
    ~ " \"is\": \"verse\"";
    return _obj_attributes;
  }
  invariant() {
  }
  @safe string txt_code()(string obj_txt_in) {
    _obj_attributes = " \"use\": \"content\","
    ~ " \"of\": \"block\","
    ~ " \"is\": \"code\"";
    return _obj_attributes;
  }
  invariant() {
  }
  @safe string txt_table()(string obj_txt_in) {
    _obj_attributes = " \"use\": \"content\","
    ~ " \"of\": \"block\","
    ~ " \"is\": \"table\"";
    return _obj_attributes;
  }
  invariant() {
  }
  @safe string txt_comment()(string obj_txt_in) {
    _obj_attributes = " \"use\": \"comment\","
    ~ " \"of\": \"comment\","
    ~ " \"is\": \"comment\"";
    return _obj_attributes;
  }
  invariant() {
  }
  @safe string _set_additional_values_parse_as_json()(
    string              _obj_attrib,
    string              obj_is_,
    ObjGenericComposite comp_obj_,
  ) {
    JSONValue oa_j = parseJSON(_obj_attrib);
    assert(
      (oa_j.type == JSON_TYPE.OBJECT)
    );
    if (obj_is_ == "heading") {
      oa_j.object["object_number"]              = comp_obj_.metainfo.ocn;
      oa_j.object["lev_markup_number"]          = comp_obj_.metainfo.heading_lev_markup;
      oa_j.object["lev_collapsed_number"]       = comp_obj_.metainfo.heading_lev_collapsed;
      oa_j.object["heading_ptr"]                = comp_obj_.ptr.heading;
      oa_j.object["doc_object_ptr"]             = comp_obj_.ptr.doc_object;
    }
    oa_j.object["parent_object_number"]         = comp_obj_.metainfo.parent_ocn;
    oa_j.object["parent_lev_markup_number"]     = comp_obj_.metainfo.parent_lev_markup;
    _obj_attrib                                 = oa_j.toString();
    return _obj_attrib;
  }
}
struct BookIndexNuggetHash {
  string main_term, sub_term, sub_term_bits;
  int object_number_offset, object_number_endpoint;
  string[] object_numbers;
  string[][string][string] bi_hash_nugget;
  string[] bi_main_terms_split_arr;
  @safe string[][string][string] bookindex_nugget_hash(S)(
    string bookindex_section,
    OCNset obj_cite_digits,
    S      tag_in_seg,
  ) {
    debug(asserts) { static assert(is(typeof(obj_cite_digits.object_number) == int)); }
    debug(bookindexraw) {
      if (!bookindex_section.empty) {
        writeln(
          "* [bookindex] ",
          "[", obj_cite_digits.object_number.to!string, ": ", tag_in_seg["seg_lv4"], "] ", bookindex_section,
          "  - - - ",
          "[", obj_cite_digits.object_number.to!string, "] ", bookindex_section
        );
      }
    }
    static auto rgx = RgxI();
    if (!bookindex_section.empty) {
      auto bi_main_terms_split_arr
        = bookindex_section.split(rgx.bi_main_terms_split);
      foreach (bi_main_terms_content; bi_main_terms_split_arr) {
        auto bi_main_term_and_rest
          = bi_main_terms_content.split(rgx.bi_main_term_plus_rest_split);
        if (auto m = bi_main_term_and_rest[0].match(
          rgx.bi_term_and_object_numbers_match)
        ) {
          main_term = m.captures[1].strip;
          object_number_offset = m.captures[2].to!int;
          object_number_endpoint = (obj_cite_digits.object_number + object_number_offset);
          object_numbers ~= (obj_cite_digits.object_number.to!string
          ~ "-" ~ object_number_endpoint.to!string);
        } else {
          main_term = bi_main_term_and_rest[0].strip;
          object_numbers ~= obj_cite_digits.object_number.to!string;
        }
        bi_hash_nugget[main_term]["_a"] ~= object_numbers;
        object_numbers = null;
        if (bi_main_term_and_rest.length > 1) {
          auto bi_sub_terms_split_arr
            = bi_main_term_and_rest[1].split(
              rgx.bi_sub_terms_plus_object_number_offset_split
            );
          foreach (sub_terms_bits; bi_sub_terms_split_arr) {
            if (auto m = sub_terms_bits.match(rgx.bi_term_and_object_numbers_match)) {
              sub_term = m.captures[1].strip;
              object_number_offset = m.captures[2].to!int;
              object_number_endpoint = (obj_cite_digits.object_number + object_number_offset);
              object_numbers ~= (obj_cite_digits.object_number.to!string
              ~ " - " ~ object_number_endpoint.to!string);
            } else {
              sub_term = sub_terms_bits.strip;
              object_numbers ~= obj_cite_digits.object_number.to!string;
            }
            if (!empty(sub_term)) {
              bi_hash_nugget[main_term][sub_term] ~= object_numbers;
            }
            object_numbers = null;
          }
        }
      }
    }
    return bi_hash_nugget;
  }
  invariant() {
  }
}
struct BookIndexReportIndent {
  int mkn, skn;
  @safe void bookindex_report_indented()(
    string[][string][string] bookindex_unordered_hashes
  ) {
    auto mainkeys
      = bookindex_unordered_hashes.byKey.array.sort().release;
    foreach (mainkey; mainkeys) {
      debug(bookindex1) { writeln(mainkey); }
      auto subkeys
        = bookindex_unordered_hashes[mainkey].byKey.array.sort().release;
      foreach (subkey; subkeys) {
        debug(bookindex1) {
          writeln("  ", subkey);
          writeln("    ", to!string(
            bookindex_unordered_hashes[mainkey][subkey]
          ));
        }
        ++skn;
      }
      ++mkn;
    }
  }
}
struct BookIndexReportSection {
  int  mkn, skn;
  static auto rgx = RgxI();
  static auto munge = ObjInlineMarkupMunge();
  @safe void bookindex_write_section()(
    string[][string][string] bookindex_unordered_hashes
  ) {
    auto mainkeys =
      bookindex_unordered_hashes.byKey.array
      .sort!("toUpper(a) < toUpper(b)", SwapStrategy.stable).release;
    foreach (mainkey; mainkeys) {
      write("_0_1 ⑆!┨", mainkey, "┣! ");
      foreach (ref_; bookindex_unordered_hashes[mainkey]["_a"]) {
        auto go = ref_.replaceAll(rgx.book_index_go, "$1");
        write(" {", ref_, "}#", go, ", ");
      }
      writeln(" \\\\");
      bookindex_unordered_hashes[mainkey].remove("_a");
      auto subkeys =
        bookindex_unordered_hashes[mainkey].byKey.array
        .sort!("toUpper(a) < toUpper(b)", SwapStrategy.stable).release;
      foreach (subkey; subkeys) {
        write("  ", subkey, ", ");
        foreach (ref_; bookindex_unordered_hashes[mainkey][subkey]) {
          auto go = ref_.replaceAll(rgx.book_index_go, "$1");
          write(" {", ref_, "}#", go, ", ");
        }
        writeln(" \\\\");
        ++skn;
      }
      ++mkn;
    }
  }
  @system ST_bookindex backmatter_bookindex_build_abstraction_section(B)(
    string[][string][string] bookindex_unordered_hashes,
    OCNset                   obj_cite_digits,
    B                        opt_action,
  ) {
    debug(asserts) { static assert(is(typeof(obj_cite_digits.object_number) == int)); }
    mixin spineNode;
    mixin InternalMarkup;
    static auto mkup = InlineMarkup();
    string type_is;
    string lev;
    int heading_lev_markup, heading_lev_collapsed;
    string attrib;
    int[string] indent;
    auto mainkeys =
      bookindex_unordered_hashes.byKey.array
      .sort!("toUpper(a) < toUpper(b)", SwapStrategy.stable).release;
    ObjGenericComposite[] bookindex_section;
    ObjGenericComposite comp_obj_;
    auto node_para_int_ = node_metadata_para_int;
    auto node_para_str_ = node_metadata_para_str;
    if ((mainkeys.length > 0)
    && (opt_action.backmatter
    && opt_action.section_bookindex)) {
      string bi_tmp;
      string[] bi_tmp_tags;
      {
        comp_obj_                                     =  set_object_heading("lev1", "backmatter", "bookindex", "Book Index");
        comp_obj_.metainfo.identifier                 = "";
        comp_obj_.metainfo.dummy_heading              = false;
        comp_obj_.metainfo.object_number_off          = false;
        comp_obj_.metainfo.object_number_type         = 0;
        comp_obj_.tags.segment_anchor_tag_epub        = "_part_book_index";
        comp_obj_.tags.anchor_tag_html                = comp_obj_.tags.segment_anchor_tag_epub;
        comp_obj_.tags.in_segment_html                = "bookindex";
        comp_obj_.tags.anchor_tags                    = ["section_bookindex"];
        comp_obj_.has.inline_links                    = true;
        bookindex_section                             ~= comp_obj_;
        tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"]            = comp_obj_.tags.in_segment_html;
        tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub;
        ++mkn;
      }
      {
        comp_obj_                                     = set_object_heading("lev4", "backmatter", "bookindex", "Index");
        comp_obj_.metainfo.identifier                 = "";
        comp_obj_.metainfo.dummy_heading              = true;
        comp_obj_.metainfo.object_number_off          = true;
        comp_obj_.metainfo.object_number_type         = 0;
        comp_obj_.tags.segment_anchor_tag_epub        = "bookindex";
        comp_obj_.tags.anchor_tag_html                = comp_obj_.tags.segment_anchor_tag_epub;
        comp_obj_.tags.in_segment_html                = comp_obj_.tags.anchor_tag_html;
        comp_obj_.metainfo.heading_lev_collapsed      = 2;
        comp_obj_.has.inline_links                    = false;
        comp_obj_.tags.anchor_tags                    = ["bookindex"];
        bookindex_section                             ~= comp_obj_;
        tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"]            = comp_obj_.tags.in_segment_html;
        tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub;
        ++mkn;
      }
      import std.array : appender;
      auto buffer = appender!(char[])();
      string[dchar] transTable = [' ' : "_"];
      foreach (mainkey; mainkeys) {
        bi_tmp_tags = [""];
        bi_tmp = mkup.ff_i ~ mkup.bold ~ mkup.ff_o ~ mainkey ~ mkup.ff_c ~ mkup.bold ~ " ";
        buffer.clear();
        bi_tmp_tags ~= translate(mainkey, transTable);
        auto bkidx_lnk(string locs) {
          string markup = "";
          if (auto m = locs.matchFirst(rgx.book_index_go)) {
            markup
              = links_and_images("{ " ~ m["link"] ~ " }"
              ~ "#" ~ m["ocn"] ~ ", ");
          } else {
            writeln(__LINE__, ": ", locs);
          }
          return markup;
        }
        foreach (ref_; bookindex_unordered_hashes[mainkey]["_a"]) {
          bi_tmp ~= bkidx_lnk(ref_);
        }
        bi_tmp ~= " \\\\\n    ";
        bookindex_unordered_hashes[mainkey].remove("_a");
        auto subkeys =
          bookindex_unordered_hashes[mainkey].byKey.array
          .sort!("toUpper(a) < toUpper(b)", SwapStrategy.stable).release;
        foreach (subkey; subkeys) {
          bi_tmp ~= subkey ~ ", ";
          buffer.clear();
          bi_tmp_tags ~= translate(subkey, transTable);
          foreach (ref_; bookindex_unordered_hashes[mainkey][subkey]) {
            bi_tmp ~= bkidx_lnk(ref_);
          }
          bi_tmp ~= " \\\\\n    ";
          ++skn;
        }
        bi_tmp                                             = bi_tmp.replaceFirst(rgx.trailing_linebreak, "");
        comp_obj_                                          = set_object_generic("backmatter", "bookindex", "para", "bookindex", bi_tmp.to!string.strip, 0);
        comp_obj_.metainfo.identifier                      = "";
        comp_obj_.metainfo.object_number_off               = true;
        comp_obj_.metainfo.object_number_type              = 0;
        comp_obj_.tags.anchor_tags                         = bi_tmp_tags;
        comp_obj_.attrib.indent_hang                       = 0;
        comp_obj_.attrib.indent_base                       = 1;
        comp_obj_.attrib.bullet                            = false;
        comp_obj_.has.inline_links                         = true;
        comp_obj_.text                                     = bi_tmp.to!string.strip;
        bookindex_section                                  ~= comp_obj_;
        ++mkn;
      }
    } else {                              // no book index, (figure out what to do here)
      comp_obj_                                       = set_object_heading("lev1", "backmatter", "bookindex", "(skip) there is no Book Index");
      comp_obj_.metainfo.identifier                   = "";
      comp_obj_.metainfo.dummy_heading                = true;
      comp_obj_.metainfo.object_number_off            = true;
      bookindex_section                               ~= comp_obj_;
    }
    ST_bookindex ret;
    {
      ret.bookindex = bookindex_section;
      ret.ocn       = obj_cite_digits;
    }
    return ret;
  }
}
struct NotesSection {
  string[string] object_notes;
  int previous_count;
  int mkn;
  static auto rgx = RgxI();
  @safe private auto gather_notes_for_endnote_section(
    ObjGenericComposite[] contents_am,
    string[string]        tag_in_seg,
    int                   cntr,
  ) {
    assert((contents_am[cntr].metainfo.is_a == "para")
    || (contents_am[cntr].metainfo.is_a     == "heading")
    || (contents_am[cntr].metainfo.is_a     == "quote")
    || (contents_am[cntr].metainfo.is_a     == "group")
    || (contents_am[cntr].metainfo.is_a     == "block")
    || (contents_am[cntr].metainfo.is_a     == "verse"));
    assert(cntr >= previous_count);
    assert(
      (contents_am[cntr].text).match(
      rgx.inline_notes_al_all_note)
    );
    mixin InternalMarkup;
    previous_count = cntr;
    static auto mkup = InlineMarkup();
    static auto munge = ObjInlineMarkupMunge();
    foreach(m;
      (contents_am[cntr].text).matchAll(
        rgx.inline_notes_al_special_char_note)
    ) {
      debug(endnotes_build) { writeln(
          "{", mkup.ff_i, mkup.superscript, mkup.ff_o, m["char"], ".", mkup.ff_c, mkup.superscript, "}"
          ~ mkup.mark_internal_site_lnk,
          tag_in_seg["seg_lv4"],
            ".fnSuffix#noteref_\n  ", m["char"], " ",
          m["note"]); // sometimes need segment name (segmented html & epub)
      }
      // you need anchor for segments at this point ->
      object_notes["anchor"] ~= "note_" ~ m["char"] ~ "』";
      object_notes["notes"]  ~= (tag_in_seg["seg_lv4"].empty)
      ? (links_and_images(
          "{" ~ mkup.ff_i ~ mkup.superscript  ~ mkup.ff_o ~ m["char"] ~ "." ~ mkup.ff_c  ~ mkup.superscript  ~ "}#noteref_"
          ~ m["char"]) ~ " "
          ~ m["note"] ~ "』"
        )
      : (links_and_images(
          "{" ~ mkup.ff_i ~ mkup.superscript ~ mkup.ff_o ~ m["char"] ~ "." ~ mkup.ff_c  ~ mkup.superscript ~ "}"
           ~ mkup.mark_internal_site_lnk
           ~ tag_in_seg["seg_lv4"]
           ~ ".fnSuffix#noteref_"
           ~ m["char"]) ~ " "
           ~ m["note"] ~ "』"
        );
    }
    foreach(m;
      (contents_am[cntr].text).matchAll(
        rgx.inline_notes_al_regular_number_note)
    ) {
      debug(endnotes_build) { writeln(
          "{", mkup.ff_i, mkup.superscipt, mkup.ff_o, m["num"], ".", mkup.ff_c, mkup.superscipt, "}"
          ~ mkup.mark_internal_site_lnk,
          tag_in_seg["seg_lv4"],
            ".fnSuffix#noteref_\n  ", m["num"], " ",
          m["note"]); // sometimes need segment name (segmented html & epub)
      }
      // you need anchor for segments at this point ->
      object_notes["anchor"] ~= "note_" ~ m["num"] ~ "』";
      object_notes["notes"]  ~= (tag_in_seg["seg_lv4"].empty)
      ? (links_and_images(
          "{" ~ mkup.ff_i ~ mkup.superscript  ~ mkup.ff_o ~ m["num"] ~ "." ~ mkup.ff_c  ~ mkup.superscript  ~ "}#noteref_"
          ~ m["num"]) ~ " "
          ~ m["note"] ~ "』"
        )
      : (links_and_images(
          "{" ~ mkup.ff_i ~ mkup.superscript ~ mkup.ff_o ~ m["num"] ~ "." ~ mkup.ff_c  ~ mkup.superscript ~ "}"
           ~ mkup.mark_internal_site_lnk
           ~ tag_in_seg["seg_lv4"]
           ~ ".fnSuffix#noteref_"
           ~ m["num"]) ~ " "
           ~ m["note"] ~ "』"
        );
    }
    return object_notes;
  }
  @safe private auto gathered_notes() {
    string[][string] endnotes_;
    if (object_notes.length > 1) {
      endnotes_["notes"] = (object_notes["notes"].split(rgx.break_string))[0..$-1];
      endnotes_["anchor"] = (object_notes["anchor"].split(rgx.break_string))[0..$-1];
    } else {
      endnotes_["notes"] = [];
      endnotes_["anchor"] = [];
    }
    return endnotes_;
  }
  @safe private ST_endnotes backmatter_endnote_objects(O)(
    OCNset         obj_cite_digits,
    O              opt_action,
  ) {
    mixin spineNode;
    ObjGenericComposite[] the_document_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_;
    if ((endnotes_["notes"].length > 0)
    && (opt_action.backmatter && opt_action.section_endnotes)) {
      {
        comp_obj_                                     = set_object_heading("lev1", "backmatter", "endnotes", "Endnotes");
        comp_obj_.metainfo.identifier                 = "";
        comp_obj_.metainfo.dummy_heading              = false;
        comp_obj_.metainfo.object_number_off          = false;
        comp_obj_.metainfo.object_number_type         = 0;
        comp_obj_.tags.segment_anchor_tag_epub        = "_part_endnotes";
        comp_obj_.tags.anchor_tag_html                = comp_obj_.tags.segment_anchor_tag_epub;
        comp_obj_.tags.in_segment_html                = "endnotes";
        comp_obj_.tags.anchor_tags                    = ["section_endnotes"];
        the_document_endnotes_section                 ~= comp_obj_;
        tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"]            = comp_obj_.tags.in_segment_html;
        tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub;
        ++mkn;
      }
      {
        comp_obj_                                     = set_object_heading("lev4", "backmatter", "endnotes", "Endnotes");
        comp_obj_.metainfo.identifier                 = "";
        comp_obj_.metainfo.dummy_heading              = true;
        comp_obj_.metainfo.object_number_off          = true;
        comp_obj_.metainfo.object_number_type         = 0;
        comp_obj_.tags.segment_anchor_tag_epub        = "endnotes";
        comp_obj_.tags.anchor_tag_html                = comp_obj_.tags.segment_anchor_tag_epub;
        comp_obj_.tags.in_segment_html                = comp_obj_.tags.anchor_tag_html;
        comp_obj_.tags.anchor_tags                    = ["endnotes"];
        the_document_endnotes_section                 ~= comp_obj_;
        tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"]            = comp_obj_.tags.in_segment_html;
        tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub;
        ++mkn;
      }
    } else {
      comp_obj_                                       = set_object_heading("lev1", "empty", "empty", "(skip) there are no Endnotes");
      comp_obj_.metainfo.identifier                   = "";
      comp_obj_.metainfo.dummy_heading                = true;
      comp_obj_.metainfo.object_number_off            = true;
      comp_obj_.metainfo.object_number_type           = 0;
      the_document_endnotes_section                   ~= comp_obj_;
    }
    if (opt_action.backmatter && opt_action.section_endnotes) {
      ObjGenericComposite comp_obj_endnote_;
      comp_obj_endnote_                                       = set_object_generic("backmatter", "endnotes", "para", "endnote", "", 0);
      comp_obj_endnote_.metainfo.identifier                   = "";
      // comp_obj_.metainfo.dummy_heading                     = false;
      comp_obj_.metainfo.object_number_off                    = true;
      comp_obj_.metainfo.object_number_type                   = 0;
      comp_obj_endnote_.attrib.indent_hang                    = 0;
      comp_obj_endnote_.attrib.indent_base                    = 0;
      comp_obj_endnote_.attrib.bullet                         = false;
      foreach (i, endnote; endnotes_["notes"]) {
        auto     m                                            = endnote.matchFirst(rgx.note_ref);
        string   notenumber                                   = m["ref"].to!string;
        string   anchor_tag                                   = "note_" ~ notenumber;
        comp_obj_endnote_.tags.anchor_tags                    = [ endnotes_["anchor"][i] ];
        comp_obj_endnote_.has.inline_links                    = true;
        comp_obj_endnote_.text                                = endnote.inline_markup_faces.strip;
        the_document_endnotes_section                         ~= comp_obj_endnote_;
      }
    }
    ST_endnotes ret;
    {
      ret.endnotes = the_document_endnotes_section;
      ret.ocn      = obj_cite_digits;
    }
    return ret;
  }
}
@system public ST_biblio_section backmatter_make_the_bibliography_section()(
  string[]     biblio_unsorted_incomplete,
  JSONValue[]  bib_arr_json,
) {
  Bibliography biblio = Bibliography();
  ObjGenericComposite comp_obj_;
  static auto mkup = InlineMarkup();
  ST_flow_bibliography _get = biblio.flow_bibliography_(biblio_unsorted_incomplete, bib_arr_json);
  JSONValue[] biblio_ordered;
  biblio_ordered            = _get.biblio_sorted;
  if (biblio_ordered.length > 0) {
    {
      comp_obj_                                 = set_object_heading("lev1", "backmatter", "bibliography", "Bibliography");
      comp_obj_.metainfo.identifier             = "";
      comp_obj_.metainfo.dummy_heading          = false;
      comp_obj_.metainfo.object_number_off      = false;
      comp_obj_.metainfo.object_number_type     = 0;
      comp_obj_.tags.segment_anchor_tag_epub    = "_part_bibliography";
      comp_obj_.tags.anchor_tag_html            = comp_obj_.tags.segment_anchor_tag_epub;
      comp_obj_.tags.in_segment_html            = "bibliography";
      comp_obj_.tags.anchor_tags                = ["section_bibliography"];
      comp_obj_.metainfo.dom_structure_markedup_tags_status  = [ 1, 1, 0, 0, 0, 0, 0, 0];
      comp_obj_.metainfo.dom_structure_collapsed_tags_status = [ 1, 1, 0, 0, 0, 0, 0, 0];
      the_document_bibliography_section         ~= comp_obj_;
      tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"]            = comp_obj_.tags.in_segment_html;
      tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub;
    }
    {
      comp_obj_                                 = set_object_heading("lev4", "backmatter", "bibliography", "Bibliography");
      comp_obj_.metainfo.identifier             = "";
      comp_obj_.metainfo.dummy_heading          = true;
      comp_obj_.metainfo.object_number_off      = true;
      comp_obj_.metainfo.object_number_type     = 0;
      comp_obj_.tags.segment_anchor_tag_epub    = "bibliography";
      comp_obj_.tags.anchor_tag_html            = comp_obj_.tags.segment_anchor_tag_epub;
      comp_obj_.tags.in_segment_html            = comp_obj_.tags.anchor_tag_html;
      comp_obj_.tags.anchor_tags                = ["bibliography"];
      the_document_bibliography_section         ~= comp_obj_;
      tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"]            = comp_obj_.tags.in_segment_html;
      tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub;
    }
    {
      string out_;
      foreach (entry; biblio_ordered) {
        out_ = format("%s \"%s\"%s%s%s%s%s%s%s%s%s.",
          ((entry["author"].str.empty) ? entry["editor"].str : entry["author"].str),
          entry["fulltitle"].str,
          ((entry["journal"].str.empty) ? "" : ", " ~ mkup.ff_i ~ mkup.italic ~ mkup.ff_o ~ entry["journal"].str ~ mkup.ff_c ~ mkup.italic),
          ((entry["volume"].str.empty) ? "" : ", " ~ entry["volume"].str),
          ((entry["in"].str.empty) ? "" : ", " ~ entry["in"].str),
          ((!(entry["author"].str.empty) && (!(entry["editor"].str.empty))) ? entry["editor"].str : ""),
          ", " ~ entry["year"].str,
          ((entry["pages"].str.empty) ? "" : ", " ~ entry["pages"].str),
          ((entry["publisher"].str.empty) ? "" : ", " ~ entry["publisher"].str),
          ((entry["place"].str.empty) ? "" : ", " ~ entry["place"].str),
          ((entry["url"].str.empty) ? "" : ", [" ~ entry["url"].str ~ "]"),
        );
        comp_obj_                                   = set_object_generic("backmatter", "bibliography", "para", "bibliography", out_.to!string.strip, 0);
        comp_obj_.metainfo.identifier               = "";
        comp_obj_.metainfo.object_number_off        = true;
        comp_obj_.metainfo.object_number_type       = 0;
        comp_obj_.attrib.indent_hang                = 0;
        comp_obj_.attrib.indent_base                = 1;
        comp_obj_.attrib.bullet                     = bullet;
        comp_obj_.tags.anchor_tags                  = [anchor_tag];
        the_document_bibliography_section           ~= comp_obj_;
      }
    }
  } else {
    comp_obj_                                   = set_object_heading("lev1", "empty", "empty", "(skip) there is no Bibliography");
    comp_obj_.metainfo.identifier               = "";
    comp_obj_.metainfo.dummy_heading            = true;
    comp_obj_.metainfo.object_number_off        = true;
    comp_obj_.metainfo.object_number_type       = 0;
    the_document_bibliography_section           ~= comp_obj_;
  }
  debug(bibliosection) { foreach (o; the_document_bibliography_section) { writeln(o.text); } }
  ST_biblio_section ret;
  {
    ret.bibliography_section = the_document_bibliography_section;
    ret.tag_assoc            = tag_assoc; //
  }
  return ret;
}
struct Bibliography {
  @system public ST_flow_bibliography flow_bibliography_()(
    string[]    biblio_unsorted_incomplete,
    JSONValue[] bib_arr_json
  ) {
    JSONValue[] biblio_unsorted
      = biblio_make_unsorted_array_of_json_objects(biblio_unsorted_incomplete, bib_arr_json); // TODO lookat returns
    biblio_arr_json = [];
    biblio_unsorted_incomplete = [];
    JSONValue[] biblio_sorted__ = biblio_sort(biblio_unsorted);
    debug(biblio0) {
      biblio_debug(biblio_sorted__);
      writeln("---");
      writeln("unsorted incomplete: ", biblio_unsorted_incomplete.length);
      writeln("json:                ", bib_arr_json.length);
      writeln("unsorted:            ", biblio_unsorted.length);
      writeln("sorted:              ", biblio_sorted__.length);
      int cntr;
      int[7] x;
      while (cntr < x.length) {
        writeln(cntr, ": ", biblio_sorted__[cntr]["fulltitle"]);
        cntr++;
      }
    }
    ST_flow_bibliography ret;
    {
      ret.biblio_sorted  = biblio_sorted__;
      ret.bib_arr_json  = bib_arr_json;
      ret.biblio_unsorted_incomplete  = biblio_unsorted_incomplete;
    }
    return ret;
  }
  @system final private JSONValue[] biblio_make_unsorted_array_of_json_objects()(
    string[]      biblio_unordered,
    JSONValue[]   bib_arr_json
  ) {
    foreach (bibent; biblio_unordered) {
      // update bib to include deemed_author, needed for:
      // sort_bibliography_array_by_deemed_author_year_title
      // either: sort on multiple fields, or; create such sort field
      JSONValue j = parseJSON(bibent);
      if (!empty(j["fulltitle"].str)) {
        if (!empty(j["author_raw"].str)) {
          j["deemed_author"] = j["author_arr"][0];
        } else if (!empty(j["editor_raw"].str)) {
          j["deemed_author"] = j["editor_arr"][0];
        }
        j["sortby_deemed_author_year_title"] = (
          j["deemed_author"].str ~
           "; " ~
           j["year"].str ~
           "; "  ~
           j["fulltitle"].str
        );
      }
      bib_arr_json ~= j;
    }
    return bib_arr_json.dup;
  }
  @system final private JSONValue[] biblio_sort()(JSONValue[] biblio_unordered) {
    JSONValue[] biblio_sorted_;
    biblio_sorted_
      = sort!((a, b){
        return ((a["sortby_deemed_author_year_title"].str) < (b["sortby_deemed_author_year_title"].str));
      })(biblio_unordered).array;
    debug(bibliosorted) {
      foreach (j; biblio_sorted_) {
        if (!empty(j["fulltitle"].str)) { writeln(j["sortby_deemed_author_year_title"]); }
      }
    }
    return biblio_sorted_;
  }
  @system void biblio_debug()(JSONValue[] biblio_sorted) {
    debug(biblio0) {
      foreach (j; biblio_sorted) {
        if (!empty(j["fulltitle"].str)) { writeln(j["sortby_deemed_author_year_title"]); }
      }
    }
  }
}
@system public ObjGenericComposite[] backmatter_gather_table_of_contents(
  ObjGenericComposite[] the_document_endnotes_section,
  ObjGenericComposite[] the_document_glossary_section,
  ObjGenericComposite[] the_document_bibliography_section,
  ObjGenericComposite[] the_document_bookindex_section,
  ObjGenericComposite[] the_document_blurb_section,
) {
  ObjGenericComposite[] toc_section_backmatter;
  string toc_txt_;
  static auto mkup = InlineMarkup();
  ObjGenericComposite   comp_obj_;
  int[string] indent = [
    "hang_position" : 1,
    "base_position" : 1,
  ];
  comp_obj_                                          = set_object_generic("frontmatter", "toc", "para", "toc", "", 0);
  comp_obj_.metainfo.identifier                      = "";
  comp_obj_.metainfo.object_number_off               = true;
  comp_obj_.metainfo.object_number_type              = 0;
  comp_obj_.attrib.indent_hang                       = indent["hang_position"];
  comp_obj_.attrib.indent_base                       = indent["base_position"];
  comp_obj_.attrib.bullet                            = false;
  if (the_document_endnotes_section.length > 1) {
    toc_txt_ = format("%s%s%s%s#%s%s",
      mkup.lnk_o,
      "Endnotes",
      mkup.lnk_c,
      mkup.url_o,
      "endnotes",
      mkup.url_c,
    );
    toc_txt_= toc_txt_.links_and_images;
    comp_obj_.text                                   = toc_txt_.to!string.strip;
    comp_obj_.has.inline_links                       = true;
    toc_section_backmatter                           ~= comp_obj_;
  }
  if (the_document_glossary_section.length > 1) {
    toc_txt_ = format("%s%s%s%s#%s%s",
      mkup.lnk_o,
      "Glossary",
      mkup.lnk_c,
      mkup.url_o,
      "glossary",
      mkup.url_c,
    );
    toc_txt_= toc_txt_.links_and_images;
    comp_obj_.text                                   = toc_txt_.to!string.strip;
    comp_obj_.has.inline_links                       = true;
    toc_section_backmatter                           ~= comp_obj_;
  }
  if (the_document_bibliography_section.length > 1){
    toc_txt_ = format("%s%s%s%s#%s%s",
      mkup.lnk_o,
      "Bibliography",
      mkup.lnk_c,
      mkup.url_o,
      "bibliography",
      mkup.url_c,
    );
    toc_txt_= toc_txt_.links_and_images;
    comp_obj_.text                                   = toc_txt_.to!string.strip;
    comp_obj_.has.inline_links                       = true;
    toc_section_backmatter                           ~= comp_obj_;
  }
  if (the_document_bookindex_section.length > 1) {
    toc_txt_ = format("%s%s%s%s#%s%s",
      mkup.lnk_o,
      "Book Index",
      mkup.lnk_c,
      mkup.url_o,
      "bookindex",
      mkup.url_c,
    );
    toc_txt_= toc_txt_.links_and_images;
    comp_obj_.text                                   = toc_txt_.to!string.strip;
    comp_obj_.has.inline_links                       = true;
    toc_section_backmatter                           ~= comp_obj_;
  }
  if (the_document_blurb_section.length > 1) {
    toc_txt_ = format("%s%s%s%s#%s%s",
      mkup.lnk_o,
      "Blurb",
      mkup.lnk_c,
      mkup.url_o,
      "blurb",
      mkup.url_c,
    );
    toc_txt_= toc_txt_.links_and_images;
    comp_obj_.has.inline_links                       = true;
    comp_obj_.text                                   = toc_txt_.to!string.strip;
    toc_section_backmatter                           ~= comp_obj_;
  }
  debug(toc) {
    writefln( "%s %s", __LINE__,);
    foreach (toc_linked_heading; toc_section_backmatter) {
      writeln(mkup.indent_by_spaces_provided(toc_linked_heading.attrib.indent_hang), toc_linked_heading.text);
    }
  }
  return toc_section_backmatter;
}
@system public ST_ancestors after_doc_determine_ancestors(
  ObjGenericComposite[] the_document_body_section,
  ObjGenericComposite[] the_document_endnotes_section,
  ObjGenericComposite[] the_document_glossary_section,
  ObjGenericComposite[] the_document_bibliography_section,
  ObjGenericComposite[] the_document_bookindex_section,
  ObjGenericComposite[] the_document_blurb_section,
) {
  @safe int[] _get_ancestors_markup(ObjGenericComposite obj, int[] _ancestors_markup) {
    if (obj.metainfo.is_a == "heading") {
      debug(dom) { writeln(obj.text); }
      if (obj.metainfo.heading_lev_markup == 1) {
        _ancestors_markup = [
          _ancestors_markup[0],
          0,0,0,0,0,0,0
        ];
      }
      if (obj.metainfo.heading_lev_markup == 2) {
        _ancestors_markup = [
          _ancestors_markup[0],
          _ancestors_markup[1],
          0,0,0,0,0,0
        ];
      }
      if (obj.metainfo.heading_lev_markup == 3) {
        _ancestors_markup = [
          _ancestors_markup[0],
          _ancestors_markup[1],
          _ancestors_markup[2],
          0,0,0,0,0
        ];
      }
      if (obj.metainfo.heading_lev_markup == 4) {
        _ancestors_markup = [
          _ancestors_markup[0],
          _ancestors_markup[1],
          _ancestors_markup[2],
          _ancestors_markup[3],
          0,0,0,0
        ];
      }
      if (obj.metainfo.heading_lev_markup == 5) {
        _ancestors_markup = [
          _ancestors_markup[0],
          _ancestors_markup[1],
          _ancestors_markup[2],
          _ancestors_markup[3],
          _ancestors_markup[4],
          0,0,0
        ];
      }
      if (obj.metainfo.heading_lev_markup == 6) {
        _ancestors_markup = [
          _ancestors_markup[0],
          _ancestors_markup[1],
          _ancestors_markup[2],
          _ancestors_markup[3],
          _ancestors_markup[4],
          _ancestors_markup[5],
          0,0
        ];
      }
      if (obj.metainfo.heading_lev_markup == 7) {
        _ancestors_markup = [
          _ancestors_markup[0],
          _ancestors_markup[1],
          _ancestors_markup[2],
          _ancestors_markup[3],
          _ancestors_markup[4],
          _ancestors_markup[5],
          _ancestors_markup[6],
          0
        ];
      }
      if (obj.metainfo.heading_lev_markup == 8) {
        _ancestors_markup = [
          _ancestors_markup[0],
          _ancestors_markup[1],
          _ancestors_markup[2],
          _ancestors_markup[3],
          _ancestors_markup[4],
          _ancestors_markup[5],
          _ancestors_markup[6],
          _ancestors_markup[7]
        ];
      }
      _ancestors_markup[obj.metainfo.heading_lev_markup] = obj.metainfo.ocn;
    }
    debug(ancestor_markup) { writeln("marked up: ", _ancestors_markup); }
    return _ancestors_markup;
  }
  @safe int[] _get_ancestors_collapsed(ObjGenericComposite obj, int[] _ancestors_collapsed) {
    if (obj.metainfo.is_a == "heading") {
      if (obj.metainfo.heading_lev_collapsed == 1) {
        _ancestors_collapsed = [
          _ancestors_collapsed[0],
          0,0,0,0,0,0,0
        ];
      }
      if (obj.metainfo.heading_lev_collapsed == 2) {
        _ancestors_collapsed = [
          _ancestors_collapsed[0],
          _ancestors_collapsed[1],
          0,0,0,0,0,0
        ];
      }
      if (obj.metainfo.heading_lev_collapsed == 3) {
        _ancestors_collapsed = [
          _ancestors_collapsed[0],
          _ancestors_collapsed[1],
          _ancestors_collapsed[2],
          0,0,0,0,0
        ];
      }
      if (obj.metainfo.heading_lev_collapsed == 4) {
        _ancestors_collapsed = [
          _ancestors_collapsed[0],
          _ancestors_collapsed[1],
          _ancestors_collapsed[2],
          _ancestors_collapsed[3],
          0,0,0,0
        ];
      }
      if (obj.metainfo.heading_lev_collapsed == 5) {
        _ancestors_collapsed = [
          _ancestors_collapsed[0],
          _ancestors_collapsed[1],
          _ancestors_collapsed[2],
          _ancestors_collapsed[3],
          _ancestors_collapsed[4],
          0,0,0
        ];
      }
      if (obj.metainfo.heading_lev_collapsed == 6) {
        _ancestors_collapsed = [
          _ancestors_collapsed[0],
          _ancestors_collapsed[1],
          _ancestors_collapsed[2],
          _ancestors_collapsed[3],
          _ancestors_collapsed[4],
          _ancestors_collapsed[5],
          0,0
        ];
      }
      if (obj.metainfo.heading_lev_collapsed == 7) {
        _ancestors_collapsed = [
          _ancestors_collapsed[0],
          _ancestors_collapsed[1],
          _ancestors_collapsed[2],
          _ancestors_collapsed[3],
          _ancestors_collapsed[4],
          _ancestors_collapsed[5],
          _ancestors_collapsed[6],
          0
        ];
      }
      if (obj.metainfo.heading_lev_collapsed == 8) {
        _ancestors_collapsed = [
          _ancestors_collapsed[0],
          _ancestors_collapsed[1],
          _ancestors_collapsed[2],
          _ancestors_collapsed[3],
          _ancestors_collapsed[4],
          _ancestors_collapsed[5],
          _ancestors_collapsed[6],
          _ancestors_collapsed[7]
        ];
      }
      _ancestors_collapsed[obj.metainfo.heading_lev_collapsed] = obj.metainfo.ocn;
    }
    debug(ancestor_collapsed) { writeln("collapsed: ", _ancestors_collapsed); }
    return _ancestors_collapsed;
  }
  // multiple 1~ levels, loop through document body
  if (the_document_body_section.length > 1) {
    int[] _ancestors_markup = [0,0,0,0,0,0,0,0];
    int[][] _ancestors_markup_;
    _ancestors_markup = [1,0,0,0,0,0,0,0];
    _ancestors_markup_ ~= _ancestors_markup;
    int[] _ancestors_collapsed = [0,0,0,0,0,0,0,0];
    int[][] _ancestors_collapsed_;
    _ancestors_collapsed = [1,0,0,0,0,0,0,0];
    _ancestors_collapsed_ ~= _ancestors_collapsed;
    foreach (ref obj; the_document_body_section) {
      if (obj.metainfo.is_a == "heading") {
        obj.metainfo.markedup_ancestors = _get_ancestors_markup(obj, _ancestors_markup);
        obj.metainfo.collapsed_ancestors = _get_ancestors_collapsed(obj, _ancestors_collapsed);
        obj.metainfo.parent_ocn = obj.metainfo.markedup_ancestors[obj.metainfo.parent_lev_markup];
      }
    }
    debug(ancestors) {
      writeln("ancestors markup o_n:    ", obj.metainfo.markedup_ancestors);
      writeln("ancestors collapsed o_n: ", obj.metainfo.markedup_ancestors);
    }
  }
  ST_ancestors ret;
  ret.the_document_body_section         = the_document_body_section;
  ret.the_document_endnotes_section     = the_document_endnotes_section;
  ret.the_document_glossary_section     = the_document_glossary_section;
  ret.the_document_bibliography_section = the_document_bibliography_section;
  ret.the_document_bookindex_section    = the_document_bookindex_section;
  ret.the_document_blurb_section        = the_document_blurb_section;
  return ret;
}
@system public ST_segnames after_doc_determine_segnames(
  ObjGenericComposite[] the_document_body_section,
  ObjGenericComposite[] the_document_endnotes_section,
  ObjGenericComposite[] the_document_glossary_section,
  ObjGenericComposite[] the_document_bibliography_section,
  ObjGenericComposite[] the_document_bookindex_section,
  ObjGenericComposite[] the_document_blurb_section,
  string[][string]      segnames,
  int                   html_segnames_ptr_cntr,
  int                   html_segnames_ptr,
) {
  if (the_document_endnotes_section.length > 1) {
    segnames["html"] ~= "endnotes";
    segnames["epub"] ~= "endnotes";
    html_segnames_ptr = html_segnames_ptr_cntr;
    foreach (ref obj; the_document_endnotes_section) {
      if (obj.metainfo.is_a == "heading") {
        obj.metainfo.parent_ocn = obj.metainfo.markedup_ancestors[obj.metainfo.parent_lev_markup];
      }
      if (obj.metainfo.heading_lev_markup == 4) {
        obj.ptr.html_segnames = html_segnames_ptr;
        break;
      }
    }
    html_segnames_ptr_cntr++;
  }
  if (the_document_glossary_section.length > 1) {
    segnames["html"] ~= "glossary";
    segnames["epub"] ~= "glossary";
    html_segnames_ptr = html_segnames_ptr_cntr;
    foreach (ref obj; the_document_glossary_section) {
      if (obj.metainfo.is_a == "heading") {
        obj.metainfo.parent_ocn = obj.metainfo.markedup_ancestors[obj.metainfo.parent_lev_markup];
      }
      if (obj.metainfo.heading_lev_markup == 4) {
        obj.ptr.html_segnames = html_segnames_ptr;
        break;
      }
    }
    html_segnames_ptr_cntr++;
  }
  if (the_document_bibliography_section.length > 1) {
    segnames["html"] ~= "bibliography";
    segnames["epub"] ~= "bibliography";
    html_segnames_ptr = html_segnames_ptr_cntr;
    foreach (ref obj; the_document_bibliography_section) {
      if (obj.metainfo.is_a == "heading") {
        obj.metainfo.parent_ocn = obj.metainfo.markedup_ancestors[obj.metainfo.parent_lev_markup];
      }
      if (obj.metainfo.heading_lev_markup == 4) {
        obj.ptr.html_segnames = html_segnames_ptr;
        break;
      }
    }
    html_segnames_ptr_cntr++;
  }
  if (the_document_bookindex_section.length > 1) {
    segnames["html"] ~= "bookindex";
    segnames["epub"] ~= "bookindex";
    html_segnames_ptr = html_segnames_ptr_cntr;
    foreach (ref obj; the_document_bookindex_section) {
      if (obj.metainfo.is_a == "heading") {
        obj.metainfo.parent_ocn = obj.metainfo.markedup_ancestors[obj.metainfo.parent_lev_markup];
      }
      if (obj.metainfo.heading_lev_markup == 4) {
        obj.ptr.html_segnames = html_segnames_ptr;
        break;
      }
    }
    html_segnames_ptr_cntr++;
  }
  if (the_document_blurb_section.length > 1) {
    segnames["html"] ~= "blurb";
    segnames["epub"] ~= "blurb";
    html_segnames_ptr = html_segnames_ptr_cntr;
    foreach (ref obj; the_document_blurb_section) {
      if (obj.metainfo.is_a == "heading") {
        obj.metainfo.parent_ocn = obj.metainfo.markedup_ancestors[obj.metainfo.parent_lev_markup];
      }
      if (obj.metainfo.heading_lev_markup == 4) {
        obj.ptr.html_segnames = html_segnames_ptr;
        break;
      }
    }
    html_segnames_ptr_cntr++;
  }
  ST_segnames ret;
  ret.segnames                          = segnames;
  ret.html_segnames_ptr_cntr            = html_segnames_ptr_cntr;
  ret.html_segnames_ptr                 = html_segnames_ptr;
  return ret;
}
// decendants
@safe auto after_doc_get_decendants()(ObjGenericComposite[] document_sections) {
  int[string] _heading_ocn_decendants;
  string[] _ocn_open_key = ["","","","","","","",""];
  auto _doc_sect_length = document_sections.length - 1;
  int _last_ocn;
  foreach (_lg, ref obj; document_sections) {
    if (obj.metainfo.is_a == "heading") {
      foreach (_dts_lv, dom_tag_status; obj.metainfo.dom_structure_markedup_tags_status) {
        switch (dom_tag_status) with (DomTags) {
        case none: break;
        case open:
            _ocn_open_key[_dts_lv] = (obj.metainfo.ocn).to!string;
            _heading_ocn_decendants[_ocn_open_key[_dts_lv]] = obj.metainfo.ocn;
          break;
        case close:
          if (_ocn_open_key[_dts_lv].empty) {
            _ocn_open_key[_dts_lv] = "0";
          }
          _heading_ocn_decendants[_ocn_open_key[_dts_lv]] = obj.metainfo.ocn - 1;
          _ocn_open_key[_dts_lv] = (0).to!string;
          break;
        case close_and_open:
          if (_ocn_open_key[_dts_lv].empty) {
            _ocn_open_key[_dts_lv] = "0";
          }
          _heading_ocn_decendants[_ocn_open_key[_dts_lv]] = obj.metainfo.ocn - 1;
          _ocn_open_key[_dts_lv] = (obj.metainfo.ocn).to!string;
          _heading_ocn_decendants[_ocn_open_key[_dts_lv]] = obj.metainfo.ocn;
          break;
        case open_still: break;
        default: break;
        }
      }
    }
    if (obj.metainfo.ocn > 0) {
      _last_ocn = obj.metainfo.ocn;
    }
    if (_lg == _doc_sect_length) {
      _heading_ocn_decendants["1"] = _last_ocn; // close existing o_n key
    }
  }
  Tuple!(int, int)[] pairs;
  foreach (pair; _heading_ocn_decendants.byPair) {
    pairs ~= tuple(pair[0].to!int, pair[1]);
  }
  return pairs.sort;
}
@safe string[] extract_images()(string content_block) {
  static auto rgx = RgxI();
  string[] images_;
  if (auto m = content_block.matchAll(rgx.image)) {
    images_ ~= m.captures[1];
  }
  return images_;
}
@system auto _image_dimensions(O,M)(O obj, M manifested) {
  static auto rgx = RgxI();
  if (obj.has.image_without_dimensions) {
    import std.math;
    import imageformats;
    int w, h, chans;
    real _w, _h;
    int max_width = 640;
    foreach (img; obj.text.matchAll(rgx.inline_image_without_dimensions)) {
      try {
        read_image_info(manifested.src.image_dir_path ~ "/" ~ img["img"], w, h, chans);
      } catch (Exception ex) {
        writeln("WARNING, image not found: ", img["img"], "\n  ", manifested.src.image_dir_path ~ "/" ~ img["img"]);
      }
      // calculate, decide max width and proportionally reduce to keep w & h within it
      debug(images) { writeln("width: ", w, ", height: ", h); }
      if (w > max_width) {
        _w = max_width;
        _h = round((max_width / w.to!real) * h.to!real);
      } else {
        _w = w;
        _h = h;
      }
      obj.text = obj.text.replaceFirst(
        rgx.inline_image_without_dimensions,
        format(q"┃%s☼%s,w%sh%s %s┃",
          "$1",
          "$3",
          _w.to!string,
          _h.to!string,
          "$6",
        )
      );
    }
    debug(images) { writeln("image without dimensions: ", obj.text); }
  }
  return obj;
}
// links
@safe auto _links(O)(O obj) {
  static auto rgx = RgxI();
  if (auto m = obj.text.match(rgx.inline_link_stow_uri)) {
    debug(links) {
      writeln("number of link matches to stow: ", (obj.text.match(rgx.inline_link_stow_uri)).count);
      writeln("links to stow: ", (obj.text.match(rgx.inline_link_stow_uri)));
    }
    int _n_matches = (obj.text.match(rgx.inline_link_stow_uri)).count.to!int;
    for(int i = 0; i < _n_matches; ++i) {
      if (obj.text.match(rgx.inline_link_stow_uri)) {
        obj.stow.link ~= obj.text.matchFirst(rgx.inline_link_stow_uri)[2];
        obj.text = obj.text.replaceFirst(
          rgx.inline_link_stow_uri,
          format(q"┃┥%s┝┤%s├┃", "$1", i)
        );
      }
    }
  }
  return obj;
}
struct NodeStructureMetadata {
  int lv, lv0, lv1, lv2, lv3, lv4, lv5, lv6, lv7;
  int obj_cite_digit;
  int[string] p_; // p_ parent_
  static auto rgx = RgxI();
  @safe ObjGenericComposite node_location_emitter(La,Ta)(
    string         lev_markup_number,
    string[string] tag_in_seg,
    La             lev_anchor_tag,
    Ta             tag_assoc,
    OCNset         obj_cite_digits,
    int            cntr_,
    int            ptr_,
    string         is_
  ) {
    debug(asserts) { static assert(is(typeof(obj_cite_digits.object_number) == int)); }
    assert(is_ != "heading");
    assert(obj_cite_digits.object_number.to!int >= 0);
    assert(is_ != "heading");                          // should not be necessary
    assert(obj_cite_digits.object_number.to!int >= 0); // should not be necessary
    if (lv7 > eN.bi.off) {
      p_["lev_markup_number"]                       = DocStructMarkupHeading.h_text_4;
      p_["object_number"]                           = lv7;
    } else if (lv6 > eN.bi.off) {
      p_["lev_markup_number"]                       = DocStructMarkupHeading.h_text_3;
      p_["object_number"]                           = lv6;
    } else if (lv5 > eN.bi.off) {
      p_["lev_markup_number"]                       = DocStructMarkupHeading.h_text_2;
      p_["object_number"]                           = lv5;
    } else {
      p_["lev_markup_number"]                       = DocStructMarkupHeading.h_text_1;
      p_["object_number"]                           = lv4;
    }
    ObjGenericComposite comp_obj_location;
    comp_obj_location                               = comp_obj_location.init;
    comp_obj_location.metainfo.is_a                 = is_;
    comp_obj_location.metainfo.ocn                  = obj_cite_digits.object_number;
    comp_obj_location.metainfo.identifier           = obj_cite_digits.identifier;
    comp_obj_location.tags.anchor_tag_html          = tag_in_seg["seg_lv4"];
    comp_obj_location.tags.segment_anchor_tag_epub  = tag_in_seg["seg_lv1to4"];
    comp_obj_location.tags.heading_lev_anchor_tag   = lev_anchor_tag;
    comp_obj_location.metainfo.parent_ocn           = p_["object_number"];
    comp_obj_location.metainfo.parent_lev_markup    = p_["lev_markup_number"];
    debug(_node) {
      if (lev_markup_number.match(rgx.levels_numbered_headings)) { writeln("x ", _node.to!string);
      } else { writeln("- ", _node.to!string); }
    }
    assert(comp_obj_location.metainfo.parent_lev_markup >= 4);
    assert(comp_obj_location.metainfo.parent_lev_markup <= 7);
    assert(comp_obj_location.metainfo.parent_ocn >= 0);
    return comp_obj_location;
  }
  invariant() {
  }
  @safe ObjGenericComposite node_emitter_heading(O,TaL,TA,SOAT)(
    O              an_object,
    string[string] tag_in_seg,
    TaL            lev_anchor_tag,
    TA             tag_assoc,
    OCNset         obj_cite_digits,
    int            cntr_,
    int            ptr_,
    string[]       lv_ancestors_txt,
    int            html_segnames_ptr,
    SOAT           substantive_object_and_anchor_tags_struct,
  ) {
    string _text                = an_object["substantive"];
    string lev_markup_number    = an_object["lev_markup_number"];
    string lev_collapsed_number = an_object["lev_collapsed_number"];
    string dummy_heading_status = an_object["dummy_heading_status"];
    string is_                  = an_object["is"];
    debug(asserts) {
      static assert(is(typeof(lev)                                       == string));
      static assert(is(typeof(obj_cite_digits.object_number)             == int));
    }
    assert(is_ == "heading");
    assert((obj_cite_digits.object_number).to!int >= 0);
    assert(
      lev_markup_number.match(rgx.levels_numbered),
      ("not a valid heading level: " ~ lev_markup_number ~ " at " ~ obj_cite_digits.object_number.to!string)
    );
    if (lev_markup_number.match(rgx.levels_numbered)) {
      if (lev_markup_number.to!int == 0) {
        // TODO first hit (of two) with this assertion failure, check, fix & reinstate
        // assert(obj_cite_digits.object_number.to!int == 1,
        //   "ERROR header lev markup number is: " ~
        //   lev_markup_number.to!string ~
        //   " obj_cite_digits.object_number.to!int should == 1 but is: " ~
        //    obj_cite_digits.object_number.to!string ~
        //   "\n" ~ _text);
      }
    }
    switch (lev_markup_number.to!int) {
    case 0:
      lv = DocStructMarkupHeading.h_sect_A;
      lv0 = obj_cite_digit;
      lv1 = 0; lv2 = 0; lv3 = 0; lv4 = 0; lv5 = 0; lv6 = 0; lv7 = 0;
      p_["lev_markup_number"] = 0;
      p_["object_number"] = 0;
      break;
    case 1:
      lv = DocStructMarkupHeading.h_sect_B;
      lv1 = obj_cite_digit;
      lv2 = 0; lv3 = 0; lv4 = 0; lv5 = 0; lv6 = 0; lv7 = 0;
      p_["lev_markup_number"]
        = DocStructMarkupHeading.h_sect_A;
      p_["object_number"] = lv0;
      break;
    case 2:
      lv = DocStructMarkupHeading.h_sect_C;
      lv2 = obj_cite_digit;
      lv3 = 0; lv4 = 0; lv5 = 0; lv6 = 0; lv7 = 0;
      p_["lev_markup_number"]
        = DocStructMarkupHeading.h_sect_B;
      p_["object_number"] = lv1;
      break;
    case 3:
      lv = DocStructMarkupHeading.h_sect_D;
      lv3 = obj_cite_digit;
      lv4 = 0; lv5 = 0; lv6 = 0; lv7 = 0;
      p_["lev_markup_number"]
        = DocStructMarkupHeading.h_sect_C;
      p_["object_number"] = lv2;
      break;
    case 4:
      lv = DocStructMarkupHeading.h_text_1;
      lv4 = obj_cite_digit;
      lv5 = 0; lv6 = 0; lv7 = 0;
      if (lv3 > eN.bi.off) {
        p_["lev_markup_number"]
          = DocStructMarkupHeading.h_sect_D;
        p_["object_number"] = lv3;
      } else if (lv2 > eN.bi.off) {
        p_["lev_markup_number"]
          = DocStructMarkupHeading.h_sect_C;
        p_["object_number"] = lv2;
      } else if (lv1 > eN.bi.off) {
        p_["lev_markup_number"]
          = DocStructMarkupHeading.h_sect_B;
        p_["object_number"] = lv1;
      } else {
        p_["lev_markup_number"]
          = DocStructMarkupHeading.h_sect_A;
        p_["object_number"] = lv0;
      }
      break;
    case 5:
      lv = DocStructMarkupHeading.h_text_2;
      lv5 = obj_cite_digit;
      lv6 = 0; lv7 = 0;
      p_["lev_markup_number"]
        = DocStructMarkupHeading.h_text_1;
      p_["object_number"] = lv4;
      break;
    case 6:
      lv = DocStructMarkupHeading.h_text_3;
      lv6 = obj_cite_digit;
      lv7 = 0;
      p_["lev_markup_number"]
        = DocStructMarkupHeading.h_text_2;
      p_["object_number"] = lv5;
      break;
    case 7:
      lv = DocStructMarkupHeading.h_text_4;
      lv7 = obj_cite_digit;
      p_["lev_markup_number"]
        = DocStructMarkupHeading.h_text_3;
      p_["object_number"] = lv6;
      break;
    default:
      break;
    }
    ObjGenericComposite comp_obj_;
    comp_obj_                                        = comp_obj_.init;
    comp_obj_.metainfo.is_of_part                    = "body";
    comp_obj_.metainfo.is_of_section                 = "body";
    comp_obj_.metainfo.is_of_type                    = "para";
    comp_obj_.metainfo.is_a                          = "heading";
    comp_obj_.text                                   = _text.to!string.strip;
    comp_obj_.metainfo.ocn                           = obj_cite_digits.object_number;
    comp_obj_.metainfo.identifier                    = obj_cite_digits.identifier;
    comp_obj_.metainfo.dummy_heading                 = (dummy_heading_status == "t") ? true: false;
    comp_obj_.metainfo.object_number_off             = obj_cite_digits.off;
    // comp_obj_.metainfo.o_n_book_index             = obj_cite_digits.bkidx;
    comp_obj_.metainfo.object_number_type            = obj_cite_digits.type;
    comp_obj_.tags.segment_anchor_tag_epub           = tag_in_seg["seg_lv1to4"];
    comp_obj_.tags.anchor_tag_html                   = tag_in_seg["seg_lv4"];
    comp_obj_.tags.in_segment_html                   = comp_obj_.tags.anchor_tag_html;
    comp_obj_.tags.heading_lev_anchor_tag            = lev_anchor_tag;
    comp_obj_.tags.html_segment_anchor_tag_is        = tag_in_seg["seg_lv4"];
    comp_obj_.tags.epub_segment_anchor_tag_is        = tag_in_seg["seg_lv1to4"];
    comp_obj_.metainfo.heading_lev_markup            = (!(lev_markup_number.empty) ? lev_markup_number.to!int : 0);
    comp_obj_.metainfo.heading_lev_collapsed         = (!(lev_collapsed_number.empty) ? lev_collapsed_number.to!int : 0);
    comp_obj_.metainfo.parent_ocn                    = p_["object_number"];
    comp_obj_.metainfo.parent_lev_markup             = p_["lev_markup_number"];
    comp_obj_.tags.heading_ancestors_text            = lv_ancestors_txt;
    comp_obj_.ptr.doc_object                         = cntr_;
    comp_obj_.ptr.html_segnames                      = ((lev_markup_number == "4") ? html_segnames_ptr : 0);
    comp_obj_.ptr.heading                            = ptr_;
    comp_obj_.has.inline_notes_reg                   = substantive_object_and_anchor_tags_struct.has_notes_reg;
    comp_obj_.has.inline_notes_star                  = substantive_object_and_anchor_tags_struct.has_notes_star;
    comp_obj_.has.inline_links                       = substantive_object_and_anchor_tags_struct.has_links;
    tag_assoc[comp_obj_.tags.anchor_tag_html]["seg_lv4"]            = comp_obj_.tags.in_segment_html;
    tag_assoc[comp_obj_.tags.segment_anchor_tag_epub]["seg_lv1to4"] = comp_obj_.tags.segment_anchor_tag_epub;
    debug(_node) {
      if (lev_markup_number.match(rgx.levels_numbered_headings)) { writeln("* ", _node.to!string); }
    }
    debug(nodeheading) {
      if (lev_markup_number.match(rgx.levels_numbered_headings)) { writeln("* ", _node.to!string); }
    }
    assert(comp_obj_.metainfo.parent_lev_markup <= 7);
    assert(comp_obj_.metainfo.parent_ocn >= 0);
    if (lev_markup_number.match(rgx.levels_numbered_headings)) {
      assert(comp_obj_.metainfo.heading_lev_markup <= 7);
      assert(comp_obj_.metainfo.ocn >= 0);
      if (comp_obj_.metainfo.parent_lev_markup > 0) {
        assert(comp_obj_.metainfo.parent_lev_markup < comp_obj_.metainfo.heading_lev_markup);
        if (comp_obj_.metainfo.ocn != 0) {
          assert(comp_obj_.metainfo.parent_ocn < comp_obj_.metainfo.ocn);
        }
      }
      if (comp_obj_.metainfo.heading_lev_markup == 0) {
        assert(comp_obj_.metainfo.parent_lev_markup == DocStructMarkupHeading.h_sect_A);
      } else if  (comp_obj_.metainfo.heading_lev_markup == DocStructMarkupHeading.h_sect_B) {
        assert(comp_obj_.metainfo.parent_lev_markup == DocStructMarkupHeading.h_sect_A);
      } else if  (comp_obj_.metainfo.heading_lev_markup == DocStructMarkupHeading.h_sect_C) {
        assert(comp_obj_.metainfo.parent_lev_markup == DocStructMarkupHeading.h_sect_B);
      } else if  (comp_obj_.metainfo.heading_lev_markup == DocStructMarkupHeading.h_sect_D) {
        assert(comp_obj_.metainfo.parent_lev_markup == DocStructMarkupHeading.h_sect_C);
      } else if  (comp_obj_.metainfo.heading_lev_markup == DocStructMarkupHeading.h_text_1) {
        assert(comp_obj_.metainfo.parent_lev_markup <= DocStructMarkupHeading.h_sect_D);
      } else if  (comp_obj_.metainfo.heading_lev_markup == DocStructMarkupHeading.h_text_2) {
        assert(comp_obj_.metainfo.parent_lev_markup == DocStructMarkupHeading.h_text_1);
      } else if  (comp_obj_.metainfo.heading_lev_markup == DocStructMarkupHeading.h_text_3) {
        assert(comp_obj_.metainfo.parent_lev_markup == DocStructMarkupHeading.h_text_2);
      } else if  (comp_obj_.metainfo.heading_lev_markup == DocStructMarkupHeading.h_text_4) {
        assert(comp_obj_.metainfo.parent_lev_markup == DocStructMarkupHeading.h_text_3);
      } else if  (comp_obj_.metainfo.heading_lev_markup == DocStructMarkupHeading.h_text_5) {
      }
    }
    return comp_obj_;
  }
  invariant() {
  }
}
// abstraction functions emitters ↑
// ↓ abstraction functions assertions
@safe pure void assertions_doc_structure()(
  string[string]  an_object,
  string          an_object_key,
  int[string]     lv
) {
  string msg_error_doc_struct = "\nERROR in document structure, check markup (heading level relationships):\n";
  if (lv["h3"] > eN.bi.off) {
    assert(lv["h0"] > eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h1"] > eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h2"] > eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
  } else if (lv["h2"] > eN.bi.off) {
    assert(lv["h0"] > eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h1"] > eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h3"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
  } else if (lv["h1"] > eN.bi.off) {
    assert(lv["h0"] > eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h2"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h3"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
  } else if (lv["h0"] > eN.bi.off) {
    assert(lv["h1"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h2"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h3"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
  } else {
    assert(lv["h0"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h1"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h2"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h3"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
  }
  if (lv["h7"] > eN.bi.off) {
    assert(lv["h4"] > eN.bi.off,
      msg_error_doc_struct
      ~ "missing segment level 1~\n"
      ~ an_object[an_object_key]
    );
    assert(lv["h5"] > eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h6"] > eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
  } else if (lv["h6"] > eN.bi.off) {
    assert(lv["h4"] > eN.bi.off,
      msg_error_doc_struct
      ~ "missing segment level 1~\n"
      ~ an_object[an_object_key]
    );
    assert(lv["h5"] > eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h7"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
  } else if (lv["h5"] > eN.bi.off) {
    assert(lv["h4"] > eN.bi.off,
      msg_error_doc_struct
      ~ "missing segment level 1~\n"
      ~ an_object[an_object_key]
    );
    assert(lv["h6"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h7"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
  } else if (lv["h4"] > eN.bi.off) {
    assert(lv["h5"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h6"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h7"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
  } else {
    assert(lv["h4"] == eN.bi.off,
      msg_error_doc_struct
      ~ "missing segment level 1~\n"
      ~ an_object[an_object_key]
    );
    assert(lv["h5"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h6"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h7"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
  }
  if (lv["h0"] == eN.bi.off) {
    assert(lv["h1"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h2"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h3"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h4"] == eN.bi.off,
      msg_error_doc_struct
      ~ "missing segment level 1~\n"
      ~ an_object[an_object_key]
    );
    assert(lv["h5"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h6"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h7"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
  }
  if (lv["h1"] == eN.bi.off) {
    assert(lv["h2"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h3"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
  }
  if (lv["h2"] == eN.bi.off) {
    assert(lv["h3"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
  }
  if (lv["h3"] == eN.bi.off) {
  }
  if (lv["h4"] == eN.bi.off) {
    assert(lv["h5"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h6"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h7"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
  }
  if (lv["h5"] == eN.bi.off) {
    assert(lv["h6"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
    assert(lv["h7"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
  }
  if (lv["h6"] == eN.bi.off) {
    assert(lv["h7"] == eN.bi.off,
      msg_error_doc_struct
      ~ an_object[an_object_key]
    );
  }
  if (lv["h7"] == eN.bi.off) {
  }
  switch ((an_object["lev"]).to!string) {
  case "A":
    if (lv["h0"] == eN.bi.off) {
      assert(lv["h1"] == eN.bi.off,
        msg_error_doc_struct
        ~ "at level A~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h2"] == eN.bi.off,
        msg_error_doc_struct
        ~ "at level A~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h3"] == eN.bi.off,
        msg_error_doc_struct
        ~ "at level A~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h4"] == eN.bi.off,
        msg_error_doc_struct
        ~ "missing segment level 1~\n"
        ~ "at level A~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h5"] == eN.bi.off,
        msg_error_doc_struct
        ~ "at level A~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h6"] == eN.bi.off,
        msg_error_doc_struct
        ~ "at level A~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h7"] == eN.bi.off,
        msg_error_doc_struct
        ~ "at level A~\n"
        ~ an_object[an_object_key]
      );
    } else {                       // (lv["h0"] > eN.bi.off)
      assert(lv["h0"] == eN.bi.off,
        msg_error_doc_struct
        ~ "should not enter level A a second time\n"
        ~ "at level A~\n"
        ~ an_object[an_object_key]
      );
    }
    break;
  case "B":
    if (lv["h1"] == eN.bi.off) {
      assert(lv["h0"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level B~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h2"] == eN.bi.off,
        msg_error_doc_struct
        ~ "at level B~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h3"] == eN.bi.off,
        msg_error_doc_struct
        ~ "at level B~\n"
        ~ an_object[an_object_key]
      );
    } else {                       // (lv["h1"] > eN.bi.off)
      assert(lv["h0"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level B~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h1"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level B~\n"
        ~ an_object[an_object_key]
      );
    }
    break;
  case "C":
    if (lv["h2"] == eN.bi.off) {
      assert(lv["h0"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level C~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h1"] > eN.bi.off,
        msg_error_doc_struct
        ~ "level C should not follow level A\n"
        ~ "at level C~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h3"] == eN.bi.off,
        msg_error_doc_struct
        ~ "at level C~\n"
        ~ an_object[an_object_key]
      );
    } else {                       // (lv["h2"] > eN.bi.off)
      assert(lv["h0"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level C~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h1"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level C~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h2"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level C~\n"
        ~ an_object[an_object_key]
      );
    }
    break;
  case "D":
    if (lv["h3"] == eN.bi.off) {
      assert(lv["h0"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level D~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h1"] > eN.bi.off,
        msg_error_doc_struct
        ~ "level D should not follow level A\n"
        ~ "at level D~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h2"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level D~\n"
        ~ an_object[an_object_key]
      );
    } else {                      // (lv["h3"] > eN.bi.off)
      assert(lv["h0"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level D~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h1"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level D~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h2"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level D~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h3"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level D~\n"
        ~ an_object[an_object_key]
      );
    }
    break;
  case "1":
    if (lv["h4"] == eN.bi.off) {
      assert(lv["h0"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level 1~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h5"] == eN.bi.off,
        msg_error_doc_struct
        ~ "at level 1~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h6"] == eN.bi.off,
        msg_error_doc_struct
        ~ "at level 1~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h7"] == eN.bi.off,
        msg_error_doc_struct
        ~ "at level 1~\n"
        ~ an_object[an_object_key]
      );
    } else {                      // (lv["h4"] > eN.bi.off)
      assert(lv["h0"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level 1~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h4"] > eN.bi.off,
        msg_error_doc_struct
        ~ "missing segment level 1~ ?\n"
        ~ "at level 1~\n"
        ~ an_object[an_object_key]
      );
    }
    break;
  case "2":
    if (lv["h5"] == eN.bi.off) {
      assert(lv["h0"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level 2~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h4"] > eN.bi.off,
        msg_error_doc_struct
        ~ "missing segment level 1~ ?\n"
        ~ "at level 2~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h6"] == eN.bi.off,
        msg_error_doc_struct
        ~ "at level 2~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h7"] == eN.bi.off,
        msg_error_doc_struct
        ~ "at level 2~\n"
        ~ an_object[an_object_key]
      );
    } else {                      // (lv["h5"] > eN.bi.off)
      assert(lv["h0"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level 2~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h4"] > eN.bi.off,
        msg_error_doc_struct
        ~ "missing segment level 1~ ?\n"
        ~ "at level 2~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h5"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level 2~\n"
        ~ an_object[an_object_key]
      );
    }
    break;
  case "3":
    if (lv["h6"] == eN.bi.off) {
      assert(lv["h0"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level 3~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h4"] > eN.bi.off,
        msg_error_doc_struct
        ~ "missing segment level 1~ ?\n"
        ~ "at level 3~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h5"] > eN.bi.off,
        msg_error_doc_struct
        ~ "missing segment level 2~ ?\n"
        ~ "at level 3~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h7"] == eN.bi.off,
        msg_error_doc_struct
        ~ "at level 3~\n"
        ~ an_object[an_object_key]
      );
    } else {                      // (lv["h6"] > eN.bi.off)
      assert(lv["h0"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level 3~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h4"] > eN.bi.off,
        msg_error_doc_struct
        ~ "missing segment level 1~ ?\n"
        ~ "at level 3~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h5"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level 3~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h6"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level 3~\n"
        ~ an_object[an_object_key]
      );
    }
    break;
  case "4":
    if (lv["h7"] == eN.bi.off) {
      assert(lv["h0"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level 4~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h4"] > eN.bi.off,
        msg_error_doc_struct
        ~ "missing segment level 1~ ?\n"
        ~ "at level 4~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h5"] > eN.bi.off,
        msg_error_doc_struct
        ~ "missing segment level 2~ ?\n"
        ~ "at level 4~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h6"] > eN.bi.off,
        msg_error_doc_struct
        ~ "missing segment level 3~ ?\n"
        ~ "at level 4~\n"
        ~ an_object[an_object_key]
      );
    } else {                      // (lv["h7"] > eN.bi.off)
      assert(lv["h0"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level 4~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h4"] > eN.bi.off,
        msg_error_doc_struct
        ~ "missing segment level 1~ ?\n"
        ~ "at level 4~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h5"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level 4~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h6"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level 4~\n"
        ~ an_object[an_object_key]
      );
      assert(lv["h7"] > eN.bi.off,
        msg_error_doc_struct
        ~ "at level 4~\n"
        ~ an_object[an_object_key]
      );
    }
    break;
  default:
    break;
  }
}
// abstraction functions assertions ↑
#+END_SRC

* template docSectKeysSeq

#+NAME: docSectKeysSeq
#+HEADER: :noweb yes
#+BEGIN_SRC d
@safe auto docSectKeysSeq(string[][string] document_section_keys_sequenced) {
  struct doc_sect_keys_seq {
    string[] scroll() {
      return document_section_keys_sequenced["scroll"];
    }
    string[] seg() {
      return document_section_keys_sequenced["seg"];
    }
    string[] sql() {
      return document_section_keys_sequenced["sql"];
    }
    string[] latex() {
      return document_section_keys_sequenced["latex"];
    }
  }
  return doc_sect_keys_seq();
}
#+END_SRC

* document header including copyright & license

#+NAME: doc_header_including_copyright_and_license
#+HEADER: :noweb yes
#+BEGIN_SRC emacs-lisp
<<./spine_version_info_and_doc_header_including_copyright_and_license.org:spine_doc_header_including_copyright_and_license()>>
#+END_SRC

* __END__