/++
  output debugs
+/
template SiSUoutputDebugs() {
  struct SDPoutputDebugs {
    auto abstract_doc_source_debugs(S)(
      auto ref const S         contents,
      string[][string]         document_section_keys_sequenced,
      string[][string][string] bookindex_unordered_hashes,      // redundant, consider
      JSONValue[]              biblio,                          // redundant, consider
      string[string][string]   dochead_make,
      string[string][string]   dochead_meta,
      string                   fn_src,
      bool[string]             opt_action_bool
    ) {
      mixin RgxInit;
      mixin InternalMarkup;
      auto rgx = Rgx();
      auto markup = InlineMarkup();
      string key;
      struct BookIndexReport {
        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;
          }
        }
      }
      debug(parent) {
        writefln(
          "%s:%s",
          __FILE__,
          __LINE__,
        );
        foreach (key; document_section_keys_sequenced["seg"]) {
          foreach (obj; contents[key]) {
            if (obj.use == "content") {
              if (obj.is_a == "heading") {
                writefln(
                  "%s node: %s heading: %s %s",
                  obj.obj_cite_number,
                  obj.node,
                  obj.lev_markup_number,
                  obj.object,
                );
              }
            }
          }
        }
      }
      debug(dumpdoc) {
        writefln(
          "%s\n%s:%s",
          "-------------------------------",
          __FILE__,
          __LINE__,
        );
        foreach (obj; contents) {
          if (obj.use == "content") {
            writefln(
              "[%s][%s]\n%s",
              obj.obj_cite_number,
              obj.is_a,
              obj.object
            );
          }
        }
      }
      void out_toc(S)(
        auto ref const S         contents,
        string                   key,
      ) {
        if (contents[key].length > 1) {
          string indent_spaces;
          foreach (obj; contents[key]) {
            indent_spaces=markup.indent_by_spaces_provided(obj.para_attrib.indent_start);
            writefln(
              "%s%s",
              indent_spaces,
              obj.object
            );
          }
        }
      }
      void out_endnotes(S)(
        auto ref const S         contents,
        string                   key,
      ) {
        if (contents[key].length > 1) {
          foreach (obj; contents[key]) {
            writefln(
              "[%s]\n%s",
              obj.is_a,
              obj.object
            );
          }
        }
      }
      void out_bookindex(S)(
        auto ref const S         contents,
        string                   key,
      ) {
        if (contents[key].length > 1) {
          foreach (obj; contents[key]) {
            writefln(
              "[%s][%s]\n%s",
              obj.obj_cite_number,
              obj.is_a,
              obj.object
            );
          }
        }
      }
      debug(section_head) {
        key="head";
        if (contents[key].length > 1) {
          foreach (obj; contents[key]) {
            writefln(
              "[%s][%s]\n%s",
              obj.obj_cite_number,
              obj.is_a,
              obj.object
            );
          }
        }
      }
      debug(section_toc) {
        key="toc_seg";
        out_toc(contents, key);
      }
      debug(section_toc_seg) {
        key="toc_seg";
        out_toc(contents, key);
      }
      debug(section_toc_scroll) {
        key="toc_scroll";
        out_toc(contents, key);
      }
      debug(section_body) {
        key="body";
        if (contents[key].length > 1) {
          foreach (obj; contents[key]) {
            writefln(
              "[%s][%s]\n%s",
              obj.obj_cite_number,
              obj.is_a,
              obj.object
            );
          }
        }
      }
      debug(section_endnotes) {
        key="endnotes_seg";
        out_endnotes(contents, key);
      }
      debug(section_endnotes_seg) {
        key="endnotes_seg";
        out_endnotes(contents, key);
      }
      debug(section_endnotes_scroll) {
        key="endnotes_scroll";
        out_endnotes(contents, key);
      }
      debug(section_glossary) {
        key="glossary";
        if (contents[key].length > 1) {
          foreach (obj; contents[key]) {
            writefln(
              "[%s][%s]\n%s",
              obj.obj_cite_number,
              obj.is_a,
              obj.object
            );
          }
        }
      }
      debug(section_bibliography) {
        key="bibliography";
        if (contents[key].length > 1) {
          foreach (obj; contents[key]) {
            writefln(
              "[%s][%s]\n%s",
              obj.obj_cite_number,
              obj.is_a,
              obj.object
            );
          }
        }
      }
      debug(section_bookindex) {
        key="bookindex_seg";
        out_bookindex(contents, key);
      }
      debug(section_bookindex_seg) {
        key="bookindex_seg";
        out_bookindex(contents, key);
      }
      debug(section_bookindex_scroll) {
        key="bookindex_scroll";
        out_bookindex(contents, key);
      }
      debug(blurb_section) {
        key="blurb";
        if (contents[key].length > 1) {
          foreach (obj; contents[key]) {
            writefln(
              "[%s][%s]\n%s",
              obj.obj_cite_number,
              obj.is_a,
              obj.object
            );
          }
        }
      }
      debug(objects) {
        writefln(
          "%s\n%s:%s",
          "-------------------------------",
          __FILE__,
          __LINE__,
        );
        foreach (obj; contents) {
          if (obj.use == "content") {
            writefln(
              "* [%s][%s] %s",
              obj.obj_cite_number,
              obj.is_a,
              obj.object
            );
          }
        }
      }
      debug(headermakejson) {
        writefln(
          "%s\n%s\n%s",
          "document header, metadata & make instructions:",
          dochead_meta,
          pointer_head_main,
        );
        foreach (main_header; pointer_head_main) {
          switch (main_header) {
          case "make":
            foreach (sub_header; pointer_head_sub_make) {
              if (to!string(dochead_meta[main_header][sub_header]).length > 2) {
                writefln(
                  "%s:%s: %s",
                  main_header,
                  sub_header,
                  dochead_meta[main_header][sub_header]
                );
              }
            }
            break;
          default:
            break;
          }
        }
      }
      debug(headermetadatajson) {
        writefln(
          "%s\n%s\n%s",
          "document header, metadata & make instructions:",
          dochead_meta,
          pointer_head_main,
        );
        foreach (main_header; pointer_head_main) {
          switch (main_header) {
          case "creator":
            foreach (sub_header; pointer_head_sub_creator) {
              if (to!string(dochead_meta[main_header][sub_header]).length > 2) {
                writefln(
                  "%s:%s: %s",
                  main_header,
                  sub_header,
                  dochead_meta[main_header][sub_header]
                );
              }
            }
            break;
          case "title":
            foreach (sub_header; pointer_head_sub_title) {
              if (to!string(dochead_meta[main_header][sub_header]).length > 2) {
                writefln(
                  "%s:%s: %s",
                  main_header,
                  sub_header,
                  dochead_meta[main_header][sub_header]
                );
              }
            }
            break;
          case "rights":
            foreach (sub_header; pointer_head_sub_rights) {
              if (to!string(dochead_meta[main_header][sub_header]).length > 2) {
                writefln(
                  "%s:%s: %s",
                  main_header,
                  sub_header,
                  dochead_meta[main_header][sub_header]
                );
              }
            }
            break;
          case "date":
            foreach (sub_header; pointer_head_sub_date) {
              if (to!string(dochead_meta[main_header][sub_header]).length > 2) {
                writefln(
                  "%s:%s: %s",
                  main_header,
                  sub_header,
                  dochead_meta[main_header][sub_header]
                );
              }
            }
            break;
          case "original":
            foreach (sub_header; pointer_head_sub_original) {
              if (to!string(dochead_meta[main_header][sub_header]).length > 2) {
                writefln(
                  "%s:%s: %s",
                  main_header,
                  sub_header,
                  dochead_meta[main_header][sub_header]
                );
              }
            }
            break;
          case "classify":
            foreach (sub_header; pointer_head_sub_classify) {
              if (to!string(dochead_meta[main_header][sub_header]).length > 2) {
                writefln(
                  "%s:%s: %s",
                  main_header,
                  sub_header,
                  dochead_meta[main_header][sub_header]
                );
              }
            }
            break;
          case "identifier":
            foreach (sub_header; pointer_head_sub_identifier) {
              if (to!string(dochead_meta[main_header][sub_header]).length > 2) {
                writefln(
                  "%s:%s: %s",
                  main_header,
                  sub_header,
                  dochead_meta[main_header][sub_header]
                );
              }
            }
            break;
          case "notes":
            foreach (sub_header; pointer_head_sub_notes) {
              if (to!string(dochead_meta[main_header][sub_header]).length > 2) {
                writefln(
                  "%s:%s: %s",
                  main_header,
                  sub_header,
                  dochead_meta[main_header][sub_header]
                );
              }
            }
            break;
          case "publisher":
            foreach (sub_header; pointer_head_sub_publisher) {
              if (to!string(dochead_meta[main_header][sub_header]).length > 2) {
                writefln(
                  "%s:%s: %s",
                  main_header,
                  sub_header,
                  dochead_meta[main_header][sub_header]
                );
              }
            }
            break;
          default:
            break;
          }
        }
      }
      debug(bookindex) {
        writefln(
          "%s\n%s:%s",
          "-------------------------------",
          __FILE__,
          __LINE__,
        );
        auto bookindex = BookIndexReport();
        bookindex.bookindex_report_sorted(bookindex_unordered_hashes);
      }
      
      debug(biblio) {
        foreach (entry; biblio) {
          writefln(
            "%s; (%s)",
            entry["sortby_deemed_author_year_title"],
            entry["author"],
          );
        }
      }
      
      debug(anchor) {
        writefln(
          "%s\n%s:%s",
          "-------------------------------",
          __FILE__,
          __LINE__,
        );
        foreach (k; document_section_keys_sequenced["seg"]) {
          foreach (obj; contents[k]) {
            if (obj.is_a == "heading") {
              writefln(
                "%s~ [%s] %s %s",
                obj.heading_attrib.lev,
                obj.obj_cite_number,
                obj.anchor_tags,
                // "[", obj["is"], "] ",
                obj.object
              );
            }
          }
        }
      }
      debug(heading) {                         // heading
        string spc;
        foreach (k; document_section_keys_sequenced["seg"]) {
          foreach (o; contents[k]) {
            if (o.is_a == "heading") {
              switch (o.heading_attrib.lev_markup_number) {
              case 0:
                spc="";
                break;
              case 1:
                spc="  ";
                break;
              case 2:
                spc="    ";
                break;
              case 3:
                spc="      ";
                break;
              case 4:
                spc="        ";
                break;
              case 5:
                spc="          ";
                break;
              case 6:
                spc="            ";
                break;
              case 7:
                spc="              ";
                break;
              case 8:
                spc="                ";
                break;
              default:
                spc="";
                break;
              }
              writefln(
                "%s* %s\n                (markup level: %s; collapsed level: %s)",
                spc,
                strip(o.object),
                o.heading_attrib.lev_markup_number,
                o.heading_attrib.lev_collapsed_number
              );
            }
          }
        }
      }
      debug(summary) {
        string[string] check = [
          "last_obj_cite_number" : "NA [debug \"checkdoc\" not run]",
        ];
        debug(headings) {
          writefln(
            "%s\n%s:%s",
            "-------------------------------",
            __FILE__,
            __LINE__,
          );
          foreach (k; document_section_keys_sequenced["seg"]) {
            foreach (obj; contents[k]) {
              if (obj.is_a == "heading") {
                writefln(
                  "%s~ [%s] %s",
                  obj.heading_attrib.lev,
                  obj.obj_cite_number,
                  // "[", obj["is"], "] ",
                  obj.object
                );
              }
            }
          }
        }
        debug(checkdoc) {
          foreach (k; document_section_keys_sequenced["seg"]) {
            foreach (obj; contents[k]) {
              if (obj.use == "content") {
                if (!empty(obj.obj_cite_number)) {
                  check["last_obj_cite_number"] = obj.obj_cite_number;
                }
              }
            }
          }
        }
        writefln(
          "%s\n\"%s\", %s\n%s\n%s\n%s%10d\n%s%10d\n%s%10d\n%s%10d\n%s%10d\n%s%10d\n%s%10d\n%s%10d\n(%s: %s)",
          "---------------------------------",
          dochead_meta["title"]["full"],
          dochead_meta["creator"]["author"],
          fn_src,
          "---------------------------------",
          "length toc array:      ",
          to!int(contents["toc_seg"].length),
          "length contents array: ",
          to!int(contents["body"].length),
          "last obj_cite_number:  ",
          to!int(check["last_obj_cite_number"]),
          "length endnotes:       ",
          (contents["endnotes_seg"].length > 1)
          ? (to!int(contents["endnotes_seg"].length))
          : 0,
          "length glossary:       ",
          (contents["glossary"].length > 1)
          ? (to!int(contents["glossary"].length))
          : 0,
          "length biblio:         ",
          (contents["bibliography"].length > 1)
          ? (to!int(contents["bibliography"].length))
          : 0,
          "length bookindex:      ",
          (contents["bookindex_seg"].length > 1)
          ? (to!int(contents["bookindex_seg"].length))
          : 0,
          "length blurb:          ",
          (contents["blurb"].length > 1)
          ? (to!int(contents["blurb"].length))
          : 0,
          __FILE__,
          __LINE__,
        );
        debug(checkdoc) {
          if (auto mfn=match(fn_src, rgx.src_fn)) {
            if (opt_action_bool["assertions"]) {
              switch (mfn.captures[2]) {
              // live manual:
              case "live-manual.ssm":
                assert(check["last_obj_cite_number"] ==
                  "1019","last obj_cite_number should be: 1019 (check test, document is frequently updated)"); // ok
                break;
              // sisu_markup:
              case "sisu_markup.sst":
                assert(check["last_obj_cite_number"] ==
                  "297","last obj_cite_number expected to be: 297 rather than " ~ check["last_obj_cite_number"]); // ok
                // assert(check["last_obj_cite_number"] == "297","last obj_cite_number expected to be: 297 rather than " ~ check["last_obj_cite_number"]);
                // notes for first divergance study sisu headings 247 250
                // sisu has issue with code that contains heading 1~ which results in no obj_cite_number! ??
                // sisu currently has incorrect last body obj_cite_number of 294!
                // bug in sisu? attend
                break;
              // sisu-markup-samples:
              case "accelerando.charles_stross.sst":
                assert(check["last_obj_cite_number"] ==
                  "2861","last obj_cite_number expected to be: 2861 rather than " ~ check["last_obj_cite_number"]); // ok
                break;
              case "alices_adventures_in_wonderland.lewis_carroll.sst":
                assert(check["last_obj_cite_number"] ==
                  "805","last obj_cite_number expected to be: 805 rather than " ~ check["last_obj_cite_number"]); // 808
                break;
              case "autonomy_markup0.sst":
                assert(check["last_obj_cite_number"] ==
                  "77","last obj_cite_number expected to be: 77 rather than " ~ check["last_obj_cite_number"]); // ok endnotes
                // assert(check["last_obj_cite_number"] == "78","last obj_cite_number expected to be: 78 rather than " ~ check["last_obj_cite_number"]);
                break;
              case "content.cory_doctorow.sst":
                assert(check["last_obj_cite_number"] ==
                  "953","last obj_cite_number expected to be: 953 rather than " ~ check["last_obj_cite_number"]); // 1007 way off, check obj_cite_number off switches
                // assert(check["last_obj_cite_number"] == "953","last obj_cite_number expected to be: 953 rather than " ~ check["last_obj_cite_number"]);
                break;
              case "democratizing_innovation.eric_von_hippel.sst":
                // fixed ERROR! range violation, broken check! endnotes, bookindex, biblio
                // error in bookindex ... (ch1; ch6; ch8 )
                assert(check["last_obj_cite_number"] ==
                  "905","last obj_cite_number expected to be: 905 rather than " ~ check["last_obj_cite_number"]); // 911
                break;
              case "down_and_out_in_the_magic_kingdom.cory_doctorow.sst":
                assert(check["last_obj_cite_number"] ==
                  "1417","last obj_cite_number expected to be: 1417 rather than " ~ check["last_obj_cite_number"]); // 1455 check obj_cite_number off switches
                break;
              case "for_the_win.cory_doctorow.sst":
                assert(check["last_obj_cite_number"] ==
                  "3510","last obj_cite_number expected to be: 3510 rather than " ~ check["last_obj_cite_number"]); // 3569 check obj_cite_number off switches
                break;
              case "free_as_in_freedom_2.richard_stallman_and_the_free_software_revolution.sam_williams.richard_stallman.sst":
                assert(check["last_obj_cite_number"] ==
                  "1082","last obj_cite_number expected to be: 1082 rather than " ~ check["last_obj_cite_number"]); // check 1079 too few
                break;
              case "free_culture.lawrence_lessig.sst":
                assert(check["last_obj_cite_number"] ==
                  "1330","last obj_cite_number expected to be: 1330 rather than " ~ check["last_obj_cite_number"]); // 1312
                // fixed ERROR! range violation, broken check!
                // error in bookindex ... sections piracy (ch1) & property (ch10 market concentration) fixed
                break;
              case "free_for_all.peter_wayner.sst": // endnotes, bookindex, biblio
                assert(check["last_obj_cite_number"] ==
                  "1559","last obj_cite_number expected to be: 1559 rather than " ~ check["last_obj_cite_number"]); // 1560, check obj_cite_number off switches, has endnotes so 2 too many
                // assert(check["last_obj_cite_number"] == "1559","last obj_cite_number expected to be: 1559 rather than " ~ check["last_obj_cite_number"]);
                break;
              case "gpl2.fsf.sst":
                assert(check["last_obj_cite_number"] ==
                  "65","last obj_cite_number expected to be: 65 rather than " ~ check["last_obj_cite_number"]); // ok endnotes? check
                // assert(check["last_obj_cite_number"] == "66","last obj_cite_number expected to be: 66 rather than " ~ check["last_obj_cite_number"]);
                break;
              case "gpl3.fsf.sst":
                assert(check["last_obj_cite_number"] ==
                  "123","last obj_cite_number expected to be: 123 rather than " ~ check["last_obj_cite_number"]); // ok
                break;
              case "gullivers_travels.jonathan_swift.sst":
                assert(check["last_obj_cite_number"] ==
                  "668","last obj_cite_number expected to be: 668 rather than " ~ check["last_obj_cite_number"]); // 674
                break;
              case "little_brother.cory_doctorow.sst":
                assert(check["last_obj_cite_number"] ==
                  "3130","last obj_cite_number expected to be: 3130 rather than " ~ check["last_obj_cite_number"]); // 3204, check obj_cite_number off switches
                break;
              case "the_cathedral_and_the_bazaar.eric_s_raymond.sst":
                assert(check["last_obj_cite_number"] ==
                  "258","last obj_cite_number expected to be: 258 rather than " ~ check["last_obj_cite_number"]); // ok
                break;
              case "the_public_domain.james_boyle.sst":
                assert(check["last_obj_cite_number"] ==
                  "970","last obj_cite_number expected to be: 970 rather than " ~ check["last_obj_cite_number"]); // 978
                break;
              case "the_wealth_of_networks.yochai_benkler.sst": // endnotes, bookindex
                assert(check["last_obj_cite_number"] ==
                  "829","last obj_cite_number expected to be: 829 rather than " ~ check["last_obj_cite_number"]); // ok
                // assert(check["last_obj_cite_number"] == "832","last obj_cite_number expected to be: 832 rather than " ~ check["last_obj_cite_number"]);
                // has endnotes and bookindex, issue with sisu.rb
                break;
              case "through_the_looking_glass.lewis_carroll.sst":
                assert(check["last_obj_cite_number"] ==
                  "949","last obj_cite_number expected to be: 949 rather than " ~ check["last_obj_cite_number"]); // 955
                break;
              case "two_bits.christopher_kelty.sst": // endnotes, bookindex, biblio
                assert(check["last_obj_cite_number"] ==
                  "1190","last obj_cite_number expected to be: 1190 rather than " ~ check["last_obj_cite_number"]); // 1191
                // assert(check["last_obj_cite_number"] == "1193","last obj_cite_number expected to be: 1193 rather than " ~ check["last_obj_cite_number"]); // 1191 ok?
                // has endnotes and bookindex, issue with sisu.rb
                break;
                // fixed ERROR! range violation!
                // error in bookindex ... (ch3 the movement)
              case "un_contracts_international_sale_of_goods_convention_1980.sst":
                assert(check["last_obj_cite_number"] ==
                  "377","last obj_cite_number expected to be: 377 rather than " ~ check["last_obj_cite_number"]); // ok
                break;
              case "viral_spiral.david_bollier.sst": // endnotes, bookindex
                assert(check["last_obj_cite_number"] ==
                  "1078","last obj_cite_number expected to be: 1078 rather than " ~ check["last_obj_cite_number"]); // 1100
                // fixed ERROR! range violation!
                // error in bookindex ... (ch7 ... building the cc machine, an extra semi colon)
                break;
              default:
                writeln(fn_src);
                break;
              }
            }
          }
        }
      }
    }
  }
}