-*- mode: org -*-
#+TITLE:       spine (doc_reform) abstraction summary and debugs
#+DESCRIPTION: documents - structuring, publishing in multiple formats & search
#+FILETAGS:    :spine:debugs:
#+AUTHOR:      Ralph Amissah
#+EMAIL:       [[mailto:ralph.amissah@gmail.com][ralph.amissah@gmail.com]]
#+COPYRIGHT:   Copyright (C) 2015 - 2021 Ralph Amissah
#+LANGUAGE:    en
#+STARTUP:     content hideblocks hidestars noindent entitiespretty
#+OPTIONS:     H:3 num:nil toc:t \n:nil @:t ::t |:t ^:nil _:nil -:t f:t *:t <:t
#+PROPERTY:    header-args  :exports code
#+PROPERTY:    header-args+ :noweb yes
#+PROPERTY:    header-args+ :eval no
#+PROPERTY:    header-args+ :results no
#+PROPERTY:    header-args+ :cache no
#+PROPERTY:    header-args+ :padline no

[[./spine.org][spine]]  [[./][org/]]
* abstraction debugs :module:spine:meta_doc_debugs:
** _module template_

#+BEGIN_SRC d :tangle "../src/doc_reform/meta/doc_debugs.d"
<<doc_header_including_copyright_and_license>>
/++
  output debugs
+/
module doc_reform.meta.doc_debugs;
template spineDebugs() {
  <<debug_imports>>
  auto spineDebugs(S,T)(
    const S  contents,
          T  doc_matters,
  ) {
    mixin spineRgxIn;
    mixin InternalMarkup;
    <<initialize>>
    <<meta_output_debugs>>
    debug(checkdoc) {
      if ((doc_matters.opt.action.debug_do)) {
        <<meta_output_debugs_summary>>
        <<meta_output_debugs_checkdoc>>
      }
    }
  }
}
#+END_SRC

** imports

#+NAME: debug_imports
#+BEGIN_SRC d
import
  doc_reform.meta.defaults,
  doc_reform.meta.rgx;
import
  std.algorithm,
  std.array,
  std.container,
  std.exception,
  std.json,
  std.stdio,
  std.file,
  std.path,
  std.range,
  std.regex,
  std.string,
  std.typecons,
  std.utf,
  std.conv : to;
#+END_SRC

** initialize :report:

#+NAME: initialize
#+BEGIN_SRC d
static auto rgx = RgxI();
auto markup = InlineMarkup();
string key;
#+END_SRC

** (parent) :parent:

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(parent) {
  writefln(
    "%s:%s",
    __FILE__,
    __LINE__,
  );
  foreach (key; doc_matters.has.keys_seq.seg) {
    foreach (obj; contents[key]) {
      if (obj.metainfo.is_of_part != "empty") {
        if (obj.metainfo.is_a == "heading") {
          writefln(
            "%s node: %s heading: %s %s",
            obj.object_number,
            obj.node,
            obj.heading_lev_markup,
            obj.text,
          );
        }
      }
    }
  }
}
#+END_SRC

** (dumpdoc) :objects:

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(dumpdoc) {
  writefln(
    "> %s:%s",
    __FILE__,
    __LINE__,
  );
}
#+END_SRC

** (segnames) :objects:

#+NAME: meta_output_debugs_checkdoc
#+BEGIN_SRC d
debug(checkdoc) {
  void out_segnames(S,T)(
    const S  contents,
          T  doc_matters,
  ) {
    foreach (key; doc_matters.has.keys_seq.seg) {
      if (contents[key].length > 1) {
        foreach (obj; contents[key]) {
          if (obj.heading_lev_markup == 4) {
            writeln(obj.ptr_html_segnames, ". (", doc_matters.has.segnames_lv4[obj.ptr_html_segnames], ") -> ",  obj.text);
          }
        }
      }
    }
  }
}
#+END_SRC

** shared output section arrange
*** out toc

#+NAME: meta_output_debugs_checkdoc
#+BEGIN_SRC d
debug(checkdoc) {
  void out_toc(S)(
    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.indent_hang);
        writefln(
          "%s%s",
          indent_spaces,
          obj.text
        );
      }
    }
  }
}
#+END_SRC

