template outputEPub() {
  struct outputEPub {
    mixin InternalMarkup;
    mixin outputXHTMLs;
    string epub_mimetypes() {
      string o;
      o = format(q"¶application/epub+zip¶");
      return o;
    }
    string epub_container_xml() {
      string o;
      o = format(q"¶<?xml version='1.0' encoding='utf-8'?>
    <container version="1.0"
      xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
      <rootfiles>
        <rootfile full-path="OEBPS/content.opf"
          media-type="application/oebps-package+xml" />
      </rootfiles>
    </container>¶");
      return o;
    }
    string epub_oebps_content(
      // string[string][string]   dochead_meta,
    ) {
      // string[] toc;
      // int counter = 0;
      string uuid = "18275d951861c77f78acd05672c9906924c59f18a2e0ba06dad95959693e9bd8"; // TODO shared elsewhere
      string content = format(q"¶<?xml version='1.0' encoding='utf-8'?>
    <?xml version='1.0' encoding='utf-8'?>
    <package xmlns="http://www.idpf.org/2007/opf" version="2.0" unique-identifier="EPB-UUID">
      <opf:metadata
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:opf="http://www.idpf.org/2007/opf"
        xmlns:dcterms="http://purl.org/dc/terms/"
        xmlns:dc="http://purl.org/dc/elements/1.1/"
        unique-identifier="urn:uuid:%s" version="2.0">
        <dc:title>%s</dc:title>
        <dc:creator opf:file-as="%s" opf:role="aut">%s</dc:creator>
        <dc:language>en</dc:language>
        <dc:date opf:event="published">%s</dc:date>
        <dc:rights>Copyright: %s</dc:rights>
        <dc:identifier opf:scheme="URI">ox/current/en/epub/sisu_markup.epub</dc:identifier>
        <dc:identifier id="bookid">urn:uuid:%s</dc:identifier>
        <!-- <dc:identifier id="EPB-UUID">urn:uuid:%s</dc:identifier> -->
      </opf:metadata>
      <manifest>
        <!-- NCX -->
        <item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml" />
        <!-- CSS Style Sheets -->
        <item id="main-css" href="css/xhtml.css" media-type="text/css" />¶",
        uuid,
        doc_matters.dochead_meta["title"]["full"],                                                               // title
        (doc_matters.dochead_meta["creator"]["author"].empty) ? "" : " by " ~ doc_matters.dochead_meta["creator"]["author"], // author
        (doc_matters.dochead_meta["creator"]["author"].empty) ? "" : " by " ~ doc_matters.dochead_meta["creator"]["author"], // author
        (doc_matters.dochead_meta["date"]["published"].empty) ? "" : " by " ~ doc_matters.dochead_meta["date"]["published"],  // date
        (doc_matters.dochead_meta["rights"]["copyright"].empty) ? "" : " by " ~ doc_matters.dochead_meta["rights"]["copyright"],  // rights
        uuid,
        uuid,
      );
      foreach (sect; doc_matters.keys_seq_seg) {
        foreach (obj; contents[sect]) {
        }
      }
      return content;
    }
    string epub_oebps_toc() {
      int counter = 0;
      string uuid = "18275d951861c77f78acd05672c9906924c59f18a2e0ba06dad95959693e9bd8"; // TODO shared elsewhere
      auto markup = InlineMarkup();
      enum DomTags { none, open, close, close_and_open, open_still, }
      string toc = format(q"¶<?xml version='1.0' encoding='utf-8'?>
    <ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
      <head>
        <!-- four required metadata items (for all NCX documents,
          (including the relaxed constraints of OPS 2.0) -->
        <title>%s%s</title>
        <link href="css/xhtml.css" rel="stylesheet" type="text/css" id="main-css" />
        <meta name="dtb:uid" content="urn:uuid:%s" />
        <!-- <meta name="epub-creator" content="SiSU http://www.jus.uio.no/sisu (this copy)" /> -->
        <meta name="dtb:depth" content="%s" />
        <meta name="dtb:totalPageCount" content="0" />
        <meta name="dtb:maxPageNumber" content="0" />
      </head>
      <docTitle>
        <text>%s</text>
      </docTitle>
      <docAuthor>
        <text>%s</text>
      </docAuthor>
      <navMap>¶",
        doc_matters.dochead_meta["title"]["full"],                                                               // title
        (doc_matters.dochead_meta["creator"]["author"].empty) ? "" : " by " ~ doc_matters.dochead_meta["creator"]["author"], // author
        uuid,                                                                                        // uuid
        "3",                                                                                         // content depth
        doc_matters.dochead_meta["title"]["full"],                                                               // title
        (doc_matters.dochead_meta["creator"]["author"].empty) ? "" : doc_matters.dochead_meta["creator"]["author"],          // author
      );
      foreach (sect; doc_matters.keys_seq_seg) {
        foreach (obj; contents[sect]) {
          if (obj.is_a == "heading") {
            foreach_reverse (k; 0 .. 7) {
              switch (obj.dom_markedup[k]) {
              case DomTags.close :
                writeln(markup.indent_by_spaces_provided(k), "</", k, ">");
    toc ~= "</navPoint>";
                break;
              case DomTags.close_and_open :
                writeln(markup.indent_by_spaces_provided(k), "</", k, ">");
                writeln(markup.indent_by_spaces_provided(k), "<", k, ">", obj.text);
                ++counter;
    toc ~= "</navPoint>";
    toc ~= format(q"¶<navPoint class="chapter" id="navpoint" playOrder="%s">
    <navLabel>
      <text>%s</text>
    </navLabel>
    <content src="%s" />¶",
    counter,
    obj.text,
    obj.segment_anchor_tag,   // lev < 4 [no link]; lev == 4 [filename] markup.xhtml; lev > 4 [filename#ocn] (links done in segment_anchor_tag)
    );
                break;
              case DomTags.open :
                writeln(markup.indent_by_spaces_provided(k), "<", k, ">", obj.text);
                ++counter;
    toc ~= format(q"¶<navPoint class="chapter" id="navpoint" playOrder="%s">
    <navLabel>
      <text>%s</text>
    </navLabel>
    <content src="%s" />¶",
    counter,
    obj.text,
    obj.segment_anchor_tag,   // lev < 4 [no link]; lev == 4 [filename] markup.xhtml; lev > 4 [filename#ocn] (fix links in segment_anchor_tag)
    );
                break;
              default :
                break;
              }
            }
          }
        }
      }
      toc ~= format(q"¶  </navMap>
    </ncx>¶");
      return toc;
    }
    
    void doc_content(C,T)(
      auto ref const C         contents,
      auto ref T               doc_matters,
    ) {
      auto xhtml_format = outputXHTMLs();
      auto rgx = Rgx();
      // string[] toc;
      string[][string] doc_epub;
      string[] doc;
      string segment_filename;
      string[] seg_filenames;
      string[] top_level_headings = ["","","",""];
      auto mimetypes = epub_mimetypes;
      auto meta_inf_container_xml = epub_container_xml;
      auto oebps_toc_ncx = epub_oebps_toc;
      auto oebps_content_opf = epub_oebps_content;
      foreach (part; doc_matters.keys_seq_seg) {
        foreach (obj; contents[part]) {
          if (obj.is_a == "heading") {
            switch (obj.heading_lev_markup) {
            // case 0:
            //   break;
            case 0: .. case 3:
              /+ fill buffer, and replace with new levels from 1 to 3 +/
              switch (obj.heading_lev_markup) {
              case 0:
                top_level_headings[0] = "";
                top_level_headings[1] = "";
                top_level_headings[2] = "";
                top_level_headings[3] = "";
                goto default;
              case 1:
                top_level_headings[1] = "";
                top_level_headings[2] = "";
                top_level_headings[3] = "";
                goto default;
              case 2:
                top_level_headings[2] = "";
                top_level_headings[3] = "";
                goto default;
              case 3:
                top_level_headings[3] = "";
                goto default;
              default:
                top_level_headings[obj.heading_lev_markup] = xhtml_format.heading(obj);
                break;
              }
              break;
            case 4:
              seg_filenames ~= obj.segment_anchor_tag;
              segment_filename = obj.segment_anchor_tag;
              doc_epub[segment_filename] ~= xhtml_format.seg_head(doc_matters.dochead_meta);
              foreach (top_level_heading; top_level_headings) {
                // writeln(top_level_heading);
                doc_epub[segment_filename] ~= top_level_heading;
              }
              doc_epub[segment_filename] ~= xhtml_format.heading(obj);
              break;
            case 5: .. case 7:
              doc_epub[segment_filename] ~= xhtml_format.heading(obj);
              break;
            default:
              writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
              break;
            }
          } else if (obj.use == "frontmatter") {
            switch (obj.is_of) {
            case "para":
              switch (obj.is_a) {
              case "toc":
                  doc_epub[segment_filename] ~= xhtml_format.toc(obj);
              //   doc_epub ~= xhtml_toc(obj);
              break;
              default:
                // writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
                break;
              }
              break;
            default:
              // writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
              break;
            }
          } else if (obj.use == "body") {
            switch (obj.is_of) {
            case "para":
              switch (obj.is_a) {
              case "para":
                doc_epub[segment_filename] ~= xhtml_format.para(obj);
                break;
              default:
                // writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
                break;
              }
              break;
            case "block":
              switch (obj.is_a) {
              case "poem":                        // double check why both poem & verse
                break;
              case "verse":
                doc_epub[segment_filename] ~= xhtml_format.nugget(obj);
                // doc_epub ~= xhtml_verse(obj);
                break;
              case "group":
                doc_epub[segment_filename] ~= xhtml_format.nugget(obj);
                // doc_epub ~= xhtml_group(obj);
                break;
              case "block":
                doc_epub[segment_filename] ~= xhtml_format.nugget(obj);
                // doc_epub ~= xhtml_block(obj);
                break;
              case "quote":
                doc_epub[segment_filename] ~= xhtml_format.nugget(obj);
                // doc_epub ~= xhtml_quote(obj);
                break;
              case "table":
                doc_epub[segment_filename] ~= xhtml_format.para(obj); //
                // doc_epub ~= xhtml_table(obj);
                break;
              case "code":
                doc_epub[segment_filename] ~= xhtml_format.code(obj);
                break;
              default:
                writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
                break;
              }
              break;
            default:
              // writeln(__FILE__, ":", __LINE__, ": ", obj.is_of);
              break;
            }
          } else if (obj.use == "backmatter") {
            switch (obj.is_of) {
            case "para":
              switch (obj.is_a) {
              case "endnote":
                doc_epub[segment_filename] ~= xhtml_format.endnote(obj);
                break;
              case "glossary":
                doc_epub[segment_filename] ~= xhtml_format.para(obj);
                break;
              case "bibliography":
                doc_epub[segment_filename] ~= xhtml_format.para(obj);
                break;
              case "bookindex":
                doc_epub[segment_filename] ~= xhtml_format.para(obj);
                break;
              case "blurb":
                doc_epub[segment_filename] ~= xhtml_format.para(obj);
                break;
              default:
                // writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
                break;
              }
              break;
            default:
              writeln(__FILE__, ":", __LINE__, ": ", obj.is_a);
              break;
            }
          }
        }
      }
      writeln(doc_matters.keys_seq_seg);
      epub_write_output_files(
        doc_matters.source_filename,
        seg_filenames,
        doc_epub,
        mimetypes,
        meta_inf_container_xml,
        oebps_toc_ncx,
        oebps_content_opf,
      );
    }
    void epub_write_output_files(Fn,FnS,De,Mt,Mic,Ot,Oc)(
      Fn  fn_src,
      FnS seg_filenames,
      De  doc_epub,
      Mt  mimetypes,
      Mic meta_inf_container_xml,
      Ot  oebps_toc_ncx,
      Oc  oebps_content_opf,
    ) {
      debug(asserts){
        static assert(is(typeof(fn_src)                 == string));
        static assert(is(typeof(seg_filenames)          == string[]));
        static assert(is(typeof(doc_epub)               == string[][string]));
        static assert(is(typeof(mimetypes)              == string));
        static assert(is(typeof(meta_inf_container_xml) == string));
        static assert(is(typeof(oebps_toc_ncx)          == string));
        static assert(is(typeof(oebps_content_opf)      == string));
      }
      mixin SiSUpaths;
      auto pth_epub = EpubPaths();
      // doc = xhtml_format.scroll_head ~ doc_epub ~  xhtml_format.tail;
      auto xhtml_format = outputXHTMLs();
      try {
        mkdirRecurse(pth_epub.doc_meta_inf(fn_src));
        mkdirRecurse(pth_epub.doc_oebps_css(fn_src));
        mkdirRecurse(pth_epub.doc_oebps_image(fn_src));
        /+ OEBPS/[segments].xhtml +/
        foreach (seg_filename; seg_filenames) {
          auto f = File(pth_epub.fn_oebps_content_xhtml(fn_src, seg_filename), "w");
          /+ // f.writeln(seg_head); // not needed built and inserted earlier +/
          foreach (docseg; doc_epub[seg_filename]) {
            f.writeln(docseg);
          }
          f.writeln(xhtml_format.tail); // needed for each lev4
        }
        /+ mimetypes +/
        auto f = File(pth_epub.fn_mimetypes(fn_src), "w");
        f.writeln(mimetypes);
        /+  META-INF/container.xml +/
        f = File(pth_epub.fn_dmi_container_xml(fn_src), "w");
        f.writeln(meta_inf_container_xml);
        /+ OEBPS/toc.ncx +/
        f = File(pth_epub.fn_oebps_toc_ncx(fn_src), "w");
        f.writeln(oebps_toc_ncx);
        /+ OEBPS/content.opf +/
        f = File(pth_epub.fn_oebps_content_opf(fn_src), "w");
        f.writeln(oebps_content_opf);
      }
      catch (ErrnoException ex) {
        // Handle error
      }
    }
    
  }
}