/+
  document abstraction
  ao_abstract_doc_source.d
+/
template SiSUdocAbstraction() {
  private:
  struct Abstraction {

    /+ ↓ abstraction imports +/
    import
      ao_defaults,                  // sdp/ao_defaults.d
      ao_object_setter,             // sdp/ao_object_setter.d
      ao_rgx,                       // sdp/ao_rgx.d
      ao_ansi_colors;               // sdp/ao_ansi_colors.d

    /+ ↓ abstraction mixins +/
    mixin ObjectSetter;
    mixin InternalMarkup;
    // // mixin SiSUrgxInitFlags;
    // // mixin AssertionsOnBlocks;
    // mixin SiSUbiblio; // issue
    // mixin SiSUheader;

    /+ ↓ abstraction struct init +/
    /+ initialize +/
    
    auto rgx = Rgx();
    ObjComposite[] contents_the_objects;
    
    string[string] an_object, processing;
    auto set_abstract_object = ObjectAbstractSet();
    auto set_header = HeaderDocMetadataMakeJson();
    auto note_section = NotesSection();
    
    /+ enum +/
    enum State { off, on }
    enum TriState { off, on, closing } // make aware, possibility of third state
    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 DocStructCollapsedHeading { lv0, lv1, lv2, lv3, lv4, lv5, lv6, lv7 } // not yet used
    
    /+ biblio variables +/
    string biblio_tag_name, biblio_tag_entry, st;
    string[] biblio_arr_json;
    JSONValue[] bib_arr_json;
    int bib_entry;
    
    /+ counters +/
    long counter, previous_count;
    int[string] line_occur;
    int verse_line, heading_pointer;
    
    /+ paragraph attributes +/
    string[string] indent;
    bool bullet = true;
    string content_non_header = "8";
    
    auto obj_im = ObjInlineMarkup();
    auto obj_att = ObjAttrib();
    
    /+ ocn +/
    int obj_cite_number, obj_cite_number_;
    auto object_citation_number = OCNemitter();
    int obj_cite_number_emit(int obj_cite_number_status_flag) {
      return object_citation_number.obj_cite_number_emitter(obj_cite_number_status_flag);
    }
    
    /+ book index variables +/
    string book_idx_tmp;
    string[][string][string] bookindex_unordered_hashes;
    auto bookindex_extract_hash = BookIndexNuggetHash();
    string[][string][string] bkidx_hash(string bookindex_section, int obj_cite_number) {
      return bookindex_extract_hash.bookindex_nugget_hash(bookindex_section, obj_cite_number);
    }
    
    /+ node +/
    string node;
    auto node_construct = NodeStructureMetadata();
    string node_jstr(
      string lev_markup_number,
      int obj_cite_number_,
      long counter,
      int heading_pointer,
      string is_
    ) {
      return node_construct.node_emitter(
        lev_markup_number,
        obj_cite_number_,
        counter,
        heading_pointer,
        is_
      );
    }
    string node_jstr_heading(
      string lev_markup_number,
      string lev_collapsed_number,
      int obj_cite_number_,
      long counter,
      int heading_pointer,
      string is_
    ) {
      return node_construct.node_emitter_heading(
        lev_markup_number,
        lev_collapsed_number,
        obj_cite_number_,
        counter,
        heading_pointer,
        is_
      );
    }
    // mixin SiSUdocAbstractionFunctions;

    /+ ↓ abstract marked up document +/
    auto abstract_doc_source(char[][] markup_sourcefile_content) {

      /+ ↓ abstraction init +/
      scope(success) {
      }
      scope(failure) {
      }
      scope(exit) {
        destroy(contents_the_objects);
        destroy(an_object);
        destroy(processing);
        destroy(biblio_arr_json);
      }
      auto type = flags_type_init;
      auto dochead_make = parseJSON(header_make_jsonstr).object;
      auto dochead_metadata = parseJSON(header_metadata_jsonstr).object;
      mixin ScreenTxtColors;
      int tell_lo(string color, int obj_cite_number, in char[] line) {
        writefln(
          "%s%s %s",
          scr_txt_marker[color],
          to!string(obj_cite_number),
          to!string(line)
        );
        return 0;
      }
      int tell_l(string color, in char[] line) {
        writefln(
          "%s%s",
          scr_txt_marker[color],
          line
        );
        return 0;
      }
      string[string] obj_cite_number_poem = [
        "start" : "",
        "end"   : ""
      ];
      int[string] lv = [
        "lv" : State.off,
        "h0" : State.off,
        "h1" : State.off,
        "h2" : State.off,
        "h3" : State.off,
        "h4" : State.off,
        "h5" : State.off,
        "h6" : State.off,
        "h7" : State.off,
        "lev_collapsed_number" : 0,
      ];
      int[string] collapsed_lev = [
        "h0" : State.off,
        "h1" : State.off,
        "h2" : State.off,
        "h3" : State.off,
        "h4" : State.off,
        "h5" : State.off,
        "h6" : State.off,
        "h7" : State.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)"
      ];
      auto 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)")
      ];
      /+ abstraction init ↑ +/

      /+ ↓ loop markup document/text line by line +/
      srcDocLoop:
      foreach (line; markup_sourcefile_content) {

        /+ ↓ markup document/text line by line +/
        /+ scope +/
        scope(exit) {
        }
        scope(failure) {
          stderr.writefln(
            "%s\n%s\n%s:%s failed here:\n  line: %s",
            __MODULE__, __FUNCTION__,
            __FILE__, __LINE__,
            line,
          );
        }
        line = replaceAll(line, rgx.true_dollar, "$$$$");
          // dollar represented as $$ needed to stop submatching on $
          // (substitutions using ${identifiers} must take into account (e.g. happen earlier))
        debug(source) {                                  // source lines
          writeln(line);
          // writeln(scr_txt_marker["green"], line);
        }
        debug(srclines) {
          if (!line.empty) {                             // source lines, not empty
            writefln(
              "%s%s",
              scr_txt_marker["green"],
              line
            );
          }
        }
        if (!line.empty) {
          check_obj_cite_number_status(line, type);
        }
        if (type["code"] == TriState.on) {
          /+ block object: code +/
          code_block(line, an_object, type);
          continue;
        } else if (!match(line, rgx.regular_parse_skip)) {
          /+ object other than code block object (includes regular text paragraph) +/
          if (((match(line, rgx.heading_biblio)
          || (type["heading_biblio"] == State.on)))
          && (!match(line, rgx.heading))
          && (!match(line, rgx.comment))) {
            /+ within block object: biblio +/
            biblio_block(line, type, bib_entry, biblio_arr_json);
            continue;
          } else if (type["poem"] == TriState.on) {
            /+ within block object: poem +/
            poem_block(line, an_object, type, counter, obj_cite_number_poem);
            continue;
          /+ within block object: group +/
          } else if (type["group"] == TriState.on) {
            /+ within block object: group +/
            group_block(line, an_object, type);
            continue;
          } else if (type["block"] == TriState.on) {
            /+ within block object: block +/
            block_block(line, an_object, type);
            continue;
          } else if (type["quote"] == TriState.on) {
            /+ within block object: quote +/
            quote_block(line, an_object, type);
            continue;
          } else if (type["table"] == TriState.on) {
            /+ within block object: table +/
            table_block(line, an_object, type);
            continue;
          } else {
          /+ not within a block group +/
            assert(
              (type["blocks"] == TriState.off)
              || (type["blocks"] == TriState.closing),
              "block status: none or closed"
            );
            assertions_flag_types_block_status_none_or_closed(type);
            if (match(line, rgx.block_open)) {
              if (match(line, (rgx.block_poem_open))) {
                /+ poem to verse exceptions! +/
                object_reset(an_object);
                processing.remove("verse");
                obj_cite_number_poem["start"] = to!string(obj_cite_number);
              }
              start_block(line, type, obj_cite_number_poem);
              continue;
            } else if (!line.empty) {
              /+ line not empty +/
              /+ non blocks (headers, paragraphs) & closed blocks +/
              assert(
                !line.empty,
                "line tested, line not empty surely"
              );
              assert(
                (type["blocks"] == TriState.off)
                || (type["blocks"] == TriState.closing),
                "code block status: none or closed"
              );
              if (type["blocks"] == TriState.closing) {
                // blocks closed, unless followed by book index
                debug(check) {                           // block
                  writeln(__LINE__);
                  tell_l("red", line);
                }
                assert(
                  match(line, rgx.book_index)
                  || match(line, rgx.book_index_open)
                  || type["book_index"] == State.on
                );
              }
              if ((match(line, rgx.book_index))
              || (match(line, rgx.book_index_open))
              || (type["book_index"] == State.on ))  {
                /+ book_index +/
                book_index(line, book_idx_tmp, an_object, type);
              } else {
                /+ not book_index +/
                if (auto m = match(line, rgx.comment)) {
                  /+ matched comment +/
                  debug(comment) {
                    tell_l("blue", line);
                  }
                  an_object["obj"] ~= line ~= "\n";
                  contents_the_objects ~=
                    set_abstract_object.contents_comment(strip(an_object["obj"]));
                  header_set_common(line_occur, an_object, type);
                  processing.remove("verse");
                  type["header_make"] = State.off;
                  type["header_metadata"] = State.off;
                  ++counter;
                } else if ((match(line, rgx.header_make))
                  || (match(line, rgx.header_metadata))
                  || (type["header_make"] == State.on
                  && (line_occur["header_make"] > State.off))
                  || (type["header_metadata"] == State.on
                  && (line_occur["header_metadata"] > State.off))) {
                    header_extract(line, line_occur, an_object, type);
                } else if (((line_occur["para"] == State.off)
                && (line_occur["heading"] == State.off))
                && ((type["para"] == State.off)
                && (type["heading"] == State.off))) {
                  /+ heading or para but neither flag nor line exists +/
                  if ((to!string(dochead_make["make"]["headings"]).length > 2)
                  && (type["make_headings"] == State.off)) {
                    /+ heading found +/
                    auto dochead_make_headings =
                      to!string(dochead_make["make"]["headings"]);
                    heading_found(line, dochead_make_headings, heading_match_str, heading_match_rgx, type);
                  }
                  if ((type["make_headings"] == State.on)
                  && ((line_occur["para"] == State.off)
                  && (line_occur["heading"] == State.off))
                  && ((type["para"] == State.off)
                  && (type["heading"] == State.off))) {
                    /+ heading make set +/
                    heading_make_set(line, line_occur, heading_match_rgx, type);
                  }
                  if (auto m = match(line, rgx.heading)) {
                    /+ heading match +/
                    heading_match(line, line_occur, an_object, lv, collapsed_lev, type);
                  } else if (line_occur["para"] == State.off) {
                    /+ para match +/
                    para_match(line, an_object, indent, bullet, type);
                  }
                } else if (line_occur["header_make"] > State.off) {
                  /+ header_make +/
                  // should be caught by sub-header
                  debug(header) {
                    tell_l("red", line);
                  }
                  an_object["obj"] ~= line ~= "\n";
                  ++line_occur["header_make"];
                } else if (line_occur["header_metadata"] > State.off) {
                  /+ header_metadata +/
                  // should be caught by sub-header
                  debug(header) {                          // para
                    tell_l("red", line);
                  }
                  an_object["obj"] ~= line ~= "\n";
                  ++line_occur["header_metadata"];
                } else if (line_occur["heading"] > State.off) {
                  /+ heading +/
                  debug(heading) {                         // heading
                    tell_l("blue", line);
                  }
                  an_object["obj"] ~= line ~= "\n";
                  ++line_occur["heading"];
                } else if (line_occur["para"] > State.off) {
                  /+ paragraph +/
                  debug(para) {
                    tell_l("blue", line);
                  }
                  an_object["obj"] ~= line;
                  ++line_occur["para"];
                }
              }
            } else if (type["blocks"] == TriState.closing) {
              /+ line empty, with blocks flag +/
              block_flag_line_empty(line, an_object, contents_the_objects, bookindex_unordered_hashes, obj_cite_number, node, counter, type, obj_cite_number_poem); // watch
            } else {
            /+ line empty +/
              /+ line.empty, post contents, empty variables: +/
              assert(
                line.empty,
                "line should be empty"
              );
              assert(
                (type["blocks"] == State.off),
                "code block status: none"
              );
              if ((type["header_make"] == State.on)
              && (line_occur["header_make"] > State.off)) {
                /+ header_make instructions (current line empty) +/
                auto dochead_metadata_and_make =
                  set_header.header_metadata_and_make_jsonstr(strip(an_object["obj"]), dochead_metadata, dochead_make);
                static assert(!isTypeTuple!(dochead_metadata_and_make));
                dochead_metadata = dochead_metadata_and_make[0];
                dochead_make = dochead_metadata_and_make[1];
                header_set_common(line_occur, an_object, type);
                processing.remove("verse");
              } else if ((type["header_metadata"] == State.on)
              && (line_occur["header_metadata"] > State.off)) {
                /+ header_metadata (current line empty) +/
                auto dochead_metadata_and_make =
                  set_header.header_metadata_and_make_jsonstr(strip(an_object["obj"]), dochead_metadata, dochead_make);
                static assert(!isTypeTuple!(dochead_metadata_and_make));
                dochead_metadata = dochead_metadata_and_make[0];
                dochead_make = dochead_metadata_and_make[1];
                header_set_common(line_occur, an_object, type);
                type["header_make"] = State.off;
                type["header_metadata"] = State.off;
                processing.remove("verse");
              } else if ((type["heading"] == State.on)
              && (line_occur["heading"] > State.off)) {
                /+ heading object (current line empty) +/
                obj_cite_number = obj_cite_number_emit(type["obj_cite_number_status"]);
                an_object["bookindex"] =
                  ("bookindex" in an_object) ? an_object["bookindex"] : "";
                bookindex_unordered_hashes =
                  bkidx_hash(an_object["bookindex"], obj_cite_number);
                an_object["is"] = "heading";
                node =
                  node_jstr_heading(
                    an_object["lev_markup_number"],
                    an_object["lev_collapsed_number"],
                    obj_cite_number,
                    counter,
                    heading_pointer,
                    an_object["is"]
                  ); // heading
                an_object["substantive"] =
                  obj_im.obj_inline_markup(an_object["is"], an_object["obj"]);
                an_object["attrib"] =
                  obj_att.obj_attributes(an_object["is"], an_object["obj"], node);
                ++heading_pointer;
                contents_the_objects ~=
                  set_abstract_object.contents_heading(
                    an_object["substantive"],
                    an_object["attrib"],
                    obj_cite_number,
                    to!int(an_object["lev_markup_number"]),
                    to!int(an_object["lev_collapsed_number"])
                  );
                // track previous heading and make assertions
                debug(objectrelated1) { // check
                  tell_l("blue", line);
                  // writeln(an_object["obj"]);
                  // writeln(contents_am[counter]["obj_cite_number"], " ", contents_am[counter]["obj"]);
                  // writeln(m.hit, "\n");
                }
                header_set_common(line_occur, an_object, type);
                type["header_make"] = State.off;
                type["header_metadata"] = State.off;
                an_object.remove("lev");
                an_object.remove("lev_markup_number");
                // an_object["lev_markup_number"]="9";
                processing.remove("verse");
                ++counter;
              } else if ((type["para"] == State.on) && (line_occur["para"] > State.off)) {
                /+ paragraph object (current line empty) +/
                obj_cite_number = obj_cite_number_emit(type["obj_cite_number_status"]);
                an_object["bookindex"] =
                  ("bookindex" in an_object) ? an_object["bookindex"] : "";
                bookindex_unordered_hashes =
                  bkidx_hash(an_object["bookindex"], obj_cite_number);
                an_object["is"] = "para";
                node =
                  node_jstr(
                    content_non_header,
                    obj_cite_number,
                    counter,
                    heading_pointer-1,
                    an_object["is"]
                  );
                an_object["substantive"] =
                  obj_im.obj_inline_markup(an_object["is"], an_object["obj"]);
                an_object["attrib"] =
                  obj_att.obj_attributes(an_object["is"], an_object["obj"], node);
                contents_the_objects ~=
                  set_abstract_object.contents_para(
                    an_object["is"],
                    an_object["substantive"],
                    an_object["attrib"],
                    obj_cite_number,
                    indent,
                    bullet
                  );
                // contents_the_objects ~=
                //   set_abstract_object.contents_para(
                //     an_object,
                //     obj_cite_number,
                //     indent,
                //     bullet
                //   );
                header_set_common(line_occur, an_object, type);
                type["header_make"] = State.off;
                type["header_metadata"] = State.off;
                indent["first"] = "0";
                indent["second"] = "0";
                bullet = false;
                processing.remove("verse");
                ++counter;
              } else {
                assert(
                  line == null,
                  "line variable should be empty, should not occur"
                );
                // check what happens when paragraph separated by 2 newlines
              }
            } // close else for line empty
          } // close else for not the above
        } // close after non code, other blocks or regular text
        if (((contents_the_objects[$-1].is_a == "para")
        || (contents_the_objects[$-1].is_a == "heading"))
        && (counter-1 > previous_count)) {
          if (match(contents_the_objects[$-1].object,
          rgx.inline_notes_delimiter_al_regular_number_note)) {
            // endnotes/ footnotes for
            // doc objects other than paragraphs & headings
            // various forms of grouped text
            previous_count=contents_the_objects.length -1;
            note_section.gather_notes_for_endnote_section(
              contents_the_objects,
              contents_the_objects.length -1
            );
            // notes[notepoint]=note_section.notes_section(contents_the_objects, counter-1);
            // notepoint +=1;
          }
        }
      } /+ ← closed: loop markup document/text line by line +/

      /+ ↓ post loop markup document/text +/
      debug(objectrelated2) { // check
          tell_l("blue", line);
        // writeln(__FILE__, ":", __LINE__);
        // writeln(counter);
        // // contents_am[0..counter]
        // writeln(contents_am.length);
      }
      /+
        Backmatter:
        * endnotes
        * glossary
        * references / bibliography
        * book index
      +/
      obj_im.obj_inline_markup("doc_end_reset", "");
      auto en_tuple =
        note_section.endnote_objects(obj_cite_number);
      static assert(!isTypeTuple!(en_tuple));
      auto endnotes_section = en_tuple[0];
      obj_cite_number = en_tuple[1];
      debug(endnotes) {
        writefln(
          "%s %s",
          __LINE__,
          endnotes_section.length
        );
        foreach (n; endnotes_section) {
          writeln(n);
        }
      }
      auto biblio_unsorted_incomplete = biblio_arr_json.dup;
      // destroy(biblio_arr_json);
      auto biblio = Bibliography();
      auto biblio_ordered =
        biblio.bibliography(biblio_unsorted_incomplete, bib_arr_json);
      auto bi = BookIndexReportSection();
      auto bi_tuple =
        bi.bookindex_build_section(bookindex_unordered_hashes, obj_cite_number);
      static assert(!isTypeTuple!(bi_tuple));
      auto bookindex_section = bi_tuple[0];
      obj_cite_number = bi_tuple[1];
      debug(bookindex) {                         // bookindex
        foreach (bi_entry; bookindex_section) {
          writeln(bi_entry["obj"]);
        }
      }
      auto document_the =
        contents_the_objects ~ endnotes_section ~ bookindex_section;
      debug(heading) {                         // heading
        string spc;
        foreach (o; document_the) {
          if (o["is"] == "heading") {
            switch (o["lev_markup_number"]) {
            case "0":
            // case to!string(DocStructMarkupHeading.h_sect_A):
              spc="";
              break;
            case "1":
            // case to!string(DocStructMarkupHeading.h_sect_B):
              spc="  ";
              break;
            case "2":
            // case to!string(DocStructMarkupHeading.h_sect_C):
              spc="    ";
              break;
            case "3":
            // case to!string(DocStructMarkupHeading.h_sect_D):
              spc="      ";
              break;
            case "4":
            // case to!string(DocStructMarkupHeading.h_text_1):
              spc="        ";
              break;
            case "5":
            // case to!string(DocStructMarkupHeading.h_text_2):
              spc="          ";
              break;
            case "6":
            // case to!string(DocStructMarkupHeading.h_text_3):
              spc="            ";
              break;
            case "7":
            // case to!string(DocStructMarkupHeading.h_text_4):
              spc="              ";
              break;
            case "8":
            // case to!string(DocStructMarkupHeading.h_text_5):
              spc="                ";
              break;
            default:
              spc="";
              break;
            }
            // writeln(
            //   spc, "* ", " ",
            //   o
            // );
            writefln(
              "%s*  $s\n            %s",
              spc,
              strip(o["obj"]),
              o["attrib"]
            );
            // writeln(spc, "* ", to!string(o["lev_collapsed_number"]), " ", strip(o["obj"]));
            // tell_l("yellow", spc, strip(o["obj"]));
          }
        }
      }
      destroy(contents_the_objects);
      destroy(endnotes_section);
      destroy(bookindex_section);
      // struct Document {
      //   char content;
      //   char head_make;
      //   char head_metadata;
      //   char bookindex_section;
      //   char biblio;
      // }
      // struct Document {
      //   char content;
      //   char head_make;
      //   char head_metadata;
      //   char bookindex_section;
      //   char biblio;
      // }
      auto t =
        tuple(
          document_the,
          dochead_make,
          dochead_metadata,
          bookindex_unordered_hashes,
          biblio_ordered
        );
      return t;
      /+ post loop markup document/text ↑ +/

    } /+ ← closed: abstract doc source +/

    /+ ↓ abstraction functions +/
    auto object_reset(ref string[string] an_object) {
      an_object.remove("obj");
      an_object.remove("substantive");
      an_object.remove("is");
      an_object.remove("attrib");
      an_object.remove("bookindex");
    }
    auto header_set_common(
      ref int[string] line_occur,
      ref string[string] an_object,
      ref int[string] type
    ) {
      // line_occur["header"] = State.off;
      line_occur["header_make"] = State.off;
      line_occur["header_metadata"] = State.off;
      line_occur["heading"] = State.off;
      line_occur["para"]= State.off;
      type["header"] = State.off;
      // type["header_make"] = State.off;
      // type["header_metadata"] = State.off;
      type["heading"] = State.off;
      type["para"] = State.off;
      object_reset(an_object);
    }
    auto check_obj_cite_number_status(char[] line, ref int[string] type) {
      if ((!line.empty) && (type["obj_cite_number_status_multi_obj"] == TriState.off)) {
        /+ not multi-line object, check whether obj_cite_number is on or turned off +/
        if (match(line, rgx.obj_cite_number_block_marks)) {
          /+ switch off obj_cite_number +/
          if (match(line, rgx.obj_cite_number_off_block)) {
            type["obj_cite_number_status_multi_obj"] = TriState.on;
            debug(ocnoff) {
              tell_l("fuchsia", line);
            }
          }
          if (match(line, rgx.obj_cite_number_off_block_dh)) {
            type["obj_cite_number_status_multi_obj"] = TriState.closing;
            debug(ocnoff) {
              tell_l("fuchsia", line);
            }
          }
        } else {
          if (type["obj_cite_number_status_multi_obj"] == TriState.off) {
            if (match(line, rgx.obj_cite_number_off)) {
              type["obj_cite_number_status"] = TriState.on;
            } else if (match(line, rgx.obj_cite_number_off_dh)) {
              type["obj_cite_number_status"] = TriState.closing;
            } else {
              // type["obj_cite_number_status"] = TriState.closing;
              type["obj_cite_number_status"] = TriState.off;
            }
          } else {
            type["obj_cite_number_status"] =
              type["obj_cite_number_status_multi_obj"];
          }
        }
      } else if ((!line.empty) && (type["obj_cite_number_status_multi_obj"] > TriState.off)) {
        if (auto m = match(line, rgx.obj_cite_number_off_block_close)) {
          type["obj_cite_number_status_multi_obj"] = TriState.off;
          type["obj_cite_number_status"] = TriState.off;
          debug(ocnoff) {
            tell_l("green", line);
          }
        }
      }
      return 0;
    }
    auto start_block(
      char[] line,
      ref int[string] type,
      string[string] obj_cite_number_poem
    ) {
      if (match(line, rgx.block_curly_code_open)) {
        /+ curly code open +/
        debug(code) {                              // code (curly) open
          writefln(
            "%s* [code curly] %s%s",
            scr_txt_color["blue"],
            scr_txt_color["off"],
            line
          );
        }
        type["blocks"] = TriState.on;
        type["code"] = TriState.on;
        type["curly_code"] = TriState.on;
      } else if (match(line, rgx.block_curly_poem_open)) {
        /+ curly poem open +/
        debug(poem) {                              // poem (curly) open
          writefln(
            "%s* [poem curly] %s%s",
            scr_txt_color["red"],
            scr_txt_color["off"],
            line
          );
        }
        obj_cite_number_poem["start"] =
          to!string(obj_cite_number);
        type["blocks"] = TriState.on;
        type["verse_new"] = State.on;
        type["poem"] = TriState.on;
        type["curly_poem"] = TriState.on;
      } else if (match(line, rgx.block_curly_group_open)) {
        /+ curly group open +/
        debug(group) {                             // group (curly) open
          writefln(
            "%s* [group curly] %s%s",
            scr_txt_color["blue"],
            scr_txt_color["off"],
            line
          );
        }
        type["blocks"] = TriState.on;
        type["group"] = TriState.on;
        type["curly_group"] = TriState.on;
      } else if (match(line, rgx.block_curly_block_open)) {
        /+ curly block open +/
        debug(block) {                             // block (curly) open
          writefln(
            "%s* [block curly] %s%s",
            scr_txt_color["blue"],
            scr_txt_color["off"],
            line
          );
        }
        type["blocks"] = TriState.on;
        type["block"] = TriState.on;
        type["curly_block"] = TriState.on;
      } else if (match(line, rgx.block_curly_quote_open)) {
        /+ curly quote open +/
        debug(quote) {                             // quote (curly) open
          writefln(
            "%s* [quote curly] %s%s",
            scr_txt_color["blue"],
            scr_txt_color["off"],
            line
          );
        }
        type["blocks"] = TriState.on;
        type["quote"] = TriState.on;
        type["curly_quote"] = TriState.on;
      } else if (match(line, rgx.block_curly_table_open)) {
        /+ curly table open +/
        debug(table) {                             // table (curly) open
          writefln(
            "%s* [table curly] %s%s",
            scr_txt_color["blue"],
            scr_txt_color["off"],
            line
          );
        }
        type["blocks"] = TriState.on;
        type["table"] = TriState.on;
        type["curly_table"] = TriState.on;
      } else if (match(line, rgx.block_tic_code_open)) {
        /+ tic code open +/
        debug(code) {                              // code (tic) open
          writefln(
            "%s* [code tic] %s%s",
            scr_txt_color["blue"],
            scr_txt_color["off"],
            line
          );
        }
        type["blocks"] = TriState.on;
        type["code"] = TriState.on;
        type["tic_code"] = TriState.on;
      } else if (match(line, rgx.block_tic_poem_open)) {
        /+ tic poem open +/
        debug(poem) {                              // poem (tic) open
          writefln(
            "%s* [poem tic] %s%s",
            scr_txt_color["red"],
            scr_txt_color["off"],
            line
          );
        }
        obj_cite_number_poem["start"] = to!string(obj_cite_number);
        type["blocks"] = TriState.on;
        type["verse_new"] = State.on;
        type["poem"] = TriState.on;
        type["tic_poem"] = TriState.on;
      } else if (match(line, rgx.block_tic_group_open)) {
        /+ tic group open +/
        debug(group) {                             // group (tic) open
          writefln(
            "%s* [group tic] %s%s",
            scr_txt_color["blue"],
            scr_txt_color["off"],
            line
          );
        }
        type["blocks"] = TriState.on;
        type["group"] = TriState.on;
        type["tic_group"] = TriState.on;
      } else if (match(line, rgx.block_tic_block_open)) {
        /+ tic block open +/
        debug(block) {                             // block (tic) open
          writefln(
            "%s* [block tic] %s%s",
            scr_txt_color["blue"],
            scr_txt_color["off"],
            line
          );
        }
        type["blocks"] = TriState.on;
        type["block"] = TriState.on;
        type["tic_block"] = TriState.on;
      } else if (match(line, rgx.block_tic_quote_open)) {
        /+ tic quote open +/
        debug(quote) {                             // quote (tic) open
          writefln(
            "%s* [quote tic] %s%s",
            scr_txt_color["blue"],
            scr_txt_color["off"],
            line
          );
        }
        type["blocks"] = TriState.on;
        type["quote"] = TriState.on;
        type["tic_quote"] = TriState.on;
      } else if (match(line, rgx.block_tic_table_open)) {
        /+ tic table open +/
        debug(table) {                             // table (tic) open
          writefln(
            "%s* [table tic] %s%s",
            scr_txt_color["blue"],
            scr_txt_color["off"],
            line
          );
        }
        type["blocks"] = TriState.on;
        type["table"] = TriState.on;
        type["tic_table"] = TriState.on;
      }
      return 0;
    }
    auto code_block(
      char[] line,
      ref string[string] an_object,
      ref int[string] type
    ) {
      if (type["curly_code"] == TriState.on) {
        if (auto m = match(line, rgx.block_curly_code_close)) {
          debug(code) {                              // code (curly) close
            tell_l("blue", line);
          }
          type["blocks"] = TriState.closing;
          type["code"] = TriState.closing;
          type["curly_code"] = TriState.off;
        } else {
          debug(code) {                              // code (curly) line
            tell_l("blue", line);
          }
          an_object["obj"] ~= line ~= "\n";                       // code (curly) line
        }
      } else if (type["tic_code"] == TriState.on) {
        if (auto m = match(line, rgx.block_tic_close)) {
          debug(code) {                              // code (tic) close
            tell_l("blue", line);
          }
          type["blocks"] = TriState.closing;
          type["code"] = TriState.closing;
          type["tic_code"] = TriState.off;
        } else {
          debug(code) {                              // code (tic) line
            tell_l("blue", line);
          }
          an_object["obj"] ~= line ~= "\n";                       // code (tic) line
        }
      }
      return 0;
    }
    final 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];
    }
    auto biblio_block(
      char[] line,
      ref int[string] type,
      ref int bib_entry,
      ref string[] biblio_arr_json
    ) {
      if (match(line, rgx.heading_biblio)) {
        type["heading_biblio"] = TriState.on;
      }
      if (empty(line) && (bib_entry == TriState.off)) {
        biblio_arr_json ~= biblio_entry_tags_jsonstr;
        bib_entry = TriState.on;
      }
      debug(biblio) {
        writefln(
          "%s * %s %s",
          scr_txt_color["yellow"],
          scr_txt_color["off"],
          line
        );
      }
      if (match(line, rgx.biblio_tags)) {
        auto bt = match(line, rgx.biblio_tags);
        bib_entry = 0;
        st=to!string(bt.captures[1]);
        biblio_tag_entry=to!string(bt.captures[2]);
        JSONValue j = parseJSON(biblio_arr_json[$-1]);
        biblio_tag_name = (match(st, rgx.biblio_abbreviations))
          ? (biblio_tag_map(st))
          : st;
        j.object[biblio_tag_name] = biblio_tag_entry;
        auto header_tag_value=to!string(bt.captures[2]);
        switch (biblio_tag_name) {
        case "author_raw": // author_arr author (fn sn)
          j["author_arr"] =
            split(header_tag_value, rgx.arr_delimiter);
          string tmp;
          biblioAuthorLoop:
          foreach (au; j["author_arr"].array) {
            if (auto x = match(au.str, rgx.name_delimiter)) {
              tmp ~= x.captures[2] ~ " " ~ x.captures[1] ~ ", ";
            } else {
              tmp ~= au.str;
            }
          }
          tmp = replace(tmp, rgx.trailing_comma, "");
          // tmp = replace(tmp, regex(r"(,[ ]*)$","g"), "");
          j["author"].str = tmp;
          break;
        case "editor_raw": // editor_arr editor (fn sn)
          j["editor_arr"] =
            split(header_tag_value, rgx.arr_delimiter);
          string tmp;
          biblioEditorLoop:
          foreach (ed; j["editor_arr"].array) {
            if (auto x = match(ed.str, rgx.name_delimiter)) {
              tmp ~= x.captures[2] ~ " " ~ x.captures[1] ~ ", ";
            } else {
              tmp ~= ed.str;
            }
          }
          tmp = replace(tmp, rgx.trailing_comma, "");
          // tmp = replace(tmp, regex(r"(,[ ]*)$","g"), "");
          j["editor"].str = tmp;
          break;
        case "fulltitle": // title & subtitle
          break;
        default:
          break;
        }
        // header_tag_value="";
        auto s = to!string(j);
        s = j.toString();
        debug(biblio) {
          writefln(
            "%s* %s%s: %s\n%s",
            scr_txt_color["red"],
            scr_txt_color["off"],
            biblio_tag_name,
            biblio_tag_entry,
            j[biblio_tag_name]
          );
        }
        biblio_arr_json ~= s;
        biblio_tag_entry="";
      }
      return 0;
    }
    auto poem_block(
      char[] line,
      ref string[string] an_object,
      ref int[string] type,
      ref long counter,
      string[string] obj_cite_number_poem
    ) {
      if (type["curly_poem"] == TriState.on) {
        if (auto m = match(line, rgx.block_curly_poem_close)) {
          an_object["obj"]="verse"; // check that this is as you please
          debug(poem) {                            // poem (curly) close
            writefln(
              "%s* [poem curly] %s%s",
              scr_txt_color["red"],
              scr_txt_color["off"],
              line
            );
          }
          if (processing.length > 0) {
            an_object["obj"] = processing["verse"];
          }
          debug(poem) {                            // poem (curly) close
            writeln(__LINE__);
            writefln(
              "%s%s %s",
              scr_txt_marker["fuchsia"],
              obj_cite_number,
              line
            );
            // writeln(an_object.keys);
            // writeln(an_object.length);
          }
          if (an_object.length > 0) {
            debug(poem) {                            // poem (curly) close
              tell_lo(
                "fuchsia",
                obj_cite_number,
                an_object["obj"]
              );
            }
            an_object["is"] = "verse";
            an_object["substantive"] =
              obj_im.obj_inline_markup(an_object["is"], an_object["obj"]);
            an_object["attrib"] =
              obj_att.obj_attributes(an_object["is"], an_object["obj"], node);
            contents_the_objects ~=
              set_abstract_object.contents_block(
                an_object["is"],
                an_object["substantive"],
                an_object["attrib"],
                obj_cite_number
              );
            object_reset(an_object);
            processing.remove("verse");
            ++counter;
          }
          obj_cite_number_poem["end"] =
            to!string(obj_cite_number);
          type["blocks"] = TriState.closing;
          type["poem"] = TriState.closing;
          type["curly_poem"] = TriState.off;
        } else {
          processing["verse"] ~= line ~= "\n";
          if (type["verse_new"] == State.on) {
            obj_cite_number =
              obj_cite_number_emit(type["obj_cite_number_status"]);
            type["verse_new"] = State.off;
          } else if (match(line, rgx.line_delimiter_only)) {
            verse_line = TriState.off;
            type["verse_new"] = State.on;
          }
          if (type["verse_new"] == State.on) {
            verse_line=1;
            an_object["obj"] = processing["verse"];
            debug(poem) {                          // poem verse
              writefln(
                "%s%s curly\n%s",
                scr_txt_marker["green"],
                obj_cite_number,
                an_object["obj"]
              );
            }
            processing.remove("verse");
            an_object["is"] = "verse";
            node = node_jstr(
              content_non_header,
              obj_cite_number,
              counter,
              heading_pointer-1,
              an_object["is"]
            );
            an_object["substantive"] =
              obj_im.obj_inline_markup(an_object["is"], an_object["obj"]);
            an_object["attrib"] =
              obj_att.obj_attributes(an_object["is"], an_object["obj"], node);
            contents_the_objects ~=
              set_abstract_object.contents_block(
                an_object["is"],
                an_object["substantive"],
                an_object["attrib"],
                obj_cite_number
              );
            object_reset(an_object);
            processing.remove("verse");
            ++counter;
          }
        }
      } else if (type["tic_poem"] == TriState.on) {
        if (auto m = match(line, rgx.block_tic_close)) { // tic_poem_close
          an_object["obj"]="verse"; // check that this is as you please
          debug(poem) {                            // poem (curly) close
            writefln(
              "%s* [poem tic] %s%s",
              scr_txt_color["red"],
              scr_txt_color["off"],
              line
            );
          }
          if (processing.length > 0) {       // needs looking at
            an_object["obj"] = processing["verse"];
          }
          if (an_object.length > 0) {
            debug(poem) {                            // poem (tic) close
              writeln(__LINE__);
              tell_lo("fuchsia", obj_cite_number, line);
            }
            processing.remove("verse");
            an_object["is"] = "verse";
            an_object["substantive"] =
              obj_im.obj_inline_markup(an_object["is"], an_object["obj"]);
            an_object["attrib"] =
              obj_att.obj_attributes(an_object["is"], an_object["obj"], node);
            contents_the_objects ~=
              set_abstract_object.contents_block(
                an_object["is"],
                an_object["substantive"],
                an_object["attrib"],
                obj_cite_number
              );
            obj_cite_number_poem["end"] = to!string(obj_cite_number);
            object_reset(an_object);
            processing.remove("verse");
            ++counter;
          }
          type["blocks"] = TriState.closing;
          type["poem"] = TriState.closing;
          type["tic_poem"] = TriState.off;
        } else {
          processing["verse"] ~= line ~= "\n";
          if (type["verse_new"] == State.on) {
            obj_cite_number =
              obj_cite_number_emit(type["obj_cite_number_status"]);
            type["verse_new"] = State.off;
          } else if (match(line, rgx.line_delimiter_only)) {
            type["verse_new"] = State.on;
            verse_line = TriState.off;
          }
          if (type["verse_new"] == State.on) {
            verse_line=1;
            an_object["obj"] = processing["verse"];
            debug(poem) {                            // poem (tic) close
              writefln(
                "%s%s tic\n%s",
                scr_txt_marker["green"],
                obj_cite_number,
                an_object["obj"]
              );
            }
            processing.remove("verse");
            an_object["is"] = "verse";
            node =
              node_jstr(
                content_non_header,
                obj_cite_number,
                counter,
                heading_pointer-1,
                an_object["is"]
              );
            an_object["substantive"] =
              obj_im.obj_inline_markup(an_object["is"], an_object["obj"]);
            an_object["attrib"] =
              obj_att.obj_attributes(an_object["is"], an_object["obj"], node);
            contents_the_objects ~=
              set_abstract_object.contents_block(
                an_object["is"],
                an_object["substantive"],
                an_object["attrib"],
                obj_cite_number
              );
            object_reset(an_object);
            processing.remove("verse");
            ++counter;
          }
        }
      }
      return 0;
    }
    auto group_block(
      char[] line,
      ref string[string] an_object,
      ref int[string] type
    ) {
      if (type["curly_group"] == State.on) {
        if (match(line, rgx.block_curly_group_close)) {
          debug(group) {                           // group (curly) close
            tell_l("blue", line);
          }
          type["blocks"] = TriState.closing;
          type["group"] = TriState.closing;
          type["curly_group"] = TriState.off;
        } else {
          debug(group) {                           // group
            tell_l("blue", line);
          }
          an_object["obj"] ~= line ~= "\n";           // build group array (or string)
        }
      } else if (type["tic_group"] == TriState.on) {
        if (match(line, rgx.block_tic_close)) {
          debug(group) {                           // group (tic) close
            tell_l("blue", line);
          }
          type["blocks"] = TriState.closing;
          type["group"] = TriState.closing;
          type["tic_group"] = TriState.off;
        } else {
          debug(group) {                           // group
            tell_l("blue", line);
          }
          an_object["obj"] ~= line ~= "\n";           // build group array (or string)
        }
      }
      return 0;
    }
    auto block_block(
      char[] line,
      ref string[string] an_object,
      ref int[string] type
    ) {
      if (type["curly_block"] == TriState.on) {
        if (match(line, rgx.block_curly_block_close)) {
          debug(block) {                           // block (curly) close
            tell_l("blue", line);
          }
          type["blocks"] = TriState.closing;
          type["block"] = TriState.closing;
          type["curly_block"] = TriState.off;
        } else {
          debug(block) {                           // block
            tell_l("blue", line);
          }
          an_object["obj"] ~= line ~= "\n";           // build block array (or string)
        }
      } else if (type["tic_block"] == TriState.on) {
        if (match(line, rgx.block_tic_close)) {
          debug(block) {                           // block (tic) close
            tell_l("blue", line);
          }
          type["blocks"] = TriState.closing;
          type["block"] = TriState.closing;
          type["tic_block"] = TriState.off;
        } else {
          debug(block) {                           // block
            tell_l("blue", line);
          }
          an_object["obj"] ~= line ~= "\n";           // build block array (or string)
        }
      }
      return 0;
    }
    auto quote_block(char[] line, ref string[string] an_object, ref int[string] type) {
      if (type["curly_quote"] == TriState.on) {
        if (match(line, rgx.block_curly_quote_close)) {
          debug(quote) {                           // quote (curly) close
            tell_l("blue", line);
          }
          type["blocks"] = TriState.closing;
          type["quote"] = TriState.closing;
          type["curly_quote"] = TriState.off;
        } else {
          debug(quote) {                           // quote
            tell_l("blue", line);
          }
          an_object["obj"] ~= line ~= "\n";           // build quote array (or string)
        }
      } else if (type["tic_quote"] == TriState.on) {
        if (match(line, rgx.block_tic_close)) {
          debug(quote) {                           // quote (tic) close
            tell_l("blue", line);
          }
          type["blocks"] = TriState.closing;
          type["quote"] = TriState.closing;
          type["tic_quote"] = TriState.off;
        } else {
          debug(quote) {                           // quote
            tell_l("blue", line);
          }
          an_object["obj"] ~= line ~= "\n";           // build quote array (or string)
        }
      }
      return 0;
    }
    auto table_block(char[] line, ref string[string] an_object, ref int[string] type) {
      if (type["curly_table"] == TriState.on) {
        if (match(line, rgx.block_curly_table_close)) {
          debug(table) {                           // table (curly) close
            tell_l("blue", line);
          }
          type["blocks"] = TriState.closing;
          type["table"] = TriState.closing;
          type["curly_table"] = TriState.off;
        } else {
          debug(table) {                           // table
            tell_l("blue", line);
          }
          an_object["obj"] ~= line ~= "\n";           // build table array (or string)
        }
      } else if (type["tic_table"] == TriState.on) {
        if (match(line, rgx.block_tic_close)) {
          debug(table) {                           // table (tic) close
            tell_l("blue", line);
          }
          type["blocks"] = TriState.closing;
          type["table"] = TriState.closing;
          type["tic_table"] = TriState.off;
        } else {
          debug(table) {                           // table
            tell_l("blue", line);
          }
          an_object["obj"] ~= line ~= "\n";           // build table array (or string)
        }
      }
      return 0;
    }
    auto block_flag_line_empty(
      char[] line,
      ref string[string] an_object,
      ref ObjComposite[] contents_the_objects,
      ref string[][string][string] bookindex_unordered_hashes,
      ref int obj_cite_number,
      ref string node,
      ref long counter,
      ref int[string] type,
      string[string] obj_cite_number_poem
    ) {
      // line.empty, post contents, empty variables ---------------
      assert(
        line.empty,
        "line should be empty"
      );
      assert(
        (type["blocks"] == TriState.closing),
        "code block status: closed"
      );
      assertions_flag_types_block_status_none_or_closed(type);
      if (type["code"] == TriState.closing) {
        obj_cite_number =
          obj_cite_number_emit(type["obj_cite_number_status"]);
        an_object["bookindex"] =
          ("bookindex" in an_object) ? an_object["bookindex"] : "";
        bookindex_unordered_hashes =
          bkidx_hash(an_object["bookindex"], obj_cite_number);
        an_object["is"] = "code";
        node =
          node_jstr(
            content_non_header,
            obj_cite_number,
            counter,
            heading_pointer-1,
            an_object["is"]
          );
        an_object["substantive"] =
          obj_im.obj_inline_markup(an_object["is"], an_object["obj"]);
        an_object["attrib"] =
          obj_att.obj_attributes(an_object["is"], an_object["obj"], node);
        contents_the_objects ~=
          set_abstract_object.contents_block(
            an_object["is"],
            an_object["substantive"],
            an_object["attrib"],
            obj_cite_number
          );
        object_reset(an_object);
        processing.remove("verse");
        ++counter;
        type["blocks"] = TriState.off;
        type["code"] = TriState.off;
      } else if (type["poem"] == TriState.closing) {
        an_object["bookindex"] =
          ("bookindex" in an_object) ? an_object["bookindex"] : "";
        bookindex_unordered_hashes =
          bkidx_hash(an_object["bookindex"], obj_cite_number);
        // obj_cite_number = obj_cite_number_emit(type["obj_cite_number_status"]);
        an_object["is"] = "verse"; // check also
        node =
          node_jstr(
            content_non_header,
            obj_cite_number,
            counter,
            heading_pointer-1,
            an_object["is"]
            // "verse"
          );
        contents_the_objects ~=
          set_abstract_object.contents_block_obj_cite_number_string(
            "poem",
            "",
            (obj_cite_number_poem["start"], obj_cite_number_poem["end"]),
            node
          ); // bookindex
        object_reset(an_object);
        processing.remove("verse");
        // ++obj_cite_number;
        type["blocks"] = TriState.off;
        type["poem"] = TriState.off;
      } else if (type["table"] == TriState.closing) {
        obj_cite_number =
          obj_cite_number_emit(type["obj_cite_number_status"]);
        an_object["bookindex"] =
          ("bookindex" in an_object) ? an_object["bookindex"] : "";
        bookindex_unordered_hashes =
          bkidx_hash(an_object["bookindex"], obj_cite_number);
        an_object["is"] = "table";
        node =
          node_jstr(
            content_non_header,
            obj_cite_number,
            counter,
            heading_pointer-1,
            an_object["is"]
          );
        an_object["substantive"] =
          obj_im.obj_inline_markup(an_object["is"], an_object["obj"]);
        an_object["attrib"] =
          obj_att.obj_attributes(an_object["is"], an_object["obj"], node);
        contents_the_objects ~=
          set_abstract_object.contents_block(
            an_object["is"],
            an_object["substantive"],
            an_object["attrib"],
            obj_cite_number
          );
        object_reset(an_object);
        processing.remove("verse");
        ++counter;
        type["blocks"] = TriState.off;
        type["table"] = TriState.off;
      } else if (type["group"] == TriState.closing) {
        obj_cite_number =
          obj_cite_number_emit(type["obj_cite_number_status"]);
        an_object["bookindex"] =
          ("bookindex" in an_object) ? an_object["bookindex"] : "";
        bookindex_unordered_hashes =
          bkidx_hash(an_object["bookindex"], obj_cite_number);
        an_object["is"] = "group";
        node =
          node_jstr(
            content_non_header,
            obj_cite_number,
            counter,
            heading_pointer-1,
            an_object["is"]
          );
        an_object["substantive"] =
          obj_im.obj_inline_markup(an_object["is"], an_object["obj"]);
        an_object["attrib"] =
          obj_att.obj_attributes(an_object["is"], an_object["obj"], node);
        contents_the_objects ~=
          set_abstract_object.contents_block(
            an_object["is"],
            an_object["substantive"],
            an_object["attrib"],
            obj_cite_number
          );
        object_reset(an_object);
        processing.remove("verse");
        ++counter;
        type["blocks"] = TriState.off;
        type["group"] = TriState.off;
      } else if (type["block"] == TriState.closing) {
        obj_cite_number = obj_cite_number_emit(type["obj_cite_number_status"]);
        an_object["bookindex"] =
          ("bookindex" in an_object) ? an_object["bookindex"] : "";
        bookindex_unordered_hashes =
          bkidx_hash(an_object["bookindex"], obj_cite_number);
        an_object["is"] = "block";
        node =
          node_jstr(
            content_non_header,
            obj_cite_number,
            counter,
            heading_pointer-1,
            an_object["is"]
           );
        an_object["substantive"] =
          obj_im.obj_inline_markup(an_object["is"], an_object["obj"]);
        an_object["attrib"] =
          obj_att.obj_attributes(an_object["is"], an_object["obj"], node);
        contents_the_objects ~=
          set_abstract_object.contents_block(
            an_object["is"],
            an_object["substantive"],
            an_object["attrib"],
            obj_cite_number
          );
        object_reset(an_object);
        processing.remove("verse");
        ++counter;
        type["blocks"] = TriState.off;
        type["block"] = TriState.off;
      } else if (type["quote"] == TriState.closing) {
        obj_cite_number =
          obj_cite_number_emit(type["obj_cite_number_status"]);
        an_object["bookindex"] =
          ("bookindex" in an_object) ? an_object["bookindex"] : "";
        bookindex_unordered_hashes =
          bkidx_hash(an_object["bookindex"], obj_cite_number);
        an_object["is"] = "quote";
        node =
          node_jstr(
            content_non_header,
            obj_cite_number,
            counter,
            heading_pointer-1,
            an_object["is"]
          );
        an_object["substantive"] =
          obj_im.obj_inline_markup(an_object["is"], an_object["obj"]);
        an_object["attrib"] =
          obj_att.obj_attributes(an_object["is"], an_object["obj"], node);
        contents_the_objects ~=
          set_abstract_object.contents_block(
            an_object["is"],
            an_object["substantive"],
            an_object["attrib"],
            obj_cite_number
          );
        object_reset(an_object);
        processing.remove("verse");
        ++counter;
        type["blocks"] = TriState.off;
        type["quote"] = TriState.off;
      }
      return 0;
    }
    auto book_index(
      char[] line,
      ref string book_idx_tmp,
      ref string[string] an_object,
      ref int[string] type
    ) {
      if (auto m = match(line, rgx.book_index)) {
        /+ match book_index +/
        debug(bookindexmatch) {                       // book index
          writefln(
            "%s* [bookindex] %s%s\n",
            scr_txt_color["blue"],
            scr_txt_color["off"],
            to!string(m.captures[1]),
          );
          // writeln(scr_txt_marker["blue"], to!string(m.captures[1]), "\n");
        }
        an_object["bookindex"] = to!string(m.captures[1]);
      } else if (auto m = match(line, rgx.book_index_open))  {
        /+ match open book_index +/
        type["book_index"] = State.on;
        book_idx_tmp = to!string(m.captures[1]);
        debug(bookindexmatch) {                       // book index
          writefln(
            "%s* [bookindex] %s%s\n",
            scr_txt_color["blue"],
            scr_txt_color["off"],
            book_idx_tmp,
          );
          // writeln(scr_txt_marker["blue"], book_idx_tmp, "\n");
        }
      } else if (type["book_index"] == State.on )  {
        /+ book_index flag set +/
        if (auto m = match(line, rgx.book_index_close))  {
          type["book_index"] = State.off;
          an_object["bookindex"] = book_idx_tmp ~ to!string(m.captures[1]);
          debug(bookindexmatch) {                     // book index
            writefln(
              "%s* [bookindex] %s%s\n",
              scr_txt_color["blue"],
              scr_txt_color["off"],
              book_idx_tmp,
            );
            // writeln(scr_txt_marker["blue"], book_idx_tmp, "\n");
          }
          book_idx_tmp = "";
        } else {
          book_idx_tmp ~= line;
        }
      }
    }
    auto header_extract(
      char[] line,
      ref int[string] line_occur,
      ref string[string] an_object,
      ref int[string] type
    ) {
      if (auto m = match(line, rgx.header_make)) {
        /+ matched header_make +/
        debug(header1) {                          // header
          tell_l("yellow", line);
        }
        type["header"] = State.on;
        type["header_make"] = State.on;
        type["header_metadata"] = State.off;
        type["heading"] = State.off;
        type["para"] = State.off;
        ++line_occur["header_make"];
        an_object["obj"] ~= line ~= "\n";
      } else if (auto m = match(line, rgx.header_metadata)) {
        /+ matched header_metadata +/
        debug(header1) {                          // header
          tell_l("yellow", line);
        }
        type["header"] = State.on;
        type["header_make"] = State.off;
        type["header_metadata"] = State.on;
        type["heading"] = State.off;
        type["para"] = State.off;
        ++line_occur["header_metadata"];
        an_object["obj"] ~= line ~= "\n";
      } else if (type["header_make"] == State.on
      && (line_occur["header_make"] > State.off)) {
        /+ header_make flag set +/
        if (auto m = match(line, rgx.header_sub)) {
          /+ sub-header +/
          debug(header1) {
            tell_l("yellow", line);
          }
          // type["header"] = State.on;
          ++line_occur["header_make"];
          an_object["obj"] ~= line ~= "\n";
        }
      } else if (type["header_metadata"] == State.on
      && (line_occur["header_metadata"] > State.off)) {
        /+ header_metadata flag set +/
        if (auto m = match(line, rgx.header_sub)) {
          /+ sub-header +/
          debug(header1) {
            tell_l("yellow", line);
          }
          ++line_occur["header_metadata"];
          an_object["obj"] ~= line ~= "\n";
        }
      }
      return 0;
    }
    auto heading_found(
      char[] line,
      string dochead_make_headings,
      ref string[string] heading_match_str,
      ref Regex!(char)[string] heading_match_rgx,
      ref int[string] type
    ) {
      if ((to!string(dochead_make_headings).length > 2)
      && (type["make_headings"] == State.off)) {
        /+ headings found +/
        debug(headingsfound) {
          writeln(dochead_make_headings);
        }
        auto make_headings_txt =
          match(
            to!string(dochead_make_headings),
            rgx.within_quotes);
        char[][] make_headings_spl =
          split(
            cast(char[]) make_headings_txt.captures[1],
            rgx.make_heading_delimiter);
        debug(headingsfound) {
          writeln(make_headings_spl.length);
          writeln(make_headings_spl);
        }
        switch (make_headings_spl.length) {
        case 7 :
          if (!empty(make_headings_spl[6])) {
            heading_match_str["h_4"] =
              "^(" ~ to!string(make_headings_spl[6]) ~ ")";
            heading_match_rgx["h_4"] =
              regex(heading_match_str["h_4"]);
          }
          goto case;
        case 6 :
          if (!empty(make_headings_spl[5])) {
            heading_match_str["h_3"] =
              "^(" ~ to!string(make_headings_spl[5]) ~ ")";
            heading_match_rgx["h_3"] =
              regex(heading_match_str["h_3"]);
          }
          goto case;
        case 5 :
          if (!empty(make_headings_spl[4])) {
            heading_match_str["h_2"] =
              "^(" ~ to!string(make_headings_spl[4]) ~ ")";
            heading_match_rgx["h_2"] =
              regex(heading_match_str["h_2"]);
          }
          goto case;
        case 4 :
          if (!empty(make_headings_spl[3])) {
            heading_match_str["h_1"] =
              "^(" ~ to!string(make_headings_spl[3]) ~ ")";
            heading_match_rgx["h_1"] =
              regex(heading_match_str["h_1"]);
          }
          goto case;
        case 3 :
          if (!empty(make_headings_spl[2])) {
            heading_match_str["h_D"] =
              "^(" ~ to!string(make_headings_spl[2]) ~ ")";
            heading_match_rgx["h_D"] =
              regex(heading_match_str["h_D"]);
          }
          goto case;
        case 2 :
          if (!empty(make_headings_spl[1])) {
            heading_match_str["h_C"] =
              "^(" ~ to!string(make_headings_spl[1]) ~ ")";
            heading_match_rgx["h_C"] =
              regex(heading_match_str["h_C"]);
          }
          goto case;
        case 1 :
          if (!empty(make_headings_spl[0])) {
            heading_match_str["h_B"] =
              "^(" ~ to!string(make_headings_spl[0]) ~ ")";
            heading_match_rgx["h_B"] =
              regex(heading_match_str["h_B"]);
          }
          break;
        default:
          break;
        }
        type["make_headings"] = State.on;
      }
    }
    auto heading_make_set(
      ref char[] line,
      ref int[string] line_occur,
      ref Regex!(char)[string] heading_match_rgx,
      ref int[string] type
    ) {
      if ((type["make_headings"] == State.on)
      && ((line_occur["para"] == State.off)
      && (line_occur["heading"] == State.off))
      && ((type["para"] == State.off)
      && (type["heading"] == State.off))) {
        /+ heading make set +/
        if (match(line, heading_match_rgx["h_B"])) {
          line = "B~ " ~ line;
          debug(headingsfound) {
            writeln(line);
          }
        }
        if (match(line, heading_match_rgx["h_C"])) {
          line = "C~ " ~ line;
          debug(headingsfound) {
            writeln(line);
          }
        }
        if (match(line, heading_match_rgx["h_D"])) {
          line = "D~ " ~ line;
          debug(headingsfound) {
            writeln(line);
          }
        }
        if (match(line, heading_match_rgx["h_1"])) {
          line = "1~ " ~ line;
          debug(headingsfound) {
            writeln(line);
          }
        }
        if (match(line, heading_match_rgx["h_2"])) {
          line = "2~ " ~ line;
          debug(headingsfound) {
            writeln(line);
          }
        }
        if (match(line, heading_match_rgx["h_3"])) {
          line = "3~ " ~ line;
          debug(headingsfound) {
            writeln(line);
          }
        }
        if (match(line, heading_match_rgx["h_4"])) {
          line = "4~ " ~ line;
          debug(headingsfound) {
            writeln(line);
          }
        }
      }
    }
    auto heading_match(
      char[] line,
      ref int[string] line_occur,
      ref string[string] an_object,
      ref int[string] lv,
      ref int[string] collapsed_lev,
      ref int[string] type
    ) {
      if (auto m = match(line, rgx.heading)) {
        /+ heading match +/
        type["heading"] = State.on;
        type["header"] = State.off;
        type["header_make"] = State.off;
        type["header_metadata"] = State.off;
        type["heading_biblio"] = State.off;
        type["para"] = State.off;
        ++line_occur["heading"];
        an_object["obj"] ~= line ~= "\n";
        an_object["lev"] ~= m.captures[1];
        assertions_doc_structure(an_object, lv); // includes most of the logic for collapsed levels
        switch (an_object["lev"]) {
        case "A":
          collapsed_lev["h0"] = 1;
          an_object["lev_collapsed_number"] =
            to!string(collapsed_lev["h0"]);
          lv["lv"] = DocStructMarkupHeading.h_sect_A;
          ++lv["h0"];
          lv["h1"] = State.off;
          lv["h2"] = State.off;
          lv["h3"] = State.off;
          lv["h4"] = State.off;
          lv["h5"] = State.off;
          lv["h6"] = State.off;
          lv["h7"] = State.off;
          goto default;
        case "B":
          collapsed_lev["h1"] = collapsed_lev["h0"] + 1;
          an_object["lev_collapsed_number"] =
            to!string(collapsed_lev["h1"]);
          lv["lv"] = DocStructMarkupHeading.h_sect_B;
          ++lv["h1"];
          lv["h2"] = State.off;
          lv["h3"] = State.off;
          lv["h4"] = State.off;
          lv["h5"] = State.off;
          lv["h6"] = State.off;
          lv["h7"] = State.off;
          goto default;
        case "C":
          collapsed_lev["h2"] = collapsed_lev["h1"] + 1;
          an_object["lev_collapsed_number"] =
            to!string(collapsed_lev["h2"]);
          lv["lv"] = DocStructMarkupHeading.h_sect_C;
          ++lv["h2"];
          lv["h3"] = State.off;
          lv["h4"] = State.off;
          lv["h5"] = State.off;
          lv["h6"] = State.off;
          lv["h7"] = State.off;
          goto default;
        case "D":
          collapsed_lev["h3"] = collapsed_lev["h2"] + 1;
          an_object["lev_collapsed_number"] =
            to!string(collapsed_lev["h3"]);
          lv["lv"] = DocStructMarkupHeading.h_sect_D;
          ++lv["h3"];
          lv["h4"] = State.off;
          lv["h5"] = State.off;
          lv["h6"] = State.off;
          lv["h7"] = State.off;
          goto default;
        case "1":
          if (lv["h3"] > State.off) {
            collapsed_lev["h4"] = collapsed_lev["h3"] + 1;
          } else if (lv["h2"] > State.off) {
            collapsed_lev["h4"] = collapsed_lev["h2"] + 1;
          } else if (lv["h1"] > State.off) {
            collapsed_lev["h4"] = collapsed_lev["h1"] + 1;
          } else if (lv["h0"] > State.off) {
            collapsed_lev["h4"] = collapsed_lev["h0"] + 1;
          }
          an_object["lev_collapsed_number"] =
            to!string(collapsed_lev["h4"]);
          lv["lv"] = DocStructMarkupHeading.h_text_1;
          ++lv["h4"];
          lv["h5"] = State.off;
          lv["h6"] = State.off;
          lv["h7"] = State.off;
          goto default;
        case "2":
          if (lv["h5"] > State.off) {
            an_object["lev_collapsed_number"] =
              to!string(collapsed_lev["h5"]);
          } else if (lv["h4"] > State.off) {
            collapsed_lev["h5"] = collapsed_lev["h4"] + 1;
            an_object["lev_collapsed_number"] =
              to!string(collapsed_lev["h5"]);
          }
          lv["lv"] = DocStructMarkupHeading.h_text_2;
          ++lv["h5"];
          lv["h6"] = State.off;
          lv["h7"] = State.off;
          goto default;
        case "3":
          if (lv["h6"] > State.off) {
            an_object["lev_collapsed_number"] =
              to!string(collapsed_lev["h6"]);
          } else if (lv["h5"] > State.off) {
            collapsed_lev["h6"] = collapsed_lev["h5"] + 1;
            an_object["lev_collapsed_number"] =
              to!string(collapsed_lev["h6"]);
          }
          lv["lv"] = DocStructMarkupHeading.h_text_3;
          ++lv["h6"];
          lv["h7"] = State.off;
          goto default;
        case "4":
          if (lv["h7"] > State.off) {
            an_object["lev_collapsed_number"] =
              to!string(collapsed_lev["h7"]);
          } else if (lv["h6"] > State.off) {
            collapsed_lev["h7"] = collapsed_lev["h6"] + 1;
            an_object["lev_collapsed_number"] =
              to!string(collapsed_lev["h7"]);
          }
          lv["lv"] = DocStructMarkupHeading.h_text_4;
          ++lv["h7"];
          goto default;
        default:
          an_object["lev_markup_number"] = to!string(lv["lv"]);
        }
        debug(heading) {                         // heading
          // writeln(m.captures[1], " ", m.captures[2], "\n");      // figure inclusion of post capture text
          // writeln(m.hit, "\n");
          tell_l("yellow", strip(line));
        }
      }
    }
    auto para_match(
      char[] line,
      ref string[string] an_object,
      ref string[string] indent,
      ref bool bullet,
      ref int[string] type
    ) {
      if (line_occur["para"] == State.off) {
        /+ para matches +/
          // paragraphs
          // (fl  ag_type["heading"] = true) &&
        if (auto m = match(line, rgx.para_indent)) {
          debug(paraindent) {                    // para indent
            tell_l("blue", line);
          }
          type["para"] = State.on;
          an_object["obj"] ~= line ~= "\n";
          indent["first"] = to!string(m.captures[1]);
          indent["second"] = "0";
          bullet = false;
        } else if (auto m = match(line, rgx.para_bullet)) {
          debug(parabullet) {                    // para bullet
            tell_l("blue", line);
          }
          type["para"] = State.on;
          an_object["obj"] ~= line;
          indent["first"] = "0";
          indent["second"] = "0";
          bullet = true;
        } else if (auto m = match(line, rgx.para_indent_hang)) {
          debug(paraindenthang) {                // para indent hang
            tell_l("blue", line);
          }
          type["para"] = State.on;
          an_object["obj"] ~= line;
          indent["first"] = to!string(m.captures[1]);
          indent["second"] = to!string(m.captures[2]);
          bullet = false;
        } else if (auto m = match(line, rgx.para_bullet_indent)) {
          debug(parabulletindent) {              // para bullet indent
            tell_l("blue", line);
          }
          type["para"] = State.on;
          an_object["obj"] ~= line;
          indent["first"] = to!string(m.captures[1]);
          indent["second"] = "0";
          bullet = true;
        } else {
          // !line.empty
          type["para"] = State.on;
          an_object["obj"] ~= line;
          indent["first"] = "0";
          indent["second"] = "0";
          bullet = false;
        }
        ++line_occur["para"];
      }
    }
    /+ abstraction functions ↑ +/

    /+ ↓ abstraction function emitters +/
    struct OCNemitter {
    // class OCNemitter : AssertOCN {
      int obj_cite_number, obj_cite_number_;
      int obj_cite_number_emitter(int obj_cite_number_status_flag)
      in { assert(obj_cite_number_status_flag <= 2); }
      body {
        if (obj_cite_number_status_flag == 0) {
          obj_cite_number=++obj_cite_number_;
        } else {
          obj_cite_number=0;
        }
        assert(obj_cite_number >= 0);
        return obj_cite_number;
      }
      invariant() {
      }
    }
    struct ObjAttributes {
    // class ObjAttributes : AssertObjAttributes {
      string[string] obj_txt;
      string para_and_blocks(string obj_txt_in)
      in { }
      body {
        auto rgx = Rgx();
        obj_txt["munge"]=obj_txt_in;
        if (match(obj_txt_in, rgx.para_bullet)) {
          obj_txt["attrib"] =" \"bullet\": \"true\","
          ~ " \"indent_first\": 0,"
          ~ " \"indent_rest\": 0,";
        } else if (auto m = match(obj_txt_in, rgx.para_bullet_indent)) {
          obj_txt["attrib"] =" \"bullet\": \"true\","
          ~ " \"indent_first\": " ~ to!string(m.captures[1]) ~ ","
          ~ " \"indent_rest\": " ~ to!string(m.captures[1]) ~ ",";
        } else if (auto m = match(obj_txt_in, rgx.para_indent_hang)) {
          obj_txt["attrib"] =" \"bullet\": \"false\","
          ~ " \"indent_first\": " ~ to!string(m.captures[1]) ~ ","
          ~ " \"indent_rest\": " ~  to!string(m.captures[2]) ~ ",";
        } else if (auto m = match(obj_txt_in, rgx.para_indent)) {
          obj_txt["attrib"] =" \"bullet\": \"false\","
          ~ " \"indent_first\": " ~ to!string(m.captures[1]) ~ ","
          ~ " \"indent_rest\": " ~ to!string(m.captures[1]) ~ ",";
        } else {
          obj_txt["attrib"] =" \"bullet\": \"false\","
          ~ " \"indent_first\": 0,"
          ~ " \"indent_rest\": 0,";
        }
        return obj_txt["attrib"];
      }
      string para(string obj_txt_in)
      in { }
      body {
        obj_txt["munge"]=obj_txt_in;
        obj_txt["attrib"] = " \"use\": \"content\","
        ~ " \"of\": \"para\","
        ~ " \"is\": \"para\"";
        return obj_txt["attrib"];
      }
      invariant() {
      }
      string heading(string obj_txt_in)
      in { }
      body {
        obj_txt["munge"]=obj_txt_in;
        obj_txt["attrib"] = " \"use\": \"content\","
        ~ " \"of\": \"para\","
        ~ " \"is\": \"heading\"";
        // obj_txt["struct"]=;
        return obj_txt["attrib"];
      }
      invariant() {
      }
      string header_make(string obj_txt_in)
      in { }
      body {
        obj_txt["munge"]=obj_txt_in;
        obj_txt["attrib"] = " \"use\": \"head\","
        ~ " \"of\": \"header\","
        ~ " \"is\": \"header_make\"";
        return obj_txt["attrib"];
      }
      invariant() {
      }
      string header_metadata(string obj_txt_in)
      in { }
      body {
        obj_txt["munge"]=obj_txt_in;
        obj_txt["attrib"] = " \"use\": \"head\","
        ~ " \"of\": \"header\","
        ~ " \"is\": \"header_metadata\"";
        return obj_txt["attrib"];
      }
      invariant() {
      }
      string code(string obj_txt_in)
      in { }
      body {
        obj_txt["munge"]=obj_txt_in;
        obj_txt["attrib"] = " \"use\": \"content\","
        ~ " \"of\": \"block\","
        ~ " \"is\": \"code\"";
        return obj_txt["attrib"];
      }
      invariant() {
      }
      string group(string obj_txt_in)
      in { }
      body {
        obj_txt["munge"]=obj_txt_in;
        obj_txt["attrib"] = " \"use\": \"content\","
        ~ " \"of\": \"block\","
        ~ " \"is\": \"group\"";
        return obj_txt["attrib"];
      }
      invariant() {
      }
      string block(string obj_txt_in)
      in { }
      body {
        obj_txt["munge"]=obj_txt_in;
        obj_txt["attrib"] = " \"use\": \"content\","
        ~ " \"of\": \"block\","
        ~ " \"is\": \"block\"";
        return obj_txt["attrib"];
      }
      invariant() {
      }
      string verse(string obj_txt_in)
      in { }
      body {
        obj_txt["munge"]=obj_txt_in;
        obj_txt["attrib"] = " \"use\": \"content\","
        ~ " \"of\": \"block\","
        ~ " \"is\": \"verse\"";
        return obj_txt["attrib"];
      }
      invariant() {
      }
      string quote(string obj_txt_in)
      in { }
      body {
        obj_txt["munge"]=obj_txt_in;
        obj_txt["attrib"] = " \"use\": \"content\","
        ~ " \"of\": \"block\","
        ~ " \"is\": \"quote\"";
        return obj_txt["attrib"];
      }
      invariant() {
      }
      string table(string obj_txt_in)
      in { }
      body {
        obj_txt["munge"]=obj_txt_in;
        obj_txt["attrib"] = " \"use\": \"content\","
        ~ " \"of\": \"block\","
        ~ " \"is\": \"table\"";
        return obj_txt["attrib"];
      }
      invariant() {
      }
      string comment(string obj_txt_in)
      in { }
      body {
        obj_txt["munge"]=obj_txt_in;
        obj_txt["attrib"] = " \"use\": \"comment\","
        ~ " \"of\": \"comment\","
        ~ " \"is\": \"comment\"";
        return obj_txt["attrib"];
      }
      invariant() {
      }
    }
    struct ObjInlineMarkupMunge {
    // struct ObjInlineMarkupMunge : AssertObjInlineMarkup {
      string[string] obj_txt;
      int n_foot, n_foot_reg, n_foot_sp_asterisk, n_foot_sp_plus;
      string obj_txt_out, tail, note;
      private auto initialize_note_numbers() {
        n_foot = 0;
        n_foot_reg = 0;
        n_foot_sp_asterisk = 0;
        n_foot_sp_plus = 0;
      }
      private auto object_notes_(string obj_txt_in)
      in { }
      body {
        auto rgx = Rgx();
        auto mkup = InlineMarkup();
        obj_txt_out = "";
        tail = "";
        obj_txt_in = replaceAll(
          obj_txt_in,
          rgx.inline_notes_curly_sp_asterisk,
          (mkup.en_a_o ~ "*" ~ " $1" ~ mkup.en_a_c)
        );
        obj_txt_in =
          replaceAll(
            obj_txt_in,
            rgx.inline_notes_curly_sp_plus,
            (mkup.en_a_o ~ "+" ~ " $1" ~ mkup.en_a_c)
          );
        obj_txt_in =
          replaceAll(
            obj_txt_in,
            rgx.inline_notes_curly,
            (mkup.en_a_o ~ " $1" ~ mkup.en_a_c)
          );
        if (match(obj_txt_in, rgx.inline_notes_al_gen)) {
          foreach(m; matchAll(obj_txt_in, rgx.inline_text_and_note_al)) {
            if (match(obj_txt_in, rgx.inline_al_delimiter_open_asterisk)) {
              ++n_foot_sp_asterisk;
              n_foot=n_foot_sp_asterisk;
            } else if (match(obj_txt_in, rgx.inline_al_delimiter_open_plus)) {
              ++n_foot_sp_plus;
              n_foot=n_foot_sp_plus;
            } else {
              ++n_foot_reg;
              n_foot=n_foot_reg;
            }
            obj_txt_out ~= replaceFirst(
              m.hit,
              rgx.inline_al_delimiter_open_regular,
              (mkup.en_a_o ~ to!string(n_foot))
            );
            tail = m.post;
            // if (!empty(m.post)) {
            //   tail = m.post;
            // } else {
            //   tail = "";
            // }
          }
        } else {
          obj_txt_out = obj_txt_in;
        }
        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.captures[1]);
            writeln(m.hit);
          }
        }
        return obj_txt_out;
      }
      string para(string obj_txt_in)
      in { }
      body {
        auto rgx = Rgx();
        obj_txt["munge"]=obj_txt_in;
        obj_txt["munge"]=replaceFirst(obj_txt["munge"], rgx.para_attribs, "");
        obj_txt["munge"]=replaceFirst(obj_txt["munge"], rgx.obj_cite_number_off_all, "");
        obj_txt["munge"]=object_notes_(obj_txt["munge"]);
        debug(munge) {
          writeln(__LINE__);
          writeln(obj_txt_in);
          writeln(__LINE__);
          writeln(to!string(obj_txt["munge"]));
        }
        return obj_txt["munge"];
      }
      string heading(string obj_txt_in)
      in { }
      body {
        auto rgx = Rgx();
        obj_txt["munge"]=obj_txt_in;
        obj_txt["munge"]=replaceFirst(obj_txt["munge"], rgx.heading, "");
        obj_txt["munge"]=replaceFirst(obj_txt["munge"], rgx.obj_cite_number_off_all, "");
        obj_txt["munge"]=object_notes_(obj_txt["munge"]);
        debug(munge) {
          writeln(__LINE__);
          writeln(obj_txt_in);
          writeln(__LINE__);
          writeln(to!string(obj_txt["munge"]));
        }
        return obj_txt["munge"];
      }
      invariant() {
      }
      string header_make(string obj_txt_in)
      in { }
      body {
        obj_txt["munge"]=obj_txt_in;
        return obj_txt["munge"];
      }
      invariant() {
      }
      string header_metadata(string obj_txt_in)
      in { }
      body {
        obj_txt["munge"]=obj_txt_in;
        return obj_txt["munge"];
      }
      invariant() {
      }
      string code(string obj_txt_in)
      in { }
      body {
        obj_txt["munge"]=obj_txt_in;
        return obj_txt["munge"];
      }
      invariant() {
      }
      string group(string obj_txt_in)
      in { }
      body {
        obj_txt["munge"]=obj_txt_in;
        obj_txt["munge"]=object_notes_(obj_txt["munge"]);
        return obj_txt["munge"];
      }
      invariant() {
      }
      string block(string obj_txt_in)
      in { }
      body {
        obj_txt["munge"]=obj_txt_in;
        obj_txt["munge"]=object_notes_(obj_txt["munge"]);
        return obj_txt["munge"];
      }
      invariant() {
      }
      string verse(string obj_txt_in)
      in { }
      body {
        obj_txt["munge"]=obj_txt_in;
        obj_txt["munge"]=object_notes_(obj_txt["munge"]);
        return obj_txt["munge"];
      }
      invariant() {
      }
      string quote(string obj_txt_in)
      in { }
      body {
        obj_txt["munge"]=obj_txt_in;
        return obj_txt["munge"];
      }
      invariant() {
      }
      string table(string obj_txt_in)
      in { }
      body {
        obj_txt["munge"]=obj_txt_in;
        return obj_txt["munge"];
      }
      invariant() {
      }
      string comment(string obj_txt_in)
      in { }
      body {
        obj_txt["munge"]=obj_txt_in;
        return obj_txt["munge"];
      }
      invariant() {
      }
    }
    struct ObjInlineMarkup {
    // struct ObjInlineMarkup : AssertObjInlineMarkup {
      auto munge = ObjInlineMarkupMunge();
      string[string] obj_txt;
      string obj_inline_markup(string obj_is_, string obj_raw)
      in { }
      body {
        obj_txt["munge"]=obj_raw.dup;
        obj_txt["munge"]=(match(obj_is_, ctRegex!(`verse|code`)))
          ? obj_txt["munge"]
          : strip(obj_txt["munge"]);
        switch (obj_is_) {
        case "header_make":
          obj_txt["munge"]=munge.header_make(obj_txt["munge"]);
          break;
        case "header_metadata":
          obj_txt["munge"]=munge.header_metadata(obj_txt["munge"]);
          break;
        case "heading":
          obj_txt["munge"]=munge.heading(obj_txt["munge"]);
          break;
        case "para":
          obj_txt["munge"]=munge.para(obj_txt["munge"]);
          break;
        case "code":
          obj_txt["munge"]=munge.code(obj_txt["munge"]);
          break;
        case "group":
          obj_txt["munge"]=munge.group(obj_txt["munge"]);
          break;
        case "block":
          obj_txt["munge"]=munge.block(obj_txt["munge"]);
          break;
        case "verse":
          obj_txt["munge"]=munge.verse(obj_txt["munge"]);
          break;
        case "quote":
          obj_txt["munge"]=munge.quote(obj_txt["munge"]);
          break;
        case "table":
          obj_txt["munge"]=munge.table(obj_txt["munge"]);
          break;
        case "comment":
          obj_txt["munge"]=munge.comment(obj_txt["munge"]);
          break;
        case "doc_end_reset":
          munge.initialize_note_numbers();
          break;
        default:
          break;
        }
        return obj_txt["munge"];
      }
      invariant() {
      }
    }
    struct ObjAttrib {
    // struct ObjAttrib : AssertObjAttrib {
    // auto sink = appender!(char[])();
      auto attrib = ObjAttributes();
      string[string] obj_attrib;
      string obj_attributes(string obj_is_, string obj_raw, string node)
      in { }
      body {
        // string s = "{ \"language\": \"D\", \"rating\": 3.14, \"code\": \"42\" }";
        scope(exit) {
          // destroy(obj_is_);
          destroy(obj_raw);
          destroy(node);
        }
        JSONValue node_j = parseJSON(node);
        obj_attrib.remove("json");
        obj_attrib["json"] ="{";
        switch (obj_is_) {
        case "header_make":
          obj_attrib["json"] ~= attrib.header_make(obj_raw);
          break;
        case "header_metadata":
          obj_attrib["json"] ~= attrib.header_metadata(obj_raw);
          break;
        case "heading":
          obj_attrib["json"] ~= attrib.heading(obj_raw); //
          break;
        case "para":
          obj_attrib["json"] ~= attrib.para_and_blocks(obj_raw)
          ~ attrib.para(obj_raw);
          break;
        case "code":
          obj_attrib["json"] ~= attrib.code(obj_raw);
          break;
        case "group":
          obj_attrib["json"] ~= attrib.para_and_blocks(obj_raw)
          ~ attrib.group(obj_raw);
          break;
        case "block":
          obj_attrib["json"] ~= attrib.para_and_blocks(obj_raw)
          ~ attrib.block(obj_raw);
          break;
        case "verse":
          obj_attrib["json"] ~= attrib.verse(obj_raw);
          break;
        case "quote":
          obj_attrib["json"] ~= attrib.quote(obj_raw);
          break;
        case "table":
          obj_attrib["json"] ~= attrib.table(obj_raw);
          break;
        case "comment":
          obj_attrib["json"] ~= attrib.comment(obj_raw);
          break;
        default:
          obj_attrib["json"] ~= attrib.para(obj_raw);
          break;
        }
        obj_attrib["json"] ~=" }";
        JSONValue oa_j = parseJSON(obj_attrib["json"]);
        assert(
          (oa_j.type == JSON_TYPE.OBJECT) &&
          (node_j.type == JSON_TYPE.OBJECT)
        );
        if (obj_is_ == "heading") {
          oa_j.object["obj_cite_number"] = node_j["obj_cite_number"];
          oa_j.object["lev_markup_number"] = node_j["lev_markup_number"];
          oa_j.object["lev_collapsed_number"] = node_j["lev_collapsed_number"];
          oa_j.object["heading_pointer"] =
            node_j["heading_pointer"]; // check
          oa_j.object["doc_object_pointer"] =
            node_j["doc_object_pointer"]; // check
        }
        oa_j.object["parent_obj_cite_number"] = node_j["parent_obj_cite_number"];
        oa_j.object["parent_lev_markup_number"] = node_j["parent_lev_markup_number"];
        obj_attrib["json"] = oa_j.toString();
        debug(structattrib) {
          if (oa_j["is"].str() == "heading") {
            // writeln(__LINE__);
            writeln(obj_attrib["json"]);
            // writeln(node);
            writeln(
              "is: ", oa_j["is"].str(),
              "; obj_cite_number: ", oa_j["obj_cite_number"].integer()
            );
          }
        }
        // obj_attrib["json"]="{}";
        return obj_attrib["json"];
      }
      invariant() {
      }
    }
    struct HeaderDocMetadataMakeJson {
    // class HeaderMetadataMakeHash : AssertHeaderMetadataMakeJson {
      auto rgx = Rgx();
      string hm, hs;
      auto header_metadata_and_make_jsonstr(
        string header,
        JSONValue[string] dochead_metadata,
        JSONValue[string] dochead_make
      )
      in { }
      body {
        scope(exit) {
          destroy(header);
          destroy(dochead_metadata);
          destroy(dochead_make);
        }
        if (auto t = match(header, rgx.head_main)) {
          char[][] obj_spl = split(
            cast(char[]) header,
            rgx.line_delimiter_ws_strip
          );
          auto hm = to!string(t.captures[1]);
          if (match(hm, rgx.main_headers)) {
            foreach (line; obj_spl) {
              if (auto m = match(line, rgx.head_main)) {
                if (!empty(m.captures[2])) {
                  if (hm == "creator") {
                    dochead_metadata[hm]["author"].str =
                      to!string(m.captures[2]);
                  } else if (hm == "title") {
                    dochead_metadata[hm]["main"].str =
                      to!string(m.captures[2]);
                  } else if (hm == "publisher") {
                    dochead_metadata[hm]["name"].str =
                      to!string(m.captures[2]);
                  }
                }
              } else if (auto s = match(line, rgx.head_sub)) {
                if (!empty(s.captures[2])) {
                  auto hs = to!string(s.captures[1]);
                  if ((hm == "make" )
                  && (dochead_make[hm].type() == JSON_TYPE.OBJECT)) {
                    switch (hm) {
                    case "make":
                      if (match(hs, rgx.subhead_make)) {
                        if (dochead_make[hm][hs].type() == JSON_TYPE.STRING) {
                          dochead_make[hm][hs].str = to!string(s.captures[2]);
                        }
                      } else {
                        writeln("not a valid header type:", hm, ":", hs);
                        destroy(hm);
                        destroy(hs);
                      }
                      break;
                    default:
                      break;
                    }
                  } else if (dochead_metadata[hm].type() == JSON_TYPE.OBJECT) {
                    switch (hm) {
                    case "creator":
                      if (match(hs, rgx.subhead_creator)) {
                        if (dochead_metadata[hm][hs].type() == JSON_TYPE.STRING) {
                          dochead_metadata[hm][hs].str =
                            to!string(s.captures[2]);
                        }
                      } else {
                        writeln("not a valid header type:", hm, ":", hs);
                        destroy(hm);
                        destroy(hs);
                      }
                      break;
                    case "title":
                      if (match(hs, rgx.subhead_title)) {
                        if ((hs == "subtitle")
                        && (dochead_metadata[hm]["sub"].type() == JSON_TYPE.STRING)) {
                          dochead_metadata[hm]["sub"].str =
                            to!string(s.captures[2]);
                        } else if (dochead_metadata[hm][hs].type() == JSON_TYPE.STRING) {
                          dochead_metadata[hm][hs].str =
                            to!string(s.captures[2]);
                        }
                      } else {
                        writeln("not a valid header type:", hm, ":", hs);
                        destroy(hm);
                        destroy(hs);
                      }
                      break;
                    case "rights":
                      if (match(hs, rgx.subhead_rights)) {
                        if (dochead_metadata[hm][hs].type() == JSON_TYPE.STRING) {
                          dochead_metadata[hm][hs].str =
                            to!string(s.captures[2]);
                        }
                      } else {
                        writeln("not a valid header type:", hm, ":", hs);
                        destroy(hm);
                        destroy(hs);
                      }
                      break;
                    case "date":
                      if (match(hs, rgx.subhead_date)) {
                        if (dochead_metadata[hm][hs].type() == JSON_TYPE.STRING) {
                          dochead_metadata[hm][hs].str =
                            to!string(s.captures[2]);
                        }
                      } else {
                        writeln("not a valid header type:", hm, ":", hs);
                        destroy(hm);
                        destroy(hs);
                      }
                      break;
                    case "original":
                      if (match(hs, rgx.subhead_original)) {
                        if (dochead_metadata[hm][hs].type() == JSON_TYPE.STRING) {
                          dochead_metadata[hm][hs].str =
                            to!string(s.captures[2]);
                        }
                      } else {
                        writeln("not a valid header type:", hm, ":", hs);
                        destroy(hm);
                        destroy(hs);
                      }
                      break;
                    case "classify":
                      if (match(hs, rgx.subhead_classify)) {
                        if (dochead_metadata[hm][hs].type() == JSON_TYPE.STRING) {
                          dochead_metadata[hm][hs].str =
                            to!string(s.captures[2]);
                        }
                      } else {
                        writeln("not a valid header type:", hm, ":", hs);
                        destroy(hm);
                        destroy(hs);
                      }
                      break;
                    case "identifier":
                      if (match(hs, rgx.subhead_identifier)) {
                        if (dochead_metadata[hm][hs].type() == JSON_TYPE.STRING) {
                          dochead_metadata[hm][hs].str =
                            to!string(s.captures[2]);
                        }
                      } else {
                        writeln("not a valid header type:", hm, ":", hs);
                        destroy(hm);
                        destroy(hs);
                      }
                      break;
                    case "notes":
                      if (match(hs, rgx.subhead_notes)) {
                        if (dochead_metadata[hm][hs].type() == JSON_TYPE.STRING) {
                          dochead_metadata[hm][hs].str =
                            to!string(s.captures[2]);
                        }
                      } else {
                        writeln("not a valid header type:", hm, ":", hs);
                        destroy(hm);
                        destroy(hs);
                      }
                      break;
                    case "publisher":
                      if (match(hs, rgx.subhead_publisher)) {
                        if (dochead_metadata[hm][hs].type() == JSON_TYPE.STRING) {
                          dochead_metadata[hm][hs].str =
                            to!string(s.captures[2]);
                        }
                      } else {
                        writeln("not a valid header type:", hm, ":", hs);
                        destroy(hm);
                        destroy(hs);
                      }
                      break;
                    case "links":
                      destroy(hm);
                      destroy(hs);
                      // if (match(hs, rgx.subhead_links)) {
                      //   if (dochead_metadata[hm][hs].type() == JSON_TYPE.STRING) {
                      //     dochead_metadata[hm][hs].str = to!string(s.captures[2]);
                      //   }
                      // } else {
                      //   writeln("not a valid header type:", hm, ":", hs);
                      //   destroy(hm);
                      //   destroy(hs);
                      // }
                      break;
                    default:
                      break;
                    }
                  }
                }
              }
            }
          } else {
            writeln("not a valid header type:", hm);
          }
        }
        auto t = tuple(dochead_metadata, dochead_make);
        static assert(!isTypeTuple!(t));
        return t;
      }
      // invariant() {
      // }
    }
    class HeaderMetadataMakeHash {
    // class HeaderMetadataMakeHash : AssertHeaderMetadataMakeHash {
      auto rgx = Rgx();
      string header_main;
      string[string] head;
      string[string] header_topic_hash(string header)
      in { }
      body {
        if (auto t = match(header, rgx.head_main)) {
          char[][] obj_spl = split(
            cast(char[]) header,
            rgx.line_delimiter_ws_strip
          );
          auto header_main = to!string(t.captures[1]);
          head[header_main] = "{";
          foreach (line; obj_spl) {
            if (auto m = match(line, rgx.head_main)) {
              if (!empty(m.captures[2])) {
                head[header_main] ~=
                  "\"" ~ header_main ~
                  "\": \"" ~
                  to!string(m.captures[2]) ~
                  "\",";
              }
            } else if (auto s = match(line, rgx.head_sub)) {
              head[header_main] ~= "\"" ~ s.captures[1] ~ "\":";
              if (!empty(s.captures[2])) {
                head[header_main] ~= "\"" ~ s.captures[2] ~ "\",";
              }
            }
          }
          head[header_main] = replaceFirst(
            head[header_main],
            rgx.tailing_comma,
            ""
          );
          head[header_main] ~= "}";
          debug(headerjson) {
            JSONValue j = parseJSON(head[header_main]);
            assert(
              (j.type == JSON_TYPE.OBJECT)
            );
          }
        }
        return head;
      }
      invariant() {
      }
    }
    struct BookIndexNuggetHash {
    // class BookIndexNuggetHash : AssertBookIndexNuggetHash {
      string main_term, sub_term, sub_term_bits;
      int obj_cite_number_offset, obj_cite_number_endpoint;
      string[] obj_cite_numbers;
      string[][string][string] bi;
      string[][string][string] hash_nugget;
      string[] bi_main_terms_split_arr;
      string[][string][string] bookindex_nugget_hash(string bookindex_section, int obj_cite_number)
      in {
        debug(bookindexraw) {
          mixin ScreenTxtColors;
          if (!bookindex_section.empty) {
            writeln(
              scr_txt_color["blue"], "* [bookindex] ", scr_txt_color["off"],
              "[", to!string(obj_cite_number), "] ", bookindex_section
            );
          }
        }
      }
      body {
        auto rgx = Rgx();
        if (!bookindex_section.empty) {
          auto bi_main_terms_split_arr =
            split(bookindex_section, rgx.bi_main_terms_split);
          foreach (bi_main_terms_content; bi_main_terms_split_arr) {
            auto bi_main_term_and_rest =
              split(bi_main_terms_content, rgx.bi_main_term_plus_rest_split);
            if (auto m = match(
              bi_main_term_and_rest[0],
              rgx.bi_term_and_obj_cite_numbers_match)
            ) {
              main_term = strip(m.captures[1]);
              obj_cite_number_offset = to!int(m.captures[2]);
              obj_cite_number_endpoint=(obj_cite_number + obj_cite_number_offset);
              obj_cite_numbers ~= (to!string(obj_cite_number) ~ "-" ~ to!string(obj_cite_number_endpoint));
            } else {
              main_term = strip(bi_main_term_and_rest[0]);
              obj_cite_numbers ~= to!string(obj_cite_number);
            }
            bi[main_term]["_a"] ~= obj_cite_numbers;
            obj_cite_numbers=null;
            if (bi_main_term_and_rest.length > 1) {
              auto bi_sub_terms_split_arr =
                split(
                  bi_main_term_and_rest[1],
                  rgx.bi_sub_terms_plus_obj_cite_number_offset_split
                );
              foreach (sub_terms_bits; bi_sub_terms_split_arr) {
                if (auto m = match(sub_terms_bits, rgx.bi_term_and_obj_cite_numbers_match)) {
                  sub_term = strip(m.captures[1]);
                  obj_cite_number_offset = to!int(m.captures[2]);
                  obj_cite_number_endpoint=(obj_cite_number + obj_cite_number_offset);
                  obj_cite_numbers ~= (to!string(obj_cite_number) ~ " - " ~ to!string(obj_cite_number_endpoint));
                } else {
                  sub_term = strip(sub_terms_bits);
                  obj_cite_numbers ~= to!string(obj_cite_number);
                }
                if (!empty(sub_term)) {
                  bi[main_term][sub_term] ~= obj_cite_numbers;
                }
                obj_cite_numbers=null;
              }
            }
          }
        }
        hash_nugget = bi;
        return hash_nugget;
      }
      invariant() {
      }
    }
    struct BookIndexReport {
    // class BookIndexReport : AssertBookIndexReport {
      int mkn, skn;
      auto bookindex_report_sorted(
        string[][string][string] bookindex_unordered_hashes
      ) {
        auto mainkeys=bookindex_unordered_hashes.byKey.array.
          sort!("toLower(a) < toLower(b)", SwapStrategy.stable).release;
        foreach (mainkey; mainkeys) {
          auto subkeys=bookindex_unordered_hashes[mainkey].byKey.array.
            sort!("toLower(a) < toLower(b)", SwapStrategy.stable).release;
          foreach (subkey; subkeys) {
            debug(bookindex) {
              writeln(
                mainkey, ": ",
                subkey, ": ",
                to!string(bookindex_unordered_hashes[mainkey][subkey])
              );
            }
            ++skn;
          }
          ++mkn;
        }
        // return bookindex_the;
      }
    }
    struct BookIndexReportIndent {
      int mkn, skn;
      auto bookindex_report_indented(
        string[][string][string] bookindex_unordered_hashes
      ) {
        auto mainkeys=
          bookindex_unordered_hashes.byKey.array.sort().release;
        foreach (mainkey; mainkeys) {
          debug(bookindex) {
            writeln(mainkey);
          }
          auto subkeys=
            bookindex_unordered_hashes[mainkey].byKey.array.sort().release;
          foreach (subkey; subkeys) {
            debug(bookindex) {
              writeln("  ", subkey);
              writeln("    ", to!string(
                bookindex_unordered_hashes[mainkey][subkey]
              ));
            }
            // bookindex_the[mkn][mainkey][skn][subkey] ~= (bookindex_unordered_hashes[mainkey][subkey]);
            ++skn;
          }
          ++mkn;
        }
      }
    }
    struct BookIndexReportSection {
      int mkn, skn;
      auto rgx = Rgx();
      auto bookindex_write_section(
        string[][string][string] bookindex_unordered_hashes
      ) {
        auto mainkeys=bookindex_unordered_hashes.byKey.array.sort().release;
        foreach (mainkey; mainkeys) {
          write("_0_1 !{", mainkey, "}! ");
          foreach (ref_; bookindex_unordered_hashes[mainkey]["_a"]) {
            auto go = replaceAll(ref_, rgx.book_index_go, "$1");
            write(" {", ref_, "}#", go, ", ");
          }
          writeln(" \\\\");
          bookindex_unordered_hashes[mainkey].remove("_a");
          auto subkeys=
            bookindex_unordered_hashes[mainkey].byKey.array.sort().release;
          foreach (subkey; subkeys) {
            write("  ", subkey, ", ");
            foreach (ref_; bookindex_unordered_hashes[mainkey][subkey]) {
              auto go = replaceAll(ref_, rgx.book_index_go, "$1");
              write(" {", ref_, "}#", go, ", ");
            }
            writeln(" \\\\");
            ++skn;
          }
          ++mkn;
        }
      }
      auto bookindex_build_section(
        string[][string][string] bookindex_unordered_hashes,
        int obj_cite_number
      ) {
        string type;
        string lev, lev_markup_number, lev_collapsed_number;
        string attrib;
        string[string] indent;
        auto set_abstract_object = ObjectAbstractSet();
        auto mainkeys =
          bookindex_unordered_hashes.byKey.array.sort().release;
        string bi_tmp;
        ObjComposite[] bookindex_section;
        // writeln(mainkeys.length);
        // B~ Book Index
        attrib="";
        lev="B";
        lev_markup_number="1";
        lev_collapsed_number="1";
        bookindex_section ~=
          set_abstract_object.contents_heading(
            "Book Index",
            attrib,
            obj_cite_number,
            to!int(lev_markup_number),
            to!int(lev_collapsed_number)
          );
        ++obj_cite_number;
        ++mkn;
        // 1~ Index
        attrib="";
        lev="1";
        lev_markup_number="4";
        lev_collapsed_number="2";
        bookindex_section ~=
          set_abstract_object.contents_heading(
            "Index",
            attrib,
            obj_cite_number,
            to!int(lev_markup_number),
            to!int(lev_collapsed_number)
          );
        ++obj_cite_number;
        ++mkn;
        foreach (mainkey; mainkeys) {
          bi_tmp = "!{" ~ mainkey ~ "}! ";
          // bi_tmp = "_0_1 !{" ~ mainkey ~ "}! ";
          foreach (ref_; bookindex_unordered_hashes[mainkey]["_a"]) {
            auto go = replaceAll(ref_, rgx.book_index_go, "$1");
            bi_tmp ~= " {" ~ ref_ ~ "}#" ~ go ~ ", ";
          }
          bi_tmp ~= " \\\\\n    ";
          bookindex_unordered_hashes[mainkey].remove("_a");
          auto subkeys =
            bookindex_unordered_hashes[mainkey].byKey.array.sort().release;
          foreach (subkey; subkeys) {
            bi_tmp ~= subkey ~ ", ";
            foreach (ref_; bookindex_unordered_hashes[mainkey][subkey]) {
              auto go = replaceAll(ref_, rgx.book_index_go, "$1");
              bi_tmp ~= " {" ~ ref_ ~ "}#" ~ go ~ ", ";
            }
            bi_tmp ~= " \\\\\n    ";
            ++skn;
          }
          bi_tmp = replaceFirst(bi_tmp, rgx.trailing_linebreak, "");
          type="para";
          attrib="";
          indent["first"] = "0";
          indent["second"] = "1";
          attrib="";
          // bookindex_section ~=
          //   set_abstract_object.contents_para(
          //     obj,
          //     obj_cite_number,
          //     indent,
          //     false
          //   );
          bookindex_section ~=
            set_abstract_object.contents_para(
              type,
              bi_tmp,
              attrib,
              obj_cite_number,
              indent,
              false
            );
          ++obj_cite_number;
          ++mkn;
        }
        auto t = tuple(bookindex_section, obj_cite_number);
        return t;
      }
      auto bookindex_build_section_(
        string[][string][string] bookindex_unordered_hashes
      ) {
        auto mainkeys =
          bookindex_unordered_hashes.byKey.array.sort().release;
        string bi_tmp;
        string[] bookindex_section;
        // int bi_num;
        // writeln(mainkeys.length);
        foreach (mainkey; mainkeys) {
          bi_tmp = "_0_1 !{" ~ mainkey ~ "}! ";
          foreach (ref_; bookindex_unordered_hashes[mainkey]["_a"]) {
            auto go = replaceAll(ref_, rgx.book_index_go, "$1");
            bi_tmp ~= " {" ~ ref_ ~ "}#" ~ go ~ ", ";
          }
          bi_tmp ~= " \\\\\n    ";
          bookindex_unordered_hashes[mainkey].remove("_a");
          auto subkeys =
            bookindex_unordered_hashes[mainkey].byKey.array.sort().release;
          foreach (subkey; subkeys) {
            bi_tmp ~= subkey ~ ", ";
            // bi_tmp ~= "  " ~ subkey ~ ", ";
            foreach (ref_; bookindex_unordered_hashes[mainkey][subkey]) {
              auto go = replaceAll(ref_, rgx.book_index_go, "$1");
              bi_tmp ~= " {" ~ ref_ ~ "}#" ~ go ~ ", ";
            }
            bi_tmp ~= " \\\\\n    ";
            ++skn;
          }
          bi_tmp = replaceFirst(bi_tmp, rgx.trailing_linebreak, "");
          bookindex_section ~= bi_tmp;
          ++mkn;
        }
        return bookindex_section;
      }
    }
    struct NotesSection {
      string object_notes;
      long previous_count;
      int mkn;
      auto rgx = Rgx();
      private auto gather_notes_for_endnote_section(
        ObjComposite[] contents_am,
        ulong counter
      )
      in {
        // endnotes/ footnotes for
        // doc objects other than paragraphs & headings
        // various forms of grouped text
        assert((contents_am[counter].is_a == "para")
        || (contents_am[counter].is_a == "heading"));
        assert(counter > previous_count);
        previous_count=counter;
        assert(
          match(contents_am[counter].object,
          rgx.inline_notes_delimiter_al_regular_number_note)
        );
      }
      body {
        foreach(m;
        matchAll(contents_am[counter].object,
        rgx.inline_notes_delimiter_al_regular_number_note)) {
          debug(endnotes_build) {
            writeln(
              "{^{", m.captures[1], ".}^}#noteref_", m.captures[1], " ",
              m.captures[2]); // sometimes need segment name (segmented html & epub)
            // writeln("{^{", m.captures[1], ".}^}#", contents_am[counter]["obj_cite_number"], " ", m.captures[2]);
          }
          object_notes ~=
            "{^{" ~ m.captures[1] ~ ".}^}#noteref_" ~
            m.captures[1] ~ " " ~ m.captures[2] ~ "』";
        }
        return object_notes;
      }
      private auto gathered_notes()
      in {
      }
      body {
        string[] endnotes_;
        if (object_notes.length > 1) {
          endnotes_ = (split(object_notes, rgx.break_string))[0..$-1];
        }
        return endnotes_;
      }
      private auto endnote_objects(int obj_cite_number)
      in {
      }
      body {
        auto set_abstract_object = ObjectAbstractSet();
        ObjComposite[] endnotes_section;
        auto endnotes_ = gathered_notes();
        // auto endnotes_ = (split(object_notes, rgx.break_string))[0..$-1];
        string type;
        string lev, lev_markup_number, lev_collapsed_number;
        string attrib;
        string[string] indent;
        // B~ Endnotes
        attrib="";
        lev="B";
        lev_markup_number="1";
        lev_collapsed_number="1";
        endnotes_section ~=
          set_abstract_object.contents_heading(
            "Endnotes",
            attrib,
            obj_cite_number,
            to!int(lev_markup_number),
            to!int(lev_collapsed_number)
          );
        ++obj_cite_number;
        ++mkn;
        // 1~ Endnotes
        attrib="";
        lev="1";
        lev_markup_number="4";
        lev_collapsed_number="2";
        endnotes_section ~=
          set_abstract_object.contents_heading(
            "Endnotes",
            attrib,
            obj_cite_number,
            to!int(lev_markup_number),
            to!int(lev_collapsed_number)
          );
        ++obj_cite_number;
        ++mkn;
        foreach (endnote; endnotes_) {
          type="para";
          attrib="";
          indent["first"] = "0";
          indent["second"] = "0";
          attrib="";
          // endnotes ~=
          //   set_abstract_object.contents_para(
          //     obj,
          //     obj_cite_number,
          //     indent,
          //     false
          //   );
          endnotes_section ~=
            set_abstract_object.contents_para(
              type,
              endnote,
              attrib,
              obj_cite_number,
              indent,
              false
            );
          ++obj_cite_number;
          ++mkn;
        }
        auto t = tuple(endnotes_section, obj_cite_number);
        return t;
      }
    }
    struct Bibliography {
      public JSONValue[] bibliography(ref string[] biblio_unsorted_incomplete, ref JSONValue[] bib_arr_json)
      in { }
      body {
        JSONValue[] biblio_unsorted =
          biblio_unsorted_complete(biblio_unsorted_incomplete, bib_arr_json);
        JSONValue[] biblio_sorted = biblio_sort(biblio_unsorted);
        biblio_debug(biblio_sorted);
        return biblio_sorted;
      }
      final private JSONValue[] biblio_unsorted_complete(
        string[] biblio_unordered,
        ref 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;
        }
        JSONValue[] biblio_unsorted_array_of_json_objects =
          bib_arr_json.dup;
        return biblio_unsorted_array_of_json_objects;
      }
      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"]);
              // writeln(j["deemed_author"], " (", j["author"], ") ",  j["fulltitle"]);
            }
          }
        }
        return biblio_sorted;
      }
      auto biblio_debug(JSONValue[] biblio_sorted) {
        debug(biblio) {
          foreach (j; biblio_sorted) {
            if (!empty(j["fulltitle"].str)) {
              writeln(j["sortby_deemed_author_year_title"]);
            }
          }
        }
      }
    }
    struct NodeStructureMetadata {
    // class NodeStructureMetadata : AssertNodeJSON {
      int lv, lv0, lv1, lv2, lv3, lv4, lv5, lv6, lv7;
      int obj_cite_number;
      int[string] p_; // p_ parent_
      string node;
      string node_emitter(
        string lev_markup_number,
        int obj_cite_number_,
        long counter_,
        int pointer_,
        string is_
      )
      in {
        auto rgx = Rgx();
        assert(is_ != "heading");
        assert(to!int(obj_cite_number_) >= 0);
      }
      body {
        // scope(failure) {
        //   writeln(__FILE__, ":", __LINE__, " failed here:");
        //   writeln("  is  : ", is_);
        //   writeln("  node: ", node);
        // }
        assert(is_ != "heading"); // should not be necessary
        assert(to!int(obj_cite_number_) >= 0); // should not be necessary
        int obj_cite_number=to!int(obj_cite_number_);
        if (lv7 > State.off) {
          p_["lev_markup_number"] = DocStructMarkupHeading.h_text_4;
          p_["obj_cite_number"] = lv7;
        } else if (lv6 > State.off) {
          p_["lev_markup_number"] = DocStructMarkupHeading.h_text_3;
          p_["obj_cite_number"] = lv6;
        } else if (lv5 > State.off) {
          p_["lev_markup_number"] = DocStructMarkupHeading.h_text_2;
          p_["obj_cite_number"] = lv5;
        } else {
          p_["lev_markup_number"] = DocStructMarkupHeading.h_text_1;
          p_["obj_cite_number"] = lv4;
        }
        node=("{ " ~
          "\"is\": \"" ~ is_ ~ "\"" ~
          ", \"heading_pointer\": " ~ to!string(pointer_) ~
          ", \"doc_object_pointer\": " ~ to!string(counter_) ~
          ", \"obj_cite_number\": " ~ to!string(obj_cite_number_) ~
          ", \"parent_obj_cite_number\": " ~ to!string(p_["obj_cite_number"]) ~
          ", \"parent_lev_markup_number\": " ~ to!string(p_["lev_markup_number"]) ~
          " }"
        );
        debug(node) {
          mixin ScreenTxtColors;
          if (match(lev_markup_number, rgx.levels_numbered_headings)) {
            writeln(scr_txt_marker["yellow"], to!string(node));
          } else {
            writeln(scr_txt_marker["white"], to!string(node));
          }
        }
        JSONValue j = parseJSON(node);
        assert(j["parent_lev_markup_number"].integer >= 4);
        assert(j["parent_lev_markup_number"].integer <= 7);
        assert(j["parent_obj_cite_number"].integer >= 0);
        return node;
      }
      invariant() {
      }
      string node_emitter_heading(
        string lev_markup_number,
        string lev_collapsed_number,
        int obj_cite_number_,
        long counter_,
        int pointer_,
        string is_
      )
      in {
        auto rgx = Rgx();
        assert(is_ == "heading");
        assert(to!int(obj_cite_number_) >= 0);
        assert(
          match(lev_markup_number, rgx.levels_numbered),
          ("not a valid heading level: " ~ lev_markup_number ~ " at " ~ to!string(obj_cite_number_))
        );
        // assert(to!int(obj_cite_number_) >= 0);
        if (match(lev_markup_number, rgx.levels_numbered)) {
          if (to!int(lev_markup_number) == 0) {
            assert(to!int(obj_cite_number_) == 1);
            // writeln(lev_markup_number);
          }
        }
      }
      body {
        // scope(failure) {
        //   writeln(__FILE__, ":", __LINE__, " failed here:");
        //   writeln("  is  : ", is_);
        //   writeln("  node: ", node);
        // }
        auto rgx = Rgx();
        int obj_cite_number = to!int(obj_cite_number_);
        switch (lev_markup_number) { // switch (to!string(lv)) {
        case "0":
          lv = DocStructMarkupHeading.h_sect_A;
          lv0 = obj_cite_number;
          lv1=0; lv2=0; lv3=0; lv4=0; lv5=0; lv6=0; lv7=0;
          p_["lev_markup_number"] = 0;
          p_["obj_cite_number"] = 0;
          break;
        case "1":
          lv = DocStructMarkupHeading.h_sect_B;
          lv1 = obj_cite_number;
          lv2=0; lv3=0; lv4=0; lv5=0; lv6=0; lv7=0;
          p_["lev_markup_number"] =
            DocStructMarkupHeading.h_sect_A;
          p_["obj_cite_number"] = lv0;
          break;
        case "2":
          lv = DocStructMarkupHeading.h_sect_C;
          lv2 = obj_cite_number;
          lv3=0; lv4=0; lv5=0; lv6=0; lv7=0;
          p_["lev_markup_number"] =
            DocStructMarkupHeading.h_sect_B;
          p_["obj_cite_number"] = lv1;
          break;
        case "3":
          lv = DocStructMarkupHeading.h_sect_D;
          lv3=obj_cite_number;
          lv4=0; lv5=0; lv6=0; lv7=0;
          p_["lev_markup_number"] =
            DocStructMarkupHeading.h_sect_C;
          p_["obj_cite_number"] = lv2;
          break;
        case "4":
          lv = DocStructMarkupHeading.h_text_1;
          lv4 = obj_cite_number;
          lv5=0; lv6=0; lv7=0;
          if (lv3 > State.off) {
            p_["lev_markup_number"] =
              DocStructMarkupHeading.h_sect_D;
            p_["obj_cite_number"] = lv3;
          } else if (lv2 > State.off) {
            p_["lev_markup_number"] =
              DocStructMarkupHeading.h_sect_C;
            p_["obj_cite_number"] = lv2;
          } else if (lv1 > State.off) {
            p_["lev_markup_number"] =
              DocStructMarkupHeading.h_sect_B;
            p_["obj_cite_number"] = lv1;
          } else {
            p_["lev_markup_number"] =
              DocStructMarkupHeading.h_sect_A;
            p_["obj_cite_number"] = lv0;
          }
          break;
        case "5":
          lv = DocStructMarkupHeading.h_text_2;
          lv5 = obj_cite_number;
          lv6=0; lv7=0;
          p_["lev_markup_number"] =
            DocStructMarkupHeading.h_text_1;
          p_["obj_cite_number"] = lv4;
          break;
        case "6":
          lv = DocStructMarkupHeading.h_text_3;
          lv6 = obj_cite_number;
          lv7=0;
          p_["lev_markup_number"] =
            DocStructMarkupHeading.h_text_2;
          p_["obj_cite_number"] = lv5;
          break;
        case "7":
          lv = DocStructMarkupHeading.h_text_4;
          lv7 = obj_cite_number;
          p_["lev_markup_number"] =
            DocStructMarkupHeading.h_text_3;
          p_["obj_cite_number"] = lv6;
          break;
        default:
          // if (lv7 > State.off) {
          //   p_["lev_markup_number"] = 7; p_["obj_cite_number"] = lv7;
          // } else if (lv6 > State.off) {
          //   p_["lev_markup_number"] = 6; p_["obj_cite_number"] = lv6;
          // } else if (lv5 > State.off) {
          //   p_["lev_markup_number"] = 5; p_["obj_cite_number"] = lv5;
          // } else {
          //   p_["lev_markup_number"] = 4; p_["obj_cite_number"] = lv4;
          // }
          break;
        }
        node=("{ " ~
          "\"is\": \"" ~ is_ ~ "\"" ~
          ", \"heading_pointer\": " ~ to!string(pointer_) ~
          ", \"doc_object_pointer\": " ~ to!string(counter_) ~
          ", \"obj_cite_number\": " ~ to!string(obj_cite_number_) ~
          ",  \"lev_markup_number\": " ~ to!string(lev_markup_number) ~
          ",  \"lev_collapsed_number\": " ~ to!string(lev_collapsed_number) ~
          ", \"parent_obj_cite_number\": " ~ to!string(p_["obj_cite_number"]) ~
          ", \"parent_lev_markup_number\": " ~ to!string(p_["lev_markup_number"]) ~
          " }"
        );
        debug(heading) {
          mixin ScreenTxtColors;
          if (match(lev_markup_number, rgx.levels_numbered_headings)) {
            writeln(scr_txt_marker["yellow"], to!string(node));
          }
        }
        debug(node) {
          mixin ScreenTxtColors;
          if (match(lev_markup_number, rgx.levels_numbered_headings)) {
            writeln(scr_txt_marker["yellow"], to!string(node));
          } else {
            writeln(scr_txt_marker["white"], to!string(node));
          }
        }
        JSONValue j = parseJSON(node);
        assert(j["parent_lev_markup_number"].integer <= 7);
        assert(j["parent_obj_cite_number"].integer >= 0);
        if (match(lev_markup_number, rgx.levels_numbered_headings)) {
          assert(j["lev_markup_number"].integer <= 7);
          assert(j["obj_cite_number"].integer >= 0);
          if (j["parent_lev_markup_number"].integer > 0) {
            assert(j["parent_lev_markup_number"].integer < j["lev_markup_number"].integer);
            if (j["obj_cite_number"].integer != 0) {
              assert(j["parent_obj_cite_number"].integer < j["obj_cite_number"].integer);
            }
          }
          if (j["lev_markup_number"].integer == 0) {
            assert(j["parent_lev_markup_number"].integer == DocStructMarkupHeading.h_sect_A);
          } else if  (j["lev_markup_number"].integer == DocStructMarkupHeading.h_sect_B) {
            assert(j["parent_lev_markup_number"].integer == DocStructMarkupHeading.h_sect_A);
          } else if  (j["lev_markup_number"].integer == DocStructMarkupHeading.h_sect_C) {
            assert(j["parent_lev_markup_number"].integer == DocStructMarkupHeading.h_sect_B);
          } else if  (j["lev_markup_number"].integer == DocStructMarkupHeading.h_sect_D) {
            assert(j["parent_lev_markup_number"].integer == DocStructMarkupHeading.h_sect_C);
          } else if  (j["lev_markup_number"].integer == DocStructMarkupHeading.h_text_1) {
            assert(j["parent_lev_markup_number"].integer <= DocStructMarkupHeading.h_sect_D);
          } else if  (j["lev_markup_number"].integer == DocStructMarkupHeading.h_text_2) {
            assert(j["parent_lev_markup_number"].integer == DocStructMarkupHeading.h_text_1);
          } else if  (j["lev_markup_number"].integer == DocStructMarkupHeading.h_text_3) {
            assert(j["parent_lev_markup_number"].integer == DocStructMarkupHeading.h_text_2);
          } else if  (j["lev_markup_number"].integer == DocStructMarkupHeading.h_text_4) {
            assert(j["parent_lev_markup_number"].integer == DocStructMarkupHeading.h_text_3);
          } else if  (j["lev_markup_number"].integer == DocStructMarkupHeading.h_text_5) {
            // writeln(j["parent_lev_markup_number"].integer);
            // assert(j["parent_lev_markup_number"].integer >= 4);
            // assert(j["parent_lev_markup_number"].integer <= 7);
          }
        }
        return node;
      }
      invariant() {
      }
    }
    /+ abstraction functions emitters ↑ +/

    /+ ↓ abstraction functions assertions +/
    auto assertions_doc_structure(string[string] an_object, int[string] lv) {
      if (lv["h3"] > State.off) {
        assert(lv["h0"] > State.off);
        assert(lv["h1"] > State.off);
        assert(lv["h2"] > State.off);
      } else if (lv["h2"] > State.off) {
        assert(lv["h0"] > State.off);
        assert(lv["h1"] > State.off);
        assert(lv["h3"] == State.off);
      } else if (lv["h1"] > State.off) {
        assert(lv["h0"] > State.off);
        assert(lv["h2"] == State.off);
        assert(lv["h3"] == State.off);
      } else if (lv["h0"] > State.off) {
        assert(lv["h1"] == State.off);
        assert(lv["h2"] == State.off);
        assert(lv["h3"] == State.off);
      } else {
        assert(lv["h0"] == State.off);
        assert(lv["h1"] == State.off);
        assert(lv["h2"] == State.off);
        assert(lv["h3"] == State.off);
      }
      if (lv["h7"] > State.off) {
        assert(lv["h4"] > State.off);
        assert(lv["h5"] > State.off);
        assert(lv["h6"] > State.off);
      } else if (lv["h6"] > State.off) {
        assert(lv["h4"] > State.off);
        assert(lv["h5"] > State.off);
        assert(lv["h7"] == State.off);
      } else if (lv["h5"] > State.off) {
        assert(lv["h4"] > State.off);
        assert(lv["h6"] == State.off);
        assert(lv["h7"] == State.off);
      } else if (lv["h4"] > State.off) {
        assert(lv["h5"] == State.off);
        assert(lv["h6"] == State.off);
        assert(lv["h7"] == State.off);
      } else {
        assert(lv["h4"] == State.off);
        assert(lv["h5"] == State.off);
        assert(lv["h6"] == State.off);
        assert(lv["h7"] == State.off);
      }
      if (lv["h0"] == State.off) {
        assert(lv["h1"] == State.off);
        assert(lv["h2"] == State.off);
        assert(lv["h3"] == State.off);
        assert(lv["h4"] == State.off);
        assert(lv["h5"] == State.off);
        assert(lv["h6"] == State.off);
        assert(lv["h7"] == State.off);
      }
      if (lv["h1"] == State.off) {
        assert(lv["h2"] == State.off);
        assert(lv["h3"] == State.off);
      }
      if (lv["h2"] == State.off) {
        assert(lv["h3"] == State.off);
      }
      if (lv["h3"] == State.off) {
      }
      if (lv["h4"] == State.off) {
        assert(lv["h5"] == State.off);
        assert(lv["h6"] == State.off);
        assert(lv["h7"] == State.off);
      }
      if (lv["h5"] == State.off) {
        assert(lv["h6"] == State.off);
        assert(lv["h7"] == State.off);
      }
      if (lv["h6"] == State.off) {
        assert(lv["h7"] == State.off);
      }
      if (lv["h7"] == State.off) {
      }
      switch (to!string(an_object["lev"])) {
      case "A":
        if (lv["h0"] == State.off) {
          assert(lv["h1"] == State.off);
          assert(lv["h2"] == State.off);
          assert(lv["h3"] == State.off);
          assert(lv["h4"] == State.off);
          assert(lv["h5"] == State.off);
          assert(lv["h6"] == State.off);
          assert(lv["h7"] == State.off);
        } else {  // (lv["h0"] > State.off)
          assert(lv["h0"] == State.off,"error should not enter level A a second time");
        }
        break;
      case "B":
        if (lv["h1"] == State.off) {
          assert(lv["h0"] > State.off);
          assert(lv["h2"] == State.off);
          assert(lv["h3"] == State.off);
        } else {                 // (lv["h1"] > State.off)
          assert(lv["h0"] > State.off);
          assert(lv["h1"] > State.off);  //
        }
        break;
      case "C":
        if (lv["h2"] == State.off) {
          assert(lv["h0"] > State.off);
          assert(lv["h1"] > State.off);
          assert(lv["h3"] == State.off);
        } else {                 // (lv["h2"] > State.off)
          assert(lv["h0"] > State.off);
          assert(lv["h1"] > State.off);
          assert(lv["h2"] > State.off);  //
        }
        break;
      case "D":
        if (lv["h3"] == State.off) {
          assert(lv["h0"] > State.off);
          assert(lv["h1"] > State.off);
          assert(lv["h2"] > State.off);
        } else {                 // (lv["h3"] > State.off)
          assert(lv["h0"] > State.off);
          assert(lv["h1"] > State.off);
          assert(lv["h2"] > State.off);
          assert(lv["h3"] > State.off);
        }
        break;
      case "1":
        if (lv["h4"] == State.off) {
          assert(lv["h0"] > State.off);
        } else {                 // (lv["h4"] > State.off)
          assert(lv["h0"] > State.off);
          assert(lv["h4"] > State.off);  //
        }
        break;
      case "2":
        if (lv["h5"] == State.off) {
          assert(lv["h0"] > State.off);
          assert(lv["h4"] > State.off);
        } else {                 // (lv["h5"] > State.off)
          assert(lv["h0"] > State.off);
          assert(lv["h4"] > State.off);
          assert(lv["h5"] > State.off);  //
        }
        break;
      case "3":
        if (lv["h6"] == State.off) {
          assert(lv["h0"] > State.off);
          assert(lv["h4"] > State.off);
          assert(lv["h5"] > State.off);
        } else {                 // (lv["h6"] > State.off)
          assert(lv["h0"] > State.off);
          assert(lv["h4"] > State.off);
          assert(lv["h5"] > State.off);
          assert(lv["h6"] > State.off);  //
        }
        break;
      case "4":
        if (lv["h7"] == State.off) {
          assert(lv["h0"] > State.off);
          assert(lv["h4"] > State.off);
          assert(lv["h5"] > State.off);
          assert(lv["h6"] > State.off);
        } else {                 // (lv["h7"] > State.off)
          assert(lv["h0"] > State.off);
          assert(lv["h4"] > State.off);
          assert(lv["h5"] > State.off);
          assert(lv["h6"] > State.off);
          assert(lv["h7"] > State.off);  //
        }
        break;
      default:
        break;
      }
    }
    auto assertions_flag_types_block_status_none_or_closed(int[string] type) {
      assert(
        (type["code"] == TriState.off)
        || (type["code"] == TriState.closing),
        "code block status: off or closing");
      assert(
        (type["poem"] == TriState.off)
        || (type["poem"] == TriState.closing),
        "poem status: off or closing");
      assert(
        (type["table"] == TriState.off)
        || (type["table"] == TriState.closing),
        "table status: off or closing");
      assert(
        (type["group"] == TriState.off)
        || (type["group"] == TriState.closing),
        "group block status: off or closing");
      assert(
        (type["block"] == TriState.off)
        || (type["block"] == TriState.closing),
        "block status: off or closing");
    }
    /+ abstraction functions assertions ↑ +/

  } /+ ← closed: struct Abstraction +/

} /+ ← closed: template SiSUdocAbstraction +/