From 0c4b3cb3707c3b16cd171620427e651d71182813 Mon Sep 17 00:00:00 2001
From: Ralph Amissah <ralph.amissah@gmail.com>
Date: Fri, 13 Dec 2019 09:09:24 -0500
Subject: present per document metadata

---
 src/doc_reform/io_in/paths_source.d            |  21 +-
 src/doc_reform/io_out/hub.d                    |   6 +
 src/doc_reform/io_out/metadata.d               | 385 +++++++++++++++++++++++++
 src/doc_reform/io_out/paths_output.d           |  21 ++
 src/doc_reform/io_out/xmls.d                   |   6 +-
 src/doc_reform/meta/conf_make_meta_structs.d   |   1 +
 src/doc_reform/meta/conf_make_meta_yaml.d      |   6 +
 src/doc_reform/meta/defaults.d                 |   3 +-
 src/doc_reform/meta/metadoc_harvest.d          |   1 +
 src/doc_reform/meta/metadoc_harvests_authors.d |  13 +-
 src/doc_reform/meta/metadoc_harvests_topics.d  |  20 +-
 11 files changed, 454 insertions(+), 29 deletions(-)
 create mode 100644 src/doc_reform/io_out/metadata.d

(limited to 'src')

diff --git a/src/doc_reform/io_in/paths_source.d b/src/doc_reform/io_in/paths_source.d
index a460f7b..3896751 100644
--- a/src/doc_reform/io_in/paths_source.d
+++ b/src/doc_reform/io_in/paths_source.d
@@ -592,20 +592,19 @@ template spinePathsPods() {
     string _base_dir_doc = "dr_doc";
     struct _PodPaths {
       string base_filename_(string fn_src) {
-        auto pth = fn_src.baseName.stripExtension;
-        return pth;
+        return  fn_src.baseName.stripExtension;
+      }
+      string internal_base() {
+        return "pod";
       }
       string pod_dir_() {
-        auto pth = _base_dir_pod;
-        return pth;
+        return _base_dir_pod;
       }
       string dr_doc_dir_() {
-        auto pth = _base_dir_doc;
-        return pth;
+        return _base_dir_doc;
       }
       string pod_filename_(string fn_src) {
-        string pth = _base_dir_pod.chainPath(base_filename_(fn_src) ~ _suffix).array;
-        return pth;
+        return _base_dir_pod.chainPath(base_filename_(fn_src) ~ _suffix).array;
       }
       string base_filesystem_(string fn_src) {
         string pth = _base_dir_pod.chainPath(base_filename_(fn_src)).array;
@@ -614,12 +613,10 @@ template spinePathsPods() {
         return pth;
       }
       string output_pod_manifest_file(string fn_src) {
-        string pth = base_filesystem_(fn_src).chainPath("pod.manifest").array;
-        return pth;
+        return base_filesystem_(fn_src).chainPath("pod.manifest").array;
       }
       string base_pod_(string fn_src) {
-        string pth = _base_dir_pod.chainPath(base_filename_(fn_src)).array; // change this
-        return pth;
+        return _base_dir_pod.chainPath(base_filename_(fn_src)).array; // change this
       }
       auto base_filename(string fn_src) {
         auto pth_1_ = base_filename_(fn_src);
diff --git a/src/doc_reform/io_out/hub.d b/src/doc_reform/io_out/hub.d
index 8de07d8..a43c28a 100644
--- a/src/doc_reform/io_out/hub.d
+++ b/src/doc_reform/io_out/hub.d
@@ -5,6 +5,7 @@
 module doc_reform.io_out.hub;
 template outputHub() {
   import doc_reform.io_out,
+    doc_reform.io_out.metadata,
     doc_reform.io_out.xmls,
     doc_reform.io_out.odt,
     doc_reform.io_out.create_zip_file,
@@ -40,6 +41,10 @@ template outputHub() {
         doc_abstraction.outputEPub3!()(doc_matters);
         msg.vv("epub3 done");
       }
+      if (sched == outTask.html_stuff) {
+        outputMetadata!()(doc_matters);
+        msg.vv("html metadata done");
+      }
       if (sched == outTask.html_scroll) {
         msg.v("html scroll processing... ");
         import doc_reform.io_out.html;
@@ -104,6 +109,7 @@ template outputHub() {
 }
 template outputHubOp() {
   import doc_reform.io_out,
+    doc_reform.io_out.metadata,
     doc_reform.io_out.xmls,
     doc_reform.io_out.odt,
     doc_reform.io_out.create_zip_file,
diff --git a/src/doc_reform/io_out/metadata.d b/src/doc_reform/io_out/metadata.d
new file mode 100644
index 0000000..f3b6176
--- /dev/null
+++ b/src/doc_reform/io_out/metadata.d
@@ -0,0 +1,385 @@
+module spine.io_out.metadata;
+template outputMetadata() {
+  void outputMetadata(T)( T  doc_matters) @safe {
+    import std.file;
+    import std.format;
+    import spine.io_out;
+    mixin InternalMarkup;
+    string[] metadata_;
+string theme_dark_0 = format(q"┃
+  body {
+    color                    : #CCCCCC;
+    background               : #000000;
+    background-color         : #000000;
+  }
+  a:link {
+    color                    : #FFFFFF;
+    text-decoration          : none;
+  }
+  a:visited {
+    color                    : #999999;
+    text-decoration          : none;
+  }
+  a:hover {
+    color                    : #000000;
+    background-color         : #555555;
+  }
+  a:hover img {
+    background-color         : #000000;
+  }
+  a:active {
+    color                    : #888888;
+    text-decoration          : underline;
+  }
+┃");
+string theme_light_0 = format(q"┃
+  body {
+    color                    : #000000;
+    background               : #FFFFFF;
+    background-color         : #FFFFFF;
+  }
+  a:link {
+    color                    : #003399;
+    text-decoration          : none;
+  }
+  a:visited {
+    color                    : #003399;
+    text-decoration          : none;
+  }
+  a:hover {
+    color                    : #000000;
+    background-color         : #f9f9aa;
+  }
+  a:hover img {
+    background-color         : #FFFFFF;
+  }
+  a:active {
+    color                    : #003399;
+    text-decoration          : underline;
+  }
+┃");
+string theme_dark_1 = format(q"┃
+  h1 {
+    color                    : #FFFFFF;
+    background               : #000000;
+  }
+  p.letter {
+    color                    : #FFFFFF;
+    background               : #333333;
+  }
+┃");
+string theme_light_1 = format(q"┃
+  h1 {
+    color                    : #FFFFFF;
+    background               : #000088;
+  }
+  p.letter {
+    color                    : #FFFFFF;
+    background               : #880000;
+  }
+┃");
+      metadata_ ~= format(q"┃<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Metadata Harvest - Topics</title>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+<meta name="dc.title" content= "metadata harvest, Authors & Topics - information Structuring Universe, Structured information Serialised Units" />
+<meta name="dc.subject" content= "document structuring, ebook, publishing, PDF, LaTeX, XML, ODF, SQL, postgresql, sqlite, electronic book, electronic publishing, electronic document, electronic citation, data structure, citation systems, granular search, digital library" />
+<meta name="generator" content="spine" />
+<link rel="generator" href="http://sisudoc.org" />
+<link href="./css/harvest.css" rel="stylesheet">
+<style TYPE="text/css">
+/* spine harvest css default stylesheet */%s
+  .norm, .bold {
+    line-height              : 150%%;
+    margin-left              : 1em;
+    margin-right             : 2em;
+    margin-top               : 10px;
+    margin-bottom            : 0px;
+    text-indent              : 0mm;
+  }
+  p, h0, h1, h2, h3, h4, h5, h6, h7 {
+    display                  : block;
+    font-family              : verdana, arial, georgia, tahoma, sans-serif, helvetica, times, roman;
+    font-size                : 100%%;
+    font-weight              : normal;
+    line-height              : 150%%;
+    /* text-align            : justify; */
+    margin-left              : 1em;
+    text-indent              : 0mm;
+    margin-top               : 2px;
+    margin-bottom            : 2px;
+    margin-right             : 6px;
+    text-align               : left;
+  }
+  h0, h1, h2, h3, h4, h5, h6, h7 { text-shadow: .2em .2em .3em #999999; }
+  h1 {
+    font-size                : 120%%;
+    font-weight              : bold;
+    color                    : #FFFFFF;
+    background               : #000088;
+    margin-left              : 0em;
+  }
+  p.work {
+    font-size                : 80%%;
+    margin-left              : 5em;
+    margin-top               : 0px;
+    margin-bottom            : 0px;
+    margin-right             : 6px;
+    text-align               : left;
+  }
+  p.author {
+    font-size                : 100%%;
+    margin-left              : 2em;
+    margin-top               : 0px;
+    margin-bottom            : 0px;
+    margin-right             : 6px;
+    text-align               : left;
+  }
+  p.publication {
+    font-size                : 80%%;
+    margin-left              : 4em;
+    margin-top               : 0px;
+    margin-bottom            : 0px;
+    margin-right             : 6px;
+    text-align               : left;
+  }
+  p.letter {
+    font-weight              : bold;
+    font-size                : 60%%;
+    margin-left              : 1em;
+    margin-top               : 0px;
+    margin-bottom            : 0px;
+    margin-right             : 6px;
+    text-align               : left;
+  }
+  p.lev0 {
+    font-size                : 120%%;
+    margin-left              : 1em;
+  }
+  p.lev1 {
+    font-size                : 110%%;
+    margin-left              : 2em;
+  }
+  p.lev2 {
+    font-size                : 100%%;
+    margin-left              : 3em;
+  }
+  p.lev3 {
+    font-size                : 90%%;
+    margin-left              : 4em;
+  }
+  p.lev4 {
+    font-size                : 80%%;
+    margin-left              : 5em;
+  }
+  p.lev5 {
+    font-size                : 80%%;
+    margin-left              : 6em;
+  }%s
+</style>
+<link rel="shortcut icon" href="../_sisu/image/rb7.ico" />
+</head>
+┃",
+  doc_matters.opt.action.css_theme_default ? theme_light_0 : theme_dark_0,
+  doc_matters.opt.action.css_theme_default ? theme_light_1 : theme_dark_1,
+) ~ "\n";
+    void metadata_write_output(M)(M doc_matters, string[] metadata_) @trusted {
+      auto pth_html = spinePathsHTML!()(doc_matters.output_path, doc_matters.src.language);
+      try {
+        if (!exists(pth_html.base)) {
+          pth_html.base.mkdirRecurse;
+        }
+        auto f = File(pth_html.fn_scroll("metadata." ~ doc_matters.src.filename), "w");
+        foreach (o; metadata_) {
+          f.writeln(o);
+        }
+      } catch (ErrnoException ex) {
+        // Handle error
+      }
+      if (!(doc_matters.opt.action.quiet)) {
+        writeln(" ", pth_html.fn_scroll("metadata." ~ doc_matters.src.filename));
+      }
+    }
+    static auto mkup = InlineMarkup();
+    if (doc_matters.opt.action.debug_do) {
+      writeln(doc_matters.src.filename_base);
+      writeln("Title:       ", doc_matters.conf_make_meta.meta.title_full);
+      writeln("  Author:    ", doc_matters.conf_make_meta.meta.creator_author);
+      writeln("  Published: ", doc_matters.conf_make_meta.meta.date_published);
+      writeln("  Copyright: ", doc_matters.conf_make_meta.meta.rights_copyright);
+      writeln("  License:   ", doc_matters.conf_make_meta.meta.rights_license);
+      if (doc_matters.conf_make_meta.meta.classify_topic_register_arr.length > 0) {
+        foreach (topic; doc_matters.conf_make_meta.meta.classify_topic_register_arr.sort!("toUpper(a) < toUpper(b)", SwapStrategy.unstable)) {
+          string[] subject_tree = topic.split(mkup.sep);
+          if (subject_tree.length > 0) { writeln("  ",         subject_tree[0]); }
+          if (subject_tree.length > 1) { writeln("    ",       subject_tree[1]); }
+          if (subject_tree.length > 2) { writeln("      ",     subject_tree[2]); }
+          if (subject_tree.length > 3) { writeln("        ",   subject_tree[3]); }
+          if (subject_tree.length > 4) { writeln("          ", subject_tree[4]); }
+        }
+      }
+    }
+    auto pth_html = spinePathsHTML!()(doc_matters.output_path, doc_matters.src.language);
+    auto pth_epub = spinePathsEPUB!()(doc_matters.output_path, doc_matters.src.language);
+    auto pth_pod =  spinePathsPods!()(doc_matters);
+    metadata_ ~= format(q"┃<body lang="en" xml:lang="en">
+    <a name="top" id="top"></a>
+    <a name="up" id="up"></a>
+    <a name="start" id="start"></a>
+    ┃");
+    if (doc_matters.opt.action.harvest_link) {
+      metadata_ ~= format(q"┃<p>[<a href="../../index.html">&nbsp;HOME&nbsp;</a>] Metadata Harvest
+       [<a href="../../authors.html">&nbsp;Authors&nbsp;</a>]
+       [<a href="../../topics.html">&nbsp;Topics&nbsp;</a>]</p>
+    <hr />
+    ┃");
+    } else {
+      metadata_ ~= format(q"┃<p>[<a href="../../index.html">&nbsp;HOME&nbsp;</a>]
+    <hr />
+    ┃");
+    }
+    if (!(doc_matters.conf_make_meta.meta.title_full.empty)) {
+      metadata_ ~= "<p class=\"lev0\">Title: <b><a href=\"" ~ doc_matters.src.filename_base ~ "/toc.html\">" ~ doc_matters.conf_make_meta.meta.title_full       ~ "</a></b></p>";
+    } else if (doc_matters.opt.action.debug_do || doc_matters.opt.action.very_verbose) {
+      writeln("ERROR no Title information provided in document header ", doc_matters.src.filename_base);
+    }
+    if (!(doc_matters.conf_make_meta.meta.creator_author.empty)) {
+      if (doc_matters.opt.action.harvest_link) {
+        metadata_ ~= "<p class=\"lev1\">Author: <b><a href=\"../../authors.html#" ~ doc_matters.conf_make_meta.meta.creator_author_surname.translate([' ' : "_"]) ~ "\">"
+                                                   ~ doc_matters.conf_make_meta.meta.creator_author   ~ "</a></b></p>";
+      } else {
+        metadata_ ~= "<p class=\"lev1\">Author: <b>"
+                                                   ~ doc_matters.conf_make_meta.meta.creator_author   ~ "</b></p>";
+      }
+    } else if (doc_matters.opt.action.debug_do || doc_matters.opt.action.very_verbose) {
+      writeln("ERROR no Author information provided in document header ", doc_matters.src.filename_base);
+    }
+    metadata_ ~= "<p class=\"lev1\">Published: "   ~ doc_matters.conf_make_meta.meta.date_published   ~ "</p>";
+    if (!(doc_matters.conf_make_meta.meta.rights_copyright.empty)) {
+      metadata_ ~= "<p class=\"lev1\">Copyright: "   ~ doc_matters.conf_make_meta.meta.rights_copyright ~ "</p>";
+    } else if (doc_matters.opt.action.debug_do || doc_matters.opt.action.very_verbose) {
+      writeln("WARNING no Copyright information provided in document header ", doc_matters.src.filename_base);
+    }
+    if (!(doc_matters.conf_make_meta.meta.rights_license.empty)) {
+      metadata_ ~= "<p class=\"lev1\">License:   "   ~ doc_matters.conf_make_meta.meta.rights_license   ~ "</p>";
+    } else if (doc_matters.opt.action.debug_do || doc_matters.opt.action.very_verbose) {
+      writeln("WARNING no License information provided in document header ", doc_matters.src.filename_base);
+    }
+    if (!(doc_matters.conf_make_meta.meta.notes_summary.empty)) {
+      metadata_ ~= "<hr /><p class=\"lev0\">Summary:</p><p class=\"lev1\">"   ~ doc_matters.conf_make_meta.meta.notes_summary   ~ "</p>";
+    } else if (doc_matters.opt.action.debug_do) {
+      writeln("WARNING no summary of text provided in document header ", doc_matters.src.filename_base);
+    }
+    if (doc_matters.conf_make_meta.meta.classify_topic_register_arr.length > 0) {
+      metadata_ ~= "<hr /><p class=\"lev0\">Topics:</p>";
+      string[] _top = ["", "", "", "", ""];
+      foreach (topic; doc_matters.conf_make_meta.meta.classify_topic_register_arr.sort!("toUpper(a) < toUpper(b)", SwapStrategy.unstable)) {
+        string[] subject_tree = topic.split(mkup.sep);
+        if (subject_tree.length > 0) {
+          if (subject_tree[0] != _top[0]) {
+            _top[0] = subject_tree[0];
+            if (doc_matters.opt.action.harvest_link) {
+              metadata_ ~=
+                "<p class=\"lev1\"><a href=\"../../topics.html#"
+                  ~ subject_tree[0].translate([' ' : "_"]) ~ "\">"
+                  ~ subject_tree[0]
+                  ~ "</a></p>";
+            } else {
+              metadata_ ~=
+                "<p class=\"lev1\">"  ~ subject_tree[0] ~ "</p>";
+            }
+          }
+          if (subject_tree.length > 1) {
+            if (subject_tree[1] != _top[1]) {
+              _top[1] = subject_tree[1];
+              _top[2] = ""; _top[3] = ""; _top[4] = "";
+              if (doc_matters.opt.action.harvest_link) {
+                metadata_ ~=
+                  "<p class=\"lev2\"><a href=\"../../topics.html#"
+                    ~ subject_tree[0].translate([' ' : "_"]) ~ "."
+                    ~ subject_tree[1].translate([' ' : "_"]) ~ "\">"
+                    ~ subject_tree[1]
+                    ~ "</a></p>";
+              } else {
+                metadata_ ~=
+                  "<p class=\"lev2\">"  ~ subject_tree[1] ~ "</p>";
+              }
+            }
+            if (subject_tree.length > 2) {
+              if (subject_tree[2] != _top[2]) {
+                _top[2] = subject_tree[2];
+                _top[3] = ""; _top[4] = "";
+                if (doc_matters.opt.action.harvest_link) {
+                  metadata_ ~=
+                    "<p class=\"lev3\"><a href=\"../../topics.html#"
+                      ~ subject_tree[0].translate([' ' : "_"]) ~ "."
+                      ~ subject_tree[1].translate([' ' : "_"]) ~ "."
+                      ~ subject_tree[2].translate([' ' : "_"]) ~ "\">"
+                      ~ subject_tree[2]
+                      ~ "</a></p>";
+                } else {
+                  metadata_ ~=
+                    "<p class=\"lev3\">"  ~ subject_tree[2] ~ "</p>";
+                }
+              }
+              if (subject_tree.length > 3) {
+                if (subject_tree[3] != _top[3]) {
+                  _top[3] = subject_tree[3];
+                  _top[4] = "";
+                  if (doc_matters.opt.action.harvest_link) {
+                    metadata_ ~=
+                      "<p class=\"lev4\"><a href=\"../../topics.html#"
+                        ~ subject_tree[0].translate([' ' : "_"]) ~ "."
+                        ~ subject_tree[1].translate([' ' : "_"]) ~ "."
+                        ~ subject_tree[2].translate([' ' : "_"]) ~ "."
+                        ~ subject_tree[3].translate([' ' : "_"]) ~ "\">"
+                        ~ subject_tree[3]
+                        ~ "</a></p>";
+                  } else {
+                    metadata_ ~=
+                      "<p class=\"lev4\">"  ~ subject_tree[3] ~ "</p>";
+                  }
+                }
+                if (subject_tree.length > 4) {
+                  if (subject_tree[4] != _top[4]) {
+                    _top[4] = subject_tree[4];
+                    if (doc_matters.opt.action.harvest_link) {
+                      metadata_ ~=
+                        "<p class=\"lev5\"><a href=\"../../topics.html#"
+                          ~ subject_tree[0].translate([' ' : "_"]) ~ "."
+                          ~ subject_tree[1].translate([' ' : "_"]) ~ "."
+                          ~ subject_tree[2].translate([' ' : "_"]) ~ "."
+                          ~ subject_tree[3].translate([' ' : "_"]) ~ "."
+                          ~ subject_tree[4].translate([' ' : "_"]) ~ "\">"
+                          ~ subject_tree[4]
+                          ~ "</a></p>";
+                    } else {
+                      metadata_ ~=
+                        "<p class=\"lev5\">"  ~ subject_tree[4] ~ "</p>";
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    } else if (doc_matters.opt.action.debug_do) {
+      writeln("WARNING no topic_register classification of text provided in document header ", doc_matters.src.filename_base);
+    }
+    metadata_ ~= "<hr /><p class=\"lev1\">source: "      ~ doc_matters.src.filename_base ~ "</p>";
+    metadata_ ~= "<p class=\"lev1\">markup source: [<a href=\"../../" ~ pth_pod.internal_base ~ "/" ~ doc_matters.src.filename_base ~ ".zip\">"
+                 ~ "&nbsp;zipped&nbsp;pod&nbsp;</a>] "
+                 ~ "[<a href=\"../../" ~ pth_pod.internal_base ~ "/" ~ doc_matters.src.filename_base ~ "/\">"
+                 ~ "&nbsp;pod&nbsp;tree&nbsp;</a>]</p>";
+    metadata_ ~= "<p class=\"lev1\">outputs: [<a href=\""    ~ doc_matters.src.filename_base ~ ".html\">"
+                 ~ "&nbsp;html&nbsp;scroll&nbsp;</a>] "
+                 ~ "[<a href=\""    ~ doc_matters.src.filename_base ~ "/toc.html\">"
+                 ~ "&nbsp;html&nbsp;seg&nbsp;</a>]"
+                 ~ "[<a href=\"../../" ~ pth_epub.internal_base ~ "/" ~ doc_matters.src.filename_base ~ "." ~ doc_matters.src.language ~ ".epub\">"
+                 ~ "&nbsp;epub&nbsp;</a>]</p>";
+    metadata_write_output(doc_matters, metadata_);
+  }
+}
diff --git a/src/doc_reform/io_out/paths_output.d b/src/doc_reform/io_out/paths_output.d
index 5f474a6..23c4624 100644
--- a/src/doc_reform/io_out/paths_output.d
+++ b/src/doc_reform/io_out/paths_output.d
@@ -20,6 +20,9 @@ template spineOutPaths() {
       string output_base() {
         return ((output_root.chainPath(lng)).asNormalizedPath).array;
       }
+      string internal_base() {
+        return lng.asNormalizedPath.array;
+      }
     }
     return _PathsStruct();
   }
@@ -116,6 +119,9 @@ template spineDocRootTreeHTML() {
       string seg(string fn_src) {
         return ((base.chainPath(base_filename_seg(fn_src))).asNormalizedPath).array;
       }
+      string fn_metadata(string fn_src) {
+        return ((base.chainPath("metadata." ~ base_filename_scroll(fn_src) ~ suffix)).asNormalizedPath).array;
+      }
       string fn_scroll(string fn_src) {
         return ((base.chainPath(base_filename_scroll(fn_src) ~ suffix)).asNormalizedPath).array;
       }
@@ -152,6 +158,9 @@ template spinePathsHTML() {
       string harvest(string fn_harvest) {
         return doc_root ~ "/" ~ fn_harvest;
       }
+      string internal_base() {
+        return ((doc_tree.base).asNormalizedPath).array;
+      }
       string base() {
         return ((output_path_root.chainPath(doc_tree.base)).asNormalizedPath).array;
       }
@@ -170,6 +179,9 @@ template spinePathsHTML() {
       string seg(string fn_src) {
         return ((output_path_root.chainPath(doc_tree.seg(fn_src))).asNormalizedPath).array;
       }
+      string fn_metadata(string fn_src) {
+        return ((output_path_root.chainPath(doc_tree.fn_metadata(fn_src))).asNormalizedPath).array;
+      }
       string fn_scroll(string fn_src) {
         return ((output_path_root.chainPath(doc_tree.fn_scroll(fn_src))).asNormalizedPath).array;
       }
@@ -246,6 +258,12 @@ template spineUrlsHTML() {
           ((doc_tree.seg(fn_src)).asNormalizedPath).array,
         );
       }
+      string fn_metadata(string fn_src) {
+        return format(q"┃%s/%s┃",
+          url_doc_root,
+          ((doc_tree.fn_metadata(fn_src)).asNormalizedPath).array,
+        );
+      }
       string fn_scroll(string fn_src) {
         return format(q"┃%s/%s┃",
           url_doc_root,
@@ -295,6 +313,9 @@ template spinePathsEPUB() {
     auto out_pth = spineOutPaths!()(output_pth_root, lng);
     string base_dir = "epub";
     struct _PathsStruct {
+      string internal_base() {
+        return (((out_pth.internal_base).chainPath(base_dir)).asNormalizedPath).array;
+      }
       string base() {
         return (((out_pth.output_base).chainPath(base_dir)).asNormalizedPath).array;
       }
diff --git a/src/doc_reform/io_out/xmls.d b/src/doc_reform/io_out/xmls.d
index 74ebf82..4cb7507 100644
--- a/src/doc_reform/io_out/xmls.d
+++ b/src/doc_reform/io_out/xmls.d
@@ -95,7 +95,7 @@ template outputXHTMLs() {
     ) @safe {
       string _publisher="Publisher"; // TODO
       string o;
-      o = format(q"┃<!-- spine header metadata -->
+      o = format(q"┃<!-- spine DocReform header metadata -->
     <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
     <meta name="dc.title" content="%s" />
     <meta name="dc.author" content="%s" />
@@ -110,7 +110,7 @@ template outputXHTMLs() {
     <meta name="dc.rights" content="%s" />
     <meta name="generator" content="%s" />
     <link rel="generator" href="%s" />
-    <!-- spine header metadata -->┃",
+    <!-- spine DocReform header metadata -->┃",
         doc_matters.conf_make_meta.meta.title_full,
         doc_matters.conf_make_meta.meta.creator_author,
         _publisher,
@@ -600,7 +600,7 @@ template outputXHTMLs() {
     ) @safe {
       string prev, next, toc;
       string harvest_link = (doc_matters.opt.action.harvest_link)
-      ? format(q"┃<p class="tiny">[<a href="../../../topics.html">&nbsp;T&nbsp;</a>|<a href="../../../authors.html">&nbsp;A&nbsp;</a>]</p>┃")
+      ? format(q"┃<p class="tiny">[<a href="../metadata.%s.html">&nbsp;m&nbsp;</a>|<a href="../../../authors.html">&nbsp;A&nbsp;</a>|<a href="../../../topics.html">&nbsp;T&nbsp;</a>]</p>┃", doc_matters.src.filename_base)
       : "";
       if (obj.tags.segment_anchor_tag_epub == "toc") {
         toc = "";
diff --git a/src/doc_reform/meta/conf_make_meta_structs.d b/src/doc_reform/meta/conf_make_meta_structs.d
index 91ecab7..7f220aa 100644
--- a/src/doc_reform/meta/conf_make_meta_structs.d
+++ b/src/doc_reform/meta/conf_make_meta_structs.d
@@ -206,6 +206,7 @@ struct MetaComposite {
   string   links;
   string   notes_abstract;
   string   notes_description;
+  string   notes_summary;
   string   original_language;
   string   original_language_char;
   string   original_publisher;
diff --git a/src/doc_reform/meta/conf_make_meta_yaml.d b/src/doc_reform/meta/conf_make_meta_yaml.d
index 5576b1c..1467fea 100644
--- a/src/doc_reform/meta/conf_make_meta_yaml.d
+++ b/src/doc_reform/meta/conf_make_meta_yaml.d
@@ -679,6 +679,12 @@ static template contentYAMLtoSpineStruct() {
         ) {
           _struct_composite.meta.notes_description = _yaml["notes"]["description"].get!string;
         }
+        if ("summary" in _yaml["notes"]
+          && _yaml["notes"]["summary"].type.string
+          && _yaml["notes"]["summary"].tag.match(rgx.yaml_tag_is_str)
+        ) {
+          _struct_composite.meta.notes_summary = _yaml["notes"]["summary"].get!string;
+        }
       }
     }
     if ("original" in _yaml
diff --git a/src/doc_reform/meta/defaults.d b/src/doc_reform/meta/defaults.d
index 847dcb9..b3f6bba 100644
--- a/src/doc_reform/meta/defaults.d
+++ b/src/doc_reform/meta/defaults.d
@@ -101,8 +101,9 @@ template spineHarvest() {
         string   uid                  = "";
         string   date_published       = "";
         string[] topic_register_arr   = [];
-        string   path_html_segtoc     = "";
+        string   path_html_metadata   = "";
         string   path_html_scroll     = "";
+        string   path_html_segtoc     = "";
         string   path_epub            = "";
         string   path_abs_html_segtoc = "";
         string   path_abs_html_scroll = "";
diff --git a/src/doc_reform/meta/metadoc_harvest.d b/src/doc_reform/meta/metadoc_harvest.d
index 704e960..362ba34 100644
--- a/src/doc_reform/meta/metadoc_harvest.d
+++ b/src/doc_reform/meta/metadoc_harvest.d
@@ -33,6 +33,7 @@ template spineMetaDocHarvest() {
     hvst.harvest.uid                   = doc_matters.src.doc_uid;
     hvst.harvest.date_published        = doc_matters.conf_make_meta.meta.date_published;
     hvst.harvest.topic_register_arr    = doc_matters.conf_make_meta.meta.classify_topic_register_arr;
+    hvst.harvest.path_html_metadata    = pth_html_rel.fn_metadata(doc_matters.src.filename);
     hvst.harvest.path_html_scroll      = pth_html_rel.fn_scroll(doc_matters.src.filename);
     hvst.harvest.path_html_segtoc      = pth_html_rel.fn_seg(doc_matters.src.filename, "toc");
     hvst.harvest.path_abs_html_scroll  = pth_html_abs.fn_scroll(doc_matters.src.filename);
diff --git a/src/doc_reform/meta/metadoc_harvests_authors.d b/src/doc_reform/meta/metadoc_harvests_authors.d
index f733a80..19ed583 100644
--- a/src/doc_reform/meta/metadoc_harvests_authors.d
+++ b/src/doc_reform/meta/metadoc_harvests_authors.d
@@ -270,11 +270,9 @@ string theme_light_1 = format(q"┃
 <a name="up" id="up"></a>
 <a name="start" id="start"></a>
 <h1>Metadata Harvest - Authors (output organised by language &amp; filetype)</h1>
-<p>[<a href="../../index.html">&nbsp;HOME&nbsp;</a>] also see <a href="topics.html">Metadata Harvest - Topics</a></p>
+<p>[<a href="../../index.html">&nbsp;HOME&nbsp;</a>] [<a href="topics.html">&nbsp;Metadata&nbsp;Harvest&nbsp;-&nbsp;Topics&nbsp;</a>]</p>
 <p></p>
 <hr />
-<p class="tiny"><a href="../../en/manifest/authors.html">English</a>&nbsp;&nbsp;&nbsp;</p>
-<hr />
 <p><a href="#A">A</a>,&nbsp;<a href="#B">B</a>,&nbsp;<a href="#C">C</a>,&nbsp;<a href="#D">D</a>,&nbsp;<a href="#E">E</a>,&nbsp;<a href="#F">F</a>,&nbsp;<a href="#G">G</a>,&nbsp;<a href="#H">H</a>,&nbsp;<a href="#I">I</a>,&nbsp;<a href="#J">J</a>,&nbsp;<a href="#K">K</a>,&nbsp;<a href="#L">L</a>,&nbsp;<a href="#M">M</a>,&nbsp;<a href="#N">N</a>,&nbsp;<a href="#O">O</a>,&nbsp;<a href="#P">P</a>,&nbsp;<a href="#Q">Q</a>,&nbsp;<a href="#R">R</a>,&nbsp;<a href="#S">S</a>,&nbsp;<a href="#T">T</a>,&nbsp;<a href="#U">U</a>,&nbsp;<a href="#V">V</a>,&nbsp;<a href="#W">W</a>,&nbsp;<a href="#X">X</a>,&nbsp;<a href="#Y">Y</a>,&nbsp;<a href="#Z">Z</a>,&nbsp;
 ┃",
   _opt_action.css_theme_default ? theme_light_0 : theme_dark_0,
@@ -296,31 +294,34 @@ string theme_light_1 = format(q"┃
       ) {
         if (doc_harvest.author_surname_fn != _prev_auth) {
           _au[doc_harvest.author_surname_fn]
-          = format(q"┃<p class="author"><a name="%s" class="lev0">%s</a></p> <p class="publication">%s "<a href="%s">%s</a>" [%s]</p>┃",
+          = format(q"┃<p class="author"><a name="%s" class="lev0">%s</a></p> <p class="publication">%s "<a href="%s">%s</a>" [<a href="%s">&nbsp;%s&nbsp;</a>]</p>┃",
             doc_harvest.author_surname.translate([' ' : "_"]),
             doc_harvest.author_surname_fn,
             (doc_harvest.date_published.length > 0)
               ? doc_harvest.date_published : "",
             doc_harvest.path_html_segtoc,
             doc_harvest.title,
+            doc_harvest.path_html_metadata,
             doc_harvest.language,
           );
           _prev_auth = doc_harvest.author_surname_fn;
         } else {
           _au[doc_harvest.author_surname_fn]
-          ~= format(q"┃<p class="publication">%s "<a href="%s">%s</a>" [%s]</p>┃",
+          ~= format(q"┃<p class="publication">%s "<a href="%s">%s</a>" [<a href="%s">&nbsp;%s&nbsp;</a>]</p>┃",
             (doc_harvest.date_published.length > 0)
               ? doc_harvest.date_published : "",
             doc_harvest.path_html_segtoc,
             doc_harvest.title,
+            doc_harvest.path_html_metadata,
             doc_harvest.language,
           );
         }
-        _author_date_title ~= format(q"┃%s %s "%s" [%s]%s┃",
+        _author_date_title ~= format(q"┃%s %s "%s" [<a href="%s">&nbsp;%s&nbsp;</a>]%s┃",
           doc_harvest.author_surname_fn,
           (doc_harvest.date_published.length > 0)
             ? "(" ~ doc_harvest.date_published ~ ")" : "",
           doc_harvest.title,
+          doc_harvest.path_html_metadata,
           doc_harvest.language,
           (_opt_action.very_verbose) ? "\n  " ~ doc_harvest.path_abs_html_scroll : "",
         );
diff --git a/src/doc_reform/meta/metadoc_harvests_topics.d b/src/doc_reform/meta/metadoc_harvests_topics.d
index 82601fc..5e11b7e 100644
--- a/src/doc_reform/meta/metadoc_harvests_topics.d
+++ b/src/doc_reform/meta/metadoc_harvests_topics.d
@@ -311,12 +311,10 @@ string theme_light_1 = format(q"┃
 <a name="up" id="up"></a>
 <a name="start" id="start"></a>
 <h1>Metadata Harvest - Topics (output organised by language &amp; filetype)</h1>
-<p>[<a href="../../index.html">&nbsp;HOME&nbsp;</a>] also see <a href="authors.html">Metadata Harvest - Authors</a></p>
+<p>[<a href="../../index.html">&nbsp;HOME&nbsp;</a>] [<a href="authors.html">&nbsp;Metadata&nbsp;Harvest&nbsp;-&nbsp;Authors&nbsp;</a>]</p>
 <p><a href="#A">A</a>,&nbsp;<a href="#B">B</a>,&nbsp;<a href="#C">C</a>,&nbsp;<a href="#D">D</a>,&nbsp;<a href="#E">E</a>,&nbsp;<a href="#F">F</a>,&nbsp;<a href="#G">G</a>,&nbsp;<a href="#H">H</a>,&nbsp;<a href="#I">I</a>,&nbsp;<a href="#J">J</a>,&nbsp;<a href="#K">K</a>,&nbsp;<a href="#L">L</a>,&nbsp;<a href="#M">M</a>,&nbsp;<a href="#N">N</a>,&nbsp;<a href="#O">O</a>,&nbsp;<a href="#P">P</a>,&nbsp;<a href="#Q">Q</a>,&nbsp;<a href="#R">R</a>,&nbsp;<a href="#S">S</a>,&nbsp;<a href="#T">T</a>,&nbsp;<a href="#U">U</a>,&nbsp;<a href="#V">V</a>,&nbsp;<a href="#W">W</a>,&nbsp;<a href="#X">X</a>,&nbsp;<a href="#Y">Y</a>,&nbsp;<a href="#Z">Z</a>,&nbsp;
 <p></p>
 <hr />
-<p class="tiny"><a href="../../en/manifest/topics.html">English</a>&nbsp;&nbsp;&nbsp;</p>
-<hr />
 ┃",
   _opt_action.css_theme_default ? theme_light_0 : theme_dark_0,
   _opt_action.css_theme_default ? theme_light_1 : theme_dark_1,
@@ -359,10 +357,12 @@ string theme_light_1 = format(q"┃
                   );
                 }
               }
-              topics ~= format(q"┃<p class="work"><a href="%s">"%s"</a> -%s┃",
+              topics ~= format(q"┃<p class="work"><a href="%s">"%s"</a> - %s [<a href="%s">&nbsp;%s&nbsp;</a>]┃",
                 t_a_.path_html_segtoc,
                 t_a_.title,
                 _auth,
+                t_a_.path_html_metadata,
+                t_a_.language,
               ) ~ "\n";
               if (_opt_action.very_verbose) {
                 writeln("- ", t_a_.title, " - ", t_a_.author);
@@ -399,10 +399,12 @@ string theme_light_1 = format(q"┃
                       );
                     }
                   }
-                  topics ~= format(q"┃<p class="work"><a href="%s">%s</a> -%s┃",
+                  topics ~= format(q"┃<p class="work"><a href="%s">%s</a> - %s [<a href="%s">&nbsp;%s&nbsp;</a>]┃",
                     t_a_.path_html_segtoc,
                     t_a_.title,
                     _auth,
+                    t_a_.path_html_metadata,
+                    t_a_.language,
                   ) ~ "\n";
                   if (_opt_action.very_verbose) {
                     writeln("  - ", t_a_.title, " - ", t_a_.author);
@@ -440,10 +442,12 @@ string theme_light_1 = format(q"┃
                         );
                       }
                     }
-                    topics ~= format(q"┃<p class="work"><a href="%s">%s</a> -%s┃",
+                    topics ~= format(q"┃<p class="work"><a href="%s">%s</a> - %s [<a href="%s">&nbsp;%s&nbsp;</a>]┃",
                       t_a_.path_html_segtoc,
                       t_a_.title,
                       _auth,
+                      t_a_.path_html_metadata,
+                      t_a_.language,
                     ) ~ "\n";
                     if (_opt_action.very_verbose) {
                       writeln("    - ", t_a_.title, " - ", t_a_.author);
@@ -481,10 +485,12 @@ string theme_light_1 = format(q"┃
                           );
                         }
                       }
-                      topics ~= format(q"┃ <p class="work"><a href="%s">%s</a> -%s┃",
+                      topics ~= format(q"┃ <p class="work"><a href="%s">%s</a> - %s [<a href="%s">&nbsp;%s&nbsp;</a>]┃",
                         t_a_.path_html_segtoc,
                         t_a_.title,
                         _auth,
+                        t_a_.path_html_metadata,
+                        t_a_.language,
                       ) ~ "\n";
                       if (_opt_action.very_verbose) {
                         writeln("      - ", t_a_.title, " - ", t_a_.author);
-- 
cgit v1.2.3