*** out endnotes :endnotes:

#+NAME: meta_output_debugs_checkdoc
#+BEGIN_SRC d
debug(checkdoc) {
  void out_endnotes(S)(
    const S  contents,
    string                   key,
  ) {
    if (contents[key].length > 1) {
      foreach (obj; contents[key]) {
        writefln(
          "[%s]\n%s",
          obj.metainfo.is_a,
          obj.text
        );
      }
    }
  }
}
#+END_SRC

*** out bookindex :bookindex:

#+NAME: meta_output_debugs_checkdoc
#+BEGIN_SRC d
debug(checkdoc) {
  void out_bookindex(S)(
    const S  contents,
    string                   key,
  ) {
    if (contents[key].length > 1) {
      foreach (obj; contents[key]) {
        writefln(
          "[%s][%s]\n%s",
          obj.object_number,
          obj.metainfo.is_a,
          obj.text
        );
      }
    }
  }
}
#+END_SRC

** sections
*** heading_section :heading:

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(section_head) {
  key="head";
  if (contents[key].length > 1) {
    foreach (obj; contents[key]) {
      writefln(
        "[%s][%s]\n%s",
        obj.object_number,
        obj.metainfo.is_a,
        obj.text
      );
    }
  }
}
#+END_SRC

*** toc_section (seg & scroll)
**** toc

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(section_toc) {
  key="toc";
  out_toc(contents, key);
}
#+END_SRC

**** toc seg

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(section_toc) {
  key="toc";
  out_toc(contents, key);
}
#+END_SRC

**** toc scroll

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(section_toc) {
  key="toc";
  out_toc(contents, key);
}
#+END_SRC

*** body_section :body:

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(section_body) {
  key="body";
  if (contents[key].length > 1) {
    foreach (obj; contents[key]) {
      writefln(
        "[%s][%s]\n%s",
        obj.object_number,
        obj.metainfo.is_a,
        obj.text
      );
    }
  }
}
#+END_SRC

*** dom structure :body:

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(toc_nav_dom) {
  enum DomTags { none, open, close, close_and_open, open_still, }
  foreach (sect; doc_matters.has.keys_seq.seg) {
    foreach (obj; contents[sect]) {
      if (obj.metainfo.is_a == "heading") {
        foreach_reverse (k; 0 .. 7) {
          switch (obj.dom_structure_markedup_tags_status[k]) with (DomTags) {
          case close :
            writeln(markup.indent_by_spaces_provided(k), "</", k, ">");
            break;
          case close_and_open :
            writeln(markup.indent_by_spaces_provided(k), "</", k, ">");
            writeln(markup.indent_by_spaces_provided(k),
              "<", k, ">", obj.text,
              " file: ", obj.segment_anchor_tag_html, ".xhtml#", obj.ocn);
            break;
          case open :
            writeln(markup.indent_by_spaces_provided(k),
              "<", k, ">", obj.text,
              " file: ", obj.segment_anchor_tag_html, ".xhtml#", obj.ocn);
            break;
          default :
            break;
          }
        }
      }
    }
  }
  writeln("--------------------");
  foreach (sect; doc_matters.has.keys_seq.seg) {
    foreach (obj; contents[sect]) {
      if (obj.metainfo.is_a == "heading") {
        foreach_reverse (k; 0 .. 7) {
          switch (obj.dom_structure_collapsed_tags_status[k]) with (DomTags) {
          case close :
            writeln(markup.indent_by_spaces_provided(k), "</", k, ">");
            break;
          case close_and_open :
            writeln(markup.indent_by_spaces_provided(k), "</", k, ">");
            writeln(markup.indent_by_spaces_provided(k),
              "<", k, ">", obj.text,
              " file: ", obj.segment_anchor_tag_html, ".xhtml#", obj.ocn);
            break;
          case open :
            writeln(markup.indent_by_spaces_provided(k),
              "<", k, ">", obj.text,
              " file: ", obj.segment_anchor_tag_html, ".xhtml#", obj.ocn);
            break;
          default :
            break;
          }
        }
      }
    }
  }
}
#+END_SRC

