template SiSUabstraction() {
  /+ sdp: sisu document parser, see http://sisudoc.org +/
  import
    abstraction_summary,
    ao_abstract_doc_source,
    ao_conf_make_meta,
    ao_conf_make_meta_native,
    ao_conf_make_meta_sdlang,
    ao_defaults,
    ao_doc_debugs,
    ao_read_config_files,
    ao_read_source_files,
    ao_rgx,
    output_hub;
  /+ sdlang http://sdlang.org +/
  import sdlang;                            // sdlang.d
  /+ std +/
  private import
    std.array,
    std.exception,
    std.getopt,
    std.process,
    std.stdio,
    std.regex,
    std.string,
    std.traits,
    std.typecons,
    std.utf,
    std.conv : to;
  mixin SiSUrgxInit;
  mixin SiSUregisters;
  mixin SiSUheaderExtractSDLang;
  mixin SiSUnode;
  mixin SiSUbiblio;
  mixin SiSUrgxInitFlags;
  mixin outputHub;
  // auto sdl_root_configuration = ConfigHub!()("conf.sdl", env);
  // auto sdl_root_doc_make = ConfigHub!()("sisu_document_make", env);
  // auto confsdl = HeaderExtractSDL();
  // auto conf_settings_aa = confsdl.configSettingsSDLangToAAmake(sdl_root_configuration);
  // auto conf_doc_make_aa = confsdl.documentMakeSDLangToAAmake(sdl_root_doc_make);
  auto rgx = Rgx();
  auto SiSUabstraction(Fn,O,E)(Fn fn_src, O opts, E env){
    auto sdl_root_configuration = ConfigHub!()("conf.sdl", env);
    auto sdl_root_doc_make = ConfigHub!()("sisu_document_make", env);
    auto confsdl = HeaderExtractSDL();
    auto conf_settings_aa = confsdl.configSettingsSDLangToAAmake(sdl_root_configuration);
    auto conf_doc_make_aa = confsdl.documentMakeSDLangToAAmake(sdl_root_doc_make);
    /+ ↓ read file (filename with path) +/
    /+ ↓ file tuple of header and content +/
    auto _0_header_1_body_content_2_insert_filelist_tuple =
      SiSUrawMarkupContent!()(fn_src);
    static assert(!isTypeTuple!(_0_header_1_body_content_2_insert_filelist_tuple));
    static assert(_0_header_1_body_content_2_insert_filelist_tuple.length==3);
    debug(header_and_body) {
      writeln(header);
      writeln(_0_header_1_body_content_2_insert_filelist_tuple.length);
      writeln(_0_header_1_body_content_2_insert_filelist_tuple.length[1][0]);
    }
    /+ ↓ split header into make and meta +/
    auto _0_make_1_dochead_meta_tuple =
      SiSUheaderExtractHub!()(_0_header_1_body_content_2_insert_filelist_tuple[0], conf_doc_make_aa);
    static assert(!isTypeTuple!(_0_make_1_dochead_meta_tuple));
    static assert(_0_make_1_dochead_meta_tuple.length==2);
    /+ ↓ document abstraction: process document, return abstraction as tuple +/
    auto da = SiSUdocAbstraction!()(
      (_0_header_1_body_content_2_insert_filelist_tuple[1]),
      (_0_make_1_dochead_meta_tuple[0]),
      (_0_make_1_dochead_meta_tuple[1]),
      opts
    );
    static assert(!isTypeTuple!(da));
    static assert(da.length==4);
    auto doc_abstraction = da[0]; // head ~ toc ~ body ~ endnotes_seg ~ glossary ~ bibliography ~ bookindex ~blurb;
    string[][string] _document_section_keys_sequenced = da[1];
    string[] _doc_html_segnames = da[2];
    auto _images = da[3];
    struct DocumentMatters {
      string[] keys_seq_seg() {
        string[] _k = _document_section_keys_sequenced["seg"];
        return _k;
      }
      string[] keys_seq_scroll() {
        string[] _k = _document_section_keys_sequenced["scroll"];
        return _k;
      }
      string[] segnames() {
        string[] _k = _doc_html_segnames;
        return _k;
      }
      auto dochead_make() {
        string[string][string] _k = _0_make_1_dochead_meta_tuple[0];
        return _k;
      }
      auto dochead_meta() {
        string[string][string] _k = _0_make_1_dochead_meta_tuple[1];
        return _k;
      }
      auto source_filename() {
        string _k = fn_src;
        return _k;
      }
      auto language() {
        string _k;
        if (auto m = match(fn_src, rgx.language_code_and_filename)) {
          _k = m.captures[1];
        } else {
          _k = "en";
        }
        return _k;
      }
      auto file_insert_list() {
        string[] _k = _0_header_1_body_content_2_insert_filelist_tuple[2];
        return _k;
      }
      auto image_list() {
        auto _k = _images;
        return _k;
      }
      auto opt_action_bool() {
        bool[string] _k = opts;
        return _k;
      }
      auto environment() {
        auto _k = env;
        return _k;
      }
    }
    auto doc_matters = DocumentMatters();
    auto t = tuple(doc_abstraction, doc_matters);
    static assert(t.length==2);
    return t;
  }
}