-*- mode: org -*- #+TITLE: metadata (multidocument) harvests #+DESCRIPTION: documents - structuring, various output representations & search #+FILETAGS: :doc_reform:hub: #+AUTHOR: Ralph Amissah #+EMAIL: [[mailto:ralph.amissah@gmail.com][ralph.amissah@gmail.com]] #+COPYRIGHT: Copyright (C) 2015 - 2019 Ralph Amissah #+LANGUAGE: en #+STARTUP: indent content hideblocks hidestars #+OPTIONS: H:3 num:nil toc:t \n:nil @:t ::t |:t ^:nil _:nil -:t f:t *:t <:t #+OPTIONS: TeX:t LaTeX:t skip:nil d:nil todo:t pri:nil tags:not-in-toc #+OPTIONS: author:nil email:nil creator:nil timestamp:nil #+PROPERTY: header-args :results silent :padline no :exports code :cache no :noweb yes #+EXPORT_SELECT_TAGS: export #+EXPORT_EXCLUDE_TAGS: noexport #+TAGS: assert(a) class(c) debug(d) mixin(m) doc_reform(s) tangle(T) template(t) WEB(W) noexport(n) * document harvest _summary_ :module:doc_reform:metadoc_show_summary: ** 0. module template metadoc harvest #+BEGIN_SRC d :tangle "../src/doc_reform/meta/metadoc_harvest.d" module doc_reform.meta.metadoc_harvest; template DocReformMetaDocHarvest() { auto DocReformMetaDocHarvest(T,H)( T doc_matters, H hvst, ) { <<metadoc_harvest_imports>> mixin InternalMarkup; <<metadoc_harvest_initialize>> <<meta_metadoc_harvest>> } } #+END_SRC ** init *** imports #+name: metadoc_harvest_imports #+BEGIN_SRC d import doc_reform.meta.defaults, doc_reform.meta.rgx; import std.array, std.exception, std.regex, std.stdio, std.string, std.traits, std.typecons, std.uni, std.utf, std.conv : to; #+END_SRC *** initialize :report: #+name: metadoc_harvest_initialize #+BEGIN_SRC d auto markup = InlineMarkup(); #+END_SRC ** harvest summary #+name: meta_metadoc_harvest_summary #+BEGIN_SRC d auto min_repeat_number = 66; auto char_repeat_number = (doc_matters.conf_make_meta.meta.title_full.length + doc_matters.conf_make_meta.meta.creator_author.length + 4); char_repeat_number = (char_repeat_number > min_repeat_number) ? char_repeat_number : min_repeat_number; writefln( "%s\n\"%s\", %s\n%s\n%s\n%s", markup.repeat_character_by_number_provided("-", char_repeat_number), doc_matters.conf_make_meta.meta.title_full, doc_matters.conf_make_meta.meta.creator_author, doc_matters.src.filename, doc_matters.conf_make_meta.meta.classify_topic_register_arr, markup.repeat_character_by_number_provided("-", char_repeat_number), ); #+END_SRC ** return harvest #+name: meta_metadoc_harvest #+BEGIN_SRC d import doc_reform.output.paths_output; auto pth_html_abs = DocReformPathsHTML!()(doc_matters.output_path, doc_matters.src.language); auto pth_html_rel = DocReformDocRootTreeHTML!()(doc_matters.src.language); hvst.harvest.title = doc_matters.conf_make_meta.meta.title_full; hvst.harvest.author = doc_matters.conf_make_meta.meta.creator_author; hvst.harvest.author_surname = doc_matters.conf_make_meta.meta.creator_author_surname; hvst.harvest.author_surname_fn = doc_matters.conf_make_meta.meta.creator_author_surname_fn; hvst.harvest.author_arr = doc_matters.conf_make_meta.meta.creator_author_arr; hvst.harvest.language_original = doc_matters.conf_make_meta.meta.original_language; hvst.harvest.language = doc_matters.src.language; 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_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); hvst.harvest.path_abs_html_segtoc = pth_html_abs.fn_seg(doc_matters.src.filename, "toc"); return hvst.harvest; #+END_SRC ** 0. module template metadoc harvest topics *** 0. module template metadoc harvest topics template #+BEGIN_SRC d :tangle "../src/doc_reform/meta/metadoc_harvests_topics.d" module doc_reform.meta.metadoc_harvests_topics; import std.algorithm, std.array, std.exception, std.regex, std.stdio, std.string, std.conv : to; import doc_reform.meta.defaults, doc_reform.meta.rgx; mixin DocReformHarvest; mixin InternalMarkup; mixin DocReformRgxInit; template DocReformMetaDocHarvestsTopics() { auto mkup = InlineMarkup(); void DocReformMetaDocHarvestsTopics(H,O)( H hvst, O _opt_action, ) { <<harvested_topics>> <<harvested_html_themes>> <<harvested_topics_html_head_1>> <<harvested_html_head>> <<harvested_topics_html_head_2>> <<harvested_topics_html_head_theme>> <<harvested_topics_html>> topics <<harvested_html_bottom>> <<harvested_topics_html_write>> } } #+END_SRC *** order topic register #+NAME: harvested_topics #+BEGIN_SRC d auto min_repeat_number = 42; string[] _document_topic_register; string[] _topic_register; string[] _sub_topic_register; string[] topics = []; string _auth = ""; foreach(k, doc_harvest; hvst.harvests) { _topic_register = []; foreach(topic; doc_harvest.topic_register_arr.sort) { _sub_topic_register = []; string _spaces; string[] subject_tree = topic.split(mkup.sep); switch (subject_tree.length) { case 1: hvst.subject_trees[subject_tree[0]]["_a"]["_a"]["_a"] ~= doc_harvest; break; case 2: hvst.subject_trees[subject_tree[0]][subject_tree[1]]["_a"]["_a"] ~= doc_harvest; break; case 3: hvst.subject_trees[subject_tree[0]][subject_tree[1]][subject_tree[2]]["_a"] ~= doc_harvest; break; case 4: hvst.subject_trees[subject_tree[0]][subject_tree[1]][subject_tree[2]][subject_tree[3]] ~= doc_harvest; break; default: break; } _topic_register ~= _sub_topic_register.join("\n"); } auto char_repeat_number = (doc_harvest.title.length + doc_harvest.author.length + 16); char_repeat_number = (char_repeat_number > min_repeat_number) ? char_repeat_number : min_repeat_number; _document_topic_register ~= format( "\"%s\", %s%s\n%s", doc_harvest.title, doc_harvest.author, (doc_harvest.date_published.length > 0) ? " (" ~ doc_harvest.date_published ~ ")" : "", _topic_register.sort!("toUpper(a) < toUpper(b)", SwapStrategy.unstable).release.join("\n"), ); } #+END_SRC *** harvested topics html head #+NAME: harvested_topics_html_head_1 #+BEGIN_SRC d topics ~= format(q"┃<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Metadata Harvest - Topics</title> #+END_SRC *** harvested topics html head #+NAME: harvested_topics_html_head_2 #+BEGIN_SRC d </head> <body lang="en" xml:lang="en"> <a name="top" id="top"></a> <a name="up" id="up"></a> <a name="start" id="start"></a> <h1>Metadata Harvest - Topics (output organised by language & filetype)</h1> <p>[<a href="../../index.html"> HOME </a>] also see <a href="authors.html">Metadata Harvest - Authors</a></p> <p><a href="#A">A</a>, <a href="#B">B</a>, <a href="#C">C</a>, <a href="#D">D</a>, <a href="#E">E</a>, <a href="#F">F</a>, <a href="#G">G</a>, <a href="#H">H</a>, <a href="#I">I</a>, <a href="#J">J</a>, <a href="#K">K</a>, <a href="#L">L</a>, <a href="#M">M</a>, <a href="#N">N</a>, <a href="#O">O</a>, <a href="#P">P</a>, <a href="#Q">Q</a>, <a href="#R">R</a>, <a href="#S">S</a>, <a href="#T">T</a>, <a href="#U">U</a>, <a href="#V">V</a>, <a href="#W">W</a>, <a href="#X">X</a>, <a href="#Y">Y</a>, <a href="#Z">Z</a>, <p></p> <hr /> <p class="tiny"><a href="../../en/manifest/topics.html">English</a> </p> <hr /> #+END_SRC *** harvested topics html head theme insert #+NAME: harvested_topics_html_head_theme #+BEGIN_SRC d ┃", _opt_action.css_theme_default ? theme_light_0 : theme_dark_0, _opt_action.css_theme_default ? theme_light_1 : theme_dark_1, ) ~ "\n"; #+END_SRC *** harvested topics html #+NAME: harvested_topics_html #+BEGIN_SRC d char _prev_k = "_".to!char; int _kn; foreach(k0; hvst.subject_trees.keys .sort!("toUpper(a) < toUpper(b)", SwapStrategy.unstable) ) { if (k0.toUpper.to!(char[])[0] != _prev_k) { topics ~= format(q"┃<p class="letter"><a name="%s">%s</a></p><p class="book_index_lev1"><a name="a"></a></p>┃", k0.toUpper.to!(char[])[0], k0.toUpper.to!(char[])[0], ); _prev_k = k0.toUpper.to!(char[])[0]; } if (k0 != "_a") { topics ~= format(q"┃<p class="lev0"><a name="%s">%s</a></p>┃", k0, k0,) ~ "\n"; if (_opt_action.very_verbose) { writeln("", k0); } if ("_a" in hvst.subject_trees[k0]) { foreach (t_a_; hvst.subject_trees[k0]["_a"]["_a"]["_a"] .multiSort!("toUpper(a.title) < toUpper(b.title)", "a.author < b.author", SwapStrategy.unstable) ) { _auth = []; if (t_a_.author_arr.length < 2) { _auth = format(q"┃ <a href="authors.html#%s">%s</a>┃", t_a_.author_surname, t_a_.author, ); } else { foreach (a; t_a_.author_arr) { _auth ~= format(q"┃ <a href="authors.html#%s">%s</a>,┃", t_a_.author_surname, a, ); } } topics ~= format(q"┃<p class="work"><a href="%s">"%s"</a> -%s┃", t_a_.path_html_segtoc, t_a_.title, _auth, ) ~ "\n"; if (_opt_action.very_verbose) { writeln("- ", t_a_.title, " - ", t_a_.author); } } } foreach(k1; hvst.subject_trees[k0].keys .sort!("toUpper(a) < toUpper(b)", SwapStrategy.unstable) ) { if (k1 != "_a") { topics ~= format(q"┃<p class="lev1"><a name="%s">%s</a></p>┃", k1, k1,) ~ "\n"; if (_opt_action.very_verbose) { writeln(" ", k1); } if ("_a" in hvst.subject_trees[k0][k1]) { foreach (t_a_; hvst.subject_trees[k0][k1]["_a"]["_a"] .multiSort!("toUpper(a.title) < toUpper(b.title)", "a.author < b.author", SwapStrategy.unstable) ) { _auth = []; if (t_a_.author_arr.length < 2) { _auth = format(q"┃ <a href="authors.html#%s">%s</a>┃", t_a_.author_surname, t_a_.author, ); } else { foreach (a; t_a_.author_arr) { _auth ~= format(q"┃ <a href="authors.html#%s">%s</a>,┃", t_a_.author_surname, a, ); } } topics ~= format(q"┃<p class="work"><a href="%s">%s</a> -%s┃", t_a_.path_html_segtoc, t_a_.title, _auth, ) ~ "\n"; if (_opt_action.very_verbose) { writeln(" - ", t_a_.title, " - ", t_a_.author); } } } } foreach(k2; hvst.subject_trees[k0][k1].keys .sort!("toUpper(a) < toUpper(b)", SwapStrategy.unstable) ) { if (k2 != "_a") { topics ~= format(q"┃<p class="lev2"><a name="%s">%s</a></p>┃", k2, k2,) ~ "\n"; if (_opt_action.very_verbose) { writeln(" ", k2); } if ("_a" in hvst.subject_trees[k0][k1][k2]) { foreach (t_a_; hvst.subject_trees[k0][k1][k2]["_a"] .multiSort!("toUpper(a.title) < toUpper(b.title)", "a.author < b.author", SwapStrategy.unstable) ) { _auth = []; if (t_a_.author_arr.length < 2) { _auth = format(q"┃ <a href="authors.html#%s">%s</a>┃", t_a_.author_surname, t_a_.author, ); } else { foreach (a; t_a_.author_arr) { _auth ~= format(q"┃ <a href="authors.html#%s">%s</a>,┃", t_a_.author_surname, a, ); } } topics ~= format(q"┃<p class="work"><a href="%s">%s</a> -%s┃", t_a_.path_html_segtoc, t_a_.title, _auth, ) ~ "\n"; if (_opt_action.very_verbose) { writeln(" - ", t_a_.title, " - ", t_a_.author); } } } } foreach(k3; hvst.subject_trees[k0][k1][k2].keys .sort!("toUpper(a) < toUpper(b)", SwapStrategy.unstable) ) { if (k3 != "_a") { topics ~= format(q"┃<p class="lev3"><a name="%s">%s</a></p>┃", k3, k3,) ~ "\n"; if (_opt_action.very_verbose) { writeln(" ", k3); } { foreach (t_a_; hvst.subject_trees[k0][k1][k2][k3] .multiSort!("toUpper(a.title) < toUpper(b.title)", "a.author < b.author", SwapStrategy.unstable) ) { _auth = []; if (t_a_.author_arr.length < 2) { _auth = format(q"┃<a href="authors.html#%s">%s</a>┃", t_a_.author_surname, t_a_.author, ); } else { foreach (a; t_a_.author_arr) { _auth ~= format(q"┃ <a href="authors.html#%s">%s</a>,┃", t_a_.author_surname, a, ); } } topics ~= format(q"┃ <p class="work"><a href="%s">%s</a> -%s┃", t_a_.path_html_segtoc, t_a_.title, _auth, ) ~ "\n"; if (_opt_action.very_verbose) { writeln(" - ", t_a_.title, " - ", t_a_.author); } } } } } } } } } #+END_SRC *** harvested topics write #+NAME: harvested_topics_html_write #+BEGIN_SRC d import doc_reform.output.paths_output; auto out_pth = DocReformPathsHTML!()(_opt_action.output_dir_set, ""); try { auto f = File(out_pth.harvest("topics.html"), "w"); foreach (o; topics) { f.writeln(o); } } catch (ErrnoException ex) { // Handle error } #+END_SRC ** 0. module template metadoc harvests authors *** 0. module template metadoc harvest authors #+BEGIN_SRC d :tangle "../src/doc_reform/meta/metadoc_harvests_authors.d" module doc_reform.meta.metadoc_harvests_authors; import std.algorithm, std.array, std.exception, std.regex, std.stdio, std.string, std.conv : to; import doc_reform.meta.defaults, doc_reform.meta.rgx; mixin DocReformHarvest; mixin InternalMarkup; mixin DocReformRgxInit; template DocReformMetaDocHarvestsAuthors() { auto mkup = InlineMarkup(); void DocReformMetaDocHarvestsAuthors(H,O)( H harvests, O _opt_action, ) { <<harvested_html_themes>> <<harvested_authors_html_head_1>> <<harvested_html_head>> <<harvested_authors_html_head_2>> <<harvested_authors_html_head_theme>> authors <<harvested_html_bottom>> <<harvested_authors_html_write>> } } #+END_SRC *** harvested authors html head #+NAME: harvested_authors_html_head_1 #+BEGIN_SRC d string[] authors = []; authors ~= format(q"┃ <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Metadata Harvest - Authors</title> #+END_SRC *** harvested authors html head #+NAME: harvested_authors_html_head_2 #+BEGIN_SRC d </head> <body lang="en" xml:lang="en"> <a name="top" id="top"></a> <a name="up" id="up"></a> <a name="start" id="start"></a> <h1>Metadata Harvest - Authors (output organised by language & filetype)</h1> <p>[<a href="../../index.html"> HOME </a>] also see <a href="topics.html">Metadata Harvest - Topics</a></p> <p></p> <hr /> <p class="tiny"><a href="../../en/manifest/authors.html">English</a> </p> <hr /> <p><a href="#A">A</a>, <a href="#B">B</a>, <a href="#C">C</a>, <a href="#D">D</a>, <a href="#E">E</a>, <a href="#F">F</a>, <a href="#G">G</a>, <a href="#H">H</a>, <a href="#I">I</a>, <a href="#J">J</a>, <a href="#K">K</a>, <a href="#L">L</a>, <a href="#M">M</a>, <a href="#N">N</a>, <a href="#O">O</a>, <a href="#P">P</a>, <a href="#Q">Q</a>, <a href="#R">R</a>, <a href="#S">S</a>, <a href="#T">T</a>, <a href="#U">U</a>, <a href="#V">V</a>, <a href="#W">W</a>, <a href="#X">X</a>, <a href="#Y">Y</a>, <a href="#Z">Z</a>, #+END_SRC *** harvested authors html theme inserts #+NAME: harvested_authors_html_head_theme #+BEGIN_SRC d ┃", _opt_action.css_theme_default ? theme_light_0 : theme_dark_0, _opt_action.css_theme_default ? theme_light_1 : theme_dark_1, ) ~ "\n"; string[string] _au; string[] _auth_date_title; string[] _author_date_title; string _prev_auth = ""; char _prev_k = "_".to!char; foreach(doc_harvest; harvests .multiSort!( "toUpper(a.author_surname_fn) < toUpper(b.author_surname_fn)", "a.date_published < b.date_published", "a.title < b.title", SwapStrategy.unstable ) ) { if (doc_harvest.author_surname_fn != _prev_auth) { _au[doc_harvest.author_surname_fn] = format(q"┃<p class="author"><a name="%s">%s</a></p> <p class="publication">%s "<a href="%s">%s</a>" [%s]</p>┃", doc_harvest.author_surname, 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.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>┃", (doc_harvest.date_published.length > 0) ? doc_harvest.date_published : "", doc_harvest.path_html_segtoc, doc_harvest.title, doc_harvest.language, ); } _author_date_title ~= format(q"┃%s %s "%s" [%s]%s┃", doc_harvest.author_surname_fn, (doc_harvest.date_published.length > 0) ? "(" ~ doc_harvest.date_published ~ ")" : "", doc_harvest.title, doc_harvest.language, (_opt_action.very_verbose) ? "\n " ~ doc_harvest.path_abs_html_scroll : "", ); } foreach (k; _au.keys.sort) { if (k.toUpper.to!(char[])[0] != _prev_k) { authors ~= format(q"┃<p class="letter"><a name="%s">%s</a></p><p class="book_index_lev1"><a name="a"></a></p>┃", k.toUpper.to!(char[])[0], k.toUpper.to!(char[])[0], ); _prev_k = k.toUpper.to!(char[])[0]; } authors ~= _au[k]; } #+END_SRC *** harvested authors write #+NAME: harvested_authors_html_write #+BEGIN_SRC d import doc_reform.output.paths_output; auto out_pth = DocReformPathsHTML!()(_opt_action.output_dir_set, ""); try { auto f = File(out_pth.harvest("authors.html"), "w"); foreach (o; authors) { f.writeln(o); } } catch (ErrnoException ex) { // Handle error } if (_opt_action.verbose || _opt_action.very_verbose ) { foreach(_adt; _author_date_title.sort) { writeln(_adt); } } #+END_SRC ** harvested authors & topics shared html *** themes **** head #+NAME: harvested_html_themes #+BEGIN_SRC d 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; } ┃"); #+END_SRC **** levels #+NAME: harvested_html_themes #+BEGIN_SRC d string theme_dark_1 = format(q"┃ h1 { color : #FFFFFF; background : #000000; } p.letter { color : #FFFFFF; background : #333333; } p.lev0 { color : #FFFFFF; background : #000000; } p.lev1 { color : #FFFFFF; background : #333333; } p.lev2 { background : #555555; } p.lev3 { background : #777777; } p.lev4 { background : #AAAAAA; } p.lev5 { } ┃"); string theme_light_1 = format(q"┃ h1 { color : #FFFFFF; background : #000088; } p.letter { color : #FFFFFF; background : #880000; } p.lev0 { color : #FFFFFF; background : #000000; } p.lev1 { color : #FFFFFF; background : #444444; } p.lev2 { background : #888888; } p.lev3 { background : #BBBBBB; } p.lev4 { background : #EEEEEE; } p.lev5 { } ┃"); #+END_SRC *** harvested html head #+NAME: harvested_html_head #+BEGIN_SRC d <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="doc_reform" /> <link rel="generator" href="http://sisudoc.org" /> <link href="../../_sisu/css/harvest.css" rel="stylesheet"> <style TYPE="text/css"> /* DocReform 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" /> #+END_SRC *** harvested html bottom #+NAME: harvested_html_bottom #+BEGIN_SRC d ~= format(q"┃ <hr /> <a name="bottom" id="bottom"></a> <a name="down" id="down"></a> <a name="end" id="end"></a> <a name="finish" id="finish"></a> <a name="stop" id="stop"></a> <a name="credits"></a> </body> </html> ┃") ~ "\n"; #+END_SRC