*** decendants

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(decendants) {
  foreach (sect; doc_matters.has.keys_seq.scroll) {
    foreach (obj; contents[sect]) {
      if (obj.metainfo.is_a == "heading") {
        writeln(obj.metainfo.ocn, " .. ", obj.metainfo.last_decendant_ocn);
      }
    }
  }
}
#+END_SRC

*** endnotes_section (seg & scroll) :endnotes:
**** endnotes

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(section_endnotes) {
  key="endnotes";
  out_endnotes(contents, key);
}
#+END_SRC

**** endnotes seg

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(section_endnotes_seg) {
  key="endnotes";
  out_endnotes(contents, key);
}
#+END_SRC

*** glossary_section :glossary:

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(section_glossary) {
  key="glossary";
  if (contents[key].length > 1) {
    foreach (obj; contents[key]) {
      writefln(
        "[%s][%s]\n%s",
        obj.object_number,
        obj.metainfo.is_a,
        obj.text
      );
    }
  }
}
#+END_SRC

*** bibliography_section (seg & scroll) :bibliography:

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(section_bibliography) {
  key="bibliography";
  if (contents[key].length > 1) {
    foreach (obj; contents[key]) {
      writefln(
        "[%s][%s]\n%s",
        obj.object_number,
        obj.metainfo.is_a,
        obj.text
      );
    }
  }
}
#+END_SRC

*** bookindex_section (seg & scroll) :bookindex:
**** bookindex

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(section_bookindex) {
  key="bookindex";
  out_bookindex(contents, key);
}
#+END_SRC

**** bookindex seg

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(section_bookindex) {
  key="bookindex";
  out_bookindex(contents, key);
}
#+END_SRC

**** bookindex scroll

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(section_bookindex_scroll) {
  key="bookindex_scroll";
  out_bookindex(contents, key);
}
#+END_SRC

*** section_blurb :blurb:

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(blurb_section) {
  key="blurb";
  if (contents[key].length > 1) {
    foreach (obj; contents[key]) {
      writefln(
        "[%s][%s]\n%s",
        obj.object_number,
        obj.metainfo.is_a,
        obj.text
      );
    }
  }
}
#+END_SRC

** (objects) :objects:

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(objects) {
  writefln(
    "> %s:%s",
    __FILE__,
    __LINE__,
  );
  foreach (obj; contents[key]) {
    if (obj.metainfo.is_of_part != "empty") {
      writefln(
        "* [%s][%s] %s",
        obj.object_number,
        obj.metainfo.is_a,
        obj.text
      );
    }
  }
}
#+END_SRC

** (headermakejson) :json:header:

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(headermakejson) {
  writefln(
    "%s\n%s\n%s",
    "document header, metadata & make instructions:",
    doc_matters.conf_make_meta.meta,
    ptr_head_main,
  );
  foreach (main_header; ptr_head_main) {
    switch (main_header) {
    case "make":
      foreach (sub_header; ptr_head_sub_make) {
        if (doc_matters.conf_make_meta.meta.title_full.to!string.length > 2) {
          writefln(
            "%s:%s: %s",
            main_header,
            sub_header,
            doc_matters.conf_make_meta.meta.title_full
          );
        }
      }
      break;
    default:
      break;
    }
  }
}
#+END_SRC

** (headermetadatajson) :json:header:

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(headermetadatajson) {
  writefln(
    "%s\n%s\n%s",
    "document header, metadata & make instructions:",
    doc_matters.conf_make_meta.meta,
    ptr_head_main,
  );
  foreach (main_header; ptr_head_main) {
    switch (main_header) {
    case "creator":
      foreach (sub_header; ptr_head_sub_creator) {
        if (doc_matters.conf_make_meta.meta.title_full.to!string.length > 2) {
          writefln(
            "%s:%s: %s",
            main_header,
            sub_header,
            doc_matters.conf_make_meta.meta.title_full,
          );
        }
      }
      break;
    case "title":
      foreach (sub_header; ptr_head_sub_title) {
        if (doc_matters.conf_make_meta.meta.title_full.to!string.length > 2) {
          writefln(
            "%s:%s: %s",
            main_header,
            sub_header,
            doc_matters.conf_make_meta.meta.title_full
          );
        }
      }
      break;
    case "rights":
      foreach (sub_header; ptr_head_sub_rights) {
        if (doc_matters.conf_make_meta.meta.title_full.to!string.length > 2) {
          writefln(
            "%s:%s: %s",
            main_header,
            sub_header,
            doc_matters.conf_make_meta.meta.title_full
          );
        }
      }
      break;
    case "date":
      foreach (sub_header; ptr_head_sub_date) {
        if (doc_matters.conf_make_meta.meta.title_full.to!string.length > 2) {
          writefln(
            "%s:%s: %s",
            main_header,
            sub_header,
            doc_matters.conf_make_meta.meta.title_full
          );
        }
      }
      break;
    case "original":
      foreach (sub_header; ptr_head_sub_original) {
        if (doc_matters.conf_make_meta.meta.title_full.to!string.length > 2) {
          writefln(
            "%s:%s: %s",
            main_header,
            sub_header,
            doc_matters.conf_make_meta.meta.title_full
          );
        }
      }
      break;
    case "classify":
      foreach (sub_header; ptr_head_sub_classify) {
        if (doc_matters.conf_make_meta.meta.title_full.to!string.length > 2) {
          writefln(
            "%s:%s: %s",
            main_header,
            sub_header,
            doc_matters.conf_make_meta.meta.title_full
          );
        }
      }
      break;
    case "identifier":
      foreach (sub_header; ptr_head_sub_identifier) {
        if (doc_matters.conf_make_meta.meta.title_full.to!string.length > 2) {
          writefln(
            "%s:%s: %s",
            main_header,
            sub_header,
            doc_matters.conf_make_meta.meta.title_full
          );
        }
      }
      break;
    case "notes":
      foreach (sub_header; ptr_head_sub_notes) {
        if (doc_matters.conf_make_meta.meta.title_full.to!string.length > 2) {
          writefln(
            "%s:%s: %s",
            main_header,
            sub_header,
            doc_matters.conf_make_meta.meta.title_full
          );
        }
      }
      break;
    case "publisher":
      foreach (sub_header; ptr_head_sub_publisher) {
        if (doc_matters.conf_make_meta.meta.title_full.to!string.length > 2) {
          writefln(
            "%s:%s: %s",
            main_header,
            sub_header,
            doc_matters.conf_make_meta.meta.title_full
          );
        }
      }
      break;
    default:
      break;
    }
  }
}
#+END_SRC

** anchor tags

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(anchor) {
  writefln(
    "> %s:%s",
    __FILE__,
    __LINE__,
  );
  foreach (k; doc_matters.has.keys_seq.seg) {
    foreach (obj; contents[k]) {
      if (obj.metainfo.is_a == "heading") {
        writefln(
          "%s~ [%s] %s %s",
          obj.marked_up_level,
          obj.object_number,
          obj.anchor_tags,
          obj.text
        );
      }
    }
  }
}
#+END_SRC

** (headings) :headings:

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(heading) {                         // heading
  foreach (k; doc_matters.has.keys_seq.seg) {
    foreach (o; contents[k]) {
      if (o.metainfo.is_a == "heading") {
        writefln(
          "%s* %s\n                (markup level: %s; collapsed level: %s)",
          replicate("  ", o.heading_lev_markup),
          strip(o.text),
          o.heading_lev_markup,
          o.heading_lev_collapsed,
        );
      }
    }
  }
}
#+END_SRC

** (summary) [+1] :summary:

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(headings) {
  writefln(
    "> %s:%s",
    __FILE__,
    __LINE__,
  );
  foreach (k; doc_matters.has.keys_seq.seg) {
    foreach (obj; contents[k]) {
      if (obj.metainfo.is_a == "heading") {
        writefln(
          "%s~ [%s] %s",
          obj.marked_up_level,
          obj.object_number,
          obj.text
        );
      }
    }
  }
}
#+END_SRC

#+NAME: meta_output_debugs
#+BEGIN_SRC d
debug(summary) {
  string[string] check = [
    "last_object_number" : "NA [debug \"checkdoc\" not run]",
  ];
}
#+END_SRC

*** compare number of object_number for known sisu markup output (checkdoc)

#+NAME: meta_output_debugs_summary
#+BEGIN_SRC d
debug(checkdoc) {
  if (auto mfn=match(doc_matters.src.filename, rgx.src_fn)) {
    if (doc_matters.opt.action.assertions) {
      switch (mfn.captures[2]) {
      // live manual:
      case "live-manual.ssm":
        assert(check["last_object_number"] ==
          "1019","last object_number should be: 1019 (check test, document is frequently updated)"); // ok
        break;
      // sisu_markup:
      case "sisu_markup.sst":
        assert(check["last_object_number"] ==
          "297","last object_number expected to be: 297 rather than " ~ check["last_object_number"]); // ok
        // assert(check["last_object_number"] == "297","last object_number expected to be: 297 rather than " ~ check["last_object_number"]);
        // notes for first divergance study sisu headings 247 250
        // sisu has issue with code that contains heading 1~ which results in no object_number! ??
        // sisu currently has incorrect last body object_number of 294!
        // bug in sisu? attend
        break;
      // sisu-markup-samples:
      case "accelerando.charles_stross.sst":
        assert(check["last_object_number"] ==
          "2861","last object_number expected to be: 2861 rather than " ~ check["last_object_number"]); // ok
        break;
      case "alices_adventures_in_wonderland.lewis_carroll.sst":
        assert(check["last_object_number"] ==
          "805","last object_number expected to be: 805 rather than " ~ check["last_object_number"]); // 808
        break;
      case "autonomy_markup0.sst":
        assert(check["last_object_number"] ==
          "77","last object_number expected to be: 77 rather than " ~ check["last_object_number"]); // ok endnotes
        // assert(check["last_object_number"] == "78","last object_number expected to be: 78 rather than " ~ check["last_object_number"]);
        break;
      case "content.cory_doctorow.sst":
        assert(check["last_object_number"] ==
          "953","last object_number expected to be: 953 rather than " ~ check["last_object_number"]); // 1007 way off, check object_number off switches
        // assert(check["last_object_number"] == "953","last object_number expected to be: 953 rather than " ~ check["last_object_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_object_number"] ==
          "905","last object_number expected to be: 905 rather than " ~ check["last_object_number"]); // 911
        break;
      case "down_and_out_in_the_magic_kingdom.cory_doctorow.sst":
        assert(check["last_object_number"] ==
          "1417","last object_number expected to be: 1417 rather than " ~ check["last_object_number"]); // 1455 check object_number off switches
        break;
      case "for_the_win.cory_doctorow.sst":
        assert(check["last_object_number"] ==
          "3510","last object_number expected to be: 3510 rather than " ~ check["last_object_number"]); // 3569 check object_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_object_number"] ==
          "1082","last object_number expected to be: 1082 rather than " ~ check["last_object_number"]); // check 1079 too few
        break;
      case "free_culture.lawrence_lessig.sst":
        assert(check["last_object_number"] ==
          "1330","last object_number expected to be: 1330 rather than " ~ check["last_object_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_object_number"] ==
          "1559","last object_number expected to be: 1559 rather than " ~ check["last_object_number"]); // 1560, check object_number off switches, has endnotes so 2 too many
        // assert(check["last_object_number"] == "1559","last object_number expected to be: 1559 rather than " ~ check["last_object_number"]);
        break;
      case "gpl2.fsf.sst":
        assert(check["last_object_number"] ==
          "65","last object_number expected to be: 65 rather than " ~ check["last_object_number"]); // ok endnotes? check
        // assert(check["last_object_number"] == "66","last object_number expected to be: 66 rather than " ~ check["last_object_number"]);
        break;
      case "gpl3.fsf.sst":
        assert(check["last_object_number"] ==
          "123","last object_number expected to be: 123 rather than " ~ check["last_object_number"]); // ok
        break;
      case "gullivers_travels.jonathan_swift.sst":
        assert(check["last_object_number"] ==
          "668","last object_number expected to be: 668 rather than " ~ check["last_object_number"]); // 674
        break;
      case "little_brother.cory_doctorow.sst":
        assert(check["last_object_number"] ==
          "3130","last object_number expected to be: 3130 rather than " ~ check["last_object_number"]); // 3204, check object_number off switches
        break;
      case "the_cathedral_and_the_bazaar.eric_s_raymond.sst":
        assert(check["last_object_number"] ==
          "258","last object_number expected to be: 258 rather than " ~ check["last_object_number"]); // ok
        break;
      case "the_public_domain.james_boyle.sst":
        assert(check["last_object_number"] ==
          "970","last object_number expected to be: 970 rather than " ~ check["last_object_number"]); // 978
        break;
      case "the_wealth_of_networks.yochai_benkler.sst": // endnotes, bookindex
        assert(check["last_object_number"] ==
          "829","last object_number expected to be: 829 rather than " ~ check["last_object_number"]); // ok
        // assert(check["last_object_number"] == "832","last object_number expected to be: 832 rather than " ~ check["last_object_number"]);
        // has endnotes and bookindex, issue with sisu.rb
        break;
      case "through_the_looking_glass.lewis_carroll.sst":
        assert(check["last_object_number"] ==
          "949","last object_number expected to be: 949 rather than " ~ check["last_object_number"]); // 955
        break;
      case "two_bits.christopher_kelty.sst": // endnotes, bookindex, biblio
        assert(check["last_object_number"] ==
          "1190","last object_number expected to be: 1190 rather than " ~ check["last_object_number"]); // 1191
        // assert(check["last_object_number"] == "1193","last object_number expected to be: 1193 rather than " ~ check["last_object_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_object_number"] ==
          "377","last object_number expected to be: 377 rather than " ~ check["last_object_number"]); // ok
        break;
      case "viral_spiral.david_bollier.sst": // endnotes, bookindex
        assert(check["last_object_number"] ==
          "1078","last object_number expected to be: 1078 rather than " ~ check["last_object_number"]); // 1100
        // fixed ERROR! range violation!
        // error in bookindex ... (ch7 ... building the cc machine, an extra semi colon)
        break;
      default:
        writeln(doc_matters.src.filename);
        break;
      }
    }
  }
}
#+END_SRC

* document header including copyright & license

#+NAME: doc_header_including_copyright_and_license
#+BEGIN_SRC txt
/+
- Name: Spine, Doc Reform [a part of]
  - Description: documents, structuring, processing, publishing, search
    - static content generator

  - Author: Ralph Amissah
    [ralph.amissah@gmail.com]

  - Copyright: (C) 2015 - 2021 Ralph Amissah, All Rights
    Reserved.

  - License: AGPL 3 or later:

    Spine (SiSU), a framework for document structuring, publishing and
    search

    Copyright (C) Ralph Amissah

    This program is free software: you can redistribute it and/or modify it
    under the terms of the GNU AFERO General Public License as published by the
    Free Software Foundation, either version 3 of the License, or (at your
    option) any later version.

    This program is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
    more details.

    You should have received a copy of the GNU General Public License along with
    this program. If not, see [https://www.gnu.org/licenses/].

    If you have Internet connection, the latest version of the AGPL should be
    available at these locations:
    [https://www.fsf.org/licensing/licenses/agpl.html]
    [https://www.gnu.org/licenses/agpl.html]

  - Spine (by Doc Reform, related to SiSU) uses standard:
    - docReform markup syntax
      - standard SiSU markup syntax with modified headers and minor modifications
    - docReform object numbering
      - standard SiSU object citation numbering & system

  - Hompages:
    [https://www.doc_reform.org]
    [https://www.sisudoc.org]

  - Git
    [https://git.sisudoc.org/projects/?p=software/spine.git;a=summary]

+/
#+END_SRC

* __END__