From 90051a7ea55acb043434b1c2483b878d602246ba Mon Sep 17 00:00:00 2001
From: Ralph Amissah <ralph.amissah@gmail.com>
Date: Fri, 2 Apr 2021 19:37:00 -0400
Subject: org mode (ruby code within)

---
 org/abstraction.org  | 7291 ++++++++++++++++++++++++++++++++++++++++++
 org/cgi.org          | 1459 +++++++++
 org/config.org       |  310 ++
 org/css.org          | 3508 ++++++++++++++++++++
 org/db.org           | 4808 ++++++++++++++++++++++++++++
 org/digests.org      |  330 ++
 org/env.org          | 8610 ++++++++++++++++++++++++++++++++++++++++++++++++++
 org/harvest.org      | 1454 +++++++++
 org/html.org         | 5971 ++++++++++++++++++++++++++++++++++
 org/hub.org          | 3163 +++++++++++++++++++
 org/i18n.org         | 2453 ++++++++++++++
 org/json.org         | 1620 ++++++++++
 org/manpage.org      |  436 +++
 org/misc.org         | 4107 ++++++++++++++++++++++++
 org/object_munge.org |  331 ++
 org/param.org        | 2363 ++++++++++++++
 org/shared.org       | 2297 ++++++++++++++
 org/sisu.org         |  128 +
 org/src.org          | 3437 ++++++++++++++++++++
 org/sst.org          | 1713 ++++++++++
 org/texinfo.org      |  946 ++++++
 org/texpdf.org       | 2969 +++++++++++++++++
 org/txt.org          | 3205 +++++++++++++++++++
 org/utils.org        |  857 +++++
 org/xhtml.org        | 5080 +++++++++++++++++++++++++++++
 org/xml.org          | 5583 ++++++++++++++++++++++++++++++++
 26 files changed, 74429 insertions(+)
 create mode 100644 org/abstraction.org
 create mode 100644 org/cgi.org
 create mode 100644 org/config.org
 create mode 100644 org/css.org
 create mode 100644 org/db.org
 create mode 100644 org/digests.org
 create mode 100644 org/env.org
 create mode 100644 org/harvest.org
 create mode 100644 org/html.org
 create mode 100644 org/hub.org
 create mode 100644 org/i18n.org
 create mode 100644 org/json.org
 create mode 100644 org/manpage.org
 create mode 100644 org/misc.org
 create mode 100644 org/object_munge.org
 create mode 100644 org/param.org
 create mode 100644 org/shared.org
 create mode 100644 org/sisu.org
 create mode 100644 org/src.org
 create mode 100644 org/sst.org
 create mode 100644 org/texinfo.org
 create mode 100644 org/texpdf.org
 create mode 100644 org/txt.org
 create mode 100644 org/utils.org
 create mode 100644 org/xhtml.org
 create mode 100644 org/xml.org

(limited to 'org')

diff --git a/org/abstraction.org b/org/abstraction.org
new file mode 100644
index 00000000..103c9218
--- /dev/null
+++ b/org/abstraction.org
@@ -0,0 +1,7291 @@
+-*- mode: org -*-
+#+TITLE:       sisu abstraction
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:abstraction:
+#+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
+
+* ao.rb
+** ao.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/ao.rb"
+# <<sisu_document_header>>
+module SiSU_AO
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'dp'                                 # dp.rb
+    include SiSU_Param
+  require_relative 'ao_doc_objects'                     # ao_doc_objects.rb
+  require_relative 'ao_syntax'                          # ao_syntax.rb
+    include SiSU_AO_Syntax
+  require_relative 'ao_doc_str'                         # ao_doc_str.rb
+  require_relative 'ao_appendices'                      # ao_appendices.rb
+  require_relative 'ao_idx'                             # ao_idx.rb
+  require_relative 'ao_numbering'                       # ao_numbering.rb
+  require_relative 'ao_hash_digest'                     # ao_hash_digest.rb
+  require_relative 'ao_endnotes'                        # ao_endnotes.rb
+  require_relative 'ao_images'                          # ao_images.rb
+  require_relative 'ao_metadata'                        # ao_metadata.rb
+  require_relative 'ao_character_check'                 # ao_character_check.rb
+  require_relative 'ao_misc_arrange'                    # ao_misc_arrange.rb
+  require_relative 'ao_expand_insertions'               # ao_expand_insertions.rb
+  require_relative 'ao_persist'                         # ao_persist.rb
+  require_relative 'prog_text_translation'              # prog_text_translation.rb
+  require_relative 'shared_sem'                         # shared_sem.rb
+  class Instantiate < SiSU_Param::Parameters::Instructions
+    def initialize
+      @@flag_vocab=0
+      @@line_mode=''
+    end
+  end
+  class Source <Instantiate
+    def initialize(opt,fnx=nil,process=:complete)
+      @opt,@fnx,@process=opt,fnx,process
+      @per ||=SiSU_AO_Persist::Persist.new.persist_init
+      @per.fns ||=opt.fns
+      fn_use=if fnx \
+      and fnx =~/\.ss[tmi]$/
+        fnx
+      elsif opt.fns =~/\.ssm$/
+        opt.fns + '.sst'
+      else
+        opt.fns
+      end
+      @make_fns=SiSU_Env::InfoFile.new(fn_use)
+      @fnm=@make_fns.marshal.ao_metadata
+      @fnc=@make_fns.marshal.ao_content
+      @idx_sst=@make_fns.marshal.ao_idx_sst_rel_html_seg
+      @idx_raw=@make_fns.marshal.ao_idx_sst_rel
+      @idx_html=@make_fns.marshal.ao_idx_html
+      @idx_xhtml=@make_fns.marshal.ao_idx_xhtml
+      @map_nametags=@make_fns.marshal.ao_map_nametags
+      @map_ocn_htmlseg=@make_fns.marshal.ao_map_ocn_htmlseg
+      @env=SiSU_Env::InfoEnv.new
+    end
+    def read                                                                   #creates ao
+      begin
+        @per=SiSU_AO_Persist::Persist.new
+        @per.ao_arr=[]
+        @per.fns=(@fnx && @fnx =~/\.ss[tmi]$/) \
+        ? @fnx
+        : @opt.fns
+        create_ao
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections,@per.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        SiSU_AO_Persist::Persist.new.persist_init
+        SiSU_AO::Instantiate.new
+      end
+    end
+    def get                                                                    #reads ao, unless does not exist then creates first
+      begin
+        ao=[]
+        unless @per.fns==@opt.fns \
+        or @per.fns==@fnx
+          @per.fns=(@fnx && @fnx =~/\.ss[tmi]$/) \
+          ? @fnx
+          : @opt.fns
+          @per.ao_arr=[]
+        end
+        ao=(@per.ao_arr.empty?) \
+        ? read_fnc
+        : @per.ao_arr.dup
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        SiSU_AO::Instantiate.new
+      end
+    end
+    def get_idx_sst                                                            #reads ao idx.sst, #unless does not exist then creates first
+      begin
+        ao=[]
+        unless @per.fns==@opt.fns \
+        or @per.fns==@fnx
+          @per.fns=(@fnx && @fnx =~/\.ss[tmi]$/) \
+          ? @fnx
+          : @opt.fns
+          @per.idx_arr_sst=[]
+        end
+        ao=(@per.idx_arr_sst.empty?) \
+        ? read_idx_sst
+        : @per.idx_arr_sst.dup #check
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        SiSU_AO::Instantiate.new
+      end
+    end
+    def get_idx_raw
+      begin
+        ao=[]
+        unless @per.fns==@opt.fns \
+        or @per.fns==@fnx
+          @per.fns=(@fnx && @fnx =~/\.ss[tmi]$/) \
+          ? @fnx
+          : @opt.fns
+          @per.idx_arr_tex=[]
+        end
+        ao=(@per.idx_arr_tex.empty?) \
+        ? read_idx_raw
+        : @per.idx_arr_tex.dup #check
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        SiSU_AO::Instantiate.new
+      end
+    end
+    def get_idx_html                                                           #reads ao idx.html, #unless does not exist then creates first
+      begin
+        ao=[]
+        unless @per.fns==@opt.fns \
+        or @per.fns==@fnx
+          @per.fns=(@fnx && @fnx =~/\.ss[tmi]$/) \
+          ? @fnx
+          : @opt.fns
+          @per.idx_arr_html=[]
+        end
+        ao=(@per.idx_arr_html.empty?) \
+        ? read_idx_html
+        : @per.idx_arr_html.dup
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        SiSU_AO::Instantiate.new
+      end
+    end
+    def get_idx_xhtml                                                          #reads ao idx.xhtml, #unless does not exist then creates first
+      begin
+        ao=[]
+        unless @per.fns==@opt.fns \
+        or @per.fns==@fnx
+          @per.fns=(@fnx && @fnx =~/\.ss[tmi]$/) \
+          ? @fnx
+          : @opt.fns
+          @per.idx_arr_xhtml=[] #...
+        end
+        ao=(@per.idx_arr_xhtml.empty?) \
+        ? read_idx_xhtml
+        : @per.idx_arr_xhtml.dup
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        SiSU_AO::Instantiate.new
+      end
+    end
+    def get_map_nametags                                                       #reads ao map.nametags, #unless does not exist then creates first
+      begin
+        ao=[]
+        unless @per.fns==@opt.fns \
+        or @per.fns==@fnx
+          @per.fns=(@fnx && @fnx =~/\.ss[tmi]$/) \
+          ? @fnx
+          : @opt.fns
+          @per.map_arr_nametags=[]
+        end
+        ao=(@per.map_arr_nametags.empty?) \
+        ? read_map_nametags
+        : @per.map_arr_nametags.dup
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        SiSU_AO::Instantiate.new
+      end
+    end
+    def get_map_ocn_htmlseg                                                    #reads ao map.ocn_htmlseg, #unless does not exist then creates first
+      begin
+        ao=[]
+        unless @per.fns==@opt.fns \
+        or @per.fns==@fnx
+          @per.fns=(@fnx && @fnx =~/\.ss[tmi]$/) \
+          ? @fnx
+          : @opt.fns
+          @per.map_arr_ocn_htmlseg=[]
+        end
+        ao=(@per.map_arr_ocn_htmlseg.empty?) \
+        ? read_map_ocn_htmlseg
+        : @per.map_arr_ocn_htmlseg.dup
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        SiSU_AO::Instantiate.new
+      end
+    end
+  protected
+    def create_ao
+      ao_array=[]
+      fnp = @fnx ? "#{@opt.fno} #{@fnx}" : @opt.fno
+      unless @opt.act[:quiet][:set]==:on
+        tell=(@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on) \
+        ? SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'Document Abstraction'
+          )
+        : SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'Document Abstraction',
+            "[#{@opt.f_pth[:lng_is]}] #{fnp}"
+          )
+        tell.blue_title_hi
+      end
+      fn=(@fnx && @fnx =~/\.ss[tmi]$/) \
+      ? @fnx
+      : @opt.fns
+      if @opt.fno =~/\.txz$/
+        Dir.chdir(@opt.f_pth[:pth])
+      end
+      meta=file_array=@env.source_file_processing_array(fn)
+      @md=SiSU_Param::Parameters::Instructions.new(meta,@opt).extract
+      meta=nil
+      ao=SiSU_AO::Make.new(fn,@md,file_array,@fnx,@process).song
+      if (@opt.act[:verbose][:set]==:on \
+      || @opt.act[:verbose_plus][:set]==:on \
+      || @opt.act[:maintenance][:set]==:on)
+        cf=SiSU_Env::CreateFile.new(fn)
+        if (@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on)
+            SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            @opt.fns,
+            "~meta/#{@opt.fns}.meta"
+          ).output
+        elsif @opt.act[:maintenance][:set]==:on
+          SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            "ao -> #{cf.meta}"
+          ).txt_grey
+        end
+      end
+      ao.each {|s| ao_array << s}
+      if @opt.act[:maintenance][:set]==:on
+        ao_array.each do |obj|
+          if defined? obj.parent
+            if defined? obj.ln
+              if defined? obj.node
+                puts %{#{obj.ln}: #{obj.ocn} : #{obj.parent} : #{obj.node} - #{obj.lc}}
+              else
+                puts %{#{obj.ln}: #{obj.ocn} : #{obj.parent}}
+              end
+            else
+              if defined? obj.node
+                puts %{   #{obj.ocn} : #{obj.parent} : #{obj.node} - #{obj.lc}}
+              else
+                puts %{   #{obj.ocn} : #{obj.parent}}
+              end
+            end
+          end
+        end
+      end
+      ao_array
+    end
+    def read_fnm
+      ao=[]
+      ao=(FileTest.file?(@fnm)) \
+      ? (File.open(@fnm,'r:utf-8'){ |f| ao=Marshal.load(f)})
+      : SiSU_AO::Source.new(@opt).create_ao
+    end
+    def read_fnc
+      ao=[]
+      ao=(FileTest.file?(@fnc)) \
+      ? (File.open(@fnc,'r:utf-8'){ |f| ao=Marshal.load(f)})
+      : SiSU_AO::Source.new(@opt,@fnx,@process).create_ao
+    end
+    def read_idx_sst
+      m=[]
+      m=(FileTest.file?(@idx_sst)) \
+      ? (File.open(@idx_sst,'r:utf-8'){ |f| m=Marshal.load(f)})
+      : nil
+    end
+    def read_idx_raw
+      m=[]
+      m=(FileTest.file?(@idx_raw)) \
+      ? (File.open(@idx_raw,'r:utf-8'){ |f| m=Marshal.load(f)})
+      : nil
+    end
+    def read_idx_html
+      m=[]
+      m=(FileTest.file?(@idx_html)) \
+      ? (File.open(@idx_html,'r:utf-8'){ |f| m=Marshal.load(f)})
+      : nil
+    end
+    def read_idx_xhtml
+      m=[]
+      m=(FileTest.file?(@idx_xhtml)) \
+      ? (File.open(@idx_xhtml,'r:utf-8'){ |f| m=Marshal.load(f)})
+      : nil
+    end
+    def read_map_nametags
+      m=[]
+      m=(FileTest.file?(@map_nametags)) \
+      ? (File.open(@map_nametags,'r:utf-8'){ |f| m=Marshal.load(f)})
+      : nil
+    end
+    def read_map_ocn_htmlseg
+      m=[]
+      m=(FileTest.file?(@map_ocn_htmlseg)) \
+      ? (File.open(@map_ocn_htmlseg,'r:utf-8'){ |f| m=Marshal.load(f)})
+      : nil
+    end
+  end
+  class Output
+    def initialize(fn,md,data)
+      @fn,@md,@data=fn,md,data
+      @cf=SiSU_Env::CreateFile.new(@fn)
+      @make=SiSU_Env::InfoFile.new(@fn)
+      @dir=SiSU_Env::InfoEnv.new(@fn)
+    end
+    def screen_dump(o)
+      if defined? o.of
+        print %{OF: #{o.of}; }
+      end
+      if defined? o.is
+        print %{IS: #{o.is.to_s}; }
+      end
+      if defined? o.ocn
+        print %{OCN: #{o.ocn}; }
+      end
+      if defined? o.node
+        print %{NODE: #{o.node}; }
+      end
+      if defined? o.parent
+        print %{Parent: #{o.parent}; }
+      end
+      if defined? o.obj and not o.obj.empty?
+        puts %{\n#{o.obj}; }
+      else "\n"
+      end
+    end
+    def screen_print(t_o)
+      if defined? t_o
+        print ' ' + t_o.to_s
+      end
+    end
+    def screen_output(data)
+      data.each do |o|
+        print o.class
+        screen_print(o.ocn)
+        screen_print(o.obj)
+        puts "\n"
+      end
+    end
+    def hard_output
+      if @md.opt.act[:maintenance][:set]==:on
+        filename_meta=@cf.metaverse.file_meta
+        @data.each {|o| filename_meta.puts o.inspect.sub(/:0x[0-9a-f]{8}\s/,': ')} #to make diffing easier
+        filename_txt=@cf.metaverse.file_txt
+        @data.each do |o|
+          if defined? o.ocn
+            filename_txt.puts case o.is
+            when :heading
+              "[#{o.is.to_s} #{o.lv}~#{o.name} [#{o.ocn}]] #{o.obj}"
+            else "[#{o.is.to_s} [#{o.ocn}]] #{o.obj}"
+            end
+          else
+            filename_txt.puts case o.is
+            when :meta
+              "[m~#{o.tag}] #{o.obj}"
+            else "[#{o.is.to_s}] #{o.obj}"
+            end
+          end
+        end
+        filename_debug=@cf.file_debug
+        @data.each do |o|
+          if defined? o.ocn
+            case o.is
+            when :heading
+              filename_debug.puts
+                "#{o.is.to_s} #{o.lv}~#{o.name} odv=#{o.odv} osp=#{o.osp} [#{o.ocn}] -->\n\t#{o.obj}"
+            end
+          end
+        end
+      else
+        hard="#{@dir.processing_path.ao}/#{@md.fns}.meta"
+        File.unlink(hard) if FileTest.file?(hard)
+        hard="#{@dir.processing_path.ao}/#{@md.fns}.txt"
+        File.unlink(hard) if FileTest.file?(hard)
+        hard="#{@dir.processing_path.ao}/#{@md.fns}.debug.txt"
+        File.unlink(hard) if FileTest.file?(hard)
+      end
+    end
+    def make_marshal_content
+      marshal_ao=@make.marshal.ao_content
+      File.open(marshal_ao,'w'){|f| Marshal.dump(@data,f)} if @data.is_a?(Array)
+    end
+    def make_marshal_metadata
+      marshal_ao=@make.marshal.ao_metadata
+      File.open(marshal_ao,'w'){|f| Marshal.dump(@data,f)} if @data.is_a?(Array)
+    end
+    def idx_html_hard_output
+      if @md.book_idx \
+      and @md.opt.act[:maintenance][:set]==:on
+        filename_meta=@cf.file_meta_idx_html
+        if @data.is_a?(Array)
+          @data.each {|s| p s.inspect + "\n" unless s.is_a?(String)}
+          @data.each {|s| filename_meta.puts s.strip + "\n" unless s.strip.empty?}
+        end
+      else
+        hard_idx_html="#{@dir.processing_path.ao}/#{@md.fns}.idx.html"
+        File.unlink(hard_idx_html) if FileTest.file?(hard_idx_html)
+      end
+    end
+    def make_marshal_idx_sst_html_seg
+      marshal_ao=@make.marshal.ao_idx_sst_rel_html_seg
+      File.open(marshal_ao,'w'){|f| Marshal.dump(@data,f)} \
+        if @data.is_a?(Array)
+    end
+    def make_marshal_idx_sst_rel
+      marshal_ao=@make.marshal.ao_idx_sst_rel
+      File.open(marshal_ao,'w'){|f| Marshal.dump(@data,f)} \
+        if @data.is_a?(Array)
+    end
+    def make_marshal_idx_html
+      marshal_ao=@make.marshal.ao_idx_html
+      File.open(marshal_ao,'w'){|f| Marshal.dump(@data,f)} \
+        if @data.is_a?(Array)
+    end
+    def make_marshal_idx_xhtml
+      marshal_ao=@make.marshal.ao_idx_xhtml
+      File.open(marshal_ao,'w'){|f| Marshal.dump(@data,f)} \
+        if @data.is_a?(Array)
+    end
+    def make_marshal_map_nametags
+      marshal_ao=@make.marshal.ao_map_nametags
+      File.open(marshal_ao,'w'){|f| Marshal.dump(@data,f)} \
+        if @data.is_a?(Hash)
+    end
+    def make_marshal_map_name_ocn_htmlseg
+      marshal_ao=@make.marshal.ao_map_ocn_htmlseg
+      File.open(marshal_ao,'w'){|f| Marshal.dump(@data,f)} \
+        if @data.is_a?(Hash)
+    end
+  end
+  class Make
+    def initialize(fn,md,data,fnx,process)
+      @fn,@md,@data,@fnx,@process=fn,md,data,fnx,process
+      @env=SiSU_Env::InfoEnv.new(@md.fns)
+    end
+    def reset
+      @@flag_vocab=0
+      @@line_mode=''
+    end
+    def song
+      reset
+      data_txt=@data
+      data_txt=
+        SiSU_AO_Insertions::Insertions.new(@md,data_txt).                  # ao_expand_insertions.rb
+          expand_insertions?
+      data_txt=
+        SiSU_AO_MiscArrangeText::SI.new(@md,data_txt).                     # ao_misc_arrange.rb
+          prepare_text
+      data_obj,
+        metadata,
+        bibliography=
+          SiSU_AO_DocumentStructureExtract::Build.new(@md,data_txt).       # ao_doc_str.rb
+            identify_parts
+      data_obj=
+        SiSU_AO_Syntax::Markup.new(@md,data_obj,bibliography).songsheet    # ao_syntax.rb
+      data_obj,
+        endnote_array=
+          SiSU_AO_CharacterCheck::Check.new(data_obj).                     # ao_character_check.rb
+            character_check_and_oldstyle_endnote_array
+      data_obj=
+         SiSU_AO_Images::Images.new(@md,data_obj).images                   # ao_images.rb
+      data_obj,
+        tags_map,
+        ocn_html_seg_map=
+          SiSU_AO_Numbering::Numbering.new(@md,data_obj,@fnx,@process).    # ao_numbering.rb
+            numbering_song
+      data_obj,
+        book_index_rel,
+        book_index_rel_html_seg,
+        html_idx,
+        xhtml_idx=
+          SiSU_AO_BookIndex::BookIndex.new(@md,data_obj,@env).             # ao_idx.rb
+            indexing_song if @md.book_idx
+      data_obj=
+        SiSU_AO_Endnotes::Endnotes.new(@md,data_obj,endnote_array).        # ao_endnotes.rb
+          endnotes
+      outputdata=data_obj
+      if (@md.opt.act[:ao][:set]==:on \
+      || @md.opt.act[:maintenance][:set]==:on)
+        SiSU_AO::Output.new(@fn,@md,outputdata).hard_output
+        SiSU_AO::Output.new(@fn,@md,outputdata).make_marshal_content
+        SiSU_AO::Output.new(@fn,@md,metadata).make_marshal_metadata
+        SiSU_AO::Output.new(@fn,@md,html_idx).idx_html_hard_output
+        SiSU_AO::Output.new(@fn,@md,book_index_rel_html_seg).make_marshal_idx_sst_html_seg
+        SiSU_AO::Output.new(@fn,@md,book_index_rel).make_marshal_idx_sst_rel
+        SiSU_AO::Output.new(@fn,@md,html_idx).make_marshal_idx_html
+        SiSU_AO::Output.new(@fn,@md,xhtml_idx).make_marshal_idx_xhtml
+        SiSU_AO::Output.new(@fn,@md,tags_map).make_marshal_map_nametags
+        SiSU_AO::Output.new(@fn,@md,ocn_html_seg_map).make_marshal_map_name_ocn_htmlseg
+      end
+      reset
+      outputdata
+    end
+  protected
+  end
+end
+__END__
+#+END_SRC
+
+** ao_appendices.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/ao_appendices.rb"
+# <<sisu_document_header>>
+module SiSU_AO_Appendices
+  class Glossary
+    def initialize(md,data)
+      @md,@data=md,data
+    end
+    def glossary_extraction
+      glossary=[]
+      glossaryflag=false
+      code_flag=false
+      flag_code_curly=:not_code_curly
+      flag_code_tics=:not_code_tics
+      @data=@data.select do |t_o|
+        if t_o =~/^code\{/
+          flag_code_curly=:code_curly
+        elsif t_o =~/^\}code/
+          flag_code_curly=:not_code_curly
+        elsif t_o =~/^``` code/
+          flag_code_tics=:code_tics
+        elsif flag_code_tics ==:code_tics \
+        and t_o =~/^```/
+          flag_code_tics=:not_code_tics
+        end
+        code_flag=if flag_code_curly==:code_curly \
+        or flag_code_tics==:code_tics
+          true
+        else false
+        end
+        unless code_flag
+          if @md.flag_glossary
+            if t_o =~/^1~!glossary/
+              glossaryflag = true
+              next
+            elsif t_o =~/^:?[B-D]~/
+              next
+            elsif t_o =~/^:?[B-D1]~/
+              glossaryflag = false
+              t_o
+            elsif glossaryflag
+              if t_o !~/\A%+ /
+                glossary << t_o
+                next
+              else
+                t_o
+              end
+            else t_o
+            end
+          else t_o
+          end
+        else t_o
+        end
+      end.compact
+      [@data,glossary]
+    end
+  end
+  class Bibliography
+    def initialize(md,data)
+      @md,@data=md,data
+    end
+    def sort_bibliography_array_by_deemed_author_year_title(bib)
+      if bib
+        bib.compact.sort_by do |c|
+          [c[:deemed_author],c[:ymd],c[:title]]
+        end
+      end
+    end
+    def citation_in_prepared_bibliography(cite)
+      @cite=cite
+      def generic
+        {
+           is:         nil, # :book, :article, :magazine, :newspaper, :blog, :other
+           author_raw: nil,
+           author:     nil,
+           author_arr: nil,
+           editor_raw: nil,
+           editor:     nil,
+           editor_arr: nil,
+           title:      nil,
+           subtitle:   nil,
+           fulltitle:  nil,
+           language:   nil,
+           trans:      nil,
+           src:        nil,
+           journal:    nil,
+           in:         nil,
+           volume:     nil,
+           edition:    nil,
+           year:       nil,
+           place:      nil,
+           publisher:  nil,
+           url:        nil,
+           pages:      nil,
+           note:       nil,
+          #format:     nil, #consider list of fields arranged with markup
+           short_name: nil,
+           id:         nil,
+        }
+      end
+      def citation_metadata
+        type=:generic
+        if type
+          citation=generic
+          citeblock=@cite.split("\n")
+          citeblock.select do |meta|
+            case meta
+            when /^((?:au|author):\s+)\S+/ #req
+              citation[:author_raw]=/^#{$1}(.+)/.match(meta)[1]
+            when /^((?:ti|title):\s+)\S+/ #req
+              citation[:title]=/^#{$1}(.+)/.match(meta)[1]
+            when /^((?:st|subtitle):\s+)\S+/
+              citation[:subtitle]=/^#{$1}(.+)/.match(meta)[1]
+            when /^((?:lng|language):\s+)\S+/
+              citation[:language]=/^#{$1}(.+)/.match(meta)[1]
+            when /^((?:edr?|editor):\s+)\S+/
+              citation[:editor_raw]=/^#{$1}(.+)/.match(meta)[1]
+            when /^((?:tr|trans(:?lator)?):\s+)\S+/
+              citation[:editor_raw]=/^#{$1}(.+)/.match(meta)[1]
+            when /^((?:pb|publisher):\s+)\S+/
+              citation[:publisher]=/^#{$1}(.+)/.match(meta)[1]
+            when /^((?:edn|edition):\s+)\S+/
+              citation[:edition]=/^#{$1}(.+)/.match(meta)[1]
+            when /^((?:yr|year):\s+)\S+/ #req?
+              citation[:year]=/^#{$1}(.+)/.match(meta)[1]
+            when /^((?:pl|publisher_state):\s+)\S+/
+              citation[:place]=/^#{$1}(.+)/.match(meta)[1]
+            when /^((?:jo|journal):\s+)\S+/ #req?
+              citation[:journal]=/^#{$1}(.+)/.match(meta)[1]
+            when /^((?:vol?|volume):\s+)\S+/
+              citation[:volume]=/^#{$1}(.+)/.match(meta)[1]
+            when /^((?:in):\s+)\S+/
+              citation[:in]=/^#{$1}(.+)/.match(meta)[1]
+            when /^((?:src):\s+)\S+/
+              citation[:src]=/^#{$1}(.+)/.match(meta)[1]
+            when /^((?:pg|pages?):\s+)\S+/
+              citation[:pages]=/^#{$1}(.+)/.match(meta)[1]
+            when /^(url:\s+)\S+/
+              citation[:url]=/^#{$1}(.+)/.match(meta)[1]
+            when /^(note:\s+)\S+/
+              citation[:note]=/^#{$1}(.+)/.match(meta)[1]
+            when /^((?:sn|shortname):\s+)\S+/ # substitution: (/#{id}/,"#{sn}")
+              citation[:short_name]=/^#{$1}(.+)/.match(meta)[1]
+            when /^(id:\s+)\S+/               # substitution: (/#{id}/,"#{sn}")
+              citation[:id]=/^#{$1}(.+)/.match(meta)[1]
+            end
+          end
+          if citation[:subtitle]
+            citation[:fulltitle] = citation[:title] \
+            + ' - ' \
+            + citation[:subtitle]
+          else
+            citation[:fulltitle] = citation[:title]
+          end
+          if citation[:author_raw]
+            citation[:author_arr]=citation[:author_raw].split(/;\s*/)
+            citation[:author]=citation[:author_arr].map do |author|
+              author.gsub(/(.+?),\s+(.+)/,'\2 \1').strip
+            end.join(', ').strip
+          end
+          if citation[:editor_raw]
+            citation[:editor_arr]=citation[:editor_raw].split(/;\s*/)
+            citation[:editor]=citation[:editor_arr].map do |editor|
+              editor.gsub(/(.+?),\s+(.+)/,'\2 \1').strip
+            end.join(', ').strip
+          end
+          citation[:ymd]=if not citation[:year] =~/^[0-9]{4}/
+            '9999'
+          else citation[:year]
+          end
+          citation[:deemed_author]=if not citation[:author_raw] \
+          and citation[:editor_raw]
+            citation[:editor_arr][0]
+          elsif citation[:author_raw]
+            citation[:author_arr][0]
+          else
+            SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+              warn('Citation needs an author or editor, title: "' \
+              + citation[:title] + '"')
+            '000'
+          end
+          unless citation[:short_name]
+            citation[:short_name]=%{#{citation[:author]}, "#{citation[:title]}" (#{citation[:date]})}
+          end
+        end
+        citation
+      end
+      self
+    end
+    def biblio_format
+      def generic(c)
+        cite=%{#{c[:author]}. /{"#{c[:fulltitle]}".}/}
+        cite=(c[:journal]) \
+        ? cite + %{ #{c[:journal]},}
+        : cite
+        cite=(c[:source]) \
+        ? cite + %{ #{c[:source]},}
+        : cite
+        cite=(c[:in]) \
+        ? cite + %{ in #{c[:in]},}
+        : cite
+        cite=(c[:volume]) \
+        ? cite + %{ #{c[:volume]},}
+        : cite
+        cite=(c[:trans]) \
+        ? cite + %{ trans. #{c[:trans]},}
+        : cite
+        cite=(c[:editor]) \
+        ? cite + %{ ed. #{c[:editor]},}
+        : cite
+        cite=(c[:place]) \
+        ? cite + %{ #{c[:place]},}
+        : cite
+        cite=(c[:publisher]) \
+        ? cite + %{ #{c[:publisher]},}
+        : cite
+        cite=(c[:year]) \
+        ? cite + %{ (#{c[:year]})}
+        : cite
+        cite=(c[:pages]) \
+        ? cite + %{ #{c[:pages]}}
+        : cite
+        cite=(c[:url]) \
+        ? cite + %{ #{c[:url]}}
+        : cite
+        cite=(c[:note]) \
+        ? cite + %{ #{c[:note]}}
+        : cite
+        cite
+      end
+      def generic_editor(c)
+        cite=%{#{c[:editor]} ed. /{"#{c[:fulltitle]}".}/}
+        cite=(c[:journal]) \
+        ? cite + %{ #{c[:journal]}, }
+        : cite
+        cite=(c[:source]) \
+        ? cite + %{ #{c[:source]}, }
+        : cite
+        cite=(c[:in]) \
+        ? cite + %{ in #{c[:in]},}
+        : cite
+        cite=(c[:volume]) \
+        ? cite + %{ #{c[:volume]},}
+        : cite
+        cite=(c[:trans]) \
+        ? cite + %{ trans. #{c[:trans]},}
+        : cite
+        cite=(c[:place]) \
+        ? cite + %{ #{c[:place]},}
+        : cite
+        cite=(c[:publisher]) \
+        ? cite + %{ #{c[:publisher]}}
+        : cite
+        cite=(c[:year]) \
+        ? cite + %{ (#{c[:year]})}
+        : cite
+        cite=(c[:pages]) \
+        ? cite + %{ #{c[:pages]}}
+        : cite
+        cite=(c[:url]) \
+        ? cite + %{ #{c[:url]}}
+        : cite
+        cite=(c[:note]) \
+        ? cite + %{ #{c[:note]}}
+        : cite
+        cite
+      end
+      self
+    end
+    def biblio_make(cite)
+      if cite[:author]
+        biblio_format.generic(cite)
+      elsif cite[:editor]
+        biblio_format.generic_editor(cite)
+      else
+        biblio_format.generic(cite)
+      end
+    end
+    def biblio_extraction
+      bibliography=[]
+      biblioflag=false
+      code_flag=false
+      flag_code_curly=:not_code_curly
+      flag_code_tics=:not_code_tics
+      @data=@data.select do |t_o|
+        if t_o =~/^code\{/
+          flag_code_curly=:code_curly
+        elsif t_o =~/^\}code/
+          flag_code_curly=:not_code_curly
+        elsif t_o =~/^``` code/
+          flag_code_tics=:code_tics
+        elsif flag_code_tics ==:code_tics \
+        and t_o =~/^```/
+          flag_code_tics=:not_code_tics
+        end
+        code_flag=if flag_code_curly==:code_curly \
+        or flag_code_tics==:code_tics
+          true
+        else false
+        end
+        unless code_flag
+          if @md.flag_auto_biblio
+            if t_o =~/^1~!biblio(?:graphy)?/
+              biblioflag = true
+              t_o
+            elsif t_o =~/^:?[B-D1]~/
+              biblioflag = false
+              t_o
+            elsif biblioflag
+              if t_o !~/\A%+ /
+                bibliography << citation_in_prepared_bibliography(t_o).citation_metadata
+                next
+              else
+                t_o
+              end
+            else t_o
+            end
+          elsif @md.flag_biblio
+            if t_o =~/^1~!biblio(?:graphy)?/
+              biblioflag = true
+              next
+            elsif t_o =~/^:?[B-D]~/
+              next
+            elsif t_o =~/^:?[B-D1]~/
+              biblioflag = false
+              t_o
+            elsif biblioflag
+              if t_o !~/\A%+ /
+                bibliography << t_o
+                next
+              else
+                t_o
+              end
+            else t_o
+            end
+          else t_o
+          end
+        else t_o
+        end
+      end.compact
+      if @md.flag_auto_biblio \
+      and bibliography.length > 0
+        data_new=[]
+        bib=sort_bibliography_array_by_deemed_author_year_title(bibliography)
+        biblio_done=[]
+        @data.select do |t_o|
+          if t_o =~/^1~!biblio(?:graphy)?/
+            bib.each do |c|
+              d=c
+              d.store(:obj, biblio_make(c))
+              biblio_done << d
+              #biblio_done << { obj: biblio_make(c), id: c[:id] }
+            end
+          else data_new << t_o
+          end
+        end
+        @data=data_new
+      end
+      [@data,biblio_done]
+    end
+  end
+  class Citations
+    def initialize(md='',data='')
+      @md,@data=md,data
+      #@biblio=[]
+    end
+    def songsheet
+      tuned_file,citations=citations_scan(@data)
+      [tuned_file,citations]
+    end
+    def sort_bibliography_array_by_author_year(bib)
+      bib.sort_by do |c|
+        [c[:author_raw],c[:year]]
+        #[c[:author_arr][0],c[:year],c[:title]]
+      end
+    end
+    def citations_regex
+      def pages_pattern
+        %r{(?:[,.:]?\s+(?:p{1,2}\.?\s+)?(?:\d+--?\d+)[,.]?\s+)?}
+      end
+      def editor_pattern
+        %r{(?<editor>(?:editor|edited by)\s+.+?)}
+      end
+      def year_pattern
+        %r{[(\[]?(?<year>\d{4})[\])]?[.,]?}
+      end
+      def authors_year_title_publication_editor_pages
+        /(?<authors>.+?)\s+#{year_pattern}\s+"(?<title>.+?)"\s+(?:#{Mx[:fa_italics_o]}|#{Mx[:srcrgx_italics_o]})(?<publication>.+?)(?:#{Mx[:fa_italics_c]}|#{Mx[:srcrgx_italics_c]})\s+#{editor_pattern}#{pages_pattern}/m # note ed. is usually edition rather than editor
+      end
+      def authors_title_publication_year_editor_pages
+        /(?<authors>.+?)\s+"(?<title>.+?)"\s+(?:#{Mx[:fa_italics_o]}|#{Mx[:srcrgx_italics_o]})(?<publication>.+?)(?:#{Mx[:fa_italics_c]}|#{Mx[:srcrgx_italics_c]})\s+#{year_pattern}\s+#{editor_pattern}#{pages_pattern}/m # note ed. is usually edition rather than editor
+      end
+      def authors_title_publication_editor_year_pages ###
+        /(?<authors>.+?)\s+"(?<title>.+?)"\s+(?:#{Mx[:fa_italics_o]}|#{Mx[:srcrgx_italics_o]})(?<publication>.+?)(?:#{Mx[:fa_italics_c]}|#{Mx[:srcrgx_italics_c]})\s+ed.\s+#{editor_pattern}#{year_pattern}#{pages_pattern}/m
+ # note ed. is usually edition rather than editor
+      end
+      def authors_title_publication_editor_pages_year ###
+        /(?<authors>.+?)\s+"(?<title>.+?)"\s+(?:#{Mx[:fa_italics_o]}|#{Mx[:srcrgx_italics_o]})(?<publication>.+?)(?:#{Mx[:fa_italics_c]}|#{Mx[:srcrgx_italics_c]})\s+#{editor_pattern}#{pages_pattern}#{year_pattern}/m # note ed. is usually edition rather than editor
+      end
+      def authors_year_title_publication_pages
+        /(?<authors>.+?)\s+#{year_pattern}\s+"(?<title>.+?)"\s+(?:#{Mx[:fa_italics_o]}|#{Mx[:srcrgx_italics_o]})(?<publication>.+?)(?:#{Mx[:fa_italics_c]}|#{Mx[:srcrgx_italics_c]})[,.;]?#{pages_pattern}/m
+      end
+      def authors_title_publication_year_pages
+        /(?<authors>.+?)\s+"(?<title>.+?)"\s+(?:#{Mx[:fa_italics_o]}|#{Mx[:srcrgx_italics_o]})(?<publication>.+?)(?:#{Mx[:fa_italics_c]}|#{Mx[:srcrgx_italics_c]})\s+#{year_pattern}\s+#{pages_pattern}/m
+      end
+      def authors_title_publication_pages_year ###
+        /(?<authors>.+?)\s+"(?<title>.+?)"\s+(?:#{Mx[:fa_italics_o]}|#{Mx[:srcrgx_italics_o]})(?<publication>.+?)(?:#{Mx[:fa_italics_c]}|#{Mx[:srcrgx_italics_c]})#{pages_pattern}#{year_pattern}/m
+      end
+      def authors_year_publication_pages
+        /(?<authors>.+?)\s+#{year_pattern}\s+(?:#{Mx[:fa_italics_o]}|#{Mx[:srcrgx_italics_o]})(?<publication>.+?)(?:#{Mx[:fa_italics_c]}|#{Mx[:srcrgx_italics_c]})#{pages_pattern}/m
+      end
+      def authors_publication_year_pages
+        /(?<authors>.+?)\s+(?:#{Mx[:fa_italics_o]}|#{Mx[:srcrgx_italics_o]})(?<publication>.+?)(?:#{Mx[:fa_italics_c]}|#{Mx[:srcrgx_italics_c]})[,.;]?\s+(?<publisher>.+?)?#{year_pattern}#{pages_pattern}[.;]?/m
+      end
+      self
+    end
+    def authors?(citations)
+      citations.each.map do |b|
+        if b =~ /^.+\s+::.+?:$/
+          c=/^(?<citation>.+?)\s+::(?<shortref>.+?):$/.match(b)
+          {
+            citation: c[:citation],
+            shortref: c[:shortref],
+            c[:shortref].to_s => c[:citation]
+          }
+        else { citation: b }
+        end
+      end
+    end
+    def long_and_short_ref?(citations) #could be useful, keep ... ectract shortref
+      citations.each.map do |b|
+        if b =~ /^.+\s+::.+?:$/
+          c=/^(?<citation>.+?)\s+::(?<shortref>.+?):$/.match(b)
+          {
+            citation: c[:citation],
+            shortref: c[:shortref],
+            c[:shortref].to_s => c[:citation]
+          }
+        else { citation: b }
+        end
+      end
+    end
+    def citation_detail(citations) #could be useful, keep ... extract shortref
+      bibahash=[]
+      number=0
+      missed=0
+      citations.select do |b|
+        z=if b =~citations_regex.authors_year_title_publication_editor_pages
+          c=citations_regex.authors_year_title_publication_editor_pages.match(b)
+          {
+            is: :article,
+            author_raw: c[:authors],
+            year: c[:year],
+            title: c[:title],
+            publication: c[:publication],
+            editor: c[:editor],
+          }
+        elsif b =~citations_regex.authors_title_publication_year_editor_pages
+          c=citations_regex.authors_title_publication_year_editor_pages.match(b)
+          {
+            is: :article,
+            author_raw: c[:authors],
+            year: c[:year],
+            title: c[:title],
+            publication: c[:publication],
+            editor: c[:editor],
+          }
+        elsif b =~citations_regex.authors_title_publication_editor_year_pages
+          c=citations_regex.authors_title_publication_editor_year_pages.match(b)
+          {
+            is: :article,
+            author_raw: c[:authors],
+            year: c[:year],
+            title: c[:title],
+            publication: c[:publication],
+            editor: c[:editor],
+          }
+        elsif b =~citations_regex.authors_title_publication_editor_pages_year
+          c=citations_regex.authors_title_publication_editor_pages_year.match(b)
+          {
+            is: :article,
+            author_raw: c[:authors],
+            year: c[:year],
+            title: c[:title],
+            publication: c[:publication],
+            editor: c[:editor],
+          }
+        elsif b =~citations_regex.authors_year_title_publication_pages
+          c=citations_regex.authors_year_title_publication_pages.match(b)
+          {
+            is: :article,
+            author_raw: c[:authors],
+            year: c[:year],
+            title: c[:title],
+            publication: c[:publication],
+          }
+        elsif b =~citations_regex.authors_title_publication_year_pages
+          c=citations_regex.authors_title_publication_year_pages.match(b)
+          {
+            is: :article,
+            author_raw: c[:authors],
+            year: c[:year],
+            title: c[:title],
+            publication: c[:publication],
+          }
+        elsif b =~citations_regex.authors_year_publication_pages
+          c=citations_regex.authors_year_publication_pages.match(b)
+          {
+            is: :book,
+            author_raw: c[:authors],
+            year: c[:year],
+            publication: c[:publication],
+          }
+        elsif b =~citations_regex.authors_publication_year_pages
+          c=citations_regex.authors_publication_year_pages.match(b)
+          {
+            is: :book,
+            author_raw: c[:authors],
+            year: c[:year],
+            publication: c[:publication],
+          }
+        else b
+        end
+        if not z.is_a?(NilClass) \
+        and z.is_a?(Hash) \
+        and z[:author_raw].length > 0
+          z[:author_arr]=z[:author_raw].split(/;\s*/)
+          z[:author]=z[:author_arr].map do |author|
+            author.gsub(/(.+?),\s+(.+)/,'\2 \1').strip
+          end.join(', ').strip
+          if @md.opt.act[:verbose_plus][:set]==:on \
+          || @md.opt.act[:maintenance][:set]==:on
+            number +=1 if z.is_a?(Hash)
+            missed +=1 if z.is_a?(String)
+            (z.is_a?(Hash)) \
+            ? (p '[' + number.to_s + '] ' + z.to_s)
+            : (p '<' + missed.to_s + '> ' + z.to_s)
+          end
+        end
+        bibahash << z if z.is_a?(Hash)
+      end
+      bibahash=sort_bibliography_array_by_author_year(bibahash.compact)
+      bibahash
+    end
+    def citations_scan(data)
+      citations=[]
+      #short_ref=[]
+      tuned_file = data.compact.select do |dob|
+        if dob.is !=:meta \
+        && dob.is !=:comment \
+        && dob.is !=:code \
+        && dob.is !=:table
+          if dob.obj =~/\.:.+?:\./
+            citations << dob.obj.scan(/\.:\s*(.+?)\s*:\./m)
+            #short_ref << dob.obj.scan(/\.:\s+(.+?)\s+::([^:]+)::\./m) #look at later
+            ##short_ref << dob.obj.scan(/\.:\s+(.+?)\s+::(.+?)::\./m) #look at later
+            #short_ref << dob.obj.scan(/\.:\s*(.+?)\s*(::(.+?):)?:\./m) #look at later
+            citations=citations.flatten.compact
+            dob.obj=dob.obj.   #remove citations delimiter & helpers from text
+              gsub(/\.:|:\./,'')
+          end
+        end
+        dob if dob.is_a?(Object)
+      end
+      #bib=long_and_short_ref?(citations) #could be useful, keep ... extract shortref
+      citations=citation_detail(citations)
+      [tuned_file,citations]
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** ao_character_check.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/ao_character_check.rb"
+# <<sisu_document_header>>
+module SiSU_AO_CharacterCheck
+  class Check
+    def initialize(data)
+      @data=data
+      @comment='%'
+      @endnote_array=[]
+    end
+    def character_check_and_oldstyle_endnote_array
+      data=@data
+      @endnote_array=[]
+      endnote_no=1
+      @tuned_file=data.select do |dob|
+        unless dob.is ==:table
+          dob.obj=dob.obj.strip.
+            gsub(/^[{~}]\s*$/,'').
+            gsub(/~#\s*/,"#{Mx[:pa_non_object_no_heading]}").
+            gsub(/-#\s*/,"#{Mx[:pa_non_object_dummy_heading]}").
+            gsub(/(#{Mx[:en_a_o]})\s*\s+/,'\1 ').
+            gsub(/(~\{\s*)\s+/,'\1 ').
+            gsub(/ \/\//,"#{Mx[:br_line]}").
+            gsub(/<br>/,"#{Mx[:br_line]}").                #needed by xml, xhtml etc.
+            gsub(/\t/,' ').
+            gsub(/\342\200\231/u,"'"). #if dob =~/’/       #Avoid #&lsquo; &rsquo; #&ldquo; &rdquo;
+            gsub(/\\copy(?:right)?\b/,'&#169;').
+            gsub(/\\trademark\b|\\tm\b/,'&#174;')
+          dob.obj=dob.obj + "\n"
+          unless dob.is ==:code
+            case dob.obj
+            when /\^~/                                     #% Note must do this first (earlier loop) and then enter gathered data into ~^\d+
+              sub_dob=dob.obj.dup
+              @endnote_array << sub_dob.gsub(/\n/,'').
+                gsub(/\^~\s+(.+)\s*/,
+                  %{#{Mx[:en_a_o]}#{endnote_no} \\1 #{Mx[:en_a_c]}}).
+                  strip
+              endnote_no+=1
+              dob=nil if dob.obj =~/\^~ .+/                #watch, removes 'binary' endnote now in endnote array for later insertion
+            end
+          end
+        end
+        dob if dob.is_a?(Object)
+      end.flatten.compact
+      [@tuned_file,@endnote_array]
+    end
+  end
+end
+#+END_SRC
+
+** ao_composite.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/ao_composite.rb"
+# <<sisu_document_header>>
+module SiSU_Assemble
+  require_relative 'se'                                 # se.rb
+  require_relative 'utils_composite'                    # utils_composite.rb
+  class RemoteImage
+    def initialize
+      @env=SiSU_Env::InfoEnv.new
+    end
+    def image(dir)
+      images=[]
+      images[0]=dir
+      images
+    end
+    def download_images(images_info)
+      path="#{@env.processing_path.processing}/external_document/image"
+      FileUtils::mkdir_p(path) \
+        unless FileTest.directory?(path)
+      download_from=images_info.shift
+      images_info.each do |i|
+        image="#{path}/#{i}"
+        imagefile=File.new(image,'w+')
+        open("#{download_from}/#{i}") do |g|
+          imagefile << g.read
+        end
+        imagefile.close
+      end
+      output_path="#{@env.path.webserv}/#{@env.path.base_markup_dir_stub}/_sisu/image_external"
+      FileUtils::mkdir_p(output_path) \
+        unless FileTest.directory?(output_path)
+      SiSU_Env::SystemCall.new("#{path}/*",output_path,'q').rsync
+    end
+  end
+  class Composite
+    include SiSU_Composite_Doc_Utils # composite doc, .ssm, extract all related insert files, array of filenames test
+    def initialize(opt)
+      @opt=opt
+      @env=SiSU_Env::InfoEnv.new
+    end
+    def read
+      begin
+        pwd=Dir.pwd
+        Dir.chdir(@opt.f_pth[:pth])
+        if @opt.fno =~/\S+?\.ssm$/
+          SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'Composite Document',
+            "[#{@opt.f_pth[:lng_is]}] #{@opt.fno}",
+          ).grey_title_hi unless @opt.act[:quiet][:set]==:on
+          composite_and_imported_filenames_array(@opt.fno) # composite doc, .ssm, extract all related insert files, array of filenames test
+          assembled=loadfile(@opt.fno)
+          write(assembled)
+        end
+        Dir.chdir(pwd)
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).
+          location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    def insert?(para)
+      if para =~ /^<<\s+((?:https?|file):\/\/\S+?\.ss[it])$/ # and NetTest
+        url($1.strip)
+      elsif para =~/^<<\s+(\S+?\.ss[it])$/
+        loadfilename=$1.strip
+        insert_array=loadfile(loadfilename)
+        file=insertion(loadfilename,insert_array)
+        file[:prepared]
+      else para
+      end
+    end
+    def loadfile(loadfilename)
+      begin
+        if FileTest.file?(loadfilename)
+          insert_array=IO.readlines(loadfilename,'')
+          if loadfilename =~/\S+?\.ss[itm]$/
+            if (@opt.act[:verbose][:set]==:on \
+            || @opt.act[:verbose_plus][:set]==:on \
+            || @opt.act[:maintenance][:set]==:on)
+              SiSU_Screen::Ansi.new(
+                @opt.act[:color_state][:set],
+                'loading:',
+                loadfilename,
+              ).txt_grey
+            end
+            tuned_file=if loadfilename =~/\S+?\.ss[im]$/
+              insert_array.each.map do |para|
+                insert?(para)
+              end
+            elsif loadfilename =~/\S+?\.sst$/
+              insert_array.each.map do |para|
+                para
+              end
+            end.flatten.compact
+          end
+        end
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    def url(loadfilename)
+      if loadfilename =~ /((?:https?|file):\/\/\S+?\.ss[it])$/ # and NetTest
+        loadfilename=$1
+        begin
+          require 'uri'
+          require 'open-uri'
+          require 'pp'
+        rescue LoadError
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+            error('uri, open-uri or pp NOT FOUND (LoadError)')
+        end
+        insert=open(loadfilename)
+        insert_array=insert.dup
+        insert.close
+        file=insertion(loadfilename,insert_array)
+        file[:prepared]
+      end
+    end
+    def write(assembled)
+      assembled_file=File.new("#{@env.processing_path.composite_file}/#{@opt.fnb}.ssm.sst",'w+')
+      assembled.each {|a| assembled_file << a }
+      assembled_file.close
+    end
+    def download_images(download_from,images_array)
+      path="#{@env.processing_path.processing}/external_document/image"
+      FileUtils::mkdir_p(path) unless FileTest.directory?(path)
+      images_array.each do |i|
+        image="#{path}/#{i}"
+        unless FileTest.exists?(image)
+          imagefile=File.new(image,'w+')
+          open("#{download_from}/#{i}") do |g|
+            imagefile << g.read
+          end
+          imagefile.close
+        end
+      end
+    end
+    def insertion(fni,insert_array)
+      file={ prepared: [], images: [] }
+      rgx_image=/(?:^|[^_\\])\{\s*(\S+?\.(?:png|jpg|gif))/
+      file[:prepared] << "\n% |#{fni}|@|^|>>ok\n\n"
+      @code_flag=false
+      insert_array.each do |i|
+        @code_flag=if i =~/^code\{/ then true
+        elsif i =~/^\}code/         then false
+        else @code_flag
+        end
+        if not @code_flag \
+        and i !~/^%+\s/
+          i=i.
+            gsub(/^([123]|:?[ABCD])~\? /,
+              '% [conditional heading:] \1~ ')    #off conditional heading (consider syntax)
+          if i =~/^@\S+?:/
+            i=i.gsub(/\n/m,"\n%  ").
+              gsub(/\n%\s+$/m,'').
+              gsub(/^@\S+?:/m,"\n% [imported header:] ")                       #off imported headers
+          end
+        end
+        file[:prepared] << i
+        if i !~/^%+\s/ \
+        and i =~rgx_image
+          file[:images] << i.scan(rgx_image).uniq
+        end
+      end
+      file[:prepared] << "\n% end import" << "\n\n"
+      if file[:images].length > 0
+        file[:images]=file[:images].flatten.uniq
+        file[:images].delete_if {|x| x =~/https?:\/\// }
+      end
+      file
+    end
+  end
+  class CompositeFileList
+    def initialize(opt)
+      @opt=opt
+      @env=SiSU_Env::InfoEnv.new
+    end
+    def read
+      begin
+        @opt.fns=@opt.fns.gsub(/\.ssm\.sst$/,'.ssm') #FIX earlier, hub
+        fns_array=IO.readlines(@opt.fns,'')
+        insertions?(fns_array)
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    def insertions?(fns_array)
+      tuned_file=[]
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        'Composite Document',
+        @opt.fno
+      ).grey_title_hi unless @opt.act[:quiet][:set]==:on
+      @ssm=[@opt.fns]
+      fns_array.each do |para|
+        if para =~/^<<\s+(\S+?\.ss[it])$/
+          loadfilename=$1.strip
+          if (@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on)
+            SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'loading:',
+              loadfilename,
+            ).txt_grey
+          end
+          tuned_file << if loadfilename =~ /(?:https?|file):\/\/\S+?\.ss[it]$/
+            @ssm << loadfilename
+          elsif loadfilename =~ /\.ss[it]$/ \
+          and FileTest.file?(loadfilename)
+            @ssm << loadfilename
+          else
+            STDERR.puts %{SKIPPED processing file: [#{@opt.lng}] "#{@opt.fns}" it requires an invalid or non-existent file: "#{loadfilename}"}
+            $process_document = :skip; break #remove this line to continue processing documents that have missing include files
+            para
+          end
+        end
+      end
+      @ssm
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** ao_doc_objects.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/ao_doc_objects.rb"
+# <<sisu_document_header>>
+Module SiSU_AO_DocumentStructure
+  class Extract
+    def extract(h,o)
+      h ? h : o
+    end
+  end
+  class ObjectMetadata
+    attr_accessor :is,:of,:tags,:obj,:digest
+    def initialize
+      @tags={}
+      @is=@tmp=@digest=nil
+      @of=:meta
+    end
+    def metadata(tags)
+      of      = @of                                                                 #Symbol, classification - group
+      is      = :meta                                                               #Symbol, classification - specific type
+      tags    = tags            || ((defined? o.tags)      ? o.tags        : {})    #String, metadata type/tag
+      obj     = nil
+      @of,@is,@tags,@obj=of,is,tags,obj
+      self
+    end
+  end
+  class ObjectMeta
+    attr_accessor :obj,:is,:of,:tag,:digest,:tmp
+    def initialize
+      @is=@obj=@tag=@digest=@digest=@tmp=nil
+      @of=:meta
+    end
+    def metadata(h,o=nil)
+      of      = @of                                                                 #Symbol, classification - group
+      is      = :meta                                                               #Symbol, classification - specific type
+      tag     = h[:tag]         || ((defined? o.tag)       ? o.tag         : nil)   #String, metadata type/tag
+      obj     = h[:obj]         || ((defined? o.obj)       ? o.obj         : nil)   #String, text content
+      tmp     = h[:tmp]         || ((defined? o.tmp)       ? o.tmp         : nil)   #available for processing, empty after use
+      digest  = h[:digest]      || ((defined? o.digest)    ? o.digest      : nil)   #hash digests, sha512, sha256 or md5
+      @of,@is,@tag,@obj,@digest,@tmp=of,is,tag,obj,digest,tmp
+      self
+    end
+  end
+  class ObjectHeading
+    attr_accessor :obj,:is,:tags,:of,:lv,:ln,:lc,:use_,:name,:idx,:ocn,:odv,:osp,:node,:parent,:ocn_,:note_,:autonum_,:digest,:tmp
+    def initialize
+      @of=:para
+      @is=@obj=@lv=@ln=@lc=@use_=@name=@idx=@size=@ocn=@odv=@osp=@node=@parent=@ocn_=@note_=@autonum_=@digest=@tmp=nil
+      @tags=[]
+    end
+    def heading_ln(lv)
+      case lv
+      when /A/ then 0
+      when /B/ then 1
+      when /C/ then 2
+      when /D/ then 3
+      when /1/ then 4
+      when /2/ then 5
+      when /3/ then 6
+      when /4/ then 7
+      when /5/ then 8
+      when /6/ then 9
+      end
+    end
+    def heading_lv(ln)
+      case ln.to_s
+      when /0/ then 'A'
+      when /1/ then 'B'
+      when /2/ then 'C'
+      when /3/ then 'D'
+      when /4/ then '1'
+      when /5/ then '2'
+      when /6/ then '3'
+      when /7/ then '4'
+      when /8/ then '5'
+      when /9/ then '6'
+      end
+    end
+    def heading(h,o=nil)
+      if not h[:ln] \
+      and (h[:lv] and h[:lv]=~/[1-6A-D]/)
+        h[:ln]=heading_ln(h[:lv])
+      elsif not h[:lv] \
+      and (h[:ln] and h[:ln].to_s=~/[0-9]/)
+        h[:lv]=heading_lv(h[:ln])
+      end
+      of      = @of                                                                 #Symbol, classification - group
+      is      = :heading                                                            #Symbol, classification - specific type
+      name    = h[:name]        || ((defined? o.name)      ? o.name        : nil)   #String, named object?
+      tags    = h[:tags]        || ((defined? o.tags)      ? o.tags        : [])    #Array, associated object tags, names if any
+      obj     = h[:obj]         || ((defined? o.obj)       ? o.obj         : nil)   #String, text content
+      idx     = h[:idx]         || ((defined? o.idx)       ? o.idx         : nil)   #String, book index provided?
+      ocn     = h[:ocn]         || ((defined? o.ocn)       ? o.ocn         : nil)   #Integer, sequential on substantive-content objects
+      odv     = h[:odv]         || ((defined? o.odv)       ? o.odv         : nil)
+      osp     = h[:osp]         || ((defined? o.osp)       ? o.osp         : nil)
+      node    = h[:node]        || ((defined? o.node)      ? o.node        : nil)   #[Node relationship doc structure info]
+      parent  = h[:parent]      || ((defined? o.parent)    ? o.parent      : nil)   #[Node parent]
+      lv      = h[:lv]          || ((defined? o.lv)        ? o.lv          : nil)   #Alpha-numeric, document structure as used in markup, A-D then 1-6
+      ln      = h[:ln]          || ((defined? o.ln)        ? o.ln          : nil)   #Integer, document structure level, for convenience in processing 1-9
+      lc      = h[:lc]          || ((defined? o.lc)        ? o.lc          : nil)   #Integer, document structure collapsed level, convenience (collapse sisu's dual level document structure for markup with simple linear structure)
+      use_    = if lv \
+        and lv == '1'
+          h[:use_]              || ((defined? o.use_)      ? o.use_        : :ok)
+        elsif not lv.empty? \
+        and lv =~ /[A-D2-3]/
+          :ok
+        else
+           h[:use_]             || ((defined? o.use_)      ? o.use_        : :ok)
+        end
+      ocn_    = if h[:ocn_].nil?
+                                   ((defined? o.ocn_)      ? o.ocn_        : true)  #Bool? no ocn, non-substantive content, do not include in toc #consider
+        else                       h[:ocn_]
+        end
+      autonum_ = if h[:autonum_].nil?
+                                   ((defined? o.autonum_)  ? o.autonum_    : true)  #Bool? auto-numbering if requested default on, false suppresses
+        else                       h[:autonum_]
+        end
+      note_   = h[:note_]       || ((defined? o.note_)     ? o.note_       : false) #Bool, endnotes/footnotes? (processing optimization)
+      digest  = h[:digest]      || ((defined? o.digest)    ? o.digest      : nil)   #hash digests, sha512, sha256 or md5
+      tmp     = h[:tmp]         || ((defined? o.tmp)       ? o.tmp         : nil)   #available for processing, empty after use
+      @of,@is,@lv,@ln,@lc,@name,@tags,@obj,@idx,@ocn,@odv,@osp,@node,@parent,@use_,@ocn_,@note_,@autonum_,@digest,@tmp=
+      of, is, lv, ln, lc, name, tags, obj, idx, ocn, odv, osp, node, parent, use_, ocn_, note_, autonum_, digest, tmp
+      self
+    end
+    def heading_insert(h,o=nil)
+      heading(h,o=nil)
+      @is     = :heading_insert                                                     #String, classification - specific type
+      self
+    end
+  end
+  class ObjectPara
+    attr_accessor :obj,:is,:tags,:of,:name,:idx,:quote_,:bullet_,:indent,:hang,:ocn,:odv,:osp,:parent,:note_,:image_,:ocn_,:digest,:tmp
+    def initialize
+      @of=:para
+      @is=@obj=@name=@idx=@quote_=@bullet_=@indent=@hang=@size=@ocn=@odv=@osp=@parent=@note_=@image_=@ocn_=@digest=@tmp=nil
+      @tags=[]
+    end
+    def paragraph(h,o=nil)
+      of      = @of                                                                 #Symbol, classification - group
+      is      = :para                                                               #Symbol, classification - specific type
+      name    = h[:name]        || ((defined? o.name)      ? o.name        : nil)   #String, named object?
+      tags    = h[:tags]        || ((defined? o.tags)      ? o.tags        : [])    #Array, associated object tags, names if any
+      obj     = h[:obj]         || ((defined? o.obj)       ? o.obj         : nil)   #String, text content
+      idx     = h[:idx]         || ((defined? o.idx)       ? o.idx         : nil)   #String, book index provided?
+      ocn     = h[:ocn]         || ((defined? o.ocn)       ? o.ocn         : nil)   #Integer, sequential on substantive-content objects
+      odv     = h[:odv]         || ((defined? o.odv)       ? o.odv         : nil)
+      osp     = h[:osp]         || ((defined? o.osp)       ? o.osp         : nil)
+      parent  = h[:parent]      || ((defined? o.parent)    ? o.parent      : nil)   #[Node parent]
+      indent  = h[:indent].to_s || ((defined? o.indent)    ? o.indent.to_s : nil)   #Integer, indent level
+      hang    = h[:hang].to_s   || ((defined? o.hang)      ? o.hang.to_s   : nil)   #Integer, hanging indent level
+      bullet_ = h[:bullet_]     || ((defined? o.bullet_)   ? o.bullet_     : false) #Bool, bulleted?
+      quote_  = h[:quote_]      || ((defined? o.quote_)    ? o.quote_      : false) #Bool, quote (blockquote)?
+      note_   = h[:note_]       || ((defined? o.note_)     ? o.note_       : false) #Bool, endnotes/footnotes? (processing optimization)
+      image_  = h[:image_]      || ((defined? o.image_)    ? o.image_      : false) #Bool, images? (processing optimization)
+      ocn_    = if h[:ocn_].nil?
+                                   ((defined? o.ocn_)      ? o.ocn_        : true)  #Bool? no ocn, non-substantive content, do not include in toc #consider
+      else         h[:ocn_]
+      end
+      digest  = h[:digest]      || ((defined? o.digest)    ? o.digest      : nil)   #hash digests, sha512, sha256 or md5
+      tmp     = h[:tmp]         || ((defined? o.tmp)       ? o.tmp         : nil)   #available for processing, empty after use
+      @of,@is,@name,@tags,@obj,@indent,@hang,@bullet_,@quote_,@idx,@ocn,@odv,@osp,@parent,@image_,@note_,@ocn_,@digest,@tmp=
+      of, is, name, tags, obj, indent, hang, bullet_, quote_, idx, ocn, odv, osp, parent, image_, note_, ocn_, digest, tmp
+      self
+    end
+    def docinfo(h,o=nil)
+      of      = @of                                                                 #String, classification - group
+      is      = :docinfo                                                            #String, classification - specific type
+      name    = h[:name]        || ((defined? o.name)      ? o.name        : nil)   #String, named object?
+      tags    = h[:tags]        || ((defined? o.tags)      ? o.tags        : nil)   #Array, associated object tags, names if any
+      obj     = h[:obj]         || ((defined? o.obj)       ? o.obj         : nil)   #String, text content
+      idx     = nil                                                                 #String, book index provided?
+      ocn     = nil                                                                 #Integer, sequential on substantive-content objects
+      odv     = h[:odv]         || ((defined? o.odv)       ? o.odv         : nil)
+      osp     = h[:osp]         || ((defined? o.osp)       ? o.osp         : nil)
+      parent  = h[:parent]      || ((defined? o.parent)    ? o.parent      : nil)   #[Node parent]
+      indent  = nil                                                                 #Integer, indent level
+      hang    = nil                                                                 #Integer, indent level
+      bullet_ = false                                                               #Bool, bulleted?
+      note_   = false                                                               #Bool, endnotes/footnotes? (processing optimization)
+      image_  = h[:image_]      || ((defined? o.image_)    ? o.image_      : false) #Bool, images? (processing optimization)
+      ocn_    = if h[:ocn_].nil?
+                                   ((defined? o.ocn_)      ? o.ocn_        : true)  #Bool? no ocn, non-substantive content, do not include in toc #consider
+      else                         h[:ocn_]
+      end
+      digest  = h[:digest]      || ((defined? o.digest)    ? o.digest      : nil)   #hash digests, sha512, sha256 or md5
+      tmp     = h[:tmp]         || ((defined? o.tmp)       ? o.tmp         : nil)   #available for processing, empty after use
+      @of,@is,@name,@tags,@obj,@indent,@hang,@bullet_,@idx,@ocn,@odv,@osp,@parent,@image_,@note_,@ocn_,@digest,@tmp=
+      of, is, name, tags, obj, indent, hang, bullet_, idx, ocn, odv, osp, parent, image_, note_, ocn_, digest, tmp
+      self
+    end
+  end
+  class ObjectBlockTxt
+    attr_accessor :obj,:is,:of,:tags,:lngsyn,:idx,:ocn,:odv,:osp,:parent,:note_,:number_,:ocn_,:digest,:tmp
+    def initialize
+      @of=:block
+      @is=@obj=@lngsyn=@idx=@ocn=@odv=@osp=@parent=@note_=@number_=@ocn_=@digest=@tmp=nil
+      @tags=[]
+    end
+    def code(h,o=nil)
+      of       = @of                                                                #Symbol, classification - group #alt 'code'
+      is       = :code                                                              #Symbol, classification - specific type
+      tags     = h[:tags]       || ((defined? o.tags)      ? o.tags        : [])    #Array, associated object tags, names if any
+      obj      = h[:obj]        || ((defined? o.obj)       ? o.obj         : nil)   #String, text content
+      lngsyn   = h[:lngsyn]     || ((defined? o.lngsyn)    ? o.lngsyn      : :txt)  #symbol, code lngsyn
+      idx      = h[:idx]        || ((defined? o.idx)       ? o.idx         : nil)   #String, book index provided?
+      ocn      = h[:ocn]        || ((defined? o.ocn)       ? o.ocn         : nil)   #Integer, sequential on substantive-content objects
+      odv      = h[:odv]        || ((defined? o.odv)       ? o.odv         : nil)
+      osp      = h[:osp]        || ((defined? o.osp)       ? o.osp         : nil)
+      parent   = h[:parent]     || ((defined? o.parent)    ? o.parent      : nil)   #[Node parent]
+      number_  = h[:number_]    || ((defined? o.number_)   ? o.number_     : false) #Bool, numbered or not?
+      note_    = h[:note_]      || ((defined? o.note_)     ? o.note_       : false) #Bool, endnotes/footnotes? (processing optimization)
+      ocn_     = if h[:ocn_].nil?
+                                   ((defined? o.ocn_)      ? o.ocn_        : true)  #Bool? no ocn, non-substantive content, do not include in toc #consider
+      else                         h[:ocn_]
+      end
+      num      = h[:num]        || ((defined? o.num)       ? o.num         : nil)
+      digest   = h[:digest]     || ((defined? o.digest)    ? o.digest      : nil)   #hash digests, sha512, sha256 or md5
+      tmp      = h[:tmp]        || ((defined? o.tmp)       ? o.tmp         : nil)   #available for processing, empty after use
+      @of,@is,@tags,@obj,@lngsyn,@idx,@ocn,@odv,@osp,@parent,@number_,@note_,@ocn_,@num,@digest,@tmp=
+      of, is, tags, obj, lngsyn, idx, ocn, odv, osp, parent, number_, note_, ocn_, num, digest, tmp
+      self
+    end
+    def box(h,o=nil)
+      of       = @of                                                                #Symbol, classification - group
+      is       = :box                                                               #Symbol, classification - specific type
+      tags     = h[:tags]       || ((defined? o.tags)      ? o.tags        : [])    #Array, associated object tags, names if any
+      obj      = h[:obj]        || ((defined? o.obj)       ? o.obj         : nil)   #String, text content
+      idx      = h[:idx]        || ((defined? o.idx)       ? o.idx         : nil)   #String, book index provided?
+      ocn      = h[:ocn]        || ((defined? o.ocn)       ? o.ocn         : nil)   #Integer, sequential on substantive-content objects
+      odv      = h[:odv]        || ((defined? o.odv)       ? o.odv         : nil)
+      osp      = h[:osp]        || ((defined? o.osp)       ? o.osp         : nil)
+      parent   = h[:parent]     || ((defined? o.parent)    ? o.parent      : nil)   #[Node parent]
+      note_    = h[:note_]      || ((defined? o.note_)     ? o.note_       : false) #Bool, endnotes/footnotes? (processing optimization)
+      ocn_     = if h[:ocn_].nil?
+                                   ((defined? o.ocn_)      ? o.ocn_        : true)  #Bool? no ocn, non-substantive content, do not include in toc #consider
+      else                         h[:ocn_]
+      end
+      num      = h[:num]        || ((defined? o.num)       ? o.num         : nil)
+      digest   = h[:digest]     || ((defined? o.digest)    ? o.digest      : nil)   #hash digests, sha512, sha256 or md5
+      tmp      = h[:tmp]        || ((defined? o.tmp)       ? o.tmp         : nil)   #available for processing, empty after use
+      @of,@is,@tags,@obj,@idx,@ocn,@odv,@osp,@parent,@note_,@ocn_,@num,@digest,@tmp=
+      of, is, tags, obj, idx, ocn, odv, osp, parent, note_, ocn_, num, digest, tmp
+      self
+    end
+    def block(h,o=nil)
+      of       = @of                                                                #Symbol, classification - group
+      is       = :block                                                             #Symbol, classification - specific type
+      tags     = h[:tags]       || ((defined? o.tags)      ? o.tags        : [])    #Array, associated object tags, names if any
+      obj      = h[:obj]        || ((defined? o.obj)       ? o.obj         : nil)   #String, text content
+      idx      = h[:idx]        || ((defined? o.idx)       ? o.idx         : nil)   #String, book index provided?
+      ocn      = h[:ocn]        || ((defined? o.ocn)       ? o.ocn         : nil)   #Integer, sequential on substantive-content objects
+      odv      = h[:odv]        || ((defined? o.odv)       ? o.odv         : nil)
+      osp      = h[:osp]        || ((defined? o.osp)       ? o.osp         : nil)
+      parent   = h[:parent]     || ((defined? o.parent)    ? o.parent      : nil)   #[Node parent]
+      note_    = h[:note_]      || ((defined? o.note_)     ? o.note_       : false) #Bool, endnotes/footnotes? (processing optimization)
+      ocn_     = if h[:ocn_].nil?
+                                   ((defined? o.ocn_)      ? o.ocn_        : true)  #Bool? no ocn, non-substantive content, do not include in toc #consider
+      else                         h[:ocn_]
+      end
+      num      = h[:num]        || ((defined? o.num)       ? o.num         : nil)
+      digest   = h[:digest]     || ((defined? o.digest)    ? o.digest      : nil)   #hash digests, sha512, sha256 or md5
+      tmp      = h[:tmp]        || ((defined? o.tmp)       ? o.tmp         : nil)   #available for processing, empty after use
+      @of,@is,@tags,@obj,@idx,@ocn,@odv,@osp,@parent,@note_,@ocn_,@num,@digest,@tmp=
+      of, is, tags, obj, idx, ocn, odv, osp, parent, note_, ocn_, num, digest, tmp
+      self
+    end
+    def group(h,o=nil)
+      of       = @of                                                                #Symbol, classification - group
+      is       = :group                                                             #Symbol, classification - specific type
+      tags     = h[:tags]       || ((defined? o.tags)      ? o.tags        : [])    #Array, associated object tags, names if any
+      obj      = h[:obj]        || ((defined? o.obj)       ? o.obj         : nil)   #String, text content
+      idx      = h[:idx]        || ((defined? o.idx)       ? o.idx         : nil)   #String, book index provided?
+      ocn      = h[:ocn]        || ((defined? o.ocn)       ? o.ocn         : nil)   #Integer, sequential on substantive-content objects
+      odv      = h[:odv]        || ((defined? o.odv)       ? o.odv         : nil)
+      osp      = h[:osp]        || ((defined? o.osp)       ? o.osp         : nil)
+      parent   = h[:parent]     || ((defined? o.parent)    ? o.parent      : nil)   #[Node parent]
+      note_    = h[:note_]      || ((defined? o.note_)     ? o.note_       : false) #Bool, endnotes/footnotes? (processing optimization)
+      ocn_     = if h[:ocn_].nil?
+                                   ((defined? o.ocn_)      ? o.ocn_        : true)  #Bool? no ocn, non-substantive content, do not include in toc #consider
+      else          h[:ocn_]
+      end
+      num      = h[:num]        || ((defined? o.num)       ? o.num         : nil)
+      digest   = h[:digest]     || ((defined? o.digest)    ? o.digest      : nil)   #hash digests, sha512, sha256 or md5
+      tmp      = h[:tmp]        || ((defined? o.tmp)       ? o.tmp         : nil)   #available for processing, empty after use
+      @of,@is,@tags,@obj,@idx,@ocn,@odv,@osp,@parent,@note_,@ocn_,@num,@digest,@tmp=
+      of, is, tags, obj, idx, ocn, odv, osp, parent, note_, ocn_, num, digest, tmp
+      self
+    end
+    def alt(h,o=nil)                                                                #see block
+      of       = @of                                                                #Symbol, classification - group
+      is       = :alt                                                               #Symbol, classification - specific type
+      tags     = h[:tags]       || ((defined? o.tags)      ? o.tags        : [])    #Array, associated object tags, names if any
+      obj      = h[:obj]        || ((defined? o.obj)       ? o.obj         : nil)   #String, text content
+      idx      = h[:idx]        || ((defined? o.idx)       ? o.idx         : nil)   #String, book index provided?
+      ocn      = h[:ocn]        || ((defined? o.ocn)       ? o.ocn         : nil)   #Integer, sequential on substantive-content objects
+      odv      = h[:odv]        || ((defined? o.odv)       ? o.odv         : nil)
+      osp      = h[:osp]        || ((defined? o.osp)       ? o.osp         : nil)
+      parent   = h[:parent]     || ((defined? o.parent)    ? o.parent      : nil)   #[Node parent]
+      note_    = h[:note_]      || ((defined? o.note_)     ? o.note_       : false) #Bool, endnotes/footnotes? (processing optimization)
+      ocn_     = if h[:ocn_].nil?
+                                   ((defined? o.ocn_)      ? o.ocn_        : true)  #Bool? no ocn, non-substantive content, do not include in toc #consider
+      else                         h[:ocn_]
+      end
+      num      = h[:num]        || ((defined? o.num)       ? o.num         : nil)
+      digest   = h[:digest]     || ((defined? o.digest)    ? o.digest      : nil)   #hash digests, sha512, sha256 or md5
+      tmp      = h[:tmp]        || ((defined? o.tmp)       ? o.tmp         : nil)   #available for processing, empty after use
+      @of,@is,@tags,@obj,@idx,@ocn,@odv,@osp,@parent,@note_,@ocn_,@num,@digest,@tmp=
+      of, is, tags, obj, idx, ocn, odv, osp, parent, note_, ocn_, num, digest, tmp
+      self
+    end
+    def verse(h,o=nil)                                                              #part of poem decide how you deal with this
+      of       = @of                                                                #Symbol, classification - group
+      is       = :verse                                                             #Symbol, classification - specific type
+      tags     = h[:tags]       || ((defined? o.tags)      ? o.tags        : [])    #Array, associated object tags, names if any
+      obj      = h[:obj]        || ((defined? o.obj)       ? o.obj         : nil)   #String, text content
+      idx      = h[:idx]        || ((defined? o.idx)       ? o.idx         : nil)   #String, book index provided?
+      ocn      = h[:ocn]        || ((defined? o.ocn)       ? o.ocn         : nil)   #Integer, sequential on substantive-content objects
+      odv      = h[:odv]        || ((defined? o.odv)       ? o.odv         : nil)
+      osp      = h[:osp]        || ((defined? o.osp)       ? o.osp         : nil)
+      parent   = h[:parent]     || ((defined? o.parent)    ? o.parent      : nil)   #[Node parent]
+      ocn_     = if h[:ocn_].nil?
+                                   ((defined? o.ocn_)      ? o.ocn_        : true)  #Bool? no ocn, non-substantive content, do not include in toc #consider
+      else                         h[:ocn_]
+      end
+      num      = h[:num]        || ((defined? o.num)       ? o.num         : nil)
+      digest   = h[:digest]     || ((defined? o.digest)    ? o.digest      : nil)   #hash digests, sha512, sha256 or md5
+      tmp      = h[:tmp]        || ((defined? o.tmp)       ? o.tmp         : nil)   #available for processing, empty after use
+      @of,@is,@tags,@obj,@idx,@ocn,@odv,@osp,@parent,@note_,@ocn_,@num,@digest,@tmp=
+      of, is, tags, obj, idx, ocn, odv, osp, parent, note_, ocn_, num, digest, tmp
+      @h=nil
+      self
+    end
+  end
+  class ObjectTable
+    attr_accessor :obj,:is,:of,:lv,:tags,:name,:idx,:indent,:hang,:size,:ocn,:num,:head_,:cols,:widths,:odv,:osp,:parent,:note_,:ocn_,:digest,:tmp
+    def initialize
+      @of=:block
+      @is=@obj=@lv=@name=@idx=@indent=@hang=@size=@ocn,@num,@head_,@cols,@widths=@odv=@osp=@parent=@note_=@ocn_=@num=@digest=@tmp=nil
+      @tags=[]
+    end
+    def table(h,o=nil)
+      of      = @of                                                                 #Symbol, classification - group
+      is      = :table                                                              #Symbol, classification - specific type
+      tags    = h[:tags]        || ((defined? o.tags)      ? o.tags        : [])    #Array, associated object tags, names if any
+      cols    = h[:cols]        || ((defined? o.cols)      ? o.cols        : nil)
+      widths  = h[:widths]      || ((defined? o.widths)    ? o.widths      : nil)
+      obj     = h[:obj]         || ((defined? o.obj)       ? o.obj         : nil)   #String, text content
+      idx     = h[:idx]         || ((defined? o.idx)       ? o.idx         : nil)   #String, book index provided?
+      ocn     = h[:ocn]         || ((defined? o.ocn)       ? o.ocn         : nil)   #Integer, sequential on substantive-content objects
+      odv     = h[:odv]         || ((defined? o.odv)       ? o.odv         : nil)
+      osp     = h[:osp]         || ((defined? o.osp)       ? o.osp         : nil)
+      parent  = h[:parent]      || ((defined? o.parent)    ? o.parent      : nil)   #[Node parent]
+      head_   = h[:head_]       || ((defined? o.head_)     ? o.head_       : false)
+      note_   = h[:note_]       || ((defined? o.note_)     ? o.note_       : false) #Bool, endnotes/footnotes? (processing optimization)
+      ocn_    = if h[:ocn_].nil?
+                                   ((defined? o.ocn_)      ? o.ocn_        : true)  #Bool? no ocn, non-substantive content, do not include in toc #consider
+      else                         h[:ocn_]
+      end
+      num     = h[:num]         || ((defined? o.num)       ? o.num         : nil)
+      digest  = h[:digest]      || ((defined? o.digest)    ? o.digest      : nil)   #hash digests, sha512, sha256 or md5
+      tmp     = h[:tmp]         || ((defined? o.tmp)       ? o.tmp         : nil)   #available for processing, empty after use
+      @of,@is,@tags,@cols,@widths,@obj,@idx,@ocn,@odv,@osp,@parent,@head_,@note_,@ocn_,@num,@digest,@tmp=
+      of, is, tags, cols, widths, obj, idx, ocn, odv, osp, parent, head_, note_, ocn_, num, digest, tmp
+      self
+    end
+  end
+  class ObjectImage
+    attr_accessor :obj,:is,:of,:lv,:idx,:size,:ocn,:parent,:note_,:ocn_,:digest,:tmp
+    def initialize
+      @of=:image
+      @is=@obj=@lv=@idx=@size=@ocn=@parent=@note_=@ocn_=@tmp=@digest=nil
+      @tags=[]
+    end
+    def image(h,o=nil)                                                         #not yet used, and what of a paragraph containing several images, consider
+      of=     @of                                                              #Symbol, classification - group
+      is=     :image                                                           #Symbol, classification - specific type
+      tags=   h[:tags]    || ((defined? o.tags)      ? o.tags    : [])         #Array, associated object tags, names if any
+      obj=    h[:obj]     || ((defined? o.obj)       ? o.obj     : nil)        #String, text content
+      size=   h[:size]    || ((defined? o.size)      ? o.size    : nil)
+      idx=    h[:idx]     || ((defined? o.idx)       ? o.idx     : nil)        #String, book index provided?
+      ocn=    h[:ocn]     || ((defined? o.ocn)       ? o.ocn     : nil)        #Integer, sequential on substantive-content objects
+      odv=    h[:odv]     || ((defined? o.odv)       ? o.odv     : nil)
+      osp=    h[:osp]     || ((defined? o.osp)       ? o.osp     : nil)
+      parent= h[:parent]  || ((defined? o.parent)    ? o.parent  : nil)        #[Node parent]
+      note_=  h[:note_]   || ((defined? o.note_)     ? o.note_   : false)      #Bool, endnotes/footnotes? (processing optimization)
+      ocn_=if h[:ocn_].nil?
+                             ((defined? o.ocn_)  ? o.ocn_    : true)           #Bool? no ocn, non-substantive content, do not include in toc #consider
+      else                   h[:ocn_]
+      end
+      digest= h[:digest]  || ((defined? o.digest)    ? o.digest  : nil)        #hash digests, sha512, sha256 or md5
+      tmp=    h[:tmp]     || ((defined? o.tmp)       ? o.tmp     : nil)        #available for processing, empty after use
+      @of,@is,@tags,@obj,@size,@idx,@ocn,@odv,@osp,@parent,@note_,@ocn_,@digest,@tmp=of,is,tags,obj,size,idx,ocn,odv,osp,parent,note_,ocn_,digest,tmp
+      self
+    end
+  end
+  class ObjectStructure
+    attr_accessor :obj,:tag,:node,:lv,:ln,:lc,:status,:is,:of,:tmp
+    def initialize
+      @of=:structure
+      @is=@obj=@node=@lv=@ln=@lc=@status=@tmp=nil
+    end
+    def xml_dom(h,o=nil)
+      of=     @of                                                              #Symbol, classification - group
+      is=     :xml_dom                                                         #Symbol, classification - specific type
+      obj=    h[:obj]     || ((defined? o.obj)       ? o.obj     : '')         #String, text content
+      lv=     h[:lv]      || ((defined? o.lv)        ? o.lv      : nil)        #Alpha-numeric, document structure as used in markup, A-D then 1-6
+      ln=     h[:ln]      || ((defined? o.ln)        ? o.ln      : nil)        #Integer, document structure level, for convenience in processing 1-9
+      lc=     h[:lc]      || ((defined? o.lc)        ? o.lc      : nil)        #Integer, document structure collapsed level, convenience (collapse sisu's dual level document structure for markup with simple linear structure)
+      node=   h[:node]    || ((defined? o.node)      ? o.node    : nil)        #[Node relationship doc structure info]
+      status= h[:status]  || ((defined? o.status)    ? o.status  : nil)        #tag status Symbol :open or :close
+      tmp=    h[:tmp]     || ((defined? o.tmp)       ? o.tmp     : nil)        #available for processing, empty after use
+      @of,@is,@obj,@status,@node,@lv,@ln,@lc,@tmp=of,is,obj,status,node,lv,ln,lc,tmp
+      self
+    end
+  end
+  class ObjectFlag
+    attr_accessor :obj,:is,:of,:flag,:act,:selections,:tmp
+    def initialize
+      @of=:flag
+      @is=@obj=@flag=@act=@selections=@tmp=nil
+    end
+    def flag(h,o=nil)
+      of=     @of                                                              #Symbol, classification - group
+      is=     :flag                                                            #Symbol, classification - specific type
+      obj=    nil                                                              #String, text content
+      flag=   h[:flag]     || ((defined? o.flag)      ? o.flag    : nil)       #String, text content
+      act=    h[:act]      || ((defined? o.act)       ? o.act     : nil)       #String, text content
+      selections=    h[:selections]      || ((defined? o.selections) ? o.selections : nil)   #String, text content
+      tmp=    h[:flag]     || ((defined? o.tmp)       ? o.tmp     : nil)       #available for processing, empty after use
+      @of, @is,@obj,@flag,@act,@selections,@tmp=
+        of,is, obj, flag, act, selections, tmp
+      self
+    end
+    def flag_ocn(h,o=nil)
+      of=     @of                                                              #Symbol, classification - group
+      is=     :flag_ocn                                                        #Symbol, classification - specific type
+      obj=    nil                                                              #String, text content
+      flag=   h[:flag]     || ((defined? o.flag)      ? o.flag    : nil)       #String, text content
+      act=    h[:act]      || ((defined? o.act)       ? o.act     : nil)       #String, text content
+      selections= h[:selections] || ((defined? o.selections) ? o.selections : nil)   #String, text content
+      tmp=    h[:flag]     || ((defined? o.tmp)       ? o.tmp     : nil)       #available for processing, empty after use
+      @of, @is,@obj,@flag,@act,@selections,@tmp=
+        of,is, obj, flag, act, selections,tmp
+      self
+    end
+    def flag_lng(h,o=nil)
+      of=     @of                                                              #Symbol, classification - group
+      is=     :flag_lng
+      obj=    nil                                                              #String, text content
+      flag=   h[:flag]     || ((defined? o.flag)      ? o.flag    : nil)       #Symbol, :lng_on or :lng_off
+      act=    h[:act]      || ((defined? o.act)       ? o.act     : nil)       #Symbol, language set to :en etc.
+      selections= h[:selections] || ((defined? o.selections) ? o.selections : nil)   #String, text content
+      tmp=    h[:act]     || ((defined? o.tmp)       ? o.tmp     : nil)       #available for processing, empty after use
+      @of, @is,@obj,@flag,@act,@selections,@tmp=
+        of,is, obj, flag, act, selections,tmp
+      self
+    end
+  end
+  class ObjectLayout
+    attr_accessor :obj,:sym,:attr,:is,:is_for,:of,:from,:tmp,:num
+    def initialize
+      @of=:layout
+      @is=@is_for=@obj=@from=@tmp=@num=nil
+    end
+    def break(h,f=nil)                                                         #decide how to deal with
+      of=     @of                                                              #Symbol, classification - group
+      is=     :break                                                           #Symbol, classification - specific type
+      obj=    h[:obj]                                                          #String, text content
+      from=   f
+      tmp=    h[:tmp]                                                          #available for processing, empty after use
+      @of,@is,@obj,@from,@tmp=of,is,obj,from,tmp
+      self
+    end
+    def insert(h,o=nil)                                                        #decide how to deal with, could mimic paragraph?
+      of=     @of                                                              #Symbol, classification - group
+      is=     :insert                                                          #Symbol, classification - specific type
+      obj=    h[:obj]     || ((defined? o.obj)       ? o.obj     : nil)        #String, text content
+      tmp=    h[:tmp]     || ((defined? o.tmp)       ? o.tmp     : nil)        #available for processing, empty after use
+      @of,@is,@obj,@tmp=of,is,obj,tmp
+      self
+    end
+    def open_close(h,o=nil)                                                    #useful for poem & quote
+      of=     @of                                                              #Symbol, classification - group
+      is=     :open_close_tags                                                 #Symbol, classification - specific type
+      is_for= h[:is_for]  || ((defined? o.is_for)    ? o.is_for  : nil)        #String, text content
+      obj=    h[:obj]     || ((defined? o.obj)       ? o.obj     : nil)        #String, text content
+      sym=    h[:sym]     || ((defined? o.sym)       ? o.sym     : nil)        #Symbol tag_open, tag_close
+      attr=   h[:attr]    || ((defined? o.attr)      ? o.attr    : nil)        #String, text content
+      tmp=    h[:tmp]     || ((defined? o.tmp)       ? o.tmp     : nil)        #available for processing, empty after use
+      num=    h[:num]     || ((defined? o.num)       ? o.num     : nil)
+      @of,@is,@is_for,@obj,@sym,@attr,@tmp,@num=
+      of, is, is_for, obj, sym, attr, tmp, num
+      self
+    end
+  end
+  class ObjectComment
+    attr_accessor :obj,:is,:of,:tmp
+    def initialize
+      @of=:comment
+      @is=@obj=@tmp=nil
+    end
+    def comment(h,o=nil)
+      of=     @of                                                              #Symbol, classification - group
+      is=     :comment                                                         #Symbol, classification - specific type
+      obj=    h[:obj]     || ((defined? o.obj)       ? o.obj     : nil)        #String, text content
+      tmp=    h[:tmp]     || ((defined? o.tmp)       ? o.tmp     : nil)        #available for processing, empty after use
+      @of,@is,@obj,@tmp=of,is,obj,tmp
+      self
+    end
+  end
+end
+__END__
+# ~# |-# no paragraph number # -# not included in toc
+#+END_SRC
+
+** ao_doc_str.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/ao_doc_str.rb"
+# <<sisu_document_header>>
+module SiSU_AO_DocumentStructureExtract
+  require_relative 'ao_persist'                     # ao_persist.rb
+  class Instantiate < SiSU_Param::Parameters::Instructions
+    def initialize
+      @@counter=@@column=@@columns=0
+      @@line_mode=''
+    end
+  end
+  class Build
+    def initialize(md,data)
+      @md,@data=md,data
+      SiSU_AO_DocumentStructureExtract::Instantiate.new
+      @pb=SiSU_AO_DocumentStructure::ObjectLayout.new.break(Hx[:br_page])
+      @pbn=SiSU_AO_DocumentStructure::ObjectLayout.new.break(Hx[:br_page_new])
+      @pbl=SiSU_AO_DocumentStructure::ObjectLayout.new.break(Hx[:br_page_line])
+      @per=SiSU_AO_Persist::PersistDocStructExt.new
+      @make=SiSU_Env::ProcessingSettings.new(@md)
+    end
+    def ln_get(lv)
+      case lv
+      when /A/ then 0
+      when /B/ then 1
+      when /C/ then 2
+      when /D/ then 3
+      when /1/ then 4
+      when /2/ then 5
+      when /3/ then 6
+      when /4/ then 7
+      when /5/ then 8
+      when /6/ then 9
+      end
+    end
+    def image_test(str)
+      str=~/\{\s*\S+?\.png.+?\}https?:\/\/\S+/ \
+      ? true
+      : false
+    end
+    def bullet_test(str)
+      (str=~/\*/) \
+      ? true
+      : false
+    end
+    def quotes?
+      @per.quote==:open \
+      ? true
+      : false
+    end
+    def hang_and_indent_test(str)
+      hang_indent=if str=~/^_([1-9])[^_]/
+        [$1,$1]
+      elsif str=~/^__([1-9])/
+        [0,$1]
+      elsif str=~/^_([0-9])_([0-9])/
+        [$1,$2]
+      else
+        [0,0]
+      end
+      hang,indent=hang_indent[0],hang_indent[1]
+      [hang,indent]
+    end
+    def hang_and_indent_def_test(str1,str2)
+      hang_indent=if str1=~/^_([1-9])[^_]/
+        [$1,$1]
+      elsif str1=~/^__([1-9])/
+        [0,$1]
+      elsif str1=~/^_([0-9])_([0-9])/
+        [$1,$2]
+      else
+        [0,0]
+      end
+      obj=if str2 =~/^(.+?)\s+\\\\(?:\s+|\n)/
+        str2.gsub(/^(.+?)(\s+\\\\(?:\s+|\n))/,
+          "#{Mx[:fa_bold_o]}\\1#{Mx[:fa_bold_c]}\\2")
+      else
+        str2.gsub(/^(.+?)\n/,
+          "#{Mx[:fa_bold_o]}\\1#{Mx[:fa_bold_c]}\n")
+      end
+      hang,indent=hang_indent[0],hang_indent[1]
+      [
+        hang,
+        indent,
+        obj,
+      ]
+    end
+    def endnote_test?(str)
+      (str=~/~\{.+?\}~|~\[.+?\]~/) \
+      ? true
+      : false
+    end
+    def extract_tags(str,nametag=nil)
+      tags=[]
+      if str.nil?
+      else
+        if str =~/(?:^|[ ])\*~([a-z0-9._-]+)(?=[ #{Mx[:br_nl]}]|$)/
+          str=str.gsub(/(^|[ ])\*~([a-z0-9._-]+)(?=[ #{Mx[:br_nl]}]|$)/i,
+              "\\1#{Mx[:tag_o]}\\2#{Mx[:tag_c]}").
+            gsub(/ [ ]+/i,' ')
+          tags=str.scan(/#{Mx[:tag_o]}(\S+?)#{Mx[:tag_c]}/).flatten.uniq
+          str=str.gsub(/[ ]?#{Mx[:tag_o]}\S+?#{Mx[:tag_c]}[ ]?/,' ') #may be issues with spaces would leave one, but "code" blocks?
+        end
+        tags=nametag ? (tags << nametag) : tags
+        tags.each do |t|
+          t.gsub!(/[^a-z0-9._-]/,'')
+        end
+      end
+      [
+        str,
+        tags,
+      ]
+    end
+    def rgx_idx_ocn_seg
+      @rgx_idx_ocn_seg=/(.+?)\s*[+](\d+)/
+    end
+    def construct_idx_array_and_hash(idxraw)
+      idx_array_raw=idxraw.scan(/[^;]+/)
+      idx_hash,idx_array,idx_lst={},[],[]
+      idx_array_raw.each do |idx|
+        idx=idx.strip
+        idx_lst=case idx
+        when /\S+?\s*:/
+          idx_couplet_tmp=[]
+          idx_couplet=idx.scan(/\s*[^:]+\s*/)
+          if idx_couplet[1] =~/[|]/
+            idx_couplet_tmp <<
+              idx_couplet[0] <<
+              idx_couplet[1].scan(/\s*[^|]+\s*/)
+          else
+            idx_couplet_tmp <<
+              idx_couplet[0] <<
+              [idx_couplet[1]]
+          end
+          idx_couplet=idx_couplet_tmp
+        else [idx]
+        end
+        term_nodes=[]
+        idx_lst.each do |term_node|
+          case term_node
+          when String
+            term_node=
+              term_node[0].chr.capitalize +
+              term_node[1,term_node.length]
+            term_node=(term_node =~/.+?[+]\d+/) \
+            ? term_node
+            : (term_node + '+0')
+            term_nodes << term_node
+            use,plus=rgx_idx_ocn_seg.match(term_node)[1,2]
+            @use=use.strip
+            unless idx_hash[@use] \
+            and defined? idx_hash[@use]
+              idx_hash[@use]=
+                { sub: [], plus: plus }
+            end
+          when Array
+            subterm_nodes=[]
+            term_node.each do |subterm_node|
+              subterm_node=(subterm_node =~/.+?[+]\d+/) \
+              ? subterm_node
+              : (subterm_node + '+0')
+              subterm_nodes << subterm_node
+              sub,sub_plus=rgx_idx_ocn_seg.match(subterm_node)[1,2]
+              unless idx_hash[@use] \
+              and defined? idx_hash[@use]
+                idx_hash[@use]=
+                  { sub: [], plus: 0 }
+              end
+              idx_hash[@use][:sub] <<
+                { sub.strip => { plus: sub_plus } }
+            end
+            term_nodes << subterm_nodes
+          end
+        end
+        idx_array << term_nodes
+      end
+      {
+        hash: idx_hash,
+        array: idx_array,
+      }
+    end
+    def extract_structure_loop(data,tuned_file)
+      data.each do |t_o|
+        if t_o =~/^--([+~-])[#]$/
+          h=case $1
+          when /[+]/
+            @per.ocn=:on
+            {
+              flag: :ocn_on,
+            }
+          when /[~]/
+            @per.ocn=:ocn_off_headings_keep
+            {
+              flag: :ocn_off,
+              mod: :headings_keep,
+            }
+          when /[-]/ #of particular relevance with level 1~ which is required to precede substantive text & used e.g. in html segmented text
+            @per.ocn=:ocn_off_headings_dummy_lev1
+            {
+              flag: :ocn_off,
+              mod: :headings_exclude,
+            }
+          else
+            @per.ocn=:on
+            {
+              flag: :ocn_on,
+            }
+          end
+          t_o=SiSU_AO_DocumentStructure::ObjectFlag.new.flag_ocn(h)
+          next
+        end
+        if t_o =~/^:[~](#{SiSU_is.language_list_regex?}|-)$/  # work with for identifying language of objects
+          lng=$1
+          h=case lng
+          when /(?:#{SiSU_is.language_list_regex?})/
+            @per.lng=:on
+            @per.lng_is=lng.to_sym
+            {
+              flag: :lng_on,
+              act:  lng.to_sym,
+            }
+          else # ^:~-
+            if @per.lng==:on
+              @per.lng=:off
+              @per.lng_is=:doc_default
+              {
+                flag: :lng_off,
+                act:  :doc_default,
+              }
+            end
+          end
+          t_o=SiSU_AO_DocumentStructure::ObjectFlag.new.flag_lng(h)
+          next
+        end
+        t_o=t_o.gsub(/(?:\n\s*\n)+/m,"\n") if @per.code==:off
+        unless t_o =~/^(?:@\S+?:|%+)\s/                  # extract book index for paragraph if any
+          idx=if t_o=~/^=\{\s*(.+)\s*\}\s*$\Z/m
+            m=$1
+            m=m.split(/[ ]*\n/).join(' ').
+              gsub(/\s+([|:;])\s+/,'\1').
+              gsub(/\s+([+]\d+)\s+/,'\1')
+            t_o=t_o.gsub(/\n=\{.+?\}\s*$/m,'')
+            idx_array_and_hash=construct_idx_array_and_hash(m)
+            idx_array_and_hash[:hash]
+          else nil
+          end
+        end
+        if (t_o.is_a?(String) \
+          && t_o !~/^(?:code(?:\.[a-z][0-9a-z_]+)?(?:\(.+?\))?|box(?:\.[a-z_]+)?|poem|alt|group|block)\{|^\}(?:code|poem|alt|group|block)|^(?:table\(.+?\)\{|\{table\()|^(?:table\{|\{table)[ ~]/ \
+           && t_o !~/^```[ ]+(?:code(?:\.[a-z][0-9a-z_]+)?(?:\(.+?\))?|box(?:\.[a-z_]+)?|poem|alt|group|block|table)|^```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$|^`:quote_(?:open|close)`/ \
+          and @per.code==:off \
+          and @per.poem==:off \
+          and @per.group==:off \
+          and @per.block==:off \
+          and @per.alt==:off \
+          and @per.box==:off \
+          and @per.table==:off
+        )
+          t_o=case t_o
+          when /^#{Mx[:meta_o]}\S+?#{Mx[:meta_c]}/                                 #metadata, header
+            if t_o=~/^#{Mx[:meta_o]}(\S+?)#{Mx[:meta_c]}\s*(.+)/m
+              tag,obj=$1,$2
+              @metadata[tag]=obj
+            end
+            t_o=nil
+          when /^%+\s/                                     #comment
+            t_o=if t_o=~/^%+\s+(.+)/
+              h={ obj: $1 }
+              SiSU_AO_DocumentStructure::ObjectComment.new.comment(h)
+            else nil
+            end
+          when /^:?([A-D1-6])\~/                           #heading / lv
+            lv=$1
+            ln=ln_get(lv)
+            t_o=if t_o=~/^:?[A-D1-6]\~\s+(.+)/m
+              obj=$1
+              note=endnote_test?(obj)
+              obj,tags=extract_tags(obj)
+              if @per.ocn==:ocn_off_headings_dummy_lev1 \
+              or @per.ocn==:ocn_off_headings_keep
+                unless obj =~ /[~-][#]\s*$/
+                  if @per.ocn==:ocn_off_headings_dummy_lev1 \
+                  and t_o =~/^1\~\S*\s+/m
+                    obj << ' -#'
+                  elsif @per.ocn==:ocn_off_headings_dummy_lev1 \
+                  or @per.ocn==:ocn_off_headings_keep
+                    obj << ' ~#'
+                  end
+                end
+              end
+              h={
+                lv: lv,
+                ln: ln,
+                obj: obj,
+                idx: idx,
+                tags: tags,
+              }
+              SiSU_AO_DocumentStructure::ObjectHeading.new.heading(h)
+            elsif t_o=~/^:?[A-D1-6]\~(\S+?)-\s+(.+)/m
+              name,obj=$1,$2
+              note=endnote_test?(obj)
+              obj,tags=extract_tags(obj)
+              if @per.ocn==:ocn_off_headings_dummy_lev1 \
+              or @per.ocn==:ocn_off_headings_keep
+                unless obj =~ /[~-][#]\s*$/
+                  if @per.ocn==:ocn_off_headings_dummy_lev1 \
+                  and t_o =~/^1\~\S*\s+/m
+                    obj << ' -#'
+                  elsif @per.ocn==:ocn_off_headings_dummy_lev1 \
+                  or @per.ocn==:ocn_off_headings_keep
+                    obj << ' ~#'
+                  end
+                end
+              end
+              h={
+                lv: lv,
+                name: name,
+                obj: obj,
+                idx: idx,
+                autonum_: false,
+                tags: tags,
+              }
+              SiSU_AO_DocumentStructure::ObjectHeading.new.heading(h)
+            elsif t_o=~/^:?[A-D1-6]\~(\S+)\s+(.+)/m
+              name,obj=$1,$2
+              note=endnote_test?(obj)
+              obj,tags=extract_tags(obj,name)
+              if @per.ocn==:ocn_off_headings_dummy_lev1 \
+              or @per.ocn==:ocn_off_headings_keep
+                unless obj =~ /[~-][#]\s*$/
+                  if @per.ocn==:ocn_off_headings_dummy_lev1 \
+                  and t_o =~/^1\~\S*\s+/m
+                    obj << ' -#'
+                  elsif @per.ocn==:ocn_off_headings_dummy_lev1 \
+                  or @per.ocn==:ocn_off_headings_keep
+                    obj << ' ~#'
+                  end
+                end
+              end
+              h={
+                lv: lv,
+                name: name,
+                obj: obj,
+                idx: idx,
+                tags: tags,
+              }
+              SiSU_AO_DocumentStructure::ObjectHeading.new.heading(h)
+            else nil
+            end
+          when /^_(?:[1-9]!?|[1-9]?\*)\s+/                  #indented and/or bullet paragraph
+            t_o=if t_o=~/^(_(?:[1-9]?\*|[1-9]!?)\s+)(.+)/m
+              tst,obj=$1,$2
+              if t_o=~/^_[1-9]!\s+.+/m
+                hang,indent,obj=hang_and_indent_def_test(tst,obj)
+              else
+                hang,indent=hang_and_indent_test(tst)
+              end
+              bullet=bullet_test(tst)
+              image=image_test(obj)
+              note=endnote_test?(obj)
+              obj,tags=extract_tags(obj)
+              unless obj=~/\A\s*\Z/m
+                if @per.ocn==:ocn_off_headings_dummy_lev1 \
+                or @per.ocn==:ocn_off_headings_keep
+                  unless obj =~ /[~-][#]\s*$/
+                    obj << ' ~#'
+                  end
+                end
+                h={
+                  bullet_: bullet,
+                  hang: hang,
+                  indent: indent,
+                  obj: obj,
+                  idx: idx,
+                  note_: note,
+                  image_: image,
+                  tags: tags,
+                  quote: quotes?,
+                }
+                SiSU_AO_DocumentStructure::ObjectPara.new.paragraph(h)
+              end
+            else nil
+            end
+          when /^_[0-9]?_[0-9]!?\s+/                  #hanging indent paragraph
+            t_o=if t_o=~/^(_[0-9]?_[0-9]!?\s+)(.+)/m
+              tst,obj=$1,$2
+              if t_o=~/^_[0-9]?_[0-9]!\s+.+/m
+                hang,indent,obj=hang_and_indent_def_test(tst,obj)
+              else
+                hang,indent=hang_and_indent_test(tst)
+              end
+              image=image_test(obj)
+              note=endnote_test?(obj)
+              obj,tags=extract_tags(obj)
+              unless obj=~/\A\s*\Z/m
+                if @per.ocn==:ocn_off_headings_dummy_lev1 \
+                or @per.ocn==:ocn_off_headings_keep
+                  unless obj =~ /[~-][#]\s*$/
+                    obj << ' ~#'
+                  end
+                end
+                h={
+                  hang: hang,
+                  indent: indent,
+                  obj: obj,
+                  idx: idx,
+                  note_: note,
+                  image_: image,
+                  tags: tags,
+                  quote: quotes?,
+                }
+                SiSU_AO_DocumentStructure::ObjectPara.new.paragraph(h)
+              end
+            else nil
+            end
+          when /^<(?:br)?:(?:pa?r|o(?:bj|---)?)>\s*$/      #[br:par] #[br:obj]
+            SiSU_AO_DocumentStructure::ObjectLayout.new.break(Hx[:br_obj])
+          when /^(?:-\\\\-|<:pb>)\s*$/                                #[br:pg]
+            SiSU_AO_DocumentStructure::ObjectLayout.new.break(Hx[:br_page],:markup)
+          when /^(?:=\\\\=|<:pn>)\s*$/                                #[br:pgn]
+            SiSU_AO_DocumentStructure::ObjectLayout.new.break(Hx[:br_page_new],:markup)
+          when /^-\.\.-\s*$/                                          #[br:pgl]
+            SiSU_AO_DocumentStructure::ObjectLayout.new.break(Hx[:br_page_line],:markup)
+          else                                             #paragraph
+            image=image_test(t_o)
+            note=endnote_test?(t_o)
+            obj,tags=extract_tags(t_o)
+            if @per.ocn==:ocn_off_headings_dummy_lev1 \
+            or @per.ocn==:ocn_off_headings_keep
+              unless obj =~ /[~-][#]\s*$/
+                obj << ' ~#'
+              end
+            end
+            unless obj=~/\A\s*\Z/m
+              h={
+                bullet_: false,
+                indent: 0,
+                hang: 0,
+                obj: obj,
+                idx: idx,
+                note_: note,
+                image_: image,
+                tags: tags,
+                quote: quotes?,
+              }
+              t_o=SiSU_AO_DocumentStructure::ObjectPara.new.paragraph(h)
+            end
+            t_o=SiSU_AO_DocumentStructureExtract::Structure.new(@md).structure_markup(t_o) #must happen earlier, node info etc. require
+          end
+        elsif @per.code==:off
+          if t_o =~/^(?:code(?:\.[a-z][0-9a-z_]+)?(?:\(.+?\))?\{|```[ ]+code(?:\.[a-z][0-9a-z_]+)?(?:\(.+?\))?)/
+            @per.code=case t_o
+            when /^code(?:\.[a-z][0-9a-z_]+)?(?:\(.+?\))?\{/ then :curls
+            when /^```[ ]+code/                  then :tics
+            else                                 @per.code #error
+            end
+            @per.lngsyn=if t_o =~/^(?:code\.[a-z][0-9a-z_]+(?:\(.+?\))?\{|```[ ]+code\.[a-z_]+)/
+              case t_o
+              when /^code\.([a-z][0-9a-z_]+)(?:\(.+?\))?\{/
+                :"#{$1}"
+              when /^```[ ]+code\.([a-z][0-9a-z_]+)/
+                :"#{$1}"
+              else :txt
+              end
+            else :txt
+            end
+            @@counter=1
+            @codeblock_numbered=
+              (t_o =~/^(?:code(?:\.[a-z][0-9a-z_]+)?\(.*number(?:lines)?.*?\)\{|```[ ]+code(?:\.[a-z][0-9a-z_]+)?\(.*number(?:lines)?.*?\)|code(?:\.[a-z][0-9a-z_]+)?\{#|```[ ]+code(?:\.[a-z][0-9a-z_]+)?\s[#])/) \
+              ? true
+              : false
+            if (t_o =~/^(?:code(?:\.[a-z][0-9a-z_]+)?\{#|```[ ]+code(?:\.[a-z][0-9a-z_]+)?\s[#])/)
+              puts "WARNING document using depreciated markup for numbering codeblocks\nuse: code(numberlines){ ... or: ```code(numberlines) ..."
+            end
+            @num_id[:code_block] +=1
+            h={
+              is_for: :code,
+              obj: '',
+              sym: :code_block_open,
+              num: @num_id[:code_block],
+              syntax: @per.lngsyn,
+            }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+          elsif t_o =~/^(?:poem\{|```[ ]+poem)/
+            @per.poem=case t_o
+            when /^poem\{/        then :curls
+            when /^```[ ]+poem/   then :tics
+            else                  @per.poem #error
+            end
+            @num_id[:poem] +=1
+            h={
+              is_for: :poem,
+              obj: '',
+              sym: :poem_open,
+              num: @num_id[:poem],
+            }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+            tuned_file << t_o
+          elsif t_o =~/^(?:box(?:\.[a-z_]+)?\{|```[ ]+box(?:\.[a-z_]+)?)/
+            @per.box=case t_o
+            when /^box\{/         then :curls
+            when /^```[ ]+box/    then :tics
+            else                       @per.box #error
+            end
+            @num_id[:box] +=1
+            h={
+              is_for: :box,
+              obj: '',
+              sym: :box_open,
+              num: @num_id[:box],
+            }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+            tuned_file << t_o
+          elsif t_o =~/^(?:group\{|```[ ]+group)/
+            @per.group=case t_o
+            when /^group\{/       then :curls
+            when /^```[ ]+group/  then :tics
+            else                       @per.group #error
+            end
+            @num_id[:group] +=1
+            h={
+              is_for: :group,
+              obj: '',
+              sym: :group_open,
+              num: @num_id[:group],
+            }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+            tuned_file << t_o
+          elsif t_o =~/^(?:block\{|```[ ]+block)/
+            @per.block=case t_o
+            when /^block\{/       then :curls
+            when /^```[ ]+block/  then :tics
+            else                       @per.block #error
+            end
+            @num_id[:block] +=1
+            h={
+              is_for: :block,
+              obj: '',
+              sym: :block_open,
+              num: @num_id[:block],
+            }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+            tuned_file << t_o
+          elsif t_o =~/^(?:alt\{|```[ ]+alt)/
+            @per.alt=case t_o
+            when /^alt\{/         then :curls
+            when /^```[ ]+alt/    then :tics
+            else                       @per.alt #error
+            end
+            @num_id[:alt] +=1
+            h={
+              is_for: :alt,
+              obj: '',
+              sym: :alt_open,
+              num: @num_id[:alt],
+            }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+            tuned_file << t_o
+          elsif t_o =~/^`:quote_open`/
+            @per.quote=:open
+            @num_id[:quote] +=1
+            h={
+              is_for: :quote,
+              obj: '',
+              sym: :quote_open,
+              num: @num_id[:quote],
+            }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+            #tuned_file << t_o #% find second source, entered twice, should be once so closed off here
+          elsif t_o =~/^(?:table\(.+?\)\{|```[ ]+table\(.+?\)|\{table\(.+?\))/
+            @num_id[:table] +=1
+            h={
+              is_for: :table,
+              obj: '',
+              sym: :table_open,
+              num: @num_id[:table],
+            }
+            ins_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+            tuned_file << ins_o
+            if t_o=~/^table\((?:.*?\bh;\s+)?.+?\)\{/
+              @per.table=:curls
+              @rows=''
+              case t_o
+              when /table\(.*?\bh;\s+c(\d+):\s+(.+?)\)\{/
+                cols=$1
+                col=$2.scan(/\d+/)
+                heading=true
+              when /table\(.*?c(\d+):\s+(.+?)\)\{/
+                cols=$1
+                col=$2.scan(/\d+/)
+                heading=false
+              end
+              @h={
+                head_: heading,
+                cols: cols,
+                widths: col,
+                idx: idx,
+              }
+            elsif t_o=~/^```[ ]+table\((?:.*?\bh;)?\s+c\d+:/
+              @per.table=:tics
+              @rows=''
+              case t_o
+              when /^```[ ]+table\(.*?\bh;\s+c(\d+):\s+(.+?)\)/
+                cols=$1
+                col=$2.scan(/\d+/)
+                heading=true
+              when /^```[ ]+table\(\s*c(\d+):\s+(.+?)\)/
+                cols=$1
+                col=$2.scan(/\d+/)
+                heading=false
+              end
+              @h={
+                head_: heading,
+                cols: cols,
+                widths: col,
+                idx: idx,
+              }
+            elsif t_o=~/^\{table\((?:.*?\bh;\s+)?(?:\s+\d+,?)?\)\s*\}\n.+\Z/m
+              m1,m2,hd=nil,nil,nil
+              tbl=/^\{table\((?:.*?\bh;\s+)?(?:\s+\d+,?)*\)\s*\}\n(.+)\Z/m.match(t_o)[1] # fix
+              hd=((t_o =~/^\{table\(.*?\bh;\s+/) ? true : false)
+              tbl,tags=extract_tags(tbl)
+              rws=tbl.split(/\n/)
+              rows=''
+              cols=nil
+              rws.each do |r|
+                cols=(cols ? cols : (r.scan('|').length) +1)
+                r=r.gsub(/\s*\|\s*/m,"#{Mx[:tc_p]}")       #r.gsub!(/\|/m,"#{Mx[:tc_p]}")
+                rows += r + Mx[:tc_c]
+              end
+              col=[]
+              if t_o =~/^\{table\((?:.*?\bh;\s+)?\s+c(\d+):.*?\)\s*\}/       #width of col 1 given as %, usually when wider than rest that are even
+                c1=$1.to_i
+                width=(100 - c1)/(cols - 1)
+                col=[ c1 ]
+                (cols - 1).times { col << width }
+              else                                         #all columns of equal width
+                width=100.00/cols
+                cols.times { col << width }
+              end
+              h={
+                head_: hd,
+                cols: cols,
+                widths: col,
+                obj: rows,
+                idx: idx,
+                tags: tags,
+                num: @num_id[:table],
+              }
+              t_o=SiSU_AO_DocumentStructure::ObjectTable.new.table(h) \
+                unless h.nil?
+              tuned_file << t_o
+              h={
+                is_for: :table,
+                obj: '',
+                sym: :table_close,
+                num: @num_id[:table],
+              }
+              t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+              t_o
+            elsif t_o=~/^```[ ]+table\((?:.*?\bh;)?\s+/
+              m1,m2,hd=nil,nil,nil
+              h=case t_o
+              when /^```[ ]+table\(.*?\bh;\s+(.+?)\)\n(.+)\Z/m      #two table representations should be consolidated as one
+                m1,tbl,hd=$1,$2,true
+              when /^```[ ]+table\((.+?)\)\n(.+)\Z/m        #two table representations should be consolidated as one
+                m1,tbl,hd=$1,$2,false
+              else nil
+              end
+              tbl,tags=extract_tags(tbl)
+              col=m1.scan(/\d+/)
+              rws=tbl.split(/\n/)
+              rows=''
+              rws.each do |r|
+                r=r.gsub(/\s*\|\s*/m,"#{Mx[:tc_p]}")       #r.gsub!(/\|/m,"#{Mx[:tc_p]}")
+                rows += r + Mx[:tc_c]
+              end
+              h={
+                head_: hd,
+                cols: col.length,
+                widths: col,
+                obj: rows,
+                idx: idx,
+                tags: tags,
+                num: @num_id[:table],
+              }
+              t_o=SiSU_AO_DocumentStructure::ObjectTable.new.table(h) \
+                unless h.nil?
+              tuned_file << t_o
+              h={
+                is_for: :table,
+                obj: '',
+                sym: :table_close,
+                num: @num_id[:table],
+                }
+              t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+              t_o
+            elsif t_o=~/^\{table\((?:.*?\bh;)?/
+              m1,m2,hd=nil,nil,nil
+              h=case t_o
+              when /\{table\(.*?\bh;\s+(.+?)\)\s*\}\n(.+)\Z/m          #two table representations should be consolidated as one
+                m1,tbl,hd=$1,$2,true
+              when /\{table\((.+?)\)\s*\}\n(.+)\Z/m            #two table representations should be consolidated as one
+                m1,tbl,hd=$1,$2,false
+              else nil
+              end
+              tbl,tags=extract_tags(tbl)
+              col=m1.scan(/\d+/)
+              rws=tbl.split(/\n/)
+              rows=''
+              rws.each do |r|
+                r=r.gsub(/\s*\|\s*/m,"#{Mx[:tc_p]}")       #r.gsub!(/\|/m,"#{Mx[:tc_p]}")
+                rows += r + Mx[:tc_c]
+              end
+              h={
+                head_: hd,
+                cols: col.length,
+                widths: col,
+                obj: rows,
+                idx: idx,
+                tags: tags,
+                num: @num_id[:table],
+              }
+              t_o=SiSU_AO_DocumentStructure::ObjectTable.new.table(h) \
+                unless h.nil?
+              tuned_file << t_o
+              h={
+                is_for: :table,
+                obj: '',
+                sym: :table_close,
+                num: @num_id[:table],
+              }
+              t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+              t_o
+            end
+## depreciated markup, code should work for new markup after removal {
+          elsif t_o =~/^(?:table\{|```[ ]+table|\{table)[ ~]/
+            puts "WARNING document using depreciated markup for tables"
+            puts "use table([table attributes]) instead:"
+            puts "table(){"
+            puts "``` table()"
+            puts "{table()}"
+            @num_id[:table] +=1
+            h={
+              is_for: :table,
+              obj: '',
+              sym: :table_open,
+              num: @num_id[:table],
+            }
+            ins_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+            tuned_file << ins_o
+            if t_o=~/^table\{(?:~h)?\s+/
+              @per.table=:curls
+              @rows=''
+              case t_o
+              when /table\{~h\s+c(\d+);\s+(.+)/
+                cols=$1
+                col=$2.scan(/\d+/)
+                heading=true
+              when /table\{\s+c(\d+);\s+(.+)/
+                cols=$1
+                col=$2.scan(/\d+/)
+                heading=false
+              end
+              @h={
+                head_: heading,
+                cols: cols,
+                widths: col,
+                idx: idx,
+              }
+            elsif t_o=~/^```[ ]+table(?:~h)?\s+c\d+/
+              @per.table=:tics
+              @rows=''
+              case t_o
+              when /^```[ ]+table~h\s+c(\d+);\s+(.+)/
+                cols=$1
+                col=$2.scan(/\d+/)
+                heading=true
+              when /^```[ ]+table\s+c(\d+);\s+(.+)/
+                cols=$1
+                col=$2.scan(/\d+/)
+                heading=false
+              end
+              @h={
+                head_: heading,
+                cols: cols,
+                widths: col,
+                idx: idx,
+              }
+            elsif t_o=~/^\{table(?:~h)?(?:\s+\d+;?)?\}\n.+\Z/m
+              m1,m2,hd=nil,nil,nil
+              tbl=/^\{table(?:~h)?(?:\s+\d+;?)?\}\n(.+)\Z/m.match(t_o)[1]
+              hd=((t_o =~/^\{table~h/) ? true : false)
+              tbl,tags=extract_tags(tbl)
+              rws=tbl.split(/\n/)
+              rows=''
+              cols=nil
+              rws.each do |r|
+                cols=(cols ? cols : (r.scan('|').length) +1)
+                r=r.gsub(/\s*\|\s*/m,"#{Mx[:tc_p]}")       #r.gsub!(/\|/m,"#{Mx[:tc_p]}")
+                rows += r + Mx[:tc_c]
+              end
+              col=[]
+              if t_o =~/^\{table(?:~h)?\s+(\d+);?\}/       #width of col 1 given as %, usually when wider than rest that are even
+                c1=$1.to_i
+                width=(100 - c1)/(cols - 1)
+                col=[ c1 ]
+                (cols - 1).times { col << width }
+              else                                         #all columns of equal width
+                width=100.00/cols
+                cols.times { col << width }
+              end
+              h={
+                head_: hd,
+                cols: cols,
+                widths: col,
+                obj: rows,
+                idx: idx,
+                tags: tags,
+                num: @num_id[:table],
+              }
+              t_o=SiSU_AO_DocumentStructure::ObjectTable.new.table(h) \
+                unless h.nil?
+              tuned_file << t_o
+              h={
+                is_for: :table,
+                obj: '',
+                sym: :table_close,
+                num: @num_id[:table],
+              }
+              t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+              t_o
+            elsif t_o=~/^```[ ]+table(?:~h)?\s+/
+              m1,m2,hd=nil,nil,nil
+              h=case t_o
+              when /^```[ ]+table~h\s+(.+?)\n(.+)\Z/m      #two table representations should be consolidated as one
+                m1,tbl,hd=$1,$2,true
+              when /^```[ ]+table\s+(.+?)\n(.+)\Z/m        #two table representations should be consolidated as one
+                m1,tbl,hd=$1,$2,false
+              else nil
+              end
+              tbl,tags=extract_tags(tbl)
+              col=m1.scan(/\d+/)
+              rws=tbl.split(/\n/)
+              rows=''
+              rws.each do |r|
+                r=r.gsub(/\s*\|\s*/m,"#{Mx[:tc_p]}")       #r.gsub!(/\|/m,"#{Mx[:tc_p]}")
+                rows += r + Mx[:tc_c]
+              end
+              h={
+                head_: hd,
+                cols: col.length,
+                widths: col,
+                obj: rows,
+                idx: idx,
+                tags: tags,
+                num: @num_id[:table],
+              }
+              t_o=SiSU_AO_DocumentStructure::ObjectTable.new.table(h) \
+                unless h.nil?
+              tuned_file << t_o
+              h={
+                is_for: :table,
+                obj: '',
+                sym: :table_close,
+                num: @num_id[:table],
+                }
+              t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+              t_o
+            elsif t_o=~/^\{table(?:~h)?\s+/
+              m1,m2,hd=nil,nil,nil
+              h=case t_o
+              when /\{table~h\s+(.+?)\}\n(.+)\Z/m          #two table representations should be consolidated as one
+                m1,tbl,hd=$1,$2,true
+              when /\{table\s+(.+?)\}\n(.+)\Z/m            #two table representations should be consolidated as one
+                m1,tbl,hd=$1,$2,false
+              else nil
+              end
+              tbl,tags=extract_tags(tbl)
+              col=m1.scan(/\d+/)
+              rws=tbl.split(/\n/)
+              rows=''
+              rws.each do |r|
+                r=r.gsub(/\s*\|\s*/m,"#{Mx[:tc_p]}")       #r.gsub!(/\|/m,"#{Mx[:tc_p]}")
+                rows += r + Mx[:tc_c]
+              end
+              h={
+                head_: hd,
+                cols: col.length,
+                widths: col,
+                obj: rows,
+                idx: idx,
+                tags: tags,
+                num: @num_id[:table],
+              }
+              t_o=SiSU_AO_DocumentStructure::ObjectTable.new.table(h) \
+                unless h.nil?
+              tuned_file << t_o
+              h={
+                is_for: :table,
+                obj: '',
+                sym: :table_close,
+                num: @num_id[:table],
+              }
+              t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+              t_o
+## } depreciated markup, code should (continue to) work for new markup after removal,
+#    when removing depreciated markup check only pass-through for new table attributes format
+#    table(.+?){  ``` table(.+?)  {table(.+?)} formats
+            end
+          end
+          t_o
+        end
+        if @per.table==:curls or @per.table==:tics
+          if (@per.table==:curls \
+          and (t_o.is_a?(String) and t_o =~/^\}table/)) \
+          or (@per.table==:tics \
+          and (t_o.is_a?(String) and t_o =~/^```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$/))
+            @per.table=:off
+            headings,columns,widths,idx=@h[:head_],@h[:cols],@h[:widths],@h[:idx]
+            @h={
+              head_: headings,
+              cols: columns,
+              widths: widths,
+              idx: idx,
+              obj: @rows,
+            }
+            t_o=SiSU_AO_DocumentStructure::ObjectTable.new.table(@h)
+            tuned_file << t_o
+            @h,@rows=nil,''
+            h={
+              is_for: :table,
+              obj: '',
+              sym: :table_close,
+              num: @num_id[:table],
+            }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+            t_o
+          else
+            if t_o.is_a?(String) \
+            and t_o !~/^(?:table\{|```[ ]+table)/
+              t_o=t_o.gsub(/^\n+/m,'').
+                gsub(/\n+/m,"#{Mx[:tc_p]}")
+              @rows += t_o + Mx[:tc_c]
+            end
+            t_o=nil
+          end
+        end
+        if @per.code==:curls \
+        or @per.code==:tics
+          if (@per.code==:curls \
+          && (t_o.is_a?(String) && t_o =~/^\}code/)) \
+          or (@per.code==:tics \
+          && (t_o.is_a?(String) && t_o =~/^```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$/m) \
+          )
+            @per.code=:off
+            if @tuned_code[-1]
+              @tuned_code[-1].
+                gsub!(/\s*(?:#{Mx[:br_line]}|#{Mx[:br_nl]})\s*\Z/m,'')
+            end
+            obj=@tuned_code.join("\n")
+            tags=[]
+            h={
+              obj: obj,
+              idx: idx,
+              syntax: @per.lngsyn,
+              tags: tags,
+              num: @num_id[:code_block],
+              number_: @codeblock_numbered,
+            }
+            @per.lngsyn=:txt
+            t_o=SiSU_AO_DocumentStructure::ObjectBlockTxt.new.code(h)
+            @tuned_code=[]
+            tuned_file << t_o
+            h={
+              is_for: :code,
+              obj: '',
+              sym: :code_close,
+              num: @num_id[:code_block],
+            }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+          end
+          if (@per.code==:curls \
+          || @per.code==:tics) \
+          and t_o.is_a?(String)
+            sub_array=t_o.dup + "#{Mx[:br_nl]}"
+            @line_mode=[]
+            sub_array.scan(/.+/) {|w| @line_mode << w if w =~/[\S]+/}
+            t_o=SiSU_AO_DocumentStructureExtract::Build.new(@md,@line_mode).build_lines(:code).join
+            @tuned_code << t_o
+            t_o=nil
+          end
+        elsif (@per.poem==:curls \
+        || @per.poem==:tics) \
+        or (@per.box==:curls \
+        || @per.box==:tics) \
+        or (@per.group==:curls \
+        || @per.group==:tics) \
+        or (@per.block==:curls \
+        || @per.block==:tics) \
+        or (@per.alt==:curls \
+        || @per.alt==:tics) \
+        or (@per.quote==:open \
+        && (t_o.is_a?(String) && t_o =~/`:quote_close`/m))
+          if (@per.poem==:curls \
+          && (t_o.is_a?(String) && t_o.to_s =~/^\}poem$/m)) \
+          or (@per.poem==:tics \
+          && (t_o.is_a?(String) && t_o =~/^```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$/))
+            @per.poem=:off
+            h={
+              is_for: :poem,
+              obj: '',
+              idx: idx,
+              sym: :poem_close,
+              num: @num_id[:poem],
+            }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+          elsif (@per.box==:curls \
+          && (t_o.is_a?(String) && t_o =~/^\}box/)) \
+          or (@per.box==:tics \
+          && (t_o.is_a?(String) && t_o.to_s =~/^```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$/))
+            @per.box=:off
+            obj,tags=extract_tags(@tuned_block.join("\n"))
+            h={
+              obj: obj,
+              idx: idx,
+              tags: tags,
+              num: @num_id[:box],
+            }
+            @tuned_block=[]
+            t_o=SiSU_AO_DocumentStructure::ObjectBlockTxt.new.box(h)
+            tuned_file << t_o
+            h={
+              is_for: :box,
+              obj: '',
+              idx: idx,
+              sym: :box_close,
+              num: @num_id[:box],
+            }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+          elsif (@per.group==:curls \
+          && ( t_o.is_a?(String) && t_o.to_s =~/^\}group/)) \
+          or (@per.group==:tics \
+          && (t_o.is_a?(String) && t_o.to_s =~/^```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$/))
+            @per.group=:off
+            obj,tags=extract_tags(@tuned_block.join("\n"))
+            h={
+              obj: obj,
+              idx: idx,
+              tags: tags,
+              num: @num_id[:group],
+            }
+            @tuned_block=[]
+            t_o=SiSU_AO_DocumentStructure::ObjectBlockTxt.new.group(h)
+            tuned_file << t_o
+            h={
+              is_for: :group,
+              obj: '',
+              sym: :group_close,
+              num: @num_id[:group],
+            }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+          elsif (@per.block==:curls \
+          && t_o.to_s =~/^\}block/) \
+          or (@per.block==:tics \
+          && (t_o.is_a?(String) \
+            && t_o =~/^```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$/) \
+          )
+            @per.block=:off
+            obj,tags=extract_tags(@tuned_block.join("\n"))
+            h={
+              obj: obj,
+              idx: idx,
+              tags: tags,
+              num: @num_id[:block],
+            }
+            @tuned_block=[]
+            t_o=SiSU_AO_DocumentStructure::ObjectBlockTxt.new.block(h)
+            tuned_file << t_o
+            h={
+              is_for: :block,
+              obj: '',
+              sym: :block_close,
+              num: @num_id[:block],
+            }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+          elsif (@per.alt==:curls \
+          && (t_o.is_a?(String) && t_o =~/^\}alt/)) \
+          or (@per.alt==:tics \
+          && t_o.is_a?(String) \
+            && (t_o =~/^```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$/)
+          )
+            @per.alt=:off
+            obj,tags=extract_tags(@tuned_block.join("\n"))
+            h={
+              obj: obj,
+              idx: idx,
+              tags: tags,
+              num: @num_id[:alt],
+            }
+            t_o=SiSU_AO_DocumentStructure::ObjectBlockTxt.new.alt(h)
+            @tuned_block=[]
+            tuned_file << t_o
+            h={
+              is_for: :alt,
+              obj: '',
+              sym: :alt_close,
+              num: @num_id[:alt],
+            }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+          elsif @per.quote==:open \
+          and (t_o.is_a?(String) &&  t_o =~/`:quote_close`/m)
+            @per.quote=:off
+            h={
+              is_for: :quote,
+              idx: idx,
+              obj: '',
+              sym: :quote_close,
+              num: @num_id[:quote],
+            }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+          elsif @per.quote==:open
+            t_o,tags=extract_tags(t_o)
+            h={
+              indent: 1,
+              obj: t_o,
+              idx: idx,
+              note_: note,
+              image_: image,
+              tags: tags,
+              quote: quotes?,
+            }
+            SiSU_AO_DocumentStructure::ObjectPara.new.paragraph(h)
+          end
+          if (@per.poem==:curls \
+          || @per.poem==:tics) \
+          or (@per.group==:curls \
+          || @per.group==:tics) \
+          or (@per.block==:curls \
+          || @per.block==:tics) \
+          or (@per.alt==:curls \
+          || @per.alt==:tics) \
+          and (t_o.is_a?(String) \
+            and t_o.to_s =~/\S/ \
+            and t_o.to_s !~/^(?:\}(?:verse|code|box|alt|group|block)|(?:verse|code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|alt|group|block)\{)/ \
+            and t_o.to_s !~/^```[ ]+(?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block)|^```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$/
+          )
+            sub_array=t_o.to_s.dup
+            @line_mode=sub_array.scan(/.+/)
+            type=if @per.poem==:curls or @per.poem==:tics
+              t_o=SiSU_AO_DocumentStructureExtract::Build.new(@md,@line_mode).build_lines(type).join
+              poem=t_o.split(/\n\n/)
+              poem.each do |v|
+                v=v.gsub(/\n/m,"#{Mx[:br_nl]}\n")
+                obj,tags=extract_tags(v)
+                h={
+                  obj: obj,
+                  tags: tags,
+                  num: @num_id[:poem],
+                }
+                t_o=SiSU_AO_DocumentStructure::ObjectBlockTxt.new.verse(h)
+                tuned_file << t_o
+              end
+              :poem
+            else :group
+            end
+          end
+          @verse_count+=1 if @per.poem==:curls or @per.poem==:tics
+        end
+        if @per.code==:off
+          if @per.poem==:curls or @per.poem==:tics \
+          or @per.box==:curls or @per.box==:tics \
+          or @per.group==:curls or @per.group==:tics \
+          or @per.block==:curls or @per.block==:tics \
+          or @per.alt==:curls or @per.alt==:tics \
+          or (@per.quote==:open and t_o =~/`:quote_close`/m)
+            if t_o.is_a?(String)
+              t_o=t_o.gsub(/\n/m,"#{Mx[:br_nl]}").
+                gsub(/[ ][ ]/m,"#{Mx[:nbsp]*2}").
+                gsub(/#{Mx[:nbsp]}\s/,"#{Mx[:nbsp]*2}")
+              t_o=t_o + Mx[:br_nl] if t_o =~/\S+/
+            elsif t_o.is==:group \
+            || t_o.is==:block \
+            || t_o.is==:alt \
+            || t_o.is==:box \
+            || t_o.is==:verse
+              t_o.obj=t_o.obj.gsub(/\n/m,"#{Mx[:br_nl]}").
+                gsub(/[ ][ ]/m,"#{Mx[:nbsp]*2}").
+                gsub(/#{Mx[:nbsp]}\s/,"#{Mx[:nbsp]*2}")
+            end
+            @tuned_block << t_o if t_o.to_s =~/\S+/
+          else tuned_file << t_o
+          end
+        else tuned_file << t_o
+        end
+      end
+      tuned_file
+    end
+    def identify_parts
+      tuned_file=[]
+      @tuned_block,@tuned_code=[],[]
+      @@counter,@verse_count=0,0
+      @num_id={
+        code_block: 0,
+        poem:       0,
+        box:        0,
+        block:      0,
+        group:      0,
+        alt:        0,
+        quote:      0,
+        table:      0,
+      }
+      @metadata={}
+      if @md.flag_auto_biblio \
+      or @md.flag_biblio
+        @data,bibliography=SiSU_AO_Appendices::Bibliography.new(@md,@data).biblio_extraction
+      end
+      if @md.flag_glossary
+        @data,glossary=SiSU_AO_Appendices::Glossary.new(@md,@data).glossary_extraction
+      end
+      tuned_file=extract_structure_loop(@data,tuned_file)
+      if @md.flag_endnotes
+        tuned_file << @pb
+        h={
+          ln: 1,
+          lc: 1,
+          obj: 'Endnotes',
+          autonum_: false,
+        }
+        tuned_file << SiSU_AO_DocumentStructure::ObjectHeading.new.heading_insert(h)
+        h={
+          ln: 4,
+          lc: 2,
+          obj: 'Endnotes',
+          name: 'endnotes',
+          autonum_: false,
+        }
+        tuned_file << SiSU_AO_DocumentStructure::ObjectHeading.new.heading_insert(h)
+        h={
+          obj: 'Endnotes'
+        }
+      end
+      if @md.flag_glossary
+        tuned_file << @pb
+        h={
+          ln: 1,
+          lc: 1,
+          obj: 'Glossary',
+          autonum_: false,
+        }
+        tuned_file << SiSU_AO_DocumentStructure::ObjectHeading.new.heading_insert(h)
+        h={
+          ln: 4,
+          lc: 2,
+          obj: 'Glossary',
+          name: 'glossary',
+          autonum_: false,
+        }
+        tuned_file << SiSU_AO_DocumentStructure::ObjectHeading.new.heading_insert(h)
+        h={
+          obj: 'Glossary'
+        }
+        if glossary.length > 0
+          tuned_file=extract_structure_loop(glossary,tuned_file)
+        end
+      end
+      if @md.flag_auto_biblio
+        tuned_file << @pb
+        h={
+          ln: 1,
+          lc: 1,
+          obj: 'References',
+          autonum_: false,
+        }
+        tuned_file << SiSU_AO_DocumentStructure::ObjectHeading.new.heading_insert(h)
+        h={
+          ln: 4,
+          lc: 2,
+          obj: 'Bibliography',
+          name: 'biblio',
+          autonum_: false,
+        }
+        tuned_file << SiSU_AO_DocumentStructure::ObjectHeading.new.heading_insert(h)
+        h={
+          obj: 'Bibliography'
+        }
+        citenumber=0
+        bibliography.each do |cite|
+          citenumber +=1 if cite.is_a?(Hash)
+          h={
+            obj: cite[:obj],
+            #obj: %{[#{citenumber}] } + cite[:obj],
+            tags: [cite[:id]],
+            hang: 0,
+            indent: 2,
+            ocn_: false,
+          }
+          tuned_file << SiSU_AO_DocumentStructure::ObjectPara.new.paragraph(h)
+        end
+      elsif @md.flag_biblio
+        tuned_file << @pb
+        h={
+          ln: 1,
+          lc: 1,
+          obj: 'References',
+          autonum_: false,
+        }
+        tuned_file << SiSU_AO_DocumentStructure::ObjectHeading.new.heading_insert(h)
+        h={
+          ln: 4,
+          lc: 2,
+          obj: 'Bibliography',
+          name: 'biblio',
+          autonum_: false,
+        }
+        tuned_file << SiSU_AO_DocumentStructure::ObjectHeading.new.heading_insert(h)
+        h={
+          obj: 'Bibliography'
+        }
+        if not bibliography.nil? \
+        and bibliography.length > 0
+          tuned_file=extract_structure_loop(bibliography,tuned_file)
+        else
+          tuned_file, citations =
+            SiSU_AO_Appendices::Citations.new(@md,tuned_file).songsheet  # ao_appendices.rb
+          citenumber=0
+          citations.compact.each do |c|
+            citenumber +=1 if c.is_a?(Hash)
+            if c[:is]==:book
+              h={
+                obj: %{#{c[:author]}. /{#{c[:publication]}}/ (#{c[:year]})},
+                #obj: %{[#{citenumber}] *{#{c[:author]}}* /{#{c[:publication]}}/ (#{c[:year]})},
+                hang: 0,
+                indent: 2,
+                ocn_: false,
+              }
+              tuned_file << SiSU_AO_DocumentStructure::ObjectPara.new.paragraph(h)
+            elsif c[:is]==:article
+              h={
+                obj: %{#{c[:author]}. /{"#{c[:title]}"}/ #{c[:publication]} editor #{c[:editor]} (#{c[:year]})},
+                #obj: %{[#{citenumber}] *{#{c[:author]}}* /{"#{c[:title]}"}/ #{c[:publication]} editor #{c[:editor]} (#{c[:year]})},
+                hang: 0,
+                indent: 2,
+                ocn_: false,
+              }
+              tuned_file << SiSU_AO_DocumentStructure::ObjectPara.new.paragraph(h)
+            end
+          end
+        end
+      end
+      if @md.book_idx
+        tuned_file << @pb
+        h={
+          ln: 1,
+          lc: 1,
+          obj: 'Index',
+          autonum_: false,
+        }
+        tuned_file << SiSU_AO_DocumentStructure::ObjectHeading.new.heading_insert(h)
+        h={
+          ln: 4,
+          lc: 2,
+          obj: 'Index',
+          name: 'book_index',
+          autonum_: false,
+        }
+        tuned_file << SiSU_AO_DocumentStructure::ObjectHeading.new.heading_insert(h)
+        h={
+          obj: 'Index'
+        }
+      end
+      tuned_file << @pb
+      if @make.build.metadata?
+        h={
+          ln: 1,
+          lc: 1,
+          obj: 'Metadata',
+          autonum_: false,
+          ocn_: false,
+        }
+        tuned_file << SiSU_AO_DocumentStructure::ObjectHeading.new.heading_insert(h)
+        h={
+          ln: 4,
+          lc: 2,
+          obj: 'SiSU Metadata, document information',
+          name: 'metadata',
+          autonum_: false,
+          ocn_: false,
+        }
+        tuned_file << SiSU_AO_DocumentStructure::ObjectHeading.new.heading_insert(h)
+      end
+      h={
+        obj: 'eof',
+      }
+      meta=SiSU_AO_DocumentStructure::ObjectMetadata.new.metadata(@metadata)
+      [tuned_file,meta,bibliography,glossary]
+    end
+    def table_rows_and_columns_array(table_str)
+      table=[]
+      table_str.split(/#{Mx[:tc_c]}/).each do |table_row|
+        table_row_with_columns=table_row.split(/#{Mx[:tc_p]}/)
+        table << table_row_with_columns
+      end
+      table
+    end
+    def meta_heading(h)
+      h={
+        lv: h[:lv],
+        ln: h[:ln],
+        name: h[:name],
+        obj: h[:obj],
+        ocn: '0',
+      }
+      SiSU_AO_DocumentStructure::ObjectHeading.new.heading(h)
+    end
+    def meta_para(str)
+      h={
+        obj: str,
+        ocn_: false,
+      }
+      SiSU_AO_DocumentStructure::ObjectPara.new.paragraph(h)
+    end
+    def build_lines(type=:none)
+      lines=@data
+      lines.each.map do |line|
+        line=if line =~/\S/ \
+        and line !~/^(?:code(?:\.[a-z][0-9a-z_]+)?\{|\}code)/ \
+        and line !~/^(?:```[ ]+code(?:\.[a-z][0-9a-z_]+)?|```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$)/ \
+        and not line.is_a?(Hash) #watch
+          @@counter+=1 if @per.code==:curls or @per.code==:tics
+          line=line.gsub(/\s\s/,"#{Mx[:nbsp]*2}").
+            gsub(/#{Mx[:nbsp]}\s/,"#{Mx[:nbsp]*2}")
+          line=line.gsub(/^/,"#{Mx[:gr_o]}codeline#{Mx[:gr_c]}") if type==:code # REMOVE try sort for texpdf special case
+          line=if line =~/(?:https?|file|ftp):\/\/\S+$/
+            line.gsub(/\s*$/," #{Mx[:br_nl]}")
+          else line.gsub(/\s*$/,"#{Mx[:br_nl]}")           #unless type=='code'
+          end
+        elsif line =~/^\s*$/
+          line.gsub(/\s*$/,"#{Mx[:br_nl]}")
+        else line
+        end
+        line
+      end
+    end
+  end
+  class Structure                                          # this must happen early
+    def initialize(md)
+      @md=md
+    end
+    def structure(data)
+      data.compact.each do |dob|
+        structure_markup(dob)
+      end
+    end
+    def structure_markup(dob)                                   #build structure where structure provided only in meta header
+      dob=if dob.is==:para \
+      && (((dob.hang !~/[1-9]/) && (dob.indent !~/[1-9]/)) \
+      || (dob.hang != dob.indent)) \
+      and not dob.bullet_
+        dob=case dob.obj
+        when /^#{@md.lv0}/
+          h={
+            is: :heading,
+            lv: 'A',
+            ln: 0,
+          }
+          SiSU_AO_DocumentStructure::ObjectHeading.new.heading(h,dob)
+        when /^#{@md.lv1}/
+          h={
+            is: :heading,
+            lv: 'B',
+            ln: 1,
+          }
+          SiSU_AO_DocumentStructure::ObjectHeading.new.heading(h,dob)
+        when /^#{@md.lv2}/
+          h={
+            is: :heading,
+            lv: 'C',
+            ln: 2,
+          }
+          SiSU_AO_DocumentStructure::ObjectHeading.new.heading(h,dob)
+        when /^#{@md.lv3}/
+          h={
+            is: :heading,
+            lv: 'D',
+            ln: 3,
+          }
+          SiSU_AO_DocumentStructure::ObjectHeading.new.heading(h,dob)
+        when /^#{@md.lv4}/
+          h={
+            is: :heading,
+            lv: '1',
+            ln: 4,
+          }
+          SiSU_AO_DocumentStructure::ObjectHeading.new.heading(h,dob)
+        when /^#{@md.lv5}/
+          h={
+            is: :heading,
+            lv: '2',
+            ln: 5,
+          }
+          SiSU_AO_DocumentStructure::ObjectHeading.new.heading(h,dob)
+        when /^#{@md.lv6}/
+          h={
+            is: :heading,
+            lv: '3',
+            ln: 6,
+          }
+          SiSU_AO_DocumentStructure::ObjectHeading.new.heading(h,dob)
+        else dob
+        end
+      else dob
+      end
+      dob
+    end
+  end
+  class OCN
+    def initialize(md,data,fnx,process)
+      @md,@data,@fnx,@process=md,data,fnx,process
+    end
+    def structure_info
+      def lv
+        %w[A~ B~ C~ D~ 1 2 3 4]
+      end
+      def possible_parents(child)
+        case child
+        when /A~/ then 'none'
+        when /B~/ then 'A~'
+        when /C~/ then 'B~'
+        when /D~/ then 'C~'
+        when /1/  then 'A~, B~, C~, D~'
+        when /2/  then '1'
+        when /3/  then '2'
+        when /4/  then '3'
+        end
+      end
+      def possible_children(parent)
+        case parent
+        when /A~/ then 'B~, 1'
+        when /B~/ then 'C~, 1'
+        when /C~/ then 'D~, 1'
+        when /D~/ then '1'
+        when /1/  then '2'
+        when /2/  then '3'
+        when /3/  then '4'
+        when /4/  then 'none'
+        end
+      end
+      self
+    end
+    def document_structure_check_info(node,node_parent,status=:ok)
+      node_ln=/^([0-7])/.match(node)[1].to_i
+      node_parent_ln=/^([0-7])/.match(node_parent)[1].to_i
+      if status==:error \
+      or @md.opt.act[:maintenance][:set]==:on
+        puts %{node: #{node},    parent node: #{node_parent}  #{status.upcase}}
+        if status==:error
+          node_ln=/^([0-7])/.match(node)[1].to_i
+          node_parent_ln=/^([0-7])/.match(node_parent)[1].to_i
+          STDERR.puts %{current level: #{structure_info.lv[node_ln]} (possible parent levels: #{structure_info.possible_parents(structure_info.lv[node_ln])})
+parent level:  #{structure_info.lv[node_parent_ln]} (possible child levels: #{structure_info.possible_children(structure_info.lv[node_parent_ln])})
+SKIPPED processing file:
+[#{@md.opt.lng}] "#{@md.fns}"}
+          if @md.opt.act[:no_stop][:set]==:on
+            $process_document = :skip
+          else exit
+          end
+        end
+      end
+    end
+    def warning_incorrect_parent_level_or_level(txt)
+      puts %{ERROR. There is an error in markup of heading levels either here or in the parent heading.
+The current header reads:
+"#{txt}"
+has incorrect level and/or parent level
+--}
+    end
+    def required_headers_present?
+      if @process == :complete
+        unless (defined? @md.title \
+        and @md.title.full)
+           STDERR.puts %{required header missing:
+
+@title:
+SKIPPED processing file:
+[#{@md.opt.lng}] "#{@md.fns}"
+}
+          if @md.opt.act[:no_stop][:set]==:on
+            $process_document = :skip
+          else exit
+          end
+        end
+        unless (defined? @md.creator.author \
+        and @md.creator.author)
+           STDERR.puts %{required header missing:
+
+@creator:
+ :author: anonymous?
+SKIPPED processing file:
+[#{@md.opt.lng}] "#{@md.fns}"
+}
+          if @md.opt.act[:no_stop][:set]==:on
+            $process_document = :skip
+          else exit
+          end
+        end
+      end
+    end
+    def ocn                                                                      #and auto segment numbering increment
+      required_headers_present?
+      data=@data
+      @o_array=[]
+      node=ocn=ocn_dv=ocn_sp=ocnh=ocnh0=ocnh1=ocnh2=ocnh3=ocnh4=ocnh5=ocnh6=ocnh7=ocno=ocnp=ocnt=ocnc=ocng=ocni=ocnu=0 # h heading, o other, t table, g group, i image
+      regex_exclude_ocn_and_node = /#{Rx[:meta]}|^@\S+?:\s|^4~endnotes|^#{Mx[:lv_o]}4:endnotes#{Mx[:lv_c]}|^\^~ |<:e[:_]\d+?>|^<:\#|<:- |<[:!]!4|<hr width|#{Mx[:br_endnotes]}|\A\s*\Z/mi #ocn here #&nbsp; added with Tune.code #¡
+      parent=node1=node2=node3=node4=node5=node6=node7=nil
+      node0='0:0;0'
+      @collapsed_lv0=0
+      @lev_occurences={ a: 0, b: 0, c: 0, d: 0, l1: 0, l2: 0, l3: 0, l4: 0 }
+      data.each do |dob|
+        h={}
+        if (dob.obj !~ regex_exclude_ocn_and_node || dob.is==:code) \
+        && (dob.of !=:comment \
+        && dob.of !=:layout \
+        && dob.of !=:meta) \
+        && dob.ocn_
+          #dob.ln now is determined, and set earlier, check how best to remove this -->
+          if dob.is==:heading
+             @ln=ln=case dob.lv
+             when 'A' then 0
+             when 'B' then 1
+             when 'C' then 2
+             when 'D' then 3
+             when '1' then 4
+             when '2' then 5
+             when '3' then 6
+             when '4' then 7
+             when '5' then 8
+             when '6' then 9
+             end
+          end
+          if not dob.obj =~/~#|-#/
+            ocn+=1
+          end
+          if @process == :complete \
+          or (@fnx == @md.opt.fns \
+          && @md.opt.fns =~/.sst$/)
+            if dob.is==:heading \
+            and (ln.to_s =~/^[0-9]/ \
+            or ln.to_s =~@md.lv0 \
+            or ln.to_s =~@md.lv1 \
+            or ln.to_s =~@md.lv2 \
+            or ln.to_s =~@md.lv3 \
+            or ln.to_s =~@md.lv4 \
+            or ln.to_s =~@md.lv5 \
+            or ln.to_s =~@md.lv6 \
+            or ln.to_s =~@md.lv7)
+              if not dob.obj =~/~#|-#/
+                ocnh+=1
+              end
+              if ln==0 \
+              or ln.to_s =~@md.lv0
+                @lev_occurences[:a] += 1
+                if not dob.obj =~/~#|-#/
+                  ocn_flag=true
+                  ocnh0+=1                     #heading
+                  node0="0:#{ocnh0};#{ocn}"
+                else
+                  #document_structure_check_info(node0,node0,:error) #fix
+                  ocn_flag=false
+                  node0="0:0;0"
+                end
+                document_structure_check_info(node0,node0)
+                @collapsed_lv0=0
+                collapsed_level=@collapsed_lv0
+                node,ocn_sp,parent=node0,"h#{ocnh}",'ROOT'
+              elsif ln==1 \
+              or ln.to_s =~@md.lv1
+                @lev_occurences[:b] += 1
+                if not dob.obj =~/~#|-#/
+                  ocn_flag=true
+                  ocnh1+=1                     #heading
+                  node1="1:#{ocnh1};#{ocn}"
+                else
+                  #document_structure_check_info(node0,node0,:error) #fix
+                  ocn_flag=false
+                  node1="1:0;0"
+                end
+                parent=if node0
+                  document_structure_check_info(node1,node0)
+                  @collapsed_lv1=@collapsed_lv0+1
+                  node0
+                else
+                  warning_incorrect_parent_level_or_level(dob.obj)
+                  document_structure_check_info(node0,node0,:error)
+                  node0
+                end
+                collapsed_level=@collapsed_lv1
+                node,ocn_sp,parent=node1,"h#{ocnh}",node0 #FIX
+              elsif ln==2 \
+              or ln.to_s =~@md.lv2
+                @lev_occurences[:c] += 1
+                if not dob.obj =~/~#|-#/
+                  ocn_flag=true
+                  ocnh2+=1
+                  node2="2:#{ocnh2};#{ocn}"
+                else
+                  #document_structure_check_info(node0,node0,:error) #fix
+                  ocn_flag=false
+                  node2="2:0;0"
+                end
+                parent=if node1
+                  document_structure_check_info(node2,node1)
+                  @collapsed_lv2=@collapsed_lv1+1
+                  node1
+                else
+                  warning_incorrect_parent_level_or_level(dob.obj)
+                  document_structure_check_info(node2,node0,:error)
+                  node0
+                end
+                collapsed_level=@collapsed_lv2
+                node,ocn_sp=node2,"h#{ocnh}"
+              elsif ln==3 \
+              or ln.to_s =~@md.lv3
+                @lev_occurences[:d] += 1
+                if not dob.obj =~/~#|-#/
+                  ocn_flag=true
+                  ocnh3+=1
+                  node3="3:#{ocnh3};#{ocn}"
+                else
+                  #document_structure_check_info(node0,node0,:error) #fix
+                  ocn_flag=false
+                  node3="3:0;0"
+                end
+                parent=if node2
+                  document_structure_check_info(node3,node2)
+                  @collapsed_lv3=@collapsed_lv2+1
+                  node2
+                elsif node1
+                  warning_incorrect_parent_level_or_level(dob.obj)
+                  puts %{parent is :A~ & this level #{dob.lv}
+either parent should be level :B~
+or this level should be level :B~ rather than #{dob.lv}}
+                  document_structure_check_info(node3,node1,:error)
+                  @collapsed_lv3=@collapsed_lv1+1
+                  node1
+                else
+                  document_structure_check_info(node3,node0,:error)
+                  warning_incorrect_parent_level_or_level(dob.obj)
+                  node0
+                end
+                collapsed_level=@collapsed_lv3
+                node,ocn_sp=node3,"h#{ocnh}"
+              elsif ln==4 \
+              or ln.to_s =~@md.lv4
+                @lev_occurences[:l1] += 1
+                if not dob.obj =~/~#|-#/
+                  ocn_flag=true
+                  ocnh4+=1
+                  node4="4:#{ocnh4};#{ocn}"
+                else
+                  ocn_flag=false
+                  node4="4:0;0"
+                end
+                parent=if node3
+                  document_structure_check_info(node4,node3)
+                  @collapsed_lv4=@collapsed_lv3+1
+                  node3
+                elsif node2
+                  document_structure_check_info(node4,node2)
+                  @collapsed_lv4=@collapsed_lv2+1
+                  node2
+                elsif node1
+                  document_structure_check_info(node4,node1)
+                  @collapsed_lv4=@collapsed_lv1+1
+                  node1
+                elsif node0
+                  document_structure_check_info(node4,node0)
+                  @collapsed_lv4=@collapsed_lv0+1
+                  node0
+                else
+                  warning_incorrect_parent_level_or_level(dob.obj)
+                  document_structure_check_info(node4,node0,:error)
+                  node0
+                end
+                collapsed_level=@collapsed_lv4
+                node,ocn_sp=node4,"h#{ocnh}"
+              elsif ln==5 \
+              or ln.to_s =~@md.lv5
+                @lev_occurences[:l2] += 1
+                if not dob.obj =~/~#|-#/
+                  ocn_flag=true
+                  ocnh5+=1
+                  node5="5:#{ocnh5};#{ocn}"
+                else
+                  ocn_flag=false
+                  node5="5:0;0"
+                end
+                parent=if node4
+                  document_structure_check_info(node5,node4)
+                  @collapsed_lv5=@collapsed_lv4+1
+                  node4
+                elsif node3
+                  warning_incorrect_parent_level_or_level(dob.obj)
+                  document_structure_check_info(node5,node3,:error)
+                  @collapsed_lv5=@collapsed_lv3+1
+                  node3
+                elsif node2
+                  warning_incorrect_parent_level_or_level(dob.obj)
+                  document_structure_check_info(node5,node2,:error)
+                  @collapsed_lv5=@collapsed_lv2+1
+                  node2
+                elsif node1
+                  warning_incorrect_parent_level_or_level(dob.obj)
+                  document_structure_check_info(node5,node1,:error)
+                  @collapsed_lv5=@collapsed_lv1+1
+                  node1
+                else
+                  warning_incorrect_parent_level_or_level(dob.obj)
+                  document_structure_check_info(node5,node0,:error)
+                  node0
+                end
+                collapsed_level=@collapsed_lv5
+                node,ocn_sp=node5,"h#{ocnh}"
+              elsif ln==6 \
+              or ln.to_s =~@md.lv6
+                @lev_occurences[:l3] += 1
+                if not dob.obj =~/~#|-#/
+                  ocn_flag=true
+                  ocnh6+=1
+                  node6="6:#{ocnh6};#{ocn}"
+                else
+                  ocn_flag=false
+                  node6="6:0;0"
+                end
+                parent=if node5
+                  document_structure_check_info(node6,node5)
+                  @collapsed_lv6=@collapsed_lv5+1
+                  node5
+                elsif node4
+                  warning_incorrect_parent_level_or_level(dob.obj)
+                  puts "parent is level #4 (1~) & this level ##{dob.ln} (#{dob.lv}~)
+either parent should be level #5 (2~)
+or this level should be #5 (2~) rather ##{dob.ln} (#{dob.lv}~)"
+                  document_structure_check_info(node6,node4,:error)
+                  @collapsed_lv6=@collapsed_lv4+1
+                  node4
+                elsif node3
+                  warning_incorrect_parent_level_or_level(dob.obj)
+                  document_structure_check_info(node6,node3,:error)
+                  @collapsed_lv6=@collapsed_lv3+1
+                  node3
+                elsif node2
+                  warning_incorrect_parent_level_or_level(dob.obj)
+                  document_structure_check_info(node6,node2,:error)
+                  @collapsed_lv6=@collapsed_lv2+1
+                  node2
+                elsif node1
+                  warning_incorrect_parent_level_or_level(dob.obj)
+                  document_structure_check_info(node6,node1,:error)
+                  @collapsed_lv6=@collapsed_lv1+1
+                  node1
+                else
+                  warning_incorrect_parent_level_or_level(dob.obj)
+                  document_structure_check_info(node6,node0,:error)
+                  node0
+                end
+                collapsed_level=@collapsed_lv6
+                node,ocn_sp=node6,"h#{ocnh}"
+              elsif ln==7 \
+              or ln.to_s =~@md.lv7
+                @lev_occurences[:l4] += 1
+                if not dob.obj =~/~#|-#/
+                  ocn_flag=true
+                  ocnh7+=1
+                  node7="7:#{ocnh7};#{ocn}"
+                else
+                  ocn_flag=false
+                  node7="7:0;0"
+                end
+                parent=if node6
+                  document_structure_check_info(node7,node6)
+                  @collapsed_lv7=@collapsed_lv6+1
+                  node5
+                elsif node5
+                  warning_incorrect_parent_level_or_level(dob.obj)
+                  puts "parent is level #5 (2~) & this level ##{dob.ln} (#{dob.lv}~)
+either parent should be level #6 (3~)
+or this level should be #6 (3~) rather ##{dob.ln} (#{dob.lv}~)"
+                  document_structure_check_info(node7,node5,:error)
+                  @collapsed_lv6=@collapsed_lv5+1
+                  node5
+                elsif node4
+                  warning_incorrect_parent_level_or_level(dob.obj)
+                  puts "parent is level #4 (1~) & this level ##{dob.ln} (#{dob.lv}~)
+either parent should be level 6~
+or this level should be #6 (3~) rather ##{dob.ln} (#{dob.lv}~)"
+                  document_structure_check_info(node7,node4,:error)
+                  @collapsed_lv6=@collapsed_lv4+1
+                  node4
+                elsif node3
+                  warning_incorrect_parent_level_or_level(dob.obj)
+                  document_structure_check_info(node7,node3,:error)
+                  @collapsed_lv6=@collapsed_lv3+1
+                  node3
+                elsif node2
+                  warning_incorrect_parent_level_or_level(dob.obj)
+                  document_structure_check_info(node7,node2,:error)
+                  @collapsed_lv6=@collapsed_lv2+1
+                  node2
+                elsif node1
+                  warning_incorrect_parent_level_or_level(dob.obj)
+                  document_structure_check_info(node7,node1,:error)
+                  @collapsed_lv6=@collapsed_lv1+1
+                  node1
+                else
+                  warning_incorrect_parent_level_or_level(dob.obj)
+                  document_structure_check_info(node7,node0,:error)
+                  node0
+                end
+                collapsed_level=@collapsed_lv7
+                node,ocn_sp=node7,"h#{ocnh}"
+              end
+            else
+              unless @lev_occurences[:l1] > 0
+                STDERR.puts %{Substantive text objects must follow a level 1~ heading and there are none at this point in processing: #{@lev_occurences[:l1]}
+SKIPPED processing file:
+[#{@md.opt.lng}] "#{@md.fns}"}
+                puts dob.obj #.gsub(/^(.{1,80})/,'"\1"')
+                exit
+              end
+              unless @ln >= 4
+                lev=case @ln
+                when 0 then 'A'
+                when 1 then 'B'
+                when 2 then 'C'
+                when 3 then 'D'
+                when 4 then '1'
+                when 5 then '2'
+                when 6 then '3'
+                when 7 then '4'
+                when 8 then '5'
+                when 9 then '6'
+                end
+                STDERR.puts %{Substantive text objects must follow a level 1~ 2~ or 3~ heading: #{lev}~
+SKIPPED processing file:
+[#{@md.opt.lng}] "#{@md.fns}"}
+                puts dob.obj.gsub(/^(.{1,80})/,'"\1"')
+                if @md.opt.act[:no_stop][:set]==:on
+                  $process_document = :skip
+                  break
+                else exit
+                end
+              end
+              if not dob.obj =~/~#|-#/
+                ocn_flag=true
+              else
+                ocn_flag=false
+              end
+              ocno+=1
+              if dob.is==:table
+                ocnt+=1
+                ocn_sp,parent="t#{ocnt}",node
+              elsif dob.is==:code
+                ocnc+=1
+                ocn_sp,parent="c#{ocnc}",node
+              elsif dob.is==:group \
+              || dob.is==:box \
+              || dob.is==:block \
+              || dob.is==:alt \
+              || dob.is==:verse
+                ocng+=1 #group, poem
+                ocn_sp,parent="g#{ocng}",node
+              elsif dob.is==:image #check
+                ocni+=1
+                ocn_sp,parent="i#{ocni}",node
+              else ocnp+=1                                 #paragraph
+                ocn_sp,parent="p#{ocnp}",node
+              end
+            end
+          end
+          if dob.is==:heading
+            if ocn_flag==true
+              dob.ln,dob.node,dob.ocn,dob.ocn_,dob.odv,dob.osp,dob.parent,dob.lc=
+                ln,  node,    ocn,    ocn_flag, ocn_dv,ocn_sp, parent,    collapsed_level
+            else
+              ocnu+=1
+              heading_use=:ok
+              if dob.obj=~/#{Mx[:pa_non_object_no_heading]}/
+                dob.obj=dob.obj.gsub(/#{Mx[:pa_non_object_no_heading]}/,'')
+                heading_use=:ok
+              elsif dob.obj=~/#{Mx[:pa_non_object_dummy_heading]}/
+                dob.obj=dob.obj.gsub(/#{Mx[:pa_non_object_dummy_heading]}/,'')
+                heading_use=:dummy
+              end
+              dob.ln,dob.node,dob.ocn,dob.ocn_,dob.use_,   dob.odv,dob.osp,dob.parent,dob.lc=
+                ln,  node,    nil,    ocn_flag,heading_use,ocn_dv, ocn_sp, parent,    collapsed_level
+            end
+          else
+            if dob.of !=:meta \
+            && dob.of !=:comment \
+            && dob.of !=:layout
+              if ocn_flag == true
+                dob.ocn,dob.ocn_,dob.odv,dob.osp,dob.parent=
+                  ocn,  ocn_flag,ocn_dv, ocn_sp, parent
+              else
+                ocnu+=1
+                dob.obj=dob.obj.gsub(/#{Mx[:fa_o]}[~-]##{Mx[:fa_c]}/,'') if dob.obj
+                ocn_dv,ocn_sp="u#{ocnu}","u#{ocnu}"
+                dob.ocn,dob.ocn_,dob.odv,dob.osp,dob.parent=
+                  nil,  ocn_flag,ocn_dv, ocn_sp, parent
+              end
+            end
+          end
+          h
+        else dob
+        end
+        if dob.is==:code \
+        || dob.is==:verse \
+        || dob.is==:alt \
+        || dob.is==:box \
+        || dob.is==:group \
+        || dob.is==:block
+          dob.obj=dob.obj.gsub(/\n+/,"\n") #newlines taken out
+        end
+        @o_array << dob
+      end
+      if @process == :complete \
+      or (@fnx == @md.opt.fns \
+      && @md.opt.fns =~/.sst$/)
+        unless @lev_occurences[:a] == 1
+          STDERR.puts %{The number of level A~ in this document: #{@lev_occurences[:a]}
+There must be one level A~ (no more and no less)
+SKIPPED processing file:
+[#{@md.opt.lng}] "#{@md.fns}"}
+          if @md.opt.act[:no_stop][:set]==:on
+            $process_document = :skip
+          else exit
+          end
+        end
+        unless @lev_occurences[:l1] > 0
+          STDERR.puts %{The number of level 1~ in this document: #{@lev_occurences[:l1]}
+There must be at least one level 1~ (and as many as required)
+SKIPPED processing file:
+[#{@md.opt.lng}] "#{@md.fns}"}
+          if @md.opt.act[:no_stop][:set]==:on
+            $process_document = :skip
+          else exit
+          end
+        end
+      end
+      @o_array
+    end
+  end
+  class XML
+    def initialize(md,data)
+      @data,@md=data,md
+    end
+    def dom
+      @s=[ 'A', 'B', 'C', 'D', '1', '2', '3' ]
+      tuned_file=structure_build
+      tuned_file
+    end
+    def spaces
+      Ax[:spaces]
+    end
+    def structure_build
+      data=@data
+      tuned_file=[]
+      hs=[0,false,false,false]
+      t={
+        lv: @s[0],
+        status: :open,
+      }
+      tuned_file << tags(t)
+      if @md.opt.act[:verbose_plus][:set]==:on
+        puts "\nXML sisu structure outline --->\n"
+        puts "<#{@s[0]}>"
+      end
+      data.each_with_index do |o,i|
+        if o.is==:heading \
+        || o.is==:heading_insert
+          case o.ln
+          when 0
+            tuned_file << tag_close(o.ln,hs)
+            tuned_file << tag_open(o,@s)
+            if @md.opt.act[:verbose_plus][:set]==:on
+              puts_tag_close(o.ln,hs)
+              puts_tag_open(o,@s)
+            end
+            hs=[0,true,false,false,false]
+          when 1
+            tuned_file << tag_close(o.ln,hs)
+            tuned_file << tag_open(o,@s)
+            if @md.opt.act[:verbose_plus][:set]==:on
+              puts_tag_close(o.ln,hs)
+              puts_tag_open(o,@s)
+            end
+            hs=[1,true,true,false,false]
+          when 2
+            tuned_file << tag_close(o.ln,hs)
+            tuned_file << tag_open(o,@s)
+            if @md.opt.act[:verbose_plus][:set]==:on
+              puts_tag_close(o.ln,hs)
+              puts_tag_open(o,@s)
+            end
+            hs=[2,true,true,true,false]
+          when 3
+            tuned_file << tag_close(o.ln,hs)
+            tuned_file << tag_open(o,@s)
+            if @md.opt.act[:verbose_plus][:set]==:on
+              puts_tag_close(o.ln,hs)
+              puts_tag_open(o,@s)
+            end
+            hs=[3,true,true,true,true]
+          when 4
+            tuned_file << tag_close(o.ln,hs)
+            tuned_file << tag_open(o,@s)
+            if @md.opt.act[:verbose_plus][:set]==:on
+              puts_tag_close(o.ln,hs)
+              puts_tag_open(o,@s)
+            end
+            hs[0]=4
+          when 5
+            tuned_file << tag_close(o.ln,hs)
+            tuned_file << tag_open(o,@s)
+            if @md.opt.act[:verbose_plus][:set]==:on
+              puts_tag_close(o.ln,hs)
+              puts_tag_open(o,@s)
+            end
+            hs[0]=5
+          when 6
+            tuned_file << tag_close(o.ln,hs)
+            tuned_file << tag_open(o,@s)
+            if @md.opt.act[:verbose_plus][:set]==:on
+              puts_tag_close(o.ln,hs)
+              puts_tag_open(o,@s)
+            end
+            hs[0]=6
+          end
+        end
+        tuned_file << o
+      end
+      if @md.opt.act[:verbose_plus][:set]==:on
+        puts_tag_close(0,hs)
+      end
+      tuned_file << tag_close(0,hs)
+      tuned_file=tuned_file.flatten
+    end
+    def tags(o)
+      tag=(o[:status]==:open) \
+      ? %{<#{o[:lv]} id="#{o[:node]}">}
+      : "</#{o[:lv]}>"
+      ln=case o[:lv]
+      when 'A' then 0
+      when 'B' then 1
+      when 'C' then 2
+      when 'D' then 3
+      when '1' then 4
+      when '2' then 5
+      when '3' then 6
+      when '4' then 7
+      when '5' then 8
+      when '6' then 9
+      end
+      h={
+        tag: tag,
+        node: o[:node],
+        lv: o[:lv],
+        ln: ln,
+        status: o[:status],
+      }
+      SiSU_AO_DocumentStructure::ObjectStructure.new.xml_dom(h) #downstream code utilise else ignore like comments
+    end
+    def tag_open(o,tag)
+      t={ lv: tag[o.ln], node: o.node, status: :open }
+      t_o=tags(t)
+      t_o
+    end
+    def tag_close(lev,hs)
+      ary=[]
+      case hs[0]
+      when 0
+        if (lev <= 0) and hs[0]
+          t={
+            lv: @s[0],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+      when 1
+        if (lev <= 1) and hs[1]
+          t={
+            lv: @s[1],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev==0)
+          t={
+            lv: @s[0],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+      when 2
+        if (lev <= 2) and hs[2]
+          t={
+            lv: @s[2],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev <= 1) and hs[1]
+          t={
+            lv: @s[1],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev==0)
+          t={
+            lv: @s[0],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+      when 3
+        if (lev <= 3) and hs[3]
+          t={
+            lv: @s[3],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev <= 2) and hs[2]
+          t={
+            lv: @s[2],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev <= 1) and hs[1]
+          t={
+            lv: @s[1],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev==0)
+          t={
+            lv: @s[0],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+      when 4
+        if (lev <= 4)
+          t={
+            lv: @s[4],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev <= 3) and hs[3]
+          t={
+            lv: @s[3],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev <= 2) and hs[2]
+          t={
+            lv: @s[2],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev <= 1) and hs[1]
+          t={
+            lv: @s[1],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev==0)
+          t={
+            lv: @s[0],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+      when 5
+        if (lev <= 5)
+          t={
+            lv: @s[5],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev <= 4)
+          t={
+            lv: @s[4],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev <= 3) and hs[3]
+          t={
+            lv: @s[3],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev <= 2) and hs[2]
+          t={
+            lv: @s[2],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev <= 1) and hs[1]
+          t={
+            lv: @s[1],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev==0)
+          t={
+            lv: @s[0],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+      when 6
+        if (lev <= 6)
+          t={
+            lv: @s[6],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev <= 5)
+          t={
+            lv: @s[5],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev <= 4)
+          t={
+            lv: @s[4],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev <= 3) and hs[3]
+          t={
+            lv: @s[3],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev <= 2) and hs[2]
+          t={
+            lv: @s[2],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev <= 1) and hs[1]
+          t={
+            lv: @s[1],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+        if (lev==0)
+          t={
+            lv: @s[0],
+            status: :close,
+          }
+          ary << tags(t)
+        end
+      end
+      ary
+    end
+    def puts_tag_open(o,tag)
+      puts %{#{spaces*o.ln}<#{tag[o.ln]} id="#{o.node}">}
+    end
+    def puts_tag_close(lev,hs)
+      case hs[0]
+      when 0
+        #puts "#{spaces*0}</#{@s[0]}>" if (lev <= 0) and hs[0]
+        puts "</#{@s[0]}>"         if (lev==0)
+      when 1
+        puts "#{spaces*1}</#{@s[1]}>" if (lev <= 1) and hs[1]
+        puts "</#{@s[0]}>"         if (lev==0)
+      when 2
+        puts "#{spaces*2}</#{@s[2]}>" if (lev <= 2) and hs[2]
+        puts "#{spaces*1}</#{@s[1]}>" if (lev <= 1) and hs[1]
+        puts "</#{@s[0]}>"         if (lev==0)
+      when 3
+        puts "#{spaces*3}</#{@s[3]}>" if (lev <= 3) and hs[3]
+        puts "#{spaces*2}</#{@s[2]}>" if (lev <= 2) and hs[2]
+        puts "#{spaces*1}</#{@s[1]}>" if (lev <= 1) and hs[1]
+        puts "</#{@s[0]}>"         if (lev==0)
+      when 4
+        puts "#{spaces*4}</#{@s[4]}>" if (lev <= 4)
+        puts "#{spaces*3}</#{@s[3]}>" if (lev <= 3) and hs[3]
+        puts "#{spaces*2}</#{@s[2]}>" if (lev <= 2) and hs[2]
+        puts "#{spaces*1}</#{@s[1]}>" if (lev <= 1) and hs[1]
+        puts "</#{@s[0]}>"         if (lev==0)
+      when 5
+        puts "#{spaces*5}</#{@s[5]}>" if (lev <= 5)
+        puts "#{spaces*4}</#{@s[4]}>" if (lev <= 4)
+        puts "#{spaces*3}</#{@s[3]}>" if (lev <= 3) and hs[3]
+        puts "#{spaces*2}</#{@s[2]}>" if (lev <= 2) and hs[2]
+        puts "#{spaces*1}</#{@s[1]}>" if (lev <= 1) and hs[1]
+        puts "</#{@s[0]}>"         if (lev==0)
+      when 6
+        puts "#{spaces*6}</#{@s[6]}>" if (lev <= 6)
+        puts "#{spaces*5}</#{@s[5]}>" if (lev <= 5)
+        puts "#{spaces*4}</#{@s[4]}>" if (lev <= 4)
+        puts "#{spaces*3}</#{@s[3]}>" if (lev <= 3) and hs[3]
+        puts "#{spaces*2}</#{@s[2]}>" if (lev <= 2) and hs[2]
+        puts "#{spaces*1}</#{@s[1]}>" if (lev <= 1) and hs[1]
+        puts "</#{@s[0]}>"         if (lev==0)
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** ao_endnotes.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/ao_endnotes.rb_"
+# <<sisu_document_header>>
+module SiSU_AO_Endnotes
+  class Endnotes
+    def initialize(md,data,endnote_array=nil)
+      @md,@data,@endnote_array=
+      md, data, endnote_array
+      @endnote_counter,
+        @endnote_counter_asterisk,
+        @endnote_counter_dag=
+        1,1,1
+    end
+    def endnotes
+      data=@data
+      endnote_ref=1
+      @tuned_file=data.each.map do |dob|
+                                                                               # manually numbered endnotes <!e(\d)!> <!e_(\d)!> -->
+        if @md.opt.selections.str =~/--no-asterisk|--no-annotate/
+          dob.obj=dob.obj.
+            gsub(/#{Mx[:en_b_o]}\s.+?#{Mx[:en_b_c]}/,'')
+        end
+        if @md.opt.selections.str =~/--no-dagger|--no-annotate/
+          dob.obj=dob.obj.
+            gsub(/#{Mx[:en_b_o]}[+]\s.+?#{Mx[:en_b_c]}/,'')
+        end
+        if (defined? dob.obj) \
+        && (defined? dob.is) \
+        && dob.is !=:code
+          case dob.obj                                                         # auto-numbered endnotes <!e!> <!e_!> -->
+          when /#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}[*+]\s+.+?#{Mx[:en_b_c]}/
+            dob.obj=dob.obj.
+              gsub(/\s*(#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/,'\1')
+            word_mode=dob.obj.scan(/\S+/m)
+            word_mode=endnote_call_number(word_mode)
+            dob.obj=word_mode.join(' ')
+            endnote_ref+=1
+          when /~\^(?:\s|$)/                                              #%note inserts endnotes previously gathered from /^(<!e[:_]!>|[-~]\{{3})/ (in earlier loop)
+            word_mode=dob.obj.scan(/\S+/m)
+            word_mode=endnote_call_number(word_mode)
+            dob.obj=word_mode.join(' ')
+            endnote_ref+=1
+          end
+        end
+        dob
+      end.flatten
+      @endnote_counter,
+        @endnote_counter_asterisk,
+        @endnote_counter_dag=
+        1,1,1
+      @tuned_file
+    end
+    def endnote_call_number(words)
+      words.each do |word|
+        case word
+        when /#{Mx[:en_a_o]}/
+          unless word =~/#{Mx[:en_a_o]}[*+]+/
+            word.gsub!(/#{Mx[:en_a_o]}/,
+              "#{Mx[:en_a_o]}#{@endnote_counter} ")
+            @endnote_counter+=1
+          end
+        when /#{Mx[:en_b_o]}/
+          if word =~/#{Mx[:en_b_o]}[+]/
+            word.gsub!(/#{Mx[:en_b_o]}[+]/,
+              "#{Mx[:en_b_o]}\+#{@endnote_counter_dag} ")
+            @endnote_counter_dag+=1
+          else
+            word.gsub!(/#{Mx[:en_b_o]}[*]?/,
+              "#{Mx[:en_b_o]}\*#{@endnote_counter_asterisk} ")
+            @endnote_counter_asterisk+=1
+          end
+        when /~\^/
+          if @endnote_array
+            word.gsub!(/~\^/,
+              "#{@endnote_array[@endnote_counter-1]}")
+            @endnote_counter+=1
+          end
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** ao_expand_insertions.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/ao_expand_insertions.rb"
+# <<sisu_document_header>>
+module SiSU_AO_Insertions
+  class Insertions
+    def initialize(md,data)
+      @md,@data=md,data
+    end
+    def output_filetypes_in_cmd(cmd_shortcut,lnk=nil) #make list of file types in shortcut command (as configured), e.g. when sisu -3 is used
+      act_defaults=SiSU_Env::InfoProcessingFlag.new
+      cmd_list=case cmd_shortcut.inspect #check on expectation, string v array
+      when /0/ then act_defaults.act_0.str
+      when /1/ then act_defaults.act_1.str
+      when /2/ then act_defaults.act_2.str
+      when /3/ then act_defaults.act_3.str
+      when /4/ then act_defaults.act_4.str
+      when /5/ then act_defaults.act_5.str
+      when /6/ then act_defaults.act_6.str
+      when /7/ then act_defaults.act_7.str
+      when /8/ then act_defaults.act_8.str
+      when /9/ then act_defaults.act_9.str
+      end
+      file_type_names={}
+      file_type_names[:gen],file_type_names[:src]=[],[]
+      file_type_names[:gen] <<= if cmd_list =~ /\b--manifest\b/
+        "~^ { document manifest }#{lnk[:manifest]}"
+      end
+      file_type_names[:gen] <<= if cmd_list =~ /\b--html\b/
+        [
+          " { html, segmented text }#{lnk[:html_toc]}",
+          " { html, scroll, document in one }#{lnk[:html_doc]}",
+        ]
+      end
+      file_type_names[:gen] <<= if cmd_list =~ /\b--epub\b/
+        [" { epub }#{lnk[:epub]}"]
+      end
+      file_type_names[:gen] <<= if cmd_list =~ /\b--pdf\b/ \
+      or cmd_list =~ /--pdf-landscape/
+        [
+          " { pdf, landscape }#{lnk[:pdf_landscape]}",
+        ]
+      end
+      file_type_names[:gen] <<= if cmd_list =~ /\b--pdf\b/ \
+      or cmd_list =~ /--pdf-portrait/
+        [
+          " { pdf, portrait }#{lnk[:pdf_portrait]}",
+        ]
+      end
+      file_type_names[:gen] <<= if cmd_list =~ /\b(?:--odt|--odf)\b/
+        " { odf:odt, open document text }#{lnk[:odt]}"
+      end
+      file_type_names[:gen] <<= if cmd_list =~ /\b--xhtml\b/
+        " { xhtml scroll }#{lnk[:xhtml]}"
+      end
+      file_type_names[:gen] <<= if cmd_list =~ /\b--docbook\b/
+        " { docbook }#{lnk[:docbook]}" #CHECK
+      end
+      file_type_names[:gen] <<= if cmd_list =~ /\b--xml-sax\b/
+        " { xml, sax }#{lnk[:xml_sax]}"
+      end
+      file_type_names[:gen] <<= if cmd_list =~ /\b--xml-dom\b/
+        " { xml, dom }#{lnk[:xml_dom]}"
+      end
+      file_type_names[:gen] <<= if cmd_list =~ /\b(?:--txt|--text|--plaintext)\b/
+        " { plain text utf-8 }#{lnk[:txt]}"
+      end
+      #file_type_names[:gen] <<= if cmd_list =~ /g/
+      #  'wiki.txt'
+      #end
+      file_type_names[:gen] <<= if cmd_list =~ /\b--concordance\b/
+        " { concordance }#{lnk[:html_concordance]}"
+      end
+      file_type_names[:gen] <<= if cmd_list =~ /\b--digest\b/
+        " { dcc, document content certificate (digests) }#{lnk[:digest]}"
+      end
+      file_type_names[:src] <<= if source and cmd_shortcut =~ /\b--source\b/
+        " { markup source text }#{lnk[:source]}"
+      end
+      file_type_names[:src] <<= if cmd_shortcut =~ /\b--sisupod\b/
+        " { markup source (zipped) pod }#{lnk[:sisupod]}"
+      end
+      file_type_names[:gen]=file_type_names[:gen].flatten
+      file_type_names[:src]=file_type_names[:src].flatten
+      file_type_names
+    end
+    def by_language(linked_doc,lng,src=nil)
+      @linked_doc,@lng,@src=linked_doc,lng,src
+      @base_path="#{@md.file.output_path.base.url}/#{lng}"
+      def fnh
+        {
+          fn: @linked_doc,
+        }
+      end
+      def path_and_file(fn,pth)
+        @base_path + '/' + pth + '/' + fn
+      end
+      def manifest
+        fn=@md.file.base_filename.manifest(fnh)
+        path_and_file(fn,'manifest')
+      end
+      def html_toc
+        fn=@md.file.base_filename.html_segtoc(fnh)
+        @base_path + '/html/' + @linked_doc + '/' + fn
+      end
+      def html_doc
+        fn=@md.file.base_filename.html_scroll(fnh)
+        path_and_file(fn,'html')
+      end
+      def html_concordance
+        fn=@md.file.base_filename.html_concordance
+        @base_path + '/html/' + @linked_doc + '/' + fn
+      end
+      def epub
+        fn=@md.file.base_filename.epub(fnh)
+        path_and_file(fn,'epub')
+      end
+      def pdf_landscape
+        fn=@md.file.base_filename.pdf_l_a4(fnh)
+        path_and_file(fn,'pdf')
+      end
+      def pdf_portrait
+        fn=@md.file.base_filename.pdf_p_a4(fnh)
+        path_and_file(fn,'pdf')
+      end
+      def odt
+        fn=@md.file.base_filename.odt(fnh)
+        path_and_file(fn,'odt')
+      end
+      def xhtml
+        fn=@md.file.base_filename.xhtml(fnh)
+        path_and_file(fn,'xhtml')
+      end
+      def docbook
+        fn=@md.file.base_filename.xml_docbook_book(fnh)
+        path_and_file(fn,'docbook')
+      end
+      def xml_sax
+        fn=@md.file.base_filename.xml_sax(fnh)
+        path_and_file(fn,'xml_sax')
+      end
+      def xml_dom
+        fn=@md.file.base_filename.xml_dom(fnh)
+        path_and_file(fn,'xml_dom')
+      end
+      def txt
+        fn=@md.file.base_filename.txt(fnh)
+        path_and_file(fn,'txt')
+      end
+      def digest
+        fn=@md.file.base_filename.hash_digest(fnh)
+        path_and_file(fn,'digest')
+      end
+      def source
+        @base_path + '/src/' + @src
+      end
+      def sisupod
+        @base_path + '/src/' + @src + '.zip'
+      end
+      self
+    end
+    def by_filetype(linked_doc,lng,src=nil)
+      @linked_doc,@lng,@src=linked_doc,lng,src
+      @lc=SiSU_Env::FilenameLanguageCodeInsert.new(@md.opt,lng).
+        language_code_insert
+      @base_path="#{@md.file.output_path.base.url}"
+      def fnh
+        {
+          fn: @linked_doc,
+          lng: @lc,
+        }
+      end
+      def path_and_file(fn,pth)
+        @base_path + '/' + pth + '/' + fn
+      end
+      def manifest
+        fn=@md.file.base_filename.manifest(fnh)
+        path_and_file(fn,'manifest')
+      end
+      def html_toc
+        fn=@md.file.base_filename.html_segtoc(fnh)
+        path_and_file(fn,'html')
+      end
+      def html_doc
+        fn=@md.file.base_filename.html_scroll(fnh)
+        path_and_file(fn,'html')
+      end
+      def html_concordance
+        fn=@md.file.base_filename.html_concordance
+        path_and_file(fn,'html')
+      end
+      def epub
+        fn=@md.file.base_filename.epub(fnh)
+        path_and_file(fn,'epub')
+      end
+      def pdf_landscape
+        fn=@md.file.base_filename.pdf_l_a4(fnh)
+        path_and_file(fn,'pdf')
+      end
+      def pdf_portrait
+        fn=@md.file.base_filename.pdf_p_a4(fnh)
+        path_and_file(fn,'pdf')
+      end
+      def odt
+        fn=@md.file.base_filename.odt(fnh)
+        path_and_file(fn,'odt')
+      end
+      def xhtml
+        fn=@md.file.base_filename.xhtml(fnh)
+        path_and_file(fn,'xhtml')
+      end
+      def docbook
+        fn=@md.file.base_filename.xml_docbook_book(fnh)
+        path_and_file(fn,'docbook')
+      end
+      def xml_sax
+        fn=@md.file.base_filename.xml_sax(fnh)
+        path_and_file(fn,'xml_sax')
+      end
+      def xml_dom
+        fn=@md.file.base_filename.xml_dom(fnh)
+        path_and_file(fn,'xml_dom')
+      end
+      def txt
+        fn=@md.file.base_filename.txt(fnh)
+        path_and_file(fn,'txt')
+      end
+      def digest
+        fn=@md.file.base_filename.hash_digest(fnh)
+        path_and_file(fn,'digest')
+      end
+      def source
+        @base_path + '/src/' + @src
+      end
+      def sisupod
+        @base_path + '/src/' + @src + '.zip'
+      end
+      self
+    end
+    def by_filename(linked_doc,lng,src=nil)
+      @linked_doc,@lng,@src=linked_doc,lng,src
+      @lc=SiSU_Env::FilenameLanguageCodeInsert.new(@md.opt,lng).language_code_insert
+      @base_path="#{@md.file.output_path.base.url}/#{@linked_doc}"
+      def fnh
+        {
+          fn: @linked_doc,
+          lng: @lc,
+        }
+      end
+      def path_and_file(fn,pth=nil)
+        (pth.nil?) \
+        ? @base_path + '/' + fn
+        : @base_path + '/' + pth + '/' + fn
+      end
+      def manifest
+        fn=@md.file.base_filename.manifest(fnh)
+        path_and_file(fn)
+      end
+      def html_toc
+        fn=@md.file.base_filename.html_segtoc(fnh)
+        path_and_file(fn)
+      end
+      def html_doc
+        fn=@md.file.base_filename.html_scroll(fnh)
+        path_and_file(fn)
+      end
+      def html_concordance
+        fn=@md.file.base_filename.html_concordance
+        path_and_file(fn)
+      end
+      def epub
+        fn=@md.file.base_filename.epub(fnh)
+        path_and_file(fn,'epub')
+      end
+      def pdf_landscape
+        fn=@md.file.base_filename.pdf_l_a4(fnh)
+        path_and_file(fn)
+      end
+      def pdf_portrait
+        fn=@md.file.base_filename.pdf_p_a4(fnh)
+        path_and_file(fn)
+      end
+      def odt
+        fn=@md.file.base_filename.odt(fnh)
+        path_and_file(fn)
+      end
+      def xhtml
+        fn=@md.file.base_filename.xhtml(fnh)
+        path_and_file(fn)
+      end
+      def docbook
+        fn=@md.file.base_filename.xml_docbook_book(fnh)
+        path_and_file(fn)
+      end
+      def xml_sax
+        fn=@md.file.base_filename.xml_sax(fnh)
+        path_and_file(fn)
+      end
+      def xml_dom
+        fn=@md.file.base_filename.xml_dom(fnh)
+        path_and_file(fn)
+      end
+      def txt
+        fn=@md.file.base_filename.txt(fnh)
+        path_and_file(fn)
+      end
+      def digest
+        fn=@md.file.base_filename.hash_digest(fnh)
+        path_and_file(fn)
+      end
+      def source
+        @base_path + '/' + @src
+      end
+      def sisupod
+        @base_path + '/' + @src + '.zip'
+      end
+      self
+    end
+    def expand_insertions?
+      data=@data
+      tuned_file,tuned_file_tmp=[],[]
+      codeblock_={
+        status: :false,
+        type:   :na,
+      }
+      data.each do |para|
+        codeblock_=if para =~/^code(?:\.[a-z][0-9a-z_]+)?\{/ \
+        and codeblock_[:status]==:false
+          {
+            status: :true,
+            type:   :curl,
+          }
+        elsif para =~/^```[ ]+code(?:\.[a-z][0-9a-z_]+)?/ \
+        and codeblock_[:status]==:false
+          {
+            status: :true,
+            type:   :tics,
+          }
+        elsif codeblock_[:type]==:curl \
+        and para =~/^\}code/m
+          {
+            status: :false,
+            type:   :na,
+          }
+        elsif codeblock_[:type]==:tics \
+        and para =~/^```(?:\s|$)/m
+          {
+            status: :false,
+            type:   :na,
+          }
+        else codeblock_
+        end
+        if para !~/^%+\s/ \
+        and codeblock_[:status] != :true \
+        and para =~/\{(?:~\^\s+)?(.+?)\s\[(?:\d(?:[sS]*))\]\}(?:\.\.\/\S+?\/|\S+?\.ss[tm]\b)/
+          @u=SiSU_Env::InfoEnv.new.url
+          m_cmd=''
+          if defined? @u.remote
+            if /(?<m_pre>.+?)\{(?<m_txt>.+?)\s\[(?<m_cmd>\d[sS]*)\]\}(?<m_source>(?<m_linked_doc>\S+?)\.ss[tm]\b)(?<m_note>.*)/m =~ para
+              m_pre=m_pre.strip
+            elsif /\{(?<m_txt>.+?)\s\[(?<m_cmd>\d[sS]*)\]\}(?<m_source>(?<m_linked_doc>\S+?)\.ss[tm]\b)(?<m_note>.*)/m =~ para
+            end
+            if m_linked_doc =~ /(\S+?)\/(\S+)/
+              m_linked_doc,m_linked_doc_lang=$1,$2
+            else
+              m_linked_doc,m_linked_doc_lang=m_linked_doc,@md.opt.lng_base
+            end
+          else
+            puts "error, does currently support relative paths (reltive paths were removed, as had problems for citation, and was not suited to all output types should possibly reconsider) #{__FILE__} #{__LINE__}"
+            if /\{(?:~\^\s+)?(?<m_txt>.+?)\s\[(?<m_cmd>\d[sS]*)\]\}\.\.\/(?<m_linked_doc>\S+?)\/(?<m_note>\s+#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]})?/ =~ para
+            end
+          end
+          lnk=case @md.opt.dir_structure_by
+          when :language
+            {
+              manifest:         by_language(m_linked_doc,m_linked_doc_lang).manifest,
+              html_toc:         by_language(m_linked_doc,m_linked_doc_lang).html_toc,
+              html_doc:         by_language(m_linked_doc,m_linked_doc_lang).html_doc,
+              epub:             by_language(m_linked_doc,m_linked_doc_lang).epub,
+              pdf_landscape:    by_language(m_linked_doc,m_linked_doc_lang).pdf_landscape,
+              pdf_portrait:     by_language(m_linked_doc,m_linked_doc_lang).pdf_landscape,
+              odt:              by_language(m_linked_doc,m_linked_doc_lang).odt,
+              xhtml:            by_language(m_linked_doc,m_linked_doc_lang).xhtml,
+              docbook:          by_language(m_linked_doc,m_linked_doc_lang).docbook,
+              xml_sax:          by_language(m_linked_doc,m_linked_doc_lang).xml_sax,
+              xml_dom:          by_language(m_linked_doc,m_linked_doc_lang).xml_dom,
+              txt:              by_language(m_linked_doc,m_linked_doc_lang).txt,
+              html_concordance: by_language(m_linked_doc,m_linked_doc_lang).html_concordance,
+              digest:           by_language(m_linked_doc,m_linked_doc_lang).digest,
+              sisupod:          by_language(m_linked_doc,m_linked_doc_lang,m_source).sisupod,
+              source:           by_language(m_linked_doc,m_linked_doc_lang,m_source).source,
+            }
+          when :filetype
+            {
+              manifest:         by_filetype(m_linked_doc,m_linked_doc_lang).manifest,
+              html_toc:         by_filetype(m_linked_doc,m_linked_doc_lang).html_toc,
+              html_doc:         by_filetype(m_linked_doc,m_linked_doc_lang).html_doc,
+              epub:             by_filetype(m_linked_doc,m_linked_doc_lang).epub,
+              pdf_landscape:    by_filetype(m_linked_doc,m_linked_doc_lang).pdf_landscape,
+              pdf_portrait:     by_filetype(m_linked_doc,m_linked_doc_lang).pdf_landscape,
+              odt:              by_filetype(m_linked_doc,m_linked_doc_lang).odt,
+              xhtml:            by_filetype(m_linked_doc,m_linked_doc_lang).xhtml,
+              docbook:          by_filetype(m_linked_doc,m_linked_doc_lang).docbook,
+              xml_sax:          by_filetype(m_linked_doc,m_linked_doc_lang).xml_sax,
+              xml_dom:          by_filetype(m_linked_doc,m_linked_doc_lang).xml_dom,
+              txt:              by_filetype(m_linked_doc,m_linked_doc_lang).txt,
+              html_concordance: by_filetype(m_linked_doc,m_linked_doc_lang).html_concordance,
+              digest:           by_filetype(m_linked_doc,m_linked_doc_lang).digest,
+              sisupod:          by_filetype(m_linked_doc,m_linked_doc_lang,m_source).sisupod,
+              source:           by_filetype(m_linked_doc,m_linked_doc_lang,m_source).source,
+            }
+          else
+            {
+              manifest:         by_filename(m_linked_doc,m_linked_doc_lang).manifest,
+              html_toc:         by_filename(m_linked_doc,m_linked_doc_lang).html_toc,
+              html_doc:         by_filename(m_linked_doc,m_linked_doc_lang).html_doc,
+              epub:             by_filename(m_linked_doc,m_linked_doc_lang).epub,
+              pdf_landscape:    by_filename(m_linked_doc,m_linked_doc_lang).pdf_landscape,
+              pdf_portrait:     by_filename(m_linked_doc,m_linked_doc_lang).pdf_landscape,
+              odt:              by_filename(m_linked_doc,m_linked_doc_lang).odt,
+              xhtml:            by_filename(m_linked_doc,m_linked_doc_lang).xhtml,
+              docbook:          by_filename(m_linked_doc,m_linked_doc_lang).docbook,
+              xml_sax:          by_filename(m_linked_doc,m_linked_doc_lang).xml_sax,
+              xml_dom:          by_filename(m_linked_doc,m_linked_doc_lang).xml_dom,
+              txt:              by_filename(m_linked_doc,m_linked_doc_lang).txt,
+              html_concordance: by_filename(m_linked_doc,m_linked_doc_lang).html_concordance,
+              digest:           by_filename(m_linked_doc,m_linked_doc_lang).digest,
+              sisupod:          by_filename(m_linked_doc,m_linked_doc_lang,m_source).sisupod,
+              source:           by_filename(m_linked_doc,m_linked_doc_lang,m_source).source,
+            }
+          end
+          linked_title="#{m_pre}{#{m_txt} }#{lnk[:manifest]}#{m_note}\n\n"
+          tuned_file_tmp << linked_title
+          output_filetypes=output_filetypes_in_cmd(m_cmd,lnk)
+          output_filetypes[:gen].each do |desc|
+            if desc
+              tuned_file_tmp << if @u.remote
+                "#{Mx[:nbsp]*4} #{desc} "
+              else # remove ...
+                "[provide document placement host location]"
+              end
+            end
+          end
+          output_filetypes[:src].each do |desc|
+            if desc
+              tuned_file_tmp << if @u.remote
+                "#{Mx[:nbsp]*4} #{desc} "
+              else
+                "[provide document placement host location]"
+              end
+            end
+          end
+          tuned_file << 'group{' << tuned_file_tmp.join("\n") << '}group'
+          tuned_file_tmp=[]
+        else tuned_file << para
+        end
+      end
+      tuned_file
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** ao_hash_digest.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/ao_hash_digest.rb"
+# <<sisu_document_header>>
+module SiSU_AO_Hash
+  require_relative 'shared_markup_alt.rb'               #shared_markup_alt.rb
+  class ObjectDigest
+    def initialize(md,data,env=nil)
+      @md,@data,@env=md,data,env
+      @env ||=SiSU_Env::InfoEnv.new(@md.fns,@md)
+    end
+    def object_digest
+    # 1. clean/stripped text without any markup, paragraph, headings etc. without endnotes
+    # 2. endnotes clean/stripped text digest only (there may be several endnotes within a paragraph)
+    # 3. whole object, text with markup and any endnotes, (question: with or without the endnote digests??? presumption better without, [however may be easier to check with?])
+    # [digests should not include other digests]
+      data=@data.compact
+      @tuned_file=[]
+      sha_ =@env.digest(@md.opt).type
+      begin
+        sha_ ? (require 'digest/sha2') : (require 'digest/md5')
+      rescue LoadError
+        SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).error(sha_ + ' NOT FOUND')
+      end
+      data.each do |t_o|
+        unless t_o.obj.is_a?(Array)
+          t_o.obj=t_o.obj.strip
+        end
+        if (t_o.of !=:structure \
+        && t_o.of  !=:comment \
+        && t_o.of  !=:layout) \
+        && t_o.ocn.is_a?(Fixnum)
+          case sha_
+          when :sha512
+            for hash_class in [ Digest::SHA512 ]
+              @tuned_file << stamped(t_o,hash_class)
+            end
+          when :sha256
+            for hash_class in [ Digest::SHA256 ]
+              @tuned_file << stamped(t_o,hash_class)
+            end
+          when :md5
+            for hash_class in [ Digest::MD5 ]
+              @tuned_file << stamped(t_o,hash_class)
+            end
+          end
+        else @tuned_file << t_o unless t_o.nil?
+        end
+      end
+      @tuned_file=@tuned_file.flatten
+      #use md5 or to create hash of each ao object including ocn, & add into to each ao object
+    end
+    def endnote_digest(data)
+      data.each.map do |en_plus|
+        case en_plus
+        when /#{Mx[:en_a_o]}|#{Mx[:en_b_o]}/
+          if en_plus =~/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/
+            t_o_txt,en_open,en_txt,en_close=
+              /(.*?)(#{Mx[:en_a_o]}|#{Mx[:en_b_o]})(.+?)(#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/m.
+              match(en_plus)[1..4]
+            stripped_en=SiSU_TextRepresentation::Alter.new(en_txt).strip_clean_of_markup
+            digest_en_strip=case @env.digest(@md.opt).type
+            when :sha512
+              Digest::SHA512.hexdigest(stripped_en)
+            when :sha256
+              Digest::SHA256.hexdigest(stripped_en)
+            when :md5
+              Digest::MD5.hexdigest(stripped_en)
+            else
+              Digest::SHA256.hexdigest(stripped_en)
+            end
+            t_o_txt +
+              en_open +
+              en_txt +
+              Mx[:id_o] +
+              digest_en_strip +
+              Mx[:id_c] +
+              en_close
+          else STDERR.puts "Error Exception - problem encountered with:\n#{en_plus}" #arbitrary exception, tidy up
+          end
+        else en_plus
+        end
+      end.join
+    end
+    def stamped(t_o,hash_class) #decide what hash information is most useful, is compromise necessary?
+      t_o.obj=SiSU_TextRepresentation::Alter.new(t_o).strip_clean_of_extra_spaces
+      #SiSU_TextRepresentation::Alter.new(t_o).strip_clean_of_markup                      #check
+      #SiSU_TextRepresentation::Alter.new(t_o).semi_revert_markup                         #check
+      #SiSU_TextRepresentation::ModifiedTextPlusHashDigest.new(@md,t_o).composite.dgst    #check
+      unless t_o.is==:code
+        case t_o.obj
+        when /#{Mx[:en_a_o]}[\d*+]+\s+.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}[*+]\d+\s+.+?#{Mx[:en_b_c]}/m
+          en_and_t_o_digest=[]
+          t_o.obj=t_o.obj.
+            gsub(/\s*(#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/m,' \1') #watch
+          t_o_plus_en=t_o.obj.
+            scan(/.*?#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|.*?#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/m)
+          t_o_tail=if t_o.obj =~/(?:.*?#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|.*?#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})+([\s\S]+)/m
+            /(?:.*?#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|.*?#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})+.*/m.match(t_o.obj)[1]
+          else ''
+          end
+          t_o_plus_en << t_o_tail
+          en_and_t_o_digest << endnote_digest(t_o_plus_en)
+          en_and_t_o_digest.join(' ')
+        else #@tuned << t_o + Mx[:id_o] + digest_strip + ':' + digest_all + Mx[:id_c] unless t_o.nil?
+        end
+      else #@tuned << t_o + Mx[:id_o] + digest_strip + ':' + digest_all + Mx[:id_c] unless t_o.nil?
+      end
+      t_o #KEEP intact
+    end
+    def strip_clean_extra_spaces(s)                                            # ao output tuned
+      s=s.dup
+      s=s.gsub(/[ ]+([,.;:?](?:$|\s))/,'\1') unless s =~/#{Mx[:en_a_o]}|#{Mx[:en_b_o]}/
+      s=s.gsub(/ [ ]+/,' ').
+        gsub(/^ [ ]+/,'').
+        gsub(/ [ ]+$/,'').
+        gsub(/((?:#{Mx[:fa_bold_c]}|#{Mx[:fa_italics_c]})')[ ]+(s )/,'\1\2').
+        gsub(/((?:#{Mx[:fa_bold_c]}|#{Mx[:fa_italics_c]})')[ ]+(s )/,'\1\2')
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** ao_idx.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/ao_idx.rb"
+# <<sisu_document_header>>
+module SiSU_AO_BookIndex
+  class BookIndex
+    def initialize(md,data,env=nil)
+      @md,@data,@env=md,data,env
+      @rgx_idx=/#{Mx[:idx_o]}(?:.+?)#{Mx[:idx_c]}\s*/
+      @rgx_idx_ocn_seg=/(.+?)~(\d+)~(\S+)/
+      @rgx_idx_ocn=/(.+?)~(\d+)/
+      @env ||=SiSU_Env::InfoEnv.new(@md.fns)
+    end
+    def indexing_song
+      data=@data
+      data,
+        sisu_markup_idx_rel,
+        sisu_markup_idx_rel_html_seg,
+        html_idx,xhtml_idx=
+          extract_book_index(data)
+      data=
+        clean_and_insert_index(
+          data,
+          sisu_markup_idx_rel_html_seg
+        )
+      [
+        data,
+        sisu_markup_idx_rel,
+        sisu_markup_idx_rel_html_seg,
+        html_idx,
+        xhtml_idx,
+      ]
+    end
+    def extract_book_index(data)
+      tuned_file=[]
+      idx_array=[]
+      data.each do |dob|
+        if (dob.is ==:heading \
+        || dob.is ==:heading_insert) \
+        && dob.ln==4
+          @seg=dob.name
+        end
+        if defined? dob.idx \
+        and dob.idx.is_a?(Hash)
+          idx_array << {
+            idx: dob.idx,
+            ocn: dob.ocn,
+            seg: @seg
+          }
+        end
+        tuned_file << dob if dob
+      end
+      if idx_array.length > 0
+        the_idx=construct_book_index(idx_array)
+        if @md.book_idx
+          idx=index(the_idx)
+          sisu_markup_idx_rel,sisu_markup_idx_rel_html_seg,html_idx,  xhtml_idx=
+            idx[:sst_rel],    idx[:sst_rel_html_seg],      idx[:html],idx[:xhtml]
+        else
+          sisu_markup_idx_rel=
+            sisu_markup_idx_rel_html_seg=
+            html_idx=
+            xhtml_idx=
+            nil
+        end
+      end
+      [
+        tuned_file,
+        sisu_markup_idx_rel,
+        sisu_markup_idx_rel_html_seg,
+        html_idx,
+        xhtml_idx,
+      ]
+    end
+    def construct_book_index(idx_array)
+      the_idx={}
+      idx_array.each do |idx|
+        idx[:idx].each_pair do |term,term_info|
+          location=(term_info[:plus].to_i > 0) \
+          ? (%{#{idx[:ocn]}-#{idx[:ocn].to_i + term_info[:plus].to_i}})
+          : idx[:ocn].to_s
+          the_idx[term]={} \
+            unless the_idx[term] \
+            and defined? the_idx[term]
+          the_idx[term]['node_0_terms']=[] \
+            unless the_idx[term]['node_0_terms'] \
+            and defined? the_idx[term]['node_0_terms']
+          the_idx[term]['node_0_terms'] << { ocn: idx[:ocn], range: location, seg: idx[:seg] }
+          if term_info[:sub].is_a?(Array) \
+          and term_info[:sub].length > 0
+            term_info[:sub].each do |y|
+              y.each_pair do |subterm,subterm_info|
+                location=(subterm_info[:plus].to_i > 0) \
+                ? (%{#{idx[:ocn]}-#{idx[:ocn].to_i + subterm_info[:plus].to_i}})
+                : idx[:ocn].to_s
+                the_idx[term]={} \
+                  unless the_idx[term] \
+                  and defined? the_idx[term]
+                the_idx[term]['node_0_terms']=[] \
+                  unless the_idx[term]['node_0_terms']\
+                  and    defined? the_idx[term]['node_0_terms']
+                the_idx[term]['node_1_subterms']={} \
+                  unless the_idx[term]['node_1_subterms'] \
+                  and defined? the_idx[term]['node_1_subterms']
+                the_idx[term]['node_1_subterms'][subterm]=[] \
+                  unless the_idx[term]['node_1_subterms'][subterm] \
+                  and defined? the_idx[term]['node_1_subterms'][subterm]
+                the_idx[term]['node_1_subterms'][subterm] <<
+                  { ocn: idx[:ocn], range: location, seg: idx[:seg] }
+              end
+            end
+          end
+        end
+      end
+      the_idx=the_idx.sort
+      the_idx
+    end
+    def clean_xml(str)
+      str=str.gsub(/&/,'&amp;')
+      str
+    end
+    def index(the_idx)
+      @x=1
+      idx={}
+      idx[:sst_rel_html_seg],idx[:sst_rel],idx[:html],idx[:xhtml]=
+        [],                  [],           [],        []
+      h={
+        obj: Mx[:br_page]
+      }
+      o=SiSU_AO_DocumentStructure::ObjectLayout.new.break(h)
+      idx[:sst_rel_html_seg] << o
+      idx[:sst_rel] << o
+      h={
+        lv: '1',
+        name: 'index',
+        obj: "Index"
+      }
+      o=SiSU_AO_DocumentStructure::ObjectHeading.new.heading(h)
+      idx[:sst_rel_html_seg] << o
+      idx[:sst_rel] << o
+      h={
+        lv: '4',
+        name: 'idx',
+        obj: " [Index] #{Mx[:pa_non_object_dummy_heading]}"
+      }
+      o=SiSU_AO_DocumentStructure::ObjectHeading.new.heading(h)
+      idx[:sst_rel_html_seg] << o
+      idx[:sst_rel] << o
+      alph=%W[9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z]
+      idx[:html] << '<p>'
+      idx[:xhtml] << '<p>'
+      alph.each do |x|
+        if x =~/[0-9]/
+          idx[:html] << ''
+          idx[:xhtml] << ''
+        else
+          idx[:html] <<
+            %{<a href="##{x}">#{x}</a>,#{$ep[:hsp]}}
+          idx[:xhtml] <<
+            %{<a href="##{x.downcase}">#{x}</a>,#{$ep[:hsp]}}
+        end
+      end
+      idx[:html] << '</p>'
+      idx[:xhtml] << '</p>'
+      letter=alph.shift
+      idx[:html] <<
+        %{\n<p class="book_index_lev1"><a name="numeral"></a></p>}
+      idx[:xhtml] <<
+        %{\n<p class="letter" id="numeral">0 - 9</p>}
+      the_idx.each do |i|
+        i.each do |x|
+          if x.is_a?(String)
+            f=/^(\S)/.match(x)[1]
+            if letter < f
+              while letter < f
+                if alph.length > 0
+                  letter=alph.shift
+                  idx[:html] <<
+                    %{\n<p class="letter"><a name="#{letter}">#{letter}</a></p><p class="book_index_lev1"><a name="#{letter.downcase}"> </a></p>}
+                  idx[:xhtml] <<
+                    %{\n<p class="letter" id="#{letter.downcase}">#{letter}</p>}
+                else break
+                end
+              end
+            end
+            idx[:sst_rel_html_seg] <<
+              %{\n\n#{Mx[:fa_bold_o]}#{x},#{Mx[:fa_bold_c]} }
+            idx[:sst_rel] <<
+              %{\n\n#{Mx[:fa_bold_o]}#{x},#{Mx[:fa_bold_c]} }
+            aname=x.gsub(/\s+/,'_')
+            idx[:html] <<
+              %{\n<p class="book_index_lev1"><a name="#{aname}"><b>#{x}</b></a>, }
+            c=clean_xml(x.dup)
+            idx[:xhtml] <<
+              %{\n<p class="book_index_lev1"><b>#{c}</b>, }
+            @o=idx[:sst_rel_html_seg].index(idx[:sst_rel_html_seg].last)
+            @t=idx[:sst_rel].index(idx[:sst_rel].last)
+            @q=idx[:html].index(idx[:html].last)
+            @r=idx[:xhtml].index(idx[:xhtml].last)
+            print "\n" + x + ', ' if @md.opt.act[:verbose_plus][:set]==:on
+          elsif x.is_a?(Array)
+            p 'array error? -->'
+            print x
+          elsif x.is_a?(Hash)
+            if x['node_0_terms'].is_a?(Array)
+              x['node_0_terms'].each do |a|
+                if a[:range]
+                  idx[:sst_rel_html_seg][@o]=
+                    idx[:sst_rel_html_seg][@o] +
+                    %{#{Mx[:lnk_o]}#{a[:range]}#{Mx[:lnk_c]}#{Mx[:rel_o]}/#{a[:seg]}.html##{a[:ocn]}#{Mx[:rel_c]}, }
+                  idx[:sst_rel][@t]=
+                    idx[:sst_rel][@t] +
+                    %{#{Mx[:lnk_o]}#{a[:range]}#{Mx[:lnk_c]}#{Mx[:rel_o]}#{a[:ocn]}#{Mx[:rel_c]}, }
+                  idx[:html][@q]=
+                    idx[:html][@q] +
+                    %{<a href="#{a[:seg]}.html##{a[:ocn]}">#{a[:range]}</a>, }
+                  idx[:xhtml][@q]=
+                    idx[:xhtml][@q] +
+                    %{<a href="#{a[:seg]}.xhtml#o#{a[:ocn]}">#{a[:range]}</a>, }
+                  print a[:range] + ', ' if @md.opt.act[:verbose_plus][:set]==:on
+                elsif a[:ocn]
+                  idx[:sst_rel_html_seg][@o]=
+                    idx[:sst_rel_html_seg][@o] +
+                    %{#{Mx[:lnk_o]}#{a[:ocn]}#{Mx[:lnk_c]}#{Mx[:rel_o]}#{a[:seg]}.html##{a[:ocn]}#{Mx[:rel_c]}, }
+                  idx[:sst_rel][@t]=
+                    idx[:sst_rel][@t] +
+                    %{#{Mx[:lnk_o]}#{a[:ocn]}#{Mx[:lnk_c]}#{Mx[:rel_o]}#{a[:ocn]}#{Mx[:rel_c]}, }
+                  idx[:html][@q]=
+                    idx[:html][@q] +
+                    %{<a href="#{a[:seg]}.html##{a[:ocn]}">#{a[:ocn]}</a>, }
+                  idx[:xhtml][@q]=
+                    idx[:xhtml][@q] +
+                    %{<a href="#{a[:seg]}.xhtml#o#{a[:ocn]}">#{a[:ocn]}</a>, }
+                  print a[:ocn] + ', ' if @md.opt.act[:verbose_plus][:set]==:on
+                else p 'error'
+                end
+              end
+              idx[:html][@q]=idx[:html][@q] + '</p>'
+              idx[:xhtml][@r]=idx[:xhtml][@r] + '</p>'
+            end
+            if x['node_1_subterms']
+             x['node_1_subterms'].sort.each do |k,y|
+                if k !~/node_0_terms/
+                  idx[:sst_rel_html_seg][@o]=
+                    idx[:sst_rel_html_seg][@o] +
+                    %{#{k}, }
+                  idx[:sst_rel][@t]=
+                    idx[:sst_rel][@t] +
+                    %{#{k}, }
+                  idx[:html][@q]=
+                    idx[:html][@q] +
+                    %{\n<p class="book_index_lev2">#{k}, }
+                  c=clean_xml(k.dup)
+                  idx[:xhtml][@r]=
+                    idx[:xhtml][@r] +
+                    %{\n<p class="book_index_lev2">#{c}, }
+                  print "\n\t" + k + ', ' if @md.opt.act[:verbose_plus][:set]==:on
+                  y.each do |z|
+                    if z[:range]
+                      idx[:sst_rel_html_seg][@o]=
+                        idx[:sst_rel_html_seg][@o] +
+                        %{#{Mx[:lnk_o]}#{z[:range]}#{Mx[:lnk_c]}#{Mx[:rel_o]}#{z[:seg]}.html##{z[:ocn]}#{Mx[:rel_c]}, }
+                      idx[:sst_rel][@t]=
+                        idx[:sst_rel][@t] +
+                        %{#{Mx[:lnk_o]}#{z[:range]}#{Mx[:lnk_c]}#{Mx[:rel_o]}#{z[:ocn]}#{Mx[:rel_c]}, }
+                      idx[:html][@q]=
+                        idx[:html][@q] +
+                        %{<a href="#{z[:seg]}.html##{z[:ocn]}">#{z[:range]}</a>, }
+                      idx[:xhtml][@q]=
+                        idx[:xhtml][@q] +
+                        %{<a href="#{z[:seg]}.xhtml#o#{z[:ocn]}">#{z[:range]}</a>, }
+                      print z[:range] + ', ' if @md.opt.act[:verbose_plus][:set]==:on
+                    elsif z[:ocn]
+                      idx[:sst_rel_html_seg][@o]=
+                        idx[:sst_rel_html_seg][@o] +
+                        %{#{Mx[:lnk_o]}#{z[:ocn]}#{Mx[:lnk_c]}#{Mx[:rel_o]}#{z[:seg]}.html##{z[:ocn]}#{Mx[:rel_c]}, }
+                      idx[:sst_rel][@t]=
+                        idx[:sst_rel][@t] +
+                        %{#{Mx[:lnk_o]}#{z[:ocn]}#{Mx[:lnk_c]}#{Mx[:rel_o]}#{z[:ocn]}#{Mx[:rel_c]}, }
+                      idx[:html][@q]=
+                        idx[:html][@q] +
+                        %{<a href="#{z[:seg]}.html##{z[:ocn]}">#{z[:ocn]}</a>, }
+                      idx[:xhtml][@q]=
+                        idx[:xhtml][@q] +
+                        %{<a href="#{z[:seg]}.xhtml#o#{z[:ocn]}">#{z[:ocn]}</a>, }
+                      print z[:ocn] + ', ' if @md.opt.act[:verbose_plus][:set]==:on
+                    else p 'error'
+                    end
+                  end
+                  idx[:html][@q]=idx[:html][@q] + '</p>'
+                  idx[:xhtml][@r]=idx[:xhtml][@r] + '</p>'
+                end
+              end
+            end
+            @x +=1
+          end
+        end
+      end
+      print "\n" if @md.opt.act[:verbose_plus][:set]==:on
+      idx
+    end
+    def screen_print(the_idx)
+      the_idx.each do |i|
+        i.each do |x|
+          if x.is_a?(String)
+            print "\n" + x + ', '
+          elsif x.is_a?(Array)
+            p 'array error? -->'
+            print x
+          elsif x.is_a?(Hash)
+            if x['node_0_terms'].is_a?(Array)
+              x['node_0_terms'].each do |a|
+                if a[:range]
+                  print a[:range] + ', '
+                elsif a[:ocn]
+                  print a[:ocn] + ', '
+                else p 'error'
+                end
+              end
+            end
+            if x['node_1_subterms']
+              x['node_1_subterms'].sort.each do |k,y|
+                if k !~/node_0_terms/
+                  print "\n\t" + k + ', '
+                  y.each do |z|
+                    if z[:range]
+                      print z[:range] + ', '
+                    elsif z[:ocn]
+                      print z[:ocn] + ', '
+                    else p 'error'
+                    end
+                  end
+                end
+              end
+            end
+          end
+        end
+      end
+    end
+    def output_idx(idx)
+      if @md.book_idx
+        path="#{@env.path.output}/#{@md.fnb}"
+        Dir.mkdir(path) unless FileTest.directory?(path)
+        puts "#{path}/#{@md.fn[:book_idx_html]} #{__FILE__}::#{__LINE__}"
+        html_index_file=File.new("#{path}/#{@md.fn[:book_idx_html]}",'w')
+        idx[:html].each {|x| html_index_file << x }
+        html_index_file.close
+      end
+    end
+    def clean_and_insert_index(data,sisu_markup_idx)
+      tuned_file=[]
+      data.each do |dob|
+        tuned_file << dob
+        if dob.obj =~/#{Mx[:br_endnotes]}/ \
+        and sisu_markup_idx
+          sisu_markup_idx.each do |idx|
+            tuned_file << idx
+          end
+        end
+      end
+      tuned_file
+    end
+    def clean_index(data)                                  #check on use of dob
+      data.each.map do |para|
+        para.gsub(/\n*#{@rgx_idx}/m,'')
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** ao_images.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/ao_images.rb"
+# <<sisu_document_header>>
+module SiSU_AO_Images
+  class Images
+    begin
+      require 'rmagick'
+      include Magick
+    rescue LoadError
+      #SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).mark('rmagic NOT FOUND')
+    end
+    def initialize(md,data)
+      @md,@data=md,data
+    end
+    def images
+      data=@data
+      @rmgk=false
+      imagemagick_=true      #imagemagick_=SiSU_Env::InfoSettings.new.program?('rmagick')
+      if imagemagick_
+        begin
+          @rmgk=SiSU_Env::Load.new('rmagick').prog
+        rescue
+          @rmgk=false
+        end
+      else
+        if (@md.opt.act[:verbose_plus][:set]==:on \
+        || @md.opt.act[:maintenance][:set]==:on)
+          SiSU_Screen::Ansi.new(
+            @md.opt.act[:color_state][:set],
+            '*WARN* use of rmagick is not enabled in sisurc.yml'
+          ).warn
+        end
+      end
+      data.select do |dob|
+        unless dob.is ==:table
+          dob.obj=dob.obj.strip
+          if dob.obj =~/#{Mx[:lnk_o]}\s*\S+\.(?:png|jpg|gif)(?:\s*|\s+.+)?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|image)/
+            if dob.obj !~/#{Mx[:lnk_o]}\s*\S+\.(?:png|jpg|gif)\s+\d+x\d+/
+              m=/#{Mx[:lnk_o]}\s*(\S+\.(?:png|jpg|gif))/
+              if imagemagick_
+                imgs=dob.obj.scan(m).flatten
+                img_col=img_row=nil
+                images=imgs.each do |image|
+                  dir=SiSU_Env::InfoEnv.new(@md.fns)
+                  path_image=[
+                    dir.path.image_source_include_local,
+                    dir.path.image_source_include_remote,
+                    dir.path.image_source_include
+                  ]
+                  image_path=nil
+                  path_image.each do |img_pth|
+                    image_path=img_pth
+                    break if FileTest.exist?("#{img_pth}/#{image}")
+                  end
+                  if FileTest.exist?("#{image_path}/#{image}")
+                    if @rmgk
+                      img=Magick::ImageList.new("#{image_path}/#{image}")
+                      img_col,img_row=img.columns,img.rows
+                    else
+                      if (@md.opt.act[:verbose_plus][:set]==:on \
+                      || @md.opt.act[:maintenance][:set]==:on)
+                        SiSU_Screen::Ansi.new(
+                          @md.opt.act[:color_state][:set],
+                          '*WARN* rmagick not present, will attempt to use imagemagick (identify) directly'
+                        ).warn
+                      end
+                      imgk=SiSU_Env::SystemCall.new.imagemagick
+                      gmgk=SiSU_Env::SystemCall.new.graphicsmagick
+                      if imgk or gmgk
+                        if imgk
+                          imgsys=`identify #{image_path}/#{image}`.strip                           #system call
+                        elsif gmgk
+                          imgsys=`gm identify #{image_path}/#{image}`.strip                        #system call
+                        end
+                        img_col,img_row=/(\d+)x(\d+)/m.match(imgsys)[1,2]
+                        img_col,img_row=img_col.to_i,img_row.to_i
+                      else
+                        errmsg='imagemagick or graphicsmagick are required to process images'
+                        if @md.opt.act[:no_stop][:set]==:on
+                          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+                            error("#{errmsg}, proceeding (as requested) without image processing")
+                          break
+                        else
+                          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+                            error("#{errmsg}, STOPPING")
+                          exit
+                        end
+                      end
+                    end
+                    row=((img && defined? img.rows) ? img.rows : img_row)
+                    col=((img && defined? img.columns) ? img.columns : img_col)
+                    if img_col > img_row                                                           #landscape
+                      if img_col> 640
+                        img_col=640
+                        img_row=((1.00*img_col/col)*row).round
+                      end
+                    else                                                                           #portrait
+                      if img_col> 640
+                        img_col=640
+                        img_row=((1.00*img_col/col)*row).round
+                      end
+                      if img_row > 640
+                        img_row=640
+                        img_col=((1.00*img_row/row)*col).round
+                      end
+                    end
+                    dob.obj=dob.obj.gsub(/(#{image})/,"#{image} #{img_col}x#{img_row}")
+                  else
+                    dob.obj=dob.obj.
+                      gsub(/#{Mx[:lnk_o]}\s*(\S+)\.(png|jpg|gif).+?#{Mx[:lnk_c]}(#{Mx[:url_o]}\S+?#{Mx[:url_c]}|image)/,
+                        '[ \1 (\2 missing) ]')
+                  end
+                end
+              else
+                images=dob.obj.scan(m) do |image|
+                  SiSU_Screen::Ansi.new(
+                    @md.opt.act[:color_state][:set],
+                    '*WARN* where image dimensions have not been provided rmagick or imagemagick is required',image
+                  ).warn unless @md.opt.act[:quiet][:set]==:on
+                end
+              end
+            end
+          end
+          if dob.obj =~/#{Mx[:lnk_o]}\s*\S+\.(?:png|jpg|gif).+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|image)/
+            dob.obj=dob.obj.gsub(/(#{Mx[:lnk_o]})\s*(\S+\.(?:png|jpg|gif))\s+/i,'\1\2 ')
+          end
+        end
+        dob unless dob.nil?
+      end
+    end
+  end
+end
+__END__
+imgsys=`identify #{image_path}/#{image}`.strip
+#+END_SRC
+
+** ao_metadata.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/ao_metadata.rb"
+# <<sisu_document_header>>
+module SiSU_AO_Metadata
+  class Metadata
+    def initialize(md,metad)
+      @md,@metadata=md,metad
+      l=SiSU_Env::StandardiseLanguage.new(@md.opt.lng).language
+      language=l[:n]
+      @tr=SiSU_Translate::Source.new(md,language)
+    end
+    def make_para(obj,ocn)
+      h={
+        obj: obj,
+        ocn: 0
+      }
+      SiSU_AO_DocumentStructure::ObjectPara.new.paragraph(h)
+    end
+    def make_heading(obj,ocn,name,lv,ln)
+      h={
+        lv: lv,
+        ln: ln,
+        name: name,
+        obj: obj,
+        ocn: 0
+      }
+      SiSU_AO_DocumentStructure::ObjectHeading.new.heading(h)
+    end
+    def metadata
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** ao_misc_arrange.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/ao_misc_arrange.rb"
+# <<sisu_document_header>>
+module SiSU_AO_MiscArrangeText
+  class SI
+    def initialize(md,data)
+      @md,@data=md,data
+    end
+    def conditional_headings(para)
+      para=para.gsub(/^(:?A~)\s*$/,'\1~ @title @author').            #conditional header
+        gsub(/^((?:[1-9]|:?[A-D])~\S*)\s*$/,
+          '\1~ [Note: heading marker::required title missing]~#')    #conditional header for incorporated document 2004w12
+      if para =~/^@\S+?:/
+        para=para.gsub(/^@(\S+?):(\s+|$)/,
+            "#{Mx[:meta_o]}\\1#{Mx[:meta_c]}\\2").
+          gsub(/^@(\S+?):([+-])(\s+|$)/,
+            "#{Mx[:meta_o]}\\1\\2#{Mx[:meta_c]}\\3")
+      end
+      para
+    end
+    def markup_blocks(para)
+      def ticks(para)
+        block_open,block_close,text=nil,nil,nil
+        if para =~/\A```[ ]+(?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block|table).*?\n.+?\n```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*\Z/m
+          @flag=:close
+          block_open,text,block_close=
+            /\A(```[ ]+(?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block|table).*?)\n(.+?)\n(```([ ]+[~-][#]|\s+\~\{.+?\}\~)?)\s*\Z/m.
+            match(para)[1..3]
+          ((para=~/^```[ ]+table(?:~h)?\s+/) \
+          and (para !~/^```[ ]+table(?:~h)?\s+c\d+/)) \
+          ? para
+          : (para=[]; para << block_open << text << block_close)
+        elsif para =~/\A```[ ]+(?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block|table).*?\n.*?\Z/m #look at, study
+          @flag=:open
+          block_open,text=/\A(```(?:[ ]+.+?))\n(.*?)\Z/m.match(para)[1,2]
+          para=[]
+          if not text.to_s.empty?
+            para << block_open << text
+          else
+            para << block_open
+          end
+        elsif para =~/\A.+?\n```(?:\s+\~\{.+?\}\~)?(?:\s+[~-][#])?(\s*=\{.+?\})?\s*\Z/m \
+        and @flag==:open
+          @flag=:close
+          text,block_close=
+            /\A(.+?)\n(```(?:\s+\~\{.+?\}\~)?(?:\s+[~-][#])?(?:\s+=\{.+?\})?)\s*\Z/m.match(para)[1,2]
+          para=[]
+          if not text.to_s.empty?
+            para << text.to_s << block_close
+          else
+            para << block_close
+          end
+        else para
+        end
+        para
+      end
+      def ticks_remove(para)
+        unless @md.opt.act[:quiet][:set] ==:on
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+           mark("ticks not recognized, ticks removed from pargraph\n#{para}")
+        end
+        para=para.gsub(/```[ ]+\S+[ ]*/m,'').
+          gsub(/```\s*/m,'').
+          strip
+      end
+      def ticks_quote(para)
+        @flag=:quote_open
+        text=para
+        para=[]
+        if text =~ /```[ ]+quote/m
+          para << '`:quote_open`'
+          text=text.gsub(/```[ ]+quote/m,'')
+        end
+        text=if text =~/(?:\n|\A)=\{.+?\}/m                               #exclude book index from indent markup
+          txt,bkidx,tail=/(.+?)((?:\n|\A)=\{.+?\}$)(.*)/m.match(text).captures
+          txt=txt.gsub(/(?:\n|\A)([^`\n]+)/m,'_1 \1')
+          txt + bkidx + tail
+        else text.gsub(/(?:\n|\A)([^`\n]+)/m,'_1 \1')
+        end
+        para << text.gsub(/```/m,'')
+        if text =~/```/m
+          @flag=:quote_close
+          para << '`:quote_close`'
+        end
+        para
+      end
+      def curly_braces(para)
+        block_open,block_close,text=nil,nil,nil
+        para=if para =~/\A(?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block|table)\{ .+?\n.+?\n\}(?:code|box|poem|alt|group|block|table)(?: [~-][#])?\s*\Z/m
+          block_open,text,block_close=
+            /\A((?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block|table)\{ .+?)\n(.+?)\n(\}(?:code|box|poem|alt|group|block|table)(?: [~-][#])?)\s*\Z/m.
+            match(para)[1..3]
+          para=[]
+          para << block_open << text << block_close
+        elsif para =~/\A(?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block|table)\{ .+?\n.+?\Z/m
+          block_open,text=
+            /\A((?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block|table)\{ .+?)\n(.+?)\Z/m.
+            match(para)[1,2]
+          para=[]
+          if not text.to_s.empty?
+            para << block_open << text
+          else
+            para << block_open
+          end
+        elsif para =~/\A.+?\n\}(?:code|box|poem|alt|group|block|table)(?: [~-][#])?\s*\Z/m
+          text,block_close=
+            /\A(.+?)\n(\}(?:code|box|poem|alt|group|block|table)(?: [~-][#])?)\s*\Z/m.
+            match(para)[1,2]
+          para=[]
+          if not text.to_s.empty?
+            para << text.to_s << block_close
+          else
+            para << block_close
+          end
+        else para
+        end
+        para
+      end
+      para=if (para =~/\A```[ ]+quote/m \
+      and @flag !=:open) \
+      or @flag==:quote_open
+        ticks_quote(para)
+      elsif para =~/\A```[ ]+(?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block|table).*?\n.*?\Z/m \
+      or @flag==:open
+        ticks(para)
+      elsif para =~/```/m
+        ticks_remove(para)
+      else
+        para
+      end
+      para=if para =~/^(?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block|table)\{|^\}(?:code|box|poem|alt|group|block|table)/m
+        curly_braces(para)
+      else
+        para
+      end
+    end
+    def prepare_text
+      data=@data
+      if data[0] =~ /^#!\s*(?:\/usr\/bin\/env sisu|\/usr\/bin\/sisu)/ # remove bang from top #! (however file is stripped, so will be removed provided no content precedes it)
+        data[0]=data[0].gsub(/^#!\s*\/usr\/bin\/sisu/,'').
+          gsub(/^#!\s*\/usr\/bin\/env sisu/,'')
+      end
+      if data[0] =~ /^(SiSU\s+[\d.]*|sisu-[\d.]+)$/ # SiSU identifier
+        data[0]=data[0].gsub(/^(SiSU\s*[\d.]*)$/,'% \1').
+          gsub(/^(sisu-[\d.]+)$/,'% \1')
+      end
+      data.each.map do |para|
+        para=conditional_headings(para)
+        markup_blocks(para)
+      end.flatten
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** ao_numbering.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/ao_numbering.rb"
+# <<sisu_document_header>>
+module SiSU_AO_Numbering
+  class Numbering
+    attr_accessor :obj,:osp,:ocn,:lv,:name,:index,:comment
+    @@segments_count=0
+    def initialize(md,data,fnx,process)
+      @md,@data,@fnx,@process=md,data,fnx,process
+      @obj=@type=@ocn=@lv=@name=@index=@comment=nil
+      @chosen_seg_names=[]
+    end
+    def chosen_seg_names(chosen,chosen_seg_name,dob,md,type)
+      @chosen_seg_names=if chosen.compact.uniq.length \
+      == chosen.compact.length
+        chosen
+      else
+        if md.opt.act[:maintenance][:set]==:on
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:green).
+            mark(
+              "duplicated auto segment name: #{type} #{chosen}\n" \
+              + "#{chosen}\n" \
+              + " manually name level 1 segments '1~given_name'\n" \
+              + 'filename: ' + md.fns + "\n" \
+              + 'heading text: "' + dob.obj + '"' + "\n" \
+              + 'duplication: "' + chosen_seg_name + '" (level: ' + dob.lv + '; numbering type: ' + type.to_s + ')'
+            )
+        end
+        chosen=chosen[0..-2]
+        chosen_seg_name=auto_numbering_exceptions(chosen,md,dob)
+        chosen << chosen_seg_name
+      end
+    end
+    def number_of_segments?
+      if @@segments_count==0
+        @data.each do |dob|
+          if dob.is ==  :heading \
+          and dob.lv == '1'
+            @@segments_count += 1
+          end
+        end
+        @@segments_count
+      else @@segments_count
+      end
+    end
+    def numbering_song
+      begin
+        data=@data
+        data=number_plaintext_para(data)
+        data=auto_number_heading_ie_title(data.compact) #tr issue
+        data=ocn(data.compact) #watch
+        data=xml(data.compact)
+        data=minor_numbering(data.compact)
+        if @process==:complete
+          data,tags_map,ocn_html_seg_map=name_para_seg_filename(data)
+        end
+        data=set_heading_top(data) unless @md.set_heading_top
+        [data,tags_map,ocn_html_seg_map]
+      ensure
+        @@segments_count=0
+      end
+    end
+    def set_tags(tags,tag)
+      tags=if not tag.empty? \
+      and tag !~/^\d+$/
+        tag=tag.gsub(/[^a-z0-9._-]/,'')
+        [tag,tags].flatten
+      else tags
+      end
+    end
+    def number_plaintext_para(data)
+      @tuned_file=[]
+      data.each do |dob|
+        if (dob.of !=:block \
+        && dob.of !=:comment \
+        && dob.of !=:layout) \
+        && dob.ocn_ #and dob.obj !~ /#{Mx[:gr_o]}Th|#{Mx[:tc_o]}#{Mx[:tc_p]}#{Mx[:tc_p]}/ #FIX
+          dob.obj=dob.obj.gsub(/(.+)\n/,'\1 ') #messy, but idea is that tables should retain breaks
+        end
+        unless dob.obj.is_a?(Array)
+          dob.obj=dob.obj.gsub(/^\s+/,'').
+            gsub(/\s$/,"\n")
+        end
+        @tuned_file << dob
+      end
+      @tuned_file=@tuned_file.flatten
+    end
+    def number_sub_heading(dob,num,title_no)
+      unless dob.obj =~/\d+\.|(?:chapter|article|section|clause)\s+\d+/i #name selection arbitrary, fix
+        dob.obj=case dob.name
+        when /-/          then dob.obj.gsub(/^/,"#{title_no} ")
+        when /^#/         then dob.obj.gsub(/^/,"#{title_no} ")
+        when /^[a-z_\.]+/ then dob.obj.gsub(/^/,"#{title_no} ")
+        else
+          dob.name=title_no if dob.name=~/^$/ #where title contains title number
+          dob.obj.gsub(/^/,"#{title_no} ") if title_no =~/\d+/ #main, where title number is to be provided #watch changed placement
+        end
+        if @md.toc_lev_limit \
+        and @md.toc_lev_limit < num
+          dob.obj=dob.obj.gsub(/^/,'!_ ') #bold line, watch
+        end
+      end
+      dob
+    end
+    def heading_tag_clean(heading_tag)
+      heading_tag=heading_tag.
+        gsub(/[ ]+/,'_').
+        gsub(/["']/,'').
+        gsub(/[\/]/,'-').
+        gsub(/#{Mx[:fa_bold_o]}|#{Mx[:fa_bold_c]}/,'').
+        gsub(/#{Mx[:fa_italics_o]}|#{Mx[:fa_italics_c]}/,'').
+        gsub(/#{Mx[:fa_underscore_o]}|#{Mx[:fa_underscore_c]}/,'').
+        gsub(/#{Mx[:fa_cite_o]}|#{Mx[:fa_cite_c]}/,'').
+        gsub(/#{Mx[:fa_insert_o]}|#{Mx[:fa_insert_c]}/,'').
+        gsub(/#{Mx[:fa_strike_o]}|#{Mx[:fa_strike_c]}/,'').
+        gsub(/#{Mx[:fa_superscript_o]}|#{Mx[:fa_superscript_c]}/,'').
+        gsub(/#{Mx[:fa_subscript_o]}|#{Mx[:fa_subscript_c]}/,'').
+        gsub(/#{Mx[:fa_hilite_o]}|#{Mx[:fa_hilite_c]}/,'').
+        gsub(/#{Mx[:gl_bullet]}/,'')
+    end
+    def auto_number_heading_ie_title(data)                                             #also does some segment naming
+      if defined? @md.make.num_top \
+      and @md.make.num_top \
+      and @md.make.num_top !~/^$/
+        input||=@md.make.num_top
+      end
+      num_top=(input ? input.to_i : nil)
+      t_no1=t_no2=t_no3=0
+      if num_top
+        no1=num_top; no2=(num_top + 1); no3=(num_top + 2)
+      end
+      chapter_number_counter=0
+      data=data.compact
+      @tuned_file=data.each.map do |dob| #@md.seg_names << [additions to segment names]
+        title_no=nil
+        if dob.is ==:heading \
+        && dob.autonum_ \
+        and defined? @md.make.num_top \
+        and @md.make.num_top !~/^$/
+          if  dob.lv=='1' \
+          and dob.obj =~/^#\s|\s#(?:\s|$)/
+            chapter_number_counter +=1
+            dob.obj=dob.obj.gsub(/^#\s/,"#{chapter_number_counter} ").
+              gsub(/#([:,]?\s|[.]?$)/,"#{chapter_number_counter}\\1")
+          end
+          if dob.ln==no1
+            @subnumber=1
+            @subnumber=0 if dob.ln==no1
+          end
+          if dob.ln.to_s =~/^[0-6]/ \
+          and not dob.use_ ==:dummy \
+          and dob.obj !~/#{Mx[:fa_o]}(?:~#|-#)#{Mx[:fa_c]}/ # <-- fix
+            if dob.ln==no1
+              t_no1+=1; t_no2=0; t_no3=0
+              title_no="#{t_no1}"
+              if @md.seg_names.is_a?(Array) \
+              and not @md.seg_names.include?(title_no)
+                if dob.ln==no1
+                  dob.name="#{title_no}" if not dob.name
+                  dob.tags=set_tags(dob.tags,title_no)
+                  tag=dob.obj.
+                    gsub(/(Article|Clause|Section|Chapter)\s+/,
+                      "\\1_#{title_no}").
+                    downcase
+                  tag=heading_tag_clean(tag)
+                  dob.tags=set_tags(dob.tags,tag)
+                  dob.obj=(dob.obj =~/(Article|Clause|Section)\s+/) \
+                  ? (dob.obj.gsub(/(Article|Clause|Section)\s+/,"\\1 #{title_no} "))
+                  : (dob.obj.gsub(/^/,"#{title_no}. ")) #fix stop later
+                end
+                if dob.ln !=no1 \
+                and dob.obj =~/^[\d.]+\s/ #fix -> if the title starts with a numbering scheme, do not auto-number, review
+                  dob.name ="#{title_no}" if not dob.name
+                  dob.tags=set_tags(dob.tags,title_no)
+                  dob.obj=dob.obj.gsub(/^/,"#{title_no}. ")
+                end
+                @md.seg_names << title_no
+              end
+              if dob.ln!=no1 \
+              and dob.name!~/^[a-z_\.]+$/ \
+              and dob.obj !~/[A-Z]\.?\s/ #bug -> tmp fix, excludes A. B. C. lettering, but not roman numerals, is arbitrary, review required # not fixed, work on
+                dob.tags=set_tags(dob.tags,title_no)
+                dob.obj=dob.obj.gsub(/^/i,"#{title_no}. ")
+              end
+            end
+            if dob.ln==no1         #watch because here you change dob.name
+              dob.tags=set_tags(dob.tags,"h#{title_no}")
+            end
+            if dob.ln==no2         #watch because here you change dob.name
+              t_no2+=1; t_no3=0
+              title_no="#{t_no1}.#{t_no2}"
+              dob.tags=set_tags(dob.tags,"h#{title_no}")
+              dob=number_sub_heading(dob,no2,title_no)
+            end
+            if dob.ln==no3         #watch because here you change dob.name
+              t_no3+=1
+              title_no="#{t_no1}.#{t_no2}.#{t_no3}"
+              dob.tags=set_tags(dob.tags,"h#{title_no}")
+              dob=number_sub_heading(dob,no3,title_no)
+            end
+          elsif dob.ln.to_s =~/^[0-6]/ \
+          and dob.name =~ /^[\w-]+-/ # endnotes, watch2005# endnotes, watch2005
+            dob.tags=set_tags(dob.tags,dob.name)
+            dob.name.gsub(/^([a-z_\.]+)-$/,'\1')
+          end
+        elsif dob.is ==:heading \
+        and dob.autonum_ \
+        and @md.markup =~/num_extract/ #AS DANGEROUS force enable with document, note already does this type of numbering for cisg, locate and coordinate logic, is currently misplaced in code, chengwei inspired 2004w23/4
+          #here lies a bug, as is nil when run from -Dv --update, FIX
+          if (dob.name.nil? or dob.name.empty?) \
+          and dob.ln.to_s =~/^[0-9]/ \
+          and dob.obj =~ /^([\d\.]+)/ #risky (must be unique) consider output to 4~~\d instead of 4~\d
+            dob.name=$1
+            dob.tags=set_tags(dob.tags,dob.name)
+          end
+          if @md.toc_lev_limit
+          end
+        elsif defined? dob.name \
+        and  dob.name
+          dob.tags=set_tags(dob.tags,dob.name)
+        end
+        dob.tags=dob.tags.uniq if defined? dob.tags
+        dob
+      end.flatten
+    end
+    def ocn(data)                                                                      #and auto segment numbering increment
+      @tuned_file=SiSU_AO_DocumentStructureExtract::OCN.new(@md,data,@fnx,@process).ocn
+      @tuned_file
+    end
+    def xml(data)
+      @tuned_file=SiSU_AO_DocumentStructureExtract::XML.new(@md,data).dom
+      @tuned_file
+    end
+    def minor_numbering(data)                                                          #and auto segment numbering increment
+      number_small,letter_small=0,0
+      letter=%w( a b c d e f g h i j k l m n o p q r s t u v w x y z )
+      @tuned_file=data.each.map do |dob|
+        if dob.of ==:heading \
+        || dob.of ==:heading_insert \
+        || dob.of ==:para \
+        || dob.of ==:block
+          if dob.is ==:heading \
+          and dob.ln.to_s=~/^[0-9]/                                                    #% sub-number system, (baby numbering) reset with any change of major number (more obviously should be placed in number titles, but that is conditionally executed, check and move later)
+            number_small,letter_small=0,0
+          elsif dob.is ==:para
+            if dob.obj =~/^#[ 1]/ \
+            and dob.obj !~/^#\s+(?:~#)?$/
+              letter_small=0
+              number_small=0 if dob.obj =~ /^#1/
+              number_small+=1
+              dob.obj=dob.obj.gsub(/^#[ 1]/,"#{number_small}. ")
+            end
+            if dob.obj =~/^_# /
+              dob.obj=dob.obj.gsub(/^_# /,"#{letter[letter_small]}. ")
+              dob.indent='1'
+              letter_small+=1
+            end
+          end
+        end
+        dob
+      end.flatten
+    end
+    def leading_zeros_fixed_width_number(possible_seg_name)
+      if possible_seg_name.to_s =~/^([0-9]+?\.|[0-9]+)$/m       #!~/[.,:-]+/
+        possible_seg_name=possible_seg_name.to_s.
+          gsub(/\.$/,'')
+        nl=possible_seg_name.to_s.length
+        zero='0'
+        zeros_fixed_width=number_of_segments?.to_s.length
+        zero_width=(zeros_fixed_width - nl)
+        zero_width == 0 \
+        ? possible_seg_name.to_s
+        : zero*zero_width +
+          possible_seg_name.to_s
+      end
+    end
+    def auto_numbering_exceptions(chosen_seg_names_,md,dob)
+      number_make=case dob.lv.to_i
+      when 1
+        @num_exc={
+          t1: @num_exc[:t1] += 1,
+          t2: 0,
+          t3: 0,
+          t4: 0
+        }
+        Mx[:segname_prefix_auto_num_other] + '_' \
+        + @num_exc[:t1].to_s
+      when 2
+        @num_exc={
+          t1: @num_exc[:t1],
+          t2: @num_exc[:t2] += 1,
+          t3: 0,
+          t4: 0
+        }
+        Mx[:segname_prefix_auto_num_other] + '_' \
+        + @num_exc[:t1].to_s + '_' \
+        + @num_exc[:t2].to_s
+      when 3
+        @num_exc={
+          t1: @num_exc[:t1],
+          t2: @num_exc[:t2],
+          t3: @num_exc[:t3] += 1,
+          t4: 0
+        }
+        Mx[:segname_prefix_auto_num_other] + '_' \
+        + @num_exc[:t1].to_s + '_' \
+        + @num_exc[:t2].to_s + '_' \
+        + @num_exc[:t3].to_s
+      when 4
+        @num_exc[:t4] += 1
+        @num_exc={
+          t1: @num_exc[:t1],
+          t2: @num_exc[:t2],
+          t3: @num_exc[:t3],
+          t4: @num_exc[:t4] += 1
+        }
+        Mx[:segname_prefix_auto_num_other] + '_' \
+        + @num_exc[:t1].to_s + '_' \
+        + @num_exc[:t2].to_s + '_' \
+        + @num_exc[:t3].to_s + '_' \
+        + @num_exc[:t4].to_s
+      end
+    end
+    def check_that_seg_names_are_unique(chosen_seg_names_,chosen_seg_name,type,md,dob)
+      begin
+        chosen_seg_names_ << chosen_seg_name
+        chosen_seg_names_=chosen_seg_names(chosen_seg_names_,chosen_seg_name,dob,md,type)
+        if chosen_seg_names_.compact.uniq.length \
+        == chosen_seg_names_.compact.length
+          #check that all auto given seg names are unique
+          chosen_seg_names_=chosen_seg_names(chosen_seg_names_,chosen_seg_name,dob,md,type)
+          chosen_seg_name
+        else
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:green).
+            mark(
+              "duplicated auto segment name: #{type} #{chosen_seg_name}\n" \
+              + "#{chosen_seg_names_}\n" \
+              + " manually name level 1 segments '1~given_name'\n" \
+              + 'filename: ' + md.fns + "\n" \
+              + 'heading text: "' + dob.obj + '"' + "\n" \
+              + 'duplication: "' + chosen_seg_name + '" (level: ' + dob.lv + '; numbering type: ' + type.to_s + ')'
+            )
+          chosen_seg_name=auto_numbering_exceptions(chosen_seg_names_,md,dob)
+          check_that_seg_names_are_unique(chosen_seg_names_,chosen_seg_name,:exception,md,dob)
+        end
+      rescue
+      end
+    end
+    def auto_seg_name(possible_seg_name,heading_num_is,dob,type)
+      prefix=case type
+      when :auto    then Mx[:segname_prefix_auto_num_provide]
+      when :extract then Mx[:segname_prefix_auto_num_extract]
+      else               '_'*dob.lv.to_i #should not occur
+      end
+      if possible_seg_name =~/^[0-9]+?\.$/m                #!~/[.,:-]+/
+        possible_seg_name=possible_seg_name.
+          gsub(/\.$/,'')
+      end
+      @chosen_seg_name=
+      if dob.lv=='4' \
+      and possible_seg_name.to_s =~/^[0-9]+(?:[.,:-][0-9]){3}/m
+        possible_seg_name=possible_seg_name.to_s.
+          gsub(/(?:[:,-]|\W)/,'.').
+          gsub(/\.$/,'')
+        prefix + possible_seg_name
+      elsif dob.lv=='3' \
+      and possible_seg_name.to_s =~/^[0-9]+(?:[.,:-][0-9]){2}/m
+        possible_seg_name=possible_seg_name.to_s.
+          gsub(/(?:[:,-]|\W)/,'.').
+          gsub(/\.$/,'')
+        prefix + possible_seg_name
+      elsif dob.lv=='2' \
+      and possible_seg_name.to_s =~/^[0-9]+(?:[.,:-][0-9]){1}/m
+        possible_seg_name=possible_seg_name.to_s.
+          gsub(/(?:[:,-]|\W)/,'.').
+          gsub(/\.$/,'')
+        prefix + possible_seg_name
+      elsif dob.lv=='1' \
+      and possible_seg_name.to_s =~/^[0-9]+[:,-]?$/m
+        if possible_seg_name.to_i <= heading_num_is.to_i
+          prefix + leading_zeros_fixed_width_number(possible_seg_name)
+        else
+          possible_seg_name=possible_seg_name.to_s.
+            gsub(/(?:[:,-]|\W)/,'.').
+            gsub(/\.$/,'')
+          prefix + possible_seg_name
+        end
+      else
+        @chosen_seg_name=auto_numbering_exceptions(@chosen_seg_names,md,dob)
+      end
+      check_that_seg_names_are_unique(@chosen_seg_names,@chosen_seg_name,type,@md,dob)
+    end
+    def set_name_and_tags(dob,possible_seg_name)
+      if @md.seg_names.is_a?(Array) \
+      and not @md.seg_names.include?(possible_seg_name)
+        dob.name=possible_seg_name
+        dob.tags=set_tags(dob.tags,dob.name)
+        @md.seg_names << possible_seg_name
+      elsif (@md.opt.act[:verbose_plus][:set]==:on \
+      or @md.opt.act[:maintenance][:set]==:on)
+        puts 'warn, there may be a conflicting numbering scheme'
+      end
+    end
+    def name_para_seg_filename(data)                                                   #segment naming, remaining
+      # paragraph name/numbering rules
+      # manual naming overrides, manual naming may be
+      #   alpha-numeric characters mixed,
+      #   numeric only (a number), if
+      #     all segments have been named,
+      #     the numbers used are over 1000 or
+      #     it is not minded that auto-numbering uses a funny scheme for naming segments (not yet implemented)
+      #       [for now a warning is printed for such documents on use of maintenance or very-verbose flag]
+      # auto-naming takes the form of giving numbers to segments
+      # the rules for which are as follows
+      #   if the title/heading text starts with a numeric, then that is used (1 3.1 3rd etc.)
+      #   otherwise the level 4 segment number from the embedded document structure info is used
+      #   if there is none a sequential number is designated, preceded by an underscore
+      @tuned_file,@unique_auto_name=[],[]
+      tags={}
+      @art_filename_auto=0
+      @counter=1
+      if not @md.seg_autoname_safe \
+      and (@md.opt.act[:verbose_plus][:set]==:on \
+      || @md.opt.act[:maintenance][:set]==:on)
+        puts 'manual segment names, numbers used as names, risk warning (segmented html)'
+      end
+      ocn_html_seg=[]
+      @num_exc={ t1: 0, t2: 0, t3: 0, t4: 0 }
+      data.each do |dob|
+        if dob.is==:heading \
+        && dob.ln \
+        and dob.ln.to_s =~/^[4-7]/
+          heading_num_is=/^\d+:(\d+);\d/m.match(dob.node)[1]
+          if dob.ln==4 \
+          and not dob.name \
+          and not @md.set_heading_seg
+            @md.set_heading_seg=true
+          end
+          if dob.name !~/^\S+/ \
+          and dob.ln.to_s =~/^[5-7]/ \
+          and dob.obj =~/^\s*(?:\S+\s+)?([0-9]+(?:[.,:-][0-9])+)/m
+            #heading starts with a recognised numeric
+            #or word followed by a recognised numeric construct,
+            #use that as name
+            if dob.ln==7 \
+            and dob.obj =~/^\s*(?:\S+\s+)?([0-9]+(?:[.,:-][0-9]){3})/m
+              possible_seg_name=$1.
+                gsub(/(?:[:,-]|\W)/,'.').
+                gsub(/\.$/,'')
+              possible_seg_name=
+                auto_seg_name(possible_seg_name,heading_num_is,dob,:extract)
+              set_name_and_tags(dob,possible_seg_name)
+            elsif dob.ln==6 \
+            and dob.obj =~/^\s*(?:\S+\s+)?([0-9]+(?:[.,:-][0-9]){2})/m
+              possible_seg_name=$1.
+                gsub(/(?:[:,-]|\W)/,'.').
+                gsub(/\.$/,'')
+              possible_seg_name=
+                auto_seg_name(possible_seg_name,heading_num_is,dob,:extract)
+              set_name_and_tags(dob,possible_seg_name)
+            elsif dob.ln==5 \
+            and dob.obj =~/^\s*(?:\S+\s+)?([0-9]+(?:[.,:-][0-9]){1})/m
+              possible_seg_name=$1.
+                gsub(/(?:[:,-]|\W)/,'.').
+                gsub(/\.$/,'')
+              possible_seg_name=
+                auto_seg_name(possible_seg_name,heading_num_is,dob,:extract)
+              set_name_and_tags(dob,possible_seg_name)
+            end
+          end
+          if dob.ln==4
+            if dob.name !~/^\S+/ \
+            and dob.obj =~/^\s*(?:\S+\s+)?([0-9]+)/m
+              #heading starts with a recognised numeric
+              #or word followed by a recognised numeric construct,
+              #use that as name
+              possible_seg_name=$1
+              possible_seg_name=
+                auto_seg_name(possible_seg_name,heading_num_is,dob,:extract)
+              set_name_and_tags(dob,possible_seg_name)
+            end
+            if dob.name
+              #extract segment name from embedded document structure info
+              if @md.seg_names.is_a?(Array) \
+              and not @md.seg_names.include?(dob.name)
+                dob.tags=set_tags(dob.tags,dob.name)
+                @md.seg_names << dob.name
+              end
+            else
+              #if no segment name,
+              #provide a numerical one
+              @art_filename_auto+=1
+              possible_seg_name=
+                auto_seg_name(@art_filename_auto,heading_num_is,dob,:auto)
+              if @md.seg_names.is_a?(Array) \
+              and not @md.seg_names.include?(possible_seg_name)
+               dob.name=possible_seg_name
+               dob.tags=set_tags(dob.tags,dob.name)
+                @md.seg_names << possible_seg_name
+              else puts 'segment name (numbering) error'
+              end
+            end
+            if not dob.name #should not occur
+              puts "e r r o r -\t#{__FILE__}::#{__LINE__}\n#{dob.inspect}"
+            end
+          end
+        end
+        if (dob.is ==:heading \
+        || dob.is ==:heading_insert) \
+        && dob.ln==4
+          @seg=dob.name
+        end
+        @tuned_file << if dob.is==:heading \
+        && (@md.pagenew || @md.pagebreak || @md.pageline)
+          m=dob.ln.to_s
+          dob_tmp=[]
+          if @md.pagenew.inspect =~/#{m}/
+            dob_tmp <<
+              SiSU_AO_DocumentStructure::ObjectLayout.new.break(Hx[:br_page_new]) <<
+              dob
+          elsif @md.pagebreak.inspect =~/#{m}/
+            dob_tmp <<
+              SiSU_AO_DocumentStructure::ObjectLayout.new.break(Hx[:br_page]) <<
+              dob
+          elsif @md.pageline.inspect =~/#{m}/
+            dob_tmp <<
+              SiSU_AO_DocumentStructure::ObjectLayout.new.break(Hx[:br_page_line]) <<
+              dob
+          end
+          unless dob_tmp.length > 0; dob
+          else                       dob_tmp
+          end
+        else dob
+        end
+        if defined? dob.ocn \
+        and dob.ocn
+          @segname=((dob.is==:heading || dob.is==:heading_insert) && dob.ln==4 && (defined? dob.name)) \
+          ? (dob.name)
+          : @segname
+          tags["#{dob.ocn}"]={ segname: @segname }
+          ocn_html_seg[dob.ocn]=if (dob.is==:heading || dob.is==:heading_insert)
+            if dob.ln.to_s =~/[0-3]/
+              {
+                seg: nil,
+                level: dob.ln,
+              }
+            #elsif dob.ln =~/[4-6]/
+            else
+              {
+                seg: @seg,
+                level: dob.ln,
+              }
+            end
+          else
+            {
+              seg: @seg,
+              level: nil,
+            }
+          end
+        end
+        dob.tags=dob.tags.uniq if defined? dob.tags
+        if defined? dob.tags \
+        and dob.tags.length > 0
+          #@segname=((dob.is=='heading'|| dob.is=='heading_insert') && dob.ln==4 && (defined? dob.name)) \
+          #? (dob.name) \
+          #: @segname
+          dob.tags.each do |y|
+            tags[y]={ ocn: dob.ocn.to_s, segname: @segname }
+          end
+        end
+        dob
+      end
+      ocn_html_seg.each_with_index do |ocn,i|
+        if ocn \
+        and ocn[:level].to_s=~/[1-3]/
+          (1..4).each do |x|
+            if ocn_html_seg[i+x] \
+            and ocn_html_seg[i+x][:level]==4
+              ocn[:seg]=ocn_html_seg[i+x][:seg]
+            end
+          end
+        end
+      end
+      if @md.seg_names.length > 0
+        @md.set_heading_seg=true
+      end
+      tuned_file=@tuned_file.flatten
+      [tuned_file,tags,ocn_html_seg]
+    end
+    def set_heading_top(data)                                                          #% make sure no false positives
+      unless @md.set_heading_top
+        if (@md.opt.act[:verbose_plus][:set]==:on \
+        or @md.opt.act[:maintenance][:set]==:on)
+          puts "\tdocument contains no top level heading, (will have to manufacture one)"
+        end
+        @tuned_file=[]
+        data.each do |t_o|
+          unless @md.set_heading_top
+            if t_o !~/^(?:#{Rx[:meta]}|@\S+:)\s/m \
+            and t_o !~/\A\s*\Z/m
+              @md.set_heading_top=true
+              if defined? @md.title \
+              and @md.title \
+              and defined? @md.title.full \
+              and defined? @md.creator \
+              and @md.creator
+                head=@md.title.main \
+                ? ([@lv='1',@obj=@md.title.main])
+                : ([@lv='1',@obj='[no title provided]'])
+                @tuned_file << head
+              end
+            end
+          end
+          @tuned_file << t_o
+        end
+        @tuned_file=@tuned_file.flatten
+      end
+    end
+    def set_heading_seg(data)                                                          #% make sure no false positives
+      unless @md.set_heading_seg
+        if (@md.opt.act[:verbose_plus][:set]==:on \
+        or @md.opt.act[:maintenance][:set]==:on)
+          puts "\tdocument contains no segment level, (will have to manufacture one)"
+        end
+        @tuned_file=[]
+        data.each do |dob|
+          unless @md.set_heading_seg
+            if defined? dob.ln and dob.ln.to_s !~/^[0-3]/m \
+            and dob.obj !~/\A\s*\Z/m \
+            and dob.is !=:layout
+              @md.set_heading_seg=true
+              head=@md.title.main \
+              ? (dob.ln,dob.name,dob.obj=4,'seg',@md.title.main)
+              : (dob.ln,dob.name,dob.obj=4,'seg','[segment]')
+              @tuned_file << head
+            end
+          end
+          @tuned_file << dob
+        end
+        @tuned_file=@tuned_file.flatten
+      end
+    end
+    def set_header_title(data)                                                         #% make sure no false positives
+      unless @md.set_header_title
+        if (@md.opt.act[:verbose_plus][:set]==:on \
+        or @md.opt.act[:maintenance][:set]==:on)
+          puts "\t no document title provided, (will have to manufacture one)"
+        end
+        @tuned_file=[]
+        data.each do |t_o|
+          unless @md.set_header_title
+            if t_o !~/^%{1,2}\s/m \
+            and t_o !~/\A\s*\Z/m
+              @tuned_file <<
+                "#{Mx[:meta_o]}title#{Mx[:meta_c]} #{@md.heading_seg_first}"
+              @md.title.main=@md.heading_seg_first
+              @md.set_header_title=true
+            end
+          end
+          @tuned_file << t_o
+        end
+        @tuned_file=@tuned_file.flatten
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** ao_persist.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/ao_persist.rb"
+# <<sisu_document_header>>
+module SiSU_AO_Persist
+  class Persist
+    @@persistance=nil
+    attr_accessor :fns, :ao_arr, :idx_arr_sst, :idx_arr_tex, :idx_arr_html, :idx_arr_xhtml, :map_arr_nametags, :map_arr_ocn_htmlseg
+    def initialize(args=nil)
+      @@persistance=args=(args ? args : (@@persistance || persist_init_hash_values))
+      @fns=args[:fns]
+      @ao_arr=args[:ao_arr]
+      @idx_arr_sst=args[:idx_arr_sst]
+      @idx_arr_tex=args[:idx_arr_tex]
+      @idx_arr_html=args[:idx_arr_html]
+      @idx_arr_xhtml=args[:idx_arr_xhtml]
+      @map_arr_nametags=args[:map_arr_nametags]
+      @map_arr_ocn_htmlseg=args[:map_arr_ocn_htmlseg]
+    end
+    def fns
+      @fns
+    end
+    def ao_arr
+      @ao_arr
+    end
+    def idx_arr_sst
+      @idx_arr_sst
+    end
+    def idx_arr_tex
+      @idx_arr_tex
+    end
+    def idx_arr_html
+      @idx_arr_html
+    end
+    def idx_arr_xhtml
+      @idx_arr_xhtml
+    end
+    def map_arr_nametags
+      @map_arr_nametags
+    end
+    def map_arr_ocn_htmlseg
+      @map_arr_ocn_htmlseg
+    end
+    def persist_init_hash_values
+      {
+        fns:                 nil,
+        ao_arr:              [],
+        idx_arr_sst:         [],
+        idx_arr_tex:         [],
+        idx_arr_html:        [],
+        idx_arr_xhtml:       [],
+        map_arr_nametags:    [],
+        map_arr_ocn_htmlseg: [],
+      }
+    end
+    def persist_init
+      @@persistance=nil
+      Persist.new(persist_init_hash_values)
+    end
+  end
+  class PersistDocStructExt
+    @@persist=nil
+    attr_accessor :ocn, :lng, :lng_is, :code, :lngsyn, :poem, :block, :box, :group, :alt, :quote, :table, :table_to
+    def initialize(args=nil)
+      @@persist=args=(args ? args : (@@persist || persist_init_hash_values))
+      @ocn=args[:ocn]
+      @lng=args[:lng]
+      @lng_is=args[:lng_is]
+      @code=args[:code]
+      @lngsyn=args[:lngsyn]
+      @poem=args[:poem]
+      @block=args[:block]
+      @box=args[:box]
+      @group=args[:group]
+      @alt=args[:alt]
+      @quote=args[:quote]
+      @table=args[:table]
+      @table_to=args[:table_to]
+    end
+    def ocn
+      @ocn
+    end
+    def lng
+      @lng
+    end
+    def lng_is
+      @lng_is
+    end
+    def code
+      @code
+    end
+    def lngsyn
+      @lngsyn
+    end
+    def poem
+      @poem
+    end
+    def block
+      @block
+    end
+    def box
+      @box
+    end
+    def group
+      @group
+    end
+    def alt
+      @alt
+    end
+    def quote
+      @quote
+    end
+    def table
+      @table
+    end
+    def table_to
+      @table_to
+    end
+    def persist_init_hash_values
+      {
+        ocn:         :on,
+        lng:         :off,
+        lng_is:      :doc_default,
+        code:        :off,
+        lngsyn:      :txt,
+        poem:        :off,
+        block:       :off,
+        box:         :off,
+        group:       :off,
+        alt:         :off,
+        quote:       :off,
+        table:       :off,
+        table_to:    :off,
+      }
+    end
+    def persist_init
+      @@persist=nil
+      PersistDocStructExt.new(persist_init_hash_values)
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** ao_syntax.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/ao_syntax.rb"
+# <<sisu_document_header>>
+module SiSU_AO_Syntax
+  class Words
+    def initialize(line,md,mkp)
+      @line,@md,@mkp=line,md,mkp
+    end
+  end
+  class Markup
+    def initialize(md='',data='',biblio=[])
+      @md,@data,@bibliography=md,data,biblio
+      @data_new=[]
+      url_and_stub=SiSU_Env::InfoEnv.new.url
+      @output_url="#{url_and_stub.remote}"
+      @env=SiSU_Env::InfoEnv.new
+      emph_set=if defined? @md.emphasis_set_to \
+      and not @md.emphasis_set_to.nil?
+        @md.emphasis_set_to
+      else @env.markup_emphasis
+      end
+      @emph=case emph_set
+      when /bold/
+        emph_italics=false
+        { o: Mx[:fa_bold_o], c: Mx[:fa_bold_c] }
+      when /italics/
+        emph_italics=true
+        { o: Mx[:fa_italics_o], c: Mx[:fa_italics_c] }
+      when /underscore/
+        emph_italics=false
+        { o: Mx[:fa_underscore_o], c: Mx[:fa_underscore_c] }
+      else p __LINE__.to_s + '::' + __FILE__
+      end
+      @http_m=%r{\{.+?\}https?://\S+|https?:\S+|:\S+|\.\.\/\S+|#\S+|\S+?\.png\b|[*]~\S+|^#{Mx[:meta_o]}.+|#{Mx[:gr_o]}(?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|block|group|alt|verse)(?:-end)?#{Mx[:gr_c]}|#{Mx[:fa_o]}:br#{Mx[:fa_c]}}
+      @manmkp_ital=emph_italics \
+      ? '[i/*]\\{.+?\\}[i/*]'
+      : '[i/]\\{.+?\\}[i/]'
+      tail_m_ital=%q{(?:\s|'s\b|[.,;:?!'")]|~\^|~\\\{\s|$)}
+      tail_m_bold=%{(?:(?:#{Mx[:fa_italics_c]})?(?:\s|'s\b|[.,;:?!'")]|~\^|~\\\{\s|$))?}
+      bold_line=%{^!_\s.+?(?:#{Mx[:br_line]}|\n|$)}
+      #ital_line=%{^/_\s.+?(?:#{Mx[:br_line]}|\n|$)} #not implemented
+      @line_scan_ital=if defined? @md.italics_match_list[:str]
+        /#{@http_m}|#{bold_line}|#{@manmkp_ital}#{tail_m_ital}|#{@md.italics_match_list[:str]}#{tail_m_ital}|\S+|\n/i
+      end
+      @manmkp_bold=emph_italics \
+      ? '^!_\s.+?(?:\n|$)|[!b]\\{.+?\\}[*!b]|[*!][a-zA-Z0-9\-_]+[!]'
+      : '^!_\s.+?(?:\n|$)|[*!b]\\{.+?\\}[*!b]|[*!][a-zA-Z0-9\-_]+[*!]'
+      @line_scan_bold=if defined? @md.bold_match_list[:str] \
+      and @md.bold_match_list[:str]
+        /#{@http_m}|#{bold_line}|(?:#{@manmkp_bold}|#{@md.bold_match_list[:str]})#{tail_m_bold}|\S+|\n/i
+      end
+    end
+    def songsheet
+      @data=@data.compact
+      @data.each do |dob|
+        dob=breaks(dob)
+        dob=if @md.sem_tag then sem(dob) else dob end #revisit
+        dob=line_actions(dob)
+        dob=paragraph_set(dob)
+        dob=substitutions(dob)
+        dob=wordlist_italics(dob)
+        dob=wordlist_bold(dob)
+        dob=bodymarkup(dob)
+        @data_new << dob unless dob.nil?
+      end
+      @data_new
+    end
+    def sem(dob) #revisit
+      dob=SiSU_Sem::Tags.new(dob,@md).rm.all
+    end
+    def breaks(dob)
+      if dob.is !=:meta \
+      && dob.is !=:comment \
+      && dob.is !=:code \
+      && dob.is !=:table
+        dob.obj=dob.obj.
+          gsub(/^-\\\\-\s*$/,"#{Mx[:br_page]}").
+          gsub(/^=\\\\=\s*$/,"#{Mx[:br_page_new]}").
+          gsub(/ \\\\(?: |$)/,"#{Mx[:br_line]}").
+          gsub(/(?:<:?pb>)/,"#{Mx[:br_page]}").                         # depreciated
+          gsub(/(?:<:?pn>)/,"#{Mx[:br_page_new]}").                     # depreciated
+          gsub(/(?:<:?br>|<br \/>)/,"#{Mx[:br_line]}").                 # depreciated
+          gsub(/(?:^-\.\.-\s*$)/,"#{Mx[:br_page_line]}")
+      end
+      dob
+    end
+    def wordlist_italics(dob)
+      dob=dob.dup
+      if (defined? @md.italics_match_list[:str] \
+      and @md.italics_match_list[:str])
+        dob.obj=if dob.is !=:meta \
+        && dob.is !=:heading \
+        && dob.is !=:heading_insert \
+        && dob.is !=:code \
+        && dob.is !=:layout \
+        && dob.is !=:comment
+          word=dob.obj.scan(@line_scan_ital)
+          word=word.flatten.compact
+          line_array=[]
+          word.each do |w|
+            unless /#{@manmkp_ital}|#{@http_m}/.match(w)
+              if defined? @md.italics_match_list[:regx] \
+              and @md.italics_match_list[:regx]
+                w=w.gsub(@md.italics_match_list[:regx],
+                  "#{Mx[:fa_italics_o]}\\1#{Mx[:fa_italics_c]}")
+              else w
+              end
+            end
+            line_array << w
+          end
+          line_array.join(' ')
+        else dob.obj
+        end
+      end
+      dob
+    end
+    def embolden(given)
+      given=given.
+        gsub(/^!_\s+((?:\{|#{Mx[:lnk_o]})(?:~^ )?.+?(?:\}|#{Mx[:lnk_o]})https?:\/\/\S+.*?)([#{Mx[:br_line]}#{Mx[:br_paragraph]}#{Mx[:br_nl]}])/,
+          "#{Mx[:fa_bold_o]} \\1 #{Mx[:fa_bold_c]}\\2").
+        gsub(/^!_\s+((?:\{|#{Mx[:lnk_o]})(?:~^ )?.+?(?:\}|#{Mx[:lnk_o]})https?:\/\/\S+.*)/,
+          "#{Mx[:fa_bold_o]} \\1 #{Mx[:fa_bold_c]}").
+        gsub(/(?:^!_|^#{Mx[:lv_o]}[7-9]:\S*?#{Mx[:lv_c]})\s*(.+?)([#{Mx[:br_line]}#{Mx[:br_paragraph]}#{Mx[:br_nl]}])/,
+          "#{Mx[:fa_bold_o]}\\1#{Mx[:fa_bold_c]}\\2").
+        gsub(/(?:^!_|^#{Mx[:lv_o]}[7-9]:\S*?#{Mx[:lv_c]})\s*(.+?)\s+((?:[*]~\S+\s*)+)/,
+          "#{Mx[:fa_bold_o]}\\1#{Mx[:fa_bold_c]}\\2").
+        gsub(/(?:^!_|^#{Mx[:lv_o]}[7-9]:\S*?#{Mx[:lv_c]})\s*(.+?)\s*([~-]#)$/,
+          "#{Mx[:fa_bold_o]}\\1#{Mx[:fa_bold_c]}\\2").
+        gsub(/(?:^!_\s+|^#{Mx[:lv_o]}[7-9]:\S*?#{Mx[:lv_c]}\s*)(.*)?\s*$/,
+          "#{Mx[:fa_bold_o]}\\1#{Mx[:fa_bold_c]}")
+    end
+    def italicise(given)
+      given=given.
+        gsub(/^\/_\s*(.+?)([#{Mx[:br_line]}#{Mx[:br_paragraph]}#{Mx[:br_nl]}])/,
+          "#{Mx[:fa_italics_o]}\\1#{Mx[:fa_italics_c]}\\2").
+        gsub(/^\/_\s*(.+?)\s+((?:[*]~\S+\s*)+)/,
+          "#{Mx[:fa_italics_o]}\\1#{Mx[:fa_italics_c]}\\2").
+        gsub(/^\/_\s*(.+?)\s*([~-]#)$/,
+          "#{Mx[:fa_italics_o]}\\1#{Mx[:fa_italics_c]}\\2").
+        gsub(/^\/_\s+(.*)?\s*$/,
+          "#{Mx[:fa_italics_o]}\\1#{Mx[:fa_italics_c]}")
+    end
+    def line_actions(dob)
+      dob.obj=if (dob.is !=:heading \
+      && dob.is !=:heading_insert \
+      && dob.is !=:comment \
+      && dob.is !=:meta) \
+      and dob.obj =~ /^!_\s+/
+        embolden(dob.obj)
+      elsif dob.obj =~ /^\/_\s+/
+        italicise(dob.obj)
+      else dob.obj
+      end
+      dob
+    end
+    def paragraph_set(dob)
+      dob.obj=if dob.is !=:meta \
+      && dob.is !=:heading \
+      && dob.is !=:heading_insert \
+      && dob.is !=:code \
+      && dob.is !=:comment \
+      && dob.is !=:table
+        dob.obj.gsub(/\n/m,' ').
+          gsub(/ \s+/m,' ')
+      else dob.obj
+      end
+      dob
+    end
+    def substitutions(dob)
+      dob=dob.dup
+      dob=if @md.flag_auto_biblio \
+      and @bibliography.length > 0
+        dob=if dob.is !=:meta \
+        && dob.is !=:heading_insert \
+        && dob.is !=:code \
+        && dob.is !=:comment \
+        && dob.is !=:table
+          @bibliography.each do |c|
+            if c[:id] and not c[:id].nil? and not c[:id].empty?
+              dob.obj=dob.obj.gsub(/#{c[:id]}/mi,c[:short_name])
+            end
+          end
+          dob
+        else dob
+        end
+        dob
+      else dob
+      end
+      dob=if defined? @md.substitution_match_list[:match_and_replace] \
+      and @md.substitution_match_list[:match_and_replace].is_a?(Array)
+        dob=if dob.is !=:meta \
+        && dob.is !=:heading_insert \
+        && dob.is !=:code \
+        && dob.is !=:comment \
+        && dob.is !=:table
+          if dob.obj =~/#{@md.substitution_match_list[:matches]}/
+            @md.substitution_match_list[:match_and_replace].each do |x|
+              dob.obj=if x[:case_s]==:i
+                dob.obj.gsub(/#{x[:match]}/mi,x[:replace])
+              else
+                dob.obj.gsub(/#{x[:match]}/m,x[:replace])
+              end
+            end
+          end
+          dob
+        else dob
+        end
+        dob
+      else dob
+      end
+    end
+    def wordlist_bold(dob)
+      dob=dob.dup
+      if (defined? @md.bold_match_list[:str] \
+      and @md.bold_match_list[:str])
+        dob.obj=if dob.is !=:meta \
+        && dob.is !=:heading \
+        && dob.is !=:heading_insert \
+        && dob.is !=:code \
+        && dob.is !=:comment \
+        && dob.is !=:table
+          line_array=[]
+          word=dob.obj.scan(@line_scan_bold)
+          word=word.flatten.compact
+          word.each do |w|
+            unless /#{@manmkp_bold}|#{@http_m}/.match(w)
+              if defined? @md.bold_match_list[:regx] \
+              and @md.bold_match_list[:regx]                                             #document header: @bold: [bold word list]
+                w=w.gsub(@md.bold_match_list[:regx],
+                  "#{Mx[:fa_bold_o]}\\1#{Mx[:fa_bold_c]}")
+              end
+            else
+              w=if w =~ /(?:^!_|^#{Mx[:lv_o]}[7-9]:\S*?#{Mx[:lv_c]})\s+/
+                embolden(w)      #bold paragraph/emphasize #may wish to remove think about 7{ 8{ conversion not satisfactory, as information is lost!
+              elsif w =~/^\/_\s+/
+                italicise(w)
+              else w
+              end
+            end
+            line_array << w
+          end
+          line_array.join(' ')
+        else dob.obj
+        end
+      else
+        dob.obj=if dob.is==:heading \
+        and dob.ln.to_s =~/[7-9]/
+          embolden(dob.obj)
+        else dob.obj
+        end
+      end
+      dob
+    end
+    def fontface_lines(dob,leader)
+      while (dob.obj =~/#{Mx[:br_nl]}/ \
+      and dob.obj =~/(?:#{leader})([*!\/_#])\{(.+?)\}\1/m) \
+      and $2 =~/#{Mx[:br_nl]}/
+        dob=if dob.obj =~/#{Mx[:br_nl]}/ \
+        and dob.obj =~/(#{leader})([*!\/_#])\{(.+?)\}\2/m
+          lead,fce,txt=$1,$2,$3
+          dob=if txt =~/#{Mx[:br_nl]}/
+            lead_break=if dob.obj =~/^#{Mx[:br_nl]}/
+              dob.obj=dob.obj.sub(/^#{Mx[:br_nl]}/,'')
+              Mx[:br_nl]
+            else ''
+            end
+            txt="#{lead_break}#{fce}\{" + txt.split(Mx[:br_nl]).join("\}#{fce}#{Mx[:br_nl]}#{fce}\{") + "\}#{fce}"
+            dob.obj=dob.obj.
+              sub(/(?:^|#{Mx[:gl_c]}|\s+|['"]|[#{Mx[:nbsp]}#{Mx[:fa_o_c]}#{Mx[:fa_c]}#{Mx[:lnk_o]}#{Mx[:br_nl]}#{Mx[:br_line]}#{Mx[:br_paragraph]}#{Mx[:tc_c]}#{Mx[:tc_p]}]|[\(\[\{]|\>)([*!\/_#])\{.+?\}\1/m,
+                "#{lead}#{txt}")
+            dob
+          else dob
+          end
+        end
+        dob
+      end
+      dob
+    end
+    def fontface(dob)
+      leader=/^|#{Mx[:gl_c]}|\s+|['"]|[#{Mx[:nbsp]}#{Mx[:fa_o_c]}#{Mx[:fa_c]}#{Mx[:lnk_o]}#{Mx[:br_nl]}#{Mx[:br_line]}#{Mx[:br_paragraph]}#{Mx[:tc_c]}#{Mx[:tc_p]}]|[\(\[\{]|[、。「‹«¿¡]|\>/
+      dob=fontface_lines(dob,leader)
+      dob.obj=dob.obj.
+        gsub(/(#{leader})\*\{(.+?)\}\*/m,
+          "\\1#{@emph[:o]}\\2#{@emph[:c]}").                                                                                                                             #emphasis
+        gsub(/(#{leader})!\{(.+?)\}!/m,
+          "\\1#{Mx[:fa_bold_o]}\\2#{Mx[:fa_bold_c]}").                                                                                                                   #bold
+        gsub(/(#{leader})\/\{(.+?)\}\//m,
+          "\\1#{Mx[:fa_italics_o]}\\2#{Mx[:fa_italics_c]}").                                                                                                             #italics
+        gsub(/(#{leader})_\{(.+?)\}_/m,
+          "\\1#{Mx[:fa_underscore_o]}\\2#{Mx[:fa_underscore_c]}").                                                                                                       #underscore
+        gsub(/(#{leader})#\{(.+?)\}#/m,
+          "\\1#{Mx[:fa_monospace_o]}\\2#{Mx[:fa_monospace_c]}").                                                                                                         #monospace
+        gsub(/(^|#{Mx[:gl_c]}|\s+|['"]|[#{Mx[:nbsp]}#{Mx[:fa_o_c]}#{Mx[:fa_c]}]|\(|\>)\"\{(.+?)\}\"/m,
+          "\\1#{Mx[:fa_cite_o]}\\2#{Mx[:fa_c_o]}cite#{Mx[:fa_c]}").                                                                                                      #cite /blockquote?
+        gsub(/(^|[^\\])\^\{(.+?)\}\^/m,
+          "\\1#{Mx[:fa_superscript_o]}\\2#{Mx[:fa_superscript_c]}").                                                                                                     #superscript
+        gsub(/(^|[^\\]),\{(.+?)\},/m,
+          "\\1#{Mx[:fa_subscript_o]}\\2#{Mx[:fa_subscript_c]}").                                                                                                         #subscript
+        gsub(/(^|#{Mx[:gl_c]}|\s+|['"]|#{Mx[:nbsp]}|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|\(|\>)\+\{(.+?)\}\+/m,
+          "\\1#{Mx[:fa_insert_o]}\\2#{Mx[:fa_insert_c]}").                                                                                                               #inserted text
+        gsub(/(^|#{Mx[:gl_c]}|\s+|['"]|#{Mx[:nbsp]}|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|\(|\>)-\{(.+?)\}-/m,
+          "\\1#{Mx[:fa_strike_o]}\\2#{Mx[:fa_strike_c]}").                                                                                                               #strikethrough - deleted text
+        gsub(/(^|#{Mx[:gl_c]}|\s+|['"]|#{Mx[:nbsp]}|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|\(|\>|\d+)\^(\S+?)\^/,
+          "\\1#{Mx[:fa_superscript_o]}\\2#{Mx[:fa_superscript_c]}")                                                                                                      #superscript single word, watch digit added
+      dob
+    end
+    def bodymarkup(dob)
+      # << http://www.jus.uio.no/sisu/sisu_markup_table/markup >>
+      # See: data/sisu/sample/document_samples_sisu_markup/
+      ## fontface
+      # *{emphasis}*        e{emphasis}e       <strong>emphasis</strong>
+      # !{bold text}!       b{bold}b           <b>bold text</b>
+      # _{underline}_       u{underline}u      <u>underline</u>
+      # /{italics}/         i{italics}i        <i>italics</i>
+      # "{citation}"        c{citation}c       <cite>citation</cite> #blockquote?
+      # ^{superscript}^                        <sup>superscript</sup>
+      # ,{subscript},                          <sub>subscript</sub>
+      # +{inserted text}+                      <ins>inserted text</ins>
+      # -{deleted text}-                       <del>deleted text</del>
+      # #{monospace text}#
+      #
+      # {url address}:url
+      # {image.png}imageurl
+      # {image.png}png
+      # ~{endnote}~
+      # !_                                    #bold/emphasise paragraph
+      # _"                                    #blockquote paragraph
+      # _1                  <:i1>            #indent paragraph 1 step
+      # _2                  <:i2>            #indent paragraph 2 steps
+      # _3                  <:i3>            #indent paragraph 3 steps
+      # _4                  <:i4>            #indent paragraph 4 steps
+      # _*                                    #bullet (list) ●
+      # _1*                                   #bullet (list) indented
+      # _1*                                   #bullet (list) indented
+      # #                                     #numbered (list) level 1
+      # _#                                    #numbered (list) level 2
+      dob=dob.dup
+      if dob.is !=:meta \
+      && dob.is !=:comment \
+      && dob.is !=:code \
+      && dob.is !=:table
+        line_array=[]
+        word=dob.obj.scan(/\S+|\n/) #unless line =~/^(?:#{Mx[:meta_o]}|%+\s)/ #visit
+        if word
+          word.each do |w| # _ - / # | : ! ^ ~
+            unless w =~/~\{|\}~|~\[|\]~|^\^~|~\^|\*~\S+|~#|\{t?~|\{table|https?:\/\/\S+/           # do something earlier about table!!
+              w=w.gsub(/\\?~/,"#{Mx[:gl_o]}#126#{Mx[:gl_c]}")                                      #escaped special character
+            end
+            w=w.gsub(/^\<$/,
+              "#{Mx[:gl_o]}#lt#{Mx[:gl_c]}").gsub(/^\>$/,"#{Mx[:gl_o]}#gt#{Mx[:gl_c]}")            #escaped special character
+            line_array << w
+          end
+          dob.obj=line_array.join(' ')
+          dob.obj=dob.obj.strip
+        end
+        dob.obj=dob.obj.
+          gsub(/^([*#.-]{1,12})$/,'\1 ~#').                                                        #ocn off for these paragraph separators
+          gsub(/~\{(.+?)\}~/m,Mx[:en_a_o] + '\1' + Mx[:en_a_c]).
+          gsub(/~\[([^*+].+?)\]~/m,Mx[:en_b_o] + '* \1' + Mx[:en_b_c]).                            #default if markup does not specify
+          gsub(/~\[(.+?)\]~/m,Mx[:en_b_o] + '\1' + Mx[:en_b_c])
+        if dob.is ==:heading \
+        and dob.ln ==0
+          dob.obj=dob.obj.gsub(/\s*@title\b/," #{@md.title.full}")
+          dob.obj=if defined? @md.creator.author \
+          and @md.creator.author
+            dob.obj.gsub(/\s+(?:@creator|@author)/,",#{Mx[:br_line]}#{@md.creator.author}")
+          else dob.obj.gsub(/\s+(?:@creator|@author)/,'')
+          end
+        end
+        if defined? @md.title \
+        and @md.title \
+        and defined? @md.title.full \
+        and defined? @md.creator \
+        and @md.creator
+          if dob.is ==:heading
+            dob.obj=dob.obj.gsub(/^\s*@title\s*$/,@md.title.full) if dob.lv =~/1/
+            dob.obj=if dob.lv =~/[23]/ \
+            and defined? @md.creator.author \
+            and @md.creator.author
+              dob.obj.
+                gsub(/^\s*(?:(by\s+)?(?:@creator|@author))\s*$/,
+                  "\\1#{@md.creator.author}")
+            else dob.obj.gsub(/^\s*(?:(by\s+)?(?:@creator|@author))\s*$/,'\1')
+            end
+          end
+        end
+        dob.obj=dob.obj.gsub(/<(https?:\/\/\S+?)>/,'< \1 >').                     #catch problem markup
+          gsub(/<:=(\S+?)>/,'{ c_\1.png 14x14 }image').
+          gsub(/<!(\S+)!>/,'<:\1>').                                              #escaped special character
+          gsub(/&nbsp;/,"#{Mx[:nbsp]}").                                          #escaped special character
+          gsub(/\\~/,"#{Mx[:gl_o]}#126#{Mx[:gl_c]}").                             #escaped special character
+          gsub(/\\\{/,"#{Mx[:gl_o]}#123#{Mx[:gl_c]}").                            #escaped special character
+          gsub(/\\\}/,"#{Mx[:gl_o]}#125#{Mx[:gl_c]}").                            #escaped special character
+          gsub(/\\\<</,"#{Mx[:gl_o]}#lt#{Mx[:gl_c]}#{Mx[:gl_o]}#lt#{Mx[:gl_c]}"). #escaped special character
+          gsub(/\\\>>/,"#{Mx[:gl_o]}#gt#{Mx[:gl_c]}#{Mx[:gl_o]}#gt#{Mx[:gl_c]}"). #escaped special character
+          gsub(/\\\</,"#{Mx[:gl_o]}#lt#{Mx[:gl_c]}").                             #escaped special character
+          gsub(/\\\>/,"#{Mx[:gl_o]}#gt#{Mx[:gl_c]}").                             #escaped special character
+          gsub(/\\\_/,"#{Mx[:gl_o]}#095#{Mx[:gl_c]}").                            #escaped special character
+          gsub(/\\\-/,"#{Mx[:gl_o]}#045#{Mx[:gl_c]}").                            #escaped special character
+          gsub(/\\\+/,"#{Mx[:gl_o]}#043#{Mx[:gl_c]}").                            #escaped special character
+          gsub(/\\\//,"#{Mx[:gl_o]}#047#{Mx[:gl_c]}").                            #escaped special character
+          gsub(/\\\#/,"#{Mx[:gl_o]}#035#{Mx[:gl_c]}").                            #escaped special character
+          gsub(/\\\&/,"#{Mx[:gl_o]}#038#{Mx[:gl_c]}").                            #&amp; #escaped special character
+          gsub(/\\\|/,"#{Mx[:gl_o]}#124#{Mx[:gl_c]}").                            #not really a sisu special character but made available as possibility
+          gsub(/\\\:/,"#{Mx[:gl_o]}#058#{Mx[:gl_c]}").                            #not really a sisu special character but made available as possibility
+          gsub(/\\\!/,"#{Mx[:gl_o]}#033#{Mx[:gl_c]}").                            #not really a sisu special character but made available as possibility
+          gsub(/\\\^/,"#{Mx[:gl_o]}#094#{Mx[:gl_c]}").                            #not really a sisu special character but made available as possibility
+          gsub(/\\\,/,"#{Mx[:gl_o]}#044#{Mx[:gl_c]}").                            #not really a sisu special character but made available as possibility
+          gsub(/\\\\/,"#{Mx[:gl_o]}#092#{Mx[:gl_c]}").                            #escaped special character
+          gsub(/\\\*/,"#{Mx[:gl_o]}#042#{Mx[:gl_c]}").                            #escaped special character
+          gsub(/\\\!/,"#{Mx[:gl_o]}#033#{Mx[:gl_c]}")                             #escaped special character
+        if dob.obj=~/(?:https?:|ftp:|\{([^{}]+?)\}(?:#|:|[.]{1,2}\/))\S+/m
+          if dob.obj=~/(?:^|[#{Mx[:gl_c]}#{Mx[:nbsp]} ])\{~\^ (?:.+?)\s*\}(?:(?:https?:|ftp:|:|[.]{1,2}\/)\S+?)\s*#{Mx[:en_a_o]}(.+?)#{Mx[:en_a_c]}/m
+            dob.obj=dob.obj.
+              gsub(/(^|[#{Mx[:gl_c]}#{Mx[:nbsp]} ])\{~\^ ([^}]+?)\s*\}((?:https?:|ftp:|:|[.]{1,2}\/)\S+?)\s*#{Mx[:en_a_o]}(.+?)#{Mx[:en_a_c]}/m,
+                "\\1#{Mx[:lnk_o]}\\2#{Mx[:lnk_c]}\\3 #{Mx[:en_a_o]}\\3 \\4#{Mx[:en_a_c]}") # watch
+          end
+          if dob.obj=~/(?:^|[#{Mx[:gl_c]}#{Mx[:nbsp]} ])\{~\^ (?:.+?)\s*\}(?:(?:https?:|ftp:|:|[.]{1,2}\/)\S+?)([;,.]?)(?=\s|[#{Mx[:br_line]}#{Mx[:br_paragraph]}#{Mx[:br_nl]}]|$)/m
+            dob.obj=dob.obj.
+              gsub(/(^|[#{Mx[:gl_c]}#{Mx[:nbsp]} ])\{~\^ (.+?)\s*\}((?:https?:|ftp:|:|[.]{1,2}\/)\S+?)([;,.]?)(?=\s|[#{Mx[:br_line]}#{Mx[:br_paragraph]}#{Mx[:br_nl]}]|$)/m,
+                "\\1#{Mx[:lnk_o]}\\2#{Mx[:lnk_c]}\\3\\4 #{Mx[:en_a_o]}\\3#{Mx[:en_a_c]} ")
+          end
+          dob.obj=dob.obj.
+              gsub(/(^|[^#])\{\s*([^{}]+?)\s*\}((?:https?:|:|[.]{2}\/|#)\S+?)(?=\s|[#{Mx[:br_line]}#{Mx[:br_paragraph]}#{Mx[:br_nl]}#{Mx[:en_a_o]}#{Mx[:en_b_o]}]|$)/,
+                "\\1#{Mx[:lnk_o]}\\2#{Mx[:lnk_c]}\\3").                                                                                                                    #linked (text or image, however text cannot include modified face, e.g. bold, ital, underline)
+            gsub(/(^|[#{Mx[:gl_c]}#{Mx[:lnk_c]}#{Mx[:en_a_o]}#{Mx[:en_b_o]}(\s])((?:https?|ftp):\/\/\S+?\.[^>< ]+?)([,.;'"]?)(?=[\s#{Mx[:en_a_c]}#{Mx[:en_b_c]}#{Mx[:br_line]}#{Mx[:br_paragraph]}#{Mx[:br_nl]}]|$)/m,
+              %{\\1#{Mx[:url_o]}\\2#{Mx[:url_c]}\\3}).
+            gsub(/#{Mx[:lnk_c]}#(\S+?[^>< ]+?)([()\[\]]*[,.;:!?'"]{0,2})(?=[\s#{Mx[:en_a_c]}#{Mx[:en_b_c]}#{Mx[:br_line]}#{Mx[:br_paragraph]}#{Mx[:br_nl]}]|$)/m,
+              %{#{Mx[:lnk_c]}#{Mx[:rel_o]}\\1#{Mx[:rel_c]}\\2}).
+            gsub(/#{Mx[:lnk_c]}:(\S+?[^>< ]+?)([()\[\]]*[,.;:!?'"]{0,2})(?=[\s#{Mx[:en_a_c]}#{Mx[:en_b_c]}#{Mx[:br_line]}#{Mx[:br_paragraph]}#{Mx[:br_nl]}]|$)/m,
+              %{#{Mx[:lnk_c]}#{Mx[:rel_o]}:\\1#{Mx[:rel_c]}\\2}).
+            gsub(/#{Mx[:lnk_c]}[.]{2}\/(\S+?[^>< ]+?)([()\[\]]*[,.;:!?'"]{0,2})(?=[\s#{Mx[:en_a_c]}#{Mx[:en_b_c]}#{Mx[:br_line]}#{Mx[:br_paragraph]}#{Mx[:br_nl]}]|$)/m,
+              %{#{Mx[:lnk_c]}#{Mx[:rel_o]}:\\1#{Mx[:rel_c]}\\2})
+        end
+        if dob.obj=~/_(?:https?|ftp):\S+/m           # _http://url #CHECK
+          dob.obj=dob.obj.gsub(/(^|[#{Mx[:gl_c]}#{Mx[:lnk_c]}#{Mx[:en_a_o]}#{Mx[:en_b_o]}(\s])(_(?:https?|ftp):\/\/\S+?\.[^>< ]+?)([,.;'"]?)(?=[\s#{Mx[:en_a_c]}#{Mx[:en_b_c]}#{Mx[:br_line]}#{Mx[:br_paragraph]}#{Mx[:br_nl]}]|$)/m,
+            %{\\1#{Mx[:url_o]}\\2#{Mx[:url_c]}\\3})
+        end
+        dob=fontface(dob)
+        dob.obj=dob.obj.
+          gsub(/<[:e]\s+(.+?)!?>/,
+            "#{Mx[:en_a_o]}\\1#{Mx[:en_a_c]}").                                                                                                                             #not tested
+          gsub(/(^|#{Mx[:br_nl]})\s*_\*\s*/,
+            "\\1#{Mx[:gl_bullet]}").                                                                                                                                        #bullets, shortcut
+          gsub(/=\{(.+?)\}/,
+            "#{Mx[:idx_o]}\\1#{Mx[:idx_c]}").
+          gsub(/^\s*_([1-9])\*\s*/,
+            "#{Mx[:pa_o]}:i\\1:\\1#{Mx[:pa_c]}#{Mx[:gl_bullet]}").                                                                                                          #bullets, shortcut
+          gsub(/^\s*_([1-9])\s+/,
+            "#{Mx[:pa_o]}:i\\1:\\1#{Mx[:pa_c]}").                                                                                                                           #indent
+          gsub(/^\s*_([1-9])!\s+(.+?)\s*$/,
+            "#{Mx[:pa_o]}:i\\1:\\1#{Mx[:pa_c]}#{Mx[:fa_bold_o]}\\2#{Mx[:fa_bold_c]} ").                                                                                     #indent bold
+          gsub(/^\s*__([1-9])\s+/,
+            "#{Mx[:pa_o]}:i0:\\1#{Mx[:pa_c]}").                                                                                                                             #hang
+          gsub(/^\s*__([1-9])!\s+(.+?)\s*$/,
+            "#{Mx[:pa_o]}:i0:\\1#{Mx[:pa_c]}#{Mx[:fa_bold_o]}\\2#{Mx[:fa_bold_c]} ").                                                                                       #hangdef
+          gsub(/^\s*_([0-9])_([0-9])\s+/,
+            "#{Mx[:pa_o]}:i\\1:\\2#{Mx[:pa_c]}").                                                                                                                           #hang
+          gsub(/^\s*_([0-9])_([0-9])!\s+(.+?)\s*$/,
+            "#{Mx[:pa_o]}:i\\1:\\2#{Mx[:pa_c]}#{Mx[:fa_bold_o]}\\3#{Mx[:fa_bold_c]} ").                                                                                     #hangdef
+          gsub(/<:hi>/,"#{Mx[:fa_hilite_o]}").                                                                                                                              #'<span style="background-color: rgb(255,240,196)">'). # bright yellow rgb(255,255,0) pale yellow rgb(255,255,200)
+          gsub(/<:\/hi>/,"#{Mx[:fa_hilite_c]}"). #'</span>').
+          gsub(/(#{Mx[:gr_o]}verse#{Mx[:gr_c]}.+)/m,"\\1\n").
+          gsub(/[ ]+($)/,'\1').
+          gsub(/\{\s*(.+?)\s*\}(https?:\S+?)([;,.]?)(?=\s|[#{Mx[:br_line]}#{Mx[:br_paragraph]}#{Mx[:br_nl]}#{Mx[:en_a_o]}#{Mx[:en_b_o]}]|$)/,
+            "#{Mx[:lnk_o]}\\1#{Mx[:lnk_c]}#{Mx[:url_o]}\\2#{Mx[:url_c]}\\3").                                                                                               #any remaining linked text or image
+          gsub(/\{\s*(.+?)\s*\}(#{Mx[:url_o]}\S+?#{Mx[:url_c]})/,
+            "#{Mx[:lnk_o]}\\1#{Mx[:lnk_c]}\\2").                                                                                                                            #any remaining linked text or image
+          gsub(/(^|\s)([a-zA-Z0-9._-]+\@\S+?\.[a-zA-Z0-9._-]+)/,"\\1#{Mx[:url_o]}\\2#{Mx[:url_c]}").
+          gsub(/(^|[ ])\{\s*(.+?)\s*\}(\S+?)([;,.]?)(?=\s|[#{Mx[:br_line]}#{Mx[:br_paragraph]}#{Mx[:br_nl]}#{Mx[:en_a_o]}#{Mx[:en_b_o]}]|$)/,
+            "\\1#{Mx[:lnk_o]}\\2#{Mx[:lnk_c]}\\3\\4").                                                                                                                      #any remaining linked text or image
+          gsub(/\{\s*(.+?)\s*\}#([a-zA-Z0-9][a-zA-Z0-9_-]*)([;,.]?)(?=\s|[#{Mx[:br_line]}#{Mx[:br_paragraph]}#{Mx[:br_nl]}#{Mx[:en_a_o]}#{Mx[:en_b_o]}]|$)/,
+            "#{Mx[:lnk_o]}\\1#{Mx[:lnk_c]}#{Mx[:rel_o]}\\2#{Mx[:rel_c]}\\3").                                                                                               #any remaining linked text or image, check need
+          gsub(/\{\s*(.+?)\s*\}(#{Mx[:rel_o]}\S+?#{Mx[:rel_c]})/,
+            "#{Mx[:lnk_o]}\\1#{Mx[:lnk_c]}\\2").                                                                                                                            #any remaining linked text or image, check need
+          gsub(/\{\s*(.+?)\s*\}(image)/,
+            "#{Mx[:lnk_o]}\\1#{Mx[:lnk_c]}\\2")                                                                                                                             #linked image
+      elsif dob.is==:table
+        dob=fontface(dob)
+      elsif dob.is ==:code
+        dob.obj=dob.obj.
+          gsub(/#{Mx[:meta_o]}(\S+?)#{Mx[:meta_c]}\s*/,'@\1: ').
+          gsub(/(^|#{Mx[:gl_c]}|\s)&lt;(?:br(?: \/)?)&gt;([\s,.]|$)/,'\1<br>\2') #convert <br> <br /> back, clumsy
+        if dob.number_
+          codeline=[]
+          ln=1
+          dob.obj.split(/#{Mx[:gr_o]}codeline#{Mx[:gr_c]}|<br(?: \/)?>|\n/).each_with_index do |cl,i|
+            unless i == 0
+              cl=cl.gsub(Mx[:br_nl],'')
+              w=3-ln.to_s.length
+              cl = "#{ln}#{Mx[:nbsp]*w}#{Mx[:vline]}#{cl}#{Mx[:br_nl]}"
+              ln +=1
+            end
+            codeline << cl
+          end
+          codeline= codeline.join("")
+          dob.obj=codeline
+        else
+          dob.obj=dob.obj.gsub(/#{Mx[:gr_o]}codeline#{Mx[:gr_c]}/,"\n")
+        end
+        dob
+      else # @\S+?:
+      end
+      dob
+    end
+    def tech                                                                       #script markup planned to be more strict for technical documents
+      # *{emphasis}*        e{emphasis}e       <strong>emphasis</strong>
+      # !{bold text}!       b{bold}b           <b>bold text</b>
+      # _{underline}_       u{underline}u      <u>underline</u>
+      # /{italics}/         i{italics}i        <i>italics</i>
+      # "{citation}"        c{citation}c       <cite>citation</cite>
+      # ^{superscript}^                        <sup>superscript</sup>
+      # ,{subscript},                          <sub>subscript</sub>
+      # +{inserted text}+                      <ins>inserted text</ins>
+      # -{deleted text}-                       <del>deleted text</del>
+      # #{monospace text}#
+      # {url address}:url
+      # {image.png}imageurl
+      # {image.png}png
+      # ~{endnote}~
+      # +1                  <!i1!>
+      # +2                  <!i2!>
+      puts 'tech'
+      @data.each do |line|
+        line=line.
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|[\(\[]|\>)e\{(.+?)\}e/,
+            "\\1#{@emph[:o]}\\2#{@emph[:c]}").                                                        #emphasis
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|[\(\[]|\>)b\{(.+?)\}b/,
+            "\\1#{Mx[:fa_bold_o]}\\2#{Mx[:fa_bold_c]}").                                              #bold
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|[\(\[]|\>)u\{(.+?)\}u/,
+            "\\1#{Mx[:fa_underscore_o]}\\2#{Mx[:fa_underscore_c]}").                                  #underscore
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|[\(\[]|\>)c\{(.+?)\}c/,
+            "\\1#{Mx[:fa_cite_o]}\\2#{Mx[:fa_c_o]}cite#{Mx[:fa_c]}").                                 #cite
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|[\(\[]|\>)i\{(.+?)\}i/,
+            "\\1#{Mx[:fa_italics_o]}\\2#{Mx[:fa_italics_c]}").                                        #italics
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|[\(\[]|\>)!\{(.+?)\}!/,
+            "\\1#{Mx[:fa_bold_o]}\\2#{Mx[:fa_bold_c]}").                                              #bold
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|[\(\[]|\>)\*\{(.+?)\}\*/,
+            "\\1#{@emph[:o]}\\2#{@emph[:c]}").                                                        #emphasis
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|[\(\[]|\>)_\{(.+?)\}_/,
+            "\\1#{Mx[:fa_underscore_o]}\\2#{Mx[:fa_underscore_c]}").                                  #underscore
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|[\(\[]|\(|\>)\/\{(.+?)\}\//,
+            "\\1#{Mx[:fa_italics_o]}\\2#{Mx[:fa_italics_c]}").                                        #italics
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|\(|\>)\"\{(.+?)\}\"/,
+            "\\1#{Mx[:fa_cite_o]}\\2#{Mx[:fa_c_o]}cite#{Mx[:fa_c]}").
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|\(|\>)\^\{(.+?)\}\^/,
+            "\\1#{Mx[:fa_superscript_o]}\\2#{Mx[:fa_superscript_c]}").
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|\(|\>)9\{(.+?)\}9/,
+            "\\1#{Mx[:fa_superscript_o]}\\2#{Mx[:fa_superscript_c]}").
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|\(|\>),\{(.+?)\},/,
+            "\\1#{Mx[:fa_subscript_o]}\\2#{Mx[:fa_subscript_c]}").
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|\(|\>)6\{(.+?)\}6/,
+            "\\1#{Mx[:fa_subscript_o]}\\2#{Mx[:fa_subscript_c]}").
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|\(|\>)\+\{(.+?)\}\+/,
+            "\\1#{Mx[:fa_insert_o]}\\2#{Mx[:fa_insert_c]}").
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|\(|\>)v\{(.+?)\}v/,
+            "\\1#{Mx[:fa_insert_o]}\\2#{Mx[:fa_insert_c]}").
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|\(|\>)-\{(.+?)\}-/,
+            "\\1#{Mx[:fa_strike_o]}\\2#{Mx[:fa_strike_c]}").
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|\(|\>)x\{(.+?)\}x/,
+            "\\1#{Mx[:fa_strike_o]}\\2#{Mx[:fa_strike_c]}").
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|\(|\>)\*(\S+?)\*/,
+            "\\1#{@emph[:o]}\\2#{@emph[:c]}").                                                        #emphasise single word, watch
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|\(|\>)\!(\S+?)\!/,
+            "\\1#{Mx[:fa_bold_o]}\\2#{Mx[:fa_bold_c]}").                                              #bold single word, watch
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|\(|\>)\/([\(\)a-zA-Z0-9']+?)\/([ ,.;:'"~$]|[^a-zA-Z0-9])/,
+            "\\1#{Mx[:fa_italics_o]}\\2#{Mx[:fa_italics_c]}\\3").                                     #italics single word, watch
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|\(|\>)_(\S+?)_/,
+            "\\1#{Mx[:fa_underscore_o]}\\2#{Mx[:fa_underscore_c]}").                                  #underscore single word, watch
+          gsub(/(^|\s+|['"]|#{Mx[:fa_o_c]}|#{Mx[:fa_c]}|\(|\>)\^(\S+?)\^/,
+            "\\1#{Mx[:fa_superscript_o]}\\2#{Mx[:fa_superscript_c]}").                                #check  #superscript single word, watch digit added
+          gsub(/^\s*_\([1-9]\)\(\*\+\)\s*/,
+            "#{Mx[:pa_o]}:i\\1#{Mx[:pa_c]}#{Mx[:fa_o]}\\2#{Mx[:fa_c_o]}").                            #bullets, shortcut
+          gsub(/^\s*_\([1-9]\)\s+/,
+            "#{Mx[:pa_o]}:i\\1#{Mx[:pa_c]}"). #watch
+          gsub(/^\s*__\([1-9]\)\s+/,
+            "#{Mx[:pa_o]}:h\\1#{Mx[:pa_c]}"). #watch
+          #line.gsub(/^\s*__\([1-9]\)!\s+/,
+          #  "#{Mx[:pa_o]}:hd\\1#{Mx[:pa_c]}"). #watch
+          gsub(/#{Mx[:br_line]}\s*_[12]\s+/,
+            "#{Mx[:br_line]} ")                                                                      #indent used in endnotes, not implemented, replace when ready with: line.gsub(/(?:<br>|<br \/>)\s*_([12])\s+/,'<br><:i\1> ')
+      end
+      @data
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** ao_endnotes.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/ao_endnotes.rb"
+# <<sisu_document_header>>
+module SiSU_AO_Endnotes
+  class Endnotes
+    def initialize(md,data,endnote_array=nil)
+      @md,@data,@endnote_array=
+      md, data, endnote_array
+      @endnote_counter,
+        @endnote_counter_asterisk,
+        @endnote_counter_dag=
+        1,1,1
+    end
+    def endnotes
+      data=@data
+      endnote_ref=1
+      @tuned_file=data.each.map do |dob|
+                                                                               # manually numbered endnotes <!e(\d)!> <!e_(\d)!> -->
+        if @md.opt.selections.str =~/--no-asterisk|--no-annotate/
+          dob.obj=dob.obj.
+            gsub(/#{Mx[:en_b_o]}\s.+?#{Mx[:en_b_c]}/,'')
+        end
+        if @md.opt.selections.str =~/--no-dagger|--no-annotate/
+          dob.obj=dob.obj.
+            gsub(/#{Mx[:en_b_o]}[+]\s.+?#{Mx[:en_b_c]}/,'')
+        end
+        if (defined? dob.obj) \
+        && (defined? dob.is) \
+        && dob.is !=:code
+          case dob.obj                                                         # auto-numbered endnotes <!e!> <!e_!> -->
+          when /#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}[*+]\s+.+?#{Mx[:en_b_c]}/
+            dob.obj=dob.obj.
+              gsub(/\s*(#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/,'\1')
+            word_mode=dob.obj.scan(/\S+/m)
+            word_mode=endnote_call_number(word_mode)
+            dob.obj=word_mode.join(' ')
+            endnote_ref+=1
+          when /~\^(?:\s|$)/                                              #%note inserts endnotes previously gathered from /^(<!e[:_]!>|[-~]\{{3})/ (in earlier loop)
+            word_mode=dob.obj.scan(/\S+/m)
+            word_mode=endnote_call_number(word_mode)
+            dob.obj=word_mode.join(' ')
+            endnote_ref+=1
+          end
+        end
+        dob
+      end.flatten
+      @endnote_counter,
+        @endnote_counter_asterisk,
+        @endnote_counter_dag=
+        1,1,1
+      @tuned_file
+    end
+    def endnote_call_number(words)
+      words.each do |word|
+        case word
+        when /#{Mx[:en_a_o]}/
+          unless word =~/#{Mx[:en_a_o]}[*+]+/
+            word.gsub!(/#{Mx[:en_a_o]}/,
+              "#{Mx[:en_a_o]}#{@endnote_counter} ")
+            @endnote_counter+=1
+          end
+        when /#{Mx[:en_b_o]}/
+          if word =~/#{Mx[:en_b_o]}[+]/
+            word.gsub!(/#{Mx[:en_b_o]}[+]/,
+              "#{Mx[:en_b_o]}\+#{@endnote_counter_dag} ")
+            @endnote_counter_dag+=1
+          else
+            word.gsub!(/#{Mx[:en_b_o]}[*]?/,
+              "#{Mx[:en_b_o]}\*#{@endnote_counter_asterisk} ")
+            @endnote_counter_asterisk+=1
+          end
+        when /~\^/
+          if @endnote_array
+            word.gsub!(/~\^/,
+              "#{@endnote_array[@endnote_counter-1]}")
+            @endnote_counter+=1
+          end
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    abstraction
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/cgi.org b/org/cgi.org
new file mode 100644
index 00000000..b127d405
--- /dev/null
+++ b/org/cgi.org
@@ -0,0 +1,1459 @@
+-*- mode: org -*-
+#+TITLE:       sisu cgi
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:cgi:
+#+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
+
+* cgi
+** cgi.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/cgi.rb"
+# <<sisu_document_header>>
+module  SiSU_CGI                                        #% database building documents
+  require_relative 'se'                                 # se.rb
+  require_relative 'cgi_pgsql'                          # cgi_pgsql.rb
+  require_relative 'cgi_sqlite'                         # cgi_sqlite.rb
+  class SearchSQL
+    def initialize(opt)
+      @opt=opt
+      @webserv=@opt.files[0].to_s.strip
+    end
+    def read
+      if @opt.act[:sample_search_form][:db]==:pg        # cgi_pgsql.rb
+        SiSU_CGI_PgSQL::SearchPgSQL.new(@opt,@webserv).pgsql
+      elsif @opt.act[:sample_search_form][:db]==:sqlite # cgi_sqlite.rb
+        SiSU_CGI_SQLite::SearchSQLite.new(@opt,@webserv).sqlite
+      else
+        puts <<-WOK
+  please select database type for which sample search form should be built (pgsql or sqlite)
+    sisu --sample-search-form --db=sqlite
+    sisu --sample-search-form --db=pg
+  other options include
+     --webserv-cgi='[cgi-server-name]'
+     --webserv-output='[sisu-output-server-with-base-path]'
+        WOK
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** cgi_sqlite.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/cgi_sqlite.rb"
+# <<sisu_document_header>>
+module  SiSU_CGI_SQLite                                 #% database building documents
+  require_relative 'se'                                 # se.rb
+  require_relative 'cgi_sql_common'                     # cgi_sql_common.rb
+    include SiSU_CGI_SQL
+  class SearchSQLite < CGI_Common
+    def initialize(opt,webserv)
+      @opt,@webserv=opt,webserv
+      @cX=SiSU_Screen::Ansi.new(opt.act[:color_state][:set]).cX
+      @env=SiSU_Env::InfoEnv.new('',opt)
+      @image_src="#{@env.url.webserv_cgi(opt)}/_sisu/image_sys"
+      @name_of={}
+      @name_of[:output_dir_structure]=if opt.dir_structure_by.to_s =~/(?:language|filetype|filename)/
+        opt.dir_structure_by.to_s
+      else 'language'
+      end
+      @name_of[:lingual]=if opt.lingual.to_s =~/(?:mono|multi)/
+        opt.lingual.to_s
+      else 'multi'
+      end
+      @name_of[:host_url_cgi]=%q{http://#{ENV['HTTP_HOST']}#{ENV['PATH_INFO']}}
+      @name_of[:host_url_docs]=%q{http://#{ENV['HTTP_HOST']}}
+      @name_of[:cgi_script]=%q{#{ENV['SCRIPT_NAME']}}
+      @image_src=%q{http://#{ENV['HTTP_HOST']}/_sisu/image_sys}
+      @common=SiSU_CGI_SQL::CGI_Common.new(@webserv,opt,@image_src,@env)
+      @cgi_file_name=@env.url.cgi_sample_search_form_name(opt)
+      @name_of_sqlite_db_file='sisu_sqlite.db'
+    end
+    def sqlite
+      serve=[]
+      Dir.foreach(@env.path.webserv) do |x|
+        if x !~/^\./ \
+        and FileTest.directory?("#{@env.path.webserv}/#{x}")
+          if FileTest.file?("#{@env.path.webserv}/#{x}/#{@name_of_sqlite_db_file}")
+            serve << x unless x =~/^_\S+/
+          end
+        end
+      end
+      serve=serve.sort
+      f1,f2,f3='','',''
+      serve.each do |x|
+        f1 << %{              <option value="#{Db[:name_prefix]}#{x}">#{x}</option>\n}
+      end
+      f2 <<  %{          selected_db=case cgi['db']\n}
+      serve.each do |x|
+        f2 << %{           when /#{Db[:name_prefix]}#{x}/ then '<option value="#{Db[:name_prefix]}#{x}">#{x}</option>'\n}
+      end
+      f2 << "          end\n"
+      f3 << %{          db_name='#{@name_of_sqlite_db_file}'\n}
+      f3 << %{          db_sqlite=case cgi['db']\n}
+      serve.each do |x|
+        f3 << %{          when /#{Db[:name_prefix]}#{x}/ then "#{@env.path.webserv}/#{x}/\#{db_name}"\n}
+      end
+      f3 << %{           else  "#{@env.path.webserv}/#{serve[0]}/\#{db_name}"\n          end\n}
+      if FileTest.writable?('.')
+        output=File.open(@cgi_file_name,'w')
+        output << header0 << header1 << header_desc << header2 << f1 << buttons1 << buttons2 << search_request << search_statement << search_statement_common << search_query1 << @common.pages << search_query2 << @common.tail << @common.main1 << f2 << f3 << dbi_connect << @common.main2 << @common.dir_structure << @common.main3
+        puts <<-WOK
+            generated sample search form: #{@cX.green}#{@cgi_file_name}#{@cX.off}
+            default database name:     #{@cX.green}#{Db[:name_prefix]}#{@env.path.base_markup_dir_stub}#{@cX.off} (#{@env.path.base_markup_dir_stub})
+            cgi & db host on:          #{@cX.blue}#{@env.url.webserv_base_cgi(@opt)}#{@cX.off}
+              to modify use:           #{@cX.brown}sisu --db-sqlite --webserv-search='#{@env.url.webserv_base_cgi(@opt)}'#{@cX.off}
+            sisu output on:            #{@cX.blue}#{@env.url.webserv_files_from_db(@opt)}#{@cX.off}
+              to modify use:           #{@cX.brown}sisu --db-sqlite --webserv-output='#{@env.url.webserv_files_from_db(@opt)}'#{@cX.off}
+            cgi search form link name: #{@cX.green}#{@env.url.cgi_sample_search_form_name(@opt)}#{@cX.off}
+              to modify use:           #{@cX.brown}sisu --db-sqlite --cgi-search-form-name='#{@env.url.cgi_sample_search_form_name(@opt)}'#{@cX.off}
+            #{@cX.fuchsia}(settings priority: command line; sisurc.yml; else defaults)#{@cX.off}
+
+            #{@cX.fuchsia}NOTE it is first necessary to create the database and tables and populate it#{@cX.off}
+
+            sisu --sqlite --dropall                          # removes existing postgresql db & tables
+            sisu --sqlite --createall -v                     # creates postgresql db & tables
+            sisu --sqlite --update -v *.sst  *.ssm           # populate the db
+            sisu --sample-search-form --sqlite               # creates the postgresql search form
+                                                             # this should be done after creating the db
+                                                             # to be searched
+            sisu --webrick &                                 # starts ruby webrick web server
+
+            # if necessary make the directory '/usr/lib/cgi-bin'
+            # here we copy the postgresql search form to cgi-bin
+            # (copy #{@cgi_file_name} to your cgi directory)
+            # set file permissions to 755
+        WOK
+        a=case @webserv
+        when /pwd/ then ''
+        else <<-WOK
+
+              sudo cp -vi #{Dir.pwd}/#{@cgi_file_name} /usr/lib/cgi-bin/.; \\
+              sudo chmod -v 755  /usr/lib/cgi-bin/#{@cgi_file_name}
+          WOK
+        end
+        b='(to create and populate sisu sqlite database see "man sisu" and in particular the -d flag)'
+        SiSU_Screen::Ansi.new(@opt.act[:color_state][:set],a,b).warn
+        a=<<-WOK
+
+              #{@env.webserv_base_cgi(@opt)}/cgi-bin/#{@cgi_file_name}
+
+        WOK
+        SiSU_Screen::Ansi.new(@opt.act[:color_state][:set],a).print_blue
+      else puts "failed in attempt to write #{@cgi_file_name} to present directory, is directory writable?"
+      end
+    end
+    def header0
+      <<-WOK_SQL
+#!/usr/bin/env ruby
+=begin
+#{about}
+ * Description: generates naive cgi search form for search of sisu database (sqlite)
+#{gpl}
+=end
+      begin
+        require 'cgi'
+        require 'fcgi'
+        require 'sqlite3'
+      rescue LoadError
+        puts 'cgi, fcgi or sqlite3 NOT FOUND (LoadError)'
+      end
+      @stub_default='sisu_sqlite'
+      @image_src="#{@image_src}"
+      @hosturl_cgi="#{@name_of[:host_url_cgi]}"
+      @hosturl_files="#{@name_of[:host_url_docs]}"
+      @output_dir_structure_by='#{@name_of[:output_dir_structure]}'
+      @lingual='#{@name_of[:lingual]}'
+      @db_name_prefix='#{Db[:name_prefix]}'
+      @base="#{@name_of[:host_url_cgi]}#{@name_of[:cgi_script]}"
+      WOK_SQL
+    end
+    def search_statement
+      <<-'WOK_SQL'
+      class DBI_SearchString
+        def initialize(l,t,q,cse=false)
+          @l,@t,@q=l,t,q
+        end
+        def string
+          search={ search: [], flag: false }
+          if @t =~/\S+/ or @q =~/\S+/
+            if @t =~/\S+/    then unescaped_search=CGI.unescape(@t)
+            elsif @q =~/\S+/ then unescaped_search=CGI.unescape(@q)
+            end
+            search_construct=[]
+            unescaped_search=unescaped_search.gsub(/\s*(AND|OR)\s*/,"%' \) \\1 #{@l} LIKE \( '%").
+              gsub(/(.+)/,"#{@l} LIKE \( '%\\1%' \)")
+            search_construct << unescaped_search
+            search_construct=search_construct.join(' ')
+            search[:search]                    << search_construct
+            search[:flag]=true
+            search
+          end
+          search
+        end
+      end
+      WOK_SQL
+    end
+    def search_query1
+      <<-'WOK_SQL'
+          @search_text=''
+          @search_text=search[:text].flatten.join(' AND ')
+          @search_text=@search_text.gsub(/(doc_objects\.clean\s+LIKE\s+\(\s*'%[^']+%'\s*\)\s+(?:(?:AND|OR)\s+doc_objects\.clean\s+LIKE\s+\(\s*'%[^']+%'\s*\))+)/,'(\1)')
+        end
+      WOK_SQL
+    end
+    def search_query2
+      <<-'WOK_SQL'
+        def sql_select_body
+          limit ||=@@limit
+          offset ||=@@offset
+          @sql_statement[:body]=%{SELECT metadata_and_text.title, metadata_and_text.creator_author, metadata_and_text.src_filename, metadata_and_text.language_document_char, metadata_and_text.notes_suffix, doc_objects.body, doc_objects.seg, doc_objects.ocn, metadata_and_text.tid FROM doc_objects, metadata_and_text WHERE #{@search_text} AND doc_objects.metadata_tid = metadata_and_text.tid ORDER BY metadata_and_text.language_document_char, metadata_and_text.title, metadata_and_text.src_filename, doc_objects.ocn}
+          @sql_statement[:range]=%{LIMIT #{limit} OFFSET #{offset} ;}
+          select=@sql_statement[:body] + ' ' + @sql_statement[:range]
+          select
+        end
+        def sql_select_body_format
+          %{<font color="#666666" size="2">#{sql_select_body}</font>}
+        end
+        def contents
+          @conn.execute(sql_select_body)
+        end
+      end
+      WOK_SQL
+    end
+    def dbi_connect
+      <<-'WOK_SQL'
+          @conn=SQLite3::Database.new(db_sqlite)
+          @conn.results_as_hash=true
+      WOK_SQL
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** cgi_pgsql.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/cgi_pgsql.rb"
+# <<sisu_document_header>>
+module  SiSU_CGI_PgSQL                                  #% database building documents
+  require_relative 'se'                                 # se.rb
+  require_relative 'cgi_sql_common'                     # cgi_sql_common.rb
+    include SiSU_CGI_SQL
+  class SearchPgSQL < CGI_Common
+    def initialize(opt,webserv)
+      @opt,@webserv=opt,webserv
+      @cX=SiSU_Screen::Ansi.new(opt.act[:color_state][:set]).cX
+      @env=SiSU_Env::InfoEnv.new('',opt)
+      @sys=SiSU_Env::SystemCall.new
+      @db=SiSU_Env::InfoDb.new
+      get_init=SiSU_Env::GetInit.new
+      @rc=get_init.sisu_yaml.rc
+      @name_of={}
+      @name_of[:output_dir_structure]=if opt.dir_structure_by.to_s =~/(?:language|filetype|filename)/
+        opt.dir_structure_by.to_s
+      else 'language'
+      end
+      @name_of[:lingual]=if opt.lingual.to_s =~/(?:mono|multi)/
+        opt.lingual.to_s
+      else 'multi'
+      end
+      @name_of[:db]=if defined? @rc['search'] \
+      and defined? @rc['search']['sisu'] \
+      and defined? @rc['search']['sisu']['action'] \
+      and @rc['search']['sisu']['action'] =~/https?:\/\/\S+?\.cgi/ \
+      and defined? @rc['search']['sisu']['db'] \
+      and @rc['search']['sisu']['db'] =~/\S+/
+        @rc['search']['sisu']['db']
+      else
+        @env.path.base_markup_dir_stub #'sisu' #breaks if not present
+      end
+      @name_of[:host_url_cgi]=%q{http://#{ENV['HTTP_HOST']}#{ENV['PATH_INFO']}}
+      @name_of[:host_url_docs]=%q{http://#{ENV['HTTP_HOST']}}
+      @name_of[:cgi_script]=%q{#{ENV['SCRIPT_NAME']}}
+      @name_of[:user]=@db.psql.user(opt)
+      @image_src=%q{http://#{ENV['HTTP_HOST']}/_sisu/image_sys}
+      @common=SiSU_CGI_SQL::CGI_Common.new(@webserv,opt,@image_src,@env)
+      @cgi_file_name=@env.url.cgi_sample_search_form_name(opt)
+    end
+    def pgsql
+      serve=[]
+      if @sys.psql
+        available_db_table=`psql --list`                            # system call requires psql
+        available_db=available_db_table.scan(/(#{Db[:name_prefix]}\S+)/) if not available_db_table.nil?
+        if available_db \
+        and available_db.is_a?(Array)
+          available_db.flatten.each do |x|
+            serve << x.gsub(/#{Db[:name_prefix]}(\S+)/,'\1')
+          end
+        else STDERR.puts "WARNING: no postgresql database available, (have you created one?)"
+        end
+        serve=serve.sort
+        f1,f2='',''
+        serve.each do |x|
+          f1 << %{              <option value="#{Db[:name_prefix]}#{x}">#{x}</option>\n} unless x =~/apache|sisu\/image/ #check
+        end
+      end
+      f2 << %q{          selected_db=%{<option value="#{@db_name_prefix}#{@stub}">#{@stub}</option>}} + "\n"
+      if FileTest.writable?('.')
+        output=File.open(@cgi_file_name,'w')
+        output << header0 << header1 << header_desc << header2 << f1 << buttons1 << buttons1_pgsql << buttons2 << search_request << search_statement << search_statement_common << search_query1 << @common.pages << search_query2 << @common.tail << @common.main1 << f2 << dbi_connect << @common.main2 << @common.dir_structure << @common.main3
+        puts <<-WOK
+            generated sample search form: #{@cX.green}#{@cgi_file_name}#{@cX.off}
+            default database name:     #{@cX.green}#{Db[:name_prefix]}#{@name_of[:db]}#{@cX.off} (#{@name_of[:db]})
+            db user:                   #{@cX.green}#{@name_of[:user]}#{@cX.off}
+              to modify use:           #{@cX.brown}sisu --db-pg --db-user='#{@name_of[:user]}'#{@cX.off}
+
+            #{@cX.fuchsia}BASED ON ALREADY EXISTING databases#{@cX.off} (default database name: #{@db.psql.db})
+            NOTE it is first necessary to createdb,
+            use sisu to create the tables & populate the postgresql db
+
+            the database to be used for this directory (#{@db.psql.db})
+            will have to be created manually if it does not exist:
+            using postgresql tools directly (the following may work):
+              (i) if you are not yet a postgresql user,
+                #{@cX.brown}sudo su postgres
+                  createuser -d -a #{@env.user}
+                exit#{@cX.off}
+              (ii) create the database:
+                #{@cX.brown}createdb #{@db.psql.db}#{@cX.off}
+            [for a list of existing databases try 'psql --list']"
+
+            you can use sisu to create the database tables and populate the database with documents
+
+            sisu --pg --dropall                              # removes existing postgresql db & tables
+            sisu --pg --createall -v                         # creates postgresql db & tables
+            sisu --pg --update -v *.sst  *.ssm               # populate the db
+            sisu --sample-search-form --db-pg                # creates the postgresql search form
+                                                             # this should be done after creating the db
+                                                             # to be searched
+            sisu --webrick &                                 # starts ruby webrick web server
+
+            # if necessary make the directory '/usr/lib/cgi-bin'
+            # here we copy the postgresql search form to cgi-bin
+            # (copy #{@cgi_file_name} to your cgi directory)
+            # set file permissions to 755
+        WOK
+        a=case @webserv
+        when /pwd/ then ''
+        else <<-WOK
+
+              sudo cp -vi #{Dir.pwd}/#{@cgi_file_name} /usr/lib/cgi-bin/.; \\
+              sudo chmod -v 755  /usr/lib/cgi-bin/#{@cgi_file_name}
+          WOK
+        end
+        SiSU_Screen::Ansi.new(@opt.act[:color_state][:set],a).warn
+        a=<<-WOK
+              #{@env.webserv_base_cgi(@opt)}/cgi-bin/#{@cgi_file_name}
+        WOK
+        SiSU_Screen::Ansi.new(@opt.act[:color_state][:set],a).print_blue
+        a="\n\t(to create and populate postgresql database see 'man sisu' and in particular the --pg option)\n\t[the database to be used for this directory (#{@db.psql.db}) will have to be created manually if it does not exist,\n\tusing postgresql tools directly: 'createdb #{@db.psql.db}' for a list of existing databases try 'psql --list']"
+        SiSU_Screen::Ansi.new(@opt.act[:color_state][:set],a).txt_grey
+      else puts 'failed in attempt to write #{@cgi_file_name} to present directory,  is directory writable?'
+      end
+    end
+    def header0
+      <<-WOK_SQL
+#!/usr/bin/env ruby
+=begin
+#{about}
+ * Description: generates naive cgi search form for search of sisu database (pgsql)
+#{gpl}
+=end
+      begin
+        require 'cgi'
+        require 'fcgi'
+        require 'pg'
+      rescue LoadError
+        puts 'cgi, fcgi or pg NOT FOUND (LoadError)'
+      end
+      @stub_default='#{@name_of[:db]}'
+      @image_src="#{@image_src}"
+      @hosturl_cgi="#{@name_of[:host_url_cgi]}"
+      @hosturl_files="#{@name_of[:host_url_docs]}"
+      @output_dir_structure_by='#{@name_of[:output_dir_structure]}'
+      @lingual='#{@name_of[:lingual]}'
+      @port='#{@db.psql.port}'
+      @db_name_prefix='#{Db[:name_prefix]}'
+      @user='#{@name_of[:user]}'  # check user name for access to pg database: e.g. www-data or '#{@env.user}'
+      @base="#{@name_of[:host_url_cgi]}#{@name_of[:cgi_script]}"
+      WOK_SQL
+    end
+    def search_statement
+      <<-'WOK_SQL'
+      class DBI_SearchString
+        def initialize(l,t,q,cse=false)
+          @l,@t,@q,@c=l,t,q,cse
+        end
+        def string
+          search={ search: [], flag: false }
+          if @t =~/\S+/ or @q =~/\S+/
+            if @t =~/\S+/    then unescaped_search=CGI.unescape(@t)
+            elsif @q =~/\S+/ then unescaped_search=CGI.unescape(@q)
+            end
+            search_construct=[]
+            unescaped_search=if @c
+              unescaped_search.gsub(/\s*(AND|OR)\s*/,"' \) \\1 #{@l}~\( '").
+                gsub(/(.+)/,"#{@l}~\( '\\1' \)")
+            else
+              unescaped_search.gsub(/\s*(AND|OR)\s*/,"' \) \\1 #{@l}~*\( '").
+                gsub(/(.+)/,"#{@l}~*\( '\\1' \)")
+            end
+            search_construct << unescaped_search
+            search_construct=search_construct.join(' ')
+            search[:search]                    << search_construct
+            search[:flag]=true
+            search
+          end
+          search
+        end
+      end
+      WOK_SQL
+    end
+    def search_query1
+      <<-'WOK_SQL'
+          @search_text=''
+          @search_text=search[:text].flatten.join(' AND ')
+          @search_text=@search_text.gsub(/(doc_objects\.clean~[*]?\(\s*'[^']+'\s*\)\s+(?:(?:AND|OR)\s+doc_objects\.clean~[*]?\(\s*'[^']+'\s*\))+)/,'(\1)')
+        end
+      WOK_SQL
+    end
+    def search_query2
+      <<-'WOK_SQL'
+        def sql_select_body
+          limit ||=@@limit
+          offset ||=@@offset
+          @sql_statement[:body]=%{SELECT metadata_and_text.title, metadata_and_text.creator_author, metadata_and_text.src_filename, metadata_and_text.language_document_char, metadata_and_text.notes_suffix, doc_objects.body, doc_objects.seg, doc_objects.ocn, metadata_and_text.tid FROM doc_objects, metadata_and_text WHERE (#{@search_text}) AND doc_objects.metadata_tid = metadata_and_text.tid ORDER BY metadata_and_text.language_document_char, metadata_and_text.title, metadata_and_text.src_filename, doc_objects.ocn}
+          @sql_statement[:range]=%{LIMIT #{limit} OFFSET #{offset} ;}
+          select=@sql_statement[:body] + ' ' + @sql_statement[:range]
+          select
+        end
+        def sql_select_body_format
+          %{<font color="#666666" size="2">#{sql_select_body}</font>}
+        end
+        def contents
+          @conn.exec(sql_select_body)
+        end
+      end
+      WOK_SQL
+    end
+    def buttons1_pgsql
+      <<-'WOK_SQL'
+        <input type="checkbox" name="casesense" #{@checked_case}> case sensitive
+      WOK_SQL
+    end
+    def dbi_connect
+      <<-'WOK_SQL'
+          @conn=PG::Connection.open(dbname: @db, port: @port, user: @user)
+      WOK_SQL
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** cgi_sql_common.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/cgi_sql_common.rb"
+# <<sisu_document_header>>
+module SiSU_CGI_SQL
+  class CGI_Common
+    def initialize(webserv,opt,image_src,dir)
+      @webserv,@opt,@image_src,@env=webserv,opt,image_src,dir
+    end
+    def about
+      <<-'WOK_SQL'
+ * Name: SiSU information Structuring Universe
+ * Author: Ralph Amissah
+   * http://www.jus.uio.no/sisu
+   * http://www.jus.uio.no/sisu/SiSU/download
+      WOK_SQL
+    end
+    def gpl
+      <<-'WOK_SQL'
+ * Name: SiSU generated sample cgi search form
+
+ * Description: generated sample cgi search form for SiSU
+   (SiSU is a framework for document structuring, publishing and search)
+
+ * Author: Ralph Amissah
+
+ * Copyright: (C) 1997 - 2015, Ralph Amissah, All Rights Reserved.
+
+ * License: GPL 3 or later:
+
+   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 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 [http://www.gnu.org/licenses/].
+
+   If you have Internet connection, the latest version of the GPL should be
+   available at these locations:
+   <http://www.fsf.org/licenses/gpl.html>
+   [http://www.gnu.org/licenses/gpl.html]
+   <http://www.jus.uio.no/sisu/gpl.fsf>
+
+ * SiSU uses:
+   * Standard SiSU markup syntax,
+   * Standard SiSU meta-markup syntax, and the
+   * Standard SiSU object citation numbering and system
+
+ * Homepages:
+   [http://www.jus.uio.no/sisu]
+   [http://www.sisudoc.org]
+
+ * Ralph Amissah
+   [ralph@amissah.com]
+   [ralph.amissah@gmail.com]
+      WOK_SQL
+    end
+    def header1
+      <<-'WOK_SQL'
+#Common TOP
+      @@offset=0
+      @@canned_search_url=@base
+      @color_heading='#DDFFAA'
+      @color_match='#ffff48'
+      class Form
+        def initialize(base,search_field,selected_db,result_type,checked_sql_limit,checked_tip,checked_stats,checked_searched,checked_url,checked_case,checked_echo,checked_sql,checked_all,checked_none,checked_selected,checked_default,search_note,the_can='')
+          search_note='' if checked_searched !~/\S/
+          the_can='' if checked_url !~/\S/
+          search_field='' if checked_echo !~/\S/
+          @base,@search_field,@selected_db,@result_type,@checked_sql_limit,@checked_tip,@checked_stats,@checked_searched,@checked_url,@checked_case,@checked_echo,@checked_sql,@checked_all,@checked_none,@checked_selected,@checked_default,@search_note,@the_can=base,search_field,selected_db,result_type,checked_sql_limit,checked_tip,checked_stats,checked_searched,checked_url,checked_case,checked_echo,checked_sql,checked_all,checked_none,checked_selected,checked_default,search_note,the_can
+          @tip=if checked_tip =~/\S/
+            '<font size="2" color="#666666">text:__; fulltxt:__; keywords:__; title:__; author:__; topic_register:__; subject:__; description:__; publisher:__; editor:__; contributor:__; date:__; type:__; format:__; identifier:__; source:__; language:__; relation:__; coverage:__; rights:__; comment:__; abstract:__; filename:__;</font><br>'
+          else ''
+          end
+        end
+        def submission_form
+            search_form=<<-WOK
+      WOK_SQL
+    end
+    def header_desc
+      <<-WOK_SQL
+    <!DOCTYPE html>
+    <html>
+    <head>
+      <title>
+      <meta charset="utf-8">
+      <meta name="sourcefile" content="SiSU._sst" />
+      SiSU search form (sample): SiSU information Structuring Universe
+      </title>
+      <link rel="generator" href="http://www.jus.uio.no/sisu" />
+      <link rel="shortcut icon" href="#{@image_src}/rb7.ico" />
+      <link href="../_sisu/css/html.css" rel="stylesheet">
+    </head>
+    <body lang="en" xml:lang="en">
+    <table summary="band" border="0" cellpadding="3" cellspacing="0">
+    <tr><td width="20%">
+     <table summary="home button / home information" border="0" cellpadding="3" cellspacing="0">
+     <tr><td align="left">
+      <br><a href="http://sisudoc.org/" target="_top">
+        <b>SiSU</b>
+      </a>
+      <br><a href="http://git.sisudoc.org/" target="_top">
+        git
+      </a>
+     </td></tr>
+     </table>
+    </td>
+    <td>
+      <label for="find"><b>#{@env.sample_search_form_title(@opt.dir_structure_by)}</b></label>
+    </td></tr>
+    </table>
+      WOK_SQL
+    end
+    def header2
+      <<-'WOK_SQL'
+    <form action="#{@base}" id="Test Form" method="post">
+      <table cellpadding="2">
+      <tr><td valign=\"top\">
+          <textarea id="find" name="find" type="text" rows="6" cols="40" maxlength="256">#{@search_field}</textarea>
+      </td>
+      <td valign=\"top\">
+        #{@tip}
+        #{@search_note}
+        #{@the_can}
+      </td></tr></table>
+      <td valign=\"top\"><tr><td>
+        <!input type="text" id="find" name="find" value="#{@search_field}" />
+        <!input type="text" id="find" name="find" value="" />
+        <font size="2" color="#222222">
+        <b>to search:</b> select which database to search (drop-down menu below); enter your search query (in the form above); and <b>click on the search button</b> (below)
+        <br>
+        <select name="db" size="1">
+          #{@selected_db}
+      WOK_SQL
+    end
+    def buttons1
+      <<-'WOK_SQL'
+        </select>
+        <input type="submit" value="SiSU search" />
+        <input type="radio" name="view" value="index" #{@result_type[:index]}> index
+        <input type="radio" name="view" value="text" #{@result_type[:text]}> text / grep
+      WOK_SQL
+    end
+    def buttons2
+      <<-'WOK_SQL'
+        <br>
+          match limit:
+          <input type="radio" name="sql_match_limit" value="1000" #{@checked_sql_limit[:l1000]}> 1,000
+          <input type="radio" name="sql_match_limit" value="2500" #{@checked_sql_limit[:l2500]}> 2,500
+        <br>
+          <input type="checkbox" name="echo" #{@checked_echo}> echo query
+          <input type="checkbox" name="stats" #{@checked_stats}> result stats
+          <input type="checkbox" name="url" #{@checked_url}> search url
+          <input type="checkbox" name="searched" #{@checked_searched}> searched
+          <input type="checkbox" name="tip" #{@checked_tip}> available fields
+          <input type="checkbox" name="sql" #{@checked_sql}> sql statement
+        <br>
+          checks:
+          <input type="radio" name="checks" value="check_default" #{@checked_default}> default
+          <input type="radio" name="checks" value="check_selected" #{@checked_selected}> selected
+          <input type="radio" name="checks" value="check_all" #{@checked_all}> all
+          <input type="radio" name="checks" value="check_none" #{@checked_none}> none
+          </font>
+      </td></tr>
+      </table>
+    </form>
+      WOK
+        end
+      end
+      WOK_SQL
+    end
+    def search_request
+      <<-'WOK_SQL'
+      class SearchRequest                                                       #% search_for
+        attr_accessor :text1,:fulltext,:keywords,:title,:author,:topic_register,:subject,:description,:publisher,:editor,:contributor,:date,:type,:format,:identifier,:source,:language,:relation,:coverage,:rights,:comment,:abstract,:owner,:date_created,:date_issued,:date_modified,:date_available,:date_valid,:filename
+        def initialize(search_field='',q='')
+          @search_field,@q=search_field,q
+          @text1=@fulltext=@keywords=@title=@author=@topic_register=@subject=@description=@publisher=@editor=@contributor=@date=@type=@format=@identifier=@source=@language=@relation=@coverage=@rights=@comment=@abstract=@owner=@date_created=@date_issued=@date_modified=@date_available=@date_valid=@filename=''
+          if @search_field=~/\S/
+            @text1=text_to_match('text:')
+            @fulltext=text_to_match('fulltxt:')
+            @topic_register=text_to_match('topic_register:')
+            @title=text_to_match('title:')                  # DublinCore 1  - title
+            @author=text_to_match('(?:author|creator)s?:')  # DublinCore 2  - creator/author
+            @subject=text_to_match('subj(?:ect)?:')         # DublinCore 3  - subject
+            @description=text_to_match('description:')      # DublinCore 4  - description
+            @publisher=text_to_match('pub(?:lisher)?:')     # DublinCore 5  - publisher
+            @editor=text_to_match('editor:')
+            @contributor=text_to_match('contributor:')      # DublinCore 6  - contributor
+            @date=text_to_match('date:')                    # DublinCore 7  - date dd-mm-yy
+            @type=text_to_match('type:')                    # DublinCore 8  - type
+            @format=text_to_match('format:')                # DublinCore 9  - format
+            @identifier=text_to_match('identifier:')        # DublinCore 10 - identifier
+            @source=text_to_match('source:')                # DublinCore 11 - source
+            @language=text_to_match('language:')            # DublinCore 12 - language
+            @relation=text_to_match('relation:')            # DublinCore 13 - relation
+            @coverage=text_to_match('coverage:')            # DublinCore 14 - coverage
+            @rights=text_to_match('rights:')                # DublinCore 15 - rights
+            @keywords=text_to_match('key(?:words?)?:')
+            @comment=text_to_match('comment:')
+            @abstract=text_to_match('abs(?:tract)?:')
+            @owner=text_to_match('owner:')
+            @date_created=text_to_match('date_created:')
+            @date_issued=text_to_match('date_issued:')
+            @date_modified=text_to_match('date_modified:')
+            @date_available=text_to_match('date_available:')
+            @date_valid=text_to_match('date_valid:')
+            @filename=text_to_match('filename:')
+            @text1=text_to_match unless @keywords or @author or @title or @text1 or @fulltext or @comment or @abstract or @rights or @subject or @publisher or @date or @filename or @topic_register
+          else
+            @text1=q['s1'] if q['s1']=~/\S/
+            @fulltext=q['ft'] if q['ft']=~/\S/
+            @keywords=q['key'] if q['key']=~/\S/
+            @title=q['ti'] if q['ti']=~/\S/
+            @author=q['au'] if q['au']=~/\S/
+            @topic_register=q['tr'] if q['tr']=~/\S/
+            @subject=q['sj'] if q['sj']=~/\S/
+            @description=q['dsc'] if q['dsc']=~/\S/
+            @publisher=q['pb'] if q['pb']=~/\S/
+            @editor=q['cntr'] if q['cntr']=~/\S/
+            @contributor=q['cntr'] if q['cntr']=~/\S/
+            @date=q['dt'] if q['dt']=~/\S/
+            @type=q['ty'] if q['ty']=~/\S/
+            @identifier=q['id'] if q['id']=~/\S/
+            @source=q['src'] if q['src']=~/\S/
+            @language=q['lang'] if q['lang']=~/\S/
+            @relation=q['rel'] if q['rel']=~/\S/
+            @coverage=q['cov'] if q['cov']=~/\S/
+            @rights=q['cr'] if q['cr']=~/\S/
+            @comment=q['co'] if q['co']=~/\S/
+            @abstract=q['ab'] if q['ab']=~/\S/
+            @date_created=q['dtc'] if q['dtc']=~/\S/
+            @date_issued=q['dti'] if q['dti']=~/\S/
+            @date_modified=q['dtm'] if q['dtm']=~/\S/
+            @date_available=q['dta'] if q['dta']=~/\S/
+            @date_valid=q['dtv'] if q['dtv']=~/\S/
+            @filename=if q['doc'] and q['search'] !~/search db/ then q['doc']
+            elsif q['fns']=~/\S/                                then q['fns']
+            end
+            @@limit=q['ltd'] if q['ltd']=~/\d+/  # 1000
+            @@offset=q['off'] if q['off']=~/\d+/ # 0
+          end
+        end
+        def text_to_match(identifier='')
+          m={
+            string: /#{identifier}\s*(.+?)/,
+            string: /#{identifier}\s*(.+?)(?:;|\n|\r|$)/,
+            word: /#{identifier}[\s(]*(\S+)/
+          }
+          search_string=if @search_field =~m[:word]
+            search_string=if @search_field =~m[:braces] then m[:braces].match(@search_field)[1]
+            elsif @search_field =~m[:string]            then m[:string].match(@search_field)[1]
+            else
+              str=m[:word].match(@search_field)[1]
+              str=str.gsub(/[()]/,'')
+              str
+            end
+            search_string=search_string.strip.gsub(/\s+/,'+')
+          #else
+          #  "__"
+          end
+        end
+      end
+      WOK_SQL
+    end
+    def search_statement_common
+      <<-'WOK_SQL'
+      class DBI_SearchStatement
+        attr_reader :text_search_flag,:sql_select_body_format,:sql_offset,:sql_limit
+        def initialize(conn,search_for,q,c)
+          @conn=conn
+          @text_search_flag=false
+          @sql_statement={ body: '', endnotes: '', range: '' }
+          #@offset||=@@offset
+          #@offset+=@@limit
+          search={ text: [], endnotes: [] }
+          cse=(c =~/\S/) ? true : false
+          st=DBI_SearchString.new('doc_objects.clean',search_for.text1,q['s1'],cse).string
+          se=DBI_SearchString.new('endnotes.clean',search_for.text1,q['s1'],cse).string
+          @text_search_flag=st[:flag]
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          st=DBI_SearchString.new('metadata_and_text.fulltext',search_for.fulltext,q['ft'],cse).string
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          st=DBI_SearchString.new('metadata_and_text.title',search_for.title,q['ti'],cse).string
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          st=DBI_SearchString.new('metadata_and_text.creator_author',search_for.author,q['au'],cse).string
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          st=DBI_SearchString.new('metadata_and_text.classify_topic_register',search_for.topic_register,q['tr'],cse).string
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          st=DBI_SearchString.new('metadata_and_text.classify_subject',search_for.subject,q['sj'],cse).string
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          st=DBI_SearchString.new('metadata_and_text.classify_keywords',search_for.keywords,q['key'],cse).string
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          st=DBI_SearchString.new('metadata_and_text.notes_description',search_for.description,q['dsc'],cse).string
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          st=DBI_SearchString.new('metadata_and_text.publisher',search_for.publisher,q['pb'],cse).string
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          st=DBI_SearchString.new('metadata_and_text.creator_editor',search_for.editor,q['cntr'],cse).string
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          st=DBI_SearchString.new('metadata_and_text.creator_contributor',search_for.contributor,q['cntr'],cse).string
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          st=DBI_SearchString.new('metadata_and_text.date_published',search_for.date,q['dt'],cse).string
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          st=DBI_SearchString.new('metadata_and_text.notes_type',search_for.type,q['ty'],cse).string
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          st=DBI_SearchString.new('metadata_and_text.original_source',search_for.source,q['src'],cse).string
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          st=DBI_SearchString.new('metadata_and_text.language_document_char',search_for.language,q['lang'],cse).string
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          st=DBI_SearchString.new('metadata_and_text.notes_relation',search_for.relation,q['rel'],cse).string
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          st=DBI_SearchString.new('metadata_and_text.notes_coverage',search_for.coverage,q['cov'],cse).string
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          st=DBI_SearchString.new('metadata_and_text.rights_all',search_for.rights,q['cr'],cse).string
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          st=DBI_SearchString.new('metadata_and_text.notes_comment',search_for.comment,q['co'],cse).string
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          st=DBI_SearchString.new('metadata_and_text.notes_abstract',search_for.abstract,q['ab'],cse).string
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          st=DBI_SearchString.new('metadata_and_text.src_filename',search_for.filename,q['fns'],cse).string
+          if st[:flag]
+            search[:text]                    << st[:search]
+          end
+          @@limit=q['ltd'] if q['ltd']=~/\d+/  # 1000
+          @@offset=q['off'] if q['off']=~/\d+/ # 0
+      WOK_SQL
+    end
+    def pages
+      <<-'WOK_SQL'
+        def sql_offset
+          @@offset
+        end
+        def sql_match_limit
+          @@limit
+        end
+        def sql_canned_search
+          @offset_next=sql_offset.to_i + sql_match_limit.to_i
+          @offset_previous=sql_offset.to_i - sql_match_limit.to_i
+          def current
+            @@canned_search_url.to_s + '&ltd=' + sql_match_limit.to_s + '&off=' + sql_offset.to_s
+          end
+          def next
+            @@canned_search_url.to_s + '&ltd=' + sql_match_limit.to_s + '&off=' + @offset_next.to_s
+          end
+          def previous
+            @offset_previous >= 0 \
+            ? (@@canned_search_url.to_s + '&ltd=' + sql_match_limit.to_s + '&off=' + @offset_previous.to_s)
+            : ''
+          end
+          def start
+            @@canned_search_url.to_s + '&ltd=' + sql_match_limit.to_s + '&off=' + 0.to_s
+          end
+          self
+        end
+        def pre_next(beyond_limit,img)
+          can=sql_canned_search
+          page=(sql_offset.to_i + sql_match_limit.to_i)/sql_match_limit.to_i
+          if beyond_limit
+            if page.to_s =~ /^1$/
+              %{<br><center>
+              pg. #{page.to_s}
+              <a href="#{can.next}">
+                <img border="0" width="22" height="22" src="#{img}/arrow_next_red.png" alt="&nbsp;&gt;&gt;" />
+              </a>
+              </center>}
+            elsif page.to_s =~ /^2$/
+              %{<br><center>
+              <a href="#{can.previous}">
+                <img border="0" width="22" height="22" src="#{img}/arrow_prev_red.png" alt="&lt;&lt;&nbsp;" />
+              </a>
+              pg. #{page.to_s}
+              <a href="#{can.next}">
+                <img border="0" width="22" height="22" src="#{img}/arrow_next_red.png" alt="&nbsp;&gt;&gt;" />
+              </a>
+              </center>}
+            else
+              %{<br><center>
+              <a href="#{can.start}">
+                <img border="0" width="22" height="22" src="#{img}/arrow_prev_red.png" alt="|&lt;&nbsp;" />
+              </a>
+              <a href="#{can.previous}">
+                <img border="0" width="22" height="22" src="#{img}/arrow_prev_red.png" alt="&lt;&lt;&nbsp;" />
+              </a>
+              pg. #{page.to_s}
+              <a href="#{can.next}">
+                <img border="0" width="22" height="22" src="#{img}/arrow_next_red.png" alt="&nbsp;&gt;&gt;" />
+              </a>
+              </center>}
+            end
+          else
+            if page.to_s =~ /^1$/ then ''
+            elsif page.to_s =~ /^2$/
+              %{<br><center>
+              <a href="#{can.previous}">
+                <img border="0" width="22" height="22" src="#{img}/arrow_prev_red.png" alt="&lt;&lt;&nbsp;" />
+              </a>
+              pg. #{page.to_s}
+              </center>}
+            else
+              %{<br><center>
+              <a href="#{can.start}">
+                <img border="0" width="22" height="22" src="#{img}/arrow_prev_red.png" alt="|&lt;&nbsp;" />
+              </a>
+              <a href="#{can.previous}">
+                <img border="0" width="22" height="22" src="#{img}/arrow_prev_red.png" alt="&lt;&lt;&nbsp;" />
+              </a>
+              pg. #{page.to_s}
+              </center>}
+            end
+          end
+        end
+      WOK_SQL
+    end
+    def tail
+      v=SiSU_Env::InfoVersion.instance.get_version
+      <<-WOK_SQL
+      def tail
+        <<-'WOK'
+    <br><hr /><br>
+<table summary="SiSU summary" cellpadding="2" border="0">
+  <!-- widget sisu -->
+<tr><td valign="top" width="10%">
+ <table summary="home button / home information" border="0" cellpadding="3" cellspacing="0">
+ <tr><td align="left">
+  <br><a href="http://sisudoc.org/" target="_top">
+    <b>SiSU</b>
+  </a>
+  <br><a href="http://git.sisudoc.org/" target="_top">
+    git
+  </a>
+ </td></tr>
+ </table>
+</td>
+<td valign="top" width="45%">
+<!-- SiSU Rights -->
+  <p class="tiny_left"><font color="#666666" size="2">
+    Generated by
+      #{v.project} #{v.version} #{v.date} (#{v.date_stamp})
+    <br>
+    <a href="http://www.sisudoc.org" >
+    <b>#{v.project}</b></a> <sup>&copy;</sup> Ralph Amissah
+    1993, current 2015.
+    All Rights Reserved.
+    <br>
+      #{v.project} is software for document structuring, publishing and search,
+    <br>
+    <a href="http://www.jus.uio.no/sisu" >
+      www.jus.uio.no/sisu
+    </a>
+    and
+    <a href="http://www.sisudoc.org" >
+      www.sisudoc.org
+    </a>
+    sources
+    <a href="http://git.sisudoc.org" >
+      git.sisudoc.org
+    </a>
+  <br>
+    <i>w3 since October 3 1993</i>
+    <a href="mailto:ralph@amissah.com" >
+      ralph@amissah.com
+    </a>
+  <br>
+    mailing list subscription
+    <a href="http://lists.sisudoc.org/listinfo/sisu" >
+      http://lists.sisudoc.org/listinfo/sisu
+    </a>
+  <br>
+    <a href="mailto:sisu@lists.sisudoc.org" >
+      sisu@lists.sisudoc.org
+    </a>
+  </font></p>
+</td><td valign="top" width="45%">
+  <p class="tiny_left"><font color="#666666" size="2">
+    #{v.project} using:
+    <br>Standard SiSU markup syntax,
+    <br>Standard SiSU meta-markup syntax, and the
+    <br>Standard SiSU <u>object citation numbering</u> and system, (object/text identifying/locating system)
+  <br>
+    <sup>&copy;</sup> Ralph Amissah 1997, current 2015.
+    All Rights Reserved.
+  </font></p>
+</td></tr>
+  <!-- widget way better -->
+<tr><td valign="top" width="10%">
+  <p class="tiny_left"><font color="#666666" size="2">
+    <a href="http://www.gnu.org/licenses/gpl.html">
+      .:
+    </a>
+  </font></p>
+</td><td valign="top" width="45%">
+  <p class="tiny_left"><font color="#666666" size="2">
+    SiSU is released under
+    <a href="http://www.gnu.org/licenses/gpl.html">GPL&nbsp;v3</a>
+    or later,
+    <a href="http://www.gnu.org/licenses/gpl.html">
+      http://www.gnu.org/licenses/gpl.html
+    </a>
+  </font></p>
+</td><td valign="top" width="45%">
+  <p class="tiny_left"><font color="#666666" size="2">
+    #{v.project}, developed using
+    <a href="http://www.ruby-lang.org/en/">
+      Ruby
+    </a>
+    on
+    <a href="http://www.debian.org/">
+      Debian/Gnu/Linux
+    </a>
+    software infrastructure,
+    with the usual GPL (or OSS) suspects.
+  </font></p>
+</td></tr>
+</table>
+    <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" id="credits"></a>
+    </body></html>
+    WOK
+      end
+      WOK_SQL
+    end
+    def main1
+      <<-'WOK_SQL'
+      @tail=tail
+      @counter_txt_doc,@counter_txt_ocn,@counter_endn_doc,@counter_endn_ocn=0,0,0,0
+      @counters_txt,@counters_endn,@sql_select_body='','',''
+      FCGI.each_cgi do |cgi|
+        begin # all code goes in begin section
+          @search={ text: [], endnotes: [] }
+          q=CGI.new
+          @db=if cgi['db'] =~ /#{@db_name_prefix}(\S+)/
+            @stub=$1
+            cgi['db']
+          else
+            @stub=@stub_default
+            @db_name_prefix + @stub
+          end
+          checked_url,checked_stats,checked_searched,checked_tip,checked_case,checked_echo,checked_sql,checked_all,checked_none,checked_selected,checked_default,selected_db='','','','','','','','',''
+          result_type=(cgi['view']=~/text/) \
+          ? result_type={ index: '', text: 'checked'}
+          : result_type={ index: 'checked', text: ''}
+          @@limit=if cgi['sql_match_limit'].to_s=~/2500/
+            checked_sql_limit={ l1000: '', l2500: 'checked'}
+            '2500'
+          else
+            checked_sql_limit={ l1000: 'checked', l2500: ''}
+            '1000'
+          end
+          checked_echo='checked' if cgi['echo'] =~/\S/
+          checked_stats='checked' if cgi['stats'] =~/\S/
+          checked_url='checked' if cgi['url'] =~/\S/ or cgi['u'].to_i==1
+          checked_searched='checked' if cgi['searched'] =~/\S/
+          checked_tip='checked' if cgi['tip'] =~/\S/
+          checked_case='checked' if cgi['casesense'] =~/\S/
+          checked_sql='checked' if cgi['sql'] =~/\S/
+          if cgi['checks'] =~/check_all/ or cgi['check_all'] =~/\S/ or cgi['a'].to_i==1
+            checked_all='checked'
+            checked_echo=checked_stats=checked_url=checked_searched=checked_tip=checked_sql='checked'
+            checked_none=''
+          elsif cgi['checks'] =~/check_none/
+            checked_none='checked'
+            checked_all=checked_url=checked_stats=checked_searched=checked_tip=checked_echo=checked_sql=''
+          elsif cgi['checks'] =~/check_selected/
+            checked_selected='checked'
+          elsif cgi['checks'] =~/check_default/
+            checked_default='checked'
+            checked_echo=checked_stats=checked_url='checked'
+            checked_searched=checked_tip=checked_case=checked_sql=''
+          else
+            checked_selected='checked'
+            checked_echo=checked_stats=checked_url='checked'
+            checked_searched=checked_tip=checked_case=checked_sql=''
+          end
+      WOK_SQL
+    end
+    def main2
+      <<-'WOK_SQL'
+          search_field=cgi['find'] if cgi['find'] # =~/\S+/
+          @search_for=SearchRequest.new(search_field,q) #.analyze               #% search_for
+                                                                                 #% searches
+          #Canned_search.new(@base,@search_for.text1,cgi)
+          if @search_for.text1=~/\S+/ or @search_for.fulltext=~/\S+/ or @search_for.author=~/\S+/ or @search_for.topic_register=~/\S+/  #and search_field =~/\S/
+            s1='s1=' + CGI.escape(@search_for.text1) if @search_for.text1=~/\S/
+            ft='&ft=' + CGI.escape(@search_for.fulltext) if @search_for.fulltext=~/\S/
+            key='key=' + CGI.escape(@search_for.keywords) if @search_for.keywords=~/\S/
+            ti='&ti=' + CGI.escape(@search_for.title) if @search_for.title=~/\S/
+            au='&au=' + CGI.escape(@search_for.author) if @search_for.author=~/\S/
+            tr='&tr=' + CGI.escape(@search_for.topic_register) if @search_for.topic_register=~/\S/
+            sj='&sj=' + CGI.escape(@search_for.subject) if @search_for.subject=~/\S/
+            dsc='&dsc=' + CGI.escape(@search_for.description) if @search_for.description=~/\S/
+            pb='&pb=' + CGI.escape(@search_for.publisher) if @search_for.publisher=~/\S/
+            edt='&edt=' + CGI.escape(@search_for.editor) if @search_for.editor=~/\S/
+            cntr='&cntr=' + CGI.escape(@search_for.contributor) if @search_for.contributor=~/\S/
+            dt='&dt=' + CGI.escape(@search_for.date) if @search_for.date=~/\S/
+            ty='&ty=' + CGI.escape(@search_for.type) if @search_for.type=~/\S/
+            id='&id=' + CGI.escape(@search_for.identifier) if @search_for.identifier=~/\S/
+            src='&src=' + CGI.escape(@search_for.source) if @search_for.source=~/\S/
+            lang='&lang=' + CGI.escape(@search_for.language) if @search_for.language=~/\S/
+            rel='&rel=' + CGI.escape(@search_for.relation) if @search_for.relation=~/\S/
+            cov='&cov=' + CGI.escape(@search_for.coverage) if @search_for.coverage=~/\S/
+            cr='&cr=' + CGI.escape(@search_for.rights) if @search_for.rights=~/\S/
+            co='&co=' + CGI.escape(@search_for.comment) if @search_for.comment=~/\S/
+            ab='&ab=' + CGI.escape(@search_for.abstract) if @search_for.abstract=~/\S/
+            dtc='&dtc=' + CGI.escape(@search_for.date_created) if @search_for.date_created=~/\S/
+            dti='&dti=' + CGI.escape(@search_for.date_issued) if @search_for.date_issued=~/\S/
+            dtm='&dtm=' + CGI.escape(@search_for.date_modified) if @search_for.date_modified=~/\S/
+            dta='&dta=' + CGI.escape(@search_for.date_available) if @search_for.date_available=~/\S/
+            dtv='&dtv=' + CGI.escape(@search_for.date_valid) if @search_for.date_valid=~/\S/
+            fns='&fns=' + CGI.escape(@search_for.filename) if @search_for.filename=~/\S/
+            @@canned_search_url=(checked_all =~/checked/) \
+            ? "#{@base}?#{s1}#{ft}#{key}#{ti}#{au}#{tr}#{sj}#{dsc}#{pb}#{edt}#{cntr}#{dt}#{ty}#{id}#{src}#{lang}#{rel}#{cov}#{cr}#{co}#{ab}#{dtc}#{dti}#{dtm}#{dta}#{dtv}#{fns}&db=#{cgi['db']}&view=#{cgi['view']}&a=1"
+            : "#{@base}?#{s1}#{ft}#{key}#{ti}#{au}#{tr}#{sj}#{dsc}#{pb}#{edt}#{cntr}#{dt}#{ty}#{id}#{src}#{lang}#{rel}#{cov}#{cr}#{co}#{ab}#{dtc}#{dti}#{dtm}#{dta}#{dtv}#{fns}&db=#{cgi['db']}&view=#{cgi['view']}"
+            mod=ft=~/\S+/ ? (ft.gsub(/ft/,'s1')) : s1
+            @canned_base_url="#{@base}?#{mod}&db=#{cgi['db']}"
+            if checked_case=~/\S/
+              @search[:text][1]=%{doc_objects.clean~'#{@search_for.text1}'} #s1
+            else
+              @search[:text][1]=%{doc_objects.clean~*'#{@search_for.text1}'} #s1
+            end
+            canned_note='search url:'
+          else
+            @@canned_search_url="#{@base}?db=#{@db}&view=index"
+            canned_note='search url example:'
+          end
+          if search_field =~/\S+/
+            analyze_format=search_field.gsub(/\s*\n/,'; ')
+          elsif checked_all =~/checked/ or checked_url =~/checked/
+            canned_search=@@canned_search_url.scan(/(?:s1|ft|au|ti|fns|tr)=[^&]+/)
+            af=canned_search.join('; ')
+            af=af.gsub(/s1=/,'text: ').
+              gsub(/ft=/,'fulltxt: ').
+              gsub(/au=/,'author: ').
+              gsub(/ti=/,'title: ').
+              gsub(/fns=/,'filename: ').
+              gsub(/tr=/,'topic_register: ').
+              gsub(/%2B/,' ')
+            analyze_format=af
+            st=af.split(/\s*;\s*/)
+            search_field=st.join("\n")
+          end
+          green=%{<font size="2" color="#004000">}
+          canned_search_url_txt=CGI.escapeHTML(@@canned_search_url)
+          the_can=%{<font size="2" color="#666666">#{canned_note} <a href="#{@@canned_search_url}">#{canned_search_url_txt}</a></font><br>}
+          p_text=p_fulltext=p_keywords=p_title=p_author=p_topic_register=p_subject=p_description=p_publisher=p_editor=p_contributor=p_date=p_type=p_format=p_identifier=p_source=p_language=p_relation=p_coverage=p_rights=p_comment=p_abstract=p_filename=''
+          p_filename=%{filename: #{green}#{@search_for.filename}</font><br>} if @search_for.filename =~/\S+/
+          p_text=%{text: #{green}#{@search_for.text1}</font><br>} if @search_for.text1 =~/\S+/
+          p_fulltext=%{fulltxt: #{green}#{@search_for.fulltext}</font><br>} if @search_for.fulltext =~/\S+/
+          p_title=%{title: #{green}#{@search_for.title}</font><br>} if @search_for.title =~/\S+/
+          p_author=%{author: #{green}#{@search_for.author}</font><br>} if @search_for.author =~/\S+/
+          p_editor=%{editor: #{green}#{@search_for.editor}</font><br>} if @search_for.editor=~/\S+/
+          p_contributor=%{contributor: #{green}#{@search_for.contributor}</font><br>} if @search_for.contributor =~/\S+/
+          p_date=%{date: #{green}#{@search_for.date}</font><br>} if @search_for.date =~/\S+/
+          p_rights=%{rights: #{green}#{@search_for.rights}</font><br>} if @search_for.rights =~/\S+/
+          p_topic_register=%{topic_register: #{green}#{@search_for.topic_register}</font><br>} if @search_for.topic_register =~/\S+/
+          p_subject=%{subject: #{green}#{@search_for.subject}</font><br>} if @search_for.subject =~/\S+/
+          p_keywords=%{keywords: #{green}#{@search_for.keywords}</font><br>} if @search_for.keywords =~/\S+/
+          p_identifier=%{identifier: #{green}#{@search_for.identifier}</font><br>} if @search_for.identifier =~/\S+/
+          p_type=%{type: #{green}#{@search_for.type}</font><br>} if @search_for.type =~/\S+/
+          p_format=%{format: #{green}#{@search_for.format}</font><br>} if @search_for.format =~/\S+/
+          p_relation=%{relation: #{green}#{@search_for.relation}</font><br>} if @search_for.relation =~/\S+/
+          p_coverage=%{coverage: #{green}#{@search_for.coverage}</font><br>} if @search_for.coverage =~/\S+/
+          p_description=%{description: #{green}#{@search_for.description}</font><br>} if @search_for.description =~/\S+/
+          p_abstract=%{abstract: #{green}#{@search_for.abstract}</font><br>} if @search_for.abstract =~/\S+/
+          p_comment=%{comment: #{green}#{@search_for.comment}</font><br>} if @search_for.comment =~/\S+/
+          p_publisher=%{publisher: #{green}#{@search_for.publisher}</font><br>} if @search_for.publisher =~/\S+/
+          p_source=%{source: #{green}#{@search_for.source}</font><br>} if @search_for.source =~/\S+/
+          p_language=%{language: #{green}#{@search_for.language}</font><br>} if @search_for.language =~/\S+/
+          search_note=<<-WOK
+      <font size="2" color="#666666">
+      <b>database:</b> #{green}#{@db}</font>; <b>selected view:</b> #{green}#{cgi['view']}</font>
+      <b>search string:</b> "#{green}#{analyze_format}</font>"<br>
+      #{p_text} #{p_fulltext} #{p_keywords} #{p_title} #{p_author} #{p_topic_register} #{p_subject} #{p_description} #{p_publisher} #{p_editor} #{p_contributor} #{p_date} #{p_type} #{p_format} #{p_identifier} #{p_source} #{p_language} #{p_relation} #{p_coverage} #{p_rights} #{p_comment} #{p_abstract} #{p_filename}
+      </font>
+      WOK
+        #eg = %{canned search e.g.:<br> <a href="#{url}">#{url}</a><br>find: #{analyze}<br>database: #{database}}
+        #% dbi_canning
+        @header=Form.new(@base,search_field,selected_db,result_type,checked_sql_limit,checked_tip,checked_stats,checked_searched,checked_url,checked_case,checked_echo,checked_sql,checked_all,checked_none,checked_selected,checked_default,search_note,the_can).submission_form #% form
+        unless q['s1'] =~/\S/ or q['au'] =~/\S/ or @search[:text][1] =~/\S/
+          print "Content-type: text/html\n\n"
+          puts (@header+@tail)
+        else #% searches
+          s1=(@search_for.text1 =~/\S/) \
+          ? @search_for.text1
+          : 'Unavailable'
+          if checked_case=~/\S/
+            @search[:text]<<%{doc_objects.clean~'#{CGI.unescape(s1)}'}
+          else
+            @search[:text]<<%{doc_objects.clean~*'#{CGI.unescape(s1)}'}
+          end
+          #% dbi_request
+          dbi_statement=DBI_SearchStatement.new(@conn,@search_for,q,checked_case)
+          @text_search_flag=false
+          @text_search_flag=dbi_statement.text_search_flag
+          s_contents=dbi_statement.contents
+          @body_main=''
+          @search_regx=nil
+          oldtid=0
+          if @text_search_flag
+            if checked_sql =~/\S/
+              sql_select_body=dbi_statement.sql_select_body_format
+            else sql_select_body=''
+            end
+            @body_main << sql_select_body
+          else
+          end
+          @hostpath="#{@hosturl_files}/#{@stub}"
+      WOK_SQL
+    end
+    def dir_structure #@opt.dir_structure_by
+      <<-'WOK_SQL'
+          def path_manifest(fn,ln=nil)
+            case @output_dir_structure_by
+            when 'filename'
+              @lingual =='mono' \
+              ? "#{@hostpath}/#{fn}/sisu_manifest.html"
+              : "#{@hostpath}/#{fn}/sisu_manifest.#{ln}.html"
+            when 'filetype'
+              @lingual =='mono' \
+              ? "#{@hostpath}/manifest/#{fn}.html"
+              : "#{@hostpath}/manifest/#{fn}.#{ln}.html"
+            else
+              "#{@hostpath}/#{ln}/manifest/#{fn}.html"
+            end
+          end
+          def path_html_seg(fn,ln=nil)
+            case @output_dir_structure_by
+            when 'filename'
+              "#{@hostpath}/#{fn}"
+            when 'filetype'
+              "#{@hostpath}/html/#{fn}"
+            else
+              "#{@hostpath}/#{ln}/html/#{fn}"
+            end
+          end
+          def path_toc(fn,ln=nil)
+            if @output_dir_structure_by =='filename' \
+            or @output_dir_structure_by =='filetype'
+              @lingual =='mono' \
+              ? "#{path_html_seg(fn,ln)}/toc.html"
+              : "#{path_html_seg(fn,ln)}/toc.#{ln}.html"
+            else
+              "#{path_html_seg(fn,ln)}/toc.html"
+            end
+          end
+          def path_filename(fn,seg,ln=nil)
+            if @output_dir_structure_by =='filename' \
+            or @output_dir_structure_by =='filetype'
+              @lingual =='mono' \
+              ? "#{path_html_seg(fn,ln)}/#{seg}.html"
+              : "#{path_html_seg(fn,ln)}/#{seg}.#{ln}.html"
+            else
+              "#{path_html_seg(fn,ln)}/#{seg}.html"
+            end
+          end
+          def path_html_doc(fn,ln=nil)
+            case @output_dir_structure_by
+            when 'filename'
+              @lingual =='mono' \
+              ? "#{path_html_seg(fn,ln)}/scroll.html"
+              : "#{path_html_seg(fn,ln)}/scroll.#{ln}.html"
+            when 'filetype'
+              @lingual =='mono' \
+              ? "#{@hostpath}/html/#{fn}.html"
+              : "#{@hostpath}/html/#{fn}.#{ln}.html"
+            else
+              "#{@hostpath}/#{ln}/html/#{fn}.html"
+            end
+          end
+      WOK_SQL
+    end
+    def main3
+      <<-'WOK_SQL'
+                    #% text_objects_body
+          s_contents.each do |c|                                               #% text body
+            location=c['src_filename'][/(.+?)\.(?:ssm\.sst|sst)$/,1]
+            file_suffix=c['src_filename'][/.+?\.(ssm\.sst|sst)$/,1]
+            lang=if location =~ /\S+?~(\S\S\S?)$/
+              l=location[/\S+?~(\S\S\S?)$/,1]
+              location=location.gsub(/(\S+?)~\S\S\S?/,'\1')
+              l=".#{l}"
+            else ''
+            end
+          #% metadata_found_body
+            if c['tid'].to_i != oldtid.to_i
+              ti=c['title']
+              can_txt_srch=(cgi['view']=~/index/) \
+              ? %{<a href="#{@canned_base_url}&fns=#{c['src_filename']}&lang=#{c['language_document_char']}&view=text"><img border="0" width="24" height="16" src="#{@image_src}/b_search.png" alt="search"></a>&nbsp;}
+              : %{<a href="#{@canned_base_url}&fns=#{c['src_filename']}&lang=#{c['language_document_char']}&view=index"><img border="0" width="24" height="16" src="#{@image_src}/b_search.png" alt="search"></a>&nbsp;}
+              title=%{<span style="background-color: #{@color_heading}"><a href="#{path_toc(location,c['language_document_char'])}"><img border="0" width="15" height="18" src="#{@image_src}/b_toc.png" alt="toc html">&nbsp;#{ti}</a></span> [#{c['language_document_char']}] by #{c['creator_author']} <a href="#{path_manifest(location,c['language_document_char'])}"><img border="0" width="15" height="15" src="#{@image_src}/b_info.png" alt="manifest"></a> #{can_txt_srch}<br>}  if file_suffix=~/s/ #hmm watch file_suffix
+              title=@text_search_flag \
+              ? '<br><hr>'+title
+              : '<br>'+title
+              @counter_txt_doc+=1
+              oldtid=c['tid'].to_i
+            else                    title=''
+            end
+            if @text_search_flag
+              if cgi['view']=~/text/ \
+              or (cgi['view']!~/index/ and cgi['search'] !~/search db/)      #% txt body
+                text=if c['suffix'] !~/1/ #seg
+                  if @search_for.text1 =~/\S+/ \
+                  or q['s1'] =~/\S+/                         #% only this branch is working !!
+                    unescaped_search=if @search_for.text1 =~/\S+/
+                      CGI.unescape(@search_for.text1)
+                    elsif q['s1'] =~/\S+/
+                      CGI.unescape(q['s1'])
+                    else nil
+                    end
+                    @search_regx=if unescaped_search                                     #check
+                      search_regex=unescaped_search.scan(/\S+/).each.map do |g|
+                         (g.to_s =~/(AND|OR)/) \
+                         ? ('|')
+                         : (%{#{g.to_s}})
+                      end.join(' ')
+                      search_regex=search_regex.gsub(/\s*\|\s*/,'|')
+                      Regexp.new(search_regex, Regexp::IGNORECASE)
+                    else nil
+                    end
+                  else nil
+                  end
+                  matched_para=(@search_regx.to_s.class==String && @search_regx.to_s=~/\S\S+/) \
+                  ? (c['body'].gsub(/(<a\s+href="https?:\/\/[^><\s]+#{@search_regx}[^>]+?>|#{@search_regx})/mi,%{<span style="background-color: #{@color_match}">\\1</span>}))
+                  : c['body']
+                  %{<hr><p><font size="2">ocn <b><a href="#{path_filename(location,c['seg'],c['language_document_char'])}##{c['ocn']}">#{c['ocn']}</a></b>:</font></p>#{matched_para}}
+                elsif c['suffix'] =~/1/ #doc
+                  %{#{title}<hr><p><font size="2">ocn #{c['ocn']}:#{c['body']}}
+                end
+                @counter_txt_ocn+=1
+                output=title+text
+              else #elsif cgi['view']=~/index/                                #% idx body
+                if c['suffix'] !~/1/ #seg
+                  index=%{<a href="#{path_filename(location,c['seg'],c['language_document_char'])}##{c['ocn']}">#{c['ocn']}</a>, } if @text_search_flag
+                elsif c['suffix'] =~/1/ #doc #FIX
+                  index=%{<a href="#{path_html_doc(location,c['language_document_char'])}##{c['ocn']}">#{c['ocn']}</a>, }
+                end
+                if c['seg'] =~/\S+/
+                  if @text_search_flag
+                    @counter_txt_ocn+=1
+                    output=title+index
+                  end
+                else
+                  @counter_txt_ocn+=1
+                  output=c['suffix'] !~/1/ \
+                  ? title+index
+                  : %{#{title}#{c['ocn'].sort}, }
+                end
+              end
+            else output=title
+            end
+            @counters_txt=if @counter_txt_doc > 0
+              if checked_stats =~/\S/
+                @@lt_t=(@counter_txt_ocn==dbi_statement.sql_match_limit.to_i) ? true : false
+                start=(@@offset.to_i+1).to_s
+                range=(@@offset.to_i+@counter_txt_ocn.to_i).to_s
+                %{<hr /><font size="2" color="#666666">Found #{@counter_txt_ocn} times in the main body of #{@counter_txt_doc} documents [ matches #{start} to #{range} ]</font><br>}
+              else ''
+              end
+            else ''
+            end
+            @body_main << output #+ details
+          end
+          oldtid = 0
+          offset=dbi_statement.sql_offset.to_s
+          limit=dbi_statement.sql_match_limit.to_s
+          @@lt_t ||=false; @@lt_e ||=false
+          canned=(@@lt_t or @@lt_e) \
+          ? dbi_statement.pre_next(true,@image_src).to_s
+          : dbi_statement.pre_next(false,@image_src).to_s
+          limit=dbi_statement.sql_match_limit.to_s
+          cgi.out{@header.force_encoding("UTF-8") + @counters_txt.force_encoding("UTF-8") + @counters_endn.force_encoding("UTF-8") + canned.force_encoding("UTF-8") + @body_main.force_encoding("UTF-8") + canned.force_encoding("UTF-8") + @tail.force_encoding("UTF-8")} #% print cgi_output_header+counters+body
+        end
+        rescue Exception => e
+          s='<pre>' + CGI::escapeHTML(e.backtrace.reverse.join("\n"))
+          s << CGI::escapeHTML(e.message) + '</pre>'
+          cgi.out{s}
+          next
+        ensure # eg. disconnect from server
+          @conn.disconnect if @conn
+        end
+      end
+      WOK_SQL
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    cgi
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/config.org b/org/config.org
new file mode 100644
index 00000000..b44d9792
--- /dev/null
+++ b/org/config.org
@@ -0,0 +1,310 @@
+-*- mode: org -*-
+#+TITLE:       sisu configure site
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:config:
+#+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
+
+* conf.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/conf.rb"
+# <<sisu_document_header>>
+module SiSU_Initialize
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+    include SiSU_Screen
+  require_relative 'relaxng'                            # relaxng.rb
+    include SiSU_Relaxng
+  require_relative 'css'                                # css.rb
+    include SiSU_Style
+  class Source
+    def initialize(opt)
+      @opt=opt
+    end
+    def read
+      ConfigSite.new(@opt).make_homepage
+      ConfigSite.new(@opt).css
+      ConfigSite.new(@opt).dtd
+      ConfigSite.new(@opt).cp_local_images
+      ConfigSite.new(@opt).cp_external_images
+      ConfigSite.new(@opt).cp_webserver_images
+    end
+  end
+  class ConfigSite #config files such as css are not updated if they already exist unless forced using the --init=site modifier
+    require_relative 'se'                               # se.rb
+    def initialize(opt)
+      @opt=opt
+      @env=SiSU_Env::InfoEnv.new(@opt.fns)
+      @suffix={
+        rnc: 'rnc',
+        rng: 'rng',
+        xsd: 'xsd',
+      }
+      @path={
+        xml: @env.path.output + '/_sisu/xml',
+        xsd: @env.path.output + '/_sisu/xml/xsd',
+        rnc: @env.path.output + '/_sisu/xml/rnc',
+        rng: @env.path.output + '/_sisu/xml/rng',
+        style: @env.path.output + '/' + @env.path.style,
+      }
+      @pwd,@home=Dir.pwd,@env.path.home
+    end
+    def make_homepage
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        'invert',
+        'Make homepage',
+        ''
+      ).colorize unless @opt.act[:quiet][:set]==:on
+      SiSU_Env::CreateSite.new(@opt).homepage
+    end
+    def cp_local_images
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        'invert',
+        'Copy images',
+        ''
+      ).colorize unless @opt.act[:quiet][:set]==:on
+      SiSU_Env::CreateSite.new(@opt).cp_local_images
+      SiSU_Env::CreateSite.new(@opt).cp_webserver_images_local #this should not have been necessary
+      SiSU_Env::CreateSite.new(@opt).cp_base_images #base images (nav etc.) used by all html
+    end
+    def cp_external_images
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        'invert',
+        'Copy external images',
+        ''
+      ).colorize if @opt.act[:verbose_plus][:set]==:on
+      SiSU_Env::CreateSite.new(@opt).cp_external_images
+    end
+    def cp_webserver_images
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        'invert',
+        'Copy webserver/output file images',
+        ''
+      ).colorize unless @opt.act[:quiet][:set]==:on
+      SiSU_Env::CreateSite.new(@opt).cp_webserver_images
+    end
+    def css
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        'invert',
+        'Configuring CSSs',
+        ''
+      ).colorize unless @opt.act[:quiet][:set]==:on
+      SiSU_Env::CreateSite.new(@opt).cp_css
+    end
+    def dtd
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        'invert',
+        'Configuring DTDs',
+        ''
+      ).colorize unless @opt.act[:quiet][:set]==:on
+      @rxng=SiSU_Relaxng::RelaxNG.new
+      @path.each { |d| FileUtils::mkdir_p(d[1]) \
+      unless FileTest.directory?(d[1]) }
+      #ugly code, sort later
+      if @rxng.methods.join =~/[^_]dtd_sax\b/
+        if @rxng.dtd_sax.length > 200
+          dtd=File.new("#{@path[:style]}/#{@rxng.rng_name.output_sax}",'w')
+          dtd << @rxng.dtd_sax
+          dtd.close
+        else trang_rnc_model_output_sax
+        end
+      else trang_rnc_model_output_sax
+      end
+      if @rxng.methods.join =~/[^_]dtd_dom\b/
+        if @rxng.dtd_dom.length > 200
+          dtd=File.new("#{@path[:style]}/#{@rxng.rng_name.output_dom}",'w')
+          dtd << @rxng.dtd_dom
+          dtd.close
+        else trang_rnc_model_output_dom
+        end
+      else trang_rnc_model_output_dom
+      end
+      if @rxng.methods.join =~/[^_]dtd_node\b/
+        if @rxng.dtd_node.length > 200
+          dtd=File.new("#{@path[:style]}/#{@rxng.rng_name.input_node}",'w')
+          dtd << @rxng.dtd_node
+          dtd.close
+        else trang_rnc_model_input_node
+        end
+      else trang_rnc_model_input_node
+      end
+      if @rxng.methods.join =~/[^_]dtd_xhtml\b/
+        if @rxng.dtd_xhtml.length > 200
+          dtd=File.new("#{@path[:style]}/#{@rxng.rng_name.output_xhtml}",'w')
+          dtd << @rxng.dtd_xhtml
+          dtd.close
+        else trang_rnc_model_output_xhtml
+        end
+      else trang_rnc_model_output_xhtml
+      end
+    end
+    def trang_rnc_model_output_sax
+      s=@suffix
+      rnc_src=@env.processing_path.ao + '/sax.' + s[:rnc]
+      rnc_file=@path[:rnc] + '/' + @rxng.rnc_name.output_sax
+      rng_file=@path[:rng] + '/' + @rxng.rng_name.output_sax
+      xsd_file=@path[:xsd] + '/' + @rxng.xsd_name.output_sax
+      rnc=File.new(rnc_src,'w')
+      rnc << @rxng.rnc_model_output_sax
+      rnc.close
+      #xsd
+      schema=SiSU_Env::SystemCall.new(rnc_src,xsd_file)
+      schema.relaxng(@opt.selections.str)
+      #rng
+      schema=SiSU_Env::SystemCall.new(rnc_src,rng_file)
+      schema.relaxng(@opt.selections.str)
+      #rnc
+      if FileTest.file?(rnc_src)
+        FileUtils::cp(rnc_src,rnc_file)
+        FileUtils::chmod(0644,rnc_file)
+      else STDERR.puts %{\t*WARN* did not find rnc - "#{rnc_src}" [#{__FILE__}:#{__LINE__}]}
+      end
+    end
+    def trang_rnc_model_output_dom
+      s=@suffix
+      rnc_src=@env.processing_path.ao + '/dom.' + s[:rnc]
+      rnc_file=@path[:rnc] + '/' + @rxng.rnc_name.output_dom
+      rng_file=@path[:rng] + '/' + @rxng.rng_name.output_dom
+      xsd_file=@path[:xsd] + '/' + @rxng.xsd_name.output_dom
+      rnc=File.new(rnc_src,'w')
+      rnc << @rxng.rnc_model_output_dom
+      rnc.close
+      #xsd
+      schema=SiSU_Env::SystemCall.new(rnc_src,xsd_file)
+      schema.relaxng(@opt.selections.str)
+      #rng
+      schema=SiSU_Env::SystemCall.new(rnc_src,rng_file)
+      schema.relaxng(@opt.selections.str)
+      #rnc
+      if FileTest.file?(rnc_src)
+        FileUtils::cp(rnc_src,rnc_file)
+        FileUtils::chmod(0644,rnc_file)
+      else STDERR.puts %{\t*WARN* did not find rnc - "#{rnc_src}" [#{__FILE__}:#{__LINE__}]}
+      end
+    end
+    def trang_rnc_model_output_xhtml
+      s=@suffix
+      rnc_src=@env.processing_path.ao + '/xhtml.' + s[:rnc]
+      rnc_file=@path[:rnc] + '/' + @rxng.rnc_name.output_xhtml
+      rng_file=@path[:rng] + '/' + @rxng.rng_name.output_xhtml
+      xsd_file=@path[:xsd] + '/' + @rxng.xsd_name.output_xhtml
+      rnc=File.new(rnc_src,'w')
+      rnc << @rxng.rnc_model_output_xhtml
+      rnc.close
+      #xsd
+      schema=SiSU_Env::SystemCall.new(rnc_src,xsd_file)
+      schema.relaxng(@opt.selections.str)
+      #rng
+      schema=SiSU_Env::SystemCall.new(rnc_src,rng_file)
+      schema.relaxng(@opt.selections.str)
+      #rnc
+      if FileTest.file?(rnc_src)
+        FileUtils::cp(rnc_src,rnc_file)
+        FileUtils::chmod(0644,rnc_file)
+      else STDERR.puts %{\t*WARN* did not find rnc - "#{rnc_src}" [#{__FILE__}:#{__LINE__}]}
+      end
+    end
+    def trang_rnc_model_input_sax
+      rnc_file=@env.processing_path.ao + '/sax.rnc'
+      dtd_file=@path[:xsd] + '/' + @rxng.rng_name.input_sax
+      rnc=File.new(rnc_file,'w')
+      rnc << @rxng.rnc_model_output_sax
+      rnc.close
+      schema=SiSU_Env::SystemCall.new(rnc_file,dtd_file)
+      schema.relaxng(@opt.selections.str)
+    end
+    def trang_rnc_model_input_dom
+      rnc_file=@env.processing_path.ao + '/dom.rnc'
+      dtd_file=@path[:xsd] + '/' + @rxng.rng_name.input_dom
+      rnc=File.new(rnc_file,'w')
+      rnc << @rxng.rnc_model_output_dom
+      rnc.close
+      schema=SiSU_Env::SystemCall.new(rnc_file,dtd_file)
+      schema.relaxng(@opt.selections.str)
+    end
+    def trang_rnc_model_input_node
+      rnc_file=@env.processing_path.ao + '/node.rnc'
+      dtd_file=@path[:xsd] + '/' + @rxng.rng_name.input_node
+      rnc=File.new(rnc_file,'w')
+      rnc << @rxng.rnc_model_input_node
+      rnc.close
+      schema=SiSU_Env::SystemCall.new(rnc_file,dtd_file)
+      schema.relaxng(@opt.selections.str)
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    config
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/css.org b/org/css.org
new file mode 100644
index 00000000..266c0051
--- /dev/null
+++ b/org/css.org
@@ -0,0 +1,3508 @@
+-*- mode: org -*-
+#+TITLE:       sisu css
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:css:
+#+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
+
+* css.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/css.rb"
+# <<sisu_document_header>>
+module SiSU_Style
+  require_relative 'se'                                 # se.rb
+  require_relative 'html_parts'                         # html_parts.rb
+  class CSS_HeadInfo
+    def initialize(md,ft='html')
+      @md,@ft=md,ft
+      @env=SiSU_Env::InfoEnv.new('',md)
+      @fn_css ||=SiSU_Env::CSS_Default.new
+      @o_str ||=SiSU_Env::ProcessingSettings.new(md).output_dir_structure
+      css_copy
+    end
+    def stylesheet
+      def css_path
+        SiSU_Env::CSS_Stylesheet.new(@md)
+      end
+      def css_embed_content
+        @css_embed_content ||=SiSU_Style::CSS.new
+      end
+      def css_embed?
+        if @ft=='html' \
+        && @o_str.dump_or_redirect?
+          true
+        else
+          false
+        end
+      end
+      def css_embed(css)
+        <<-WOK
+          <style TYPE="text/css">
+          #{css}
+          </style>
+        WOK
+      end
+      def css_action
+        css=case @ft
+        when 'html'
+          css=css_embed_content.html
+          css_embed(css)
+        when 'xhtml'
+          css_path.xhtml
+        when 'xml_sax'
+          css_path.xml_sax
+        when 'xml_dom'
+          css_path.xml_dom
+        when 'xml_docbook'
+          css_path.xml_docbook
+        else
+          css_embed_content.html
+        end
+      end
+      def css_head
+        (css_embed?) \
+        ? css_action
+        : "#{css_path.html}#{css_path.html_seg}"
+      end
+      def css_head_seg
+        (css_embed?) \
+        ? css_action
+        : css_path.html_seg
+      end
+      def css_head_xml
+        css_action
+      end
+      self
+    end
+    def css_copy
+      if @o_str.dump_or_redirect?
+        css=SiSU_Style::CSS.new
+        if @o_str.dump?
+          css_pth="#{@md.opt.opt_act[:dump][:inst]}/#{@env.path.style}"
+        elsif @o_str.redirect?
+          css_pth="#{@md.opt.opt_act[:redirect][:inst]}/#{@md.fnb}/#{@env.path.style}"
+        end
+        FileUtils::mkdir_p(css_pth) unless FileTest.directory?(css_pth)
+        case @ft
+        when 'html'
+          style=File.new("#{css_pth}/#{@fn_css.html}",'w')
+          style << css.html
+          style.close
+        when 'xhtml'
+          style=File.new("#{css_pth}/#{@fn_css.xhtml}",'w')
+          style << css.xhtml
+          style.close
+        when 'xml_sax'
+          style=File.new("#{css_pth}/#{@fn_css.xml_sax}",'w')
+          style << css.xml_sax
+          style.close
+        when 'xml_dom'
+          style=File.new("#{css_pth}/#{@fn_css.xml_dom}",'w')
+          style << css.xml_dom
+          style.close
+          css_path.xml_dom
+        when 'xml_docbook'
+          style=File.new("#{css_pth}/#{@fn_css.xml_docbook}",'w')
+          style << css.xml_docbook
+          style.close
+          css_path.xml_docbook
+        end
+      end
+    end
+  end
+  class CSS
+    include SiSU_Parts_HTML
+    def fonts
+      the_font.set_fonts
+    end
+    def html_tables                               #stylesheet for css table_pages
+<<WOK
+/* SiSU table output stylesheet */
+  body {
+    color: black;
+    background: #{the_color.white};
+  }
+  p {
+    display: block;
+    line-height: 1.5;
+    font-family: #{the_font.set_fonts};
+  }
+  a:link {
+    color: #{the_color.blue_ink};
+    text-decoration: none;
+  }
+  a:visited {
+    color: #{the_color.blue_ink};
+    text-decoration: none;
+    /* background-color: #{the_color.blue_tinge}; */
+  }
+  a:hover {
+    color: #{the_color.black};
+    text-decoration: underline;
+    background-color: #{the_color.yellow_light};
+  }
+  a:active {
+    color: #{the_color.blue_ink};
+    text-decoration: underline;
+  }
+WOK
+    end
+    def harvest
+      <<WOK
+/* SiSU harvest css default stylesheet */
+  body {
+    color: black;
+    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;
+  }
+
+  .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;
+  }
+  h1 {
+    font-size: 120%;
+    font-weight: bold;
+    color: white;
+    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;
+    color: white;
+    background: #880000;
+  }
+  p.lev0 {
+    font-size: 120%;
+    margin-left: 1em;
+    color: white;
+    background: #000000;
+  }
+
+  p.lev1 {
+    font-size: 110%;
+    margin-left: 2em;
+    color: white;
+    background: #444444;
+  }
+
+  p.lev2 {
+    font-size: 100%;
+    margin-left: 3em;
+    background: #888888;
+  }
+
+  p.lev3 {
+    font-size: 90%;
+    margin-left: 4em;
+    background: #bbbbbb;
+  }
+
+  p.lev4 {
+    font-size: 80%;
+    margin-left: 5em;
+    background: #eeeeee;
+  }
+
+  p.lev5 {
+    font-size: 80%;
+    margin-left: 6em;
+  }
+WOK
+    end
+    def html                                      #stylesheet for css html pages== html.css
+<<WOK
+/* SiSU css default stylesheet */
+  body {
+    color: black;
+    background: #ffffff;
+    background-color: #ffffff;
+  }
+/*
+    table {
+      margin-left: 5%;
+      display: block;
+    }
+    tr {
+      display: block;
+    }
+    th,td {
+      display: inline;
+      vertical-align: top;
+    }
+,*/
+  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;
+  }
+  a.lnkocn:link {
+    color: #777777;
+    text-decoration: none;
+  }
+  a.lnkocn:visited {
+    color: #555555;
+    text-decoration: none;
+  }
+  div {
+    margin-left: 0;
+    margin-right: 0;
+  }
+  div.p {
+    margin-left: 5%;
+    margin-right: 1%;
+  }
+
+  #top_band {
+    position: absolute;
+    top: 0;
+    bottom: 80px;
+    width: 100%;
+  }
+  #top_band_search {
+    position: absolute;
+    top: 0px;
+    right: 0px;
+    margin-left: 75%;
+    width: 20%;
+  }
+  #column_left {
+    position: absolute;
+    top: 80px;
+    left: 0;
+    margin-left: 1%;
+    width: 20%;
+  }
+  #column_center {
+    position: absolute;
+    top: 80px;
+    margin-left: 20%;
+    width: 55%;
+  }
+  #column_right {
+    position: absolute;
+    top: 80px;
+    right: 0px;
+    margin-left: 75%;
+    width: 25%;
+  }
+  #pane_major {
+    position: absolute;
+    top: 0px;
+    left: 0;
+    margin-left: 0;
+    width: 80%;
+  }
+  #pane_minor {
+    position: absolute;
+    top: 0px;
+    right: 0px;
+    margin-left: 75%;
+    width: 20%;
+    background-color: #aaaaaa;
+  }
+
+  .norm, .bold, .verse, .group, .block, .alt {
+    line-height: 133%;
+    margin-left: 0em;
+    margin-right: 2em;
+    margin-top: 12px;
+    margin-bottom: 0px;
+    padding-left: 0em;
+    text-indent: 0em;
+  }
+  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: 133%;
+    text-align: justify;
+    margin-left: 0em;
+    margin-right: 2em;
+    text-indent: 0mm;
+    margin-top: 0.8em;
+    margin-bottom: 0.8em;
+  }
+
+  /* indent */
+
+  p.norm { }
+  p.i1 {padding-left: 1em;}
+  p.i2 {padding-left: 2em;}
+  p.i3 {padding-left: 3em;}
+  p.i4 {padding-left: 4em;}
+  p.i5 {padding-left: 5em;}
+  p.i6 {padding-left: 6em;}
+  p.i7 {padding-left: 7em;}
+  p.i8 {padding-left: 8em;}
+  p.i9 {padding-left: 9em;}
+
+  /* hanging indent */
+
+  p.h0i0 {
+    padding-left: 0em;
+    text-indent:  0em;
+  }
+  p.h0i1 {
+    padding-left: 1em;
+    text-indent: -1em;
+  }
+  p.h0i2 {
+    padding-left: 2em;
+    text-indent: -2em;
+  }
+  p.h0i3 {
+    padding-left: 3em;
+    text-indent: -3em;
+  }
+  p.h0i4 {
+    padding-left: 4em;
+    text-indent: -4em;
+  }
+  p.h0i5 {
+    padding-left: 5em;
+    text-indent: -5em;
+  }
+  p.h0i6 {
+    padding-left: 6em;
+    text-indent: -6em;
+  }
+  p.h0i7 {
+    padding-left: 7em;
+    text-indent: -7em;
+  }
+  p.h0i8 {
+    padding-left: 8em;
+    text-indent: -8em;
+  }
+  p.h0i9 {
+    padding-left: 9em;
+    text-indent: -9em;
+  }
+
+  p.h1i0 {
+    padding-left: 0em;
+    text-indent:  1em;
+  }
+  p.h1i1 {
+    padding-left: 1em;
+    text-indent:  0em;
+  }
+  p.h1i2 {
+    padding-left: 2em;
+    text-indent: -1em;
+  }
+  p.h1i3 {
+    padding-left: 3em;
+    text-indent: -2em;
+  }
+  p.h1i4 {
+    padding-left: 4em;
+    text-indent: -3em;
+  }
+  p.h1i5 {
+    padding-left: 5em;
+    text-indent: -4em;
+  }
+  p.h1i6 {
+    padding-left: 6em;
+    text-indent: -5em;
+  }
+  p.h1i7 {
+    padding-left: 7em;
+    text-indent: -6em;
+  }
+  p.h1i8 {
+    padding-left: 8em;
+    text-indent: -7em;
+  }
+  p.h1i9 {
+    padding-left: 9em;
+    text-indent: -8em;
+  }
+
+  p.h2i0 {
+    padding-left: 0em;
+    text-indent:  2em;
+  }
+  p.h2i1 {
+    padding-left: 1em;
+    text-indent:  1em;
+  }
+  p.h2i2 {
+    padding-left: 2em;
+    text-indent:  0em;
+  }
+  p.h2i3 {
+    padding-left: 3em;
+    text-indent: -1em;
+  }
+  p.h2i4 {
+    padding-left: 4em;
+    text-indent: -2em;
+  }
+  p.h2i5 {
+    padding-left: 5em;
+    text-indent: -3em;
+  }
+  p.h2i6 {
+    padding-left: 6em;
+    text-indent: -4em;
+  }
+  p.h2i7 {
+    padding-left: 7em;
+    text-indent: -5em;
+  }
+  p.h2i8 {
+    padding-left: 8em;
+    text-indent: -6em;
+  }
+  p.h2i9 {
+    padding-left: 9em;
+    text-indent: -7em;
+  }
+
+  p.h3i0 {
+    padding-left: 0em;
+    text-indent:  3em;
+  }
+  p.h3i1 {
+    padding-left: 1em;
+    text-indent:  2em;
+  }
+  p.h3i2 {
+    padding-left: 2em;
+    text-indent:  1em;
+  }
+  p.h3i3 {
+    padding-left: 3em;
+    text-indent:  0em;
+  }
+  p.h3i4 {
+    padding-left: 4em;
+    text-indent: -1em;
+  }
+  p.h3i5 {
+    padding-left: 5em;
+    text-indent: -2em;
+  }
+  p.h3i6 {
+    padding-left: 6em;
+    text-indent: -3em;
+  }
+  p.h3i7 {
+    padding-left: 7em;
+    text-indent: -4em;
+  }
+  p.h3i8 {
+    padding-left: 8em;
+    text-indent: -5em;
+  }
+  p.h3i9 {
+    padding-left: 9em;
+    text-indent: -6em;
+  }
+
+  p.h4i0 {
+    padding-left: 0em;
+    text-indent:  4em;
+  }
+  p.h4i1 {
+    padding-left: 1em;
+    text-indent:  3em;
+  }
+  p.h4i2 {
+    padding-left: 2em;
+    text-indent:  2em;
+  }
+  p.h4i3 {
+    padding-left: 3em;
+    text-indent:  1em;
+  }
+  p.h4i4 {
+    padding-left: 4em;
+    text-indent:  0em;
+  }
+  p.h4i5 {
+    padding-left: 5em;
+    text-indent: -1em;
+  }
+  p.h4i6 {
+    padding-left: 6em;
+    text-indent: -2em;
+  }
+  p.h4i7 {
+    padding-left: 7em;
+    text-indent: -3em;
+  }
+  p.h4i8 {
+    padding-left: 8em;
+    text-indent: -4em;
+  }
+  p.h4i9 {
+    padding-left: 9em;
+    text-indent: -5em;
+  }
+
+  p.h5i0 {
+    padding-left: 0em;
+    text-indent:  5em;
+  }
+  p.h5i1 {
+    padding-left: 1em;
+    text-indent:  4em;
+  }
+  p.h5i2 {
+    padding-left: 2em;
+    text-indent:  3em;
+  }
+  p.h5i3 {
+    padding-left: 3em;
+    text-indent:  2em;
+  }
+  p.h5i4 {
+    padding-left: 4em;
+    text-indent:  1em;
+  }
+  p.h5i5 {
+    padding-left: 5em;
+    text-indent:  0em;
+  }
+  p.h5i6 {
+    padding-left: 6em;
+    text-indent: -1em;
+  }
+  p.h5i7 {
+    padding-left: 7em;
+    text-indent: -2em;
+  }
+  p.h5i8 {
+    padding-left: 8em;
+    text-indent: -3em;
+  }
+  p.h5i9 {
+    padding-left: 9em;
+    text-indent: -4em;
+  }
+
+  p.h6i0 {
+    padding-left: 0em;
+    text-indent:  6em;
+  }
+  p.h6i1 {
+    padding-left: 1em;
+    text-indent:  5em;
+  }
+  p.h6i2 {
+    padding-left: 2em;
+    text-indent:  4em;
+  }
+  p.h6i3 {
+    padding-left: 3em;
+    text-indent:  3em;
+  }
+  p.h6i4 {
+    padding-left: 4em;
+    text-indent:  2em;
+  }
+  p.h6i5 {
+    padding-left: 5em;
+    text-indent:  1em;
+  }
+  p.h6i6 {
+    padding-left: 6em;
+    text-indent:  0em;
+  }
+  p.h6i7 {
+    padding-left: 7em;
+    text-indent: -1em;
+  }
+  p.h6i8 {
+    padding-left: 8em;
+    text-indent: -2em;
+  }
+  p.h6i9 {
+    padding-left: 9em;
+    text-indent: -3em;
+  }
+
+  p.h7i0 {
+    padding-left: 0em;
+    text-indent:  7em;
+  }
+  p.h7i1 {
+    padding-left: 1em;
+    text-indent:  6em;
+  }
+  p.h7i2 {
+    padding-left: 2em;
+    text-indent:  5em;
+  }
+  p.h7i3 {
+    padding-left: 3em;
+    text-indent:  4em;
+  }
+  p.h7i4 {
+    padding-left: 4em;
+    text-indent:  3em;
+  }
+  p.h7i5 {
+    padding-left: 5em;
+    text-indent:  2em;
+  }
+  p.h7i6 {
+    padding-left: 6em;
+    text-indent:  1em;
+  }
+  p.h7i7 {
+    padding-left: 7em;
+    text-indent:  0em;
+  }
+  p.h7i8 {
+    padding-left: 8em;
+    text-indent: -1em;
+  }
+  p.h7i9 {
+    padding-left: 9em;
+    text-indent: -2em;
+  }
+
+  p.h8i0 {
+    padding-left: 0em;
+    text-indent:  8em;
+  }
+  p.h8i1 {
+    padding-left: 1em;
+    text-indent:  7em;
+  }
+  p.h8i2 {
+    padding-left: 2em;
+    text-indent:  6em;
+  }
+  p.h8i3 {
+    padding-left: 3em;
+    text-indent:  5em;
+  }
+  p.h8i4 {
+    padding-left: 4em;
+    text-indent:  4em;
+  }
+  p.h8i5 {
+    padding-left: 5em;
+    text-indent:  3em;
+  }
+  p.h8i6 {
+    padding-left: 6em;
+    text-indent:  2em;
+  }
+  p.h8i7 {
+    padding-left: 7em;
+    text-indent:  1em;
+  }
+  p.h8i8 {
+    padding-left: 8em;
+    text-indent:  0em;
+  }
+  p.h8i9 {
+    padding-left: 9em;
+    text-indent: -1em;
+  }
+
+  p.h9i0 {
+    padding-left: 0em;
+    text-indent:  9em;
+  }
+  p.h9i1 {
+    padding-left: 1em;
+    text-indent:  8em;
+  }
+  p.h9i2 {
+    padding-left: 2em;
+    text-indent:  7em;
+  }
+  p.h9i3 {
+    padding-left: 3em;
+    text-indent:  6em;
+  }
+  p.h9i4 {
+    padding-left: 4em;
+    text-indent:  5em;
+  }
+  p.h9i5 {
+    padding-left: 5em;
+    text-indent:  4em;
+  }
+  p.h9i6 {
+    padding-left: 6em;
+    text-indent:  3em;
+  }
+  p.h9i7 {
+    padding-left: 7em;
+    text-indent:  2em;
+  }
+  p.h9i8 {
+    padding-left: 8em;
+    text-indent:  1em;
+  }
+  p.h9i9 {
+    padding-left: 9em;
+    text-indent:  0em;
+  }
+
+  p.it0 {
+    margin-left: 0em;
+    margin-top: 6px;
+    margin-bottom: 0px;
+    line-height: 100%;
+  }
+  p.it1 {
+    margin-left: 1em;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    line-height: 100%;
+  }
+  p.it2 {
+    margin-left: 2em;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    line-height: 100%;
+  }
+  p.it3 {
+    margin-left: 3em;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    line-height: 100%;
+  }
+  p.it4 {
+    margin-left: 4em;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    line-height: 100%;
+  }
+  p.it5 {
+    margin-left: 5em;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    line-height: 100%;
+  }
+  p.it6 {
+    margin-left: 6em;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    line-height: 100%;
+  }
+  p.it7 {
+    margin-left: 7em;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    line-height: 100%;
+  }
+  p.it8 {
+    margin-left: 8em;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    line-height: 100%;
+  }
+  p.it9 {
+    margin-left: 9em;
+    margin-bottom: 0px;
+    margin-top: 0px;
+    line-height: 100%;
+  }
+
+  p.block { }
+
+  p.group { }
+
+  p.alt { }
+
+  p.verse {
+    margin-bottom: 6px;
+  }
+
+  p.code {
+    font-family: inconsolata, andale mono, courier new, courier, monospace;
+    font-size: 90%;
+    text-align: left;
+    background-color: #eeeeee;
+  }
+
+  p.caption {
+    text-align: left;
+    font-size: 80%;
+    display: inline;
+  }
+
+  p.endnote {
+    font-size: 96%;
+    line-height: 120%;
+    text-align: left;
+    margin-right: 15mm;
+  }
+  p.endnote_indent {
+    font-size: 96%;
+    line-height: 120%;
+    text-align: left;
+    margin-left: 2em;
+    margin-right: 15mm;
+  }
+
+  p.center {
+    text-align: center;
+  }
+  p.bold {
+    font-weight: bold;
+  }
+  p.bold_left {
+    font-weight: bold;
+    text-align: left;
+  }
+  p.centerbold {
+    text-align: center;
+    font-weight: bold;
+  }
+  p.em {
+    font-weight: bold;
+    font-style: normal;
+    background: #fff3b6;
+  }
+
+  p.small {
+    font-size: 80%;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    margin-right: 6px;
+    text-align: left;
+  }
+
+  .tiny, .tiny_left, .tiny_right, .tiny_center {
+    font-size: 10px;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    color: #777777;
+    margin-right: 6px;
+    text-align: left;
+  }
+  p.tiny { }
+  p.tiny_left {
+    margin-left: 0px;
+    margin-right: 0px;
+    text-align: left;
+  }
+  p.tiny_right {
+    margin-right: 1em;
+    text-align: right;
+  }
+  p.tiny_center {
+    margin-left: 0px;
+    margin-right: 0px;
+    text-align: center;
+  }
+
+  p.pane, p.pane_title, p.pane_blurb, p.pane_link, p.pane_indent {
+    font-size: 80%;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    margin-left: 2mm;
+    margin-right: 4px;
+    text-align: left;
+  }
+  p.pane { }
+  p.pane_title {
+    font-weight: bold;
+    margin-bottom: 0px;
+  }
+  p.pane_blurb {
+    font-size: 10px;
+    margin-bottom: 0px;
+  }
+  p.pane_link {
+    font-size: 10px;
+    margin-bottom: 0px;
+    margin-left: 4mm;
+  }
+  p.pane_indent {
+    font-size: 10px;
+    margin-bottom: 0px;
+    margin-left: 4mm;
+  }
+
+  p.concordance_word {
+    line-height: 150%;
+    font-weight: bold;
+    display: inline;
+    margin-top: 4px;
+    margin-bottom: 1px;
+  }
+  p.concordance_count {
+    font-size: 80%;
+    color: #777777;
+    display: inline;
+    margin-left: 0em;
+  }
+  p.concordance_object {
+    font-size: 80%;
+    line-height: 120%;
+    text-align: left;
+    margin-left: 3em;
+    margin-top: 1px;
+    margin-bottom: 3px;
+  }
+  p.book_index_lev1 {
+    line-height: 100%;
+    margin-top: 4px;
+    margin-bottom: 1px;
+  }
+  p.book_index_lev2 {
+    line-height: 100%;
+    text-align: left;
+    margin-left: 3em;
+    margin-top: 1px;
+    margin-bottom: 3px;
+  }
+
+  p.quickref {
+    font-size: 10px;
+    font-style: italic;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    color: #777777;
+    margin-right: 5px;
+    text-align: left;
+  }
+  p.bigref {
+    font-size: 11px;
+    font-weight: bold;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    color: #777777;
+    margin-right: 5px;
+    text-align: center;
+  }
+
+  p.letter {
+    font-weight: bold;
+    font-size: 80%;
+    margin-left: 0em;
+    margin-top: 2px;
+    margin-bottom: 2px;
+    margin-right: 6px;
+    text-align: left;
+    color: white;
+    background: #880000;
+  }
+
+  tt {
+    font-family: inconsolata, andale mono, courier new, courier, monospace;
+    background-color: #eeeeee;
+  }
+
+  label.ocn {
+    width: 2%;
+    float: right;
+    top: 0;
+    font-size: 10px;
+    margin-top: 0px;
+    margin-bottom: 5px;
+    color: #777777;
+    margin-right: 5px;
+    text-align: right;
+    background-color: #ffffff;
+  }
+
+  table { }
+  tr { }
+  th,td {
+    vertical-align: top;
+    text-align: left;
+  }
+  th {
+    font-weight: bold;
+  }
+
+  p.left,th.left,td.left {
+    text-align: left;
+  }
+  p.small_left,th.small_left,td.small_left {
+    text-align: left;
+    font-size: 80%;
+  }
+  p.right,th.right,td.right {
+    text-align: right;
+  }
+
+  #horizontal_links {
+    background: #eeeeee;
+    margin-left: 5%;
+    margin-right: 5%;
+  }
+  #horizontal {
+    margin: 0;
+    padding: 0 0 0 10px;
+    border-top: 1px solid #000077;
+    border-bottom: 1px solid #000077;
+  }
+  #horizontal li {
+    margin: 0 0 0 0;
+    padding: 0 16px 0 0;
+    display: inline;
+    list-style-type: none;
+    text-align: left;
+    background: none;
+  }
+  #horizontal a {
+    line-height: 12px;
+    margin: 0 0 0 0;
+    text-decoration: none;
+    color: #000077;
+  }
+  #horizontal a.active, #horizontal a:hover {
+    border-bottom: 2px solid #777777;
+    padding-bottom: 2px;
+    color: #000077;
+  }
+  #horizontal a:hover {
+    color: #000077;
+  }
+
+  #document_versions {
+    position: absolute;
+    top: 10mm;
+    right: 2%;
+    width: 12%;
+    float: right;
+  }
+
+  #vertical_links {
+    position: absolute;
+    top: 10mm;
+    right: 0px;
+    width: 20%;
+    background: #dddddd;
+    float: right;
+  }
+  #vertical {
+    padding: 0 12px 0px 0px;
+    margin-left: 2%;
+    margin-right: 2%;
+  }
+  #vertical li {
+    display: block;
+    list-style-type: none;
+  }
+  #vertical a {
+    line-height: 12px;
+    text-decoration: none;
+    color: #000077;
+  }
+  #vertical a.active, #vertical a:hover {
+    border-bottom: 2px solid #777777;
+    padding-bottom: 2px;
+    color: #000077;
+  }
+
+  ul, li {
+    list-style-type: none;
+    list-style: none;
+    padding-left: 20px;
+    display: block;
+    font-family: verdana, arial, georgia, tahoma, sans-serif, helvetica, times, roman;
+    font-weight: normal;
+    line-height: 150%;
+    text-align: left;
+    text-indent: 0mm;
+    margin-left: 1em;
+    margin-right: 2em;
+    margin-top: 3px;
+    margin-bottom: 3px;
+  }
+
+  li {
+    background: url(../image_sys/bullet_09.png) no-repeat 0px 6px;
+  }
+
+  ul {
+  }
+  li.bullet { margin-left: 1em; }
+  li.i1 { margin-left: 2em; }
+  li.i2 { margin-left: 3em; }
+  li.i3 { margin-left: 4em; }
+  li.i4 { margin-left: 5em; }
+  li.i5 { margin-left: 6em; }
+  li.i6 { margin-left: 7em; }
+  li.i7 { margin-left: 8em; }
+  li.i8 { margin-left: 9em; }
+  li.i9 { margin-left: 10em; }
+
+  li.doc, li.ref, li.refcenter {
+    margin-top: 0px;
+    margin-bottom: 0px;
+    margin-right: 0px;
+    font-size: 8px;
+    font-style: normal;
+    text-align: left;
+  }
+  li.doc {
+    background: url(../image_sys/bullet_09.png) no-repeat 0px 6px;
+    padding-left: 16px;
+    margin-left: 10px;
+    margin-right: 0px;
+  }
+  li.ref {
+    background: none;
+    padding-left: 0;
+    margin-left: 0;
+    color: #777777;
+  }
+  li.refcenter {
+    background: url(../image_sys/bullet_09.png) no-repeat 0px 6px;
+    padding-left: 20px;
+    margin-left: 10%;
+    font-size: 9px;
+    color: #777777;
+    text-align: center;
+  }
+  li.refbold {
+    list-style-type: none;
+    padding-left: 16px;
+    margin-left: 0;
+    margin-right: 10mm;
+    font-weight: bold;
+  }
+
+  h0, h1, h2, h3, h4, h5, h6, h7 {
+    font-weight: bold;
+    line-height: 120%;
+    text-align: left;
+    margin-top: 20px;
+    margin-bottom: 10px;
+  }
+  h4.norm, h5.norm, h6.norm, h7.norm {
+    margin-top: 10px;
+    margin-bottom: 0px;
+  }
+  h1.center, h2.center, h3.center, h4.center, h5.center, h6.center, h7.center {
+    text-align: center;
+  }
+  h0 { font-size: 125%; }
+  h1 { font-size: 120%; }
+  h2 { font-size: 115%; }
+  h3 { font-size: 110%; }
+  h4 { font-size: 105%; }
+  h5 { font-size: 100%; }
+  h6 { font-size: 100%; }
+  h7 { font-size: 100%; }
+
+  h1.i {margin-left: 2em;}
+  h2.i {margin-left: 3em;}
+  h3.i {margin-left: 4em;}
+  h4.i {margin-left: 5em;}
+  h5.i {margin-left: 6em;}
+  h6.i {margin-left: 7em;}
+  h7.i {margin-left: 8em;}
+  h8.i {margin-left: 9em;}
+  h9.i {margin-left: 10em;}
+  h1.top_band {
+    display: inline;
+    text-align: left;
+    margin-top: 0;
+    margin-left: 4mm;
+    text-indent: 0mm;
+    font-weight: bold;
+    font-size: 120%;
+  }
+  h2.top_band_tiny {
+    font-size: 10px;
+    font-weight: normal;
+    margin-top: 0px;
+    margin-left: 4mm;
+    text-indent: 0mm;
+    margin-bottom: 0px;
+    color: #777777;
+    margin-left: 140px;
+    margin-right: 0px;
+    text-align: left;
+  }
+
+  p.top_band {
+    display: inline;
+    text-align: left;
+    margin-top: 0;
+    margin-left: 140px;
+    text-indent: 0mm;
+    font-weight: bold;
+    font-size: 120%;
+  }
+  p.top_band_tiny {
+    font-size: 10px;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    color: #777777;
+    margin-left: 140px;
+    margin-right: 0px;
+    text-align: left;
+  }
+  p.top_band_image {
+    float: left;
+    display: inline;
+    text-align: left;
+    margin-top: 0;
+    margin-left: 1mm;
+    text-indent: 0mm;
+    margin-right: 1mm;
+  }
+
+  .banner, .subbanner {
+    font-weight: bold;
+    text-align: center;
+    margin-left: 10mm;
+    margin-right: 15mm;
+    margin-top: 20px;
+    margin-bottom: 10px;
+  }
+
+  h1.banner {
+    font-size: 120%;
+  }
+  h1.subbanner {
+    font-size: 115%;
+  }
+  h2.banner {
+    font-size: 110%;
+  }
+  h3.banner {
+    color: #990000;
+    font-size: 105%;
+  }
+  h4.banner {
+    color: #ff0000;
+    font-size: 100%;
+  }
+  h5.banner {
+  }
+  h6.banner {
+  }
+  h7.banner {
+  }
+
+  .toc {
+    font-weight: normal;
+    margin-top: 6px;
+    margin-bottom: 6px;
+  }
+  h1.toc {
+    margin-left: 1em;
+    font-size: 115%;
+    line-height: 150%;
+  }
+  h2.toc {
+    margin-left: 2em;
+    font-size: 110%;
+    line-height: 140%;
+  }
+  h3.toc {
+    margin-left: 3em;
+    font-size: 105%;
+    line-height: 120%;
+  }
+  h4.toc {
+    margin-left: 4em;
+    font-size: 100%;
+    line-height: 120%;
+  }
+  h5.toc {
+    margin-left: 5em;
+    font-size: 95%;
+    line-height: 110%;
+  }
+  h6.toc {
+    margin-left: 6em;
+    font-size: 90%;
+    line-height: 110%;
+  }
+  h7.toc {
+    margin-left: 7em;
+    font-size: 85%;
+    line-height: 100%;
+  }
+
+  .microtoc {
+    margin-top: 2px;
+    margin-bottom: 2px;
+  }
+
+  h1.microtoc {
+    margin-left: 0mm;
+    font-size: 115%;
+  }
+  h2.microtoc {
+    margin-left: 5mm;
+    font-size: 110%;
+  }
+  h3.microtoc {
+    margin-left: 10mm;
+    font-size: 105%;
+  }
+  h4.microtoc {
+    margin-left: 15mm;
+    font-weight: normal;
+    font-size: 100%;
+  }
+  h5.microtoc {
+    margin-left: 20mm;
+    font-weight: normal;
+    font-size: 95%;
+  }
+  h6.microtoc {
+    margin-left: 25mm;
+    font-weight: normal;
+    font-size: 90%;
+  }
+  h7.microtoc {
+    margin-left: 30mm;
+    font-weight: normal;
+    font-size: 85%;
+  }
+
+  .subtoc {
+    margin-right: 34%;
+    font-weight: normal;
+  }
+  h5.subtoc {
+    margin-left: 2em;
+    font-size: 80%;
+    margin-top: 2px;
+    margin-bottom: 2px;
+  }
+  h6.subtoc {
+    margin-left: 3em;
+    font-size: 75%;
+    margin-top: 0px;
+    margin-bottom: 0px;
+  }
+  h7.subtoc {
+    margin-left: 4em;
+    font-size: 70%;
+    margin-top: 0px;
+    margin-bottom: 0px;
+  }
+
+  div.substance {
+    width: 100%;
+    background-color: #ffffff;
+  }
+  div.ocn {
+    width: 5%;
+    float: right;
+    top: 0;
+    background-color: #ffffff;
+  }
+  div.endnote {
+    width: 95%;
+    background-color: #fffffff;
+  }
+  div.toc {
+    position: absolute;
+    float: left;
+    margin: 0;
+    padding: 0;
+    padding-top: 0.5em;
+    border: 0;
+    width: 13em;
+    background-color: #eeeeee;
+    margin-right:1em;
+  }
+  div.summary {
+    margin: 0;
+    padding: 0;
+    border-left: 13em solid #eeeeee;
+    padding-left: 1em;
+    background-color: #eeeeee;
+  }
+  div.content, div.main_column {
+    margin: 0;
+    padding: 0;
+    border-left: 13em solid #ffffff;
+    padding-left: 1em;
+    padding-right: 1em;
+  }
+  div.content0, div.main_column0 {
+    margin: 0;
+    padding: 0;
+    border-left: 0% solid #ffffff;
+    padding-left: 5%;
+  }
+  div.scroll {
+    margin: 0;
+    padding: 0;
+    padding-left: 1em;
+    padding-right: 1em;
+  }
+  div.content:after {
+    content:' ';
+    clear:both;
+    display:block;
+    height:0;
+    overflow:hidden
+  }
+  div.footer {
+    clear:left;
+    padding: 0.5em;
+    font-size: 80%;
+    margin: 0;
+  }
+  div.toc ul {
+    list-style: none;
+    padding: 0;
+    margin: 0;
+  }
+  div.toc li ul a, li ul span.currentlink
+  {
+    font-weight: normal;
+    font-size: 90%;
+    padding-left: 2em;
+    background-color: #eeeeee;
+  }
+  div.toc a, span.currentlink{
+    display:block;
+    text-decoration: none;
+    padding-left: 0.5em;
+    color: #0000aa;
+  }
+  hr {
+    width: 90%;
+  }
+
+  span.currentlink {
+    text-decoration: none;
+    background-color: #aaaaf9;
+  }
+
+  div.toc a:visited {
+    color: #0000aa;
+  }
+  div.toc a:hover {
+    color: #000000;
+    background-color: #f9f9aa;
+  }
+
+  .minitoc {
+    font-weight: normal;
+    margin-top: 2px;
+    margin-bottom: 2px;
+  }
+  h1.minitoc, h2.minitoc, h3.minitoc {
+    margin-left: 0em;
+    font-weight: bold;
+    text-align: left;
+    font-size: 90%;
+    margin-top: 4px;
+    margin-bottom: 4px;
+  }
+  h4.minitoc {
+    margin-left: 0em;
+    font-size: 90%;
+  }
+  h5.minitoc {
+    margin-left: 1em;
+    font-size: 85%;
+  }
+  h6.minitoc {
+    margin-left: 2em;
+    font-size: 85%;
+  }
+  h7.minitoc {
+    margin-left: 3em;
+    font-size: 80%;
+  }
+  h0.minitoc {
+    margin-left: 0em;
+    font-size: 90%;
+  }
+
+  h1.c, h2.c, h3.c, h4.c, h5.c, h6.c, h7.c, p.c {
+    text-align: center
+  }
+  h1.red, h2.red, h3.red, h4.red, h5.red, h6.red, h7.red {
+    text-align: center;
+    color: #ff0000;
+    margin-left: 5mm;
+    text-indent: 5mm;
+    margin-top: 30px;
+    margin-bottom: 20px;
+    margin-right: 15mm;
+  }
+  h1.ruby, h2.ruby, h3.ruby, h4.ruby, h5.ruby, h6.ruby, h7.ruby {
+    text-align: center;
+    color: #990000;
+    margin-left: 5mm;
+    text-indent: 5mm;
+    margin-top: 30px;
+    margin-bottom: 20px;
+    margin-right: 15mm;
+  }
+WOK
+    end
+    def homepage                                  #stylesheet for index, home page
+<<WOK
+  body {color: black; background: #{the_color.white}; margin:10px 10px 0px 10px; padding:0px;}
+  p { line-height: 1.5 }
+  a:link      {color: #{the_color.blue_ink};   text-decoration: none; }
+  a:visited       {color: #{the_color.blue_ink};   text-decoration: none; }
+  a:hover {color: #{the_color.black}; text-decoration: underline; background-color: #{the_color.yellow_light};}
+  a:active {color: #{the_color.blue_ink}; text-decoration: underline;}
+  #banner {
+    background:#{the_color.white};
+  }
+  #column_left {
+    width:25%;
+    float:left;
+    background:#b9d4dd;
+    padding-bottom:10px;
+  }
+  #column_center {
+    width:55%;
+    float:left;
+    background:#{the_color.white};
+    padding-bottom:10px;
+  }
+  #column_right {
+    width:20%;
+    float:left;
+    background:#b9d4dd;
+    padding-bottom:10px;
+  }
+  p,h1,pre {
+    font-family: #{the_font.set_fonts};
+    margin:0px 10px 10px 10px;
+  }
+  h1 {
+    font-size:14px;
+    padding-top:10px;
+  }
+  #column_right p { font-size:12px}
+  #banner h1 { margin:0px; padding:10px}
+WOK
+    end
+    def xhtml                                     #stylesheet for xhtml
+<<WOK
+/* SiSU css xhtml & sax.xml default style */
+    document {
+      display: block;
+      margin-left: 0mm;
+      margin-right: 0mm;
+    }
+    head {
+      display: block;
+      margin-bottom: 20px;
+      background-color: #dddddd;
+    }
+    metadata {
+      display: block;
+    }
+    meta {
+      display: inline;
+      line-height: 1;
+      font-size: 10px;
+      color: #990000;
+      margin-right: 2mm;
+      margin-top: 0px;
+      margin-bottom: 0px;
+
+    }
+    data,md {
+      display: inline;
+      line-height: 1;
+      font-size: 10px;
+      color: #000099;
+      margin-top: 0px;
+      margin-bottom: 0px;
+    }
+    source_control {
+      display: block;
+    }
+    dc {
+      display: block;
+      font-family: #{the_font.set_fonts};
+      color: blue;
+      background-color: #dddddd;
+      font-weight: normal;
+      text-align: justify;
+      font-size: xx-small;
+      line-height: 120%;
+      margin-left: 5%;
+      margin-right: 5mm;
+      margin-top: 0px;
+      margin-bottom: 0px;
+    }
+    sc {
+      display: inline;
+      color: green;
+    }
+    keywords,copyright {
+      display: block;
+      font-family: #{the_font.set_fonts};
+      color: red;
+      background-color: #dddddd;
+      font-weight: normal;
+      text-align: justify;
+      font-size: xx-small;
+      line-height: 120%;
+      margin-left: 5%;
+      margin-right: 5mm;
+      margin-top: 0px;
+      margin-bottom: 0px;
+    }
+    table {
+      margin-left: 5%;
+      display: block;
+    }
+    tr {
+      display: block;
+    }
+    th,td {
+      display: inline;
+    }
+    body {
+      color: black;
+      background: #ffffff;
+    }
+    a:link {
+      color: #003399;
+      text-decoration: none;
+    }
+    a:visited {
+      color: #003399;
+      text-decoration: none;
+      /* background-color: #e3ecef; */
+    }
+    a:hover {
+      color: #000000;
+      text-decoration: underline;
+      background-color: #fff3b6;
+    }
+    a:hover IMG {
+      background-color: #ffffff;
+    }
+    a:active {
+      color: #003399;
+      text-decoration: underline;
+    }
+    object {
+      display: block;
+      margin-left: 2mm;
+      margin-right: 2mm;
+      margin-top: 4px;
+      margin-bottom: 8px;
+    }
+    text,text[class|="norm"] {
+      display: block;
+      font-family: #{the_font.set_fonts};
+      text-align: justify;
+      font-weight: normal;
+      font-size: 100%;
+      line-height: 150%;
+      margin-left: 5%;
+      margin-right: 5%;
+      margin-top: 2px;
+      margin-bottom: 0px;
+    }
+    text[class|="h1"] {
+      font-size: 120%;
+      font-weight: bold;
+      text-align: left;
+      line-height: 120%;
+      margin-top: 20px;
+      margin-bottom: 10px;
+    }
+    text[class|="h2"] {
+      font-weight: bold;
+      font-size: 110%;
+      text-align: left;
+      margin-top: 20px;
+      margin-bottom: 10px;
+    }
+    text[class|="h3"] {
+      font-size: 110%;
+      font-weight: bold;
+      text-align: left;
+    }
+    text[class|="h4"] {
+      font-size: 110%;
+      font-weight: bold;
+      text-align: left;
+    }
+    text[class|="h5"] {
+      font-size: 110%;
+      font-weight: bold;
+      text-align: left;
+    }
+    text[class|="h6"] {
+      font-size: 110%;
+      font-weight: bold;
+      text-align: left;
+    }
+    text[class|="h7"] {
+      font-size: 110%;
+      font-weight: bold;
+      text-align: left;
+    }
+    text[class|="indent0"] {
+      padding-left: 10%;
+    }
+    text[class|="indent1"] {
+      padding-left: 15%;
+    }
+    text[class|="indent2"] {
+      padding-left: 20%;
+    }
+    text[class|="indent3"] {
+      padding-left: 25%;
+    }
+    text[class|="indent4"] {
+      padding-left: 30%;
+    }
+    text[class|="indent5"] {
+      padding-left: 35%;
+    }
+    text[class|="indent6"] {
+      padding-left: 40%;
+    }
+    text[class|="indent7"] {
+      padding-left: 45%;
+    }
+    text[class|="indent8"] {
+      padding-left: 50%;
+    }
+    text[class|="indent9"] {
+      padding-left: 55%;
+    }
+
+    text[class|="hang0_indent0"] {
+      padding-left: 10%;
+      text-indent:   0%;
+    }
+    text[class|="hang0_indent1"] {
+      padding-left: 15%;
+      text-indent:  -5%;
+    }
+    text[class|="hang0_indent2"] {
+      padding-left: 20%;
+      text-indent: -10%;
+    }
+    text[class|="hang0_indent3"] {
+      padding-left: 25%;
+      text-indent: -15%;
+    }
+    text[class|="hang0_indent4"] {
+      padding-left: 30%;
+      text-indent: -20%;
+    }
+    text[class|="hang0_indent5"] {
+      padding-left: 35%;
+      text-indent: -25%;
+    }
+    text[class|="hang0_indent6"] {
+      padding-left: 40%;
+      text-indent: -30%;
+    }
+    text[class|="hang0_indent7"] {
+      padding-left: 45%;
+      text-indent: -35%;
+    }
+    text[class|="hang0_indent8"] {
+      padding-left: 50%;
+      text-indent: -40%;
+    }
+    text[class|="hang0_indent9"] {
+      padding-left: 55%;
+      text-indent: -45%;
+    }
+
+    text[class|="hang1_indent0"] {
+      padding-left: 10%;
+      text-indent:   5%;
+    }
+    text[class|="hang1_indent1"] {
+      padding-left: 15%;
+      text-indent:   0%;
+    }
+    text[class|="hang1_indent2"] {
+      padding-left: 20%;
+      text-indent:  -5%;
+    }
+    text[class|="hang1_indent3"] {
+      padding-left: 25%;
+      text-indent: -10%;
+    }
+    text[class|="hang1_indent4"] {
+      padding-left: 30%;
+      text-indent: -15%;
+    }
+    text[class|="hang1_indent5"] {
+      padding-left: 35%;
+      text-indent: -20%;
+    }
+    text[class|="hang1_indent6"] {
+      padding-left: 40%;
+      text-indent: -25%;
+    }
+    text[class|="hang1_indent7"] {
+      padding-left: 45%;
+      text-indent: -30%;
+    }
+    text[class|="hang1_indent8"] {
+      padding-left: 50%;
+      text-indent: -35%;
+    }
+    text[class|="hang1_indent9"] {
+      padding-left: 55%;
+      text-indent: -40%;
+    }
+
+    text[class|="hang2_indent0"] {
+      padding-left: 10%;
+      text-indent:  10%;
+    }
+    text[class|="hang2_indent1"] {
+      padding-left: 15%;
+      text-indent:   5%;
+    }
+    text[class|="hang2_indent2"] {
+      padding-left: 20%;
+      text-indent:   0%;
+    }
+    text[class|="hang2_indent3"] {
+      padding-left: 25%;
+      text-indent:  -5%;
+    }
+    text[class|="hang2_indent4"] {
+      padding-left: 30%;
+      text-indent: -10%;
+    }
+    text[class|="hang2_indent5"] {
+      padding-left: 35%;
+      text-indent: -15%;
+    }
+    text[class|="hang2_indent6"] {
+      padding-left: 40%;
+      text-indent: -20%;
+    }
+    text[class|="hang2_indent7"] {
+      padding-left: 45%;
+      text-indent: -25%;
+    }
+    text[class|="hang2_indent8"] {
+      padding-left: 50%;
+      text-indent: -30%;
+    }
+    text[class|="hang2_indent9"] {
+      padding-left: 55%;
+      text-indent: -35%;
+    }
+
+    text[class|="hang3_indent0"] {
+      padding-left: 10%;
+      text-indent:  15%;
+    }
+    text[class|="hang3_indent1"] {
+      padding-left: 15%;
+      text-indent:  10%;
+    }
+    text[class|="hang3_indent2"] {
+      padding-left: 20%;
+      text-indent:   5%;
+    }
+    text[class|="hang3_indent3"] {
+      padding-left: 25%;
+      text-indent:   0%;
+    }
+    text[class|="hang3_indent4"] {
+      padding-left: 30%;
+      text-indent:  -5%;
+    }
+    text[class|="hang3_indent5"] {
+      padding-left: 35%;
+      text-indent: -10%;
+    }
+    text[class|="hang3_indent6"] {
+      padding-left: 40%;
+      text-indent: -15%;
+    }
+    text[class|="hang3_indent7"] {
+      padding-left: 45%;
+      text-indent: -20%;
+    }
+    text[class|="hang3_indent8"] {
+      padding-left: 50%;
+      text-indent: -25%;
+    }
+    text[class|="hang3_indent9"] {
+      padding-left: 55%;
+      text-indent: -30%;
+    }
+
+    text[class|="hang4_indent0"] {
+      padding-left: 10%;
+      text-indent:  20%;
+    }
+    text[class|="hang4_indent1"] {
+      padding-left: 15%;
+      text-indent:  15%;
+    }
+    text[class|="hang4_indent2"] {
+      padding-left: 20%;
+      text-indent:  10%;
+    }
+    text[class|="hang4_indent3"] {
+      padding-left: 25%;
+      text-indent:   5%;
+    }
+    text[class|="hang4_indent4"] {
+      padding-left: 30%;
+      text-indent:   0%;
+    }
+    text[class|="hang4_indent5"] {
+      padding-left: 35%;
+      text-indent:  -5%;
+    }
+    text[class|="hang4_indent6"] {
+      padding-left: 40%;
+      text-indent: -10%;
+    }
+    text[class|="hang4_indent7"] {
+      padding-left: 45%;
+      text-indent: -15%;
+    }
+    text[class|="hang4_indent8"] {
+      padding-left: 50%;
+      text-indent: -20%;
+    }
+    text[class|="hang4_indent9"] {
+      padding-left: 55%;
+      text-indent: -25%;
+    }
+
+    text[class|="hang5_indent0"] {
+      padding-left: 10%;
+      text-indent:  25%;
+    }
+    text[class|="hang5_indent1"] {
+      padding-left: 15%;
+      text-indent:  20%;
+    }
+    text[class|="hang5_indent2"] {
+      padding-left: 20%;
+      text-indent:  15%;
+    }
+    text[class|="hang5_indent3"] {
+      padding-left: 25%;
+      text-indent:  10%;
+    }
+    text[class|="hang5_indent4"] {
+      padding-left: 30%;
+      text-indent:   5%;
+    }
+    text[class|="hang5_indent5"] {
+      padding-left: 35%;
+      text-indent:   0%;
+    }
+    text[class|="hang5_indent6"] {
+      padding-left: 40%;
+      text-indent:  -5%;
+    }
+    text[class|="hang5_indent7"] {
+      padding-left: 45%;
+      text-indent: -10%;
+    }
+    text[class|="hang5_indent8"] {
+      padding-left: 50%;
+      text-indent: -15%;
+    }
+    text[class|="hang5_indent9"] {
+      padding-left: 55%;
+      text-indent: -20%;
+    }
+
+    text[class|="hang6_indent0"] {
+      padding-left: 10%;
+      text-indent:  30%;
+    }
+    text[class|="hang6_indent1"] {
+      padding-left: 15%;
+      text-indent:  25%;
+    }
+    text[class|="hang6_indent2"] {
+      padding-left: 20%;
+      text-indent:  20%;
+    }
+    text[class|="hang6_indent3"] {
+      padding-left: 25%;
+      text-indent:  15%;
+    }
+    text[class|="hang6_indent4"] {
+      padding-left: 30%;
+      text-indent:  10%;
+    }
+    text[class|="hang6_indent5"] {
+      padding-left: 35%;
+      text-indent:   5%;
+    }
+    text[class|="hang6_indent6"] {
+      padding-left: 40%;
+      text-indent:   0%;
+    }
+    text[class|="hang6_indent7"] {
+      padding-left: 45%;
+      text-indent:  -5%;
+    }
+    text[class|="hang6_indent8"] {
+      padding-left: 50%;
+      text-indent: -10%;
+    }
+    text[class|="hang6_indent9"] {
+      padding-left: 55%;
+      text-indent: -15%;
+    }
+
+    text[class|="hang7_indent0"] {
+      padding-left: 10%;
+      text-indent:  35%;
+    }
+    text[class|="hang7_indent1"] {
+      padding-left: 15%;
+      text-indent:  30%;
+    }
+    text[class|="hang7_indent2"] {
+      padding-left: 20%;
+      text-indent:  25%;
+    }
+    text[class|="hang7_indent3"] {
+      padding-left: 25%;
+      text-indent:  20%;
+    }
+    text[class|="hang7_indent4"] {
+      padding-left: 30%;
+      text-indent:  15%;
+    }
+    text[class|="hang7_indent5"] {
+      padding-left: 35%;
+      text-indent:  10%;
+    }
+    text[class|="hang7_indent6"] {
+      padding-left: 40%;
+      text-indent:   5%;
+    }
+    text[class|="hang7_indent7"] {
+      padding-left: 45%;
+      text-indent:   0%;
+    }
+    text[class|="hang7_indent8"] {
+      padding-left: 50%;
+      text-indent:  -5%;
+    }
+    text[class|="hang7_indent9"] {
+      padding-left: 55%;
+      text-indent: -10%;
+    }
+
+    text[class|="hang8_indent0"] {
+      padding-left: 10%;
+      text-indent:  40%;
+    }
+    text[class|="hang8_indent1"] {
+      padding-left: 15%;
+      text-indent:  35%;
+    }
+    text[class|="hang8_indent2"] {
+      padding-left: 20%;
+      text-indent:  30%;
+    }
+    text[class|="hang8_indent3"] {
+      padding-left: 25%;
+      text-indent:  25%;
+    }
+    text[class|="hang8_indent4"] {
+      padding-left: 30%;
+      text-indent:  20%;
+    }
+    text[class|="hang8_indent5"] {
+      padding-left: 35%;
+      text-indent:  15%;
+    }
+    text[class|="hang8_indent6"] {
+      padding-left: 40%;
+      text-indent:  10%;
+    }
+    text[class|="hang8_indent7"] {
+      padding-left: 45%;
+      text-indent:   5%;
+    }
+    text[class|="hang8_indent8"] {
+      padding-left: 50%;
+      text-indent:   0%;
+    }
+    text[class|="hang8_indent9"] {
+      padding-left: 55%;
+      text-indent:  -5%;
+    }
+
+    text[class|="hang9_indent0"] {
+      padding-left: 10%;
+      text-indent:  45%;
+    }
+    text[class|="hang9_indent1"] {
+      padding-left: 15%;
+      text-indent:  40%;
+    }
+    text[class|="hang9_indent2"] {
+      padding-left: 20%;
+      text-indent:  35%;
+    }
+    text[class|="hang9_indent3"] {
+      padding-left: 25%;
+      text-indent:  30%;
+    }
+    text[class|="hang9_indent4"] {
+      padding-left: 30%;
+      text-indent:  25%;
+    }
+    text[class|="hang9_indent5"] {
+      padding-left: 35%;
+      text-indent:  20%;
+    }
+    text[class|="hang9_indent6"] {
+      padding-left: 40%;
+      text-indent:  15%;
+    }
+    text[class|="hang9_indent7"] {
+      padding-left: 45%;
+      text-indent:  10%;
+    }
+    text[class|="hang9_indent8"] {
+      padding-left: 50%;
+      text-indent:   5%;
+    }
+    text[class|="hang9_indent9"] {
+      padding-left: 55%;
+      text-indent:   0%;
+    }
+
+    text[class|="indent_bullet"] {
+      text-indent: 0%;
+    }
+    text[class|="indent_bullet0"] {
+      text-indent: 0%;
+    }
+    text[class|="indent_bullet1"] {
+      text-indent: 10%;
+    }
+    text[class|="indent_bullet2"] {
+      text-indent: 15%;
+    }
+    text[class|="indent_bullet3"] {
+      text-indent: 20%;
+    }
+    text[class|="indent_bullet4"] {
+      text-indent: 25%;
+    }
+    text[class|="indent_bullet5"] {
+      text-indent: 30%;
+    }
+    text[class|="indent_bullet6"] {
+      text-indent: 35%;
+    }
+    text[class|="indent_bullet7"] {
+      text-indent: 40%;
+    }
+    text[class|="indent_bullet8"] {
+      text-indent: 45%;
+    }
+    text[class|="indent_bullet9"] {
+      text-indent: 50%;
+    }
+    text[class|="verse"], text[class|="block"], text[class|="group"], text[class|="code"] {
+      text-align: left;
+    }
+    ocn {
+      display: block;
+      text-align: right;
+      vertical-align: super;
+      color: #990000;
+      font-size: xx-small;
+      margin-right: 0mm;
+      margin-top: 0px;
+      margin-bottom: 0px;
+    }
+    named {
+      display: block;
+      margin-right: 0mm;
+      margin-top: 0px;
+      margin-bottom: 0px;
+    }
+    endnote {
+      display: block;
+      font-size: small;
+      font-family: #{the_font.set_fonts};
+      font-weight: normal;
+      line-height: 150%;
+      text-align: justify;
+      margin-left: 10%;
+      margin-right: 5%;
+      margin-top: 4px;
+      margin-bottom: 0px;
+    }
+    endnote_indent {
+      display: block;
+      font-size: small;
+      font-family: #{the_font.set_fonts};
+      font-weight: normal;
+      line-height: 150%;
+      text-align: justify;
+      margin-left: 15%;
+      margin-right: 5%;
+      margin-top: 4px;
+      margin-bottom: 0px;
+    }
+    en {
+      font-size: xx-small;
+      vertical-align: super;
+    }
+    i { font-style: italic; }
+    b { font-style: bold; }
+    u { text-decoration: underline; }
+    br { display: block; }
+
+    text[class|="table"] {
+      display: table;
+      /* display: block; */
+      text-align: left;
+    }
+
+    table {
+      margin-left: 0%;
+      display: block;
+      /* display: table; */
+      width: 100%;
+    }
+    tr {
+      display: block;
+      /* display: table-row; */
+    }
+    th, td {
+      display: table-cell;
+      /* display: inline; */
+      vertical-align: top;
+    }
+    p.left, th.left, td.left {
+      text-align: left;
+    }
+    p.small_left, th.small_left, td.small_left {
+      text-align: left;
+      font-size: 80%;
+    }
+    p.right, th.right, td.right {
+      text-align: right;
+    }
+
+    .svg_outer {
+      display: block;
+      margin-bottom: 0;
+      margin-left: 0;
+      margin-right: 0;
+      margin-top: 0;
+      padding-bottom: 0;
+      padding-left: 0;
+      padding-right: 0;
+      padding-top: 0;
+      text-align: left;
+    }
+    .svg_inner {
+      display: block;
+      text-align: center;
+    }
+WOK
+    end
+    def xml_sax                                   #stylesheet for xml sax
+      xhtml
+    end
+    def xml_dom                                   #sylesheet for xml dom, work on, starts from copy of css_xhtml
+<<WOK
+/* SiSU css dom.xml default style */
+    document {
+      display: block;
+      margin-left: 0mm;
+      margin-right: 0mm;
+    }
+    head {
+      display: block;
+      margin-bottom: 20px;
+      background-color: #dddddd;
+    }
+    header {
+      display: block;
+    }
+    meta {
+      display: inline;
+      line-height: 1;
+      font-size: 10px;
+      color: #990000;
+      margin-right: 2mm;
+      margin-top: 0px;
+      margin-bottom: 0px;
+
+    }
+    md {
+      display: inline;
+      line-height: 1;
+      font-size: 10px;
+      color: #000099;
+      margin-top: 0px;
+      margin-bottom: 0px;
+    }
+    source_control {
+      display: block;
+    }
+    dc {
+      display: block;
+      font-family: #{the_font.set_fonts};
+      color: blue;
+      background-color: #dddddd;
+      font-weight: normal;
+      text-align: justify;
+      font-size: xx-small;
+      line-height: 120%;
+      margin-left: 5%;
+      margin-right: 5mm;
+      margin-top: 0px;
+      margin-bottom: 0px;
+    }
+    sc {
+      display: inline;
+      color: green;
+    }
+    keywords,copyright {
+      display: block;
+      font-family: #{the_font.set_fonts};
+      color: red;
+      background-color: #dddddd;
+      font-weight: normal;
+      text-align: justify;
+      font-size: xx-small;
+      line-height: 120%;
+      margin-left: 5%;
+      margin-right: 5mm;
+      margin-top: 0px;
+      margin-bottom: 0px;
+    }
+    body {
+      color: black;
+      background: #ffffff;
+    }
+    a:link {
+      color: #003399;
+      text-decoration: none;
+    }
+    a:visited {
+      color: #003399;
+      text-decoration: none;
+      /* background-color: #e3ecef; */
+    }
+    a:hover {
+      color: #000000;
+      text-decoration: underline;
+      background-color: #fff3b6;
+    }
+    a:hover IMG {
+      background-color: #ffffff;
+    }
+    a:active {
+      color: #003399;
+      text-decoration: underline;
+    }
+    object {
+      display: block;
+      margin-left: 2mm;
+      margin-right: 2mm;
+      margin-top: 4px;
+      margin-bottom: 8px;
+    }
+    heading {
+      font-weight: bold;
+    }
+    contents {
+      font-weight: normal;
+    }
+    text {
+      display: block;
+      font-family: #{the_font.set_fonts};
+      text-align: justify;
+      font-size: 100%;
+      line-height: 150%;
+      margin-left: 5%;
+      margin-right: 5%;
+      margin-top: 2px;
+      margin-bottom: 0px;
+    }
+    text[class|="norm"] {
+      font-weight: normal;
+    }
+    text[class|="h1"] {
+      font-size: 120%;
+      font-weight: bold;
+      text-align: left;
+      line-height: 120%;
+      margin-top: 20px;
+      margin-bottom: 10px;
+    }
+    text[class|="h2"] {
+      font-weight: bold;
+      font-size: 110%;
+      text-align: left;
+      margin-top: 20px;
+      margin-bottom: 10px;
+    }
+    text[class|="h3"] {
+      font-size: 110%;
+      font-weight: bold;
+      text-align: left;
+    }
+    text[class|="h4"] {
+      font-size: 110%;
+      font-weight: bold;
+      text-align: left;
+    }
+    text[class|="h5"] {
+      font-size: 110%;
+      font-weight: bold;
+      text-align: left;
+    }
+    text[class|="h6"] {
+      font-size: 110%;
+      font-weight: bold;
+      text-align: left;
+    }
+    text[class|="h7"] {
+      font-size: 110%;
+      font-weight: bold;
+      text-align: left;
+    }
+    text[class|="indent0"] {
+      padding-left: 10%;
+    }
+    text[class|="indent1"] {
+      padding-left: 15%;
+    }
+    text[class|="indent2"] {
+      padding-left: 20%;
+    }
+    text[class|="indent3"] {
+      padding-left: 25%;
+    }
+    text[class|="indent4"] {
+      padding-left: 30%;
+    }
+    text[class|="indent5"] {
+      padding-left: 35%;
+    }
+    text[class|="indent6"] {
+      padding-left: 40%;
+    }
+    text[class|="indent7"] {
+      padding-left: 45%;
+    }
+    text[class|="indent8"] {
+      padding-left: 50%;
+    }
+    text[class|="indent9"] {
+      padding-left: 55%;
+    }
+
+    text[class|="hang0_indent0"] {
+      padding-left: 10%;
+      text-indent:   0%;
+    }
+    text[class|="hang0_indent1"] {
+      padding-left: 15%;
+      text-indent:  -5%;
+    }
+    text[class|="hang0_indent2"] {
+      padding-left: 20%;
+      text-indent: -10%;
+    }
+    text[class|="hang0_indent3"] {
+      padding-left: 25%;
+      text-indent: -15%;
+    }
+    text[class|="hang0_indent4"] {
+      padding-left: 30%;
+      text-indent: -20%;
+    }
+    text[class|="hang0_indent5"] {
+      padding-left: 35%;
+      text-indent: -25%;
+    }
+    text[class|="hang0_indent6"] {
+      padding-left: 40%;
+      text-indent: -30%;
+    }
+    text[class|="hang0_indent7"] {
+      padding-left: 45%;
+      text-indent: -35%;
+    }
+    text[class|="hang0_indent8"] {
+      padding-left: 50%;
+      text-indent: -40%;
+    }
+    text[class|="hang0_indent9"] {
+      padding-left: 55%;
+      text-indent: -45%;
+    }
+
+    text[class|="hang1_indent0"] {
+      padding-left: 10%;
+      text-indent:   5%;
+    }
+    text[class|="hang1_indent1"] {
+      padding-left: 15%;
+      text-indent:   0%;
+    }
+    text[class|="hang1_indent2"] {
+      padding-left: 20%;
+      text-indent:  -5%;
+    }
+    text[class|="hang1_indent3"] {
+      padding-left: 25%;
+      text-indent: -10%;
+    }
+    text[class|="hang1_indent4"] {
+      padding-left: 30%;
+      text-indent: -15%;
+    }
+    text[class|="hang1_indent5"] {
+      padding-left: 35%;
+      text-indent: -20%;
+    }
+    text[class|="hang1_indent6"] {
+      padding-left: 40%;
+      text-indent: -25%;
+    }
+    text[class|="hang1_indent7"] {
+      padding-left: 45%;
+      text-indent: -30%;
+    }
+    text[class|="hang1_indent8"] {
+      padding-left: 50%;
+      text-indent: -35%;
+    }
+    text[class|="hang1_indent9"] {
+      padding-left: 55%;
+      text-indent: -40%;
+    }
+
+    text[class|="hang2_indent0"] {
+      padding-left: 10%;
+      text-indent:  10%;
+    }
+    text[class|="hang2_indent1"] {
+      padding-left: 15%;
+      text-indent:   5%;
+    }
+    text[class|="hang2_indent2"] {
+      padding-left: 20%;
+      text-indent:   0%;
+    }
+    text[class|="hang2_indent3"] {
+      padding-left: 25%;
+      text-indent:  -5%;
+    }
+    text[class|="hang2_indent4"] {
+      padding-left: 30%;
+      text-indent: -10%;
+    }
+    text[class|="hang2_indent5"] {
+      padding-left: 35%;
+      text-indent: -15%;
+    }
+    text[class|="hang2_indent6"] {
+      padding-left: 40%;
+      text-indent: -20%;
+    }
+    text[class|="hang2_indent7"] {
+      padding-left: 45%;
+      text-indent: -25%;
+    }
+    text[class|="hang2_indent8"] {
+      padding-left: 50%;
+      text-indent: -30%;
+    }
+    text[class|="hang2_indent9"] {
+      padding-left: 55%;
+      text-indent: -35%;
+    }
+
+    text[class|="hang3_indent0"] {
+      padding-left: 10%;
+      text-indent:  15%;
+    }
+    text[class|="hang3_indent1"] {
+      padding-left: 15%;
+      text-indent:  10%;
+    }
+    text[class|="hang3_indent2"] {
+      padding-left: 20%;
+      text-indent:   5%;
+    }
+    text[class|="hang3_indent3"] {
+      padding-left: 25%;
+      text-indent:   0%;
+    }
+    text[class|="hang3_indent4"] {
+      padding-left: 30%;
+      text-indent:  -5%;
+    }
+    text[class|="hang3_indent5"] {
+      padding-left: 35%;
+      text-indent: -10%;
+    }
+    text[class|="hang3_indent6"] {
+      padding-left: 40%;
+      text-indent: -15%;
+    }
+    text[class|="hang3_indent7"] {
+      padding-left: 45%;
+      text-indent: -20%;
+    }
+    text[class|="hang3_indent8"] {
+      padding-left: 50%;
+      text-indent: -25%;
+    }
+    text[class|="hang3_indent9"] {
+      padding-left: 55%;
+      text-indent: -30%;
+    }
+
+    text[class|="hang4_indent0"] {
+      padding-left: 10%;
+      text-indent:  20%;
+    }
+    text[class|="hang4_indent1"] {
+      padding-left: 15%;
+      text-indent:  15%;
+    }
+    text[class|="hang4_indent2"] {
+      padding-left: 20%;
+      text-indent:  10%;
+    }
+    text[class|="hang4_indent3"] {
+      padding-left: 25%;
+      text-indent:   5%;
+    }
+    text[class|="hang4_indent4"] {
+      padding-left: 30%;
+      text-indent:   0%;
+    }
+    text[class|="hang4_indent5"] {
+      padding-left: 35%;
+      text-indent:  -5%;
+    }
+    text[class|="hang4_indent6"] {
+      padding-left: 40%;
+      text-indent: -10%;
+    }
+    text[class|="hang4_indent7"] {
+      padding-left: 45%;
+      text-indent: -15%;
+    }
+    text[class|="hang4_indent8"] {
+      padding-left: 50%;
+      text-indent: -20%;
+    }
+    text[class|="hang4_indent9"] {
+      padding-left: 55%;
+      text-indent: -25%;
+    }
+
+    text[class|="hang5_indent0"] {
+      padding-left: 10%;
+      text-indent:  25%;
+    }
+    text[class|="hang5_indent1"] {
+      padding-left: 15%;
+      text-indent:  20%;
+    }
+    text[class|="hang5_indent2"] {
+      padding-left: 20%;
+      text-indent:  15%;
+    }
+    text[class|="hang5_indent3"] {
+      padding-left: 25%;
+      text-indent:  10%;
+    }
+    text[class|="hang5_indent4"] {
+      padding-left: 30%;
+      text-indent:   5%;
+    }
+    text[class|="hang5_indent5"] {
+      padding-left: 35%;
+      text-indent:   0%;
+    }
+    text[class|="hang5_indent6"] {
+      padding-left: 40%;
+      text-indent:  -5%;
+    }
+    text[class|="hang5_indent7"] {
+      padding-left: 45%;
+      text-indent: -10%;
+    }
+    text[class|="hang5_indent8"] {
+      padding-left: 50%;
+      text-indent: -15%;
+    }
+    text[class|="hang5_indent9"] {
+      padding-left: 55%;
+      text-indent: -20%;
+    }
+
+    text[class|="hang6_indent0"] {
+      padding-left: 10%;
+      text-indent:  30%;
+    }
+    text[class|="hang6_indent1"] {
+      padding-left: 15%;
+      text-indent:  25%;
+    }
+    text[class|="hang6_indent2"] {
+      padding-left: 20%;
+      text-indent:  20%;
+    }
+    text[class|="hang6_indent3"] {
+      padding-left: 25%;
+      text-indent:  15%;
+    }
+    text[class|="hang6_indent4"] {
+      padding-left: 30%;
+      text-indent:  10%;
+    }
+    text[class|="hang6_indent5"] {
+      padding-left: 35%;
+      text-indent:   5%;
+    }
+    text[class|="hang6_indent6"] {
+      padding-left: 40%;
+      text-indent:   0%;
+    }
+    text[class|="hang6_indent7"] {
+      padding-left: 45%;
+      text-indent:  -5%;
+    }
+    text[class|="hang6_indent8"] {
+      padding-left: 50%;
+      text-indent: -10%;
+    }
+    text[class|="hang6_indent9"] {
+      padding-left: 55%;
+      text-indent: -15%;
+    }
+
+    text[class|="hang7_indent0"] {
+      padding-left: 10%;
+      text-indent:  35%;
+    }
+    text[class|="hang7_indent1"] {
+      padding-left: 15%;
+      text-indent:  30%;
+    }
+    text[class|="hang7_indent2"] {
+      padding-left: 20%;
+      text-indent:  25%;
+    }
+    text[class|="hang7_indent3"] {
+      padding-left: 25%;
+      text-indent:  20%;
+    }
+    text[class|="hang7_indent4"] {
+      padding-left: 30%;
+      text-indent:  15%;
+    }
+    text[class|="hang7_indent5"] {
+      padding-left: 35%;
+      text-indent:  10%;
+    }
+    text[class|="hang7_indent6"] {
+      padding-left: 40%;
+      text-indent:   5%;
+    }
+    text[class|="hang7_indent7"] {
+      padding-left: 45%;
+      text-indent:   0%;
+    }
+    text[class|="hang7_indent8"] {
+      padding-left: 50%;
+      text-indent:  -5%;
+    }
+    text[class|="hang7_indent9"] {
+      padding-left: 55%;
+      text-indent: -10%;
+    }
+
+    text[class|="hang8_indent0"] {
+      padding-left: 10%;
+      text-indent:  40%;
+    }
+    text[class|="hang8_indent1"] {
+      padding-left: 15%;
+      text-indent:  35%;
+    }
+    text[class|="hang8_indent2"] {
+      padding-left: 20%;
+      text-indent:  30%;
+    }
+    text[class|="hang8_indent3"] {
+      padding-left: 25%;
+      text-indent:  25%;
+    }
+    text[class|="hang8_indent4"] {
+      padding-left: 30%;
+      text-indent:  20%;
+    }
+    text[class|="hang8_indent5"] {
+      padding-left: 35%;
+      text-indent:  15%;
+    }
+    text[class|="hang8_indent6"] {
+      padding-left: 40%;
+      text-indent:  10%;
+    }
+    text[class|="hang8_indent7"] {
+      padding-left: 45%;
+      text-indent:   5%;
+    }
+    text[class|="hang8_indent8"] {
+      padding-left: 50%;
+      text-indent:   0%;
+    }
+    text[class|="hang8_indent9"] {
+      padding-left: 55%;
+      text-indent:  -5%;
+    }
+
+    text[class|="hang9_indent0"] {
+      padding-left: 10%;
+      text-indent:  45%;
+    }
+    text[class|="hang9_indent1"] {
+      padding-left: 15%;
+      text-indent:  40%;
+    }
+    text[class|="hang9_indent2"] {
+      padding-left: 20%;
+      text-indent:  35%;
+    }
+    text[class|="hang9_indent3"] {
+      padding-left: 25%;
+      text-indent:  30%;
+    }
+    text[class|="hang9_indent4"] {
+      padding-left: 30%;
+      text-indent:  25%;
+    }
+    text[class|="hang9_indent5"] {
+      padding-left: 35%;
+      text-indent:  20%;
+    }
+    text[class|="hang9_indent6"] {
+      padding-left: 40%;
+      text-indent:  15%;
+    }
+    text[class|="hang9_indent7"] {
+      padding-left: 45%;
+      text-indent:  10%;
+    }
+    text[class|="hang9_indent8"] {
+      padding-left: 50%;
+      text-indent:   5%;
+    }
+    text[class|="hang9_indent9"] {
+      padding-left: 55%;
+      text-indent:   0%;
+    }
+
+    text[class|="indent_bullet"] {
+      text-indent: 0%;
+    }
+    text[class|="indent_bullet0"] {
+      text-indent: 0%;
+    }
+    text[class|="indent_bullet1"] {
+      padding-left: 10%;
+    }
+    text[class|="indent_bullet2"] {
+      padding-left: 15%;
+    }
+    text[class|="indent_bullet3"] {
+      padding-left: 20%;
+    }
+    text[class|="indent_bullet4"] {
+      padding-left: 25%;
+    }
+    text[class|="indent_bullet5"] {
+      padding-left: 30%;
+    }
+    text[class|="indent_bullet6"] {
+      padding-left: 35%;
+    }
+    text[class|="indent_bullet7"] {
+      padding-left: 40%;
+    }
+    text[class|="indent_bullet8"] {
+      padding-left: 45%;
+    }
+    text[class|="indent_bullet9"] {
+      padding-left: 50%;
+    }
+    text[class|="verse"], text[class|="block"], text[class|="group"], text[class|="code"] {
+      text-align: left;
+    }
+    table {
+      margin-left: 5%;
+      display: block;
+    }
+    tr {
+      display: block;
+    }
+    th, td {
+      display: inline;
+    }
+    nametag {
+      display: none;
+    }
+    number {
+      padding-right: 4px;
+    }
+    ocn {
+      font-weight: normal;
+      display: block;
+      text-align: right;
+      vertical-align: super;
+      color: #990000;
+      font-size: xx-small;
+      margin-right: 0mm;
+      margin-top: 0px;
+      margin-bottom: 0px;
+    }
+    endnote {
+      display: block;
+      font-size: small;
+      font-family: #{the_font.set_fonts};
+      font-weight: normal;
+      line-height: 150%;
+      text-align: justify;
+      margin-left: 10%;
+      margin-right: 5%;
+      margin-top: 4px;
+      margin-bottom: 0px;
+    }
+    endnote_indent {
+      display: block;
+      font-size: small;
+      font-family: #{the_font.set_fonts};
+      font-weight: normal;
+      line-height: 150%;
+      text-align: justify;
+      margin-left: 15%;
+      margin-right: 5%;
+      margin-top: 4px;
+      margin-bottom: 0px;
+    }
+    en {
+      font-size: xx-small;
+      vertical-align: super;
+    }
+    i { font-style: italic; }
+    b { font-style: bold; }
+    u { text-decoration: underline; }
+    br { display: block; }
+WOK
+    end
+    def xml_docbook                               #stylesheet for docbook
+<<WOK
+/* SiSU css docbook.xml default style */
+    book {
+      display: block;
+      margin-left: 0mm;
+      margin-right: 0mm;
+    }
+    bookinfo {
+      display: block;
+      margin-bottom: 20px;
+      background-color: #dddddd;
+    }
+    source_control {
+      display: block;
+    }
+    dc,sc {
+      display: block;
+      font-family: #{the_font.set_fonts};
+      color: blue;
+      background-color: #dddddd;
+      font-weight: normal;
+      text-align: justify;
+      font-size: xx-small;
+      line-height: 120%;
+      margin-left: 5%;
+      margin-right: 5mm;
+      margin-top: 0px;
+      margin-bottom: 0px;
+    }
+    sc {
+      color: green;
+    }
+    keywords,copyright {
+      display: block;
+      font-family: #{the_font.set_fonts};
+      color: red;
+      background-color: #dddddd;
+      font-weight: normal;
+      text-align: justify;
+      font-size: xx-small;
+      line-height: 120%;
+      margin-left: 5%;
+      margin-right: 5mm;
+      margin-top: 0px;
+      margin-bottom: 0px;
+    }
+    body {
+      color: black;
+      background: #ffffff;
+    }
+    a:link {
+      color: #003399;
+      text-decoration: none;
+    }
+    a:visited {
+      color: #003399;
+      text-decoration: none;
+      /* background-color: #e3ecef; */
+    }
+    a:hover {
+      color: #000000;
+      text-decoration: underline;
+      background-color: #fff3b6;
+    }
+    a:hover IMG {
+      background-color: #ffffff;
+    }
+    a:active {
+      color: #003399;
+      text-decoration: underline;
+    }
+    object {
+      display: block;
+      margin-left: 2mm;
+      margin-right: 2mm;
+      margin-top: 4px;
+      margin-bottom: 8px;
+    }
+    part {
+      display: block;
+      /* font-weight: bold; */
+    }
+    contents {
+      font-weight: normal;
+    }
+    para {
+      display: block;
+      font-family: #{the_font.set_fonts};
+      /* font-weight: normal; */
+      text-align: justify;
+      font-size: 100%;
+      line-height: 150%;
+      margin-left: 5%;
+      margin-right: 5%;
+      margin-top: 2px;
+      margin-bottom: 0px;
+    }
+    para.verse, para.block, para.group, para.code {
+      text-align: left;
+    }
+    para.norm {
+      font-family: #{the_font.set_fonts};
+      font-weight: normal;
+    }
+    para.h1, title {
+      display: block;
+      font-family: #{the_font.set_fonts};
+      font-size: 120%;
+      font-weight: bold;
+      text-align: left;
+      line-height: 120%;
+      margin-top: 20px;
+      margin-bottom: 10px;
+    }
+    para.h2 {
+      font-weight: bold;
+      font-size: 110%;
+      text-align: left;
+      margin-top: 20px;
+      margin-bottom: 10px;
+    }
+    para.h3 {
+      font-size: 110%;
+      font-weight: bold;
+      text-align: left;
+    }
+    para.h4 {
+      font-size: 110%;
+      font-weight: bold;
+      text-align: left;
+    }
+    para.h5 {
+      font-size: 110%;
+      font-weight: bold;
+      text-align: left;
+    }
+    para.h6 {
+      font-size: 110%;
+      font-weight: bold;
+      text-align: left;
+    }
+    para.h7 {
+      font-size: 110%;
+      font-weight: bold;
+      text-align: left;
+    }
+    table {
+      margin-left: 5%;
+      display: block;
+    }
+    tr {
+      display: block;
+    }
+    th, td {
+      display: inline;
+    }
+    nametag {
+      display: none;
+    }
+    number {
+      padding-right: 4px;
+    }
+    ocn {
+      font-weight: normal;
+      display: block;
+      text-align: right;
+      vertical-align: super;
+      color: #990000;
+      font-size: xx-small;
+      margin-right: 0mm;
+      margin-top: 0px;
+      margin-bottom: 0px;
+    }
+    endnote {
+      display: block;
+      font-size: small;
+      font-family: #{the_font.set_fonts};
+      font-weight: normal;
+      line-height: 150%;
+      text-align: justify;
+      margin-left: 10%;
+      margin-right: 5%;
+      margin-top: 4px;
+      margin-bottom: 0px;
+    }
+    endnote_indent {
+      display: block;
+      font-size: small;
+      font-family: #{the_font.set_fonts};
+      font-weight: normal;
+      line-height: 150%;
+      text-align: justify;
+      margin-left: 15%;
+      margin-right: 5%;
+      margin-top: 4px;
+      margin-bottom: 0px;
+    }
+    en {
+      font-size: xx-small;
+      vertical-align: super;
+    }
+    i { font-style: italic; }
+    b { font-style: bold; }
+    u { text-decoration: underline; }
+    br { display: block; }
+WOK
+    end
+    def css_xhtml_p                               #stylesheet for ...
+<<WOK
+    body {
+      color: black;
+      background: #ffffff;
+    }
+    a:link {
+      color: #003399;
+      text-decoration: none;
+    }
+    a:visited {
+      color: #003399;
+      text-decoration: none;
+      /* background-color: #e3ecef; */
+    }
+    a:hover {
+      color: #000000;
+      text-decoration: underline;
+      background-color: #fff3b6;
+    }
+    a:hover IMG {
+      background-color: #ffffff;
+    }
+    a:active {
+      color: #003399;
+      text-decoration: underline;
+    }
+    object {
+      display: block;
+      margin-top: 3px;
+      margin-bottom: 3px;
+      margin-right: 5mm;
+    }
+    p {
+      display: block;
+      font-family: #{the_font.set_fonts};
+      font-size: 100%;
+      font-weight: normal;
+      line-height: 150%;
+      text-align: justify;
+      margin-left: 10mm;
+      margin-top: 3px;
+      margin-bottom: 0px;
+      margin-right: 5mm
+    }
+    p.norm { }
+    p.endnote {
+      font-size: 100%;
+      margin-left: 20%;
+      text-indent: 5%
+    }
+    p.endnote_indent {
+      font-size: 100%;
+      margin-left: 25%;
+      text-indent: 5%
+    }
+    p.h1 {
+      font-family: #{the_font.set_fonts};
+      font-weight: bold;
+      line-height: 120%;
+      margin-left: 10mm;
+      margin-right: 10mm;
+      text-align: left;
+      margin-top: 20px;
+      margin-bottom: 10px;
+    }
+    p.h2 {
+      font-weight: bold;
+      font-size: 110%;
+      margin-left: 10mm;
+      margin-right: 15mm;
+      text-align: left;
+      margin-top: 20px;
+      margin-bottom: 10px;
+    }
+    p.h3 {
+      font-size: 150%;
+      font-weight: bold;
+      text-align: left;
+    }
+    p.h4 {
+      font-size: 150%;
+      font-weight: bold;
+      text-align: left;
+    }
+    p.h5 {
+      font-size: 150%;
+      font-weight: bold;
+      text-align: left;
+    }
+    p.h6 {
+      font-size: 150%;
+      font-weight: bold;
+      text-align: left;
+    }
+    p.h7 {
+      font-size: 150%;
+      font-weight: bold;
+      text-align: left;
+    }
+    ocn {
+      display: block;
+      text-align: right;
+      vertical-align: super;
+      color: #990000;
+      font-size: xx-small;
+      margin-top: 0px;
+      margin-bottom: 6px;
+    }
+    en {
+      font-size: xx-small;
+      vertical-align: super;
+    }
+    i { font-style: italic; }
+    b { font-style: bold; }
+    u { text-decoration: underline; }
+    br { display: block; }
+WOK
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    css
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/db.org b/org/db.org
new file mode 100644
index 00000000..4a2f216b
--- /dev/null
+++ b/org/db.org
@@ -0,0 +1,4808 @@
+-*- mode: org -*-
+#+TITLE:       sisu db sql
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:db:sql:
+#+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
+
+* dbi.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/dbi.rb"
+# <<sisu_document_header>>
+module  SiSU_DBI                                                                 #% database building
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env; include SiSU_Screen
+  require_relative 'dp'                                 # dp.rb
+    include SiSU_Param
+  require_relative 'db_dbi'                             # db_dbi.rb
+    include SiSU_DbDBI
+  require_relative 'html_lite_shared'                   # html_lite_shared.rb
+    include SiSU_FormatShared
+  class SQL
+    def initialize(opt)
+      @opt=opt
+      @db=SiSU_Env::InfoDb.new
+      if @opt.act[:psql][:set]==:on \
+      or @opt.act[:sqlite][:set]==:on
+        @sql_type=if @opt.act[:psql][:set]==:on
+          maintenance_check(@opt,__FILE__,__LINE__) if @opt.act[:maintenance][:set]==:on
+          :pg
+        elsif @opt.act[:psql][:set]==:on
+          maintenance_check(@opt,__FILE__,__LINE__) if @opt.act[:maintenance][:set]==:on
+          :pg
+        elsif @opt.act[:sqlite][:set]==:on
+          maintenance_check(@opt,__FILE__,__LINE__) if @opt.act[:maintenance][:set]==:on
+          :sqlite
+        elsif @opt.act[:sqlite][:set]==:on
+          maintenance_check(@opt,__FILE__,__LINE__) if @opt.act[:maintenance][:set]==:on
+          :sqlite
+        else
+          maintenance_check(@opt,__FILE__,__LINE__) if @opt.act[:maintenance][:set]==:on
+          :sqlite
+        end
+        if    @sql_type==:pg    then SiSU_Env::Load.new('pg',true).prog
+        elsif @sql_type==:sqlite then SiSU_Env::Load.new('sqlite3',true).prog
+        end
+      end
+    end
+    def maintenance_check(opt,file,line)
+      p opt.selections.str
+      p "at #{file} #{line}"
+    end
+    def read_psql
+      begin
+        begin
+          require 'pg'
+        rescue LoadError
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+            error('pg NOT FOUND (LoadError)')
+        end
+        @conn=@db.psql.conn_pg
+      rescue
+        if @opt.act[:psql_create][:set]==:on
+          cX=SiSU_Screen::Ansi.new(@opt.act[:color_state][:set]).cX
+          puts <<-WOK
+manually create the database: "#{cX.green}#{@db.db}#{cX.off}" if it does not yet exist
+  #{cX.yellow}createdb #{@db.db}#{cX.off}
+          WOK
+          #sudo su -p postgres;  createdb #{@db.db}; #[createuser?]
+        end
+      ensure
+      end
+    end
+    def read_sqlite
+      begin
+        begin
+          begin
+            require 'sqlite3'
+          rescue LoadError
+            SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+              error('sqlite3 NOT FOUND (LoadError)')
+          end
+          @conn=@db.sqlite.conn_sqlite3
+        rescue LoadError
+          errmsg='sqlite3 NOT FOUND (LoadError)'
+          if @opt.act[:no_stop][:set]==:on
+            SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+              error(errmsg + ', ' + 'attempt to proceed without sqlite output (as requested)')
+          else
+            SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+              error(errmsg + ', ' + 'STOPPING')
+            exit
+          end
+        end
+      end
+    end
+    def connect
+      case @sql_type
+      when :pg     then read_psql #read_pg
+      when :sqlite then read_sqlite
+      end
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        "SQL DB #{@sql_type.upcase}",
+        @opt.fno
+      ).dbi_title unless @opt.act[:quiet][:set]==:on
+      begin
+        SiSU_DbDBI::Case.new(@opt,@conn,@sql_type).cases
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@cf,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+      begin
+      rescue
+        connect
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* dbi_discrete.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/dbi_discrete.rb"
+# <<sisu_document_header>>
+module  SiSU_DBI_Discrete                               #% database building
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env; include SiSU_Screen
+  require_relative 'dp'                                 # dp.rb
+    include SiSU_Param
+  require_relative 'db_dbi'                             # db_dbi.rb
+    include SiSU_DbDBI
+  require_relative 'html_lite_shared'                   # html_lite_shared.rb
+    include SiSU_FormatShared
+  begin
+    require 'fileutils'
+      include FileUtils::Verbose
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('fileutils NOT FOUND (LoadError)')
+  end
+  class SQL
+    def initialize(opt)
+      SiSU_Env::Load.new('sqlite3',true).prog
+      @opt=opt
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+      @md=@particulars.md
+      if @opt.act[:sqlite][:set]==:on
+        @sql_type=:sqlite
+        if @opt.act[:maintenance][:set]==:on
+          maintenance_check(@opt,__FILE__,__LINE__)
+        end
+      end
+      @output_path=@md.file.output_path.sqlite_discrete.dir
+      @filename=@md.file.base_filename.sqlite_discrete
+      @file_maint=sql_maintenance_file
+      @file="#{@output_path}/#{@filename}"
+    end
+    def build
+      prepare
+      create_and_populate
+    end
+    def maintenance_check(opt,file,line)
+      #p opt.selections.str
+      p "at #{file} #{line}"
+    end
+    def prepare
+      if not FileTest.directory?(@output_path)
+        FileUtils::mkdir_p(@output_path)
+      elsif @file
+        FileUtils::rm_rf(@file)
+      end
+    end
+    def db_exist?(db,conn)
+      msg=%{no connection with sqlite database established, createdb "#{db.sqlite.db}"?}
+      if (not (FileTest.file?(db.sqlite.db)) \
+      or FileTest.zero?(db.sqlite.db))
+        puts msg
+        exit
+      end
+      if conn.is_a?(NilClass)
+        puts msg
+        exit
+      end
+    end
+    def create_and_populate
+      db=SiSU_Env::DbOp.new(@md)
+      conn=db.sqlite_discrete.conn_sqlite3
+      sdb=SiSU_DbDBI::Create.new(@opt,conn,@file,:sqlite)
+      sdb_index=SiSU_DbDBI::Index.new(@opt,conn,@file,:sqlite)
+      sdb.output_dir?
+      begin
+        SiSU_Screen::Ansi.new(
+          @opt.act[:color_state][:set],
+          'SQLite (discrete)',
+          "[#{@opt.f_pth[:lng_is]}] #{@opt.fno}"
+        ).green_title_hi unless @opt.act[:quiet][:set]==:on
+        sdb.create_db
+        sdb.create_table.metadata_and_text
+        sdb.create_table.doc_objects
+        sdb.create_table.endnotes
+        sdb.create_table.endnotes_asterisk
+        sdb.create_table.endnotes_plus
+        sdb.create_table.urls
+        sdb_index.create_indexes
+        db_exist?(db,conn)
+        sdb_import=SiSU_DbDBI::Import.new(@opt,conn,@file_maint,:sqlite)
+        sdb_import.marshal_load
+        tell=SiSU_Screen::Ansi.new(
+               @opt.act[:color_state][:set],
+               "sqlite3 #{db.sqlite.db} database?"
+             )
+        tell.puts_grey if @opt.act[:verbose][:set]==:on
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,'-d').location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+        sdb.output_dir?
+      end
+    end
+    def read_sqlite
+      begin
+        begin
+          require 'sqlite3'
+          @conn=@db.sqlite.conn_sqlite3
+        rescue LoadError
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).error('sqlite3 not available')
+        ensure
+          Dir.chdir(@opt.f_pth[:pth])
+        end
+      end
+    end
+    def connect
+      begin
+        SiSU_Screen::Ansi.new(
+          @opt.act[:color_state][:set],
+          "DBI (#{@sql_type}) #{@opt.selections.str}",
+          @opt.fns
+        ).dbi_title unless @opt.act[:quiet][:set]==:on
+        @db.sqlite_discrete.conn_sqlite3
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@cf,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    def populate
+    end
+    def sql_maintenance_file
+      file=if @opt.act[:maintenance][:set]==:on
+        if @opt.fns and not @opt.fns.empty?
+          @env=SiSU_Env::InfoEnv.new(@opt.fns) if @opt.fns
+          if @sql_type ==:sqlite
+            puts "\n#{@env.processing_path.sqlite}/#{@opt.fns}.sql"
+          end
+          @db=SiSU_Env::InfoDb.new
+          @job="sqlite3 #{@db.sqlite.db} < #{@env.processing_path.sqlite}/#{@opt.fns}.sql"
+          if @sql_type ==:sqlite
+            File.new("#{@env.processing_path.sqlite}/#{@opt.fns}.sql",'w+')
+          else
+            File.new("#{@env.processing_path.postgresql}/#{@opt.fns}.sql",'w+')
+          end
+        elsif @opt.fns \
+        and @opt.fns.inspect =~/create/
+          nil #sort variations later
+        else nil
+        end
+      else nil
+      end
+      file
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* db_dbi.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/db_dbi.rb"
+# <<sisu_document_header>>
+module  SiSU_DbDBI
+  require_relative 'db_columns'                                             # db_columns.rb
+  require_relative 'db_tests'                                               # db_tests.rb
+  require_relative 'db_create'                                              # db_create.rb
+  require_relative 'db_select'                                              # db_select.rb
+  require_relative 'db_indexes'                                             # db_indexes.rb
+  require_relative 'db_drop'                                                # db_drop.rb
+  require_relative 'db_remove'                                              # db_remove.rb
+  require_relative 'db_load_tuple'                                          # db_load_tuple.rb
+  require_relative 'db_import'                                              # db_import.rb
+  class ColumnSize < SiSU_DbColumns::ColumnSize                             # db_columns.rb
+  end
+  class Test < SiSU_DbTests::Test                                           # db_tests.rb
+  end
+  class Create <SiSU_DbCreate::Create                                       # db_create.rb
+  end
+  class Case <SiSU_DbSelect::Case                                           # db_select.rb
+  end
+  class Index <SiSU_DbIndex::Index                                          # db_indexes.rb
+  end
+  class Drop <SiSU_DbDrop::Drop                                             # db_drop.rb
+  end
+  class Remove <SiSU_DbRemove::Remove                                       # db_remove.rb
+  end
+  class LoadDocuments <SiSU_DbTuple::LoadDocuments                          # db_load_tuple.rb
+  end
+  class LoadMetadata <SiSU_DbTuple::LoadMetadata                            # db_load_tuple.rb
+  end
+  class LoadUrls <SiSU_DbTuple::LoadUrls                                    # db_update urls
+  end
+  class Import <SiSU_DbImport::Import #<SiSU_DB::ColumnSize                 # db_import.rb
+  end
+end
+__END__
+#+END_SRC
+
+* db_sqltxt.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/db_sqltxt.rb"
+# <<sisu_document_header>>
+module SiSU_DbText
+  class Prepare
+    def special_character_escape(str)
+      str=str.to_s.gsub(/'/m,"''"). #string.gsub!(/'/,"\047") #string.gsub!(/'/,"\\'")
+        gsub(/(\\)/m,'\1\1'). #ok but with warnings, double backslash on sqlite #str.gsub!(/[\\]/m,'\\x5C') #ok but with warnings, but not for sqlite #str.gsub!(/(\\)/m,'\1') #ok for sqlite not for pgsql
+        gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/m,"<br>\n").
+        gsub(/#{Mx[:tag_o]}\S+?#{Mx[:tag_c]}/m,''). #check
+        gsub(/#{Mx[:lnk_o]}\s*(\S+?\.(?:png|jpg))(?:\s+\d+x\d+)?(.+?)#{Mx[:lnk_c]}\S+/m,'[image: \1] \2').
+        gsub(/#{Mx[:lnk_o]}\s*(.+?)\s*#{Mx[:lnk_c]}(?:file|ftp):\/\/\S+?([.,!?]?(?:\s|$))/m,'\1\2').
+        gsub(/#{Mx[:lnk_o]}\s*(.+?)\s*#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/m,'\1')
+    end
+    def clean_searchable_text_from_document_objects(arr)
+      en=[]
+      arr=(arr.is_a?(String)) ? [ arr ] : arr
+      txt_arr=arr.each.map do |s|
+        s=s.gsub(/#{Mx[:fa_o]}[a-z]{1,4}#{Mx[:fa_o_c]}/m,'').
+            gsub(/#{Mx[:fa_c_o]}[a-z]{1,4}#{Mx[:fa_c]}/m,'').
+            gsub(/<br>/m,' ')
+        en << s.scan(/#{Mx[:en_a_o]}\s*(.+?)\s*#{Mx[:en_a_c]}/m)
+        s=s.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}/m,'').
+          gsub(/#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/m,'').
+          gsub(/ \s+/m,' ')
+        #p s if s =~/[^ \nA-Za-z0-9'"`?!#@$%^&*=+,.;:\[\]()<>{}‹›|\\\/~_-]/
+        s
+      end
+      txt_arr=txt_arr << en
+      txt=txt_arr.flatten.join("\n")
+      special_character_escape(txt)
+    end
+    def clean_document_objects_body(arr)
+      en=[]
+      arr=(arr.is_a?(String)) ? [ arr ] : arr
+      txt_arr=arr.each.map do |s|
+        en << s.scan(/#{Mx[:en_a_o]}\s*(.+?)\s*#{Mx[:en_a_c]}/m)
+        s=s.
+          gsub(/#{Mx[:en_a_o]}\s*(\d+).+?#{Mx[:en_a_c]}/m,
+            '<sup>\1</sup>').
+          gsub(/#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/m,'').
+          gsub(/ \s+/m,' ')
+        s
+      end
+      en_arr=en.flatten.each.map do |e|
+        e.sub(/^(\d+)\s*/,'<sup>\1</sup> ')
+      end
+      txt_arr=txt_arr << en_arr
+      txt=txt_arr.flatten.join("\n<br>")
+      special_character_escape(txt)
+    end
+    def clean_searchable_text_from_document_source(arr)
+      txt_arr,en=[],[]
+      arr=(arr.is_a?(String)) ? arr.split(/\n+/m) : arr
+      arr.each do |s|
+        s=s.gsub(/([*\/_-])\{(.+?)\}\1/m,'\2').
+          gsub(/^(?:block|group|poem|code)\{/m,'').
+          gsub(/^\}(?:block|group|poem|code)/m,'').
+          gsub(/\A(?:@\S+:\s+.+)\Z/m,'')
+        if s =~/^:A~/
+          if defined? @md.creator \
+          and defined? @md.creator.author \
+          and not @md.creator.author.empty?
+            s=s.gsub(/@author/,@md.creator.author)
+          else
+            SiSU_Screen::Ansi.new(
+              'v',
+              'WARNING Document Author information missing; provide @creator: :author:',
+              @md.fnb
+            ).warn unless @md.opt.act[:quiet][:set]==:on
+          end
+          if defined? @md.title \
+          and defined? @md.title.full \
+          and not @md.title.full.empty?
+            s=s.gsub(/@title/,@md.title.full)
+          else
+            SiSU_Screen::Ansi.new(
+              'v',
+              'WARNING Document Title missing; provide @title:',
+              @md.fnb
+            ).warn unless @md.opt.act[:quiet][:set]==:on
+          end
+        end
+        s=s.gsub(/^(?:_[1-9]\*?|_\*)\s+/m,'').
+          gsub(/^(?:[1-9]\~(\S+)?)\s+/m,'').
+          gsub(/^(?::?[A-C]\~(\S+)?)\s+/m,'').
+          gsub(/^%{1,3} .+/m,''). #removed even if contained in code block
+          gsub(/<br>/m,' ')
+        #en << s.scan(/~\{\s*(.+?)\s*\}~/m)
+        s=s.gsub(/~\{.+?\}~/m,'').
+          gsub(/ \s+/m,' ')
+        ##special_character_escape(s)
+        #p s if s =~/[^ \nA-Za-z0-9'"`?!#@$%^&*=+,.;:\[\]()<>{}‹›|\\\/~_-]/
+        s
+      end
+      txt_arr << arr << en
+      txt=txt_arr.flatten.join("\n")
+      txt=special_character_escape(txt)
+      txt
+    end
+    def strip_markup(str) #define rules, make same as in dal clean
+      str=str.gsub(/#{Mx[:fa_superscript_o]}(\d+)#{Mx[:fa_superscript_c]}/,'[\1]').
+        gsub(/(?:&nbsp\\;|#{Mx[:nbsp]})+/,' ').
+        gsub(/#{Mx[:tc_o]}#{Mx[:tc_p]}#{Mx[:tc_p]}\d+(.+)#{Mx[:tc_c]}/u,'\1').         #tables
+        gsub(/#{Mx[:tc_p]}#{Mx[:tc_p]}\d+#{Mx[:tc_p]}/u,' ').                          #tables
+        gsub(/#{Mx[:tc_p]}/u,' ').                                                     #tables tidy later
+        gsub(/<.+?>/,'').
+        gsub(/#{Mx[:lnk_o]}.+?\.(?:png|jpg|gif).+?#{Mx[:lnk_c]}(?:file|ftp)\/\/:\S+ /,' [image] '). # else image names found in search
+        gsub(/#{Mx[:lnk_o]}.+?\.(?:png|jpg|gif).+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/,' [image]'). # else image names found in search
+        gsub(/\s\s+/,' ').
+        strip
+    end
+    def unique_words(str)
+      a=str.scan(/[a-zA-Z0-9\\\/_-]{2,}/) #a=str.scan(/\S+{2,}/)
+      str=a.uniq.sort.join(' ')
+      str
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* create drop import remove
+** db_create.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/db_create.rb"
+# <<sisu_document_header>>
+module SiSU_DbCreate
+  require_relative 'db_columns'                         # db_columns.rb
+  class Create < SiSU_DbColumns::Columns
+    require_relative 'se'                               # se.rb
+    @@dl=nil
+    def initialize(opt,conn,file,sql_type=:pg)
+      @opt,@conn,@file,@sql_type=opt,conn,file,sql_type
+      @cX=SiSU_Screen::Ansi.new(@opt.act[:color_state][:set]).cX
+      @comment=(@sql_type==:pg) \
+      ? (SiSU_DbCreate::Comment.new(@conn,@sql_type))
+      : nil
+      @@dl ||=SiSU_Env::InfoEnv.new.digest.length
+    end
+    def available
+      DBI.available_drivers.each do |driver|
+        puts "Driver: #{driver}"
+        DBI.data_sources(driver).each do |dsn|
+          puts "\tDatasource: #{dsn}"
+        end
+      end
+    end
+    def create_db
+      @env=SiSU_Env::InfoEnv.new(@opt.fns)
+      tell=(@sql_type==:sqlite) \
+      ? SiSU_Screen::Ansi.new(
+          @opt.act[:color_state][:set],
+          'Create SQLite db tables in:',
+          %{"#{@file}"}
+        )
+      : SiSU_Screen::Ansi.new(
+          @opt.act[:color_state][:set],
+          'Create pgSQL db tables in:',
+          %{"#{Db[:name_prefix]}#{@env.path.base_markup_dir_stub}"}
+        )
+      if (@opt.act[:verbose][:set]==:on \
+      || @opt.act[:verbose_plus][:set]==:on \
+      || @opt.act[:maintenance][:set]==:on)
+        tell.dark_grey_title_hi
+      end
+      SiSU_Env::SystemCall.new.create_pg_db(@env.path.base_markup_dir_stub) if @sql_type==:pg #watch use of path.base_markup_dir_stub instead of stub
+    end
+    def output_dir?
+      dir=SiSU_Env::InfoEnv.new('')
+      if @opt.act[:sqlite][:set]==:on
+        dir.path.webserv_stub_ensure
+      end
+    end
+    def create_table
+      def conn_exec(sql)
+        if @sql_type==:pg
+          conn_exec_pg(sql)
+        elsif @sql_type==:sqlite
+          conn_exec_sqlite(sql)
+        end
+      end
+      def conn_exec_pg(sql)
+        begin
+          @conn.exec_params(sql)
+        rescue
+          if @conn.is_a?(NilClass)
+            errmsg="No pg connection (check pg dependencies)"
+            if @opt.act[:no_stop][:set]==:on
+              SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+                error("#{errmsg}, proceeding without pg output (as requested)")
+            else
+              SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+                error("#{errmsg}, STOPPING")
+              exit
+            end
+          end
+        end
+      end
+      def conn_exec_sqlite(sql)
+        begin
+          @conn.execute(sql)
+        rescue
+          if @conn.is_a?(NilClass)
+            errmsg="No sqlite3 connection (check sqlite3 dependencies)"
+            if @opt.act[:no_stop][:set]==:on
+              SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+                error("#{errmsg}, proceeding without sqlite output (as requested)")
+            else
+              SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+                error("#{errmsg}, STOPPING")
+              exit
+            end
+          end
+        end
+      end
+      def metadata_and_text
+        if (@opt.act[:verbose_plus][:set]==:on \
+        or @opt.act[:maintenance][:set]==:on)
+          print %{
+          currently using sisu_dbi module
+          to be populated from document files
+          create tables metadata_and_text
+          data import through ruby transfer
+          }
+        end
+        create_metadata_and_text=%{
+          CREATE TABLE metadata_and_text (
+            tid                  BIGINT PRIMARY KEY,
+            /* title */
+            #{column.title.create_column}
+            #{column.title_main.create_column}
+            #{column.title_sub.create_column}
+            #{column.title_short.create_column}
+            #{column.title_edition.create_column}
+            #{column.title_note.create_column}
+            #{column.title_language.create_column}
+            #{column.title_language_char.create_column}
+            /* creator */
+            #{column.creator_author.create_column}
+            #{column.creator_author_honorific.create_column}
+            #{column.creator_author_nationality.create_column}
+            #{column.creator_editor.create_column}
+            #{column.creator_contributor.create_column}
+            #{column.creator_illustrator.create_column}
+            #{column.creator_photographer.create_column}
+            #{column.creator_translator.create_column}
+            #{column.creator_prepared_by.create_column}
+            #{column.creator_digitized_by.create_column}
+            #{column.creator_audio.create_column}
+            #{column.creator_video.create_column}
+            /* language */
+            #{column.language_document.create_column}
+            #{column.language_document_char.create_column}
+            #{column.language_original.create_column}
+            #{column.language_original_char.create_column}
+            /* date */
+            #{column.date_added_to_site.create_column}
+            #{column.date_available.create_column}
+            #{column.date_created.create_column}
+            #{column.date_issued.create_column}
+            #{column.date_modified.create_column}
+            #{column.date_published.create_column}
+            #{column.date_valid.create_column}
+            #{column.date_translated.create_column}
+            #{column.date_original_publication.create_column}
+            #{column.date_generated.create_column}
+            /* publisher */
+            #{column.publisher.create_column}
+            /* original */
+            #{column.original_publisher.create_column}
+            #{column.original_language.create_column}
+            #{column.original_language_char.create_column}
+            #{column.original_source.create_column}
+            #{column.original_institution.create_column}
+            #{column.original_nationality.create_column}
+            /* rights */
+            #{column.rights_all.create_column}
+            #{column.rights_copyright_text.create_column}
+            #{column.rights_copyright_translation.create_column}
+            #{column.rights_copyright_illustrations.create_column}
+            #{column.rights_copyright_photographs.create_column}
+            #{column.rights_copyright_preparation.create_column}
+            #{column.rights_copyright_digitization.create_column}
+            #{column.rights_copyright_audio.create_column}
+            #{column.rights_copyright_video.create_column}
+            #{column.rights_license.create_column}
+            /* classify */
+            #{column.classify_topic_register.create_column}
+            #{column.classify_subject.create_column}
+            #{column.classify_loc.create_column}
+            #{column.classify_dewey.create_column}
+            #{column.classify_keywords.create_column}
+            /* identifier */
+            #{column.identifier_oclc.create_column}
+            #{column.identifier_isbn.create_column}
+            /* notes */
+            #{column.notes_abstract.create_column}
+            #{column.notes_description.create_column}
+            #{column.notes_comment.create_column}
+            #{column.notes_history.create_column}
+            #{column.notes_coverage.create_column}
+            #{column.notes_relation.create_column}
+            /* column.notes_source.create_column */
+            #{column.notes_type.create_column}
+            #{column.notes_format.create_column}
+            #{column.notes_prefix.create_column}
+            #{column.notes_prefix_a.create_column}
+            #{column.notes_prefix_b.create_column}
+            #{column.notes_suffix.create_column}
+            /* src */
+            #{column.src_filename.create_column}
+            #{column.src_fingerprint.create_column}
+            #{column.src_filesize.create_column}
+            #{column.src_word_count.create_column}
+            #{column.src_txt.create_column}
+            /* misc */
+            #{column.fulltext.create_column}
+            #{column.links.create_column.gsub(/,$/,'')}
+/*          subj                 VARCHAR(64) NULL, */
+/*          contact              VARCHAR(100) NULL, */
+/*          information          VARCHAR(100) NULL, */
+/*          types                CHAR(1) NULL, */
+/*          writing_focus_nationality VARCHAR(100) NULL, */
+          );
+        }
+        conn_exec(create_metadata_and_text)
+        @comment.psql.metadata_and_text if @comment
+      end
+      def doc_objects                                                 # create doc_objects base
+        if (@opt.act[:verbose_plus][:set]==:on \
+        or @opt.act[:maintenance][:set]==:on)
+          print %{
+          to be populated from documents files
+          create tables doc_objects
+          data import through ruby transfer
+          }
+        end
+        create_doc_objects=%{
+          CREATE TABLE doc_objects (
+            lid             BIGINT PRIMARY KEY,
+            metadata_tid    BIGINT REFERENCES metadata_and_text,
+            ocn             SMALLINT,
+            ocnd            VARCHAR(6),
+            ocns            VARCHAR(6),
+            clean           TEXT NULL,
+            body            TEXT NULL,
+            book_idx        TEXT NULL,
+            seg             VARCHAR(256) NULL,
+            lev_an          VARCHAR(1),
+            lev             SMALLINT NULL,
+            lev0            SMALLINT,
+            lev1            SMALLINT,
+            lev2            SMALLINT,
+            lev3            SMALLINT,
+            lev4            SMALLINT,
+            lev5            SMALLINT,
+            lev6            SMALLINT,
+            lev7            SMALLINT,
+            en_a            SMALLINT NULL,
+            en_z            SMALLINT NULL,
+            en_a_asterisk   SMALLINT NULL,
+            en_z_asterisk   SMALLINT NULL,
+            en_a_plus       SMALLINT NULL,
+            en_z_plus       SMALLINT NULL,
+            t_of            VARCHAR(16),
+            t_is            VARCHAR(16),
+            node            VARCHAR(16) NULL,
+            parent          VARCHAR(16) NULL,
+            digest_clean    CHAR(#{@@dl}),
+            digest_all      CHAR(#{@@dl}),
+            types           CHAR(1) NULL
+          );
+        }
+        conn_exec(create_doc_objects)
+        @comment.psql.doc_objects if @comment
+      end
+      def endnotes
+        if (@opt.act[:verbose_plus][:set]==:on \
+        or @opt.act[:maintenance][:set]==:on)
+          print %{
+          to be populated from document files
+          create tables endnotes
+          data import through ruby transfer
+          }
+        end
+        create_endnotes=%{
+          CREATE TABLE endnotes (
+            nid             BIGINT PRIMARY KEY,
+            document_lid    BIGINT REFERENCES doc_objects,
+            nr              SMALLINT,
+            clean           TEXT NULL,
+            body            TEXT NULL,
+            ocn             SMALLINT,
+            ocnd            VARCHAR(6),
+            ocns            VARCHAR(6),
+            digest_clean    CHAR(#{@@dl}),
+            metadata_tid    BIGINT REFERENCES metadata_and_text
+          );
+        }
+        conn_exec(create_endnotes)
+        @comment.psql.endnotes if @comment
+      end
+      def endnotes_asterisk
+        if (@opt.act[:verbose_plus][:set]==:on \
+        or @opt.act[:maintenance][:set]==:on)
+          print %{
+          to be populated from document files
+          create tables endnotes_asterisk
+          data import through ruby transfer
+          }
+        end
+        create_endnotes_asterisk=%{
+          CREATE TABLE endnotes_asterisk (
+            nid             BIGINT PRIMARY KEY,
+            document_lid    BIGINT REFERENCES doc_objects,
+            nr              SMALLINT,
+            clean           TEXT NULL,
+            body            TEXT NULL,
+            ocn             SMALLINT,
+            ocnd            VARCHAR(6),
+            ocns            VARCHAR(6),
+            digest_clean    CHAR(#{@@dl}),
+            metadata_tid    BIGINT REFERENCES metadata_and_text
+          );
+        }
+        conn_exec(create_endnotes_asterisk)
+        @comment.psql.endnotes_asterisk if @comment
+      end
+      def endnotes_plus
+        if (@opt.act[:verbose_plus][:set]==:on \
+        or @opt.act[:maintenance][:set]==:on)
+          print %{
+          to be populated from document files
+          create tables endnotes_plus
+          data import through ruby transfer
+          }
+        end
+        create_endnotes_plus=%{
+          CREATE TABLE endnotes_plus (
+            nid             BIGINT PRIMARY KEY,
+            document_lid    BIGINT REFERENCES doc_objects,
+            nr              SMALLINT,
+            clean           TEXT NULL,
+            body            TEXT NULL,
+            ocn             SMALLINT,
+            ocnd            VARCHAR(6),
+            ocns            VARCHAR(6),
+            digest_clean    CHAR(#{@@dl}),
+            metadata_tid    BIGINT REFERENCES metadata_and_text
+          );
+        }
+        conn_exec(create_endnotes_plus)
+        @comment.psql.endnotes_plus if @comment
+      end
+      def urls                                                       # create doc_objects file links mapping
+        if (@opt.act[:verbose_plus][:set]==:on \
+        or @opt.act[:maintenance][:set]==:on)
+          print %{
+          currently using sisu_dbi module
+          to be populated from doc_objects files
+          create tables urls
+          data import through ruby transfer
+          }
+        end
+        create_urls=%{
+          CREATE TABLE urls (
+            metadata_tid    BIGINT REFERENCES metadata_and_text,
+            plaintext       varchar(512),
+            html_toc        varchar(512),
+            html_doc        varchar(512),
+            xhtml           varchar(512),
+            xml_sax         varchar(512),
+            xml_dom         varchar(512),
+            odf             varchar(512),
+            pdf_p           varchar(512),
+            pdf_l           varchar(512),
+            concordance     varchar(512),
+            latex_p         varchar(512),
+            latex_l         varchar(512),
+            digest          varchar(512),
+            manifest        varchar(512),
+            markup          varchar(512),
+            sisupod         varchar(512)
+          );
+        }
+        conn_exec(create_urls)
+        @comment.psql.urls if @comment
+      end
+      self
+    end
+  end
+  class Comment < SiSU_DbColumns::Columns
+    def initialize(conn,sql_type=:pg)
+      @conn=conn
+      if sql_type == :pg then psql
+      end
+    end
+    def psql
+      def conn_execute_array(sql_arr)
+        @conn.transaction do |conn|
+          sql_arr.each do |sql|
+            conn.exec_params(sql)
+          end
+        end
+      end
+      def metadata_and_text
+        sql_arr=[
+          %{COMMENT ON Table metadata_and_text
+            IS 'contains SiSU metadata and fulltext for search (including source .sst if shared)';},
+          %{COMMENT ON COLUMN metadata_and_text.tid
+            IS 'unique';},
+          %{#{column.title.column_comment}},
+          %{#{column.title_main.column_comment}},
+          %{#{column.title_sub.column_comment}},
+          %{#{column.title_short.column_comment}},
+          %{#{column.title_edition.column_comment}},
+          %{#{column.title_note.column_comment}},
+          %{#{column.title_language.column_comment}},
+          %{#{column.title_language_char.column_comment}},
+          %{#{column.creator_author.column_comment}},
+          %{#{column.creator_author_honorific.column_comment}},
+          %{#{column.creator_author_nationality.column_comment}},
+          %{#{column.creator_editor.column_comment}},
+          %{#{column.creator_contributor.column_comment}},
+          %{#{column.creator_illustrator.column_comment}},
+          %{#{column.creator_photographer.column_comment}},
+          %{#{column.creator_translator.column_comment}},
+          %{#{column.creator_prepared_by.column_comment}},
+          %{#{column.creator_digitized_by.column_comment}},
+          %{#{column.creator_audio.column_comment}},
+          %{#{column.creator_video.column_comment}},
+          %{#{column.language_document.column_comment}},
+          %{#{column.language_document_char.column_comment}},
+          %{#{column.language_original.column_comment}},
+          %{#{column.language_original_char.column_comment}},
+          %{#{column.date_added_to_site.column_comment}},
+          %{#{column.date_available.column_comment}},
+          %{#{column.date_created.column_comment}},
+          %{#{column.date_issued.column_comment}},
+          %{#{column.date_modified.column_comment}},
+          %{#{column.date_published.column_comment}},
+          %{#{column.date_valid.column_comment}},
+          %{#{column.date_translated.column_comment}},
+          %{#{column.date_original_publication.column_comment}},
+          %{#{column.date_generated.column_comment}},
+          %{#{column.publisher.column_comment}},
+          %{#{column.original_publisher.column_comment}},
+          %{#{column.original_language.column_comment}},
+          %{#{column.original_language_char.column_comment}},
+          %{#{column.original_source.column_comment}},
+          %{#{column.original_institution.column_comment}},
+          %{#{column.original_nationality.column_comment}},
+          %{#{column.rights_all.column_comment}},
+          %{#{column.rights_copyright_text.column_comment}},
+          %{#{column.rights_copyright_translation.column_comment}},
+          %{#{column.rights_copyright_illustrations.column_comment}},
+          %{#{column.rights_copyright_photographs.column_comment}},
+          %{#{column.rights_copyright_preparation.column_comment}},
+          %{#{column.rights_copyright_digitization.column_comment}},
+          %{#{column.rights_copyright_audio.column_comment}},
+          %{#{column.rights_copyright_video.column_comment}},
+          %{#{column.rights_license.column_comment}},
+          %{#{column.classify_topic_register.column_comment}},
+          %{#{column.classify_subject.column_comment}},
+          %{#{column.classify_loc.column_comment}},
+          %{#{column.classify_dewey.column_comment}},
+          %{#{column.classify_keywords.column_comment}},
+          %{#{column.identifier_oclc.column_comment}},
+          %{#{column.identifier_isbn.column_comment}},
+          %{#{column.notes_abstract.column_comment}},
+          %{#{column.notes_comment.column_comment}},
+          %{#{column.notes_description.column_comment}},
+          %{#{column.notes_history.column_comment}},
+          %{#{column.notes_coverage.column_comment}},
+          %{#{column.notes_relation.column_comment}},
+          %{#{column.notes_type.column_comment}},
+          %{#{column.notes_format.column_comment}},
+          %{#{column.notes_prefix.column_comment}},
+          %{#{column.notes_prefix_a.column_comment}},
+          %{#{column.notes_prefix_b.column_comment}},
+          %{#{column.notes_suffix.column_comment}},
+          %{#{column.src_filename.column_comment}},
+          %{#{column.src_fingerprint.column_comment}},
+          %{#{column.src_filesize.column_comment}},
+          %{#{column.src_word_count.column_comment}},
+          %{#{column.src_txt.column_comment}},
+          %{#{column.fulltext.column_comment}},
+          %{#{column.links.column_comment}},
+        ]
+        conn_execute_array(sql_arr)
+      end
+      def doc_objects
+        sql_arr=[
+          %{COMMENT ON Table doc_objects
+            IS 'contains searchable text of SiSU document objects';},
+          %{COMMENT ON COLUMN doc_objects.lid
+            IS 'unique';},
+          %{COMMENT ON COLUMN doc_objects.metadata_tid
+            IS 'tie to title in metadata_and_text';},
+          %{COMMENT ON COLUMN doc_objects.lev_an
+            IS 'doc level A-D 1-4';},
+          %{COMMENT ON COLUMN doc_objects.lev
+            IS 'doc level 0-7 \d\~';},
+          %{COMMENT ON COLUMN doc_objects.seg
+            IS 'segment name from level number 4 (lv 1)';},
+          %{COMMENT ON COLUMN doc_objects.ocn
+            IS 'object citation number';},
+          %{COMMENT ON COLUMN doc_objects.en_a
+            IS 'first endnote number in text object (eg. NULL or 34) (used with en_z to create range)';},
+          %{COMMENT ON COLUMN doc_objects.en_z
+            IS 'last endnote number within text object (eg. NULL, 34 or say 47) (used with en_a to create range)';},
+          %{COMMENT ON COLUMN doc_objects.en_a_asterisk
+            IS 'first endnote number in text object (eg. NULL or 34) (used with en_z_asterisk to create range)';},
+          %{COMMENT ON COLUMN doc_objects.en_z_asterisk
+            IS 'last endnote number within text object (eg. NULL, 34 or say 47) (used with en_a_asterisk to create range)';},
+          %{COMMENT ON COLUMN doc_objects.en_a_plus
+            IS 'first endnote number in text object (eg. NULL or 34) (used with en_z_plus to create range)';},
+          %{COMMENT ON COLUMN doc_objects.en_z_plus
+            IS 'last endnote number within text object (eg. NULL, 34 or say 47) (used with en_a_plus to create range)';},
+          %{COMMENT ON COLUMN doc_objects.types
+            IS 'document types seg scroll';},
+          %{COMMENT ON COLUMN doc_objects.clean
+            IS 'text object - substantive text: clean, stripped of markup';},
+          %{COMMENT ON COLUMN doc_objects.body
+            IS 'text object - substantive text: light html markup';},
+          %{COMMENT ON COLUMN doc_objects.book_idx
+            IS 'book index creation information for paragraph, if provided';},
+          %{COMMENT ON COLUMN doc_objects.lev0
+            IS 'document structure, level number 0';},
+          %{COMMENT ON COLUMN doc_objects.lev1
+            IS 'document structure, level number 1';},
+          %{COMMENT ON COLUMN doc_objects.lev2
+            IS 'document structure, level number 2';},
+          %{COMMENT ON COLUMN doc_objects.lev3
+            IS 'document structure, level number 3';},
+          %{COMMENT ON COLUMN doc_objects.lev4
+            IS 'document structure, level number 4';},
+          %{COMMENT ON COLUMN doc_objects.lev5
+            IS 'document structure, level number 5';},
+          %{COMMENT ON COLUMN doc_objects.lev6
+            IS 'document structure, level number 6';},
+          %{COMMENT ON COLUMN doc_objects.lev7
+            IS 'document structure, level number 7';},
+          %{COMMENT ON COLUMN doc_objects.t_of
+            IS 'document structure, type of object (object is of)';},
+          %{COMMENT ON COLUMN doc_objects.t_is
+            IS 'document structure, object is';},
+          %{COMMENT ON COLUMN doc_objects.node
+            IS 'document structure, object node if heading';},
+          %{COMMENT ON COLUMN doc_objects.parent
+            IS 'document structure, object parent (is a heading)';}
+        ]
+        conn_execute_array(sql_arr)
+      end
+      def endnotes
+        sql_arr=[
+          %{COMMENT ON Table endnotes
+            IS 'contains searchable text of SiSU documents endnotes';},
+          %{COMMENT ON COLUMN endnotes.nid
+            IS 'unique';},
+          %{COMMENT ON COLUMN endnotes.document_lid
+            IS 'ties to text block from which referenced';},
+          %{COMMENT ON COLUMN endnotes.nr
+            IS 'endnote number <!e_(\d+)!>';},
+          %{COMMENT ON COLUMN endnotes.clean
+            IS 'endnote substantive content, stripped of markup';},
+          %{COMMENT ON COLUMN endnotes.body
+            IS 'endnote substantive content';},
+          %{COMMENT ON COLUMN endnotes.ocn
+            IS 'object citation no# <\~(\d+)> from which endnote is referenced';},
+          %{COMMENT ON COLUMN doc_objects.metadata_tid
+            IS 'tie to title in metadata_and_text - unique for each document';}
+        ]
+        conn_execute_array(sql_arr)
+      end
+      def endnotes_asterisk
+        sql_arr=[
+          %{COMMENT ON Table endnotes_asterisk
+            IS 'contains searchable text of SiSU documents endnotes marked with asterisk';},
+          %{COMMENT ON COLUMN endnotes_asterisk.nid
+            IS 'unique';},
+          %{COMMENT ON COLUMN endnotes_asterisk.document_lid
+            IS 'ties to text block from which referenced';},
+          %{COMMENT ON COLUMN endnotes_asterisk.nr
+            IS 'endnote number <!e_(\d+)!>';},
+          %{COMMENT ON COLUMN endnotes_asterisk.clean
+            IS 'endnote substantive content, stripped of markup';},
+          %{COMMENT ON COLUMN endnotes_asterisk.body
+            IS 'endnote substantive content';},
+          %{COMMENT ON COLUMN endnotes_asterisk.ocn
+            IS 'object citation no# <\~(\d+)> from which endnote is referenced';},
+          %{COMMENT ON COLUMN doc_objects.metadata_tid
+            IS 'tie to title in metadata_and_text - unique for each document';}
+        ]
+        conn_execute_array(sql_arr)
+      end
+      def endnotes_plus
+        sql_arr=[
+          %{COMMENT ON Table endnotes_plus
+            IS 'contains searchable text of SiSU documents endnotes marked with plus';},
+          %{COMMENT ON COLUMN endnotes_plus.nid
+            IS 'unique';},
+          %{COMMENT ON COLUMN endnotes_plus.document_lid
+            IS 'ties to text block from which referenced';},
+          %{COMMENT ON COLUMN endnotes_plus.nr
+            IS 'endnote number <!e_(\d+)!>';},
+          %{COMMENT ON COLUMN endnotes_plus.clean
+            IS 'endnote substantive content, stripped of markup';},
+          %{COMMENT ON COLUMN endnotes_plus.body
+            IS 'endnote substantive content';},
+          %{COMMENT ON COLUMN endnotes_plus.ocn
+            IS 'object citation no# <\~(\d+)> from which endnote is referenced';},
+          %{COMMENT ON COLUMN doc_objects.metadata_tid
+            IS 'tie to title in metadata_and_text - unique for each document';},
+        ]
+        conn_execute_array(sql_arr)
+      end
+      def urls
+        sql_arr=[
+          %{COMMENT ON Table urls
+            IS 'contains base url links to different SiSU output';},
+          %{COMMENT ON COLUMN doc_objects.metadata_tid
+            IS 'tie to title in metadata_and_text - unique for each document, the mapping of rows is one to one';},
+          %{COMMENT ON COLUMN urls.plaintext
+            IS 'plaintext utf-8';},
+          %{COMMENT ON COLUMN urls.html_toc
+            IS 'table of contents for segmented html document';},
+          %{COMMENT ON COLUMN urls.html_doc
+            IS 'html document (scroll)';},
+          %{COMMENT ON COLUMN urls.xhtml
+            IS 'xhtml document (scroll)';},
+          %{COMMENT ON COLUMN urls.xml_sax
+            IS 'xml sax oriented document (scroll)';},
+          %{COMMENT ON COLUMN urls.xml_dom
+            IS 'xml dom oriented document (scroll)';},
+          %{COMMENT ON COLUMN urls.odf
+            IS 'opendocument format text';},
+          %{COMMENT ON COLUMN urls.pdf_p
+            IS 'pdf portrait';},
+          %{COMMENT ON COLUMN urls.pdf_l
+            IS 'pdf landscape';},
+          %{COMMENT ON COLUMN urls.concordance
+            IS 'rudimentary document index linked to html';},
+          %{COMMENT ON COLUMN urls.latex_p
+            IS 'latex portrait';},
+          %{COMMENT ON COLUMN urls.latex_l
+            IS 'latex_landscape';},
+          %{COMMENT ON COLUMN urls.markup
+            IS 'markup';},
+          %{COMMENT ON COLUMN urls.sisupod
+            IS 'SiSU document format .tgz (all SiSU information on document)';},
+        ]
+        conn_execute_array(sql_arr)
+      end
+      self
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** db_drop.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/db_drop.rb"
+# <<sisu_document_header>>
+module SiSU_DbDrop
+  require_relative 'utils_response'                   # utils_response.rb
+  class Drop
+    include SiSU_Response
+    def initialize(opt,conn,db_info,sql_type)
+      @opt,@conn,@db_info,@sql_type=opt,conn,db_info,sql_type
+      case @sql_type
+      when :sqlite
+        cascade=''
+      else
+        cascade='CASCADE'
+      end
+      @drop_table=[
+        "DROP TABLE metadata_and_text #{cascade};",
+        "DROP TABLE doc_objects #{cascade};",
+        "DROP TABLE urls #{cascade};",
+        "DROP TABLE endnotes #{cascade};",
+        "DROP TABLE endnotes_asterisk #{cascade};",
+        "DROP TABLE endnotes_plus #{cascade};",
+      ]
+    end
+    def drop
+      def tables                                                              #% drop all tables
+        begin
+          msg_sqlite="as not all disk space is recovered after dropping the database << #{@db_info.sqlite.db} >>, you may be better off deleting the file, and recreating it as necessary"
+          case @sql_type
+          when :sqlite
+            puts msg_sqlite
+            ans=response?('remove sql database?')
+            if ans \
+            and File.exist?(@db_info.sqlite.db)
+              @conn.close
+              File.unlink(@db_info.sqlite.db)
+              db=SiSU_Env::InfoDb.new
+              conn=db.sqlite.conn_sqlite3
+              sdb=SiSU_DbDBI::Create.new(@opt,conn,@db_info,@sql_type)
+              sdb_index=SiSU_DbDBI::Index.new(@opt,conn,@db_info,@sql_type)
+              sdb.output_dir?
+              begin
+                sdb.create_db
+                sdb.create_table.metadata_and_text
+                sdb.create_table.doc_objects
+                sdb.create_table.endnotes
+                sdb.create_table.endnotes_asterisk
+                sdb.create_table.endnotes_plus
+                sdb.create_table.urls
+                sdb_index.create_indexes
+              rescue
+                SiSU_Errors::Rescued.new($!,$@,'-D').location do
+                  __LINE__.to_s + ':' + __FILE__
+                end
+                sdb.output_dir?
+              end
+              exit
+            else
+              @conn.transaction
+              @drop_table.each do |d|
+                begin
+                  @conn.exec_params(d)
+                rescue
+                  next
+                end
+                end
+              @conn.commit
+            end
+          when :pg
+            @conn.transaction
+            @drop_table.each do |d|
+              begin
+                @conn.exec_params(d)
+              rescue
+                next
+              end
+            end
+            @conn.commit
+          end
+        rescue
+          case @sql_type
+          when :sqlite
+            ans=response?('remove sql database?')
+            if ans and File.exist?(@db_info.sqlite.db); File.unlink(@db_info.sqlite.db)
+            end
+          else
+            @drop_table.each do |d|
+              begin
+                @conn.exec_params(d)
+              rescue
+                next
+              end
+            end
+          end
+        ensure
+        end
+      end
+      def indexes
+        def conn_execute_array(sql_arr)
+          @conn.transaction do |conn|
+            sql_arr.each do |sql|
+              begin
+                conn.exec_params(sql)
+              rescue
+                next
+              end
+            end
+          end
+        end
+        def base                                                             #% drop base indexes
+          print "\n          drop documents common indexes\n" unless @opt.act[:quiet][:set]==:on
+          sql_arr=[
+            %{DROP INDEX idx_title;},
+            %{DROP INDEX idx_author;},
+            %{DROP INDEX idx_filename;},
+            %{DROP INDEX idx_topics;},
+            %{DROP INDEX idx_ocn;},
+            %{DROP INDEX idx_digest_clean;},
+            %{DROP INDEX idx_digest_all;},
+            %{DROP INDEX idx_lev0;},
+            %{DROP INDEX idx_lev1;},
+            %{DROP INDEX idx_lev2;},
+            %{DROP INDEX idx_lev3;},
+            %{DROP INDEX idx_lev4;},
+            %{DROP INDEX idx_lev5;},
+            %{DROP INDEX idx_lev6;},
+            %{DROP INDEX idx_endnote_nr;},
+            %{DROP INDEX idx_digest_en;},
+            %{DROP INDEX idx_endnote_nr_asterisk;},
+            %{DROP INDEX idx_endnote_asterisk;},
+            %{DROP INDEX idx_digest_en_asterisk;},
+            %{DROP INDEX idx_endnote_nr_plus;},
+            %{DROP INDEX idx_endnote_plus;},
+            %{DROP INDEX idx_digest_en_plus},
+          ]
+          conn_execute_array(sql_arr)
+        end
+        def text                                                             #% drop TEXT indexes, sqlite
+          print "\n          drop documents TEXT indexes\n" unless @opt.act[:quiet][:set]==:on
+          sql_arr=[
+            %{DROP INDEX idx_clean;},
+            %{DROP INDEX idx_endnote},
+          ]
+          conn_execute_array(sql_arr)
+        end
+        self
+      end
+      indexes.base
+      @opt.act[:psql][:set]==:on ? '' : indexes.text
+      self
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** db_import.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/db_import.rb"
+# <<sisu_document_header>>
+module SiSU_DbImport
+  require_relative 'db_columns'                         # db_columns.rb
+  require_relative 'db_load_tuple'                      # db_load_tuple.rb
+  require_relative 'db_sqltxt'                          # db_sqltxt.rb
+  require_relative 'html_lite_shared'                   # html_lite_shared.rb
+  class Import < SiSU_DbText::Prepare
+    include SiSU_Param
+    include SiSU_Screen
+    include SiSU_DbAction
+    @@dl=nil
+    @@hname=nil
+    attr_accessor :tp
+    def initialize(opt,conn,file_maint,sql_type=:pg)
+      @opt,@conn,@file_maint,@sql_type=opt,conn,file_maint,sql_type
+      @cX=SiSU_Screen::Ansi.new(@opt.act[:color_state][:set]).cX
+      @env=SiSU_Env::InfoEnv.new(@opt.fns)
+      @dal="#{@env.processing_path.ao}"
+      @fnb=if @opt.fns.empty? \
+      or @opt.selections.str.empty?
+        ''
+      else
+        @md=SiSU_Param::Parameters.new(@opt).get
+        @md.fnb
+      end
+      @fnc="#{@dal}/#{@opt.fns}.content.rbm"
+      @@seg,@@seg_full='',''                                  #create? consider placing field just before clean text as opposed to seg which contains seg(.html) name info seg_full would contain seg info for levels 5 & 6 where available eg seg_full may be 7.3 (level 5) and 7.3.1 (level 6) where seg  is 7
+      @col=Hash.new('')
+      @col[:ocn]=''
+      @counter={}
+      @db=SiSU_Env::InfoDb.new
+      if @sql_type==:sqlite
+        @driver_sqlite3=
+        (@conn.inspect.match(/^(.{10})/)[1] \
+        == @db.sqlite.conn_sqlite3.inspect.match(/^(.{10})/)[1]) \
+        ? true
+        : false
+      end
+      sql='SELECT MAX(lid) FROM doc_objects'
+      begin
+        @col[:lid] ||=0
+        @col[:lid]=@driver_sqlite3 \
+        ? @conn.execute( sql ).join.to_i
+        : @conn.exec( sql ).getvalue(0,0).to_i
+      rescue
+        if @opt.act[:maintenance][:set]==:on
+          puts "#{__FILE__}:#{__LINE__}"
+        end
+      end
+      @col[:lid]=0 if @col[:lid].nil? or @col[:lid].to_s.empty?
+      sql='SELECT MAX(nid) FROM endnotes'
+      begin
+        @id_n=@driver_sqlite3 \
+        ? @conn.execute( sql ).join.to_i
+        : @conn.exec( sql ).getvalue(0,0).to_i
+        @id_n ||=0
+      rescue
+        if @opt.act[:maintenance][:set]==:on
+          puts "#{__FILE__}:#{__LINE__}"
+        end
+      end
+      @id_n =0 if @col[:lid].nil? or @col[:lid].to_s.empty?
+      @col[:lv0]=@col[:lv1]=@col[:lv2]=@col[:lv3]=@col[:lv4]=@col[:lv5]=@col[:lv6]=@col[:lv7]=0
+      @db=SiSU_Env::InfoDb.new
+      @pdf_fn=SiSU_Env::FileOp.new(@md).base_filename
+      @@dl ||=SiSU_Env::InfoEnv.new.digest.length
+    end
+    def marshal_load
+      require_relative 'ao'                               # ao.rb
+      @ao_array=SiSU_AO::Source.new(@opt).get             # ao file drawn here
+      if (@opt.act[:verbose][:set]==:on \
+      || @opt.act[:verbose_plus][:set]==:on \
+      || @opt.act[:maintenance][:set]==:on)
+        SiSU_Screen::Ansi.new(
+          @opt.act[:color_state][:set],
+          "#{@db.psql.db}::#{@opt.fns}"
+        ).puts_blue
+      end
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        'Marshal Load',
+        @fnc
+      ).puts_grey if @opt.act[:verbose][:set]==:on
+      select_first_match=%{
+        SELECT metadata_and_text.tid
+        FROM metadata_and_text
+        WHERE metadata_and_text.src_filename = '#{@md.fns}'
+        AND metadata_and_text.language_document_char = '#{@opt.lng}'
+      ;} # note, for .ssm: @md.fns (is set during runtime & is) != @opt.fns @md.opt.fns
+      file_exist=if @sql_type==:sqlite
+        begin
+          @conn.get_first_value(select_first_match)
+        rescue SQLite3::Exception => e
+          # not tested
+          puts "Exception occurred"
+          puts e
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).mark(
+            "\n" \
+            + 'Attempting to initialize db' + "\n" \
+            + 'Creating db tables'
+          )
+          sdb={
+            create: SiSU_DbDBI::Create.new(@opt,@conn,@file_maint,@sql_type),
+            index: SiSU_DbDBI::Index.new(@opt,@conn,@file_maint,@sql_type),
+          }
+          db_action(sdb).create
+        end
+      else
+        begin
+          @conn.exec(select_first_match).field_values("tid")[0]
+        rescue PG::Error => e
+          err=[
+            e.result.error_field( PG::Result::PG_DIAG_SEVERITY ),
+            e.result.error_field( PG::Result::PG_DIAG_SQLSTATE ),
+            e.result.error_field( PG::Result::PG_DIAG_MESSAGE_PRIMARY ),
+            e.result.error_field( PG::Result::PG_DIAG_MESSAGE_DETAIL ),
+            e.result.error_field( PG::Result::PG_DIAG_MESSAGE_HINT ),
+            e.result.error_field( PG::Result::PG_DIAG_STATEMENT_POSITION ),
+            e.result.error_field( PG::Result::PG_DIAG_INTERNAL_POSITION ),
+            e.result.error_field( PG::Result::PG_DIAG_INTERNAL_QUERY ),
+            e.result.error_field( PG::Result::PG_DIAG_CONTEXT ),
+            e.result.error_field( PG::Result::PG_DIAG_SOURCE_FILE ),
+            e.result.error_field( PG::Result::PG_DIAG_SOURCE_LINE ),
+            e.result.error_field( PG::Result::PG_DIAG_SOURCE_FUNCTION ),
+          ]
+          p err
+          if err[2] =~/relation "\S+?" does not exist/ \
+          or err.inspect =~/relation "\S+?" does not exist/
+            SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).mark(
+              "\n" \
+              + err[2] + "\n" \
+              + 'Attempting to initialize db' + "\n" \
+              + 'Creating db tables'
+            )
+            sdb={
+              create: SiSU_DbDBI::Create.new(@opt,@conn,@file_maint,@sql_type),
+              index: SiSU_DbDBI::Index.new(@opt,@conn,@file_maint,@sql_type),
+            }
+            db_action(sdb).create
+            retry
+          end
+        end
+      end
+      if not file_exist
+        t_d=[]                                                              # transaction_data
+        t_d << db_import_metadata
+        t_d << db_import_documents(@ao_array)
+        t_d << db_import_urls(@ao_array,@fnc)                              #import OID on/off
+        t_d=t_d.flatten
+        if (@opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on)
+          puts @conn.class if defined? @conn.class
+          puts @conn.driver_name if defined? @conn.driver_name
+          puts @conn.driver if defined? @conn.driver
+        end
+        begin                                                               #% sql
+          if @sql_type==:sqlite
+            @conn.transaction do |conn|
+              t_d.each do |sql|
+                conn.execute(sql)
+              end
+            end
+            #also 'execute' works for sqlite
+            #@conn.execute("BEGIN")
+            #  t_d.each do |sql|
+            #    @conn.execute(sql)
+            #  end
+            #@conn.execute("COMMIT")
+          else
+            #'do' works for postgresql
+            @conn.exec("BEGIN")
+              t_d.each do |sql|
+                @conn.exec(sql)
+              end
+            @conn.exec("COMMIT")
+          end
+        rescue
+          SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+          sqlfn="#{@env.processing_path.sql}/#{@md.fnb}.sql"
+          sql=File.new(sqlfn,'w')
+          t_d.each {|i| sql.puts i}
+          p sqlfn
+          if @opt.act[:maintenance][:set]==:on
+            puts sql
+            p @conn.methods.sort
+            puts "#{__FILE__}:#{__LINE__}"
+          end
+        ensure
+        end
+      else
+        if file_exist
+          @db=SiSU_Env::InfoDb.new
+          puts "\nfile #{@opt.fns} in language code #{@opt.lng} already exists in database #{@db.psql.db}, use --update instead?"
+        end
+      end
+    end
+    def pf_db_import_transaction_open
+    end
+    def pf_db_import_transaction_close
+    end
+    def book_idx_hash_to_str(book_idx)
+      book_idx=book_idx ? book_idx : ''
+      book_idx_str,book_subidx_part='',''
+      if not book_idx.empty?
+        book_idx_str=''
+        book_idx.each_pair do |k0,v0|
+          book_idx_str << %{#{k0}+#{v0[:plus]}}
+          book_subidx_part=''
+          if v0[:sub].length > 0
+            v0[:sub].each do |subterms|
+               subterms.each_pair do |k1,v1|
+                 book_subidx_part << %{\n  #{k1}+#{v1[:plus]} | }
+               end
+            end
+            book_idx_str=book_idx_str + ':' + book_subidx_part
+          end
+        end
+      end
+      book_idx_str
+    end
+    def db_import_metadata                                                       #% import documents - populate database
+      if (@opt.act[:verbose][:set]==:on \
+      || @opt.act[:verbose_plus][:set]==:on \
+      || @opt.act[:maintenance][:set]==:on)
+        print %{ #{@cX.grey}import documents dbi_unit #{@cX.off} }
+      end
+      @tp={}
+      @md=SiSU_Param::Parameters.new(@opt).get
+#% sisutxt & fulltxt
+      if FileTest.exist?(@md.fns)
+        txt_arr=IO.readlines(@md.fns,'')
+        src=txt_arr.join("\n")
+        src=special_character_escape(src)
+        @tp[:sisutxt_f],@tp[:sisutxt_i]='sisutxt, ',"'#{src}', "
+        txt=clean_searchable_text_from_document_source(txt_arr)
+        #txt=special_character_escape(txt)
+        @tp[:fulltxt_f],@tp[:fulltxt_i]='fulltxt, ',"'#{txt}', "
+      end
+#% title
+      if defined? @md.title.full \
+      and @md.title.full=~/\S+/                                              # DublinCore 1 - title
+        #@tp[:title]=@md.title.full
+        #special_character_escape(@tp[:title])
+        #@tp[:title_f],@tp[:title_i]='title, ',"'#{@tp[:title]}', "
+        sql='SELECT MAX(tid) FROM metadata_and_text;'
+        begin
+          @@id_t ||=0
+          id_t=@driver_sqlite3 \
+          ? @conn.execute( sql ).join.to_i # { |x| id_t=x.join.to_i }
+          : @conn.exec( sql ).getvalue(0,0).to_i
+          @@id_t=id_t if id_t
+        rescue
+          if @opt.act[:maintenance][:set]==:on
+            puts "#{__FILE__} #{__LINE__}"
+          end
+        end
+        @@id_t+=1 #bug related, needs to be performed once at start of file, but consider moving, as, placed here it means program will fail if document header lacks @title:
+        if (@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on)
+          puts %{\n#{@cX.grey}Processing file number#{@cX.off}: #{@cX.green}#{@@id_t}#{@@cX.off}}
+        end
+      end
+      ################ CLEAR ##############
+      SiSU_DbDBI::Test.new(self,@opt).verify                          #% import title names, filenames (tuple)
+      t=SiSU_DbTuple::LoadMetadata.new(@conn,@@id_t,@md,@file_maint)
+      tuple=t.tuple
+      tuple
+    end
+    def db_import_documents(ao_array)                                     #% import documents - populate main database table, import into substantive database tables (tuple)
+      begin
+        @col[:tid]=@@id_t
+        @en,@en_ast,@en_pls,@tuple_array=[],[],[],[]
+        @col[:en_a],@col[:en_z]=nil,nil
+        ao_array.each do |data|
+          data.obj=data.obj.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'\1').
+            gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'\1').
+            gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'\1').
+            gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'\1').
+            gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'\1').
+            gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'\1').
+            gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'\1').
+            gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'\1').
+            gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,'\1').
+            gsub(/#{Mx[:gl_o]}(●)#{Mx[:gl_c]}\s*/,'\1 ').
+            gsub(/#{Mx[:tag_o]}\S+?#{Mx[:tag_c]}/,'') #check
+          @col[:seg]=@@seg
+          if data.of ==:para \
+          || data.of ==:heading \
+          || data.of ==:heading_insert \
+          || data.of ==:block \
+          || data.of ==:group      # regular text what of code-blocks grouped text etc.
+            notedata=data.obj.dup
+                                                                               #% :headings
+            if data.is==:heading \
+            && (data.ln.inspect=~/[0-3]/)
+              (
+                @col[:lev],
+                txt,@col[:ocn],
+                @col[:lev_an],
+                @col[:ocnd],@col[:ocns],
+                @col[:t_of],@col[:t_is],
+                @col[:node],@col[:parent],
+                @col[:digest_clean],@col[:digest_all]=
+                data.ln,
+                data.obj,data.ocn,
+                data.lv,
+                data.odv,data.osp,
+                data.of,data.is,
+                data.node,data.parent,
+                '',''
+              )
+              @col[:lid]+=1
+              txt=endnotes(txt).extract_any
+              body=SiSU_FormatShared::CSS_Format.new(@md,data).lev4_minus
+              @col[:body]=clean_document_objects_body(body)
+              plaintext=@col[:body].dup
+              plaintext=strip_markup(plaintext)
+              @col[:plaintext]=clean_searchable_text_from_document_objects(plaintext)
+              book_idx=book_idx_hash_to_str(data.idx)
+              @col[:book_idx]=clean_searchable_text_from_document_objects(book_idx)
+              if @en[0] then @en_a,@en_z=@en[0].first,@en[0].last
+              end
+              if @en_ast[0] then @en_a_asterisk,@en_z_asterisk=@en_ast[0].first,@en_ast[0].last
+              end
+              if @en_pls[0] then @en_a_plus,@en_z_plus=@en_pls[0].first,@en_pls[0].last
+              end
+              t=SiSU_DbTuple::LoadDocuments.new(@conn,@col,@opt,@file_maint)
+              @tuple_array << t.tuple
+              case @col[:lev]
+              when /0/ then @col[:lv0]+=1
+              when /1/ then @col[:lv1]+=1
+              when /2/ then @col[:lv2]+=1
+              when /3/ then @col[:lv3]+=1
+              when /4/ then @col[:lv4]+=1
+              end
+              @col[:lev]=@col[:plaintext]=@col[:body]=''
+            elsif data.is==:heading \
+            && data.ln==4
+              (
+                @@seg,txt,
+                @col[:ocn],@col[:lev_an],
+                @col[:ocnd],@col[:ocns],
+                @col[:t_of],@col[:t_is],
+                @col[:node],@col[:parent],
+                @col[:digest_clean],@col[:digest_all]=
+                data.name,data.obj,
+                data.ocn,data.lv,
+                data.odv,data.osp,
+                data.of,data.is,
+                data.node,data.parent,
+                '',''
+              )
+              @col[:seg]=@@seg
+              @col[:lv4]+=1
+              @col[:lid]+=1
+              @col[:lev]=4
+              @hname=if @col[:seg] \
+              and not @col[:seg].to_s.empty?
+                @@hname=@col[:seg].to_s
+              else @@hname
+              end
+              @env=SiSU_Env::InfoEnv.new(@md.fns)
+              @base_url="#{@env.url.root}/#{@md.fnb}/#{@hname}.html"
+              txt=endnotes(txt).extract_any
+              body=SiSU_FormatShared::CSS_Format.new(@md,data).lev4_plus
+              @col[:body]=clean_document_objects_body(body)
+              plaintext=@col[:body].dup
+              plaintext=strip_markup(plaintext)
+              @col[:plaintext]=clean_searchable_text_from_document_objects(plaintext)
+              book_idx=book_idx_hash_to_str(data.idx)
+              @col[:book_idx]=clean_searchable_text_from_document_objects(book_idx)
+              @en_a,@en_z=@en[0].first,@en[0].last if @en[0]
+              @en_a_asterisk,@en_z_asterisk=@en_ast[0].first,@en_ast[0].last if @en_ast[0]
+              @en_a_plus,@en_z_plus=@en_pls[0].first,@en_pls[0].last if @en_pls[0]
+              t=SiSU_DbTuple::LoadDocuments.new(@conn,@col,@opt,@file_maint)
+              @tuple_array << t.tuple
+              @col[:lev]=@col[:plaintext]=@col[:body]=''
+            elsif data.is==:heading \
+            && data.ln==5
+              (
+                txt,
+                @col[:ocn],@col[:lev_an],
+                @col[:ocnd],@col[:ocns],
+                @col[:t_of],@col[:t_is],
+                @col[:node],@col[:parent],
+                @col[:digest_clean],@col[:digest_all]=
+                data.obj,
+                data.ocn,data.lv,
+                data.odv,data.osp,
+                data.of,data.is,
+                data.node,data.parent,
+                '',''
+              )
+              @@seg_full=data.name if data.is==:heading \
+              && data.ln==5 \
+              && data.name #check data.name
+              @@seg ||='' #nil # watch
+              @col[:seg]=@@seg
+              @col[:lv5]+=1
+              @col[:lid]+=1
+              @col[:lev]=5
+              @hname=if @col[:seg] \
+              and not @col[:seg].to_s.empty?
+                @@hname=@col[:seg].to_s
+              else @@hname
+              end
+              @env=SiSU_Env::InfoEnv.new(@md.fns)
+              @base_url="#{@env.url.root}/#{@md.fnb}/#{@hname}.html"
+              txt=endnotes(txt).extract_any
+              body=SiSU_FormatShared::CSS_Format.new(@md,data).lev4_plus
+              @col[:body]=clean_document_objects_body(body)
+              plaintext=@col[:body].dup
+              plaintext=strip_markup(plaintext)
+              @col[:plaintext]=clean_searchable_text_from_document_objects(plaintext)
+              book_idx=book_idx_hash_to_str(data.idx)
+              @col[:book_idx]=clean_searchable_text_from_document_objects(book_idx)
+              @en_a,@en_z=@en[0].first,@en[0].last if @en[0]
+              @en_a_asterisk,@en_z_asterisk=@en_ast[0].first,@en_ast[0].last if @en_ast[0]
+              @en_a_plus,@en_z_plus=@en_pls[0].first,@en_pls[0].last if @en_pls[0]
+              t=SiSU_DbTuple::LoadDocuments.new(@conn,@col,@opt,@file_maint)
+              @tuple_array << t.tuple
+              @col[:lev]=@col[:plaintext]=@col[:body]=''
+            elsif data.is==:heading \
+            && data.ln==6
+              txt,       @col[:ocn],@col[:lev_an],@col[:ocnd],@col[:ocns],@col[:t_of],@col[:t_is],@col[:node],@col[:parent],@col[:digest_clean],@col[:digest_all]=
+                data.obj,data.ocn,  data.lv,      data.odv,   data.osp,   data.of,    data.is,    data.node,  data.parent,  '',                 ''
+              @@seg_full=data.name if data.is==:heading && data.ln==6 && data.name #check data.name
+              @@seg ||='' #nil # watch
+              @col[:seg]=@@seg
+              @col[:lv6]+=1
+              @col[:lid]+=1
+              @col[:lev]=6
+              @hname=if @col[:seg] \
+              and not @col[:seg].to_s.empty?
+                @@hname=@col[:seg].to_s
+              else @@hname
+              end
+              @env=SiSU_Env::InfoEnv.new(@md.fns)
+              @base_url="#{@env.url.root}/#{@md.fnb}/#{@hname}.html"
+              txt=endnotes(txt).extract_any
+              body=SiSU_FormatShared::CSS_Format.new(@md,data).lev4_plus
+              @col[:body]=clean_document_objects_body(body)
+              plaintext=@col[:body].dup
+              plaintext=strip_markup(plaintext)
+              @col[:plaintext]=clean_searchable_text_from_document_objects(plaintext)
+              book_idx=book_idx_hash_to_str(data.idx)
+              @col[:book_idx]=clean_searchable_text_from_document_objects(book_idx)
+              @en_a,@en_z=@en[0].first,@en[0].last if @en[0]
+              @en_a_asterisk,@en_z_asterisk=@en_ast[0].first,@en_ast[0].last if @en_ast[0]
+              @en_a_plus,@en_z_plus=@en_pls[0].first,@en_pls[0].last if @en_pls[0]
+              t=SiSU_DbTuple::LoadDocuments.new(@conn,@col,@opt,@file_maint)
+              @tuple_array << t.tuple
+              @col[:lev]=@col[:plaintext]=@col[:body]=''
+            elsif data.is==:heading \
+            && data.ln==7
+              txt,       @col[:ocn],@col[:lev_an],@col[:ocnd],@col[:ocns],@col[:t_of],@col[:t_is],@col[:node],@col[:parent],@col[:digest_clean],@col[:digest_all]=
+                data.obj,data.ocn,  data.lv,      data.odv,   data.osp,   data.of,    data.is,    data.node,  data.parent,  '',                 ''
+              @@seg_full=data.name if data.is==:heading && data.ln==7 && data.name #check data.name
+              @@seg ||='' #nil # watch
+              @col[:seg]=@@seg
+              @col[:lv7]+=1
+              @col[:lid]+=1
+              @col[:lev]=7
+              @hname=if @col[:seg] \
+              and not @col[:seg].to_s.empty?
+                @@hname=@col[:seg].to_s
+              else @@hname
+              end
+              @env=SiSU_Env::InfoEnv.new(@md.fns)
+              @base_url="#{@env.url.root}/#{@md.fnb}/#{@hname}.html"
+              txt=endnotes(txt).extract_any
+              body=SiSU_FormatShared::CSS_Format.new(@md,data).lev4_plus
+              @col[:body]=clean_document_objects_body(body)
+              plaintext=@col[:body].dup
+              plaintext=strip_markup(plaintext)
+              @col[:plaintext]=clean_searchable_text_from_document_objects(plaintext)
+              book_idx=book_idx_hash_to_str(data.idx)
+              @col[:book_idx]=clean_searchable_text_from_document_objects(book_idx)
+              @en_a,@en_z=@en[0].first,@en[0].last if @en[0]
+              @en_a_asterisk,@en_z_asterisk=@en_ast[0].first,@en_ast[0].last if @en_ast[0]
+              @en_a_plus,@en_z_plus=@en_pls[0].first,@en_pls[0].last if @en_pls[0]
+              t=SiSU_DbTuple::LoadDocuments.new(@conn,@col,@opt,@file_maint)
+              @tuple_array << t.tuple
+              @col[:lev]=@col[:plaintext]=@col[:body]=''
+                                                                               #% :structure :layout :comment
+            elsif data.of==:structure \
+            || data.of==:layout \
+            || data.of==:comment
+              #added watch
+                                                                               #% :
+            else                                                               #% regular text
+              @col[:lid]+=1
+              (
+                txt=''
+                txt,@col[:ocn],
+                @col[:ocnd],@col[:ocns],
+                @col[:t_of],@col[:t_is],
+                @col[:node],@col[:parent],
+                @col[:digest_clean],@col[:digest_all],
+                @col[:lev]=
+                data.obj,data.ocn,
+                data.odv,data.osp,
+                data.of,data.is,
+                '',data.parent,
+                '','',
+                9
+              )
+              @hname=if @col[:seg] \
+              and not @col[:seg].to_s.empty?
+                @@hname=@col[:seg].to_s
+              else @@hname
+              end
+              @env=SiSU_Env::InfoEnv.new(@md.fns)
+              @base_url="#{@env.url.root}/#{@md.fnb}/#{@hname}.html"
+              txt=endnotes(txt).extract_any
+              if @sql_type==:pg \
+              and txt.size > (SiSU_DbColumns::ColumnSize.new.document_clean - 1)             # examine pg build & remove limitation
+                puts "\n\nTOO LARGE (TXT - see error log)\n\n"
+                open("#{Dir.pwd}/pg_documents_error_log",'a') do |error|
+                  error.puts("\n#{@opt.fns}\nTEXT BODY\n#{@col[:body].size} object #{@col[:ocn]} -> #{@col[:body].slice(0..500)}")
+                end
+                txt=%{\n\nLARGE TEXT BLOCK OMITTED\n\n}
+              end
+              @en_a,@en_z=@en[0].first,@en[0].last if @en[0]
+              @en_a_asterisk,@en_z_asterisk=@en_ast[0].first,@en_ast[0].last if @en_ast[0]
+              @en_a_plus,@en_z_plus=@en_pls[0].first,@en_pls[0].last if @en_pls[0]
+              body=if data.is==:table
+                SiSU_FormatShared::CSS_Format.new(@md,data).html_table
+              elsif data.is==:code
+                SiSU_FormatShared::CSS_Format.new(@md,data).code
+              elsif defined? data.indent \
+              and defined? data.hang \
+              and data.indent =~/[1-9]/ \
+              and data.indent == data.hang
+                SiSU_FormatShared::CSS_Format.new(@md,data).indent(data.indent)
+              elsif defined? data.indent \
+              and defined? data.hang \
+              and data.hang =~/[0-9]/ \
+              and data.indent != data.hang
+                SiSU_FormatShared::CSS_Format.new(@md,data).hang_indent(data.hang,data.indent)
+              else
+                SiSU_FormatShared::CSS_Format.new(@md,data).norm
+              end
+              @col[:body]=clean_document_objects_body(body)
+              plaintext=@col[:body].dup
+              plaintext=strip_markup(plaintext)
+              @col[:plaintext]=clean_searchable_text_from_document_objects(plaintext)
+              book_idx=book_idx_hash_to_str(data.idx)
+              @col[:book_idx]=clean_searchable_text_from_document_objects(book_idx)
+              t=SiSU_DbTuple::LoadDocuments.new(@conn,@col,@opt,@file_maint)
+              @tuple_array << t.tuple
+              @en,@en_ast,@en_pls=[],[],[]
+              @col[:en_a]=@col[:en_z]=nil
+              @col[:lev]=@col[:plaintext]=@col[:body]=@col[:words]=''
+            end
+            if notedata =~/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}/                                         #% import into database endnotes tables
+              endnote_array=notedata.scan(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}/)
+              endnote_array.each do |inf|
+                if inf[/#{Mx[:en_a_o]}\d+.+?#{Mx[:en_a_c]}/]
+                  if inf[/#{Mx[:en_a_o]}(\d+)(.+?)#{Mx[:en_a_c]}/]
+                    nr,txt,digest_clean=$1,$2.strip,0
+                  end
+                  @id_n ||=0
+                  @id_n+=1
+                  txt=special_character_escape(txt)
+                  body=SiSU_FormatShared::CSS_Format.new(@md,data).endnote(nr,txt)
+                  txt=strip_markup(txt)
+                  if txt.size > (SiSU_DbColumns::ColumnSize.new.endnote_clean - 1)
+                    puts "\n\nTOO LARGE (ENDNOTE - see error log)\n\n"
+                    open("#{Dir.pwd}/pg_documents_error_log",'a') do |error|
+                      error.puts("\n#{@opt.fns}\nENDNOTE\n#{txt.size} object #{@col[:ocn]},#{@col[:ocnd]},#{@col[:ocns]} -> #{txt.slice(0..500)}")
+                    end
+                    txt=%{\n\nLARGE TEXT BLOCK OMITTED\n\n}
+                  end
+                  if txt
+                    en={
+                      type: 'endnotes',
+                      id:      @id_n,
+                      lid:     @col[:lid],
+                      nr:      nr,
+                      txt:     txt,
+                      body:    body,
+                      ocn:     @col[:ocn],
+                      ocnd:    @col[:ocnd],
+                      ocns:    @col[:ocns],
+                      id_t:    @@id_t,
+                      hash:    digest_clean
+                    }
+                    t=SiSU_DbTuple::LoadEndnotes.new(@conn,en,@opt,@file_maint)
+                    @tuple_array << t.tuple
+                  end
+                end
+              end
+              word_mode=notedata.scan(/\S+/)
+            end
+            if notedata =~/#{Mx[:en_b_o]}\*.+?#{Mx[:en_b_c]}/                                      #% import into database endnotes tables
+              endnote_array=notedata.scan(/#{Mx[:en_b_o]}\*.+?#{Mx[:en_b_c]}/)
+              endnote_array.each do |inf|
+                if inf[/#{Mx[:en_b_o]}\*\d+.+?#{Mx[:en_b_c]}/]                    # dal new endnotes 2003w31/1
+                  if inf[/#{Mx[:en_b_o]}[*](\d+)(.+?)#{Mx[:en_b_c]}/]           # dal new endnotes 2003w31/1
+                    nr,txt,digest_clean=$1,$2.strip,0
+                  end
+                  @id_n+=1
+                  txt=special_character_escape(txt)
+                  body=SiSU_FormatShared::CSS_Format.new(@md,data).endnote(nr,txt)
+                  txt=strip_markup(txt)
+                  if txt.size > (SiSU_DbColumns::ColumnSize.new.endnote_clean - 1)
+                    puts "\n\nTOO LARGE (ENDNOTE - see error log)\n\n"
+                    open("#{Dir.pwd}/pg_documents_error_log",'a') do |error|
+                      error.puts("\n#{@opt.fns}\nENDNOTE\n#{txt.size} object #{@col[:ocn]},#{@col[:ocnd]},#{@col[:ocns]} -> #{txt.slice(0..500)}")
+                    end
+                    txt=%{\n\nLARGE TEXT BLOCK OMITTED\n\n}
+                  end
+                  if txt
+                    en={
+                      type: 'endnotes_asterisk',
+                      id:      @id_n,
+                      lid:     @col[:lid],
+                      nr:      nr,
+                      txt:     txt,
+                      body:    body,
+                      ocn:     @col[:ocn],
+                      ocnd:    @col[:ocnd],
+                      ocns:    @col[:ocns],
+                      id_t:    @@id_t,
+                      hash:    digest_clean
+                    }
+                    t=SiSU_DbTuple::LoadEndnotes.new(@conn,en,@opt,@file_maint)
+                    @tuple_array << t.tuple
+                  end
+                end
+              end
+              word_mode=notedata.scan(/\S+/)
+            end
+            if notedata =~/#{Mx[:en_b_o]}\+.+?#{Mx[:en_b_c]}/                                           #% import into database endnotes tables
+              endnote_array=notedata.scan(/#{Mx[:en_b_o]}\+.+?#{Mx[:en_b_c]}/)
+              endnote_array.each do |inf|
+                if inf[/#{Mx[:en_b_o]}\+\d+.+?#{Mx[:en_b_c]}/]                        # dal new endnotes 2003w31/1
+                  if inf[/#{Mx[:en_b_o]}[+](\d+)(.+?)#{Mx[:en_b_c]}/]               # dal new endnotes 2003w31/1
+                    nr,txt,digest_clean=$1,$2.strip,0
+                  end
+                  @id_n+=1
+                  txt=special_character_escape(txt)
+                  body=SiSU_FormatShared::CSS_Format.new(@md,data).endnote(nr,txt)
+                  txt=strip_markup(txt)
+                  if txt.size > (SiSU_DbColumns::ColumnSize.new.endnote_clean - 1)
+                    puts "\n\nTOO LARGE (ENDNOTE - see error log)\n\n"
+                    open("#{Dir.pwd}/pg_documents_error_log",'a') do |error|
+                      error.puts("\n#{@opt.fns}\nENDNOTE\n#{txt.size} object #{@col[:ocn]},#{@col[:ocnd]},#{@col[:ocns]} -> #{txt.slice(0..500)}")
+                    end
+                    txt=%{\n\nLARGE TEXT BLOCK OMITTED\n\n}
+                  end
+                  if txt
+                    en={
+                      type: 'endnotes_plus',
+                      id:      @id_n,
+                      lid:     @col[:lid],
+                      nr:      nr,
+                      txt:     txt,
+                      body:    body,
+                      ocn:     @col[:ocn],
+                      ocnd:    @col[:ocnd],
+                      ocns:    @col[:ocns],
+                      id_t:    @@id_t,
+                      hash:    digest_clean
+                    }
+                    t=SiSU_DbTuple::LoadEndnotes.new(@conn,en,@opt,@file_maint)
+                    @tuple_array << t.tuple
+                  end
+                end
+              end
+              word_mode=notedata.scan(/\S+/)
+            end
+          end
+        end
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+      @tuple_array
+    end
+    def endnotes(txt)
+      @txt=txt
+      def extract_any
+        if @txt =~/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})[*+]?(\d+)\s+.+?(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/
+          endnotes(@txt).range
+          @en << endnotes(@txt).standard if @txt =~/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}/
+          @en_ast << endnotes(@txt).asterisk if @txt =~/#{Mx[:en_b_o]}\*.+?#{Mx[:en_b_c]}/
+          @en_pls << endnotes(@txt).plus if @txt =~/#{Mx[:en_b_o]}\+.+?#{Mx[:en_b_c]}/
+          @txt=endnotes(@txt).clean_text
+        end
+        @txt
+      end
+      def standard
+        (@txt =~/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}/) \
+        ? @txt.scan(/#{Mx[:en_a_o]}(\d+).+?#{Mx[:en_a_c]}/)
+        : nil
+      end
+      def asterisk
+        (@txt =~/#{Mx[:en_b_o]}\*.+?#{Mx[:en_b_c]}/) \
+        ? @txt.scan(/#{Mx[:en_b_o]}[*](\d+).+?#{Mx[:en_b_c]}/)
+        : nil
+      end
+      def plus
+        (@txt =~/#{Mx[:en_b_o]}\+.+?#{Mx[:en_b_c]}/) \
+        ? @txt.scan(/#{Mx[:en_b_o]}[+](\d+).+?#{Mx[:en_b_c]}/)
+        : nil
+      end
+      def clean_text(base_url=nil)
+        @txt=if base_url
+          @txt.gsub(/#{Mx[:en_a_o]}(\d+).+?#{Mx[:en_a_c]}/,%{<sup><a href="#{base_url}#_\\1" name="-\\1">\\1</a></sup>}).
+            gsub(/#{Mx[:en_b_o]}([*]\d+).+?#{Mx[:en_b_c]}/,%{<sup><a href="#{base_url}#_\\1" name="-\\1">\\1</a></sup>}).
+            gsub(/#{Mx[:en_b_o]}([+]\d+).+?#{Mx[:en_b_c]}/,%{<sup><a href="#{base_url}#_\\1" name="-\\1">\\1</a></sup>})
+        else
+          @txt.gsub(/#{Mx[:en_a_o]}(\d+).+?#{Mx[:en_a_c]}/,'<sup>\1</sup>').
+            gsub(/#{Mx[:en_b_o]}([*]\d+).+?#{Mx[:en_b_c]}/,'<sup>\1</sup>').
+            gsub(/#{Mx[:en_b_o]}([+]\d+).+?#{Mx[:en_b_c]}/,'<sup>\1</sup>')
+        end
+        @txt
+      end
+      def range
+        @col[:en_a]=@col[:en_z]=nil
+        if @txt =~/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}([*]\d+).+?#{Mx[:en_b_c]}|#{Mx[:en_b_o]}([+]\d+).+?#{Mx[:en_b_c]}/
+          word_array=@txt.scan(/\S+/)
+          word_array.each do |w|
+            if w[/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})[*+]?(\d+)\s+.+?(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/]                                                # not tested since change 2003w31
+              @col[:en_a]=$1 unless @col[:en_a]
+              @col[:en_z]=@col[:en_a].dup unless @col[:en_a]
+              @col[:en_z]=$1 if @col[:en_a]
+            end
+          end
+        end
+        @col
+      end
+      self
+    end
+    def db_import_urls(dbi_unit,content)                                           #% import documents OID - populate database
+      begin
+        @fnc=content
+        @env=SiSU_Env::InfoEnv.new(@opt.fns)
+        f,u={},{}
+        if @fnb.empty? \
+        or @fnb.nil?
+          p 'file output path error' #remove
+        end
+        if FileTest.file?("#{@md.file.output_path.txt.dir}/#{@md.file.base_filename.txt}")==true
+          f[:txt],u[:txt]='plaintext,', "'#{@md.file.output_path.txt.url}/#{@md.file.base_filename.txt}',"
+        end
+        if FileTest.file?("#{@md.file.output_path.html_seg.dir}/#{@md.file.base_filename.html_segtoc}")==true
+          f[:html_toc],u[:html_toc]='html_toc,', "'#{@md.file.output_path.html_seg.url}/#{@md.file.base_filename.html_segtoc}',"
+        end
+        if FileTest.file?("#{@md.file.output_path.html_scroll.dir}/#{@md.file.base_filename.html_scroll}")==true
+          f[:html_doc],u[:html_doc]='html_doc,', "'#{@md.file.output_path.html_scroll.url}/#{@md.file.base_filename.html_scroll}',"
+        end
+        if FileTest.file?("#{@md.file.output_path.xhtml.dir}/#{@md.file.base_filename.xhtml}")==true
+          f[:xhtml],u[:xhtml]='xhtml,', "'#{@md.file.output_path.xhtml.url}/#{@md.file.base_filename.xhtml}',"
+        end
+        if FileTest.file?("#{@md.file.output_path.xml_sax.dir}/#{@md.file.base_filename.xml_sax}")==true
+          f[:xml_sax],u[:xml_sax]='xml_sax,', "'#{@md.file.output_path.xml_sax.url}/#{@md.file.base_filename.xml_sax}',"
+        end
+        if FileTest.file?("#{@md.file.output_path.xml_dom.dir}/#{@md.file.base_filename.xml_dom}")==true
+          f[:xml_dom],u[:xml_dom]='xml_dom,', "'#{@md.file.output_path.xml_dom.url}/#{@md.file.base_filename.xml_dom}',"
+        end
+        if FileTest.file?("#{@md.file.output_path.epub.dir}/#{@md.file.base_filename.epub}")==true
+          f[:epub],u[:epub]='epub,', "'#{@md.file.output_path.epub.url}/#{@md.file.base_filename.epub}',"
+        end
+        if FileTest.file?("#{@md.file.output_path.odt.dir}/#{@md.file.base_filename.odt}")==true
+          f[:odf],u[:odf]='odf,', "'#{@md.file.output_path.odt.url}/#{@md.file.base_filename.odt}',"
+        end
+        if FileTest.file?("#{@md.file.output_path.pdf.dir}/#{@pdf_fn.pdf_p_a4}")==true #\
+        #or FileTest.file?("#{@md.file.output_path.pdf.dir}/#{@pdf_fn.pdf_p_letter}")==true
+          f[:pdf_p],u[:pdf_p]='pdf_p,', "'#{@md.file.output_path.pdf.url}/#{@pdf_fn.pdf_p_a4}',"
+        end
+        if FileTest.file?("#{@md.file.output_path.pdf.dir}/#{@pdf_fn.pdf_l_a4}")==true #\
+        #or FileTest.file?("#{@md.file.output_path.pdf.dir}/#{@pdf_fn.pdf_l_letter}")==true
+          f[:pdf_l],u[:pdf_l]='pdf_l,', "'#{@md.file.output_path.pdf.url}/#{@pdf_fn.pdf_l_a4}',"
+        end
+        if FileTest.file?("#{@md.file.output_path.html_concordance.dir}/#{@md.file.base_filename.html_concordance}")==true
+          f[:concordance],u[:concordance]='concordance,', "'#{@md.file.output_path.html_concordance.url}/#{@md.file.base_filename.html_concordance}',"
+        end
+        #if FileTest.file?("#{@md.file.output_path.x.dir}/#{@md.file.base_filename.x}")==true
+        #  f[:latex_p],u[:latex_p]='latex_p,', "'#{@md.file.output_path.x.url}/#{@md.file.base_filename.x}',"
+        #end
+        ##if FileTest.file?("#{out}/#{@fnb}/#{@opt.fns}.tex")==true
+        ##  f[:latex_p],u[:latex_p]='latex_p,', "'#{base}/#{@fnb}/#{@opt.fns}.tex',"
+        ##end
+        #if FileTest.file?("#{@md.file.output_path.x.dir}/#{@md.file.base_filename.x}")==true
+        #  f[:latex_l],u[:latex_l]='latex_l,', "'#{@md.file.output_path.x.url}/#{@md.file.base_filename.x}',"
+        #end
+        ##if FileTest.file?("#{out}/#{@fnb}/#{@opt.fns}.landscape.tex")==true
+        ##  f[:latex_l],u[:latex_l]='latex_l,', "'#{base}/#{@fnb}/#{@opt}.fns}.landscape.tex',"
+        ##end
+        if FileTest.file?("#{@md.file.output_path.digest.dir}/#{@md.file.base_filename.digest}")==true
+          f[:digest],u[:digest]='digest,', "'#{@md.file.output_path.digest.url}/#{@md.file.base_filename.digest}',"
+        end
+        if FileTest.file?("#{@md.file.output_path.manifest.dir}/#{@md.file.base_filename.manifest}")==true #revisit, was to be text, this is html
+          f[:manifest],u[:manifest]='manifest,', "'#{@md.file.output_path.manifest.url}/#{@md.file.base_filename.manifest}',"
+        end
+        if FileTest.file?("#{@md.file.output_path.src.dir}/#{@md.file.base_filename.src}")==true
+          f[:markup],u[:markup]='markup,', "'#{@md.file.output_path.src.url}/#{@md.file.base_filename.src}',"
+        end
+        if FileTest.file?("#{@md.file.output_path.sisupod.dir}/#{@md.file.base_filename.sisupod}")==true
+          f[:sisupod],u[:sisupod]='sisupod,', "'#{@md.file.output_path.sisupod.url}/#{@md.file.base_filename.sisupod}',"
+        end
+        t=SiSU_DbTuple::LoadUrls.new(@conn,f,u,@@id_t,@opt,@file_maint)
+        tuple=t.tuple
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+      tuple
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** db_remove.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/db_remove.rb"
+# <<sisu_document_header>>
+module SiSU_DbRemove
+  class Remove
+    include SiSU_DbAction
+    def initialize(opt,conn,file,sql_type)
+      @opt,@conn,@file,@sql_type=opt,conn,file,sql_type
+      @md=SiSU_Param::Parameters.new(@opt).get
+      @fnb=@md.fnb
+      @db=SiSU_Env::InfoDb.new
+    end
+    def remove
+      driver_sqlite3=if @sql_type==:sqlite
+        (@conn.inspect.match(/^(.{10})/)[1]==@db.sqlite.conn_sqlite3.inspect.match(/^(.{10})/)[1]) \
+        ? true
+        : false
+      end
+      del_id=if driver_sqlite3
+        begin
+          remove_selected=%{
+            SELECT tid
+            FROM metadata_and_text
+            WHERE src_filename = '#{@md.fns}'
+            AND metadata_and_text.language_document_char = '#{@opt.lng}'
+          ;} # note, for .ssm: @md.fns (is set during runtime & is) != @opt.fns @md.opt.fns
+          @conn.get_first_value(remove_selected).to_i
+        rescue SQLite3::Exception => e
+          #not tested
+          puts "Exception occurred"
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).mark(e.inspect)
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).mark(
+            "\n" \
+            + 'Attempting to initialize db' + "\n" \
+            + 'Creating db tables'
+          )
+          sdb={
+            create: SiSU_DbDBI::Create.new(@opt,@conn,@file_maint,@sql_type),
+            index: SiSU_DbDBI::Index.new(@opt,@conn,@file_maint,@sql_type),
+          }
+          db_action(sdb).create
+        end
+      else
+        begin
+          remove_selected=%{
+            SELECT metadata_and_text.tid
+            FROM metadata_and_text
+            WHERE metadata_and_text.src_filename = '#{@md.fns}'
+            AND metadata_and_text.language_document_char = '#{@opt.lng}'
+          ;} # note, for .ssm: @md.fns (is set during runtime & is) != @opt.fns @md.opt.fns
+          x=@conn.exec(remove_selected)
+          x.field_values("tid")[0]
+        rescue PG::Error => e
+          err=[
+            e.result.error_field( PG::Result::PG_DIAG_SEVERITY ),
+            e.result.error_field( PG::Result::PG_DIAG_SQLSTATE ),
+            e.result.error_field( PG::Result::PG_DIAG_MESSAGE_PRIMARY ),
+            e.result.error_field( PG::Result::PG_DIAG_MESSAGE_DETAIL ),
+            e.result.error_field( PG::Result::PG_DIAG_MESSAGE_HINT ),
+            e.result.error_field( PG::Result::PG_DIAG_STATEMENT_POSITION ),
+            e.result.error_field( PG::Result::PG_DIAG_INTERNAL_POSITION ),
+            e.result.error_field( PG::Result::PG_DIAG_INTERNAL_QUERY ),
+            e.result.error_field( PG::Result::PG_DIAG_CONTEXT ),
+            e.result.error_field( PG::Result::PG_DIAG_SOURCE_FILE ),
+            e.result.error_field( PG::Result::PG_DIAG_SOURCE_LINE ),
+            e.result.error_field( PG::Result::PG_DIAG_SOURCE_FUNCTION ),
+          ]
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).mark("\n" + err.inspect)
+          if err[2] =~/relation "\S+?" does not exist/ \
+          or err.inspect =~/relation "\S+?" does not exist/
+            SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).mark(
+              "\n" \
+              + err[2] + "\n" \
+              + 'Attempting to initialize db' + "\n" \
+              + 'Creating db tables'
+            )
+            sdb={
+              create: SiSU_DbDBI::Create.new(@opt,@conn,@file_maint,@sql_type),
+              index: SiSU_DbDBI::Index.new(@opt,@conn,@file_maint,@sql_type),
+            }
+            db_action(sdb).create
+          end
+        end
+      end
+      if del_id
+        sql_entry=[
+          "DELETE FROM endnotes WHERE metadata_tid = '#{del_id}';",
+          "DELETE FROM endnotes_asterisk WHERE metadata_tid = '#{del_id}';",
+          "DELETE FROM endnotes_plus WHERE metadata_tid = '#{del_id}';",
+          "DELETE FROM doc_objects WHERE metadata_tid = '#{del_id}';",
+          "DELETE FROM urls WHERE metadata_tid = '#{del_id}';",
+          "DELETE FROM metadata_and_text WHERE metadata_and_text.tid = '#{del_id}';",
+        ]
+        if driver_sqlite3
+          @conn.transaction
+          sql_entry.each do |s|
+            begin
+              @conn.execute(s)
+            rescue
+              next
+            end
+          end
+          @conn.commit if driver_sqlite3
+        else
+          sql_entry.each do |s|
+            begin
+              @conn.exec_params(s)
+            rescue
+              next
+            end
+          end
+        end
+        if @opt.act[:maintenance][:set]==:on
+          @file.puts sql_entry
+        end
+      else
+        if (@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on)
+          SiSU_Screen::Ansi.new(
+            @opt.selections.str,
+            "no such file in database #{@db.psql.db}::#{@opt.fns}"
+          ).puts_grey
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* db_load_tuple.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/db_load_tuple.rb"
+# <<sisu_document_header>>
+module SiSU_DbTuple
+  require_relative 'db_columns'                         # db_columns.rb
+  class LoadDocuments
+    require_relative 'dp'                               # dp.rb
+      include SiSU_Param
+    def initialize(conn,col,opt,file_maint)
+      @conn,@col,@opt,@file_maint=conn,col,opt,file_maint
+      @col[:lev]=@col[:lev].to_i
+      unless @col[:lev].inspect=~/^[0-7]/ \
+      or @col[:lev]==0..7
+        @col[:lev]=9
+      end
+      @col[:ocn]=0 unless @col[:ocn].inspect=~/\d+/
+      @cX=SiSU_Screen::Ansi.new(@opt.act[:color_state][:set]).cX
+    end
+    def tuple                                                                    #% import line
+      sql_entry=if @col[:en_a]
+        "INSERT INTO doc_objects (lid, metadata_tid, lev, lev_an, clean, body, book_idx, ocn, ocnd, ocns, seg, lev0, lev1, lev2, lev3, lev4, lev5, lev6, lev7, en_a, en_z, t_of, t_is, node, parent, digest_clean, digest_all) " +
+        "VALUES (#{@col[:lid]}, #{@col[:tid]}, #{@col[:lev]}, '#{@col[:lev_an]}', '#{@col[:plaintext]}', '#{@col[:body]}', '#{@col[:book_idx]}', '#{@col[:ocn]}', '#{@col[:ocnd]}', '#{@col[:ocns]}', '#{@col[:seg]}', '#{@col[:lv0]}', '#{@col[:lv1]}', '#{@col[:lv2]}', '#{@col[:lv3]}', '#{@col[:lv4]}', '#{@col[:lv5]}', '#{@col[:lv6]}', '#{@col[:lv7]}', '#{@col[:en_a]}', '#{@col[:en_z]}', '#{@col[:t_of]}', '#{@col[:t_is]}', '#{@col[:node]}', '#{@col[:parent]}', '#{@col[:digest_clean]}', '#{@col[:digest_all]}');"
+      else
+        "INSERT INTO doc_objects (lid, metadata_tid, lev, lev_an, clean, body, book_idx, ocn, ocnd, ocns, seg, lev0, lev1, lev2, lev3, lev4, lev5, lev6, lev7, t_of, t_is, node, parent, digest_clean, digest_all) " +
+        "VALUES (#{@col[:lid]}, #{@col[:tid]}, #{@col[:lev]}, '#{@col[:lev_an]}', '#{@col[:plaintext]}', '#{@col[:body]}', '#{@col[:book_idx]}', '#{@col[:ocn]}', '#{@col[:ocnd]}', '#{@col[:ocns]}', '#{@col[:seg]}', '#{@col[:lv0]}', '#{@col[:lv1]}', '#{@col[:lv2]}', '#{@col[:lv3]}', '#{@col[:lv4]}', '#{@col[:lv5]}', '#{@col[:lv6]}', '#{@col[:lv7]}', '#{@col[:t_of]}', '#{@col[:t_is]}', '#{@col[:node]}', '#{@col[:parent]}', '#{@col[:digest_clean]}', '#{@col[:digest_all]}');"
+      end
+      if @opt.act[:maintenance][:set]==:on
+          puts @file_maint.inspect
+          puts sql_entry
+          @file_maint.puts sql_entry
+      elsif @opt.act[:verbose_plus][:set]==:on
+          puts sql_entry
+      end
+      if @opt.act[:verbose][:set]==:on
+        if @col[:lev].inspect =~/[0-35-7]/
+          lev=case @col[:lev].inspect
+          when /0/ then ':A'
+          when /1/ then ':B'
+          when /2/ then ':C'
+          when /3/ then ':D'
+          when /5/ then ' 2'
+          when /6/ then ' 3'
+          when /7/ then ' 4'
+          end
+          puts %{#{lev}>\t#{@col[:lv0]}\t#{@col[:lv1]}\t#{@col[:lv2]}\t#{@col[:lv3]}\t#{@col[:lv4]}\t#{@col[:lv5]}\t#{@col[:lv6]}\t#{@col[:lv7]}\t#{@col[:ocn]}\t#{@col[:node]}\t#{@col[:ocns]}}
+        elsif @col[:lev].inspect =~/[4]/
+          puts %{ #{@cX.green}1>#{@cX.off}\t#{@col[:lv0]}\t#{@col[:lv1]}\t#{@col[:lv2]}\t#{@col[:lv3]}\t#{@col[:lv4]}\t#{@col[:lv5]}\t#{@col[:lv6]}\t#{@col[:lv7]}\t#{@col[:ocn]}\t#{@col[:node]}\t#{@col[:ocns]}\t#{@col[:seg]}}
+        end
+      end
+      sql_entry
+    end
+  end
+  class LoadMetadata #< SiSU_DbColumns::Columns
+    def initialize(conn,id,md,file_maint)
+      @conn,@id,@md,@file_maint=conn,id,md,file_maint
+      @tp=SiSU_DbColumns::Columns.new(md)
+    end
+    def tuple
+      sql_entry="INSERT INTO metadata_and_text (
+#{@tp.column.title.tuple[0]}
+#{@tp.column.title_main.tuple[0]}
+#{@tp.column.title_sub.tuple[0]}
+#{@tp.column.title_short.tuple[0]}
+#{@tp.column.title_edition.tuple[0]}
+#{@tp.column.title_note.tuple[0]}
+#{@tp.column.title_language.tuple[0]}
+#{@tp.column.title_language_char.tuple[0]}
+#{@tp.column.creator_author.tuple[0]}
+#{@tp.column.creator_author_honorific.tuple[0]}
+#{@tp.column.creator_author_nationality.tuple[0]}
+#{@tp.column.creator_editor.tuple[0]}
+#{@tp.column.creator_contributor.tuple[0]}
+#{@tp.column.creator_illustrator.tuple[0]}
+#{@tp.column.creator_photographer.tuple[0]}
+#{@tp.column.creator_translator.tuple[0]}
+#{@tp.column.creator_prepared_by.tuple[0]}
+#{@tp.column.creator_digitized_by.tuple[0]}
+#{@tp.column.creator_audio.tuple[0]}
+#{@tp.column.creator_video.tuple[0]}
+#{@tp.column.language_document.tuple[0]}
+#{@tp.column.language_document_char.tuple[0]}
+#{@tp.column.language_original.tuple[0]}
+#{@tp.column.language_original_char.tuple[0]}
+#{@tp.column.date_added_to_site.tuple[0]}
+#{@tp.column.date_available.tuple[0]}
+#{@tp.column.date_created.tuple[0]}
+#{@tp.column.date_issued.tuple[0]}
+#{@tp.column.date_modified.tuple[0]}
+#{@tp.column.date_published.tuple[0]}
+#{@tp.column.date_valid.tuple[0]}
+#{@tp.column.date_translated.tuple[0]}
+#{@tp.column.date_original_publication.tuple[0]}
+#{@tp.column.date_generated.tuple[0]}
+#{@tp.column.publisher.tuple[0]}
+#{@tp.column.original_publisher.tuple[0]}
+#{@tp.column.original_language.tuple[0]}
+#{@tp.column.original_language_char.tuple[0]}
+#{@tp.column.original_source.tuple[0]}
+#{@tp.column.original_institution.tuple[0]}
+#{@tp.column.original_nationality.tuple[0]}
+#{@tp.column.rights_all.tuple[0]}
+#{@tp.column.rights_copyright_text.tuple[0]}
+#{@tp.column.rights_copyright_translation.tuple[0]}
+#{@tp.column.rights_copyright_illustrations.tuple[0]}
+#{@tp.column.rights_copyright_photographs.tuple[0]}
+#{@tp.column.rights_copyright_preparation.tuple[0]}
+#{@tp.column.rights_copyright_digitization.tuple[0]}
+#{@tp.column.rights_copyright_audio.tuple[0]}
+#{@tp.column.rights_copyright_video.tuple[0]}
+#{@tp.column.rights_license.tuple[0]}
+#{@tp.column.classify_topic_register.tuple[0]}
+#{@tp.column.classify_subject.tuple[0]}
+#{@tp.column.classify_loc.tuple[0]}
+#{@tp.column.classify_dewey.tuple[0]}
+#{@tp.column.classify_keywords.tuple[0]}
+#{@tp.column.identifier_oclc.tuple[0]}
+#{@tp.column.identifier_isbn.tuple[0]}
+#{@tp.column.notes_abstract.tuple[0]}
+#{@tp.column.notes_description.tuple[0]}
+#{@tp.column.notes_comment.tuple[0]}
+#{@tp.column.notes_history.tuple[0]}
+#{@tp.column.notes_format.tuple[0]}
+#{@tp.column.notes_relation.tuple[0]}
+#{@tp.column.notes_coverage.tuple[0]}
+#{@tp.column.notes_type.tuple[0]}
+#{@tp.column.notes_prefix.tuple[0]}
+#{@tp.column.notes_prefix_a.tuple[0]}
+#{@tp.column.notes_prefix_b.tuple[0]}
+#{@tp.column.notes_suffix.tuple[0]}
+#{@tp.column.src_filename.tuple[0]}
+#{@tp.column.src_fingerprint.tuple[0]}
+#{@tp.column.src_filesize.tuple[0]}
+#{@tp.column.src_word_count.tuple[0]}
+#{@tp.column.src_txt.tuple[0]}
+#{@tp.column.fulltext.tuple[0]}
+tid)
+" +
+       "VALUES (
+#{@tp.column.title.tuple[1]}
+#{@tp.column.title_main.tuple[1]}
+#{@tp.column.title_sub.tuple[1]}
+#{@tp.column.title_short.tuple[1]}
+#{@tp.column.title_edition.tuple[1]}
+#{@tp.column.title_note.tuple[1]}
+#{@tp.column.title_language.tuple[1]}
+#{@tp.column.title_language_char.tuple[1]}
+#{@tp.column.creator_author.tuple[1]}
+#{@tp.column.creator_author_honorific.tuple[1]}
+#{@tp.column.creator_author_nationality.tuple[1]}
+#{@tp.column.creator_editor.tuple[1]}
+#{@tp.column.creator_contributor.tuple[1]}
+#{@tp.column.creator_illustrator.tuple[1]}
+#{@tp.column.creator_photographer.tuple[1]}
+#{@tp.column.creator_translator.tuple[1]}
+#{@tp.column.creator_prepared_by.tuple[1]}
+#{@tp.column.creator_digitized_by.tuple[1]}
+#{@tp.column.creator_audio.tuple[1]}
+#{@tp.column.creator_video.tuple[1]}
+#{@tp.column.language_document.tuple[1]}
+#{@tp.column.language_document_char.tuple[1]}
+#{@tp.column.language_original.tuple[1]}
+#{@tp.column.language_original_char.tuple[1]}
+#{@tp.column.date_added_to_site.tuple[1]}
+#{@tp.column.date_available.tuple[1]}
+#{@tp.column.date_created.tuple[1]}
+#{@tp.column.date_issued.tuple[1]}
+#{@tp.column.date_modified.tuple[1]}
+#{@tp.column.date_published.tuple[1]}
+#{@tp.column.date_valid.tuple[1]}
+#{@tp.column.date_translated.tuple[1]}
+#{@tp.column.date_original_publication.tuple[1]}
+#{@tp.column.date_generated.tuple[1]}
+#{@tp.column.publisher.tuple[1]}
+#{@tp.column.original_publisher.tuple[1]}
+#{@tp.column.original_language.tuple[1]}
+#{@tp.column.original_language_char.tuple[1]}
+#{@tp.column.original_source.tuple[1]}
+#{@tp.column.original_institution.tuple[1]}
+#{@tp.column.original_nationality.tuple[1]}
+#{@tp.column.rights_all.tuple[1]}
+#{@tp.column.rights_copyright_text.tuple[1]}
+#{@tp.column.rights_copyright_translation.tuple[1]}
+#{@tp.column.rights_copyright_illustrations.tuple[1]}
+#{@tp.column.rights_copyright_photographs.tuple[1]}
+#{@tp.column.rights_copyright_preparation.tuple[1]}
+#{@tp.column.rights_copyright_digitization.tuple[1]}
+#{@tp.column.rights_copyright_audio.tuple[1]}
+#{@tp.column.rights_copyright_video.tuple[1]}
+#{@tp.column.rights_license.tuple[1]}
+#{@tp.column.classify_topic_register.tuple[1]}
+#{@tp.column.classify_subject.tuple[1]}
+#{@tp.column.classify_loc.tuple[1]}
+#{@tp.column.classify_dewey.tuple[1]}
+#{@tp.column.classify_keywords.tuple[1]}
+#{@tp.column.identifier_oclc.tuple[1]}
+#{@tp.column.identifier_isbn.tuple[1]}
+#{@tp.column.notes_abstract.tuple[1]}
+#{@tp.column.notes_comment.tuple[1]}
+#{@tp.column.notes_description.tuple[1]}
+#{@tp.column.notes_history.tuple[1]}
+#{@tp.column.notes_format.tuple[1]}
+#{@tp.column.notes_relation.tuple[1]}
+#{@tp.column.notes_coverage.tuple[1]}
+#{@tp.column.notes_type.tuple[1]}
+#{@tp.column.notes_prefix.tuple[1]}
+#{@tp.column.notes_prefix_a.tuple[1]}
+#{@tp.column.notes_prefix_b.tuple[1]}
+#{@tp.column.notes_suffix.tuple[1]}
+#{@tp.column.src_filename.tuple[1]}
+#{@tp.column.src_fingerprint.tuple[1]}
+#{@tp.column.src_filesize.tuple[1]}
+#{@tp.column.src_word_count.tuple[1]}
+#{@tp.column.src_txt.tuple[1]}
+#{@tp.column.fulltext.tuple[1]}
+#{@id}
+);"
+      if @md.opt.act[:maintenance][:set]==:on
+        puts "maintenance mode on: creating sql transaction file (for last transaction set (document) only):\n\t#{@file_maint.inspect}"
+        @file_maint.puts sql_entry
+      end
+      sql_entry
+    end
+  end
+  class LoadUrls
+    def initialize(conn,f,u,id,opt,file_maint)
+      @conn,@f,@u,@id,@opt,@file_maint=conn,f,u,id,opt,file_maint
+    end
+    def tuple
+      sql_entry="INSERT INTO urls (#{@f[:txt]} #{@f[:html_toc]} #{@f[:html_doc]} #{@f[:xhtml]} #{@f[:xml_sax]} #{@f[:xml_dom]} #{@f[:odf]} #{@f[:pdf_p]} #{@f[:pdf_l]} #{@f[:concordance]} #{@f[:latex_p]} #{@f[:latex_l]} #{@f[:manifest]} #{@f[:digest]} #{@f[:markup]} #{@f[:sisupod]} metadata_tid) " +
+      "VALUES (#{@u[:txt]} #{@u[:html_toc]} #{@u[:html_doc]} #{@u[:xhtml]} #{@u[:xml_sax]} #{@u[:xml_dom]} #{@u[:odf]} #{@u[:pdf_p]} #{@u[:pdf_l]} #{@u[:concordance]} #{@u[:latex_p]} #{@u[:latex_l]} #{@u[:manifest]} #{@u[:digest]} #{@u[:markup]} #{@u[:sisupod]} #{@id});"
+      if @opt.act[:maintenance][:set]==:on
+        @file_maint.puts sql_entry
+      end
+      sql_entry
+    end
+  end
+  class LoadEndnotes
+    def initialize(conn,en,opt,file_maint)
+      @conn,@en,@opt,@file_maint=conn,en,opt,file_maint
+    end
+    def tuple
+      sql_entry="INSERT INTO #{@en[:type]} (nid, document_lid, nr, clean, body, ocn, ocnd, ocns, metadata_tid, digest_clean) " +
+      "VALUES ('#{@en[:id]}', '#{@en[:lid]}', '#{@en[:nr]}', '#{@en[:txt]}', '#{@en[:body]}', '#{@en[:ocn]}', '#{@en[:ocnd]}', '#{@en[:ocns]}', '#{@en[:id_t]}', '#{@en[:hash]}');"
+      if @opt.act[:maintenance][:set]==:on
+        @file_maint.puts sql_entry
+      end
+      sql_entry
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* db_select.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/db_select.rb"
+# <<sisu_document_header>>
+module SiSU_DbAction
+  def db_action(sdb)
+    @sdb=sdb
+    def createdb
+      @sdb[:create].output_dir?
+      begin
+        @sdb[:create].create_db
+      rescue
+        @sdb[:create].output_dir?
+      end
+    end
+    def drop
+      @sdb[:drop].drop.tables
+    end
+    def create
+      @sdb[:create].output_dir?
+      begin
+        @sdb[:create].create_table.metadata_and_text
+        @sdb[:create].create_table.doc_objects
+        @sdb[:create].create_table.endnotes
+        @sdb[:create].create_table.endnotes_asterisk
+        @sdb[:create].create_table.endnotes_plus
+        @sdb[:create].create_table.urls
+        @sdb[:index].create_indexes
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,'--sqlite').location
+        @sdb[:create].output_dir? do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      end
+    end
+    def import
+      db_exist?
+      @sdb[:import].marshal_load
+      tell=case @sql_type
+      when :sqlite
+        SiSU_Screen::Ansi.new(
+          @opt.act[:color_state][:set],
+          "sqlite3 #{@db.sqlite.db} database?"
+        )
+      when :pg
+        SiSU_Screen::Ansi.new(
+          @opt.act[:color_state][:set],
+          "pgaccess or psql #{@db.psql.db} database?"
+        )
+      else '???'
+      end
+      tell.puts_grey if @opt.act[:verbose][:set]==:on
+    end
+    def remove
+      db_exist?
+      @sdb[:remove_doc].remove
+    end
+    def update
+      remove
+      import
+    end
+    self
+  end
+end
+module SiSU_DbSelect
+  class Case
+    include SiSU_DbAction
+    def initialize(opt,conn='',sql_type=:pg)
+      @opt,@conn,@sql_type=opt,conn,sql_type
+      @db=SiSU_Env::InfoDb.new
+      @file_maint=sql_maintenance_file
+      @sdb={
+        create: SiSU_DbDBI::Create.new(@opt,@conn,@file_maint,@sql_type),
+        index: SiSU_DbDBI::Index.new(@opt,@conn,@file_maint,@sql_type),
+        drop: SiSU_DbDBI::Drop.new(@opt,@conn,@db,@sql_type),
+      }
+      if (@opt.act[:psql_import][:set]==:on \
+      || @opt.act[:psql_update][:set]==:on) \
+      or (@opt.act[:sqlite_import][:set]==:on \
+      || @opt.act[:sqlite_update][:set]==:on)
+        @sdb[:import]=SiSU_DbDBI::Import.new(@opt,@conn,@file_maint,@sql_type)
+        @sdb[:remove_doc]=SiSU_DbDBI::Remove.new(@opt,@conn,@file_maint,@sql_type)
+      elsif (@opt.act[:psql_remove][:set]==:on \
+      or @opt.act[:sqlite_remove][:set]==:on)
+        @sdb[:remove_doc]=SiSU_DbDBI::Remove.new(@opt,@conn,@file_maint,@sql_type)
+      end
+    end
+    def db_exist?
+      if @sql_type==:sqlite \
+      and (not (FileTest.file?(@db.sqlite.db)) \
+      or FileTest.zero?(@db.sqlite.db))
+        puts %{no connection with sqlite database established, you may need to run:\n} \
+        + %{    sisu --sqlite --createall\n} \
+        + %{  before attempting to populate the database}
+        SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).mark(
+          "\n" \
+          + 'Attempting to initialize db' + "\n" \
+          + 'Creating db tables'
+        )
+        db_action(@sdb).create
+      end
+      if @conn.is_a?(NilClass)
+        if @sql_type==:sqlite
+          puts %{no connection with sqlite database established, you may need to run:\n} \
+          + %{    sisu --sqlite --createall\n} \
+          + %{  before attempting to populate the database}
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).mark(
+            "\n" \
+            + 'Attempting to initialize db' + "\n" \
+            + 'Creating db tables'
+          )
+          db_action(@sdb).create
+          @db.sqlite.db
+        else
+          puts %{no connection with pg database established, you may need to run:\n} \
+          + %{    createdb "#{@db.psql.db}"\n} \
+          + %{  after that don't forget to run:\n} \
+          + %{    sisu --pg --createall\n} \
+          + %{  before attempting to populate the database}
+          @db.psql.db
+        end
+        exit
+      end
+    end
+    def sql_maintenance_file
+      file=if @opt.act[:maintenance][:set]==:on
+        if @opt.fns and not @opt.fns.empty?
+          @env=SiSU_Env::InfoEnv.new(@opt.fns) if @opt.fns
+          if @sql_type ==:sqlite
+            puts "\n#{@env.processing_path.sqlite}/#{@opt.fns}.sql"
+          end
+          @db=SiSU_Env::InfoDb.new
+          @job="sqlite3 #{@db.sqlite.db} < #{@env.processing_path.sqlite}/#{@opt.fns}.sql"
+          if @sql_type ==:sqlite
+            File.new("#{@env.processing_path.sqlite}/#{@opt.fns}.sql",'w+')
+          else
+            File.new("#{@env.processing_path.postgresql}/#{@opt.fns}.sql",'w+')
+          end
+        elsif @opt.fns \
+        and (@opt.act[:sqlite_create][:set] ==:on \
+        || @opt.act[:psql_create][:set] ==:on)
+          nil #sort variations later
+        else nil
+        end
+      else nil
+      end
+      file
+    end
+    def cases
+      if @opt.act[:psql_drop][:set] ==:on \
+      or @opt.act[:sqlite_drop][:set] ==:on
+        db_action(@sdb).drop
+      end
+      if @opt.act[:psql_createdb][:set] ==:on \
+      or @opt.act[:sqlite_createdb][:set] ==:on
+        db_action(@sdb).createdb
+      end
+      if @opt.act[:psql_create][:set] ==:on \
+      or @opt.act[:sqlite_create][:set] ==:on
+        db_action(@sdb).create
+      end
+      if @opt.act[:psql_update][:set] ==:on \
+      or @opt.act[:sqlite_update][:set] ==:on
+        db_action(@sdb).update
+      else
+        if @opt.act[:psql_remove][:set] ==:on \
+        or @opt.act[:sqlite_remove][:set] ==:on
+          db_action(@sdb).remove
+        end
+        if @opt.act[:psql_import][:set] ==:on \
+        or @opt.act[:sqlite_import][:set] ==:on
+          db_action(@sdb).import
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* structure
+** db_columns.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/db_columns.rb"
+# <<sisu_document_header>>
+module SiSU_DbColumns
+  require_relative 'se'                                # se.rb
+  require_relative 'db_sqltxt'                         # db_sqltxt.rb
+  class Columns < SiSU_DbText::Prepare
+    def initialize(md=nil)
+      @md=md
+      @db=SiSU_Env::InfoDb.new #watch
+      @lang ||=SiSU_i18n::Languages.new
+      if defined? md.opt.act \
+      and ((md.opt.act[:psql_import][:set]==:on \
+      || md.opt.act[:psql_update][:set]==:on) \
+      or (md.opt.act[:sqlite_import][:set]==:on \
+      || md.opt.act[:sqlite_update][:set]==:on)) \
+      and FileTest.exist?(md.fns)
+        txt_arr=IO.readlines(md.fns,'')
+        src=txt_arr.join("\n")
+        if @db.share_source?
+          @sisutxt=special_character_escape(src)
+        else @sisutxt=''
+        end
+        @fulltext=clean_searchable_text_from_document_objects(txt_arr)
+       else @sisutxt,@fulltext='',''
+      end
+    end
+#% structures
+    #def column_define
+    #  def varchar(name,size)
+    #    "#{name}                VARCHAR(#{size}) NULL,"
+    #  end
+    #end
+=begin
+#% title
+@title:
+ :subtitle:
+ :short:
+ :edition:
+ :language:
+ :note:
+=end
+    def column
+      def title                          # DublinCore 1 - title
+        def name
+          'title'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_title]}) NOT NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+            IS 'metadata full document title [DC1]';}
+        end
+        def tuple
+          if defined? @md.title.full \
+          and @md.title.full=~/\S+/
+            txt=@md.title.full
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def title_main
+        def name
+          'title_main'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_title_part]}) NOT NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+            IS 'metadata main document title';}
+        end
+        def tuple
+          if defined? @md.title.main \
+          and @md.title.main=~/\S+/
+            txt=@md.title.main
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def title_sub
+        def name
+          'title_sub'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_title_part]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+            IS 'metadata document subtitle';}
+        end
+        def tuple
+          if defined? @md.title.sub \
+          and @md.title.sub=~/\S+/
+            txt=@md.title.sub
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def title_short
+        def name
+          'title_short'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_title_part]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+            IS 'metadata document short title if any';}
+        end
+        def tuple
+          if defined? @md.title.short \
+          and @md.title.short=~/\S+/
+            txt=@md.title.short
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def title_edition
+        def name
+          'title_edition'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_title_edition]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+            IS 'metadata document edition (version)';}
+        end
+        def tuple
+          if defined? @md.title.edition \
+          and @md.title.edition=~/\S+/
+            txt=@md.title.edition
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def title_note
+        def name
+          'title_note'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_info_note]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+            IS 'metadata document notes associated with title';}
+        end
+        def tuple
+          if defined? @md.title.note \
+          and @md.title.note=~/\S+/
+            txt=@md.title.note
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def title_language
+        def name
+          'title_language'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_language]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+            IS 'metadata document language [DC12]';}
+        end
+        def tuple
+          if @lang.list[@md.opt.lng][:n]
+            txt=@lang.list[@md.opt.lng][:n]
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def title_language_char            # consider
+        def name
+          'title_language_char'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_language_char]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+            IS 'metadata document language iso code';}
+        end
+        def tuple
+          if defined? @md.opt.lng \
+          and @md.opt.lng=~/\S+/
+            txt=@md.opt.lng
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+=begin
+#% creator
+@creator:
+ :author:
+ :editor:
+ :contributor:
+ :illustrator:
+ :photographer:
+ :translator:
+ :prepared_by:
+ :digitized_by:
+ :audio:
+ :video:
+=end
+      def creator_author                 # DublinCore 2 - creator/author (author)
+        def name
+          'creator_author'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_name]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document author (creator) [DC2]';}
+        end
+        def tuple
+          if defined? @md.creator.author_detail \
+          and @md.creator.author_detail.is_a?(Array) \
+          and @md.creator.author_detail.length > 0
+            txt=''
+            @md.creator.author_detail.each do |h|
+              txt=txt + %{#{h[:the]}, #{h[:others]}; }
+            end
+            txt=txt.gsub(/[;, ]+\s*$/,'')
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def creator_author_honorific       # consider
+        def name
+          'creator_author_hon'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_creator_misc_short]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document author honorific (title e.g, Ms. Dr. Prof.)';}
+        end
+        def tuple
+          if defined? @md.creator.author_hon \
+          and @md.creator.author_hon=~/\S+/
+            txt=@md.creator.author_hon
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def creator_author_nationality     # consider
+        def name
+          'creator_author_nationality'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_creator_misc_short]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata nationality of document author (creator)';}
+        end
+        def tuple
+          if defined? @md.creator.author_nationality_detail \
+          and @md.creator.author_nationality=~/\S+/
+            txt=@md.creator.author_nationality_detail
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def creator_editor
+        def name
+          'creator_editor'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_name]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document editor name(s)';}
+        end
+        def tuple
+          if defined? @md.creator.editor_detail \
+          and @md.creator.editor_detail.is_a?(Array) \
+          and @md.creator.editor_detail.length > 0
+            txt=''
+            @md.creator.editor_detail.each do |h|
+              txt=txt + %{#{h[:the]}, #{h[:others]}; }
+            end
+            txt=txt.gsub(/[;, ]+\s*$/,'')
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def creator_contributor            # DublinCore 6 - contributor
+        def name
+          'creator_contributor'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_name]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document contributor name(s) [DC6]';}
+        end
+        def tuple
+          if defined? @md.creator.contributor_detail \
+          and @md.creator.contributor_detail.is_a?(Array) \
+          and @md.creator.contributor_detail.length > 0
+            txt=''
+            @md.creator.contributor_detail.each do |h|
+              txt=txt + %{#{h[:the]}, #{h[:others]}; }
+            end
+            txt=txt.gsub(/[;, ]+\s*$/,'')
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def creator_illustrator
+        def name
+          'creator_illustrator'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_name]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document illustrator name(s)';}
+        end
+        def tuple
+          if defined? @md.creator.illustrator_detail \
+          and @md.creator.illustrator_detail.is_a?(Array) \
+          and @md.creator.illustrator_detail.length > 0
+            txt=''
+            @md.creator.illustrator_detail.each do |h|
+              txt=txt + %{#{h[:the]}, #{h[:others]}; }
+            end
+            txt=txt.gsub(/[;, ]+\s*$/,'')
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def creator_photographer
+        def name
+          'creator_photographer'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_name]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document photographer name(s)';}
+        end
+        def tuple
+          if defined? @md.creator.photographer_detail \
+          and @md.creator.photographer_detail.is_a?(Array) \
+          and @md.creator.photographer_detail.length > 0
+            txt=''
+            @md.creator.photographer_detail.each do |h|
+              txt=txt + %{#{h[:the]}, #{h[:others]}; }
+            end
+            txt=txt.gsub(/[;, ]+\s*$/,'')
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def creator_translator
+        def name
+          'creator_translator'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_name]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document translator name(s)';}
+        end
+        def tuple
+          if defined? @md.creator.translator_detail \
+          and @md.creator.translator_detail.is_a?(Array) \
+          and @md.creator.translator_detail.length > 0
+            txt=''
+            @md.creator.translator_detail.each do |h|
+              txt=txt + %{#{h[:the]}, #{h[:others]}; }
+            end
+            txt=txt.gsub(/[;, ]+\s*$/,'')
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def creator_prepared_by
+        def name
+          'creator_prepared_by'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_name]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document prepared by name(s)';}
+        end
+        def tuple
+          if defined? @md.creator.prepared_by_detail \
+          and @md.creator.prepared_by_detail.is_a?(Array) \
+          and @md.creator.prepared_by_detail.length > 0
+            txt=''
+            @md.creator.prepared_by_detail.each do |h|
+              txt=txt + %{#{h[:the]}, #{h[:others]}; }
+            end
+            txt=txt.gsub(/[;, ]+\s*$/,'')
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def creator_digitized_by
+        def name
+          'creator_digitized_by'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_name]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document digitized by name(s)';}
+        end
+        def tuple
+          if defined? @md.creator.digitized_by_detail \
+          and @md.creator.digitized_by_detail.is_a?(Array) \
+          and @md.creator.digitized_by_detail.length > 0
+            txt=''
+            @md.creator.digitized_by_detail.each do |h|
+              txt=txt + %{#{h[:the]}, #{h[:others]}; }
+            end
+            txt=txt.gsub(/[;, ]+\s*$/,'')
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def creator_audio
+        def name
+          'creator_audio'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_name]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document audio by name(s)';}
+        end
+        def tuple
+          if defined? @md.creator.audio_detail \
+          and @md.creator.audio_detail.is_a?(Array) \
+          and @md.creator.audio_detail.length > 0
+            txt=''
+            @md.creator.audio_detail.each do |h|
+              txt=txt + %{#{h[:the]}, #{h[:others]}; }
+            end
+            txt=txt.gsub(/[;, ]+\s*$/,'')
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def creator_video
+        def name
+          'creator_video'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_name]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document video by name(s)';}
+        end
+        def tuple
+          if defined? @md.creator.video_detail \
+          and @md.creator.video_detail.is_a?(Array) \
+          and @md.creator.video_detail.length > 0
+            txt=''
+            @md.creator.video_detail.each do |h|
+              txt=txt + %{#{h[:the]}, #{h[:others]}; }
+            end
+            txt=txt.gsub(/[;, ]+\s*$/,'')
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+=begin
+#% language
+#taken from other fields
+@title:
+ :language:
+@original:
+ :language:
+#not available -->
+#@language:
+# :document:
+# :original:
+=end
+      def language_document
+        def name
+          'language_document'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_language]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document language';}
+        end
+        def tuple
+          if @lang.list[@md.opt.lng][:n]
+            txt=@lang.list[@md.opt.lng][:n]
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def language_document_char
+        def name
+          'language_document_char'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_language_char]}) NOT NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document language';}
+        end
+        def tuple
+          #modify check, is now required, SiSUv3d_
+          if defined? @md.opt.lng \
+          and @md.opt.lng=~/\S+/
+            txt=@md.opt.lng
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def language_original
+        def name
+          'language_original'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_language]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata original document/text language';}
+        end
+        def tuple
+          if defined? @md.language.original \
+          and @md.language.original=~/\S+/
+            txt=@md.language.original
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def language_original_char
+        def name
+          'language_original_char'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_language_char]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document language';}
+        end
+        def tuple
+          if defined? @md.language.original_char \
+          and @md.language.original_char=~/\S+/
+            txt=@md.language.original_char
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+=begin
+#% date
+@date:
+ :added_to_site:
+ :available:
+ :created:
+ :issued:
+ :modified:
+ :published:
+ :valid:
+ :translated:
+ :original_publication:
+=end
+      def date_added_to_site
+        def name
+          'date_added_to_site'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_date_text]}) NULL,"
+          #"#{name}                DATE,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata date added to site';}
+        end
+        def tuple
+          if defined? @md.date.added_to_site \
+          and @md.date.added_to_site=~/\S+/
+            txt=@md.date.added_to_site
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def date_available
+        def name
+          'date_available'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_date_text]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata date added to site [DC]';}
+        end
+        def tuple
+          if defined? @md.date.available \
+          and @md.date.available=~/\S+/
+            txt=@md.date.available
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def date_created
+        def name
+          'date_created'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_date_text]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata date created [DC]';}
+        end
+        def tuple
+          if defined? @md.date.created \
+          and @md.date.created=~/\S+/
+            txt=@md.date.created
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def date_issued
+        def name
+          'date_issued'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_date_text]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata date issued [DC]';}
+        end
+        def tuple
+          if defined? @md.date.issued \
+          and @md.date.issued=~/\S+/
+            txt=@md.date.issued
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def date_modified
+        def name
+          'date_modified'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_date_text]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata date modified [DC]';}
+        end
+        def tuple
+          if defined? @md.date.modified \
+          and @md.date.modified=~/\S+/
+            txt=@md.date.modified
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def date_published
+        def name
+          'date_published'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_date_text]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata date published [DC7]';}
+        end
+        def tuple
+          if defined? @md.date.published \
+          and @md.date.published=~/\S+/
+            txt=@md.date.published
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def date_valid
+        def name
+          'date_valid'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_date_text]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata date valid [DC]';}
+        end
+        def tuple
+          if defined? @md.date.valid \
+          and @md.date.valid=~/\S+/
+            txt=@md.date.valid
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def date_translated
+        def name
+          'date_translated'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_date_text]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata date translated';}
+        end
+        def tuple
+          if defined? @md.date.translated \
+          and @md.date.translated=~/\S+/
+            txt=@md.date.translated
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def date_original_publication
+        def name
+          'date_original_publication'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_date_text]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata date of original publication';}
+        end
+        def tuple
+          if defined? @md.date.original_publication \
+          and @md.date.original_publication=~/\S+/
+            txt=@md.date.original_publication
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def date_generated
+        def name
+          'date_generated'
+        end
+        def create_column              #choose other representation of time
+          "#{name}                VARCHAR(30) NULL,"
+          #"#{name}                VARCHAR(10) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata date of sisu generation of document, automatically populated';}
+        end
+        def tuple                      #choose other representation of time
+          if defined? @md.generated \
+          and @md.generated.to_s=~/\S+/
+            txt=@md.generated.to_s
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+=begin
+#% publisher
+@publisher:
+=end
+      def publisher
+        def name
+          'publisher'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_name]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document publisher [DC5]';}
+        end
+        def tuple
+          if defined? @md.publisher \
+          and @md.publisher=~/\S+/
+            txt=@md.publisher
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+##% current
+#    def current_publisher
+#      def name
+#        'current_publisher'
+#      end
+#      def size
+#        10
+#      end
+#      def create_column
+#        "#{name}                VARCHAR(#{current_publisher.size}) NULL,"
+#      end
+#      def tuple
+#        t=if defined? @md.current.publisher \
+#        and @md.current.publisher=~/\S+/
+#          txt=@md.current.publisher
+#          txt=special_character_escape(txt)
+#          "'#{txt}', "
+#        end
+#      end
+#      self
+#    end
+=begin
+#% original
+@original:
+ :publisher:
+ #:date:                                #repeated under date
+ :language:
+ :institution:
+ :nationality:
+ :source:
+=end
+      def original_publisher
+        def name
+          'original_publisher'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_name]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document original publisher [DC5]';}
+        end
+        def tuple
+          if defined? @md.original.publisher \
+          and @md.original.publisher=~/\S+/
+            txt=@md.original.publisher
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def original_language
+        def name
+          'original_language'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_language]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document original language';}
+        end
+        def tuple
+          if defined? @md.original.language \
+          and @md.original.language=~/\S+/
+            txt=@md.original.language
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def original_language_char         # consider
+        def name
+          'original_language_char'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_language_char]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document original language iso character';}
+        end
+        def tuple
+          if defined? @md.original.language_char \
+          and @md.original.language_char=~/\S+/
+            txt=@md.original.language_char
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def original_source
+        def name
+          'original_source'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_name]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document original source [DC11]';}
+        end
+        def tuple
+          if defined? @md.original.source \
+          and @md.original.source=~/\S+/
+            txt=@md.original.source
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def original_institution
+        def name
+          'original_institution'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_name]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document original institution';}
+        end
+        def tuple
+          if defined? @md.original.institution \
+          and @md.original.institution=~/\S+/
+            txt=@md.original.institution
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def original_nationality
+        def name
+          'original_nationality'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_language]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document original nationality';}
+        end
+        def tuple
+          if defined? @md.original.nationality \
+          and @md.original.nationality=~/\S+/
+            txt=@md.original.nationality
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+=begin
+#% rights
+@rights:
+ #:copyright:                          #mapped to :text: used where no other copyrights and included in :all:
+ :text:
+ :translation:
+ :illustrations:
+ :photographs:
+ :preparation:
+ :digitization:
+ :audio:
+ :video:
+ :license:
+ :all:
+=end
+      def rights_all
+        def name
+          'rights'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_info_note]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata rights associated with document (composite) [DC15]';}
+        end
+        def tuple
+          if defined? @md.rights.all \
+          and @md.rights.all=~/\S+/
+            txt=@md.rights.all
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def rights_copyright_text
+        def name
+          'rights_copyright_text'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_info_note]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata copyright associated for document text';}
+        end
+        def tuple
+          if defined? @md.rights.copyright_text \
+          and @md.rights.copyright_text=~/\S+/
+            txt=@md.rights.copyright_text
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def rights_copyright_translation
+        def name
+          'rights_copyright_translation'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_info_note]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata copyright associated for document text translation (if any)';}
+        end
+        def tuple
+          if defined? @md.rights.copyright_translation \
+          and @md.rights.copyright_translation=~/\S+/
+            txt=@md.rights.copyright_translation
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def rights_copyright_illustrations
+        def name
+          'rights_copyright_illustrations'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_info_note]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata copyright associated for document text illustrations (if any)';}
+        end
+        def tuple
+          if defined? @md.rights.copyright_illustrations \
+          and @md.rights.copyright_illustrations=~/\S+/
+            txt=@md.rights.copyright_illustrations
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def rights_copyright_photographs
+        def name
+          'rights_copyright_photographs'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_info_note]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata copyright associated for document text photographs (if any)';}
+        end
+        def tuple
+          if defined? @md.rights.copyright_photographs \
+          and @md.rights.copyright_photographs=~/\S+/
+            txt=@md.rights.copyright_photographs
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def rights_copyright_preparation
+        def name
+          'rights_copyright_preparation'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_info_note]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata copyright associated for document text preparation (if any)';}
+        end
+        def tuple
+          if defined? @md.rights.copyright_preparation \
+          and @md.rights.copyright_preparation=~/\S+/
+            txt=@md.rights.copyright_preparation
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def rights_copyright_digitization
+        def name
+          'rights_copyright_digitization'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_info_note]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata copyright associated for document text digitization (if any)';}
+        end
+        def tuple
+          if defined? @md.rights.copyright_digitization \
+          and @md.rights.copyright_digitization=~/\S+/
+            txt=@md.rights.copyright_digitization
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def rights_copyright_audio
+        def name
+          'rights_copyright_audio'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_info_note]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata copyright associated for document text audio (if any)';}
+        end
+        def tuple
+          if defined? @md.rights.copyright_audio \
+          and @md.rights.copyright_audio=~/\S+/
+            txt=@md.rights.copyright_audio
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def rights_copyright_video
+        def name
+          'rights_copyright_video'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_info_note]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata copyright associated for document text video (if any)';}
+        end
+        def tuple
+          if defined? @md.rights.copyright_video \
+          and @md.rights.copyright_video=~/\S+/
+            txt=@md.rights.copyright_video
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def rights_license
+        def name
+          'rights_license'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_info_note]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata license granted for use of document if any)';}
+        end
+        def tuple
+          if defined? @md.rights.license \
+          and @md.rights.license=~/\S+/
+            txt=@md.rights.license
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+=begin
+#% identifier
+@identifier:
+ :oclc:
+ :isbn:
+=end
+      def identifier_oclc
+        def name
+          'identifier_oclc'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_library]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata identifier document Online Computer Library Center number';}
+        end
+        def tuple
+          if defined? @md.identifier.oclc \
+          and @md.identifier.oclc=~/\S+/
+            txt=@md.identifier.oclc
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def identifier_isbn
+        def name
+          'identifier_isbn'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_small]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata identifier document isbn (if any)';}
+        end
+        def tuple
+          if defined? @md.identifier.isbn \
+          and @md.identifier.isbn=~/\S+/
+            txt=@md.identifier.isbn
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+=begin
+#% classify
+@classify:
+ :topic_register:
+ :subject:
+ :keywords:
+ :type:
+ :loc:
+ :dewey:
+=end
+      def classify_topic_register
+        def name
+          'classify_topic_register'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_info_note]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata classify document topic register (semi-structured document subject information)';}
+        end
+        def tuple
+          if defined? @md.classify.topic_register \
+          and @md.classify.topic_register=~/\S+/
+            txt=@md.classify.topic_register
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def classify_subject
+        def name
+          'classify_subject'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_txt_long]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata classify document subject matter [DC3]';}
+        end
+        def tuple
+          if defined? @md.classify.subject \
+          and @md.classify.subject=~/\S+/
+            txt=@md.classify.subject
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def classify_loc
+        def name
+          'classify_loc'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_library]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata classify document Library of Congress';}
+        end
+        def tuple
+          if defined? @md.classify.loc \
+          and @md.classify.loc=~/\S+/
+            txt=@md.classify.loc
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def classify_dewey
+        def name
+          'classify_dewey'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_library]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata classify document Dewey';}
+        end
+        def tuple
+          if defined? @md.classify.dewey \
+          and @md.classify.dewey=~/\S+/
+            txt=@md.classify.dewey
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def classify_keywords
+        def name
+          'classify_keywords'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_txt_long]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata classify document keywords';}
+        end
+        def tuple
+          if defined? @md.classify.keywords \
+          and @md.classify.keywords=~/\S+/
+            txt=@md.classify.keywords
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+=begin
+#% notes
+@notes:
+ :abstract:
+ :description:
+ :comment:
+ :coverage:
+ :relation:
+ :format:
+ :history:
+ :prefix:
+ :prefix_a:
+ :prefix_b:
+ :suffix:
+=end
+      def notes_abstract
+        def name
+          'notes_abstract'
+        end
+        def create_column
+          "#{name}                     TEXT NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document notes abstract';}
+        end
+        def tuple
+          if defined? @md.notes.abstract \
+          and @md.notes.abstract=~/\S+/
+            txt=@md.notes.abstract
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def notes_description
+        def name
+          'notes_description'
+        end
+        def create_column
+          "#{name}                    TEXT NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document notes description [DC4]';}
+        end
+        def tuple
+          if defined? @md.notes.description \
+          and @md.notes.description=~/\S+/
+            txt=@md.notes.description
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def notes_comment
+        def name
+          'notes_comment'
+        end
+        def create_column
+          "#{name}                       TEXT NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document notes comment';}
+        end
+        def tuple
+          if defined? @md.notes.comment \
+          and @md.notes.comment=~/\S+/
+            txt=@md.notes.comment
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def notes_coverage
+        def name
+          'notes_coverage'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_txt_short]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata classify document coverage [DC14]';}
+        end
+        def tuple
+          if defined? @md.classify.coverage \
+          and @md.classify.coverage=~/\S+/
+            txt=@md.classify.coverage
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def notes_relation
+        def name
+          'notes_relation'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_txt_short]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata classify document relation [DC13]';}
+        end
+        def tuple
+          if defined? @md.classify.relation \
+          and @md.classify.relation=~/\S+/
+            txt=@md.classify.relation
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def notes_history   #check, consider removal
+        def name
+          'notes_history'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_txt_long]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document notes history';}
+        end
+        def tuple
+          if defined? @md.notes.history \
+          and @md.notes.history=~/\S+/
+            txt=@md.notes.history
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def notes_type #check
+        def name
+          'notes_type'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_txt_long]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata notes document type [DC8]';}
+        end
+        def tuple
+          if defined? @md.notes.type \
+          and @md.notes.type=~/\S+/
+            txt=@md.notes.type
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def notes_format
+        def name
+          'notes_format'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_txt_long]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata classify document format [DC9]';}
+        end
+        def tuple
+          if defined? @md.classify.format \
+          and @md.classify.format=~/\S+/
+            txt=@md.classify.format
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def notes_prefix
+        def name
+          'notes_prefix'
+        end
+        def create_column
+          "#{name}                TEXT NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document notes prefix';}
+        end
+        def tuple
+          if defined? @md.notes.prefix \
+          and @md.notes.prefix=~/\S+/
+            txt=@md.notes.prefix
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def notes_prefix_a
+        def name
+          'notes_prefix_a'
+        end
+        def create_column
+          "#{name}                TEXT NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document notes prefix_a';}
+        end
+        def tuple
+          if defined? @md.notes.prefix_a \
+          and @md.notes.prefix_a=~/\S+/
+            txt=@md.notes.prefix_a
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def notes_prefix_b
+        def name
+          'notes_prefix_b'
+        end
+        def create_column
+          "#{name}                TEXT NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document notes prefix_b';}
+        end
+        def tuple
+          if defined? @md.notes.prefix_b \
+          and @md.notes.prefix_b=~/\S+/
+            txt=@md.notes.prefix_b
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def notes_suffix
+        def name
+          'notes_suffix'
+        end
+        def create_column                # keep text
+          "#{name}                TEXT NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document notes suffix';}
+        end
+        def tuple
+          if defined? @md.notes.suffix \
+          and @md.notes.suffix=~/\S+/
+            txt=@md.notes.suffix
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+=begin
+#% src
+=end
+      def src_filename
+        def name
+          'src_filename'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_filename]}) NOT NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'sisu markup source text filename';}
+        end
+        def tuple
+          if defined? @md.fns \
+          and @md.fns=~/\S+/
+            txt=@md.fns
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def src_fingerprint
+        def name
+          'src_fingerprint' #hash/digest, sha512, sha256 or md5
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_digest]}) NULL,"
+          #"#{name}                TEXT NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+            IS 'sisu markup source text fingerprint, hash digest sha512, sha256 or md5';}
+        end
+        def tuple
+          if defined? @md.dgst \
+          and @md.dgst.is_a?(Array) \
+          and @md.dgst[1]=~/\S+/
+            txt=@md.dgst[1]
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def src_filesize
+        def name
+          'src_filesize'
+        end
+        def create_column
+          "#{name}                VARCHAR(#{Db[:col_filesize]}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+            IS 'sisu markup source text file size';}
+        end
+        def tuple
+         if defined? @md.filesize \
+         and @md.filesize=~/\S+/
+           txt=@md.filesize
+           txt=special_character_escape(txt)
+           ["#{name}, ","'#{txt}', "]
+         else ['','']
+         end
+        end
+        self
+      end
+      def src_word_count
+        def name
+          'src_word_count'
+        end
+        def create_column
+          "#{name}                TEXT NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+            IS 'sisu markup source text word count';}
+        end
+        def tuple
+          if defined? @md.wc_words \
+          and @md.wc_words.to_s=~/\S+/
+            txt=@md.wc_words
+            txt=special_character_escape(txt)
+            ["#{name}, ","'#{txt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def src_txt                      # consider naming sisusrc
+        def name
+          'src_text'
+        end
+        def create_column
+          "#{name}                TEXT NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'sisu markup source text (if shared)';}
+        end
+        def tuple
+          if ((@md.opt.act[:psql_import][:set]==:on \
+          || @md.opt.act[:psql_update][:set]==:on) \
+          or (@md.opt.act[:sqlite_import][:set]==:on \
+          || @md.opt.act[:sqlite_update][:set]==:on)) \
+          and FileTest.exist?(@md.fns)
+            ["#{name}, ","'#{@sisutxt}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+=begin
+#% misc
+@links:
+=end
+      def fulltext
+        def name
+          'fulltext'
+        end
+        def create_column
+          "#{name}                TEXT NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+            IS 'document full text clean, searchable';}
+        end
+        def tuple
+          if ((@md.opt.act[:psql_import][:set]==:on \
+          || @md.opt.act[:psql_update][:set]==:on) \
+          or (@md.opt.act[:sqlite_import][:set]==:on \
+          || @md.opt.act[:sqlite_update][:set]==:on)) \
+          and  FileTest.exist?(@md.fns)
+            ["#{name}, ","'#{@fulltext}', "]
+          else ['','']
+          end
+        end
+        self
+      end
+      def links
+        def name
+          'links'
+        end
+        def create_column
+          "#{name}                TEXT NULL,"
+          #"#{name}                 VARCHAR(#{links.size}) NULL,"
+        end
+        def column_comment
+          %{COMMENT ON COLUMN metadata_and_text.#{name}
+           IS 'metadata document links';}
+        end
+        #def tuple
+        #  #BUG HERE - links is an array of paired values :say :url
+        #  if defined? @md.links \
+        #  and @md.links=~/\S+/
+        #    txt=@md.links
+        #    txt=special_character_escape(txt)
+        #    ["#{name}, ","'#{txt}', "]
+        #  else ['','']
+        #  end
+        #end
+        self
+      end
+      self
+    end
+  end
+  class ColumnSize
+    def document_clean # restriction not necessary
+      60000
+    end
+    def document_body
+      16000
+    end
+    def document_seg
+      120
+    end
+    def document_seg_full
+      120
+    end
+    def endnote_clean # restriction not necessary
+      60000
+    end
+    def endnote_body
+      16000
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** db_indexes.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/db_indexes.rb"
+# <<sisu_document_header>>
+module SiSU_DbIndex
+  class Index                                           # create documents Indexes def initialize(opt,conn='',sql_type)
+    def initialize(opt,conn,file,sql_type)
+      @opt,@conn,@file,@sql_type=opt,conn,file,sql_type
+    end
+    def create_indexes                                                           # check added from pg not tested
+      def conn_execute_sql_pg(conn,sql)
+        conn.exec_params(sql)
+      end
+      def conn_execute_sql_sqlite(conn,sql)
+        conn.execute(sql)
+      end
+      def conn_execute_sql(conn,sql)
+        if @sql_type==:pg
+          conn_execute_sql_pg(conn,sql)
+        elsif @sql_type==:sqlite
+          conn_execute_sql_sqlite(conn,sql)
+        else
+        end
+      end
+      def conn_execute_array(sql_arr)
+        begin
+          @conn.transaction do |conn|
+            sql_arr.each do |sql|
+              conn_execute_sql(conn,sql)
+            end
+          end
+        rescue
+          if @conn.is_a?(NilClass)
+            errmsg="No sqlite3 connection (check sqlite3 dependencies)"
+            if @opt.act[:no_stop][:set]==:on
+              SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+                error("#{errmsg}, proceeding without sqlite output (as requested)")
+            else
+              SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+                error("#{errmsg}, STOPPING")
+              exit
+            end
+          end
+        end
+      end
+      def base
+        if (@opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on)
+          print "\n          create documents common indexes\n"
+        end
+        sql_arr=[
+          %{CREATE INDEX idx_ocn ON doc_objects(ocn);},
+          %{CREATE INDEX idx_digest_clean ON doc_objects(digest_clean);},
+          %{CREATE INDEX idx_digest_all ON doc_objects(digest_all);},
+          %{CREATE INDEX idx_lev0 ON doc_objects(lev0);},
+          %{CREATE INDEX idx_lev1 ON doc_objects(lev1);},
+          %{CREATE INDEX idx_lev2 ON doc_objects(lev2);},
+          %{CREATE INDEX idx_lev3 ON doc_objects(lev3);},
+          %{CREATE INDEX idx_lev4 ON doc_objects(lev4);},
+          %{CREATE INDEX idx_lev5 ON doc_objects(lev5);},
+          %{CREATE INDEX idx_lev6 ON doc_objects(lev6);},
+          %{CREATE INDEX idx_endnote_nr ON endnotes(nr);},
+          %{CREATE INDEX idx_digest_en ON endnotes(digest_clean);},
+          %{CREATE INDEX idx_endnote_nr_asterisk ON endnotes_asterisk(nr);},
+          %{CREATE INDEX idx_endnote_asterisk ON endnotes_asterisk(clean);},
+          %{CREATE INDEX idx_digest_en_asterisk ON endnotes_asterisk(digest_clean);},
+          %{CREATE INDEX idx_endnote_nr_plus ON endnotes_plus(nr);},
+          %{CREATE INDEX idx_endnote_plus ON endnotes_plus(clean);},
+          %{CREATE INDEX idx_digest_en_plus ON endnotes_plus(digest_clean);},
+          %{CREATE INDEX idx_title ON metadata_and_text(title);},
+          %{CREATE INDEX idx_author ON metadata_and_text(creator_author);},
+          %{CREATE INDEX idx_filename ON metadata_and_text(src_filename);},
+          %{CREATE INDEX idx_language ON metadata_and_text(language_document_char);},
+          %{CREATE INDEX idx_topics ON metadata_and_text(classify_topic_register)},
+        ]
+        conn_execute_array(sql_arr)
+      end
+      def text
+        if (@opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on)
+          print "\n          create documents TEXT indexes\n"
+        end
+        sql_arr=[
+          %{CREATE INDEX idx_clean ON doc_objects(clean);},
+          %{CREATE INDEX idx_endnote ON endnotes(clean);}
+        ]
+        conn_execute_array(sql_arr)
+      end
+      base
+      @opt.act[:psql][:set]==:on ? '' : text
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* db_tests.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/db_tests.rb"
+# <<sisu_document_header>>
+module SiSU_DbTests
+  class Test
+    def initialize(info,opt)
+      @ck,@opt=info,opt
+      unless @opt.act[:quiet][:set]==:on
+        puts @ck.tp[:fns]  if @ck.tp[:fns] and not @ck.tp[:fns].empty?
+        puts @ck.tp[:title] if @ck.tp[:title] and not @ck.tp[:title].empty?
+        puts @ck.tp[:creator] if @ck.tp[:creator] and not @ck.tp[:creator].empty?
+      end
+    end
+    def verify
+      unless @opt.act[:quiet][:set]==:on
+        puts @ck.tp[:fns].length.to_s                + ' checklength ' + @ck.tp[:fns]                if @ck.tp[:fns]                and @ck.tp[:fns].length                >@ck.lt_filename
+        puts @ck.tp[:title].length.to_s              + ' checklength ' + @ck.tp[:title]              if @ck.tp[:title]              and @ck.tp[:title].length              >@ck.lt_title
+        puts @ck.tp[:subtitle].length.to_s           + ' checklength ' + @ck.tp[:subtitle]           if @ck.tp[:subtitle]           and @ck.tp[:subtitle].length           >@ck.lt_subtitle
+        puts @ck.tp[:creator].length.to_s            + ' checklength ' + @ck.tp[:creator]            if @ck.tp[:creator]            and @ck.tp[:creator].length            >@ck.lt_creator
+        puts @ck.tp[:author_title].length.to_s       + ' checklength ' + @ck.tp[:author_title]       if @ck.tp[:author_title]       and @ck.tp[:author_title].length       >@ck.lt_author_title
+        puts @ck.tp[:illustrator].length.to_s        + ' checklength ' + @ck.tp[:illustrator]        if @ck.tp[:illustrator]        and @ck.tp[:illustrator].length        >@ck.lt_illustrator
+        puts @ck.tp[:translator].length.to_s         + ' checklength ' + @ck.tp[:translator]         if @ck.tp[:translator]         and @ck.tp[:translator].length         >@ck.lt_translator
+        puts @ck.tp[:prepared_by].length.to_s        + ' checklength ' + @ck.tp[:prepared_by]        if @ck.tp[:prepared_by]        and @ck.tp[:prepared_by].length        >@ck.lt_prepared_by
+        puts @ck.tp[:digitized_by].length.to_s       + ' checklength ' + @ck.tp[:digitized_by]       if @ck.tp[:digitized_by]       and @ck.tp[:digitized_by].length       >@ck.lt_digitized_by
+        puts @ck.tp[:subject].length.to_s            + ' checklength ' + @ck.tp[:subject]            if @ck.tp[:subject]            and @ck.tp[:subject].length            >@ck.lt_subject
+        puts @ck.tp[:description].length.to_s        + ' checklength ' + @ck.tp[:description]        if @ck.tp[:description]        and @ck.tp[:description].length        >@ck.lt_description
+        puts @ck.tp[:publisher].length.to_s          + ' checklength ' + @ck.tp[:publisher]          if @ck.tp[:publisher]          and @ck.tp[:publisher].length          >@ck.lt_publisher
+        puts @ck.tp[:contributor].length.to_s        + ' checklength ' + @ck.tp[:contributor]        if @ck.tp[:contributor]        and @ck.tp[:contributor].length        >@ck.lt_contributor
+        puts @ck.tp[:date].length.to_s               + ' checklength ' + @ck.tp[:date]               if @ck.tp[:date]               and @ck.tp[:date].length               >@ck.lt_date
+        puts @ck.tp[:date_created].length.to_s       + ' checklength ' + @ck.tp[:date_created]       if @ck.tp[:date_created]       and @ck.tp[:date_created].length       >@ck.lt_date
+        puts @ck.tp[:date_issued].length.to_s        + ' checklength ' + @ck.tp[:date_issued]        if @ck.tp[:date_issued]        and @ck.tp[:date_issued].length        >@ck.lt_date
+        puts @ck.tp[:date_valid].length.to_s         + ' checklength ' + @ck.tp[:date_valid]         if @ck.tp[:date_valid]         and @ck.tp[:date_valid].length         >@ck.lt_date
+        puts @ck.tp[:date_available].length.to_s     + ' checklength ' + @ck.tp[:date_available]     if @ck.tp[:date_available]     and @ck.tp[:date_available].length     >@ck.lt_date
+        puts @ck.tp[:date_modified].length.to_s      + ' checklength ' + @ck.tp[:date_modified]      if @ck.tp[:date_modified]      and @ck.tp[:date_modified].length      >@ck.lt_date
+        puts @ck.tp[:date_translated].length.to_s    + ' checklength ' + @ck.tp[:date_translated]    if @ck.tp[:date_translated]    and @ck.tp[:date_translated].length    >@ck.lt_date
+        puts @ck.tp[:date_added_to_site].length.to_s + ' checklength ' + @ck.tp[:date_added_to_site] if @ck.tp[:date_added_to_site] and @ck.tp[:date_added_to_site].length >@ck.lt_date
+        puts @ck.tp[:type].length.to_s               + ' checklength ' + @ck.tp[:type]               if @ck.tp[:type]               and @ck.tp[:type].length               >@ck.lt_type
+        puts @ck.tp[:format].length.to_s             + ' checklength ' + @ck.tp[:format]             if @ck.tp[:format]             and @ck.tp[:format].length             >@ck.lt_format
+        puts @ck.tp[:identifier].length.to_s         + ' checklength ' + @ck.tp[:identifier]         if @ck.tp[:identifier]         and @ck.tp[:identifier].length         >@ck.lt_identifier
+        puts @ck.tp[:source].length.to_s             + ' checklength ' + @ck.tp[:source]             if @ck.tp[:source]             and @ck.tp[:source].length             >@ck.lt_source
+        puts @ck.tp[:language].length.to_s           + ' checklength ' + @ck.tp[:language]           if @ck.tp[:language]           and @ck.tp[:language].length           >@ck.lt_language
+        puts @ck.tp[:language_original].length.to_s  + ' checklength ' + @ck.tp[:language_original]  if @ck.tp[:language_original]  and @ck.tp[:language_original].length  >@ck.lt_language_original
+        puts @ck.tp[:relation].length.to_s           + ' checklength ' + @ck.tp[:relation]           if @ck.tp[:relation]           and @ck.tp[:relation].length           >@ck.lt_relation
+        puts @ck.tp[:coverage].length.to_s           + ' checklength ' + @ck.tp[:coverage]           if @ck.tp[:coverage]           and @ck.tp[:coverage].length           >@ck.lt_coverage
+        puts @ck.tp[:rights].length.to_s             + ' checklength ' + @ck.tp[:rights]             if @ck.tp[:rights]             and @ck.tp[:rights].length             >@ck.lt_rights
+        puts @ck.tp[:copyright].length.to_s          + ' checklength ' + @ck.tp[:copyright]          if @ck.tp[:copyright]          and @ck.tp[:copyright].length          >@ck.lt_copyright
+        puts @ck.tp[:owner].length.to_s              + ' checklength ' + @ck.tp[:owner]              if @ck.tp[:owner]              and @ck.tp[:owner].length              >@ck.lt_owner
+        puts @ck.tp[:keywords].length.to_s           + ' checklength ' + @ck.tp[:keywords]           if @ck.tp[:keywords]           and @ck.tp[:keywords].length           >@ck.lt_keywords
+        puts @ck.tp[:abstract].length.to_s           + ' checklength ' + @ck.tp[:abstract]           if @ck.tp[:abstract]           and @ck.tp[:abstract].length           >@ck.lt_abstract
+        puts @ck.tp[:comment].length.to_s            + ' checklength ' + @ck.tp[:comment]            if @ck.tp[:comment]            and @ck.tp[:comment].length            >@ck.lt_comment
+        puts @ck.tp[:loc].length.to_s                + ' checklength ' + @ck.tp[:loc]                if @ck.tp[:loc]                and @ck.tp[:loc].length                >@ck.lt_loc
+        puts @ck.tp[:dewey].length.to_s              + ' checklength ' + @ck.tp[:dewey]              if @ck.tp[:dewey]              and @ck.tp[:dewey].length              >@ck.lt_dewey
+        puts @ck.tp[:isbn].length.to_s               + ' checklength ' + @ck.tp[:isbn]               if @ck.tp[:isbn]               and @ck.tp[:isbn].length               >@ck.lt_isbn
+        puts @ck.tp[:pg].length.to_s                 + ' checklength ' + @ck.tp[:pg]                 if @ck.tp[:pg]                 and @ck.tp[:pg].length                 >@ck.lt_pg
+        puts @ck.tp[:topic_register].length.to_s     + ' checklength ' + @ck.tp[:topic_register]     if @ck.tp[:topic_register]     and @ck.tp[:topci_register].length     >@ck.lt_topic_register
+        puts @ck.tp[:date]                                                                           if @ck.tp[:date] and not @ck.tp[:date].empty? and @ck.tp[:date] !~/\d\d-\d\d-\d\d/
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    db sql
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/digests.org b/org/digests.org
new file mode 100644
index 00000000..7107f53f
--- /dev/null
+++ b/org/digests.org
@@ -0,0 +1,330 @@
+-*- mode: org -*-
+#+TITLE:       sisu digests
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:digests:
+#+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
+
+* digests.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/digests.rb"
+# <<sisu_document_header>>
+module SiSU_DigestView
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+  require_relative 'prog_text_translation'              # prog_text_translation.rb
+  require_relative 'shared_markup_alt.rb'               # shared_markup_alt.rb
+  class Source
+    @@dg=nil
+    def initialize(opt)
+      @opt=opt
+      @fnb=@opt.fnb
+      @@endnotes_para=[]
+      @@dg=nil
+      @dg=@@dg ||=SiSU_Env::InfoEnv.new.digest(opt).type
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+    end
+    def read
+      begin
+        @env,@md,@ao_array=@particulars.env,@particulars.md,@particulars.ao_array
+        unless @opt.act[:quiet][:set]==:on
+          tool=(@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on) \
+          ? "#{@env.program.text_editor} file://#{@md.file.output_path.hash_digest.dir}/#{@md.file.base_filename.hash_digest}"
+          : "[#{@opt.f_pth[:lng_is]}] #{@opt.fno}"
+          (@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on) \
+          ? SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              "Document #{@dg} Digests",
+              tool
+            ).green_hi_blue
+          : SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              "Document #{@dg} Digests",
+              tool
+            ).green_title_hi
+          if @opt.act[:verbose_plus][:set]==:on \
+          or @opt.act[:maintenance][:set]==:on
+            SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              @opt.fns,
+              "file://#{@md.file.output_path.hash_digest.dir}/#{@md.file.base_filename.hash_digest}"
+            ).flow
+          end
+        end
+        if SiSU_Env::SystemCall.new.openssl
+          SiSU_DigestView::Source::Scroll.new(@particulars).songsheet
+        else
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).error('*EXITED* hash digests will not run without openssl')
+        end
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    private
+    class Scroll <Source
+      @@dl=nil
+      @@ds={
+        digests_clean: [],
+        digests_with_markup: [],
+        tree: [],
+        summary: [],
+      }
+      @@description,@@sc_info=[],[]
+      def initialize(particulars)
+        @particulars=particulars
+        @data,@env,@md=@particulars.ao_array,@particulars.env,@particulars.md
+        SiSU_Env::FileOp.new(@md).mkdir
+        @@dg ||=@env.digest(@md.opt).type
+        @@dl ||=@env.digest(@md.opt).length
+        @dg,@dl=@@dg,@@dl
+        l=SiSU_Env::StandardiseLanguage.new(@md.opt.lng).language
+        @language=l[:n]
+        @tr=SiSU_Translate::Source.new(@md,@language)
+        @sp=' '
+      end
+      def songsheet
+        @@description,@@ds[:digests_clean],@@ds[:digests_with_markup],@@ds[:tree],@@ds[:summary],@@sc_info=[],[],[],[],[],[]
+        message_digest
+        ao_structure
+        supplementary
+        output
+      end
+      def spaces
+        Ax[:spaces]
+      end
+      def description(f,e='')
+        puts f + e.to_s if @md.opt.act[:verbose_plus][:set]==:on
+        @@description << f << e
+      end
+      def digests_clean(f,e='')
+        puts f if @md.opt.act[:verbose_plus][:set]==:on
+        @@ds[:digests_clean] << f + "\n"
+      end
+      def digests_with_markup(f)
+        puts f if @md.opt.act[:verbose_plus][:set]==:on
+        @@ds[:digests_with_markup] << f + "\n"
+      end
+      def ao_structure_tree(f,e='')
+        puts f + e.to_s if @md.opt.act[:verbose_plus][:set]==:on
+        @@ds[:tree] << f << e
+      end
+      def ao_structure_summary(f,e='')
+        puts f + e.to_s if @md.opt.act[:verbose_plus][:set]==:on
+        @@ds[:summary] << f << e
+      end
+      def rcinfo(f,e='')
+        puts f + e.to_s if @md.opt.act[:verbose_plus][:set]==:on
+        @@sc_info << f << e
+      end
+      def output
+        file=SiSU_Env::FileOp.new(@md)
+        filename_digest=file.write_file.hash_digest
+        filename_digest << @@description.join << @@ds[:digests_clean].join << @@ds[:digests_with_markup].join << @@ds[:tree].join << @@ds[:summary].join << @@sc_info.join
+      end
+      def rgx_txt(txt)
+        txt=txt.gsub(/([()])/,"\\\\\\1")
+      end
+      def message_digest
+        @p=[]
+        @g,@v,@r='','',''
+        manifest="#{@env.url.root}/#{@md.fnb}/sisu_manifest.html"
+        description("#{@md.title.full}\n")
+        description("#{@md.author}\n")
+        description("#{@md.fns}\n")
+        description("----------------------------------------------\n")
+        description("SiSU Document Content Certificate (Digest/DCC)\n")
+        description("----------------------------------------------\n")
+        description("                               #{@dg} digests\n")
+        description("------------\n")
+        description("Sourcefile digest:             #{@md.dgst[1]}\n")
+        description("  source filename:             #{@md.fns}\n")
+        description("available outputs:             #{manifest}\n")
+        description("------------\n")
+        description("Document Digests\n")
+      end
+      def ao_structure
+        a=%{\nocn     digests (#{@dg}) clean text (stripped markup)}
+        digests_clean(a)
+        data=@data
+        endnotes=nil
+        data.each do |t_o|
+          dgst=SiSU_TextRepresentation::ModifiedTextPlusHashDigest.new(@md,t_o).composite.dgst
+          if dgst
+            if t_o.is==:heading
+              digests_clean("#{@sp*0}#{dgst[:ocn]}#{@sp*(8-dgst[:ocn].to_s.length)}#{dgst[:dgst_stripped_txt]} #{dgst[:is]} #{t_o.lv}")
+            elsif t_o.is==:heading_insert
+              digests_clean("#{@sp*0}[#{dgst[:ocn]}]#{@sp*(6-dgst[:ocn].to_s.length)}#{dgst[:dgst_stripped_txt]} #{dgst[:is]} #{t_o.lv}")
+            else
+              digests_clean("#{@sp*0}#{dgst[:ocn]}#{@sp*(8-dgst[:ocn].to_s.length)}#{dgst[:dgst_stripped_txt]} #{dgst[:is]}")
+              if dgst[:images]
+                dgst[:images].each do |img|
+                  digests_clean("#{@sp*8}#{img[:img_dgst]}#{@sp*66}#{img[:img_type]} #{img[:img_name]}")
+                end
+              end
+            end
+            if dgst[:endnotes]
+              dgst[:endnotes].each do |en|
+                digests_clean("#{@sp*8}#{en[:note_dgst]} note [#{en[:note_number]}]")
+                endnotes=en[:note_number]
+              end
+            end
+          end
+        end
+        b=%{\nocn     object (#{@dg}) digests (object includes its markup & endnotes (if any))}
+        digests_with_markup(b)
+        data.each do |t_o|
+          dgst=SiSU_TextRepresentation::ModifiedTextPlusHashDigest.new(@md,t_o).composite.dgst
+          if dgst
+            if t_o.is==:heading
+              digests_with_markup("#{@sp*0}#{dgst[:ocn]}#{@sp*(8-dgst[:ocn].to_s.length)}#{dgst[:dgst_markedup_txt]} #{dgst[:is]} #{t_o.lv}")
+            elsif t_o.is==:heading_insert
+              digests_with_markup("#{@sp*0}[#{dgst[:ocn]}]#{@sp*(6-dgst[:ocn].to_s.length)}#{dgst[:dgst_markedup_txt]} #{dgst[:is]} #{t_o.lv}")
+            else
+              digests_with_markup("#{@sp*0}#{dgst[:ocn]}#{@sp*(8-dgst[:ocn].to_s.length)}#{dgst[:dgst_markedup_txt]} #{dgst[:is]}")
+            end
+          end
+        end
+        l=Hash.new(0)
+        ocn=nil
+        ao_structure_tree("------------\n")
+        ao_structure_tree("document structure[*]\n")
+        data.each do |t_o|
+          if t_o.is==:heading
+            x=case t_o.ln
+            when 0 then l[0] +=1
+              spaces*0 << ':A'
+            when 1 then l[1] +=1
+              spaces*1 << ':B'
+            when 2 then l[2] +=1
+              spaces*2 << ':C'
+            when 3 then l[3] +=1
+              spaces*3 << ':D'
+            when 4 then l[4] +=1
+              spaces*4 << '1'
+            when 5 then l[5] +=1
+              spaces*5 << '2'
+            when 6 then l[6] +=1
+              spaces*6 << '3'
+            else nil
+            end
+          end
+          ocn=t_o.ocn if defined? t_o.ocn and t_o.is !=:heading_insert
+          ao_structure_tree("#{x}\n") if x and not x.empty?
+        end
+        ao_structure_tree("  [*] heading levels\n")
+        ao_structure_summary("------------\n")
+        ao_structure_summary("document structure[*]\n")
+        [0,1,2,3,4,5,6].each do |y|
+          v=case y
+          when 0 then ':A'
+          when 1 then ':B'
+          when 2 then ':C'
+          when 3 then ':D'
+          when 4 then '1 '
+          when 5 then '2 '
+          when 6 then '3 '
+          end
+          ao_structure_summary("#{v}            = #{l[y]}\n") if l[y] > 0
+        end
+        ao_structure_summary("objects (ocn) = #{ocn}\n")
+        ao_structure_summary("endnotes      = #{endnotes}\n")
+        ao_structure_summary("  [*] number of headers (@) and of each heading level (:A to :D and 1 to 3)\n")
+      end
+      def supplementary
+        if defined? @md.sc_number \
+        and @md.sc_number
+          rcinfo("------------\n")
+          rcinfo("source control information\n")
+          rcinfo("  (the following information while not important for document content certification\n   may help the publisher in locating the version referred to)\n")
+          rcinfo("  rcs version number:            #{@md.sc_number}\n")
+          if defined? @md.sc_date \
+          and @md.sc_date
+            rcinfo("  rcs date:                      #{@md.sc_date}\n")
+          end
+          if defined? @md.sc_time \
+          and @md.sc_time
+            rcinfo("  rcs time:                      #{@md.sc_time}\n")
+          end
+        end
+        rcinfo("------------\n")
+        rcinfo("Note: the time generated related fields (text and digests) will vary between otherwise identical document outputs\n")
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    digests
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/env.org b/org/env.org
new file mode 100644
index 00000000..fafc90ef
--- /dev/null
+++ b/org/env.org
@@ -0,0 +1,8610 @@
+-*- mode: org -*-
+#+TITLE:       sisu environment
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:se:
+#+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
+
+* sisu environment
+** se.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se.rb"
+# <<sisu_document_header>>
+@@cX=nil
+module SiSU_Env
+  require_relative 'constants'                         # constants.rb
+  require_relative 'utils'                             # utils.rb
+  require_relative 'se_date'                           # se_date.rb
+  require_relative 'se_info_system'                    # se_info_system.rb
+  require_relative 'se_load'                           # se_load.rb
+  require_relative 'se_get_init'                       # se_get_init.rb
+  require_relative 'se_envcall'                        # se_envcall.rb
+  require_relative 'se_programs'                       # se_programs.rb
+  require_relative 'se_standardise_lang'               # se_standardise_lang.rb
+  require_relative 'se_info_env'                       # se_info_env.rb
+  require_relative 'se_processing'                     # se_processing.rb
+  require_relative 'se_filemap'                        # se_filemap.rb
+  require_relative 'se_file_op'                        # se_file_op.rb
+  require_relative 'se_cleanoutput'                    # se_cleanoutput.rb
+  require_relative 'se_remotes'                        # se_remotes.rb
+  require_relative 'se_version'                        # se_version.rb
+  require_relative 'se_db'                             # se_db.rb
+  require_relative 'se_css'                            # se_css.rb
+  require_relative 'se_clear'                          # se_clear.rb
+  require_relative 'se_createsite'                     # se_createsite.rb
+  require_relative 'se_info_port'                      # se_info_port.rb
+  begin
+    require 'singleton'
+    require 'fileutils'
+      include FileUtils::Verbose
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('singleton or fileutils NOT FOUND (LoadError)')
+  end
+  @@noyaml=false
+  class InfoDate < SiSU_Info_Date::InfoDate                # se_date.rb
+  end
+  class InfoSystemGen < SiSU_Info_Sys_Gen::InfoSystemGen   # se_info_system.rb
+  end
+  class InfoSystem < SiSU_Info_Sys::InfoSystem             # se_info_system.rb
+  end
+  class Load < SiSU_Load::Load                             # se_load.rb
+  end
+  class GetInit < SiSU_Get_Init::GetInit                   # se_get_init.rb
+  end
+  class EnvCall < SiSU_Env_Call::EnvCall                   # se_envcall.rb
+  end
+  class SystemCall < SiSU_Sys_Call::SystemCall             # se_programs.rb
+  end
+  class StandardiseLanguage < SiSU_Standardise_Lang::StandardiseLanguage # se_standardise_lang.rb
+  end
+  class InfoEnv < SiSU_Info_Env::InfoEnv                   # se_info_env.rb
+  end
+  class InfoProcessingFlag < SiSU_Info_Processing_Flag::InfoProcessingFlag # se_processing.rb
+  end
+  class InfoSettings < SiSU_Info_Set::InfoSettings         # se_programs.rb
+  end
+  class FileMap < SiSU_File_Map::FileMap                   # se_filemap.rb
+  end
+  class CleanOutput < SiSU_Clean_Output::CleanOutput       # se_cleanoutput.rb
+  end
+  class InfoRemoteHost < SiSU_Info_Remote_Host::InfoRemoteHost # se_remotes.rb
+  end
+  class InfoRemote < SiSU_Info_Remote::InfoRemote          # se_remotes.rb
+  end
+  class InfoVersion < SiSU_Info_Version::InfoVersion       # se_version.rb
+  end
+  class InfoAbout < SiSU_Info_About::InfoAbout             # se_version.rb
+  end
+  class InfoFile < SiSU_Info_File::InfoFile                # se_file_op.rb
+  end
+  class ProcessingSettings < SiSU_Processing_Settings::ProcessingSettings # se_processing.rb
+  end
+  class InfoDb < SiSU_Info_Db::InfoDb                      # se_db.rb
+  end
+  class DbOp < SiSU_Db_Op::DbOp                            # se_db.rb
+  end
+  class FileOp < SiSU_File_Op::FileOp                      # se_file_op.rb
+  end
+  class FilenameLanguageCodeInsert < SiSU_Filename_Lang::FilenameLanguageCodeInsert # se_file_op.rb
+  end
+  class CreateFile < SiSU_Create_File::CreateFile          # se_file_op.rb
+  end
+  class Clear < SiSU_Clear::Clear                          # se_clear.rb
+  end
+  class InfoPort < SiSU_Info_Port::InfoPort                # se_info_port.rb
+  end
+  class InfoProgram < SiSU_Info_Program::InfoProgram       # se_programs.rb
+  end
+  class CSS_Default < SiSU_CSS::CSS_Default                # se_css.rb
+  end
+  class CSS_Select < SiSU_CSS::CSS_Select                  # se_css.rb
+  end
+  class CSS_Stylesheet < SiSU_CSS::CSS_Stylesheet          # se_css.rb
+  end
+  class CreateSite < SiSU_Create_Site::CreateSite          # se_createsite.rb
+  end
+end
+module SiSU_Screen
+  require_relative 'utils_screen_text_color'               # utils_screen_text_color.rb
+end
+module SiSU_Errors
+  require_relative 'errors'                             # errors.rb
+end
+__END__
+#+END_SRC
+
+** se_cleanoutput.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se_cleanoutput.rb"
+# <<sisu_document_header>>
+module SiSU_Clean_Output
+  require_relative 'constants'                             # constants.rb
+  require_relative 'utils'                                 # utils.rb
+  class CleanOutput
+    begin
+      require 'fileutils'
+        include FileUtils::Verbose
+    rescue LoadError
+      SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+        error('fileutils NOT FOUND (LoadError)')
+    end
+    def initialize(opt)
+      @opt=opt
+      z=SiSU_Env::FileMap.new(opt)
+      zap=z.local_sisu_source
+      if opt.cmd =~ /h/i
+        zap=Dir.glob(zap).join(' ')
+        @zap=if opt.cmd !~ /w/
+          zap.gsub(/#{@source_path}\/concordance.html/,'')
+        else zap
+        end
+      end
+      @env=SiSU_Env::InfoEnv.new
+    end
+    def zap
+      def deletion(fn)
+        if FileTest.file?(fn)==true
+          File.delete(fn)
+          tell=SiSU_Screen::Ansi.new(@opt.cmd,@opt.fns, 'remove: ' + fn)
+          tell.warn unless @opt.cmd =~/q/
+        end
+      end
+      def remove_output
+        if @opt.act[:maintenance][:set] == :on
+          m=InfoFile.new(@opt.fnc)
+          tell=SiSU_Screen::Ansi.new(
+            @opt.cmd,@opt.fns,
+            'remove maintenance files from: ' + @env.processing_path.ao
+          )
+          tell.warn unless @opt.cmd =~/q/
+          deletion(m.marshal.ao_content)
+          deletion(m.marshal.ao_idx_sst_rel_html_seg)
+          deletion(m.ao_idx_sst_rel)
+          deletion(m.ao_idx_html)
+          deletion(m.ao_idx_xhtml)
+          deletion(m.ao_metadata)
+          deletion(m.ao_map_nametags)
+          deletion(m.ao_map_ocn_htmlseg)
+          deletion(m.html_tune)
+        end
+        md=SiSU_Param::Parameters.new(@opt).get
+        f=SiSU_Env::FileOp.new(md)
+        deletion(f.place_file.html_segtoc.dir)
+        deletion(f.place_file.html_scroll.dir)
+        deletion(f.place_file.html_book_index.dir)
+        deletion(f.place_file.html_concordance.dir)
+        deletion(f.place_file.epub.dir)
+        deletion("#{f.output_path.pdf.dir}/#{f.base_filename.pdf_p_letter}")
+        deletion("#{f.output_path.pdf.dir}/#{f.base_filename.pdf_l_letter}")
+        deletion("#{f.output_path.pdf.dir}/#{f.base_filename.pdf_p_a4}")
+        deletion("#{f.output_path.pdf.dir}/#{f.base_filename.pdf_l_a4}")
+        deletion("#{f.output_path.pdf.dir}/#{f.base_filename.pdf_p_a5}")
+        deletion("#{f.output_path.pdf.dir}/#{f.base_filename.pdf_l_a5}")
+        deletion("#{f.output_path.pdf.dir}/#{f.base_filename.pdf_p_b5}")
+        deletion("#{f.output_path.pdf.dir}/#{f.base_filename.pdf_l_b5}")
+        deletion("#{f.output_path.pdf.dir}/#{f.base_filename.pdf_p_legal}")
+        deletion("#{f.output_path.pdf.dir}/#{f.base_filename.pdf_p_legal}")
+        deletion(f.place_file.odt.dir)
+        deletion(f.place_file.xhtml.dir)
+        deletion(f.place_file.xml_sax.dir)
+        deletion(f.place_file.xml_dom.dir)
+        deletion(f.place_file.xml_scaffold_structure_sisu.dir)
+        deletion(f.place_file.xml_scaffold_structure_collapse.dir)
+        deletion(f.place_file.info.dir)
+        deletion(f.place_file.manpage.dir)
+        deletion(f.place_file.sqlite_discrete.dir)
+        deletion(f.place_file.txt.dir)
+        deletion(f.place_file.hash_digest.dir)
+        deletion(f.place_file.manifest.dir)
+        deletion(f.place_file.qrcode_md.dir)
+        deletion(f.place_file.qrcode_title.dir)
+        deletion(f.place_file.src.dir)
+        deletion(f.place_file.sisupod.dir)
+      end
+      self
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** se_clear.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se_clear.rb"
+# <<sisu_document_header>>
+module SiSU_Clear
+  require_relative 'constants'                             # constants.rb
+  require_relative 'utils'                                 # utils.rb
+  require_relative 'se_info_env'                           # se_info_env.rb
+  begin
+    require 'singleton'
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('singleton NOT FOUND (LoadError)')
+  end
+  class Clear < SiSU_Info_Env::InfoEnv                     # se_info_env.rb
+    #todo unify with FileOp
+    def initialize(cmd,fns,operation='')
+      @cmd=cmd
+      begin
+        super(fns)
+        @env=SiSU_Env::InfoEnv.new(fns)
+        SiSU_Env::InfoVersion.instance
+        if operation.class.inspect =~/SiSU_Param/
+          @md=operation
+        end
+        case operation #watch
+        when /pdf/                 then @env_out=''
+        when /sql/
+        when /xml|plaintext|ascii/ then @env_out=@env.path.output + @fnb #check change of name to plaintext from ascii
+        else
+          if defined? @md.sfx_src \
+          and @md.sfx_src =~/ss[ftsumc]/
+            @env_out_root=@env.path.output
+            @env_out="#{@env.path.output}/#{@fnb}"
+            @@publisher='SiSU http://www.jus.uio.no/sisu'
+            @env_pdf="#{@env_out_root}/pdf"
+          end
+        end
+      rescue
+        SiSU_Screen::Ansi.new(@cmd,$!,$@).rescue do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    def param_instantiate
+      @cX||=SiSU_Screen::Ansi.new(@cmd)
+      @@date=SiSU_Env::InfoDate.new
+      @@publisher='SiSU scribe'
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** se_createsite.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se_createsite.rb"
+# <<sisu_document_header>>
+module SiSU_Create_Site
+  require_relative 'constants'                             # constants.rb
+  require_relative 'html_parts'                            # html_parts.rb
+  require_relative 'utils'                                 # utils.rb
+  require_relative 'utils_screen_text_color'               # utils_screen_text_color.rb
+  require_relative 'se_info_env'                           # se_info_env.rb
+  begin
+    require 'fileutils'
+      include FileUtils::Verbose
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('fileutils NOT FOUND (LoadError)')
+  end
+  class CreateSite < SiSU_Info_Env::InfoEnv                # se_info_env.rb
+    require_relative 'css'                                 # css.rb
+      include SiSU_Style
+    def initialize(opt)
+      @opt=opt
+      @env=SiSU_Env::InfoEnv.new
+      @init=SiSU_Env::GetInit.new
+      @home,@pwd=ENV['HOME'],ENV['PWD'] #@pwd=Dir.pwd
+      @rc=SiSU_Env::GetInit.new.sisu_yaml.rc
+      @home_set=SiSU_Proj_HTML::Home.new
+    end
+    def create_default_sisu_homepage(action=:none)
+      if action==:none
+        puts %{  place your homepages in directory:\n    "#{@env.path.rc}/home/*.html"\n  (no action taken)}
+      else # turned off, unless something other than :none passed
+        puts %{  place your homepages in directory:\n    "#{@env.path.rc}/home/*.html"\n  (in order to replace default sisu homepage)}
+        filename_homepage=
+          @env.path.webserv + '/' \
+          + @env.path.base_markup_dir_stub + '/index.html'
+        filename_home_toc=
+          @env.path.webserv + '/' \
+          + @env.path.base_markup_dir_stub + '/toc.html'
+        file_homepage=File.new(filename_homepage,'w')
+        file_home_toc=File.new(filename_home_toc,'w')
+        file_homepage << @home_set.homepage
+        file_home_toc << @home_set.homepage
+        file_homepage.close
+        file_home_toc.close
+      end
+    end
+    def homepage
+      home_pages_manually_created=Dir.glob("#{@env.path.rc}/home/*.html")
+      FileUtils::mkdir_p("#{@env.path.webserv}/#{@env.path.base_markup_dir_stub}") \
+        unless FileTest.directory?("#{@env.path.webserv}/#{@env.path.base_markup_dir_stub}")
+      if home_pages_manually_created.length > 0
+        home_pages_manually_created.each do |homepage|
+          FileUtils.cp(homepage,"#{@env.path.webserv}/#{@env.path.base_markup_dir_stub}")
+        end
+      else
+        create_default_sisu_homepage(:none) # :default
+      end
+    end
+    def cp_images(src_path,dest_path)
+      if FileTest.directory?(src_path)
+        FileUtils::cd(src_path)
+        source=Dir.glob("*.{png,jpg,gif,ico}")
+        FileUtils::mkdir_p(dest_path) unless FileTest.directory?(dest_path)
+        FileUtils::chmod(0755,dest_path)
+        source.each do |i|
+          if FileTest.file?(i)
+            FileUtils::cp(i,"#{dest_path}/#{i}")
+            FileUtils::chmod(0644,"#{dest_path}/#{i}")
+          else STDERR.puts %{\t*WARN* did not find image - "#{i}" [#{__FILE__}:#{__LINE__}]}
+          end
+        end
+        FileUtils::cd(@pwd)
+      else STDERR.puts %{\t*WARN* did not find - #{src_path} [#{__FILE__}:#{__LINE__}]}
+      end
+    end
+    def cp_local_images
+      src=@pwd + '/_sisu/image'
+      dest=
+        @env.path.webserv + '/' \
+        + @env.path.base_markup_dir_stub + '/_sisu/image'
+      cp_images(src,dest) if FileTest.directory?(src)
+    end
+    def cp_external_images
+      src=@env.processing_path.processing + '/' \
+      + 'external_document/image'
+      dest=
+        @env.path.webserv + '/' \
+        + @env.path.base_markup_dir_stub + '/' \
+        + '_sisu/image_external'
+      if FileTest.directory?(src)
+        cp_images(src,dest) if FileTest.directory?(src)
+      end
+    end
+    def cp_webserver_images
+      src=@env.path.image_source
+      dest_arr=[
+        "#{@env.path.webserv}/_sisu/image",
+        "#{@env.path.webserv}/#{@env.path.base_markup_dir_stub}/_sisu/image",
+      ]
+      dest_arr.each do |dest|
+        cp_images(src,dest) if FileTest.directory?(src)
+      end
+    end
+    def cp_webserver_images_local      #this should not have been necessary
+      src=@env.path.image_source
+      dest=
+        @env.path.webserv + '/' \
+        + @env.path.base_markup_dir_stub + '/' \
+        + '_sisu/image'
+      cp_images(src,dest) if FileTest.directory?(src)
+    end
+    def cp_base_images #fix images
+      src=SiSU_is.path_base_system_data? + '/image'
+      dest_arr=[
+        "#{@env.path.webserv}/_sisu/image_sys",
+        "#{@env.path.webserv}/#{@env.path.base_markup_dir_stub}/_sisu/image_sys"
+      ]
+      dest_arr.each do |dest|
+        cp_images(src,dest) if FileTest.directory?(src)
+      end
+    end
+    def cp_css
+      FileUtils::mkdir_p("#{@env.path.output}/#{@env.path.style}") \
+        unless FileTest.directory?("#{@env.path.output}/#{@env.path.style}")
+      css_path=[
+        '/etc/sisu/css',
+        "#{@home}/.sisu/css",
+        "#{@pwd}/_sisu/css",
+      ] #BROKEN
+      if defined? @rc['permission_set']['css_modify'] \
+      and @rc['permission_set']['css_modify']
+        SiSU_Screen::Ansi.new(
+          @opt.selections.str,
+          "*WARN* modify is css set to: #{@rc['permission_set']['css_modify']}"
+        ).warn if @opt.act[:verbose_plus][:set]==:on \
+        or @opt.act[:maintenance][:set]==:on
+        css_path.each do |x|
+          if FileTest.directory?(x)
+            FileUtils::cd(x)
+            source=Dir.glob("*.{css}")
+            source.each do |i|
+              if FileTest.file?(i)
+                FileUtils::cp(
+                  i,
+                  @env.path.output + '/' + @env.path.style
+                )
+              else STDERR.puts %{\t*WARN* did not find css - "#{i}" [#{__FILE__}:#{__LINE__}]}
+              end
+            end
+            FileUtils::cd(@pwd)
+          end
+        end
+      else
+        SiSU_Screen::Ansi.new(
+          @opt.selections.str,
+          "*WARN* modify css is not set or is set to: false"
+        ).warn if @opt.act[:verbose_plus][:set]==:on \
+        or @opt.act[:maintenance][:set]==:on
+      end
+      fn_css=SiSU_Env::CSS_Default.new
+      css=SiSU_Style::CSS.new
+      path_style="#{@env.path.output}/#{@env.path.style}"
+      FileUtils::mkdir_p(path_style) \
+        unless FileTest.directory?(path_style)
+      if @opt.act[:site_init][:set]==:on \
+      or not FileTest.file?("#{path_style}/#{fn_css.homepage}")
+        style=File.new("#{path_style}/#{fn_css.homepage}",'w')
+        style << css.homepage
+        style.close
+      end
+      if @opt.act[:site_init][:set]==:on \
+      or not FileTest.file?("#{path_style}/#{fn_css.html_tables}")
+        style=File.new("#{path_style}/#{fn_css.html_tables}",'w')
+        style << css.html_tables
+        style.close
+      end
+      if @opt.act[:site_init][:set]==:on \
+      or not FileTest.file?("#{path_style}/#{fn_css.html}")
+        style=File.new("#{path_style}/#{fn_css.html}",'w')
+        style << css.html
+        style.close
+      end
+      if @opt.act[:site_init][:set]==:on \
+      or not FileTest.file?("#{path_style}/#{fn_css.harvest}")
+        style=File.new("#{path_style}/#{fn_css.harvest}",'w')
+        style << css.harvest
+        style.close
+      end
+      if @opt.act[:site_init][:set]==:on \
+      or (@opt.act[:xml_sax][:set]==:on \
+      and not FileTest.file?("#{path_style}/#{fn_css.xml_sax}"))
+        style=File.new("#{path_style}/#{fn_css.xml_sax}",'w')
+        style << css.xml_sax
+        style.close
+      end
+      if @opt.act[:site_init][:set]==:on \
+      or (@opt.act[:xml_dom][:set]==:on \
+      and not FileTest.file?("#{path_style}/#{fn_css.xml_dom}"))
+        style=File.new("#{path_style}/#{fn_css.xml_dom}",'w')
+        style << css.xml_dom
+        style.close
+      end
+      if @opt.act[:site_init][:set]==:on \
+      or (@opt.act[:xml_docbook_book][:set] == :on \
+      and not FileTest.file?("#{path_style}/#{fn_css.xml_docbook}"))
+        style=File.new("#{path_style}/#{fn_css.xml_docbook}",'w')
+        style << css.xml_docbook
+        style.close
+      end
+      if @opt.act[:site_init][:set]==:on \
+      or (@opt.act[:xhtml][:set] == :on \
+      and not FileTest.file?("#{path_style}/#{fn_css.xhtml}"))
+        style=File.new("#{path_style}/#{fn_css.xhtml}",'w')
+        style << css.xhtml
+        style.close
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** se_css.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se_css.rb"
+# <<sisu_document_header>>
+module SiSU_CSS
+  require_relative 'constants'                             # constants.rb
+  require_relative 'utils'                                 # utils.rb
+  require_relative 'se_info_env'                           # se_info_env.rb
+  class CSS_Default
+    def html
+      'html.css'
+    end
+    def html_tables
+      'html_tables.css'
+    end
+    def xhtml
+      'xhtml.css'
+    end
+    def xml_sax
+      'sax.css'
+    end
+    def xml_dom
+      'dom.css'
+    end
+    def xml_docbook
+      'docbook.css'
+    end
+    def homepage
+      'homepage.css'
+    end
+    def harvest
+      'harvest.css'
+    end
+  end
+  class CSS_Select < SiSU_Info_Env::InfoEnv                # se_info_env.rb
+    def initialize(md)
+      @md=md
+      @env=SiSU_Env::InfoEnv.new('',@md)
+    end
+    def html
+      if @md.doc_css \
+      and FileTest.file?("#{@env.path.output}/#{@env.path.style}/#{@md.doc_css}_html.css")
+        @md.doc_css + '_html.css'
+      elsif FileTest.file?("#{@env.path.output}/#{@env.path.style}/#{@env.path.base_markup_dir_stub}_html.css")
+        @env.path.base_markup_dir_stub + '_html.css'
+      else
+        SiSU_Env::CSS_Default.new.html
+      end
+    end
+    def html_tables
+      if @md.doc_css \
+      and FileTest.file?("#{@env.path.output}/#{@env.path.style}/#{@md.doc_css}_html_tables.css")
+        @md.doc_css + '_html_tables.css'
+      elsif FileTest.file?("#{@env.path.output}/#{@env.path.style}/#{@env.path.base_markup_dir_stub}_html_tables.css")
+        @env.path.base_markup_dir_stub + '_html_tables.css'
+      else SiSU_Env::CSS_Default.new.html_tables
+      end
+    end
+    def xhtml
+      if @md.doc_css \
+      and FileTest.file?("#{@env.path.output}/#{@env.path.style}/#{@md.doc_css}_xhtml.css")
+        @md.doc_css + '_xhtml.css'
+      elsif FileTest.file?("#{@env.path.output}/#{@env.path.style}/#{@env.path.base_markup_dir_stub}_xhtml.css")
+        @env.path.base_markup_dir_stub + '_xhtml.css'
+      else SiSU_Env::CSS_Default.new.xhtml
+      end
+    end
+    def xml_sax
+      if @md.doc_css \
+      and FileTest.file?("#{@env.path.output}/#{@env.path.style}/#{@md.doc_css}_xml_sax.css")
+        @md.doc_css + '_xml_sax.css'
+      elsif FileTest.file?("#{@env.path.output}/#{@env.path.style}/#{@env.path.base_markup_dir_stub}_xml_sax.css")
+        @env.path.base_markup_dir_stub + '_xml_sax.css'
+      else SiSU_Env::CSS_Default.new.xml_sax
+      end
+    end
+    def xml_dom
+      if @md.doc_css \
+      and FileTest.file?("#{@env.path.output}/#{@env.path.style}/#{@md.doc_css}_xml_dom.css")
+        @md.doc_css + '_xml_dom.css'
+      elsif FileTest.file?("#{@env.path.output}/#{@env.path.style}/#{@env.path.base_markup_dir_stub}_xml_dom.css")
+        @env.path.base_markup_dir_stub + '_xml_dom.css'
+      else SiSU_Env::CSS_Default.new.xml_dom
+      end
+    end
+    def xml_docbook
+      if @md.doc_css \
+      and FileTest.file?("#{@env.path.output}/#{@env.path.style}/#{@md.doc_css}_docbook.css")
+        @md.doc_css + '_xml_dom.css'
+      elsif FileTest.file?("#{@env.path.output}/#{@env.path.style}/#{@env.path.base_markup_dir_stub}_docbook.css")
+        @env.path.base_markup_dir_stub + '_docbook.css'
+      else SiSU_Env::CSS_Default.new.xml_docbook
+      end
+    end
+    def homepage
+      if @md.doc_css \
+      and FileTest.file?("#{@env.path.output}/#{@env.path.style}/#{@md.doc_css}_homepage.css")
+        @md.doc_css + '_homepage.css'
+      elsif FileTest.file?("#{@env.path.output}/#{@env.path.style}/#{@env.path.base_markup_dir_stub}_homepage.css")
+        @env.path.base_markup_dir_stub + '_homepage.css'
+      else SiSU_Env::CSS_Default.new.homepage
+      end
+    end
+  end
+  class CSS_Stylesheet
+    def initialize(md)
+      @md=md
+      @css=SiSU_Env::CSS_Select.new(@md)
+      @env=SiSU_Env::InfoEnv.new('',@md)
+      @file=SiSU_Env::FileOp.new(@md)
+    end
+    def html
+      stylesheet=
+        @file.path_rel_links.html_scroll_css \
+        + @env.path.style + '/' \
+        + @css.html
+      %{  <link href="#{stylesheet}" rel="stylesheet">}
+    end
+    def html_seg
+      stylesheet=
+        @file.path_rel_links.html_seg_css \
+        + @env.path.style + '/' \
+        + @css.html
+      %{  <link href="#{stylesheet}" rel="stylesheet">}
+    end
+    def html_tables
+      stylesheet=
+        @file.path_rel_links.html_seg_css \
+        + @env.path.style + '/' \
+        + @css.html
+      %{  <link href="#{stylesheet}" rel="stylesheet">}
+    end
+    def xhtml_epub
+      %{  <link rel="stylesheet" href="css/xhtml.css" type="text/css" />}
+    end
+    def epub
+      xhtml_epub
+    end
+    def xhtml
+      stylesheet=
+        @file.path_rel_links.xhtml_css \
+        + @env.path.style + '/' \
+        + @css.xhtml
+      %{<?xml-stylesheet type="text/css" href="#{stylesheet}"?>}
+    end
+    def xml_sax
+      stylesheet=
+        @file.path_rel_links.xml_css \
+        + @env.path.style + '/' \
+        + @css.xml_sax
+      %{<?xml-stylesheet type="text/css" href="#{stylesheet}"?>}
+    end
+    def xml_dom
+      stylesheet=
+        @file.path_rel_links.xml_css \
+        + @env.path.style + '/' \
+        + @css.xml_dom
+      %{<?xml-stylesheet type="text/css" href="#{stylesheet}"?>}
+    end
+    def xml_docbook
+      stylesheet=
+        @file.path_rel_links.xml_css \
+        + @env.path.style + '/' \
+        + @css.xml_docbook
+      %{<?xml-stylesheet type="text/css" href="#{stylesheet}"?>}
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** se_date.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se_date.rb"
+# <<sisu_document_header>>
+module SiSU_Info_Date
+  require_relative 'constants'                             # constants.rb
+  require_relative 'utils'                                 # utils.rb
+  class InfoDate
+    begin
+      require 'date'
+    rescue LoadError
+      SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+        error('date NOT FOUND (LoadError)')
+    end
+    attr_accessor :dt,:t
+    def initialize
+      @dt,@t=Date.today.to_s,Time.now
+    end
+    def week
+      w=@t.strftime('%W')
+      "#{@t.year}w#{w}"
+    end
+    def month
+      "#{@t.year}#{@t.month}"
+    end
+    def year
+      @t.year
+    end
+    def weekonly
+      @t.strftime('%W')
+    end
+    def monthonly
+      @t.month
+    end
+    def year_static
+      YEAR
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** se_db.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se_db.rb"
+# <<sisu_document_header>>
+module SiSU_Info_Db
+  require_relative 'constants'                             # constants.rb
+  require_relative 'utils'                                 # utils.rb
+  require_relative 'se_info_env'                           # se_info_env.rb
+  class InfoDb < SiSU_Info_Env::InfoEnv                    # se_info_env.rb
+    @@rc=nil
+    def initialize
+      @@pwd=@pwd=SiSU_Utils::Path.new.base_markup
+      @env=SiSU_Env::InfoEnv.new
+      pt=Pathname.new(@pwd)
+      r=Px[:lng_lst_rgx]
+      u=/.+?\/([^\/]+)(?:\/(?:#{r})$|$)/
+      @pwd_stub=pt.realpath.to_s[u,1]
+      @rc=@@rc ||=SiSU_Env::GetInit.new.sisu_yaml.rc
+      @defaults=SiSU_Env::InfoEnv.new.defaults
+    end
+    def share_source?
+      ((defined? @rc['db']['share_source']) \
+      && @rc['db']['share_source']==true) \
+      ? @rc['db']['share_source']
+      : false
+    end
+    def engine
+      def default
+        ((defined? @rc['db']['engine']['default']) \
+        && @rc['db']['engine']['default']=~/postgresql|sqlite/) \
+        ? @rc['db']['engine']['default']
+        : 'sqlite'
+      end
+      self
+    end
+    def psql
+      def user(opt=nil)
+        if opt \
+        and opt.selections.str =~/--db-user[=-]["']?(\S+)["']+/
+          $1
+        elsif opt \
+        and opt.selections.str =~/--webserv[=-]webrick/
+          @env.user
+        else
+          ((defined? @rc['db']['postgresql']['user']) \
+          && @rc['db']['postgresql']['user']=~/\S+/) \
+          ? @rc['db']['postgresql']['user']
+          : @env.user
+        end
+      end
+      def db #db_name
+        "#{Db[:name_prefix]}#{@pwd_stub}"
+      end
+      def port #PGPORT
+        ((defined? @rc['db']['postgresql']['port']) \
+        && ( @rc['db']['postgresql']['port'] =~/\d+/ \
+        || @rc['db']['postgresql']['port'].is_a?(Fixnum))) \
+        ? @rc['db']['postgresql']['port']
+        : (@defaults[:postgresql_port])
+      end
+      def password
+        ((defined? @rc['db']['postgresql']['password']) \
+        && @rc['db']['postgresql']['password']=~/\S+/) \
+        ? @rc['db']['postgresql']['password']
+        : ''
+      end
+      def host
+        ((defined? @rc['db']['postgresql']['host']) \
+        && @rc['db']['postgresql']['host']=~/(?:\S{1,3}\.){3}\S{1,3}|\S+?\.\S+/) \
+        ? @rc['db']['postgresql']['host']
+        : ''
+      end
+      def dbi
+        PG::Connection.open(:dbname =>  psql.db)
+      end
+      def dbi_
+        (psql.host =~/(?:\S{1,3}\.){3}\S{1,3}|\S+?\.\S+/) \
+        ? "DBI:Pg:database=#{psql.db};host=#{psql.host};port=#{psql.port}"
+        : "DBI:Pg:database=#{psql.db};port=#{psql.port}"
+      end
+      def conn_dbi
+        DBI.connect(psql.dbi,psql.user,psql.db)
+      end
+      def conn_pg
+        begin
+          require 'pg'
+        rescue LoadError
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+            error('pg NOT FOUND (LoadError)')
+        end
+        PG::Connection.new(dbname: psql.db, port: psql.port)
+      end
+     self
+    end
+    def sqlite
+      def db
+        "#{@env.path.webserv}/#{@pwd_stub}/sisu_sqlite.db"
+      end
+      def db_discrete(md)
+        # "#{@env.path.webserv}/#{@pwd_stub}/sisu_sqlite.db"
+      end
+      def dbi
+        "DBI:SQLite3:#{sqlite.db}" #sqlite3 ?
+      end
+      def sqlite3
+        sqlite.db #sqlite3 ?
+      end
+      def conn_dbi
+        DBI.connect(sqlite.dbi)
+      end
+      def conn_sqlite3
+        SQLite3::Database.new(sqlite.sqlite3)
+      end
+      self
+    end
+  end
+end
+module SiSU_Db_Op
+  require_relative 'constants'                             # constants.rb
+  require_relative 'utils'                                 # utils.rb
+  class DbOp < SiSU_Info_Db::InfoDb
+    def initialize(md)
+      begin
+        @md=md
+      rescue
+        SiSU_Screen::Ansi.new(md.opt.selections.str,$!,$@).rescue do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    def sqlite_discrete
+      def db
+        @md.file.output_path.sqlite_discrete.dir \
+        + '/' \
+        + @md.file.base_filename.sqlite_discrete
+      end
+      def dbi
+        "DBI:SQLite3:#{sqlite_discrete.db}"
+      end
+      def sqlite3
+        sqlite_discrete.db
+      end
+      def conn_dbi
+        DBI.connect(sqlite_discrete.dbi)
+      end
+      def conn_sqlite3
+        begin
+          $sqlite3=:yes
+          require 'sqlite3'
+          SQLite3::Database.new(sqlite_discrete.sqlite3)
+        rescue LoadError
+          $sqlite3=:no
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+            error('sqlite3 NOT FOUND (LoadError)')
+        end
+      end
+      self
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** se_envcall.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se_envcall.rb"
+# <<sisu_document_header>>
+module SiSU_Env_Call
+  begin
+    require 'singleton'
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('singleton NOT FOUND (LoadError)')
+  end
+  class EnvCall
+    @@rc,@@fns,@@fnn,@@fnb,@@fnt,@@flv,@@fnz=nil,nil,nil,nil,nil,nil,nil
+    @@ad={}
+    attr_accessor :rc,:fnn,:fnb,:fnt,:fnv,:fnz,:ad
+    def initialize(fns='')
+      @fns=fns
+      @sys=SiSU_Info_Sys::InfoSystem.instance
+      get_init=SiSU_Env::GetInit.new
+      @rc=get_init.sisu_yaml.rc
+      @ad=get_init.ads
+      if @fns \
+      and @fns != '' \
+      and @fns !=@@fns
+        @@fns,@@fnn,@@fnb,@@fnt,@@flv,@@fnz=@fns,nil,nil,nil,nil,nil
+      end
+      if @fns \
+      and @fns != '' #watch
+        m=/((.+?)(?:\~\w\w(?:_\w\w)?)?)\.((?:-|ssm\.)?sst|ssm|ssi)$/
+        @@fnn ||=@fns[m,1]
+        @@fnb ||=@fns[m,2]
+        @@fnt ||=@fns[m,3]
+        @@flv ||=document_language_versions_found[:f]
+        unless @@fns =~/\S+?\.txz/
+          @@fnz ||=if @@fns =~/(?:\~\S{2,3})?\.(?:ssm\.sst|ssm)$/; @@fnb + '.ssm.txz'
+          elsif @@fnb; @@fnb + '.sst.txz'
+          else '' # e.g. termsheet
+          end
+        end
+      end
+      @fnn,@fnb,@fnt,@flv,@fnz=@@fnn,@@fnb,@@fnt,@@flv,@@fnz
+    end
+    def default_language?
+      if @rc \
+      && defined? @rc['language_default']
+        if (@rc['language_default'].is_a?(String)) \
+        && (@rc['language_default'] =~/#{Px[:lng_lst_rgx]}/)
+          @rc['language_default']
+        else 'en'
+        end
+      else 'en'
+      end
+    end
+    def mono_multi_lingual?
+      if @rc \
+      && defined? @rc['output_dir_structure_by']
+        if @rc['output_dir_structure_by'] \
+        =~/dump/
+          :mono
+        elsif @rc['output_dir_structure_by'] \
+        =~/language|redirect/
+          :multi
+        elsif @rc['output_dir_structure_by'] \
+        =~/monolingual|filetype_mono|filenaneme_mono/
+          :mono
+        else :multi
+        end
+      else :multi
+      end
+    end
+    def output_dir_structure
+      def by?
+        output_structure=:filename #set default output structure
+        if @rc \
+        && defined? @rc['output_dir_structure_by']
+          output_structure=if (@rc['output_dir_structure_by'] =~/dump/) \
+          or ((defined? @rc['output_structure']['dump']) \
+          && @rc['output_structure']['dump'] ==true)
+            :dump
+          elsif (@rc['output_dir_structure_by'] =~/redirect/) \
+          or ((defined? @rc['output_structure']['redirect']) \
+          && @rc['output_structure']['redirect'] ==true)
+            :redirect
+          elsif (@rc['output_dir_structure_by'] =~/language/) \
+          or ((defined? @rc['output_structure']['by_language']) \
+          && @rc['output_structure']['by_language'] ==true)
+            :language
+          elsif (@rc['output_dir_structure_by'] =~/filetype/) \
+          or ((defined? @rc['output_structure']['by_filetype']) \
+          && @rc['output_structure']['by_filetype'] ==true)
+            :filetype
+          elsif (@rc['output_dir_structure_by'] =~/filename/) \
+          or ((defined? @rc['output_structure']['by_filename']) \
+          && @rc['output_structure']['by_filename'] ==true)
+            :filename
+          else #set default
+            :language
+          end
+        else #set default
+          :language
+        end
+      end
+      def dump?
+        ((by?) ==:dump) \
+        ? true
+        : false
+      end
+      def redirect?
+        ((by?) ==:redirect) \
+        ? true
+        : false
+      end
+      def by_language_code?
+        ((by?) ==:language) \
+        ? true
+        : false
+      end
+      def by_filetype?
+        ((by?) ==:filetype) \
+        ? true
+        : false
+      end
+      def by_filename?
+        ((by?) ==:filename) \
+        ? true
+        : false
+      end
+      def multilingual?
+        by_language_code?
+      end
+      self
+    end
+    def document_language_versions_found #REVISIT
+      @fn={}
+      filename=(@fns =~/\.ssm\.sst$/) \
+      ? @fns.gsub(/\.ssm\.sst$/,'.ssm')
+      : @fns
+      if filename.is_a?(String) \
+      and not filename.empty?
+        if output_dir_structure.by_language_code?
+          m=/((.+?)(?:\~\w{2,3})?)\.(sst|ssm)$/
+          @fn[:b],@fn[:m],@fn[:t]=filename[m,1],filename[m,2],filename[m,3]
+        else m=/(.+?)\.(sst|ssm)$/
+          @fn[:b]=@fn[:m]=filename[m,1]
+          @fn[:t]=filename[m,2]
+        end
+      end
+      lng_base=SiSU_Env::InfoEnv.new.language_default_set
+      lang=SiSU_Env::StandardiseLanguage.new
+      langs=lang.codes
+      x=[]
+      if FileTest.file?("#{@fn[:m]}.#{@fn[:t]}")
+        n=@fn[:m].gsub(/^.+?\//,'')
+        n =n + '.' + @fn[:t]
+        x << { f: "#{@fn[:m]}.#{@fn[:t]}", l: lng_base, n: n }
+      end
+      langs.each do |l|
+        lng=SiSU_Env::StandardiseLanguage.new(l)
+        if FileTest.file?("#{@fn[:m]}~#{lng.code}.#{@fn[:t]}")
+          x << { f: "#{@fn[:m]}~#{lng.code}.#{@fn[:t]}", l: lng.code }
+        elsif FileTest.file?("#{@fn[:m]}~#{lng.name}.#{@fn[:t]}")
+          x << { f: "#{@fn[:m]}~#{lng.name}.#{@fn[:t]}", l: lng.code }
+        end
+        if FileTest.file?("#{lng.code}/#{@fn[:m]}~#{lng.code}.#{@fn[:t]}")
+          if FileTest.file?("#{lng.code}/#{@fn[:m]}~#{lng.code}.#{@fn[:t]}")
+            x << { f: "#{lng.code}/#{@fn[:m]}~#{lng.code}.#{@fn[:t]}", l: lng.code }
+          elsif FileTest.file?("#{lng.code}/#{@fn[:m]}~#{lng.name}.#{@fn[:t]}")
+            x << { f: "#{lng.code}/#{@fn[:m]}~#{lng.name}.#{@fn[:t]}", l: lng.code }
+          end
+        end
+        if FileTest.file?("#{lng.code}/#{@fn[:m]}.#{@fn[:t]}")
+          if FileTest.file?("#{lng.code}/#{@fn[:m]}.#{@fn[:t]}")
+            x << { f: "#{lng.code}/#{@fn[:m]}.#{@fn[:t]}", l: lng.code }
+          elsif FileTest.file?("#{lng.code}/#{@fn[:m]}.#{@fn[:t]}")
+            x << { f: "#{lng.code}/#{@fn[:m]}.#{@fn[:t]}", l: lng.code }
+          end
+        end
+      end
+      @fn[:f]=x
+      @fn
+    end
+    def published_manifests?(output_base)
+      @fn={}
+      @m=[]
+      unless (@fns.nil? \
+      or @fns.empty?)
+        if output_dir_structure.by_language_code?
+          m=/((.+?)(?:\~\w{2,3})?)\.((?:-|ssm\.)?sst$)/
+          @fn[:b],@fn[:m],@fn[:t]=@fns[m,1],@fns[m,2],@fns[m,3]
+        else m=/(.+?)\.((?:-|ssm\.)?sst$)/
+          @fn[:b]=@fn[:m]=@fns[m,1]
+          @fn[:t]=@fns[m,2]
+        end
+      end
+      lang=SiSU_Env::StandardiseLanguage.new
+      langs=lang.codes
+      x=[]
+      if FileTest.file?("#{@fn[:m]}.#{@fn[:t]}"); x << "#{@fn[:m]}.#{@fn[:t]}"
+      end
+      dir=SiSU_Env::InfoEnv.new(@fns)
+      @m << { m: 'sisu_manifest.html', l: 'English' } #fix later, default language
+      langs.each do |l|
+        lng=SiSU_Env::StandardiseLanguage.new(l)
+        fns_c="#{@fn[:m]}~#{lng.code}.#{@fn[:t]}"
+        fns_l="#{@fn[:m]}~#{lng.name}.#{@fn[:t]}"
+        if FileTest.file?(fns_c)
+          fn_set_lang=SiSU_Env::StandardiseLanguage.new.
+            file_to_language(fns_c) #reconsider file_to_language
+          lng=fn_set_lang[:n]
+          fn=SiSU_Env::EnvCall.new(fns_c).lang(fn_set_lang[:c])
+          @m << { m: fn[:manifest], l: lng }
+        elsif FileTest.file?(fns_l)
+          fn_set_lang=SiSU_Env::StandardiseLanguage.new.
+            file_to_language(fns_l) #reconsider file_to_language
+          @fnl=dir.i18n.lang_filename(fn_set_lang[:c])
+          fn=SiSU_Env::EnvCall.new(fns_l).lang(fn_set_lang[:c])
+          @m << { m: fn[:manifest], l: lng }
+        end
+      end
+      @m=@m.uniq
+    end
+    def filename(code,name,suffix)
+      "#{name}#{suffix}"
+    end
+    def lang(code)
+      {
+        html:            filename(code,'','.html'),
+        book_index:      filename(code,'book_index','.html'),
+        concordance:     filename(code,'concordance','.html'),
+        sax:             filename(code,'sax','.xml'),
+        dom:             filename(code,'dom','.xml'),
+        docbook:         filename(code,'docbook','.xml'),
+        xhtml:           filename(code,'scroll','.xhtml'),
+        pdf_l:           filename(code,'','.pdf'),
+        pdf_p:           filename(code,'','.pdf'),
+        pdf_l_a4:        filename(code,"a4",'.pdf'),
+        pdf_p_a4:        filename(code,"a4",'.pdf'),
+        pdf_l_a5:        filename(code,"a5",'.pdf'),
+        pdf_p_a5:        filename(code,"a5",'.pdf'),
+        pdf_l_b5:        filename(code,"b5",'.pdf'),
+        pdf_p_b5:        filename(code,"b5",'.pdf'),
+        pdf_l_letter:    filename(code,"letter",'.pdf'),
+        pdf_p_letter:    filename(code,"letter",'.pdf'),
+        pdf_l_legal:     filename(code,"legal",'.pdf'),
+        pdf_p_legal:     filename(code,"legal",'.pdf'),
+        toc:             filename(code,'toc','.html'),
+        doc:             filename(code,fnb,'.html'),
+        index:           filename(code,'index','.html'),
+        po:              filename(code,@fns,'.po'),
+        pot:             filename(code,@fns,'.pot'),
+        odf:             filename(code,'','.odt'),
+        epub:            filename(code,'','.epub'),
+        plain:           filename(code,'','.txt'),
+        qrcode:          filename(code,'','.jpg'),
+        manpage:         filename(code,'','.1'),          #fix, section number
+        wiki:            filename(code,'wiki','.txt'),
+        digest:          filename(code,'digest','.txt'),
+        metadata:        filename(code,'metadata','.html'), #chk
+        manifest:        filename(code,'manifest','.html'),
+        oai_pmh:         filename(code,'oai_pmh','.xml'),
+        sitemap:         filename(code,'sitemap','.xml'),
+        sitemap_touch:   filename(code,"sitemap_#{fnb}",'.xml'),
+        sxs:             filename(code,fnb,'.sxs.xml'),
+        sxd:             filename(code,fnb,'.sxd.xml'),
+        sxn:             filename(code,fnb,'.sxn.xml'),
+        sisupod:         filename(nil,@fnz,''),
+        book_idx_html:   filename(code,'book_index','.html'),
+        book_idx_epub:   filename(code,'book_index','.xhtml'),
+        epub_concord:    filename(code,'concordance','.xhtml'),
+      }
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** se_filemap.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se_filemap.rb"
+# <<sisu_document_header>>
+module SiSU_File_Map
+  require_relative 'constants'                             # constants.rb
+  require_relative 'utils'                                 # utils.rb
+  require_relative 'se_info_env'                           # se_info_env.rb
+  class FileMap < SiSU_Info_Env::InfoEnv                   # se_info_env.rb
+    attr_accessor :local_sisu_source
+    def initialize(opt='') #watch / REVIEW
+      super()
+      @opt=opt #,opt.fns,opt.selections.str
+      @env=(@opt.fns && !(@opt.fns.empty?) \
+      ? (SiSU_Env::InfoEnv.new(@opt.fns))
+      : (SiSU_Env::InfoEnv.new('dummy.sst')))
+      ft=[]
+      if @opt.act[:ao][:set]==:on
+        @md=SiSU_Param::Parameters.new(@opt).get
+        if @md \
+        and defined? @md.fn \
+        and @md.fn        # used for by_language_code?
+          if @md.opt.act[:html][:set]==:on                 #% --html, -h -H
+            ft << @md.fn[:html]
+          end
+          if @md.opt.act[:concordance][:set]==:on          #% --concordance, -w
+            ft << @md.fn[:concordance]
+          end
+          if @md.opt.act[:manifest][:set]==:on             #% --manifest, -y
+            ft << @md.fn[:manifest]
+          end
+          if @md.opt.act[:txt][:set]==:on                  #% --txt, -t -a
+            ft << @md.fn[:plain]
+          end
+          if @md.opt.act[:txt_textile][:set]==:on          #% --textile
+            ft << @md.fn[:txt_textile]
+          end
+          if @md.opt.act[:txt_asciidoc][:set]==:on         #% --asciidoc
+            ft << @md.fn[:txt_asciidoc]
+          end
+          if @md.opt.act[:txt_markdown][:set]==:on         #% --markdown
+            ft << @md.fn[:txt_markdown]
+          end
+          if @md.opt.act[:txt_rst][:set]==:on              #% --rst, --rest
+            ft << @md.fn[:txt_rst]
+          end
+          if @md.opt.act[:txt_orgmode][:set]==:on          #% --orgmode
+            ft << @md.fn[:txt_orgmode]
+          end
+          if @md.opt.act[:xhtml][:set]==:on                #% --xhtml, -b xhtml
+            ft << @md.fn[:xhtml]
+          end
+          if @md.opt.act[:epub][:set]==:on                 #% --epub, -e
+            ft << @md.fn[:epub]
+          end
+          if @md.opt.act[:manpage][:set]==:on              #% --manpage, -i
+            ft << @md.fn[:manpage]
+          end
+          if @md.opt.act[:hash_digests][:set]==:on         #% --hash-digests, -N digest tree
+            ft << @md.fn[:digest]
+          end
+          if @md.opt.act[:odt][:set]==:on                  #% --odt, -o opendocument
+            ft << @md.fn[:odf]
+          end
+          if @md.opt.act[:pdf][:set]==:on                  #% --pdf-l --pdf, -p latex/ texpdf
+            ft << @md.fn[:pdf_l] << @md.fn[:pdf_p]
+          end
+          if @md.opt.act[:share_source][:set]==:on
+            ft << @md.fns
+          end
+          if @md.opt.act[:sisupod][:set]==:on              #% --sisupod, -S make sisupod
+            ft << @md.fn[:sisupod]
+          end
+          if @md.opt.act[:xml_sax][:set]==:on              #% --xml-sax, -x xml sax type
+            ft << @md.fn[:sax]
+          end
+          if @md.opt.act[:xml_dom][:set]==:on              #% --xml-dom, -X xml dom type
+            ft << @md.fn[:dom]
+          end
+          if @md.opt.act[:xml_docbook_book][:set]==:on     #% --xml-docbook-book
+            ft << @md.fn[:xml_docbook_book]
+          end
+          if @md.opt.act[:xml_fictionbook][:set]==:on      #% --xml-fictionbook
+            ft << @md.fn[:xml_fictionbook]
+          end
+          if @md.opt.act[:xml_scaffold_structure_sisu][:set]==:on          #% --xml-scaffold --xml-scaffold-sisu
+            ft << @md.fn[:xml_scaffold_structure_sisu]
+          end
+          if @md.opt.act[:xml_scaffold_structure_collapse][:set]==:on      #% --xml-scaffold-collapse
+            ft << @md.fn[:xml_scaffold_structure_collapse]
+          end
+          @fnb=@md.fnb
+        else   # still needed where/when dp document param is not parsed
+          if @opt.act[:html][:set]==:on                    #% --html, -h -H
+            ft << '.html' << '.html.??'
+          end
+          if @opt.act[:concordance][:set]==:on             #% --concordance, -w
+            ft << 'concordance.html' << '??.concordance.html' << 'concordance.??.html'
+          end
+          if @opt.act[:manifest][:set]==:on                #% --manifest, -y
+            ft << 'sisu_manifest.html' << '??.sisu_manifest.html' << 'sisu_manifest.??.html'
+          end
+          if @opt.act[:txt][:set]==:on                     #% --txt, -t -a
+            ft << 'plain.txt' << '??.plain.txt' << 'plain.??.txt'
+          end
+          if @opt.act[:txt_textile][:set]==:on             #% --textile
+            ft << 'plain.txt' << '??.plain.txt' << 'plain.??.txt'
+          end
+          if @opt.act[:txt_asciidoc][:set]==:on            #% --asciidoc
+            ft << 'plain.txt' << '??.plain.txt' << 'plain.??.txt'
+          end
+          if @opt.act[:txt_markdown][:set]==:on            #% --markdown
+            ft << 'plain.txt' << '??.plain.txt' << 'plain.??.txt'
+          end
+          if @opt.act[:txt_rst][:set]==:on                 #% --rst, --rest
+            ft << 'plain.txt' << '??.plain.txt' << 'plain.??.txt'
+          end
+          if @opt.act[:txt_orgmode][:set]==:on             #% --orgmode
+            ft << 'plain.txt' << '??.plain.txt' << 'plain.??.txt'
+          end
+          if @opt.act[:xhtml][:set]==:on                   #% --xhtml, -b xhtml
+            ft << 'scroll.xhtml' << '??.scroll.xhtml' << 'scroll.??.xhtml'
+          end
+          if @opt.act[:epub][:set]==:on                    #% --epub, -e
+            ft  << @fnb << '.epub'
+          end
+          if @opt.act[:manpage][:set]==:on                 #% --manpage, -i
+            ft << '.1' << '??.man.1' << 'man.??.1'
+          end
+          if @opt.act[:hash_digests][:set]==:on            #% --hash-digests, -N digest tree
+            ft << 'digest.txt' << '??.digest.txt' << 'digest.??.txt'
+          end
+          if @opt.act[:odt][:set]==:on                     #% --odt, -o opendocument
+            ft << 'opendocument.odt' << '??.opendocument.odt' << 'opendocument.??.odt'
+          end
+          if @opt.act[:pdf][:set]==:on                     #% --pdf-l --pdf, -p latex/ texpdf
+            ft << 'landscape.pdf' << 'portrait.pdf' << '.pdf'
+          end
+          if @opt.act[:share_source][:set]==:on
+            ft << '.sst' << '.ssi' << '.ssm'
+          end
+          if @opt.act[:sisupod][:set]==:on                 #% --sisupod, -S make sisupod
+            ft << '.zip'
+          end
+          if @opt.act[:xml_sax][:set]==:on                 #% --xml-sax, -x xml sax type
+            ft << 'sax.xml' << '??.sax.xml' << 'sax.??.xml'
+          end
+          if @opt.act[:xml_dom][:set]==:on                 #% --xml-dom, -X xml dom type
+            ft << 'dom.xml' << '??.dom.xml' << 'dom.??.xml'
+          end
+          if @opt.act[:xml_docbook_book][:set]==:on        #% --xml-docbook-book
+            ft << 'docbook.xml' << '??.docbook.xml' << 'docbook.??.xml'
+          end
+          if @opt.act[:xml_fictionbook][:set]==:on         #% --xml-fictionbook
+            ft << 'fictionbook.xml' << '??.fictionbook.xml' << 'fictionbook.??.xml'
+          end
+          if @opt.act[:xml_scaffold_structure_sisu][:set]==:on          #% --xml-scaffold --xml-scaffold-sisu
+            ft << 'scaffold.xml' << '??.scaffold.xml' << 'scaffold.??.xml'
+          end
+          if @opt.act[:xml_scaffold_structure_collapse][:set]==:on      #% --xml-scaffold-collapse
+            ft << 'scaffold.xml' << '??.scaffold.xml' << 'scaffold.??.xml'
+          end
+        end
+        ft=ft.uniq
+        filetypes=ft.join(',')
+        @filetypes=if filetypes !~/..+/ then ''   # -r called alone, copy all
+        elsif @opt.selections.str =~/u/            then ''   # -u added, copy all, (used to create remote directory tree see output path), not the usual function of -u
+        elsif filetypes =~/\S+?,\S+/    then '*{' + filetypes + '}' # more than one relevant file type
+        else                                 '*' + filetypes # one relevant file type
+        end
+        @source_path=(@fnb && !(@fnb.empty?) \
+        ? "#{@env.path.output}/#{@fnb}"
+        : @env.path.output)
+        @source_path_epub=(@fnb && !(@fnb.empty?) \
+        ? "#{@env.path.output}/epub"
+        : @env.path.output_epub)
+        @source_path_src=(@fnb && !(@fnb.empty?) \
+        ? "#{@env.path.output}/src"
+        : @env.path.output_src)
+        @source_path_pod=(@fnb && !(@fnb.empty?) \
+        ? "#{@env.path.output}/pod"
+        : @env.path.output_pod)
+        @source_path_harvest=(@fnb && !(@fnb.empty?) \
+        ? "#{@env.path.output}/manifest"
+        : @env.path.output_harvest)
+        @local_sisu_source=(@filetypes =~/\S/) \
+        ? "#{@source_path}/#{@filetypes}"
+        : @source_path
+      end
+      if @opt.act[:rsync][:set]==:on
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** se_file_op.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se_file_op.rb"
+# <<sisu_document_header>>
+module SiSU_Info_File
+  require_relative 'utils'                                 # utils.rb
+  require_relative 'se_info_env'                           # se_info_env.rb
+  begin
+    require 'fileutils'
+      include FileUtils::Verbose
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('fileutils NOT FOUND (LoadError)')
+  end
+  class InfoFile < SiSU_Info_Env::InfoEnv                  # se_info_env.rb
+    #todo unify with FileOp
+    def initialize(fns)
+      begin
+        super(fns)
+        @fns=fns
+        @env=SiSU_Env::InfoEnv.new(@fns)
+        m=/((.+?)(?:\~\w\w(?:_\w\w)?)?)\.((?:-|ssm\.)?sst|ssm)$/
+        @fnn,@fnb,@fnt=@fns[m,1],@fns[m,2],@fns[m,3]
+      rescue
+        SiSU_Screen::Ansi.new('',$!,$@).rescue do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    def basefilename #Remove if possible
+      m=/(.+?)\.(?:(?:-|ssm\.)?sst|ssm)$/m
+      @fns[m,1]
+    end
+    def make_file(path,filename)
+      (File.writable?("#{path}/.")) \
+      ? File.new("#{path}/#{filename}",'w+')
+      : (SiSU_Screen::Ansi.new(
+          '',
+          "*WARN* is the file or directory writable?, could not create #{filename}"
+        ).warn)
+    end
+    def touch_file(path,filename)
+      if File.writable?("#{path}/.");
+        FileUtils::touch("#{path}/#{filename}")
+      else
+        SiSU_Screen::Ansi.new(
+          '',
+          "*WARN* is the file or directory writable?, could not create #{filename}"
+        ).warn
+      end
+    end
+    def make_path(path)
+      FileUtils::mkdir_p(path) unless FileTest.directory?(path)
+    end
+    def marshal
+      def ao_content
+        @env.processing_path.ao + '/' \
+          + @fns + '.content.rbm'
+      end
+      def ao_idx_sst_rel_html_seg
+        @env.processing_path.ao + '/' \
+          + @fns + '.idx_sst.rbm'
+      end
+      def ao_idx_sst_rel #used by tex & odf
+        @env.processing_path.ao + '/' \
+          + @fns + '.idx_raw.rbm'
+      end
+      def ao_idx_html
+        @env.processing_path.ao + '/' \
+          + @fns + '.idx_html.rbm'
+      end
+      def ao_idx_xhtml
+        @env.processing_path.ao + '/' \
+          + @fns + '.idx_xhtml.rbm'
+      end
+      def ao_metadata
+        @env.processing_path.ao + '/' \
+          + @fns + '.metadata.rbm'
+      end
+      def ao_map_nametags
+        @env.processing_path.ao + '/' \
+          + @fns + '.map_name_tags.rbm'
+      end
+      def ao_map_ocn_htmlseg
+        @env.processing_path.ao + '/' \
+          + @fns + '.map_ocn_htmlseg.rbm'
+      end
+      def html_tune
+        @env.processing_path.tune + '/' \
+          + @fns + '.marshal_tune'
+      end
+      def xhtml_tune
+        @env.processing_path.tune + '/' \
+          + @fns + '.marshal_tune'
+      end
+      self
+    end
+    def write_file_processing
+      def html_tune
+        File.new("#{@env.processing_path.tune}/#{@fns}.tune",'w+')
+      end
+      self
+    end
+    def mkdir #check moved from FileOp, existing mkdir
+      def processing
+        def ao
+          FileUtils::mkdir_p(@env.processing_path.ao) \
+            unless FileTest.directory?(@env.processing_path.ao)
+        end
+        def tune
+          FileUtils::mkdir_p(@env.processing_path.tune) \
+            unless FileTest.directory?(@env.processing_path.tune)
+        end
+        self
+      end
+    end
+  end
+end
+module SiSU_File_Op
+  require_relative 'constants'                             # constants.rb
+  require_relative 'utils'                                 # utils.rb
+  begin
+    require 'fileutils'
+      include FileUtils::Verbose
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('fileutils NOT FOUND (LoadError)')
+  end
+  class FileOp < SiSU_Info_File::InfoFile
+    #todo unify with CreateFile
+    def initialize(md,fno='')
+      begin
+        @md,@fno=md,fno
+        @env=SiSU_Env::InfoEnv.new(@md.fns)
+      rescue
+        SiSU_Screen::Ansi.new(md.opt.selections.str,$!,$@).rescue do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    def output_dir_structure
+      SiSU_Env::ProcessingSettings.new(@md).output_dir_structure
+    end
+    def mkdir_initialize                # not used but consider using
+      FileUtils::mkdir_p(output_path.base.dir) \
+        unless FileTest.directory?(output_path.base.dir)
+      FileUtils::mkdir_p("#{output_path.base.dir}/#{@md.fnb}") \
+        unless FileTest.directory?("#{output_path.base.dir}/#{@md.fnb}")
+      FileUtils::mkdir_p("#{output_path.base.dir}/#{@env.path.style}") \
+        unless FileTest.directory?("#{output_path.base.dir}/#{@env.path.style}")
+      FileUtils::mkdir_p(@env.processing_path.ao) \
+        unless FileTest.directory?(@env.processing_path.ao)
+      FileUtils::mkdir_p(@env.processing_path.tune) \
+        unless FileTest.directory?(@env.processing_path.tune)
+    end
+    def path_rel_links
+      def html_scroll_2
+        if output_dir_structure.by_language_code?
+          '../../'
+        elsif output_dir_structure.by_filetype?
+          '../'
+        else
+          '../'
+        end
+      end
+      def html_seg_2
+        if output_dir_structure.by_language_code?
+          '../../../'
+        elsif output_dir_structure.by_filetype?
+          '../../'
+        else
+          '../'
+        end
+      end
+      def html_scroll_1
+        if output_dir_structure.by_language_code?
+          '../'
+        elsif output_dir_structure.by_filetype?
+          '../'
+        else
+          './'
+        end
+      end
+      def html_seg_1
+        if output_dir_structure.by_language_code?
+          '../../'
+        elsif output_dir_structure.by_filetype?
+          '../../'
+        else
+          './'
+        end
+      end
+      def default_output_css
+        if (@md.opt.opt_act[:dump][:bool] \
+        &&  @md.opt.opt_act[:dump][:inst]) \
+        || (@md.opt.opt_act[:redirect][:bool] \
+        &&  @md.opt.opt_act[:redirect][:inst])
+          './'
+        elsif output_dir_structure.by_language_code?
+          '../../'
+        elsif output_dir_structure.by_filetype?
+          '../'
+        else
+          '../'
+        end
+      end
+      def html_scroll_css
+        default_output_css
+      end
+      def xhtml_css
+        default_output_css
+      end
+      def xml_css
+        default_output_css
+      end
+      def html_seg_css
+        if output_dir_structure.by_language_code?
+          '../../../'
+        elsif output_dir_structure.by_filetype?
+          '../../'
+        else
+          '../'
+        end
+      end
+      def manifest_css
+        if output_dir_structure.by_language_code?
+          '../../_sisu/css'
+        elsif output_dir_structure.by_filetype?
+          ''
+        else
+          '../'
+        end
+      end
+      self
+    end
+    def mkdir
+      def output
+        def base
+          FileUtils::mkdir_p(output_path.base.dir) \
+            unless FileTest.directory?(output_path.base.dir)
+        end
+        def css
+          FileUtils::mkdir_p("#{output_path.base.dir}/#{@env.path.style}") \
+            unless FileTest.directory?("#{output_path.base.dir}/#{@env.path.style}")
+        end
+        def epub
+          path=output_path.epub.dir
+          make_path(path)
+        end
+        self
+      end
+      self
+    end
+    def mkfile #consider using more
+      path="#{output_path.base.dir}/#{@md.fnb}"
+      make_path(path)
+      filename=@fno
+      make_file(path,filename)
+    end
+    def mkfile_pwd
+      path=Dir.pwd
+      filename=@fno
+      make_file(path,filename)
+    end
+    def write_file
+      def txt
+        path=output_path.txt.dir
+        make_path(path)
+        fn=base_filename.txt
+        make_file(path,fn)
+      end
+      def textile
+        path=output_path.textile.dir
+        make_path(path)
+        fn=base_filename.textile
+        make_file(path,fn)
+      end
+      def asciidoc
+        path=output_path.asciidoc.dir
+        make_path(path)
+        fn=base_filename.asciidoc
+        make_file(path,fn)
+      end
+      def markdown
+        path=output_path.markdown.dir
+        make_path(path)
+        fn=base_filename.markdown
+        make_file(path,fn)
+      end
+      def rst
+        path=output_path.rst.dir
+        make_path(path)
+        fn=base_filename.rst
+        make_file(path,fn)
+      end
+      def orgmode
+        path=output_path.orgmode.dir
+        make_path(path)
+        fn=base_filename.orgmode
+        make_file(path,fn)
+      end
+      def html_scroll
+        pth=output_path.html.dir
+        make_path(pth)
+        p_fn=place_file.html_scroll.dir
+        File.new(p_fn,'w+')
+      end
+      def html_seg_index
+        pth=((output_dir_structure.by_filename?) \
+        || (output_dir_structure.dump?)) \
+        ? "#{output_path.html.dir}"
+        : "#{output_path.html.dir}/#{@md.fnb}"
+        make_path(pth)
+        p_fn=place_file.html_seg_index.dir
+        File.new(p_fn,'w+')
+      end
+      def html_segtoc
+        pth=((output_dir_structure.by_filename?) \
+        || (output_dir_structure.dump?) \
+        || (output_dir_structure.redirect?)) \
+        ? "#{output_path.html.dir}"
+        : "#{output_path.html.dir}/#{@md.fnb}"
+        make_path(pth)
+        p_fn=place_file.html_segtoc.dir
+        File.new(p_fn,'w+')
+      end
+      def xhtml
+        path=output_path.xhtml.dir
+        make_path(path)
+        fn=base_filename.xhtml
+        make_file(path,fn)
+      end
+      def xml_sax
+        path=output_path.xml.dir
+        make_path(path)
+        fn=base_filename.xml_sax
+        make_file(path,fn)
+      end
+      def xml_dom
+        path=output_path.xml.dir
+        make_path(path)
+        fn=base_filename.xml_dom
+        make_file(path,fn)
+      end
+      def xml_docbook_book
+        path=output_path.xml_docbook_book.dir
+        make_path(path)
+        fn=base_filename.xml_docbook_book
+        make_file(path,fn)
+      end
+      def xml_fictionbook
+        path=output_path.xml_fictionbook.dir
+        make_path(path)
+        fn=base_filename.xml_fictionbook
+        make_file(path,fn)
+      end
+      def xml_scaffold_structure_sisu
+        path=output_path.xml_scaffold_structure_sisu.dir
+        make_path(path)
+        fn=base_filename.xml_scaffold_structure_sisu
+        make_file(path,fn)
+      end
+      def xml_scaffold_structure_collapse
+        path=output_path.xml_scaffold_structure_collapse.dir
+        make_path(path)
+        fn=base_filename.xml_scaffold_structure_collapse
+        make_file(path,fn)
+      end
+      def json
+        path=output_path.json.dir
+        make_path(path)
+        fn=base_filename.json
+        make_file(path,fn)
+      end
+      def manpage
+        path=output_path.manpage.dir
+        make_path(path)
+        fn=base_filename.manpage
+        make_file(path,fn)
+      end
+      def texinfo
+        path=output_path.texinfo.dir
+        make_path(path)
+        fn=base_filename.texinfo
+        make_file(path,fn)
+      end
+      def info
+        path=output_path.texinfo.dir
+        make_path(path)
+        fn=base_filename.info
+        make_file(path,fn)
+      end
+      def hash_digest
+        path=output_path.hash_digest.dir
+        make_path(path)
+        fn=base_filename.hash_digest
+        make_file(path,fn)
+      end
+      def qrcode
+        path=output_path.qrcode.dir
+        make_path(path)
+        fn=base_filename.qrcode
+        make_file(path,fn)
+      end
+      def manifest
+        path=output_path.manifest.dir
+        make_path(path)
+        fn=base_filename.manifest
+        make_file(path,fn)
+      end
+      def manifest_txt
+        path=output_path.manifest.dir
+        make_path(path)
+        fn=base_filename.manifest_txt
+        make_file(path,fn)
+      end
+      def po4a_cfg
+        path=output_path.po4a.dir
+        make_path(path)
+        fn=base_filename.po4a_cfg
+        make_file(path,fn)
+      end
+      def pot
+        path=output_path.pot.dir
+        make_path(path)
+        fn=base_filename.pot
+        make_file(path,fn)
+      end
+      def po(lng=@md.opt.lng)
+        path=output_path.po(lng).dir
+        make_path(path)
+        fn=base_filename.po
+        make_file(path,fn)
+      end
+      def po4a_sst(lng=@md.opt.lng)
+        path=output_path.po4a_sst(lng).dir
+        make_path(path)
+        fn=base_filename.po4a_sst
+        make_file(path,fn)
+      end
+      self
+    end
+    def place_file
+      def txt
+        def dir
+          output_path.txt.dir + '/' \
+          + base_filename.txt
+        end
+        def rel
+          output_path.txt.rel + '/' \
+          + base_filename.txt
+        end
+        self
+      end
+      def textile
+        def dir
+          output_path.textile.dir + '/' \
+          + base_filename.textile
+        end
+        def rel
+          output_path.textile.rel + '/' \
+          + base_filename.textile
+        end
+        self
+      end
+      def asciidoc
+        def dir
+          output_path.asciidoc.dir + '/' \
+          + base_filename.asciidoc
+        end
+        def rel
+          output_path.asciidoc.rel + '/' \
+          + base_filename.asciidoc
+        end
+        self
+      end
+      def markdown
+        def dir
+          output_path.markdown.dir + '/' \
+          + base_filename.markdown
+        end
+        def rel
+          output_path.markdown.rel + '/' \
+          + base_filename.markdown
+        end
+        self
+      end
+      def rst
+        def dir
+          output_path.rst.dir + '/' \
+          + base_filename.rst
+        end
+        def rel
+          output_path.rst.rel + '/' \
+          + base_filename.rst
+        end
+        self
+      end
+      def orgmode
+        def dir
+          output_path.orgmode.dir + '/' \
+          + base_filename.orgmode
+        end
+        def rel
+          output_path.orgmode.rel + '/' \
+          + base_filename.orgmode
+        end
+        self
+      end
+      def html_scroll
+        def dir
+          output_path.html_scroll.dir + '/' \
+          + base_filename.html_scroll
+        end
+        def rel
+          output_path.html_scroll.rel + '/' \
+          + base_filename.html_scroll
+        end
+        self
+      end
+      def html_seg_index
+        def dir
+          output_path.html_seg.dir + '/' \
+          + base_filename.html_seg_index
+        end
+        def rel
+          output_path.html_seg.rel + '/' \
+          + base_filename.html_seg_index
+        end
+        self
+      end
+      def html_segtoc
+        def dir
+          output_path.html_seg.dir + '/' \
+          + base_filename.html_segtoc
+        end
+        def rel
+          output_path.html_seg.rel + '/' \
+          + base_filename.html_segtoc
+        end
+        self
+      end
+      def html_book_index
+        def dir
+          output_path.html_seg.dir + '/' \
+          + base_filename.html_book_index
+        end
+        def rel
+          output_path.html_seg.rel + '/' \
+          + base_filename.html_book_index
+        end
+        self
+      end
+      def html_concordance
+        def dir
+          output_path.html_seg.dir + '/' \
+          + base_filename.html_concordance
+        end
+        def rel
+          output_path.html_seg.rel + '/' \
+          + base_filename.html_concordance
+        end
+        self
+      end
+      def odt
+        def dir
+          output_path.odt.dir + '/' \
+          + base_filename.odt
+        end
+        def rel
+          output_path.odt.rel + '/' \
+          + base_filename.odt
+        end
+        self
+      end
+      def epub
+        def dir
+          output_path.epub.dir + '/' \
+          + base_filename.epub
+        end
+        def rel
+          output_path.epub.rel + '/' \
+          + base_filename.epub
+        end
+        self
+      end
+      def pdf_p
+        STDERR.puts 'ERROR not available due to multiple page format sizes'
+      end
+      def pdf_l
+        STDERR.puts 'ERROR not available due to multiple page format sizes'
+      end
+      def xhtml
+        def dir
+          output_path.xhtml.dir + '/' \
+          + base_filename.xhtml
+        end
+        def rel
+          output_path.xhtml.rel + '/' \
+          + base_filename.xhtml
+        end
+        self
+      end
+      def xml_sax
+        def dir
+          output_path.xml.dir + '/' \
+          + base_filename.xml_sax
+        end
+        def rel
+          output_path.xml.rel + '/' \
+          + base_filename.xml_sax
+        end
+        self
+      end
+      def xml_dom
+        def dir
+          output_path.xml.dir + '/' \
+          + base_filename.xml_dom
+        end
+        def rel
+          output_path.xml.rel + '/' \
+          + base_filename.xml_dom
+        end
+        self
+      end
+      def xml_docbook_book
+        def dir
+          output_path.xml_docbook.dir + '/' \
+          + base_filename.xml_docbook_book
+        end
+        def rel
+          output_path.xml_docbook.rel + '/' \
+          + base_filename.xml_docbook_book
+        end
+        self
+      end
+      def xml_fictionbook
+        def dir
+          output_path.xml_fictionbook.dir + '/' \
+          + base_filename.xml_fictionbook
+        end
+        def rel
+          output_path.xml_fictionbook.rel + '/' \
+          + base_filename.xml_fictionbook
+        end
+        self
+      end
+      def xml_scaffold_structure_sisu
+        def dir
+          output_path.xml.dir + '/' \
+          + base_filename.xml_scaffold_structure_sisu
+        end
+        def rel
+          output_path.xml.rel + '/' \
+          + base_filename.xml_scaffold_structure_sisu
+        end
+        self
+      end
+      def xml_scaffold_structure_collapse
+        def dir
+          output_path.xml.dir + '/' \
+          + base_filename.xml_scaffold_structure_collapse
+        end
+        def rel
+          output_path.xml.rel + '/' \
+          + base_filename.xml_scaffold_structure_collapse
+        end
+        self
+      end
+      def json
+        def dir
+          output_path.json.dir + '/' \
+          + base_filename.json
+        end
+        def rel
+          output_path.json.rel + '/' \
+          + base_filename.json
+        end
+        self
+      end
+      def sqlite_discrete
+        def dir
+          output_path.sqlite_discrete.dir + '/' \
+          + base_filename.sqlite_discrete
+        end
+        def rel
+          output_path.sqlite_discrete.rel + '/' \
+          + base_filename.sqlite_discrete
+        end
+        self
+      end
+      def hash_digest
+        def dir
+          output_path.hash_digest.dir + '/' \
+          + base_filename.hash_digest
+        end
+        def rel
+          output_path.hash_digest.rel + '/' \
+          + base_filename.hash_digest
+        end
+        self
+      end
+      def src
+        def dir
+          output_path.src.dir + '/' \
+            + base_filename.src
+        end
+        def rel
+          output_path.src.rel + '/' \
+          + base_filename.src
+        end
+        self
+      end
+      def sisupod
+        def dir
+          output_path.sisupod.dir + '/' \
+          + base_filename.sisupod
+        end
+        def rel
+          output_path.sisupod.rel + '/' \
+          + base_filename.sisupod
+        end
+        self
+      end
+      def po
+        def dir
+          output_path.po.dir + '/' \
+          + base_filename.po
+        end
+        def rel
+          output_path.po.rel + '/' \
+          + base_filename.po
+        end
+        self
+      end
+      def pot
+        def dir
+          output_path.pot.dir + '/' \
+          + base_filename.pot
+        end
+        def rel
+          output_path.pot.rel + '/' \
+          + base_filename.pot
+        end
+        self
+      end
+      def po_git
+        def dir
+          output_path.po_git + '/' \
+          + base_filename.po
+        end
+        def rel
+          #output_path.po_git + '/' + base_filename.po
+        end
+        self
+      end
+      def pot_git
+        def dir
+          output_path.pot_git + '/' \
+          + base_filename.pot
+        end
+        def rel
+          #output_path.pot_git + '/' + base_filename.pot
+        end
+        self
+      end
+      def manpage
+        def dir
+          output_path.manpage.dir + '/' \
+          + base_filename.manpage
+        end
+        def rel
+          output_path.manpage.rel + '/' \
+          + base_filename.manpage
+        end
+        self
+      end
+      def texinfo
+        def dir
+          output_path.texinfo.dir + '/' \
+          + base_filename.texinfo
+        end
+        def rel
+          output_path.texinfo.rel + '/' \
+          + base_filename.texinfo
+        end
+        self
+      end
+      def info
+        def dir
+          output_path.texinfo.dir + '/' \
+          + base_filename.info
+        end
+        def rel
+          output_path.texinfo.rel + '/' \
+          + base_filename.info
+        end
+        self
+      end
+      def qrcode_title
+        def dir
+          output_path.qrcode.dir + '/' \
+          + base_filename.qrcode_title
+        end
+        def rel
+          output_path.qrcode.rel + '/' \
+          + base_filename.qrcode_title
+        end
+        self
+      end
+      def qrcode_md
+        def dir
+          output_path.qrcode.dir + '/' \
+          + base_filename.qrcode_md
+        end
+        def rel
+          output_path.qrcode.rel + '/' \
+          + base_filename.qrcode_md
+        end
+        self
+      end
+      def manifest
+        def dir
+          output_path.manifest.dir + '/' \
+            + base_filename.manifest
+        end
+        def rel
+          output_path.manifest.rel + '/' \
+            + base_filename.manifest
+        end
+        self
+      end
+      self
+    end
+    def base_filename
+      def i18n(f)
+        f=default_hash.merge(f)
+        f[:lng] ||=@md.lang_code_insert
+        f[:fn] + f[:lng] + f[:ft]
+      end
+      def default_hash
+        {
+          fn: @md.fnb,
+          lng: @md.lang_code_insert,
+        }
+      end
+      def default_hash_build(fh,sfx)
+        if fh.is_a?(Hash)
+          fh[:fn] ||=@md.fnb
+          fh[:lng] ||= @md.lang_code_insert
+          fh[:ft]=sfx
+          fh
+        else
+          {
+            fn: @md.fnb,
+            lng: @md.lang_code_insert,
+            ft: sfx,
+          }
+        end
+      end
+      def lang_code?(lng)
+        (output_dir_structure.by_language_code?) \
+        ? ''
+        : (lng ||=@md.lang_code_insert)
+      end
+      def txt(fh=nil)
+        fh=default_hash_build(fh,Sfx[:txt])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_filename?
+          {
+            fn: 'plain',
+            ft: fh[:ft],
+            lng: fh[:lng],
+           }
+         else
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def textile(fh=nil)
+        fh=default_hash_build(fh,Sfx[:txt_textile])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_filename?
+          {
+            fn: 'plain',
+            ft: fh[:ft],
+            lng: fh[:lng],
+           }
+         else
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def asciidoc(fh=nil)
+        fh=default_hash_build(fh,Sfx[:txt_asciidoc])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_filename?
+          {
+            fn: 'plain',
+            ft: fh[:ft],
+            lng: fh[:lng],
+           }
+         else
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def markdown(fh=nil)
+        fh=default_hash_build(fh,Sfx[:txt_markdown])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_filename?
+          {
+            fn: 'plain',
+            ft: fh[:ft],
+            lng: fh[:lng],
+           }
+         else
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def rst(fh=nil)
+        fh=default_hash_build(fh,Sfx[:txt_rst])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_filename?
+          {
+            fn: 'plain',
+            ft: fh[:ft],
+            lng: fh[:lng],
+           }
+         else
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def orgmode(fh=nil)
+        fh=default_hash_build(fh,Sfx[:txt_orgmode])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_filename?
+          {
+            fn: 'plain',
+            ft: fh[:ft],
+            lng: fh[:lng],
+           }
+         else
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def html_scroll(fh=nil)
+        fh=default_hash_build(fh,Sfx[:html])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_filename?
+          {
+            fn: 'scroll',
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        else
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def html_seg_index(fh=nil)
+        fh=default_hash_build(fh,Sfx[:html])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh={
+          fn: 'index',
+          ft: fh[:ft],
+          lng: fh[:lng],
+        }
+        i18n(fnh)
+      end
+      def html_segtoc(fh=nil)
+        fh=default_hash_build(fh,Sfx[:html])
+        fnh=if output_dir_structure.dump_or_redirect?
+          {
+            fn: fh[:fn] + '.toc',
+            ft: fh[:ft],
+          }
+        else
+          {
+            fn: 'toc',
+            ft: fh[:ft],
+            lng: lang_code?(fh[:lng]),
+          }
+        end
+        i18n(fnh)
+      end
+      def html_seg(fh)
+        fh=default_hash_build(fh,Sfx[:html])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh={
+          fn: fh[:fn],
+          ft: fh[:ft],
+          lng: fh[:lng],
+        }
+        i18n(fnh)
+      end
+      def html_book_index(fh=nil)
+        fh=default_hash_build(fh,Sfx[:html])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh={
+          fn: 'book_index',
+          ft: fh[:ft],
+          lng: fh[:lng],
+        }
+        i18n(fnh)
+      end
+      def html_concordance(fh=nil)
+        fh=default_hash_build(fh,Sfx[:html])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.dump_or_redirect?
+          {
+            fn: 'concordance',
+            ft: fh[:ft],
+          }
+        else
+          {
+            fn: 'concordance',
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def xhtml(fh=nil)
+        fh=default_hash_build(fh,Sfx[:xhtml])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_filename?
+          {
+            fn: 'scroll',
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        else
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def epub(fh=nil)
+        fh=default_hash_build(fh,Sfx[:epub])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh={
+          fn: fh[:fn],
+          ft: fh[:ft],
+          lng: fh[:lng],
+        }
+        i18n(fnh)
+      end
+      def odt(fh=nil)
+        fh=default_hash_build(fh,Sfx[:odt])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_filename?
+          {
+            fn: 'opendocument',
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        else
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def xml_sax(fh=nil)
+        fh=default_hash_build(fh,Sfx[:xml_sax])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_filename?
+          {
+            fn: 'scroll',
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        else
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def xml_dom(fh=nil)
+        fh=default_hash_build(fh,Sfx[:xml_dom])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_filename?
+          {
+            fn: 'scroll',
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        else
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def xml_docbook_book(fh=nil)
+        fh=default_hash_build(fh,Sfx[:xml_docbook_book])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_filename?
+          {
+            fn: 'scroll',
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        else
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def xml_fictionbook(fh=nil)
+        fh=default_hash_build(fh,Sfx[:xml_fictionbook])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_filename?
+          {
+            fn: 'scroll',
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        else
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def xml_scaffold_structure_sisu(fh=nil)
+        fh=default_hash_build(fh,Sfx[:xml_scaffold_structure_sisu])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_filename?
+          {
+            fn: 'scroll',
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        else
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def xml_scaffold_structure_collapse(fh=nil)
+        fh=default_hash_build(fh,Sfx[:xml_scaffold_structure_collapse])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_filename?
+          {
+            fn: 'scroll',
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        else
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def json(fh=nil)
+        fh=default_hash_build(fh,Sfx[:json])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_filename?
+          {
+            fn: 'scroll',
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        else
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def pdf_p(fh=nil)
+        fh=default_hash_build(fh,Sfx[:pdf])
+        fh[:lng]=lang_code?(fh[:lng])
+        if output_dir_structure.by_filename?
+          'portrait' + fh[:lng] + '.'
+        else
+          fh[:fn] + '.portrait' + fh[:lng] + '.'
+        end
+      end
+      def pdf_l(fh=nil)
+        fh=default_hash_build(fh,Sfx[:pdf])
+        fh[:lng]=lang_code?(fh[:lng])
+        if output_dir_structure.by_filename?
+          'landscape' + fh[:lng] + '.'
+        else
+          fh[:fn] + '.landscape' + fh[:lng] + '.'
+        end
+      end
+      def pdf_p_a4(fh=nil)
+        pdf_p(fh) + @md.fn[:pdf_p_a4]
+      end
+      def pdf_p_a5(fh=nil)
+        pdf_p(fh) + @md.fn[:pdf_p_a5]
+      end
+      def pdf_p_b5(fh=nil)
+        pdf_p(fh) + @md.fn[:pdf_p_b5]
+      end
+      def pdf_p_letter(fh=nil)
+        pdf_p(fh) + @md.fn[:pdf_p_letter]
+      end
+      def pdf_p_legal(fh=nil)
+        pdf_p(fh) + @md.fn[:pdf_p_legal]
+      end
+      def pdf_l_a4(fh=nil)
+        pdf_l(fh) + @md.fn[:pdf_l_a4]
+      end
+      def pdf_l_a5(fh=nil)
+        pdf_l(fh) + @md.fn[:pdf_l_a5]
+      end
+      def pdf_l_b5(fh=nil)
+        pdf_l(fh) + @md.fn[:pdf_l_b5]
+      end
+      def pdf_l_letter(fh=nil)
+        pdf_l(fh) + @md.fn[:pdf_l_letter]
+      end
+      def pdf_l_legal(fh=nil)
+        pdf_l(fh) + @md.fn[:pdf_l_legal]
+      end
+      def manpage(fh=nil)
+        fh=default_hash_build(fh,Sfx[:manpage])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh={
+          fn: fh[:fn],
+          ft: fh[:ft],
+          lng: fh[:lng],
+        }
+        i18n(fnh)
+      end
+      def info(fh=nil)
+        fh=default_hash_build(fh,Sfx[:info])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh={
+          fn: fh[:fn],
+          ft: fh[:ft],
+          lng: fh[:lng],
+        }
+        i18n(fnh)
+      end
+      def texinfo(fh=nil)
+        fh=default_hash_build(fh,Sfx[:texinfo])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh={
+          fn: fh[:fn],
+          ft: fh[:ft],
+          lng: fh[:lng],
+        }
+        i18n(fnh)
+      end
+      def sqlite_discrete(fh=nil)
+        fh=default_hash_build(fh,Sfx[:sql])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh={
+          fn: fh[:fn],
+          ft: fh[:ft],
+          lng: fh[:lng],
+        }
+        i18n(fnh)
+      end
+      def hash_digest(fh=nil)
+        fh=default_hash_build(fh,Sfx[:txt])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_language_code?
+          {
+            fn: fh[:fn] + '.hash_digest',
+            ft: fh[:ft],
+          }
+        elsif output_dir_structure.by_filetype?
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        else
+          {
+            fn: 'digest',
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def sitemap(fh=nil)
+        fh=default_hash_build(fh,Sfx[:xml])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_language_code?
+          {
+            fn: fh[:fn] + '.sitemap',
+            ft: fh[:ft],
+          }
+        elsif output_dir_structure.by_filetype?
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        else
+          {
+            fn: 'sitemap',
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def qrcode_title(fh=nil)
+        fh=default_hash_build(fh,'.title.png')
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_filename?
+          {
+            fn: 'sisu_manifest',
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        else
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def qrcode_md #check name below
+        fh=default_hash_build(fh,'.md.png')
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_filename?
+          {
+            fn: 'sisu_manifest',
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        else
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def manifest_txt(fh=nil)
+        fh=default_hash_build(fh,Sfx[:txt])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.by_filename?
+          {
+            fn: 'sisu_manifest',
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        else
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def manifest(fh=nil)
+        fh=default_hash_build(fh,Sfx[:html])
+        fh[:lng]=lang_code?(fh[:lng])
+        fnh=if output_dir_structure.dump_or_redirect?
+          {
+            fn: fh[:fn] + '.manifest',
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        elsif output_dir_structure.by_filename?
+          {
+            fn: 'sisu_manifest',
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        else
+          {
+            fn: fh[:fn],
+            ft: fh[:ft],
+            lng: fh[:lng],
+          }
+        end
+        i18n(fnh)
+      end
+      def src
+        @md.fno
+      end
+      def po4a_cfg
+        'po4a.cfg'
+      end
+      def po #check
+        (@fno.empty?) \
+        ? (@md.fn[:po])
+        : (@fno + '.po')
+      end
+      def pot
+        (@fno.empty?) \
+        ? (@md.fn[:pot])
+        : (@fno + '.pot')
+      end
+      def po4a_sst #check
+        @fno
+      end
+      def sisupod
+        (@md.fns =~/\.ssm\.sst$/) \
+        ? @md.fns.gsub(/(?:\~\S{2,3})?\.ssm\.sst$/,'.ssm.txz')
+        : @md.fns.gsub(/(?:\~\S{2,3})?(\.sst)$/,'\1.txz')
+      end
+      self
+    end
+    def set_path(ft)
+      @ft=ft
+      def dir
+        def abc
+          if output_dir_structure.redirect?
+            @md.opt.opt_act[:redirect][:inst] + '/' + @md.fnb
+          elsif output_dir_structure.dump?
+            @md.opt.opt_act[:dump][:inst]
+          elsif output_dir_structure.by_language_code?
+            output_path.base.dir + '/' + @md.opt.lng + '/' + @ft
+          elsif output_dir_structure.by_filetype?
+            output_path.base.dir + '/' + @ft
+          else
+            output_path.base.dir + '/' + @md.fnb
+          end
+        end
+        def ab
+          if output_dir_structure.redirect?
+            @md.opt.opt_act[:redirect][:inst] + '/' + @md.fnb
+          elsif output_dir_structure.dump?
+            @md.opt.opt_act[:dump][:inst]
+          elsif output_dir_structure.by_language_code?
+            output_path.base.dir + '/' + @md.opt.lng + '/' + @ft
+          else
+            output_path.base.dir + '/' + @ft
+          end
+        end
+        def ab_src
+          if output_dir_structure.redirect?
+            @md.opt.opt_act[:redirect][:inst] + '/' + @md.fnb
+          elsif output_dir_structure.dump?
+            @md.opt.opt_act[:dump][:inst]
+          else
+            output_path.base.dir + '/' \
+              + @ft + '/' \
+              + @md.opt.fng + '/' \
+              + Gt[:sisupod] + '/' \
+              + Gt[:doc] + '/' \
+              + @md.opt.lng
+          end
+        end
+        def ab_pod
+          if output_dir_structure.redirect?
+            @md.opt.opt_act[:redirect][:inst] + '/' + @md.fnb
+          elsif output_dir_structure.dump?
+            @md.opt.opt_act[:dump][:inst]
+          else
+            output_path.base.dir + '/' + @ft
+          end
+        end
+        self
+      end
+      def url
+        def abc
+          if output_dir_structure.by_language_code?
+            output_path.base.url + '/' + @md.opt.lng + '/' + @ft
+          elsif output_dir_structure.by_filetype?
+            output_path.base.url + '/' + @ft
+          else
+            output_path.base.url + '/' + @md.fnb
+          end
+        end
+        def ab
+          if output_dir_structure.by_language_code?
+            output_path.base.url + '/' + @md.opt.lng + '/' + @ft
+          else
+            output_path.base.url + '/' + @ft
+          end
+        end
+        def ab_src
+          output_path.base.url + '/' \
+            + @ft + '/' \
+            + @md.opt.fng + '/' \
+            + Gt[:sisupod] + '/' \
+            + Gt[:doc] + '/' \
+            + @md.opt.lng
+        end
+        def ab_pod
+          output_path.base.url + '/' + @ft
+        end
+        self
+      end
+      def rel
+        def abc
+          if output_dir_structure.by_language_code?
+            @md.opt.lng + '/' + @ft
+          elsif output_dir_structure.by_filetype?
+            @ft
+          else
+            @md.fnb
+          end
+        end
+        def ab
+          if output_dir_structure.by_language_code?
+            @md.opt.lng + '/' + @ft
+          else
+            @ft
+          end
+        end
+        def ab_src
+          @ft
+        end
+        def ab_pod
+          @ft
+        end
+        self
+      end
+      def rel_sm
+        def abc
+          if output_dir_structure.by_language_code?
+            @md.opt.lng + '/' + @ft
+          elsif output_dir_structure.by_filetype?
+            @ft
+          else
+            @md.fnb
+          end
+        end
+        def ab
+          if output_dir_structure.dump_or_redirect?
+            '.'
+          elsif output_dir_structure.by_language_code? \
+          or output_dir_structure.by_filetype?
+            '../' + @ft
+          else '.'
+          end
+        end
+        def ab_src
+          locate="#{@ft}/#{@md.opt.fng}/#{Gt[:sisupod]}/#{Gt[:doc]}/#{@md.opt.lng}"
+          if output_dir_structure.dump_or_redirect?
+            '.'
+          elsif output_dir_structure.by_language_code?
+            '../../' + locate
+          else
+            '../' + locate
+          end
+        end
+        def ab_pod
+          if output_dir_structure.dump_or_redirect?
+            '.'
+          elsif output_dir_structure.by_language_code?
+            '../../' + @ft
+          else
+            '../' + @ft
+          end
+        end
+        self
+      end
+      def rcp
+        def abc
+          if output_dir_structure.by_language_code?
+            output_path.stub.rcp + '/' + @md.opt.lng + '/' + @ft
+          elsif output_dir_structure.by_filetype?
+            output_path.stub.rcp + '/' + @ft
+          else
+            output_path.stub.rcp + '/' + @md.fnb
+          end
+        end
+        def ab
+          if output_dir_structure.by_language_code?
+            output_path.stub.rcp + '/' + @md.opt.lng + '/' + @ft
+          else
+            output_path.stub.rcp + '/' + @ft
+          end
+        end
+        self
+      end
+      self
+    end
+    def output_path
+      def web_base
+        def dir
+          @env.path.webserv
+        end
+        def url
+          #"#{@env.url.root}"
+        end
+        def rel
+          '.'
+        end
+        def rcp
+          '.'
+        end
+        self
+      end
+      def stub
+        def dir
+          @md.opt.f_pth[:pth_stub]
+        end
+        #def url
+        #  "#{@env.url.root}"
+        #end
+        def rel
+          './' + @md.opt.f_pth[:pth_stub]
+        end
+        def rcp
+          @md.opt.f_pth[:pth_stub]
+        end
+        self
+      end
+      def webserver_path
+        if output_dir_structure.dump?
+          @md.opt.opt_act[:dump][:inst]
+        elsif output_dir_structure.redirect?
+          @md.opt.opt_act[:redirect][:inst]
+        else
+          @env.path.webserv
+        end
+      end
+      def base
+        def dir
+          webserver_path + '/' + @md.opt.f_pth[:pth_stub]
+        end
+        def url
+          @env.url.webserv + '/' + @md.opt.f_pth[:pth_stub]
+        end
+        def rel
+          './' + @md.opt.f_pth[:pth_stub]
+        end
+        def rcp
+          './' + @md.opt.f_pth[:pth_stub]
+        end
+        self
+      end
+      def sisugit
+        def dir
+          output_path.base.dir + '/git'
+        end
+        def url
+          output_path.base.url + '/git'
+        end
+        def rel
+          output_path.base.rel + '/git'
+        end
+        def rcp
+          output_path.base.rcp + '/git'
+        end
+        self
+      end
+      #def pod
+      #  ft='pod'
+      #  path=set_path(ft).dir.ab
+      #end
+      def src
+        def ft
+          Gt[:src]
+        end
+        def dir
+          set_path(ft).dir.ab_src
+        end
+        def url
+          set_path(ft).url.ab_src
+        end
+        def rel
+          set_path(ft).rel.ab_src
+        end
+        def rcp
+          set_path(ft).rcp.ab_src
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab_src
+        end
+        self
+      end
+      def sisupod
+        def ft
+          Gt[:src]
+        end
+        def dir
+          set_path(ft).dir.ab_pod
+        end
+        def url
+          set_path(ft).url.ab_pod
+        end
+        def rel
+          set_path(ft).rel.ab_pod
+        end
+        def rcp
+          set_path(ft).rcp.ab_pod
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab_pod
+        end
+        self
+      end
+      def po4a
+        def dir
+         output_path.base.dir + '/' \
+           + Gt[:src] + '/' \
+           + @md.opt.fng + '/po4a'
+        end
+        def url
+          output_path.base.url + '/po4a/' \
+            + @md.fnb
+        end
+        def rcp
+          #p "#{output_path.base.dir}/po4a/#{@md.fnb}"
+        end
+        self
+      end
+      def po(lng=@md.opt.lng)
+        @lng=lng
+        def dir
+          output_path.base.dir + '/' \
+            + Gt[:src] + '/' \
+            + @md.opt.fng + '/po4a/po/' \
+            + @lng
+        end
+        def url
+          output_path.base.url + '/po4a/' \
+            + @md.fnb + '/po/' \
+            + @lng
+        end
+        self
+      end
+      def pot
+        def dir
+         output_path.base.dir + '/' \
+           + Gt[:src] + '/' \
+           + @md.opt.fng + '/po4a/pot'
+        end
+        def url
+          output_path.base.url + '/po4a/' \
+            + @md.fnb + '/pot'
+        end
+        def rcp
+          #p "#{output_path.base.dir}/po4a/#{@md.fnb}/pot"
+        end
+        self
+      end
+      def po_git # consider !!!
+        def ft
+          Gt[:po]
+        end
+        def dir
+          pth=@env.processing_path.git + '/' \
+            + @md.fnb + '/' \
+            + ft + '/' \
+            + @md.opt.lng
+          FileUtils::mkdir_p(pth) unless FileTest.directory?(pth)
+          pth
+        end
+        self
+      end
+      def pot_git # consider !!!
+        def ft
+          Gt[:pot]
+        end
+        def dir
+          @env.processing_path.git + '/' \
+            + @md.fnb + '/' \
+            + ft
+        end
+        self
+      end
+      def po4a_sst(lng=@md.opt.lng)
+        @lng=lng
+        def dir
+          output_path.base.dir + '/' \
+            + Gt[:src] + '/' \
+            + @md.opt.fng + '/po4a/' \
+            + @lng
+        end
+        def url
+          output_path.base.url + '/po4a/' \
+            + @md.fnb \
+            + @lng
+        end
+        self
+      end
+      def md_harvest
+        manifest
+        self
+      end
+      def txt
+        def ft
+          'txt'
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        self
+      end
+      def textile
+        def ft
+          'textile' \
+            + DEVELOPER[:under_construction]
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        self
+      end
+      def asciidoc
+        def ft
+          'asciidoc' \
+            + DEVELOPER[:under_construction]
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        self
+      end
+      def markdown
+        def ft
+          'markdown' \
+            + DEVELOPER[:under_construction]
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        self
+      end
+      def rst
+        def ft
+          'rst' \
+            + DEVELOPER[:under_construction]
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        self
+      end
+      def orgmode
+        def ft
+          'orgmode' \
+            + DEVELOPER[:under_construction]
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        self
+      end
+      def html_scroll
+        def ft
+          'html'
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        def rel_image
+          if output_dir_structure.dump_or_redirect?
+            './image'
+          elsif output_dir_structure.by_language_code?
+            '../../_sisu/image'
+          elsif output_dir_structure.by_filetype?
+            '../_sisu/image'
+          else
+            '../_sisu/image'
+          end
+        end
+        self
+      end
+      def html_seg
+        def ft
+          'html/' + @md.fnb
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        def rel_image
+          if output_dir_structure.dump_or_redirect?
+            './image'
+          elsif output_dir_structure.by_language_code?
+            '../../../_sisu/image'
+          elsif output_dir_structure.by_filetype?
+            '../../_sisu/image'
+          else
+            '../_sisu/image'
+          end
+        end
+        self
+      end
+      def html_concordance
+        html_seg
+        self
+      end
+      def html
+        def ft
+          'html'
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).url.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        def rel_image
+          if output_dir_structure.by_language_code?
+            '../../_sisu/image'
+          elsif output_dir_structure.by_filetype?
+            '../_sisu/image'
+          else
+            '../_sisu/image'
+          end
+        end
+        self
+      end
+      def xhtml
+        def ft
+          'xhtml'
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        def rel_image
+          '../../_sisu/image'
+        end
+        self
+      end
+      def epub
+        def ft
+          'epub'
+        end
+        def dir
+          set_path(ft).dir.ab
+        end
+        def url
+          set_path(ft).url.ab
+        end
+        def rel
+          set_path(ft).rel.ab
+        end
+        def rcp
+          set_path(ft).rcp.ab
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        def rel_image
+          './image'
+        end
+        self
+      end
+      def odt
+        def ft
+          'odt'
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        self
+      end
+      def xml
+        def ft
+          'xml'
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        def rel_image
+          '../../_sisu/image'
+        end
+        self
+      end
+      def xml_sax
+        xml
+        self
+      end
+      def xml_dom
+        xml
+        self
+      end
+      def xml_docbook
+        def ft
+          'docbook'
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        def rel_image
+          '../../_sisu/image'
+        end
+        self
+      end
+      def xml_docbook_article
+        def ft
+          'docbook' \
+            + DEVELOPER[:under_construction]
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        def rel_image
+          '../../_sisu/image'
+        end
+        self
+      end
+      def xml_docbook_book
+        def ft
+          'docbook'
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        def rel_image
+          '../../_sisu/image'
+        end
+        self
+      end
+      def xml_fictionbook
+        def ft
+          'fictionbook' \
+            + DEVELOPER[:under_construction]
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        def rel_image
+          '../../_sisu/image'
+        end
+        self
+      end
+      def xml_scaffold_structure_sisu
+        def ft
+          'sisu.scaffold.xml'
+          #'xml'
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        def rel_image
+          '../../_sisu/image'
+        end
+        self
+      end
+      def xml_scaffold_structure_collapse
+        def ft
+          'collapsed.scaffold.xml'
+          #'xml'
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        def rel_image
+          '../../_sisu/image'
+        end
+        self
+      end
+      def json
+        def ft
+          'json'
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        def rel_image
+          '../../_sisu/image'
+        end
+        self
+      end
+      def pdf
+        def ft
+          'pdf'
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        self
+      end
+      def sqlite_discrete
+        def ft
+          'sql'
+        end
+        def dir
+          set_path(ft).dir.ab
+        end
+        def url
+          set_path(ft).url.ab
+        end
+        def rel
+          set_path(ft).rel.ab
+        end
+        def rcp
+          set_path(ft).rcp.ab
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        self
+      end
+      def hash_digest
+        def ft
+          'hashes'
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        self
+      end
+      def manifest
+        def ft
+          'manifest'
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rel_image
+          if output_dir_structure.dump_or_redirect?
+            './image'
+          elsif output_dir_structure.by_language_code?
+            '../../_sisu/image'
+          elsif output_dir_structure.by_filetype?
+            '../_sisu/image'
+          else
+            '../_sisu/image'
+          end
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        self
+      end
+      def qrcode
+        def ft
+          'manifest/qrcode'
+        end
+        def dir
+          set_path(ft).dir.abc
+        end
+        def url
+          set_path(ft).url.abc
+        end
+        def rel
+          set_path(ft).rel.abc
+        end
+        def rcp
+          set_path(ft).rcp.abc
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        self
+      end
+      def harvest
+        def ft
+          'site_metadata'
+        end
+        def dir
+          set_path(ft).dir.ab
+        end
+        def url
+          set_path(ft).url.ab
+        end
+        def rel
+          set_path(ft).rel.ab
+        end
+        def rcp
+          set_path(ft).rcp.ab
+        end
+        def rel_sm
+          if output_dir_structure.by_language_code?
+            ''
+          elsif output_dir_structure.by_filetype?
+            ''
+          else
+            ''
+          end
+        end
+        self
+      end
+      def manpage
+        def ft
+          'man'
+        end
+        def dir
+          set_path(ft).dir.ab
+        end
+        def url
+          set_path(ft).url.ab
+        end
+        def rel
+          set_path(ft).rel.ab
+        end
+        def rcp
+          set_path(ft).rcp.ab
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        self
+      end
+      def texinfo
+        def ft
+          'texinfo'
+        end
+        def dir
+          set_path(ft).dir.ab
+        end
+        def url
+          set_path(ft).url.ab
+        end
+        def rel
+          set_path(ft).rel.ab
+        end
+        def rcp
+          set_path(ft).rcp.ab
+        end
+        def rel_sm
+          set_path(ft).rel_sm.ab
+        end
+        self
+      end
+      def sitemaps
+        def ft
+          'sitemaps'
+        end
+        def dir
+          set_path(ft).dir.ab
+        end
+        def url
+          set_path(ft).url.ab
+        end
+        def rel
+          set_path(ft).rel.ab
+        end
+        def rcp
+          set_path(ft).rcp.ab
+        end
+        self
+      end
+      def sqlite #check url
+        def dir
+          output_path.base.dir
+        end
+        def url
+          output_path.base.url
+        end
+        def rel
+          output_path.base.rel
+        end
+        def rcp
+          output_path.base.rcp
+        end
+        self
+      end
+      #def cgi
+      #end
+      def css
+        @d='_sisu/css'
+        def dir
+          output_path.base.dir + '/' + @d
+        end
+        def url
+          output_path.base.url + '/' + @d
+        end
+        def rel
+          @d
+          #output_path.base.rel + '/' + @d
+        end
+        def rcp
+          output_path.stub.rcp + '/' + @d
+        end
+        self
+      end
+      def images
+        @d='_sisu/image'
+        def dir
+          output_path.base.dir + '/' + @d
+        end
+        def url
+          output_path.base.url + '/' + @d
+        end
+        def rel
+          @d
+          #output_path.base.rel + '/' + @d
+        end
+        def rcp
+          output_path.stub.rcp + '/' + @d
+        end
+        self
+      end
+      def images_external
+        @d='_sisu/image_external'
+        def dir
+          output_path.base.dir + '/' + @d
+        end
+        def url
+          output_path.base.url + '/' + @d
+        end
+        def rel
+          output_path.base.rel + '/' + @d
+        end
+        def rcp
+          output_path.base.rcp + '/' + @d
+        end
+        self
+      end
+      #def css
+      #  #"#{@env.path.output}/#{@env.path.style}"
+      #end
+      self
+    end
+  end
+end
+module SiSU_Create_File
+  require_relative 'constants'                             # constants.rb
+  require_relative 'utils'                                 # utils.rb
+  require_relative 'se_info_env'                           # se_info_env.rb
+  class CreateFile < SiSU_Info_Env::InfoEnv                # se_info_env.rb
+    #todo unify with FileOp
+    def initialize(fns)
+      begin
+        super(fns)
+        @env=SiSU_Env::InfoEnv.new(fns)
+      rescue
+        SiSU_Screen::Ansi.new('',$!,$@).rescue do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    def html_root
+      #@env.path.output
+    end
+    def mkdir_pdf
+      Dir.mkdir(@env.processing_path.tex) \
+        unless FileTest.directory?(@env.processing_path.tex)
+    end
+    def file_generic(output_file='')
+      fn=@env.path.output + '/' \
+      + @fnb + '/' \
+      + output_file
+      File.new(fn,'w+')
+    end
+    def file_error
+      fn='/tmp/errorlog.sisu'
+      File.new(fn,'w+')
+    end
+    def file_txt
+      fn=@env.processing_path.ao + '/' \
+      + @fns + '.txt'
+      File.new(fn,'w+')
+    end
+    def file_debug
+      fn=@env.processing_path.ao + '/' \
+      + @fns + '.debug.txt'
+      File.new(fn,'w+')
+    end
+    def metaverse
+      def file_meta
+        fn=@env.processing_path.ao + '/' \
+        + @fns + '.meta'
+        File.new(fn,'w+')
+      end
+      def file_meta_idx_html
+        fn=@env.processing_path.ao + '/' \
+        + @fns + '.idx.html'
+        File.new(fn,'w+')
+      end
+      self
+    end
+    def file_note
+      fn=Dir.pwd + '/' \
+      + @fns + '.fn'
+      File.new(fn,'w+')
+    end
+    def meta
+      @env.processing_path.ao + '/' \
+      + @fns + '.meta'
+    end
+    def file_semantic
+      fn='./semantic.yaml'
+      File.new(fn,'w+')
+    end
+    def file_rss
+      fn='./semantic.xml'
+      File.new(fn,'w+')
+    end
+    def epub
+      @pth=@env.processing_path.epub
+      def xhtml_index
+        fn=@pth + '/' \
+        + Ep[:d_oebps] + '/index.xhtml'
+        File.new(fn,'w+')
+      end
+      def xhtml_cover_image
+        fn=@pth + '/' \
+        + Ep[:d_oebps] + '/cover_image.xhtml'
+        File.new(fn,'w+')
+      end
+      def xhtml_segtoc
+        fn=@pth + '/' \
+        + Ep[:d_oebps] + '/toc.xhtml'
+        File.new(fn,'w+')
+      end
+      def mimetype  #fixed application/epub+zip ~/grotto/theatre/dbld/builds/epub_sample/mimetype
+        File.new("#{@pth}/mimetype",'w')
+      end
+      def metadata #variable matadata ~/grotto/theatre/dbld/builds/epub_sample/metadata.opf
+        fn=@pth + '/' \
+        + Ep[:d_oebps] + '/' \
+        + Ep[:f_opf]
+        File.new(fn,'w')
+      end
+      def toc_ncx  #variable toc ~/grotto/theatre/dbld/builds/epub_sample/toc.ncx
+        fn=@pth + '/' \
+        + Ep[:d_oebps] + '/' \
+        + Ep[:f_ncx]
+        File.new(fn,'w')
+      end
+      def metainf_cont #variable content ~/grotto/theatre/dbld/builds/epub_sample/META-INF/container.xml
+        fn=@pth + '/META-INF/container.xml'
+        File.new(fn,'w')
+      end
+      def xhtml_css #fixed epub xhtml css
+        fn=@pth + '/' \
+        + Ep[:d_oebps] + '/css/xhtml.css'
+        File.new(fn,'w')
+      end
+      self
+    end
+    def file_texinfo
+      fn=@env.processing_path.texinfo + '/' \
+      + @fnb + '.texinfo'
+      File.new(fn,'w+')
+    end
+  end
+end
+module SiSU_Filename_Lang
+  require_relative 'constants'                             # constants.rb
+  require_relative 'utils'                                 # utils.rb
+  class FilenameLanguageCodeInsert
+    def initialize(opt,lng=nil)
+      @opt=opt
+      @lng=lng ||=opt.lng
+    end
+    def language_code_insert
+      if @opt.dir_structure_by ==:language \
+      or ((@opt.dir_structure_by ==:filetype \
+      || @opt.dir_structure_by ==:filename) \
+      and (@opt.lingual ==:mono \
+      && @lng == @opt.act[:default_language][:code]))
+        ''
+      elsif (@opt.dir_structure_by ==:filetype \
+      || @opt.dir_structure_by ==:filename) \
+      and not @opt.lingual ==:mono
+        '.' + @lng
+      else
+        '.' + @lng
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** se_get_init.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se_get_init.rb"
+# <<sisu_document_header>>
+module SiSU_Get_Init
+  require_relative 'constants'                             # constants.rb
+  require_relative 'utils'                                 # utils.rb
+  require_relative 'se_info_system'                        # se_info_system.rb
+  @@noyaml=false
+  class GetInit < SiSU_Info_Sys_Gen::InfoSystemGen         # se_info_system.rb
+    @@noyaml=false
+    @@rc,@@sisu_doc_makefile,@@sisurc_path,@@tx=nil,nil,nil,nil
+    @@ad={ promo: nil, promo_list: nil, flag_promo: false }
+    @@sdmd=nil
+    attr_accessor :yaml
+    def initialize
+      super()
+        @markup_dir_changed_=if @@sdmd==$sisu_document_markup_directory
+          false
+        else
+          @@sdmd=$sisu_document_markup_directory
+          true
+        end
+    end
+    def tex
+      require_relative 'texpdf_parts'                        # texpdf_parts.rb
+      @@tx ||=SiSU_Parts_TeXpdf::TeX.new
+    end
+    def rc_path_options
+      v=SiSU_Env::InfoVersion.instance.get_version
+      [
+        $sisu_document_markup_directory_base_fixed_path \
+        + '/.sisu/v' \
+        + v.version_major,
+        $sisu_document_markup_directory_base_fixed_path \
+        + '/.sisu',
+        $sisu_document_markup_directory_base_fixed_path \
+        + '/_sisu/v' \
+        + v.version_major,
+        $sisu_document_markup_directory_base_fixed_path \
+        + '/_sisu',
+        @@home \
+        + '/.sisu/v' \
+        + v.version_major,
+        @@home \
+        + '/.sisu', \
+        @@sisu_etc \
+        + '/v' \
+        + v.version_major,
+        @@sisu_etc,
+      ]
+    end
+    def sisu_document_make
+      def makefile_name
+        S_CONF[:header_make]
+      end
+      def makefile
+        rc_path_options.each do |v|
+          if FileTest.exist?("#{v}/#{makefile_name}")
+            @sisu_make_path=v
+            break
+          end
+        end
+        @sisu_make_file_path=@sisu_make_path \
+        ? "#{@sisu_make_path}/#{makefile_name}"
+        : nil
+      end
+      def makefile_read
+        if makefile
+          sisu_doc_makefile=IO.read(makefile, mode: 'r:utf-8')
+          @sisu_doc_makefile=sisu_doc_makefile.split(/\s*\n\s*\n/m)
+        end
+        @sisu_doc_makefile
+      end
+      self
+    end
+    def sisu_yaml
+      def rc
+        if @markup_dir_changed_
+          rc_path_options.each do |v|
+            if @@noyaml \
+            or FileTest.exist?("#{v}/noyaml")
+              STDERR.puts "WARNING - YAML loading switched off, to enable delete the file:\n\t#{v}/noyaml\n\n" unless @@noyaml
+              @@noyaml=true
+              break
+            else
+              f=S_CONF[:rc_yml]
+              p_f="#{v}/#{f}"
+              if FileTest.exist?(p_f)
+                begin
+                  require 'yaml'
+                rescue LoadError
+                  SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+                    error('yaml NOT FOUND (LoadError)')
+                end
+                @@sisurc_path=v
+                @@rc=YAML::load(File::open(p_f))
+                break
+              end
+              unless @@rc
+                f='sisurc.yaml'
+                p_f="#{v}/#{f}"
+                if FileTest.exist?(p_f)
+                  begin
+                    require 'yaml'
+                  rescue LoadError
+                    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+                      error('yaml NOT FOUND (LoadError)')
+                  end
+                  @@sisurc_path=v
+                  @@rc=YAML::load(File::open(p_f))
+                  break
+                end
+              end
+            end
+          end
+        end
+        @@rc
+      end
+      def rc_path
+        rc
+        @@sisurc_path
+      end
+      self
+    end
+    def ads #WORK AREA
+      tell_no_yaml='WARNING - YAML loading switched off, to enable delete the file:'
+      if @markup_dir_changed_
+        @ad_path=[
+          "#{$sisu_document_markup_directory_base_fixed_path}/.sisu/skin/yml",
+          "#{$sisu_document_markup_directory_base_fixed_path}/_sisu/skin/yml",
+          "#{@@home}/.sisu/skin/yml",
+          "#{@@sisu_etc}/skin/yml",
+        ]
+        @ad_path.each do |v|
+          if @@noyaml \
+          or FileTest.exist?("#{v}/noyaml")
+            puts tell_no_yaml + "\n\t#{v}/noyaml\n" unless @@noyaml
+            @@noyaml=true
+            break
+          else
+            if FileTest.exist?("#{v}/list.yml")
+              unless @@ad[:promo_list]
+                begin
+                  require 'yaml'
+                rescue LoadError
+                  SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+                    error('yaml NOT FOUND (LoadError)')
+                end
+                @@ad[:promo_list] ||= YAML::load(File::open("#{v}/list.yml"))
+              end
+              @@ad[:flag_promo]=true
+              break
+            end
+            @@ad[:flag_promo]=false
+          end
+        end
+        @ad_path.each do |v|
+          if @@noyaml \
+          or FileTest.exist?("#{v}/noyaml")
+            puts tell_no_yaml + "\n\t#{v}/noyaml\n" unless @@noyaml
+            @@noyaml=true
+            break
+          else
+            if FileTest.exist?("#{v}/promo.yml")
+              unless @@ad[:promo]
+                begin
+                  require 'yaml'
+                rescue LoadError
+                  SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+                    error('yaml NOT FOUND (LoadError)')
+                end
+                @@ad[:promo] ||= YAML::load(File::open("#{v}/promo.yml"))
+              end
+              @@ad[:flag_promo]=true
+              break
+            end
+            @@ad[:flag_promo]=false
+          end
+        end
+      end
+      @@ad
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** se_hub_particulars.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se_hub_particulars.rb"
+# <<sisu_document_header>>
+module SiSU_Particulars
+  begin
+    require 'singleton'
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('singleton NOT FOUND (LoadError)')
+  end
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'dp'                                 # dp.rb
+    include SiSU_Param
+  require_relative 'ao'                                 # ao.rb
+  class CombinedSingleton
+    include Singleton
+    def get_all(opt)
+      set_env(opt)
+      set_file(opt)
+      set_md(opt)
+      set_ao(opt)                #needs @md
+    end
+    def get_env(opt)
+      set_env(opt)
+    end
+    def get_file(opt)
+      set_file(opt)
+    end
+    def get_md(opt)
+      set_md(opt)
+    end
+    def get_ao_array(opt)
+      set_ao(opt)                #needs @md
+    end
+    def get_env_md(opt)
+      set_env(opt)
+      set_md(opt)
+    end
+    def get_idx_sst(opt)
+      set_sst_idx(opt)
+    end
+    def get_idx_raw(opt)
+      set_raw_idx(opt)
+    end
+    def get_idx_html(opt)
+      set_html_idx(opt)
+    end
+    def get_idx_xhtml(opt)
+      set_xhtml_idx(opt)
+    end
+    def get_name_tags(opt)
+      set_name_tags(opt)
+    end
+    def get_maps(opt)
+      set_nametags_map(opt)
+      set_ocn_htmlseg_map(opt)
+    end
+    def get_map_nametags(opt)
+      set_nametags_map(opt)
+    end
+    def get_map_ocn_htmlseg(opt)
+      set_ocn_htmlseg_map(opt)
+    end
+    attr_accessor :opt,:md,:sst_idx,:raw_idx,:html_idx,:xhtml_idx
+    def set_md(opt)
+      begin
+        @md=SiSU_Param::Parameters.new(opt).get
+        self
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,opt.selections.str,opt.fnl).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      end
+    end
+    attr_accessor :opt,:env,:file
+    def set_env(opt)
+      begin
+        @env=SiSU_Env::InfoEnv.new(opt.fns)
+        self
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,opt.selections.str,opt.fnl).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      end
+    end
+    def set_file(opt)
+      begin
+        set_md(opt) unless @md
+        @file=SiSU_Env::FileOp.new(@md)
+        self
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,opt.selections.str,opt.fnl).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      end
+    end
+    attr_accessor :opt,:ao_array
+    def set_ao(opt)
+      begin
+        @ao_array=SiSU_AO::Source.new(opt).get
+        self
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,opt.selections.str,opt.fnl).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      end
+    end
+    def set_sst_idx(opt)
+      begin
+        @sst_idx=SiSU_AO::Source.new(opt).get_idx_sst
+        self
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,opt.selections.str,opt.fnl).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      end
+    end
+    def set_raw_idx(opt)
+      begin
+        @raw_idx=SiSU_AO::Source.new(opt).get_idx_raw
+        self
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,opt.selections.str,opt.fnl).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      end
+    end
+    def set_html_idx(opt)
+      begin
+        @html_idx=SiSU_AO::Source.new(opt).get_idx_html
+        self
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,opt.selections.str,opt.fnl).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      end
+    end
+    def set_xhtml_idx(opt)
+      begin
+        @xhtml_idx=SiSU_AO::Source.new(opt).get_idx_xhtml
+        self
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,opt.selections.str,opt.fnl).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      end
+    end
+    attr_accessor :nametags_map
+    def set_nametags_map(opt)
+      begin
+        opt=@md ? @md : opt
+        @nametags_map=SiSU_AO::Source.new(opt).get_map_nametags
+        self
+      rescue
+        if @md
+          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.opt.fnl).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+        else
+          SiSU_Errors::Rescued.new($!,$@,opt.selections.str,opt.fnl).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+        end
+      end
+    end
+    attr_accessor :ocn_htmlseg_map
+    def set_ocn_htmlseg_map(opt)
+      begin
+        @ocn_htmlseg_map=SiSU_AO::Source.new(@md).get_map_ocn_htmlseg
+        self
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,opt.selections.str,opt.fnl).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      end
+    end
+  end
+end
+__END__
+consider running as separate objects
+#+END_SRC
+
+** se_info_env.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se_info_env.rb"
+# <<sisu_document_header>>
+@@current_document=Dir.pwd #nil #''
+module SiSU_Info_Env
+  require_relative 'se_envcall'                            # se_envcall.rb
+  require_relative 'html_parts'                            # html_parts.rb
+  begin
+    require 'singleton'
+    require 'fileutils'
+      include FileUtils::Verbose
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('singleton or fileutils NOT FOUND (LoadError)')
+  end
+  class InfoEnv < SiSU_Env_Call::EnvCall                   # se_envcall.rb
+    begin
+      require 'pathname'
+      require 'fileutils'
+        include FileUtils
+    rescue LoadError
+      SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+        error('pathname or fileutils NOT FOUND (LoadError)')
+    end
+    attr_accessor :filename,:sys,:home,:hostname,:user,:env,:rc,:www,:fnb,:fnn,:fnt,:flv,:webserv_path,:stub_pwd,:base_markup_dir_stub,:stub_src,:webserv_host_cgi,:webserv_port_cgi,:processing,:processing_git,:etc,:yamlrc_dir
+    @@image_flag,@@local_image=true,true   #warning on @@image_flag
+    @@fb,@@man_path=nil,nil
+    def initialize(fns='',md=nil)
+      super() #you may not want to re-execute this static info so frequently!
+      @init=SiSU_Env::GetInit.new #SiSU_Get_Init::GetInit
+      @fns,@md=fns,md
+      @env=SiSU_Env::EnvCall.new(fns) if fns #SiSU_Env_Call::EnvCall
+      fnb=if @md \
+      and defined? @md.fnb
+        @md.fnb
+      elsif defined? @env.fnb \
+      and @env.fnb
+        @env.fnb
+      elsif @fns.is_a?(String) \
+      and not @fns.empty?
+        m=/(.+)?\.(?:(?:-|ssm\.)?sst|ssm)$/m
+        @fns[m,1] if not @fns.empty?
+      end
+      if fnb; @@fb ||=fnb
+      end
+      @sys=SiSU_Info_Sys::InfoSystem.instance
+      @fnb ||=@@fb #clean up this... used primarily for zap which is not passed normal parameters
+      @fixed_websev_root='' # @home
+      @pwd=@@pwd=Dir.pwd
+      @base_markup_dir_stub=SiSU_Utils::Path.new.base_markup_stub
+      @stub_src=     @base_markup_dir_stub + '/src'
+      @stub_pod=     @base_markup_dir_stub + '/pod'
+      @stub_epub=    @base_markup_dir_stub + '/epub'
+      m=/.+\/(?:src\/)?(\S+)/m # m=/.+?\/(?:src\/)?([^\/]+)$/im # m=/.+\/(\S+)/m
+      @stub_pwd=@@pwd[m,1] || '' #; p __LINE__; #p @pwd; #p m; #p @stub_pwd
+      pt=Pathname.new(Dir.pwd)
+      stub=if output_dir_structure.by_language_code?
+        r=Px[:lng_lst_rgx]
+        stub=if Dir.pwd =~/.+?\/([^\/]+)(?:\/(#{r})$)/
+          lng=pt.split[-1].to_s
+          lng_part='/' + lng
+          base=pt.split[0].split[-1].to_s
+        else
+          lng_part='/' + language_default_set
+          base=pt.split[-1].to_s
+        end
+        base + lng_part
+      elsif output_dir_structure.by_filetype?
+        pt.split[-1].to_s
+      elsif  output_dir_structure.by_filename?
+        ''
+      else
+        SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+          warn('set output type, by: language, filetype or filename')
+      end
+      @stub_set_manifest=stub + '/manifest'
+    end
+    def user
+      @sys.user
+    end
+    def hostname
+      @sys.hostname
+    end
+    def host
+      @sys.host
+    end
+    def arch
+      @sys.arch
+    end
+    def rbver
+      @sys.rbver
+    end
+    def locale
+      @sys.locale
+    end
+    def concord_max
+      ((defined? @rc['processing']['concord_max']) \
+      && @rc['processing']['concord_max']) \
+      ? @rc['processing']['concord_max']
+      : (defaults[:concord_max])
+    end
+    def language_default_set           #set directory (default) language
+      ((defined? @rc['default']['language']) \
+      && @rc['default']['language'] =~/\S+/) \
+      ? @rc['default']['language']
+      : 'en'
+    end
+    def markup_emphasis
+      if defined? @rc['default']['emphasis'] \
+      and @rc['default']['emphasis'] \
+      and @rc['default']['emphasis']=~/bold/
+        'bold'
+      elsif defined? @rc['default']['emphasis'] \
+      and @rc['default']['emphasis'] \
+      and @rc['default']['emphasis']=~/italic/
+        'italics'
+      elsif defined? @rc['default']['emphasis'] \
+      and @rc['default']['emphasis'] \
+      and @rc['default']['emphasis']=~/underscore/
+        'underscore'
+      else 'bold'
+      end
+    end
+    def plaintext_wrap
+      ((defined? @rc['default']['text_wrap']) \
+      && (@rc['default']['text_wrap']) \
+      && (@rc['default']['text_wrap'].to_s=~/\d\d+/) \
+      && (@rc['default']['text_wrap'].to_i > 19) \
+      && (@rc['default']['text_wrap'].to_i < 201)) \
+      ? @rc['default']['text_wrap'].to_i
+      : 78
+    end
+    def current_document
+      @@current_document||=Dir.pwd
+      @@current_document
+    end
+    def stub_pwd                       #200412
+      @stub_pwd
+    end
+    def base_markup_dir_stub
+      @base_markup_dir_stub
+    end
+    def stub_md_harvest                #watch
+      @stub_set_manifest
+    end
+    def stub_src
+      @stub_src
+    end
+    def stub_pod
+      @stub_pod
+    end
+    def sisupod_v4(opt)
+      #processing_path.processing
+      #  sisupod
+      #    doc/
+      #      manifest.txt
+      #      en/content.sst                [file content]
+      #      fr/content.sst
+      #      _sisu
+      #        sisu_document_make
+      #        image@ (ln -s ../../image)
+      #        audio@ (ln -s ../../audio)
+      #        video@ (ln -s ../../video)
+      #    image/                          [all images for specific document gathered here]
+      #    audio/
+      #    video/
+      spp="#{processing_path.processing}/#{Gt[:sisupod]}"
+      sppc="#{spp}/doc/_sisu"
+      lng_dirs=[]
+      if FileTest.directory?(spp) \
+      or FileTest.file?(spp)
+        FileUtils::rm_rf(spp)
+      end
+      paths=[]
+      flv=SiSU_Env::EnvCall.new(opt.fns).
+        document_language_versions_found
+      flv[:f].each {|l| lng_dirs << l[:l] }
+      lng_dirs.uniq.each do |lng|
+        paths << "#{spp}/doc/#{lng}"
+      end
+      paths \
+      << "#{spp}/image"
+     #<< "#{spp}/audio" \
+     #<< "#{spp}/video" \
+      paths.each do |x|
+        unless FileTest.directory?(x)
+          FileUtils::mkdir_p(x)
+        end
+      end
+      if FileTest.directory?(sppc)
+        pwd=Dir.pwd
+        Dir.chdir(sppc)
+        FileUtils::ln_s('../../image', 'image')
+       #FileUtils::ln_s('../../audio', 'audio')
+       #FileUtils::ln_s('../../video', 'video')
+        Dir.chdir(pwd)
+      end
+    end
+    def sisupod_v3(opt)
+      #processing_path.processing
+      #  sisupod
+      #    doc/
+      #      manifest.txt
+      #      en/content.sst                [file content]
+      #      fr/content.sst
+      #      _sisu
+      #        skin/
+      #          doc                       [relevant skin if any other than default]
+      #        image@ (ln -s ../../image)
+      #        audio@ (ln -s ../../audio)
+      #        video@ (ln -s ../../video)
+      #    image/                          [all images for specific document gathered here]
+      #    audio/
+      #    video/
+      spp="#{processing_path.processing}/#{Gt[:sisupod]}"
+      sppc="#{spp}/doc/_sisu"
+      lng_dirs=[]
+      if FileTest.directory?(spp) \
+      or FileTest.file?(spp)
+        FileUtils::rm_rf(spp)
+      end
+      paths=[]
+      flv=SiSU_Env::EnvCall.new(opt.fns).
+        document_language_versions_found
+      flv[:f].each {|l| lng_dirs << l[:l] }
+      lng_dirs.uniq.each do |lng|
+        paths << "#{spp}/doc/#{lng}"
+      end
+      paths \
+      << "#{spp}/image" \
+      << "#{sppc}/skin/doc" \
+      << "#{sppc}/skin/dir" \
+      << "#{sppc}/skin/site"
+     #<< "#{spp}/audio" \
+     #<< "#{spp}/video" \
+      paths.each do |x|
+        unless FileTest.directory?(x)
+          FileUtils::mkdir_p(x)
+        end
+      end
+      if FileTest.directory?(sppc)
+        pwd=Dir.pwd
+        Dir.chdir(sppc)
+        FileUtils::ln_s('../../image', 'image')
+       #FileUtils::ln_s('../../audio', 'audio')
+       #FileUtils::ln_s('../../video', 'video')
+        Dir.chdir(pwd)
+      end
+    end
+    def sisupod_v2
+      #processing_path.processing
+      #  sisupod
+      #    content.sst              [file content]
+      #    filename.sst             [link to content.sst]
+      #    _sisu
+      #      skin/
+      #        doc                  [relevant skin if any other than default]
+      #      image                  [all images for specific document gathered here]
+      sisupod_processing_path="#{processing_path.processing}/#{Gt[:sisupod]}"
+      if FileTest.directory?(sisupod_processing_path) \
+      or FileTest.file?(sisupod_processing_path)
+        FileUtils::rm_rf(sisupod_processing_path)
+      end
+      paths=[]
+      paths=[
+        "#{processing_path.processing}/#{Gt[:sisupod]}/_sisu/skin/doc",
+        "#{processing_path.processing}/#{Gt[:sisupod]}/_sisu/skin/dir",
+        "#{processing_path.processing}/#{Gt[:sisupod]}/_sisu/skin/site",
+        "#{processing_path.processing}/#{Gt[:sisupod]}/_sisu/image"
+      ]
+      paths.each {|x| FileUtils::mkdir_p(x) unless FileTest.directory?(x) }
+    end
+    def defaults                       #multiple default directories
+      @default_dir ||=@sys.default_dir #DEFAULT_DIR
+    end
+    def html_seg_title_banner?
+      ((defined? @rc['html']['seg_title_banner']) \
+      && @rc['html']['seg_title_banner']==true) \
+      ? @rc['html']['seg_title_banner']
+      : false
+    end
+    def html_quick_ref?
+      ((defined? @rc['html']['quick_ref']) \
+      && @rc['html']['quick_ref']==true) \
+      ? @rc['html']['quick_ref']
+      : false
+    end
+    def html_minitoc?
+      if defined? @rc['html']['minitoc'] \
+      and @rc['html']['minitoc'].is_a?(String)
+        @rc['html']['minitoc']
+      else false
+      end
+    end
+    def manifest_minitoc?
+      if defined? @rc['manifest']['minitoc'] \
+      and @rc['manifest']['minitoc'].is_a?(String)
+        @rc['manifest']['minitoc']
+      else false
+      end
+    end
+    def build
+      def omit_list
+        @off_list ||=if defined? @rc['omit_list'] \
+        and @rc['omit_list'].is_a?(String)
+          @rc['omit_list']
+        elsif defined? @rc['omit']['list'] \
+        and @rc['omit']['list'].is_a?(String)
+          @rc['omit']['list']
+        else
+          nil
+        end
+      end
+      def listed?(test) #fix
+        listed=if omit_list
+          x=(omit_list.scan(/\b#{test}\b/)).join
+          test==x \
+          ? true
+          : false
+        else
+          false
+        end
+        listed
+      end
+      def ocn?
+        if (defined? @rc['omit']['ocn'] \
+        and not @rc['omit']['ocn'].nil?) \
+        or listed?('ocn')
+          :off
+        else
+          :na
+        end
+      end
+      def toc?
+        if (defined? @rc['omit']['toc'] \
+        and not @rc['omit']['toc'].nil?) \
+        or listed?('toc')
+          :off
+        else
+          :na
+        end
+      end
+      def manifest?
+        if (defined? @rc['omit']['manifest'] \
+        and not @rc['omit']['manifest'].nil?) \
+        or listed?('manifest')
+          :off
+        else
+          :na
+        end
+      end
+      def links_to_manifest?
+        if (defined? @rc['omit']['links_to_manifest'] \
+        and not @rc['omit']['links_to_manifest'].nil?) \
+        or (listed?('links_to_manifest') \
+        ||  listed?('manifest_links'))
+          :off
+        else
+          :na
+        end
+      end
+      def metadata?
+        if (defined? @rc['omit']['metadata'] \
+        and not @rc['omit']['metadata'].nil?) \
+        or listed?('metadata')
+          :off
+        else
+          :na
+        end
+      end
+      def minitoc?
+        if (defined? @rc['omit']['minitoc'] \
+        and not @rc['omit']['minitoc'].nil?) \
+        or (listed?('minitoc'))
+          :off
+        else
+          :na
+        end
+      end
+      def manifest_minitoc?
+        if (defined? @rc['omit']['manifest_minitoc'] \
+        and not @rc['omit']['manifest_minitoc'].nil?) \
+        or listed?('manifest_minitoc')
+          :off
+        else
+          :na
+        end
+      end
+      def html_minitoc?
+        if (defined? @rc['omit']['html_minitoc'] \
+        and not @rc['omit']['html_minitoc'].nil?) \
+        or (listed?('html_minitoc') \
+        || listed?('minitoc'))
+          :off
+        else
+          :na
+        end
+      end
+      def html_navigation?
+        if (defined? @rc['omit']['html_navigation'] \
+        and not @rc['omit']['html_navigation'].nil?) \
+        or listed?('html_navigation')
+          :off
+        else
+          :na
+        end
+      end
+      def html_navigation_bar?
+        if (defined? @rc['omit']['html_navigation_bar'] \
+        and not @rc['omit']['html_navigation_bar'].nil?) \
+        or listed?('html_navigation_bar')
+          :off
+        else
+          :na
+        end
+      end
+      def segsubtoc?
+        if (defined? @rc['omit']['segsubtoc'] \
+        and not @rc['omit']['segsubtoc'].nil?) \
+        or listed?('segsubtoc')
+          :off
+        else
+          :na
+        end
+      end
+      def html_right_pane?
+        if (defined? @rc['omit']['html_right_pane'] \
+        and not @rc['omit']['html_right_pane'].nil?) \
+        or listed?('html_right_pane')
+          :off
+        else
+          :na
+        end
+      end
+      def html_top_band?
+        if (defined? @rc['omit']['html_top_band'] \
+        and not @rc['omit']['html_top_band'].nil?) \
+        or listed?('html_top_band')
+          :off
+        else
+          :na
+        end
+      end
+      def search_form? #decide later, as is configured here (in sisurc) and can be turned off on command line
+        if (defined? @rc['omit']['search_form'] \
+        and not @rc['omit']['search_form'].nil?) \
+        or listed?('search_form')
+          :off
+        else
+          :na
+        end
+      end
+      def html_search_form? #decide later, as is configured here (in sisurc) and can be turned off on command line
+        if (defined? @rc['omit']['html_search_form'] \
+        and not @rc['omit']['html_search_form'].nil?) \
+        or listed?('html_search_form')
+          :off
+        else
+          :na
+        end
+      end
+      self
+    end
+    def odt_ocn?
+      ((defined? @rc['odt']['ocn']) \
+      && @rc['odt']['ocn']==false) \
+      ? @rc['odt']['ocn']
+      : true
+    end
+    def xml_docbook_ocn?
+      ((defined? @rc['xml_docbook']['ocn']) \
+      && @rc['xml_docbook']['ocn']==false) \
+      ? @rc['xml_docbook']['ocn']
+      : true
+    end
+    def xml_fictionbook_ocn?
+      ((defined? @rc['xml_fictionbook']['ocn']) \
+      && @rc['xml_fictionbook']['ocn']==false) \
+      ? @rc['xml_fictionbook']['ocn']
+      : true
+    end
+    def xml_scaffold_ocn?
+      ((defined? @rc['xml_scaffold']['ocn']) \
+      && @rc['xml_scaffold']['ocn']==false) \
+      ? @rc['xml_scaffold']['ocn']
+      : true
+    end
+    def plaintext_ocn?
+      ((defined? @rc['plaintext']['ocn']) \
+      && @rc['plaintext']['ocn']==false) \
+      ? @rc['plaintext']['ocn']
+      : true
+    end
+    def textile_ocn?
+      ((defined? @rc['textile']['ocn']) \
+      && @rc['textile']['ocn']==true) \
+      ? @rc['textile']['ocn']
+      : false
+    end
+    def asciidoc_ocn?
+      ((defined? @rc['asciidoc']['ocn']) \
+      && @rc['asciidoc']['ocn']==true) \
+      ? @rc['asciidoc']['ocn']
+      : false
+    end
+    def markdown_ocn?
+      ((defined? @rc['markdown']['ocn']) \
+      && @rc['markdown']['ocn']==true) \
+      ? @rc['markdown']['ocn']
+      : false
+    end
+    def rst_ocn?
+      ((defined? @rc['rst']['ocn']) \
+      && @rc['rst']['ocn']==true) \
+      ? @rc['rst']['ocn']
+      : false
+    end
+    def orgmode_ocn?
+      ((defined? @rc['orgmode']['ocn']) \
+      && @rc['orgmode']['ocn']==true) \
+      ? @rc['orgmode']['ocn']
+      : false
+    end
+    def widget #needs (md) #move
+      @rc=SiSU_Env::GetInit.new.sisu_yaml.rc
+      @ad=SiSU_Env::GetInit.new.ads
+      @html_bits=SiSU_Proj_HTML::Bits.new
+      @flag={
+        ad: false,
+        md: false,
+        sk: false,
+        rc: false
+      }
+      def promo?
+        @flag[:ad]=if @md.flag_promo \
+        && @ad[:flag_promo]
+          @flag[:md]=true
+          true
+        elsif defined? @html_bits.widget_promo \
+        and not @html_bits.widget_promo.nil? \
+        and @html_bits.widget_promo.is_a?(Array) \
+        and @html_bits.widget_promo.length > 0
+          @flag[:sk]=true
+          true
+        elsif defined? @rc['html']['promo'] \
+        and not @rc['html']['promo'].nil? \
+        and @rc['html']['promo'].length > 0
+          @flag[:rc]=true
+          true
+        else false
+        end
+        @flag
+      end
+      def search?
+        searches=['sisu']
+        flag=false
+        if defined? @rc['search']
+          searches.each do |type|
+            flag=if defined? @rc['search'][type] \
+            and defined? @rc['search'][type]['action'] \
+            and @rc['search'][type]['flag']==true \
+            and @rc['search'][type]['action'] =~/https?:\/\//
+              flag=if promo?[:ad]
+                false
+              elsif defined? @html_bits.widget_search \
+              and @html_bits.widget_search==true
+                true
+              elsif defined? @rc['search'][type]['flag'] \
+              and @rc['search'][type]['flag']==true
+                true
+              else false
+              end
+            else false
+            end
+          end
+        else false
+        end
+        flag
+      end
+      def search_fixed?
+        searches=['sisu','hyperestraier']
+        flag=if defined? @rc['search']
+          searches.each do |type|
+            if defined? @rc['search'][type] \
+            and defined? @rc['search'][type]['action'] \
+            and @rc['search'][type]['action'] =~/https?:\/\// \
+            and defined? @rc['search'][type]['db'] \
+            and @rc['search'][type]['db'] =~/\S+/
+              flag=if promo?[:ad]
+                false
+              elsif defined? @html_bits.widget_search \
+              and @html_bits.widget_search==true
+                true
+              elsif defined? @rc['search'][type]['flag'] \
+              and @rc['search'][type]['flag']==true
+                true
+              else false
+              end
+            else false
+            end
+          end
+        else false
+        end
+      end
+      def search_form(type='sisusearch',action=nil,db=nil,table=false)
+        rc=SiSU_Env::GetInit.new.sisu_yaml.rc
+        create_form_sisu=if action \
+        and db \
+        and action =~/https?:\/\// \
+        and db =~/\S+/
+          true
+        elsif widget.search?
+          db=if rc['search']['sisu']['flag']==true \
+          and rc['search']['sisu']['db']=~/\S+/
+            (rc['search']['sisu']['db']=~/^#{Db[:name_prefix]}\S+/) \
+            ? rc['search']['sisu']['db']
+            : "#{Db[:name_prefix]}#{rc['search']['sisu']['db']}"
+          else nil
+          end
+          action=rc['search']['sisu']['action']
+          true
+        elsif defined? rc['search']['sisu']['flag'] \
+        and defined? rc['search']['sisu']['action'] \
+        and rc['search']['sisu']['flag']==true \
+        and rc['search']['sisu']['action'] =~/https?:\/\//
+          true
+        else false
+        end
+        if table
+          table_open='<td align="center" bgcolor="#ffffff">'
+          table_close='</td>'
+        else
+          table_open=''
+          table_close='<br />'
+        end
+        form=if create_form_sisu \
+        and type=~/sisusearch/ \
+        and defined? rc['search']['sisu'] \
+        and defined? rc['search']['sisu']['action']
+          <<WOK
+<!-- SiSU Search -->
+#{table_open}
+<a name="search"></a>
+<form method="get" action="#{rc['search']['sisu']['action']}" target="_top">
+<font size="2">
+<input type="text" name="s1" size="24" maxlength="255" />
+<input type="hidden" name="db" value="#{db}" />
+<input type="hidden" name="ltd" value="1000" />
+<input type="hidden" name="off" value="0" />
+<input type="hidden" name="doc" value="#{@md.fnb}" /><br />
+<input type="submit" name="search" value="search doc" />
+<input type="submit" name="search" value="search db" />
+</font></form>
+#{table_close}
+<!-- SiSU Search -->
+WOK
+        else ''
+        end
+        form
+      end
+      def search_form_static(action=nil,db=nil)
+        rc=SiSU_Env::GetInit.new.sisu_yaml.rc
+        create_form=if rc['search']['sisu']['flag']==true \
+        and action \
+        and db \
+        and action =~/https?:\/\// \
+        and db =~/\S+/
+          true
+        elsif widget.search_fixed?
+          db=if rc['search']['sisu']['flag']==true \
+          and rc['search']['sisu']['db']=~/\S+/
+            (rc['search']['sisu']['db']=~/^#{Db[:name_prefix]}\S+/) \
+            ? rc['search']['sisu']['db']
+            : "#{Db[:name_prefix]}#{rc['search']['sisu']['db']}"
+          else nil
+          end
+          action=rc['search']['sisu']['action']
+          true
+        else false
+        end
+        if create_form
+          %{<td align="center" bgcolor="#ffffff">
+<!-- SiSU Search -->
+<a name="search"></a>
+<form method="get" action="#{rc['search']['sisu']['action']}" target="_top">
+<font size="2">
+<input type="text" name="s1" size="24" maxlength="255" />
+<br />
+<input type="hidden" name="db" value="#{db}" />
+<input type="hidden" name="ltd" value="1000" />
+<input type="hidden" name="off" value="0" />
+<input type="hidden" name="doc" value="#{@md.fnb}" />
+<input type="submit" name="search" value="search doc" />
+<input type="submit" name="search" value="search db" />
+</font>
+</form>
+<!-- SiSU Search -->
+</td> }
+        else ''
+        end
+      end
+      def search_action #check
+        if search?
+        else ''
+        end
+      end
+      self
+    end
+    def widget_static
+      @rc=SiSU_Env::GetInit.new.sisu_yaml.rc
+      @html_bits=SiSU_Proj_HTML::Bits.new
+      @flag={ ad: false, md: false, sk: false, rc: false }
+      def search?
+        flag=if defined? @rc['search'] \
+        and defined? @rc['search']['sisu'] \
+        and defined? @rc['search']['sisu']['action'] \
+        and @rc['search']['sisu']['action'] =~/https?:\/\// \
+        and defined? @rc['search']['sisu']['db'] \
+        and @rc['search']['sisu']['db'] =~/\S+/
+          flag=if defined? @html_bits.widget_search \
+          and @html_bits.widget_search==true
+            true
+          elsif defined? @rc['search']['sisu']['flag'] \
+          and @rc['search']['sisu']['flag']==true
+            true
+          else
+            false
+          end
+        else
+          false
+        end
+      end
+      def search_fixed?
+        flag=if defined? @rc['search'] \
+        and defined? @rc['search']['sisu'] \
+        and defined? @rc['search']['sisu']['action'] \
+        and @rc['search']['sisu']['action'] =~/https?:\/\// \
+        and defined? @rc['search']['sisu']['db'] \
+        and @rc['search']['sisu']['db'] =~/\S+/ \
+        and defined? @rc['search']['sisu']['db'] \
+        and @rc['search']['sisu']['db'] =~/\S+/
+          flag=if defined? @html_bits.widget_search \
+          and @html_bits.widget_search==true
+            true
+          elsif defined? @rc['search']['sisu']['flag'] \
+          and @rc['search']['sisu']['flag']==true
+            true
+          else
+            false
+          end
+        else
+          false
+        end
+      end
+      def search_form(action=nil,db=nil)
+        rc=SiSU_Env::GetInit.new.sisu_yaml.rc
+        create_form=if defined? rc['search']['sisu']['flag'] \
+        and rc['search']['sisu']['flag']==true \
+        and action \
+        and db \
+        and action =~/https?:\/\// \
+        and db =~/\S+/
+          true
+        elsif widget_static.search? \
+        and rc['search']['sisu']['flag']==true
+          db=if rc['search']['sisu']['db']=~/\S+/
+            (rc['search']['sisu']['db']=~/^#{Db[:name_prefix]}\S+/) \
+            ? rc['search']['sisu']['db']
+            : "#{Db[:name_prefix]}#{rc['search']['sisu']['db']}"
+          else nil
+          end
+          action=rc['search']['sisu']['action']
+          true
+        else false
+        end
+        if create_form \
+        and @fnb \
+        and @fnb=~/\S+/
+          %{<!-- SiSU Search -->
+<a name="search"></a>
+<form method="get" action="#{rc['search']['sisu']['action']}" target="_top">
+<font size="2">
+<input type="text" name="s1" size="24" maxlength="255" />
+<br />
+<input type="hidden" name="db" value="#{db}" />
+<input type="hidden" name="doc" value="#{@fnb}" />
+<input type="submit" name="search" value="search doc" />
+<input type="submit" name="search" value="search db" />
+</font>
+</form>
+<!-- SiSU Search --> }
+        elsif create_form
+          %{<!-- SiSU Search -->
+<a name="search"></a>
+<form method="get" action="#{rc['search']['sisu']['action']}" target="_top">
+<font size="2">
+<input type="text" name="s1" size="24" maxlength="255" />
+<br />
+<input type="hidden" name="db" value="#{db}" />
+<input type="submit" name="search" value="search db" />
+</font>
+</form>
+<!-- SiSU Search --> }
+        else ''
+        end
+      end
+      def search_action #check
+        if search?
+        else ''
+        end
+      end
+      self
+    end
+    def source_file_path
+      file=@fns.gsub(/\.ssm(?:\.sst)?/,'.ssm.sst')
+      unless file =~/\.ssm\.sst$/; "#{Dir.pwd}"
+      else "#{processing_path.composite_file}"
+      end
+    end
+    def source_file_with_path
+      file=@fns.gsub(/\.ssm(?:\.sst)?/,'.ssm.sst')
+      "#{source_file_path}/#{file}"
+    end
+    def texpdf_hyperlinks(cli)
+      @cli=cli
+      @hyplnks=if cli != :na
+        cli
+      elsif (defined? @rc['default']['pdf_hyperlinks']) \
+      && (@rc['default']['pdf_hyperlinks']=~/color/)
+        :color
+      elsif (defined? @rc['default']['pdf_hyperlinks']) \
+      && (@rc['default']['pdf_hyperlinks'] \
+      =~/(?:no-color|color-off|mono(?:chrome)?)/)
+        :mono
+      else :na
+      end
+      def landscape
+        if @cli != :na
+          @cli
+        elsif (defined? @rc['default']['pdf_hyperlinks_landscape']) \
+        && (@rc['default']['pdf_hyperlinks_landscape']=~/color/)
+          :color
+        elsif (defined? @rc['default']['pdf_hyperlinks_landscape']) \
+        && (@rc['default']['pdf_hyperlinks_landscape'] \
+        =~/(?:no-color|color-off|mono(?:chrome)?)/)
+          :mono
+        elsif @hyplnks != :na
+          @hyplnks
+        else :na
+        end
+      end
+      def portrait
+        if @cli != :na
+          @cli
+        elsif (defined? @rc['default']['pdf_hyperlinks_portrait']) \
+        && (@rc['default']['pdf_hyperlinks_portrait']=~/color/)
+          :color
+        elsif (defined? @rc['default']['pdf_hyperlinks_portrait']) \
+        && (@rc['default']['pdf_hyperlinks_portrait'] \
+        =~/(?:no-color|color-off|mono(?:chrome)?)/)
+          :mono
+        elsif @hyplnks != :na
+          @hyprlnks
+        else :na
+        end
+      end
+      self
+    end
+    def font
+      def size(pt=nil)
+        if pt && pt != :na
+          pt
+        elsif defined? @rc['default']['fontsize'] \
+        && @rc['default']['fontsize']=~/\d{1,2}/
+          @rc['default']['fontsize']
+        else :na
+        end
+      end
+      def texpdf
+        # you may wish to check selected font against available fonts:
+        # fc-list :outline -f "%{family}\n"
+        # fc-list :lang=ja
+        def main
+          (defined? @rc['default']['texpdf_fontface']) \
+          && (@rc['default']['texpdf_fontface']=~/\S{3,}/)  \
+          ? @rc['default']['texpdf_fontface']
+          : 'Liberation Sans'
+        end
+        def sans                       # not used
+          (defined? @rc['default']['texpdf_fontface_sans']) \
+          && (@rc['default']['texpdf_fontface_sans']=~/\S{3,}/)  \
+          ? @rc['default']['texpdf_fontface_sans']
+          : 'Liberation Sans'
+        end
+        def serif                      # not used
+          (defined? @rc['default']['texpdf_fontface_serif']) \
+          && (@rc['default']['texpdf_font_serif']=~/\S{3,}/)  \
+          ? @rc['default']['texpdf_fontface_serif']
+          : 'Liberation Serif'
+        end
+        def mono
+          (defined? @rc['default']['texpdf_fontface_mono']) \
+          && (@rc['default']['texpdf_fontface_mono']=~/\S{3,}/)  \
+          ? @rc['default']['texpdf_fontface_mono']
+          : 'Liberation Mono'
+        end
+        def cjk
+          (defined? @rc['default']['texpdf_fontface_cjk']) \
+          && (@rc['default']['texpdf_fontface_cjk']=~/\S{3,}/)  \
+          ? @rc['default']['texpdf_fontface_cjk']
+          : 'IPAGothic' # 'IPAGothic' # 'IPAMincho' # 'TakaoMincho' # 'VL Gothic'
+        end
+        def cjk_zh
+          (defined? @rc['default']['texpdf_fontface_cjk_zh']) \
+          && (@rc['default']['texpdf_fontface_cjk_zh']=~/\S{3,}/)  \
+          ? @rc['default']['texpdf_fontface_cjk_zh']
+          : 'IPAGothic'
+        end
+        def cjk_ja
+          (defined? @rc['default']['texpdf_fontface_cjk_ja']) \
+          && (@rc['default']['texpdf_fontface_cjk_ja']=~/\S{3,}/)  \
+          ? @rc['default']['texpdf_fontface_cjk_ja']
+          : 'IPAGothic'
+        end
+        def cjk_ko
+          (defined? @rc['default']['texpdf_fontface_cjk_ko']) \
+          && (@rc['default']['texpdf_fontface_cjk_ko']=~/\S{3,}/)  \
+          ? @rc['default']['texpdf_fontface_cjk_ko']
+          : 'IPAGothic'
+        end
+        def size(pt=nil)
+          if pt && pt != :na
+            pt
+          elsif (defined? @rc['default']['texpdf_fontsize']) \
+          && (@rc['default']['texpdf_fontsize']=~/\d{1,2}/)
+            @rc['default']['texpdf_fontsize']
+          elsif (defined? @rc['default']['fontsize']) \
+          && (@rc['default']['fontsize']=~/\d{1,2}/)
+            @rc['default']['fontsize']
+          else
+            :na
+          end
+        end
+        self
+      end
+      self
+    end
+    def path_rel_links
+      def html_scroll_2
+        if @env.output_dir_structure.by_language_code?
+          '../../'
+        elsif @env.output_dir_structure.by_filetype?
+          '../'
+        else
+          '../'
+        end
+      end
+      def html_seg_2
+        if @env.output_dir_structure.by_language_code?
+          '../../../'
+        elsif @env.output_dir_structure.by_filetype?
+          '../../'
+        else
+          '../'
+        end
+      end
+      def html_scroll_1
+        if @env.output_dir_structure.by_language_code?
+          '../'
+        elsif @env.output_dir_structure.by_filetype?
+          '../'
+        else
+          './'
+        end
+      end
+      def html_seg_1
+        if @env.output_dir_structure.by_language_code?
+          '../../'
+        elsif @env.output_dir_structure.by_filetype?
+          '../../'
+        else
+          './'
+        end
+      end
+      self
+    end
+    def read_source_file_array(fns)
+      (fns !~/\.ssm.sst$/) \
+      ? (IO.readlines(fns, mode: 'r:utf-8', cr_newline: true))
+      : (IO.readlines(
+           "#{processing_path.composite_file}/#{fns}",
+           mode: 'r:utf-8',
+           cr_newline: true
+        ))
+    end
+    def read_source_file(fns)
+      read_source_file_array(fns)
+    end
+    def read_source_file_string(fns)
+      (fns !~/\.ssm.sst$/) \
+      ? (IO.read(fns, mode: 'r:utf-8', cr_newline: true))
+      : (IO.read(
+           "#{processing_path.composite_file}/#{fns}",
+           mode: 'r:utf-8',
+           cr_newline: true
+        ))
+    end
+    def source_file_processing_array(fns)
+      read_source_file_string(fns).split(/\s*\n\s*\n/m)
+    end
+    def path                           #dir
+      def home
+        @sys.home
+      end
+      def sisurc_path
+        SiSU_Get_Init::GetInit.new.sisu_yaml.rc_path
+      end
+      def pwd
+        @sys.pwd
+      end
+      def stub_pwd
+        @stub_pwd
+      end
+      def base_markup_dir_stub
+        @base_markup_dir_stub
+      end
+      def stub_epub
+        @stub_epub
+      end
+      def stub_src
+        @stub_src
+      end
+      def stub_pod
+        @stub_pod
+      end
+      def etc
+        defaults[:sisu_etc]            #live/dynamic
+      end
+      def arch
+        @sys.dir_arch
+      end
+      def sitearch
+        @sys.dir_sitearch
+      end
+      def bin
+        @sys.dir_bin
+      end
+      def share                        #shared data repository source directory
+        #SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:green).
+        #  mark(defaults[:sisu_share])
+        defaults[:sisu_share]
+      end
+      def style
+        if @md \
+        && ((@md.opt.opt_act[:dump][:bool] \
+        &&   @md.opt.opt_act[:dump][:inst]) \
+        ||  (@md.opt.opt_act[:redirect][:bool] \
+        &&   @md.opt.opt_act[:redirect][:inst]))
+          'css'
+        else
+         defaults[:stylesheet_stub]
+        end
+      end
+      def sample_data                  #sample data repository source directory
+        defaults[:sample_data_path]
+      end
+      def rc
+        @init.rc_path
+      end
+      def yamlrc
+        GetInit.new.sisu_yaml.rc_path
+      end
+      def man #check use
+        (defined? @rc['webserv']['man']) \
+        ? "#{webserv}/#{@rc['webserv']['man']}"
+        : defaults[:webserv_man]
+      end
+      def webserv_path #testing, check need, remove
+        webserv
+      end
+      def webserv                      #separation required for webrick which cannot use path.output (different requirements as no file is passed)
+        man_path=if @@man_path.nil?
+          man_path=if defined? @rc['webserv']['path'] \
+          and @rc['webserv']['path'] =~/\S\S+/
+            pwd=Dir.pwd
+            Dir.chdir(SiSU_Utils::Path.new.base_markup)
+            man_path=@@man_path=File.expand_path(@rc['webserv']['path'])
+            Dir.chdir(pwd)
+            man_path
+          else defaults[:webserv_path]
+          end
+        else @@man_path
+        end
+        man_path_head=man_path.gsub(/(\S+)\/[^\/\s]+$/,'\1')
+        unless FileTest.directory?(man_path)
+          FileUtils::mkdir_p(man_path) if File.writable?("#{man_path_head}/.")
+        end
+        @webserv_path=if defined? man_path \
+        and File.writable?("#{man_path}/.")
+          man_path #web server path as configured in rc file
+        elsif FileTest.directory?(defaults[:webserv_path]) \
+        and File.writable?("#{defaults[:webserv_path]}/.") #web server path default
+          defaults[:webserv_path]
+        else #create default directory under home and place output there
+          unless FileTest.directory?(defaults[:output_local])
+            FileUtils::mkdir_p(defaults[:output_local])
+          end
+          defaults[:output_local]
+        end
+      end
+      def webserv_stub_ensure
+        FileUtils::mkdir_p(path.webserv) unless FileTest.directory?(path.webserv)
+        FileUtils::mkdir_p("#{path.webserv}/#{@base_markup_dir_stub}") \
+          unless FileTest.directory?("#{path.webserv}/#{@base_markup_dir_stub}")
+      end
+      def webserv_map_pwd #dir
+        "#{path.webserv}/#{base_markup_dir_stub}"
+      end
+      def webserv_dir                  #fixed/hard path to /www web/presentation directory, on Debian /var/www subdirectories are created within it, depending on markup directory stub-name (last segment of markup directory name)
+        defaults[:webserv_dir]
+      end
+      def webserv_image                #web/presentation directory, subdirectories are created within it, depending on markup directory stub-name (last segment of markup directory name)
+        images=if defined? @rc['webserv']['images']
+          @rc['webserv']['images']
+        else defaults[:images]
+        end
+        "#{path.webserv}/#{images}"
+      end
+      def output                       #web/webserv output directory... subdirectory into which further subdirectories are made based on file names
+        r=Px[:lng_lst_rgx]
+        u=/.+?\/([^\/]+)(?:\/(?:#{r})$|$)/
+        base_stub=@sys.pwd.gsub(u,'\1')
+        if Dir.pwd =~/\/#{Gt[:sisupod]}\/[^\/]+\/#{Gt[:pod]}\/#{Gt[:doc]}/
+          "#{path.webserv}/#{Gt[:doc]}"
+        else
+          "#{path.webserv}/#{base_stub}"
+        end
+      end
+      def feed
+        (defined? @rc['webserv']['feed']) \
+        ? ("#{public_output}/#{@rc['webserv']['feed']}")
+        : (defaults[:webserv_feed])
+      end
+      def feed_home
+        "#{public_output}/#{@rc['webserv']['feed_home']}"
+      end
+      def scripts                      #used previously only to include tla version info
+        if defined? @rc['project']['path']
+          "#{home}/#{@rc['project']['path']}"
+        end
+      end
+      def cgi
+        (defined? @rc['webserv']['cgi']) \
+        ? "#{@rc['webserv']['cgi']}"
+        : (defaults[:webserv_cgi])
+      end
+      def php
+        (defined? @rc['webserv']['php']) \
+        ? "#{public_output}/#{@rc['webserv']['php']}"
+        : (defaults[:webserv_php])
+      end
+      #% programs
+      def output_tell
+        url.webserv_map_pwd
+      end
+      def image_source_sisu_includes(md=nil)
+        if md \
+        and (md.opt.sisu_install_type? == \
+        :full_path_to_sisu_bin_in_sisu_dir_tree) \
+        and FileTest.directory?(
+          "#{md.opt.sisu_data_dir?}/image"
+        )==true
+          "#{md.opt.sisu_data_dir?}/image"
+        else
+          "#{share}/image"
+        end
+      end
+      def image_source(md=nil)                 #image repository source directory
+        if defined? @rc['image']['path'] \
+        and defined? @rc['image']['public']
+          pth="#{@rc['image']['path']}"
+          "#{pth}/#{@rc['image']['public']}"
+        else
+          image_source_sisu_includes(md)
+        end
+      end
+      def image_source_include(md=nil)         #image repository source directory
+        if defined? @rc['image']['path'] \
+        and defined? @rc['image']['public'] \
+        and FileTest.directory?(
+          "#{@rc['image']['path']}/#{@rc['image']['public']}"
+        )==true
+          "#{@rc['image']['path']}/#{@rc['image']['public']}"
+        elsif FileTest.directory?("#{@@pwd}/#{defaults[:image_stub]}")==true
+          "#{@@pwd}/#{defaults[:image_stub]}"
+        elsif FileTest.directory?(
+          "#{SiSU_Utils::Path.new.base_markup}/#{defaults[:image_stub]}"
+        )==true
+          "#{SiSU_Utils::Path.new.base_markup}/#{defaults[:image_stub]}"
+        else
+          image_source_sisu_includes(md)
+        end
+      end
+      def image_external
+        "#{processing}/external_document/image"
+      end
+      def image_source_include_local
+        if FileTest.directory?(defaults[:image_local])
+          defaults[:image_local]
+        end
+      end
+      def image_source_include_remote
+        if FileTest.directory?(image_external)
+          image_external
+        end
+      end
+      self
+    end
+    def processing_path
+      def encoding
+        pth="#{processing}/#{defaults[:processing_encoding]}"
+        FileUtils::mkdir_p(pth) unless FileTest.directory?(pth)
+        pth
+      end
+      def processing_base_tmp
+        defaults[:processing_path_tmp_base]
+      end
+      def tmp_root_dir
+        defaults[:processing_dir_tmp_root]
+      end
+      def root_dir
+        proposed_path_base=if defined? @rc['processing']['path'] \
+        and not @rc['processing']['path'].nil? \
+        and not @rc['processing']['path'].empty?
+          x=if @rc['processing']['path'] =~/^(?:~|home)$/
+            home #fix
+          else @rc['processing']['path']
+          end
+        else nil
+        end
+        proposed_dir=if defined? @rc['processing']['dir'] \
+        and not @rc['processing']['dir'].nil? \
+        and not @rc['processing']['dir'].empty?
+          @rc['processing']['dir']
+        else defaults[:processing_dir]
+        end
+        v=SiSU_Env::InfoVersion.instance.get_version
+        v_dev=(DEVELOPER[:maintenance]==:true) \
+        ? "_#{v.version}"
+        : ''
+        path=if proposed_path_base \
+        and FileTest.directory?(proposed_path_base) \
+        and File.writable?("#{proposed_path_base}/.")
+          x=proposed_dir \
+          ? "#{proposed_path_base}/#{proposed_dir}"
+          : "#{proposed_path_base}/#{defaults[:processing_dir]}"
+        else defaults[:processing_dir_tmp_root]
+        end
+        path = path + v_dev
+      end
+      def usr_dir?
+        case root_dir
+        when /^\/home/ then false
+        else                true
+        end
+      end
+      def stub_dir
+        (usr_dir?) \
+        ? ("#{root_dir}/#{user}/#{stub_pwd}")
+        : ("#{root_dir}/#{stub_pwd}") # see defaults[:processing_path]
+      end
+      def stub_dir_orig # ends up with lang, if lang dir
+        (usr_dir?) \
+        ? ("#{root_dir}/#{user}/#{stub_pwd}")
+        : ("#{root_dir}/#{stub_pwd}") # see defaults[:processing_path]
+      end
+      def processing_sisupod(opt=nil)  #processing directory, used/needed for sisu work files, has sub-directories (ao,tex etc)
+        @opt=opt
+        def paths
+          processing_path_usr="#{root_dir}/#{user}"
+          processing_path_fnb=processing_path_usr \
+            + '/' + Gt[:pods] \
+            + '/' + @opt.fng
+          processing_path_sisupod=processing_path_fnb \
+            + '/' + Gt[:sisupod]
+          {
+            fnb: processing_path_fnb,
+            sisupod: processing_path_sisupod,
+          }
+        end
+        def make
+          unless FileTest.directory?(root_dir)
+            FileUtils::mkdir_p(root_dir)
+            File.chmod(0777,root_dir)
+          end
+          if usr_dir?
+            processing_path_usr="#{root_dir}/#{user}"
+            FileUtils::mkdir_p(processing_path_usr) \
+              unless FileTest.directory?(processing_path_usr)
+            File.chmod(0700,processing_path_usr)
+          end
+          sisupod_processing_path=paths[:sisupod]
+          FileUtils::mkdir_p(sisupod_processing_path) \
+            unless FileTest.directory?(sisupod_processing_path)
+          sisupod_processing_path_lng=if defined? @opt.lng
+            sisupod_processing_path \
+              + '/' + Gt[:doc] \
+              + '/' + @opt.lng
+          else
+            sisupod_processing_path \
+              + '/' + Gt[:doc]
+          end
+          unless FileTest.directory?(sisupod_processing_path_lng)
+            #puts "a processing directory (#{sisupod_processing_path_lng}) is being created for use by sisu"
+            FileUtils::mkdir_p(sisupod_processing_path_lng)
+            File.chmod(0700,sisupod_processing_path_lng)
+          end
+          sisupod_processing_path
+        end
+        self
+      end
+      def processing                   #processing directory, used/needed for sisu work files, has sub-directories (ao,tex etc)
+        unless FileTest.directory?(root_dir)
+          FileUtils::mkdir_p(root_dir)
+          File.chmod(0777,root_dir)
+        end
+        if usr_dir?
+          processing_path_usr="#{root_dir}/#{user}"
+          FileUtils::mkdir_p(processing_path_usr) \
+            unless FileTest.directory?(processing_path_usr)
+          File.chmod(0700,processing_path_usr)
+        end
+        FileUtils::mkdir_p(stub_dir) \
+          unless FileTest.directory?(stub_dir)
+        File.chmod(0700,stub_dir)
+        path_processing=[
+          stub_dir,
+          defaults[:processing_path],
+          defaults[:processing_path_home]
+        ]
+        processing=nil
+        path_processing.each do |v|                                              #
+          processing=v
+          unless FileTest.directory?(processing)
+            FileUtils::mkdir_p(processing)
+            File.chmod(0700,processing)
+          end
+          break
+        end
+        processing
+      end
+      def ao
+        pth=if defined? @rc['processing']['dal'] \
+          and @rc['processing']['dal'].is_a?(String)
+          "#{processing}/#{@rc['processing']['dal']}"
+        else "#{processing}/#{defaults[:processing_ao]}"
+        end
+        FileUtils::mkdir_p(pth) unless FileTest.directory?(pth)
+        pth
+      end
+      def tune
+        pth=if defined? @rc['processing']['tune'] \
+          and @rc['processing']['tune'].is_a?(String)
+          "#{processing}/#{@rc['processing']['tune']}"
+        else "#{processing}/#{defaults[:processing_tune]}"
+        end
+        FileUtils::mkdir_p(pth) unless FileTest.directory?(pth)
+        pth
+      end
+      def composite_file
+        pth=processing_path.ao  #"#{processing}/composite"
+        FileUtils::mkdir_p(pth) unless FileTest.directory?(pth)
+        pth
+      end
+      def git
+        pth=if defined? @rc['git']['dir'] \
+        and @rc['git']['dir'].is_a?(String)
+          (@rc['git']['dir'] =~/^(?:~|home)$/) \
+          ? home + '/' + Gt[:git]
+          : @rc['git']['dir'] + '/' + Gt[:git]
+        else defaults[:processing_git]
+        end
+        unless FileTest.directory?(pth)
+          FileUtils::mkdir_p(pth)
+          File.chmod(0700,pth)
+        end
+        pth
+      end
+      def odf_pth
+        pth="#{processing}/odf/#{@fns}"
+        pth
+      end
+      def odf
+        odt
+      end
+      def odt
+        pth=odf_pth + '/odt'
+        FileUtils::mkdir_p(pth) unless FileTest.directory?(pth)
+        pth
+      end
+      def odf
+        pth="#{processing}/odf"
+        FileUtils::mkdir_p(pth) unless FileTest.directory?(pth)
+        pth
+      end
+      def odt_bld
+        FileUtils::rm_rf(processing_path.odt)
+        FileUtils::mkdir_p(processing_path.odt) \
+          unless FileTest.directory?(processing_path.odt)
+        FileUtils::mkdir_p("#{processing_path.odt}/Configurations2") \
+          unless FileTest.directory?("#{processing_path.odt}/Configurations2")
+        FileUtils::mkdir_p("#{processing_path.odt}/META-INF") \
+          unless FileTest.directory?("#{processing_path.odt}/META-INF")
+        FileUtils::mkdir_p("#{processing_path.odt}/Pictures") \
+          unless FileTest.directory?("#{processing_path.odt}/Pictures")
+        FileUtils::mkdir_p("#{processing_path.odt}/Thumbnails") \
+          unless FileTest.directory?("#{processing_path.odt}/Thumbnails")
+        processing_path.odt
+      end
+      def epub
+        "#{processing}/epub/#{@fnb}"
+      end
+      def epub_bld #(md)
+        FileUtils::rm_rf(processing_path.epub) \
+          if FileTest.directory?(processing_path.epub)
+        FileUtils::mkdir_p(processing_path.epub) \
+          unless FileTest.directory?(processing_path.epub)
+        FileUtils::mkdir_p("#{processing_path.epub}/META-INF") \
+          unless FileTest.directory?("#{processing_path.epub}/META-INF")
+        FileUtils::mkdir_p("#{processing_path.epub}/#{Ep[:d_oebps]}/image") \
+          unless FileTest.directory?("#{processing_path.epub}/#{Ep[:d_oebps]}/image")
+        FileUtils::mkdir_p("#{processing_path.epub}/#{Ep[:d_oebps]}/css") \
+          unless FileTest.directory?("#{processing_path.epub}/#{Ep[:d_oebps]}/css")
+        processing_path.epub
+      end
+      def epub_cp_images(md)
+        pth="#{processing_path.epub}/#{Ep[:d_oebps]}/image"
+        FileUtils::mkdir_p(pth) unless FileTest.directory?(pth)
+        src=(md.opt.sisu_install_type? == :full_path_to_sisu_bin_in_sisu_dir_tree) \
+        ? "#{md.opt.sisu_data_dir?}/image"
+        : "#{md.opt.sisu_data_dir?}/sisu/image"
+        images=%W[bullet_09.png arrow_next_red.png arrow_prev_red.png arrow_up_red.png]
+        images.each do |i| #move to avoid repeated tests
+          if FileTest.file?("#{src}/#{i}")
+            FileUtils::cp("#{src}/#{i}","#{pth}/#{i}") \
+              unless FileTest.file?("#{pth}/#{i}")
+          else STDERR.puts %{\t*WARN* did not find image - "#{i}" [#{__FILE__}:#{__LINE__}]}
+          end
+        end
+        pth
+      end
+      def tex
+        pth=if defined? @rc['processing']['latex'] \
+        and @rc['processing']['latex'].is_a?(String)
+          "#{processing}/#{@rc['processing']['latex']}"
+        else "#{processing}/#{defaults[:processing_latex]}"
+        end
+        FileUtils::mkdir_p(pth) unless FileTest.directory?(pth)
+        pth
+      end
+      def texi
+        pth=if defined? @rc['processing']['texinfo'] \
+        and @rc['processing']['texinfo'].is_a?(String)
+          "#{processing}/#{@rc['processing']['texinfo']}"
+        else "#{processing}/#{defaults[:processing_texinfo]}"
+        end
+        FileUtils::mkdir_p(pth) unless FileTest.directory?(pth)
+        pth
+      end
+      def texinfo                      #texinfo webserv, check
+        "#{processing}/#{defaults[:processing_texinfo]}"
+      end
+      def manpage
+        "#{path.output}/man"
+      end
+      def lout
+        pth=if defined? @rc['processing']['lout'] \
+        and @rc['processing']['lout'].is_a?(String)
+          "#{processing}/#{@rc['processing']['lout']}"
+        else "#{processing}/#{defaults[:processing_lout]}"
+        end
+        FileUtils::mkdir_p(pth) unless FileTest.directory?(pth)
+        pth
+      end
+      def sql
+        pth="#{processing}/sql"
+        FileUtils::mkdir_p(pth) unless FileTest.directory?(pth)
+        pth
+      end
+      def sqlite
+        pth=if defined? @rc['processing']['sqlite'] \
+        and @rc['processing']['sqlite'].is_a?(String)
+          "#{processing}/#{@rc['processing']['sqlite']}"
+        else "#{processing}/#{defaults[:processing_sqlite]}"
+        end
+        FileUtils::mkdir_p(pth) unless FileTest.directory?(pth)
+        pth
+      end
+      def postgresql
+        pth=if defined? @rc['processing']['postgresql'] \
+        and @rc['processing']['postgresql'].is_a?(String)
+          "#{processing}/#{@rc['processing']['postgresql']}"
+        else "#{processing}/#{defaults[:processing_postgresql]}"
+        end
+        FileUtils::mkdir_p(pth) unless FileTest.directory?(pth)
+        pth
+      end
+      self
+    end
+    def url
+      def hostname
+        "http://#{@sys.hostname}"
+      end
+      def dir_url
+        "file://#{path.webserv}/#{stub_pwd}"
+      end
+      def localhost
+        "http://localhost/#{stub_pwd}"
+      end
+      def local
+        "http://#{hostname}/#{@stub_pwd}"
+      end
+      def root
+        if defined? @rc['webserv']['url_root'] \
+        and @rc['webserv']['url_root'] =~/https?:\/\//
+          "#{@rc['webserv']['url_root']}/#{@stub_pwd}"
+        elsif defined? @rc['webserv']['url_root'] \
+        and @rc['webserv']['url_root'] =~/localhost/
+          "http://localhost/#{@stub_pwd}"
+        else "file://#{path.output}"
+        end
+      end
+      def remote
+        root
+      end
+      def txt
+        "#{root}/txt"
+      end
+      def html
+        "#{root}/html"
+      end
+      def epub
+        "#{root}/epub"
+      end
+      def odt
+        "#{root}/odt"
+      end
+      def pdf
+        "#{root}/pdf"
+      end
+      def src_txt
+        "#{root}/src"
+      end
+      def src_pod
+        "#{root}/pod"
+      end
+      def pot
+        "#{root}/po4a/pot"
+      end
+      def po
+        "#{root}/po4a/po"
+      end
+      def webserv_host_base(opt=nil)
+        if defined? @rc['webserv']['host']
+          case  @rc['webserv']['host']
+          when /https?:\/\// then @rc['webserv']['host']
+          when /\S+/         then "http://#{@rc['webserv']['host']}"
+          else                    defaults[:webserv_host_cgi]
+          end
+        else                      defaults[:webserv_host_cgi]
+        end
+      end
+      def webserv_cgi(opt=nil)         #web url for local webserv (localhost, or hostname)
+        http=if defined? @rc['webserv_cgi']['host'] \
+        and @rc['webserv_cgi']['host'].is_a?(String)
+          http=((@rc['webserv_cgi']['host'] =~ /https?:\/\//) ? '' : 'http://') #check https? missing
+          if port.webserv_port_cgi
+            http + @rc['webserv_cgi']['host'] + ':' \
+            + port.webserv_port_cgi + '/' \
+            + @stub_pwd
+          else
+            http + @rc['webserv_cgi']['host'] + '/' \
+            + @stub_pwd
+          end
+        else
+          http=((webserv_host_base=~/https?:\/\//) ? '' : 'http://')
+          if port.webserv_port_cgi(opt)
+            http + webserv_host_base + ':' \
+            + port.webserv_port_cgi(opt) + '/'\
+            + @stub_pwd
+          else
+            http + webserv_host_base + '/' \
+            + @stub_pwd
+          end
+        end
+        http=http.strip
+      end
+      def webserv_base_cgi(opt=nil)    #web url for local webserv (localhost, or hostname)
+        http_cgi=if opt.selections.str =~/--webserv-(?:cgi|db|search)[=-]["']?(\S+)["']+/
+          m=$1
+          (m=~/http\/\/:/) ? m : %{http://#{m}}
+        elsif defined? @rc['webserv_cgi']['host'] \
+        and @rc['webserv_cgi']['host'].is_a?(String)
+          http=((@rc['webserv_cgi']['host'] =~ /https?:\/\//) ? '' : 'http://')
+          if port.webserv_port_cgi(opt)
+            http + @rc['webserv_cgi']['host'] + ':' \
+            + port.webserv_port_cgi(opt).to_s
+          else
+            http + @rc['webserv_cgi']['host']
+          end
+        else
+          http=((webserv_host_base=~/https?:\/\//) ? '' : 'http://')
+          if port.webserv_port_cgi(opt)
+            http + webserv_host_base + ':' \
+            + port.webserv_port_cgi(opt).to_s
+          else http + webserv_host_base
+          end
+        end
+        http_cgi=http_cgi.strip
+        #%q{http://#{ENV['HTTP_HOST']}}
+      end
+      def webrick #must have a port    #REMOVE
+        if defined? @rc['webserv_cgi']['host'] \
+        and @rc['webserv_cgi']['host'].is_a?(String)
+          http=if @rc['webserv_cgi']['host'] =~/http:\/\//
+            'http://'
+          elsif @rc['webserv_cgi']['host'] =~/https:\/\//
+            'https://'
+          else defaults
+          end
+          http + @rc['webserv_cgi']['host']
+        elsif webserv_host_base \
+        and webserv_host_base.is_a?(String)
+          webserv_host_base
+        else
+          #http + 'localhost'
+          'localhost'
+        end
+      end
+      def webserv                      #web url for local webserv (localhost, or hostname)
+        if defined? @rc['webserv']['url_root'] \
+        and @rc['webserv']['url_root'] =~/http/
+          # needed for alternative output dir structures, fixes manifest url links, check may cause problems elsewhere
+          @rc['webserv']['url_root']
+        elsif path.webserv_dir \
+        and path.webserv =~ /#{path.webserv_dir}/ #revisit
+          path.webserv + '/' \
+            + @base_markup_dir_stub.
+              gsub(/#{path.webserv_dir}/,
+                "#{url.hostname}/#{@stub_pwd}")
+        elsif defined? @rc['webserv']['webrick_url'] \
+        and @rc['webserv']['webrick_url']==false
+          'file://' + path.webserv
+        elsif port.webserv_port_cgi =~/\S+/
+          url.hostname + ':' + port.webserv_port_cgi
+        else
+          url.hostname
+        end
+      end
+      def webserv_base                 #web url for local webserv (localhost, or hostname)
+        if path.webserv_dir \
+        and path.webserv =~ /#{path.webserv_dir}/ #revisit
+          path.webserv + '/' \
+          + @stub_pwd.
+            gsub(/#{path.webserv_dir}/,
+              "#{url.hostname}")
+        elsif defined? @rc['webserv']['webrick_url'] \
+        and @rc['webserv']['webrick_url']==false
+          "file://#{path.webserv}"
+        else "#{url.webrick_base}"
+        end
+      end
+      def webserv_files_from_db(opt=nil) #sort this out, messy
+        if opt.selections.str =~/--webserv-output[=-]["']?(\S+)["']+/
+          m=$1
+          (m=~/(?:http|file\/)\/\/:/) ? m : %{http://#{m}}
+        else
+          show_output_on=if defined? @rc['webserv_cgi']['show_output_on']
+            @rc['webserv_cgi']['show_output_on']
+          elsif  defined? @rc['webserv_cgi']['file_links']
+            @rc['webserv_cgi']['file_links']
+          else ''
+          end
+          m=case show_output_on
+          when /webserv_cgi/ then url.webserv_base_cgi(opt)
+          when /webserv/     then @rc['webserv']['url_root']
+          when /https?:\/\// then @rc['webserv_cgi']['file_links']
+          when /\S+/         then 'http://' + @rc['webserv_cgi']['file_links']
+          else                     webserv_base_cgi(opt)
+          end
+        end
+        #%q{http://#{ENV['HTTP_HOST']}/cgi-bin}
+      end
+      def cgi_sample_search_form_name(opt=nil)
+        if opt.selections.str \
+        =~/--(?:cgi-)?search-form-name[=-]["']?(\S+?\.cgi)/
+          $1
+        elsif not opt.selections.str =~/--db[=-]["']?sqlite/ \
+        and defined? @rc['search'] \
+        and defined? @rc['search']['sisu'] \
+        and defined? @rc['search']['sisu']['action'] \
+        and @rc['search']['sisu']['action'] =~/https?:\/\/\S+?\.cgi/
+          /(?:https?:\/\/\S+?)\/([^\/]+?\.cgi)$/.
+            match(@rc['search']['sisu']['action'])[1]
+        else
+          (opt.selections.str =~/--db[=-]["']?sqlite/) \
+          ? "#{Db[:name_prefix_db]}sqlite.cgi" \
+          :  "#{Db[:name_prefix_db]}pg.cgi"
+        end
+      end
+      def sample_search_form_title(organised_by=:language)
+        title=if defined? @rc['search']['sisu']['title'] \
+        and @rc['search']['sisu']['title'] =~/\S+/
+          @rc['search']['sisu']['title']
+        else %{SiSU (generated sample) search form}
+        end
+        title=title + " (content organised by #{organised_by})"
+      end
+      def output_tell                  #BROKEN Revisit 2011-02
+        output_type=if defined? @rc['show_output_on'] \
+        and @rc['show_output_on'] \
+        =~/^(?:filesystem|webserv|(?:local|remote)(?:_webserv)?|webrick)/
+          @rc['show_output_on']
+        else 'filesystem'
+        end
+        case output_type
+        when /^filesystem(?:_url)?/       then url.dir_url
+        when /^remote(?:_webserv)?/       then url.remote
+        when /^(?:webserv|local_webserv)/ then url.local
+        when /^local(:\d+)/               then url.hostname + $1 + '/' + stub_pwd
+        when /^localhost(:\d+)/           then url.localhost + $1 +  '/' + stub_pwd
+        when /^localhost/                 then url.localhost
+        when /^webrick/                   then url.webrick
+        when /^path/                      then url.webserv_map_pwd
+        else                                   url.webserv_map_pwd
+        end
+      end
+      def images
+        "#{Xx[:html_relative2]}/_sisu/image"
+      end
+      #def images
+      #  '../_sisu/image'
+      #end
+      def images_local
+        if FileTest.directory?(path.image_source_include)
+          path.image_source_include
+        else
+          if @@local_image==true
+            cmd=@md.opt.selections.str ? @md.opt.selections.str : ''
+            SiSU_Screen::Ansi.new(
+              cmd,
+              "WARNING - no local image directory or images:",
+              defaults[:image_local]
+            ).warn unless @md.opt.act[:quiet][:set]==:on
+            @@local_image=false
+          end
+          url.images
+        end
+      end
+      def images_external
+        if FileTest.directory?(image_external)
+          if @@image_flag
+            images=Dir.glob("#{image_external}/*.{png,jpg,gif}")
+            pth=path.webserv + '/' \
+            + @stub_pwd
+            FileUtils::mkdir_p("#{pth}/_sisu/image_external") \
+              unless FileTest.directory?("#{pth}/_sisu/image_external")
+            images.each { |i| File.install(i,"#{pth}/#{i}") } \
+              unless images.length > 0
+            @@image_flag=false
+          end
+          "#{Xx[:html_relative2]}/_sisu/image_external"
+        else
+          if @@local_image==true
+            SiSU_Screen::Ansi.new(
+              @cmd,
+              'WARNING - image directory for external images or no such images:',
+              :image_external
+            ).warn unless @md.opt.act[:quiet][:set]==:on
+            @@local_image=false
+          end
+          url.images_external
+        end
+      end
+      def images_epub
+        './image'
+      end
+      self
+    end
+    def port
+      def webrick_port
+        if @md \
+        and @md.opt.act[:sample_search_form][:set]==:on \
+        and @md.opt.selections.str=~/port=(\d+)/
+           $1
+        else
+          if defined? @rc['webserv_cgi']['port']
+            if @rc['webserv_cgi']['port'].nil? \
+            and (defined? @md.opt.selections \
+            and @md.opt.selections.str=~/webrick/)
+              defaults[:webserv_port_cgi]
+            elsif not @rc['webserv_cgi']['port'].nil?
+              @rc['webserv_cgi']['port']
+            else defaults[:webserv_port_cgi]
+            end
+          else   defaults[:webserv_port_cgi]
+          end
+        end
+      end
+      def webserv_port_cgi(opt=nil)
+        port=if opt \
+        and opt.act[:sample_search_form][:set]==:on \
+        and opt.selections.str=~/port[=-](\d+)/
+           $1
+        else
+          port=if defined? @rc['webserv_cgi']['port']
+            if @rc['webserv_cgi']['port'].nil? \
+            and (defined? opt.selections \
+            and opt.selections.str=~/webrick/)
+              defaults[:webserv_port_cgi]
+            elsif not @rc['webserv_cgi']['port'].nil?
+              @rc['webserv_cgi']['port']
+            else nil
+            end
+          else
+            if (defined? opt.selections \
+            and opt.selections.str=~/webrick/)
+              defaults[:webserv_port_cgi]
+            else nil
+            end
+          end
+        end
+        port.to_s
+      end
+      self
+    end
+    def digest_conf?
+      if defined? @rc['default']['digest'] \
+      and @rc['default']['digest'] != nil
+        case @rc['default']['digest']
+        when /^sha(?:5|512)?$/ then :sha512
+        when /^sha(?:2|256)?$/ then :sha256
+        when /^md5$/           then :md5
+        else                        :sha256
+        end
+      else                          :sha256
+      end
+    end
+    def digest(opt=nil)
+      @opt=opt
+      def type
+        if @opt
+          case @opt.act[:hash_digest_algo]
+          when :sha512 then :sha512
+          when :sha256 then :sha256
+          when :md5    then :md5
+          else              digest_conf?
+          end
+        else                digest_conf?
+        end
+      end
+      def length
+        case digest(@opt).type
+        when :sha512 then 128
+        when :sha256 then  64
+        when :md5    then  32
+        else               64
+        end
+      end
+      def pattern
+        "[0-9a-f]{#{digest(@opt).length}}" #/[0-9a-f]{#{digest.length}}/
+      end
+      self
+    end
+    def program
+      def text_editor
+        if defined? @rc['program_select']['editor'] \
+        and @rc['program_select']['editor'] =~/\S\S+/
+          @rc['program_select']['editor']
+        elsif defined? @rc['program_select']['text_editor'] \
+        and @rc['program_select']['text_editor'] =~/\S\S+/
+          @rc['program_select']['text_editor']
+        else 'editor'                                                            #'gvim -c :R -c :S'
+        end
+      end
+      def pdf_viewer
+        ((defined? @rc['program_select']['pdf_viewer']) \
+        && @rc['program_select']['pdf_viewer'] =~/\S\S+/) \
+        ? @rc['program_select']['pdf_viewer']
+        : 'pdf-viewer'                                                        #'evince'
+      end
+      def web_browser
+        if defined? @rc['program_select']['www_browser'] \
+        and @rc['program_select']['www_browser'] =~/\S\S+/
+          @rc['program_select']['www_browser']
+        elsif defined? @rc['program_select']['web_browser'] \
+        and @rc['program_select']['web_browser'] =~/\S\S+/
+          @rc['program_select']['web_browser']
+        else 'x-www-browser'                                                      #'firefox' 'iceweasel' 'kazehakase' 'galeon'
+        end
+      end
+      def www_browser
+        web_browser
+      end
+      def console_web_browser
+        if defined? @rc['program_select']['console_www_browser'] \
+        and @rc['program_select']['console_www_browser'] =~/\S\S+/
+          @rc['program_select']['console_www_browser']
+        elsif defined? @rc['program_select']['console_web_browser'] \
+        and @rc['program_select']['console_web_browser'] =~/\S\S+/
+          @rc['program_select']['console_web_browser']
+        else 'console-www-browser'                                             #'lynx' 'links' 'links2' 'elinks' 'w3m'
+        end
+      end
+      def console_www_browser
+        web_browser
+      end
+      def epub_viewer
+        ((defined? @rc['program_select']['epub_viewer']) \
+        && @rc['program_select']['epub_viewer'] =~/\S\S+/) \
+        ? @rc['program_select']['epub_viewer']
+        : 'ebook-viewer'                                                    #'calibre' 'fbreader'
+      end
+      def xml_viewer
+        ((defined? @rc['program_select']['xml_viewer']) \
+        && @rc['program_select']['xml_viewer'] =~/\S\S+/) \
+        ? @rc['program_select']['xml_viewer']
+        : text_editor
+      end
+      def docbook_viewer
+        ((defined? @rc['program_select']['xml_viewer']) \
+        && @rc['program_select']['xml_viewer'] =~/\S\S+/) \
+        ? @rc['program_select']['xml_viewer']
+        : text_editor
+      end
+      def fictionbook_viewer
+        ((defined? @rc['program_select']['xml_viewer']) \
+        && @rc['program_select']['xml_viewer'] =~/\S\S+/) \
+        ? @rc['program_select']['xml_viewer']
+        : text_editor
+      end
+      def xml_editor
+        xml_viewer
+      end
+      def odf_viewer
+        ((defined? @rc['program_select']['odf_viewer']) \
+        && @rc['program_select']['odf_viewer'] =~/\S\S+/) \
+        ? @rc['program_select']['odf_viewer']
+        : 'lowriter'                                                           #'odf-viewer','oowriter'
+      end
+      def manpage_viewer
+        'man'
+      end
+      def manpage_generator
+        ((defined? @rc['program_select']['man']) \
+        && @rc['program_select']['man'] =~/\S\S+/) \
+        ? @rc['program_select']['man']
+        : 'nroff -man'                                                        #'nroff -man' #'groff -man -Tascii'
+      end
+      def texinfo
+        ((defined? @rc['program_select']['info_viewer']) \
+        && @rc['program_select']['info_viewer'] =~/\S\S+/) \
+        ? @rc['program_select']['info_viewer']
+        : 'pinfo -f'                                                          #'pinfo -f' 'info' 'tkinfo'
+      end
+      def file_encoding
+        is=(defined? @rc['program_set']['file_encoding']) \
+        ? @rc['program_set']['encoding'] : ''
+        (is.nil? || is==true) ? 'encoding' : is
+      end
+      def wc #wordcount
+        is=(defined? @rc['program_set']['wc']) \
+          ? @rc['program_set']['wc'] : ''
+        (is.nil? || is==true) ? 'wc' : is
+      end
+      def tidy
+        is=(defined? @rc['program_set']['tidy']) \
+          ? @rc['program_set']['tidy'] : nil
+        (is.nil? || is==true) ? 'tidy' : is
+      end
+      def rmagick
+        is=(defined? @rc['program_set']['rmagick']) \
+          ? @rc['program_set']['rmagick'] : nil
+        (is.nil? || is==true) ? 'rmagick' : is
+      end
+      def rexml                        #should be part of ruby 1.8 but apparently not always
+        is=(defined? @rc['program_set']['rexml']) ? \
+          @rc['program_set']['rexml'] : ''
+        (is.nil? || is==true) ? 'rexml' : is
+      end
+      def pdflatex
+        is=(defined? @rc['program_set']['pdflatex']) ? \
+          @rc['program_set']['pdflatex'] : ''
+        (is.nil? || is==true) ? 'pdflatex' : is
+      end
+      def postgresql
+        is=(defined? @rc['program_set']['postgresql']) ? \
+          @rc['program_set']['postgresql'] : ''
+        (is.nil? || is==true) ? 'postgresql' : is
+      end
+      def sqlite
+        is=(defined? @rc['program_set']['sqlite']) ? \
+          @rc['program_set']['sqlite'] : ''
+        (is.nil? || is==true) ? 'sqlite' : is
+      end
+      self
+    end
+    def i18n
+      def language                     # language settings
+        m=/.+\/\S+?\~(\S+)/
+        pwd=Dir.pwd
+        conf=(defined? @rc['default']['language']) \
+        ? @rc['default']['language'] : nil
+        l=if pwd=~ m    then pwd[m,1]                                        #2 directory: by visible directory name
+        elsif conf      then @rc['default']['language']                      #3 config: from sisurc.yaml
+        else            defaults[:language]                                  #4 sisu: program default
+        end                                                                  #1 document: param gets
+        SiSU_Env::StandardiseLanguage.new(l)
+      end
+      #def multilingual
+      #  x=(defined? @rc['output_structure']['multilingual'] \
+      #  && @rc['output_structure']['multilingual'] ==true) \
+      #  ? true : false
+      #end
+      #def bundle
+      #  x=(defined? @rc['output_structure']['bundle'] \
+      #  && @rc['output_structure']['bundle'] ==true) \
+      #  ? true : false
+      #end
+      def lang_filename(l)
+        @lang={}
+        x=if output_dir_structure.by_language_code?
+          (( defined? @rc['default']['language_file']) \
+          && @rc['default']['language_file'] != nil) \
+          ? @rc['default']['language_file']
+          : 1
+        else 0
+        end
+        if (l != defaults[:language_code]) \
+        or (language.code != defaults[:language_code]) #watch
+          if x==1    then @lang[:pre],@lang[:mid],@lang[:post]="#{l}.",'',''
+          elsif x==2 then @lang[:pre],@lang[:mid],@lang[:post]='',".#{l}",''
+          elsif x==3 then @lang[:pre],@lang[:mid],@lang[:post]='','',".#{l}"
+          else            @lang[:pre],@lang[:mid],@lang[:post]='','',''
+          end
+        else              @lang[:pre],@lang[:mid],@lang[:post]='','',''
+        end
+        @lang
+      end
+      self
+    end
+    def file_encoding
+      is=''
+      if defined? @rc['program_set']['file_encoding']
+        is=@rc['program_set']['encoding']
+      end
+      if is.nil? \
+      or is==true
+        is='encoding'
+      end
+      is
+    end
+    def papersize                      # paper settings, default overidden in param if set within document
+      (defined? @rc['default']['papersize']) \
+      ? @rc['default']['papersize'].downcase
+      : (defaults[:papersize].downcase)
+    end
+    def sisupod_gen(fns_pod)
+      sisupod_gen_v3(fns_pod)
+    end
+    def sisupod_gen_v3(fns_pod)
+      pwd=Dir.pwd
+      sisupod_processing_path=
+        processing_path.processing + '/' + Gt[:sisupod]
+      if FileTest.directory?(sisupod_processing_path) \
+      or FileTest.file?(sisupod_processing_path)
+        FileUtils::rm_rf(sisupod_processing_path)
+      end
+      unless FileTest.directory?(sisupod_processing_path)
+        FileUtils::mkdir_p(sisupod_processing_path)
+      end
+      f_pod=if FileTest.file?("#{Dir.pwd}/#{fns_pod}")
+        "#{Dir.pwd}/#{fns_pod}"
+      elsif FileTest.file?(fns_pod)
+        fns_pod
+      end
+      if f_pod \
+      && FileTest.file?(f_pod)
+        (SiSU_Env::SystemCall.new.program_found?('tree')) \
+        ? 'tree ' + processing_path.processing + '/' + Gt[:sisupod]
+        : ''
+        if FileTest.directory?(processing_path.processing)
+          Dir.chdir(processing_path.processing)
+          system(%{tar xJf #{f_pod}})
+          Dir.chdir(pwd)
+        end
+        #system(tree)                                                          #enable if (/[vVM]/)
+      else
+        SiSU_Screen::Ansi.new(
+          '',
+          '*WARN* file not found: ' + fns_pod
+        ).warn unless @md.opt.act[:quiet][:set]==:on
+      end
+      sisupod_processing_path
+    end
+    def sisupod_gen_v2(fns_pod)
+      sisupod_processing_path=
+        processing_path.processing + '/' + Gt[:sisupod]
+      if FileTest.directory?(sisupod_processing_path) \
+      or FileTest.file?(sisupod_processing_path)
+        FileUtils::rm_rf(sisupod_processing_path)
+      end
+      unless FileTest.directory?(sisupod_processing_path)
+        FileUtils::mkdir_p(sisupod_processing_path)
+      end
+      (FileTest.file?(fns_pod)) \
+      ? system("unzip -q #{fns_pod} -d #{processing_path.processing}")
+      : (SiSU_Screen::Ansi.new(
+          '',
+          "*WARN* file not found: #{fns_pod}"
+        ).warn unless @md.opt.act[:quiet][:set]==:on)
+      sisupod_processing_path
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** se_info_port.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se_info_port.rb"
+# <<sisu_document_header>>
+module SiSU_Info_Port
+  require_relative 'constants'                             # constants.rb
+  require_relative 'utils'                                 # utils.rb
+  require_relative 'se_info_env'                           # se_info_env.rb
+  class InfoPort < SiSU_Info_Env::InfoEnv                  # se_info_env.rb
+    def initialize
+      @env=SiSU_Env::InfoEnv.new
+    end
+    def webrick
+      @env.port.webrick_port
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** se_info_system.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se_info_system.rb"
+# <<sisu_document_header>>
+module SiSU_Info_Sys_Gen
+  require_relative 'constants'                             # constants.rb
+  require_relative 'utils'                                 # utils.rb
+  class InfoSystemGen
+    begin
+      require 'rbconfig'
+    rescue LoadError
+      SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+        error('rbconfig NOT FOUND (LoadError)')
+    end
+    @@user,       @@home,     @@hostname,     @@pwd,     @@sisu_etc,                            @@host,                @@arch,                @@rbver,          @@dir_arch,               @@dir_sitearch,               @@dir_bin,               @@locale,                @@rc,@@sisurc_path,@@ad=
+      ENV['USER'],ENV['HOME'],ENV['HOSTNAME'],ENV['PWD'],RbConfig::CONFIG['sysconfdir'] + '/sisu',RbConfig::CONFIG['host'],RbConfig::CONFIG['arch'],%x{ruby -v}.strip,RbConfig::CONFIG['archdir'],RbConfig::CONFIG['sitearchdir'],RbConfig::CONFIG['bindir'],%x{locale charmap}.strip,nil, nil,          {} # %x{ruby -v}.strip # RbConfig::CONFIG['rb_ver']
+    out=RbConfig::CONFIG['localstatedir']
+    etc=RbConfig::CONFIG['sysconfdir'] + '/sisu'
+    share=RbConfig::CONFIG['datadir']  + '/sisu'
+    data=RbConfig::CONFIG['datadir']   + '/doc/sisu'
+    m=/.+\/(?:src\/)?(\S+)/m # m=/.+?\/(?:src\/)?([^\/]+)$/im # m=/.+\/(\S+)/m
+    @stub_pwd ||=@@pwd[m,1]
+    @base_markup_dir_stub=SiSU_Utils::Path.new.base_markup_stub
+    prcss_dir='_sisu_processing_'
+    prcss_dir_tmp_root="/tmp/#{prcss_dir}"
+    prcss_dir_stub="#{prcss_dir}/#{@stub_pwd}"
+    if @@user
+      tmp_processing="#{prcss_dir_tmp_root}/#{@@user}/#{@base_markup_dir_stub}"
+      tmp_processing_individual="#{prcss_dir_tmp_root}/#{@@user}/#{@base_markup_dir_stub}"
+    else #error
+      tmp_processing=tmp_processing_individual="/tmp/#{prcss_dir_stub}"
+    end
+    processing_pth=tmp_processing_individual
+    processing_dir=prcss_dir
+    processing_git="#{Dir.pwd}/#{Gt[:grotto]}"
+    #user=ENV['USER']
+    port_pgsql=if defined? ENV['PGPORT'] \
+    and not (ENV['PGPORT'].nil? \
+    || ENV['PGPORT'].empty?) \
+    and ENV['PGPORT']=~/^\d+$/
+      ENV['PGPORT']
+    else '5432'
+    end
+    IMAGES=:images
+    SISU_ETC=:sisu_etc
+    SISU_SHARE=:sisu_share
+    SAMPLE_DATA_PATH=:sample_data_path
+    IMAGE_STUB=:image_stub
+    STYLESHEET_STUB=:stylesheet_stub
+    IMAGE_LOCAL=:image_local
+    WEBSERV_PATH=:webserv_path
+    WEBSERV_MAN=:webserv_man
+    WEBSERV_PHP=:webserv_php
+    WEBSERV_CGI=:webserv_cgi
+    WEBSERV_RSS=:webserv_rss
+    WEBSERV_SQLITE=:webserv_sqlite
+    OUTPUT_LOCAL=:output_local
+    PROCESSING_DIR=:processing_dir
+    PROCESSING_PATH=:processing_path
+    PROCESSING_DIR_TMP_ROOT=:processing_dir_tmp_root
+    PROCESSING_PATH_TMP_BASE=:processing_path_tmp_base
+    PROCESSING_AO=:processing_ao
+    PROCESSING_TUNE=:processing_tune
+    PROCESSING_LATEX=:processing_latex
+    PROCESSING_TEXINFO=:processing_texinfo
+    PROCESSING_LOUT=:processing_lout
+    PROCESSING_SQLITE=:processing_sqlite
+    PROCESSING_POSTGRESQL=:processing_postgresql
+    PROCESSING_ENCODING=:processing_encoding
+    PROCESSING_GIT=:processing_git
+    PAPERSIZE=:papersize
+    #LANGUAGE=:language
+    #LANGUAGE_CODE=:language_code
+    MULTILINGUAL=:multilingual
+    BUNDLE=:bundle
+    CONCORD_MAX=:concord_max
+    DIGEST=:digest
+    WEBSERV_HOST_CGI=:webserv_host_cgi
+    WEBSERV_PORT_CGI=:webserv_port_cgi
+    POSTGRESQL_USER=:postgresql_user
+    POSTGRESQL_PORT=:postgresql_port
+    SQLITE_USER=:sqlite_user
+    SQLITE_PATH=:sqlite_path
+    SQLITE_PORT=:sqlite_port
+    DEFAULT_DIR={
+      IMAGES =>                   '_sisu/image',
+      SISU_ETC =>                 etc,
+      SISU_SHARE =>               share,
+      SAMPLE_DATA_PATH =>         data,
+      IMAGE_STUB =>               '_sisu/image',
+      STYLESHEET_STUB =>          '_sisu/css',
+      IMAGE_LOCAL =>              @@pwd + '/_sisu/image',
+      WEBSERV_PATH =>             out + '/www',
+      #WEBSERV_DIR =>             www, # uncomment for urls...
+      #WEBSERV_IMAGE =>            out + '/www/_sisu/image',
+      WEBSERV_MAN =>              out + '/www/man', #alter
+      WEBSERV_PHP =>              out + '/www/php',
+      WEBSERV_CGI =>              '/usr/lib/cgi-bin',
+      WEBSERV_RSS =>              out + '/www/feed',
+      WEBSERV_SQLITE =>           out + '/www/sqlite',
+      OUTPUT_LOCAL =>             @@home + '/sisu_www',
+      PROCESSING_DIR =>           processing_dir,
+      PROCESSING_PATH =>          processing_pth,
+      PROCESSING_DIR_TMP_ROOT  => prcss_dir_tmp_root,
+      PROCESSING_PATH_TMP_BASE => processing_pth,
+      PROCESSING_AO =>            'ao',
+      PROCESSING_TUNE =>          'tune',
+      PROCESSING_LATEX =>         'tex',
+      PROCESSING_TEXINFO =>       'texinfo',
+      PROCESSING_SQLITE =>        'sqlite',
+      PROCESSING_POSTGRESQL=>     'postgresql',
+      PROCESSING_ENCODING =>      'encoding',
+      PROCESSING_GIT =>           processing_git,
+      #TEXINFO_STUB =>             'texinfo',
+      PAPERSIZE =>                'A4', #A4, US_letter, book_b5, book_a5, US_legal
+      #LANGUAGE =>                 'English',
+      #LANGUAGE_CODE =>            'en', #change, unecessary duplication though currently used
+      MULTILINGUAL =>             false,
+      BUNDLE =>                   false,
+      CONCORD_MAX =>              260000,
+      DIGEST =>                   :sha256,
+      WEBSERV_HOST_CGI =>         'http://localhost',
+      WEBSERV_PORT_CGI =>         8081, #8111,8123,8081
+      POSTGRESQL_USER =>          @@user, #'ralph', # change user !!!
+      POSTGRESQL_PORT =>          port_pgsql,
+      #POSGRESQL_LINKS_PATH =>    '',
+      SQLITE_USER =>              @@user,
+      SQLITE_PATH =>              @@user, #??
+      SQLITE_PORT =>              '**',
+    }
+    @@default_dir=DEFAULT_DIR
+    m=/.+\/(?:src\/)?(\S+)/m # m=/.+?\/(?:src\/)?([^\/]+)$/im # m=/.+\/(\S+)/m
+    @@pwd=@pwd=SiSU_Utils::Path.new.base_markup
+    attr_accessor :user,:home,:hostname,:pwd,:host,:arch,:rbver,:dir_arch,:dir_sitearch,:dir_bin,:locale,:webserv_path,:webserv_host_cgi,:webserv_port_cgi,:default_dir,:rc_path,:ad_path
+    def initialize
+      @user,   @home, @hostname, @pwd, @sisu_etc, @host, @arch, @rbver, @dir_arch, @dir_sitearch, @dir_bin, @locale, @default_dir=
+        @@user,@@home,@@hostname,@@pwd,@@sisu_etc,@@host,@@arch,@@rbver,@@dir_arch,@@dir_sitearch,@@dir_bin,@@locale,@@default_dir
+      #note rbver is duplicated in InfoVersion
+    end
+  end
+end
+module SiSU_Info_Sys
+  class InfoSystem < SiSU_Info_Sys_Gen::InfoSystemGen
+    include Singleton
+    def initialize
+      super()
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** se_load.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se_load.rb"
+# <<sisu_document_header>>
+module SiSU_Load
+  require_relative 'constants'                             # constants.rb
+  require_relative 'utils'                                 # utils.rb
+  class Load
+    def initialize(prog,mandatory=false)
+      @prog,@mandatory=prog,mandatory
+    end
+    def prog
+      load_prog=false
+      $:.each do |reqpath|
+        if FileTest.exist?("#{reqpath}/#{@prog}.rb")
+          load_prog=true
+          #SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).ok("#{reqpath}/#{@prog}.rb loaded")
+          break
+        #else SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).warn("#{reqpath}/#{@prog}.rb not found")
+        end
+      end
+      if load_prog \
+      and @prog=~/dbi/
+        begin
+          require 'dbi'
+        rescue LoadError
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+            error('dbi NOT FOUND (LoadError)')
+        end
+      end
+      if load_prog
+        begin
+          require @prog
+        rescue LoadError
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+            error("#{@prog} NOT FOUND (LoadError)")
+        end
+      else
+        @mandatory \
+        ? (SiSU_Screen::Ansi.new(@prog,"*WARN* module required: #{@prog}").warn)
+        : '' #(SiSU_Screen::Ansi.new(@prog,"*WARN* #{@prog} load requested").warn)
+      end
+      load_prog
+    end
+    def prog?
+      load_prog=false
+      $:.each do |reqpath|
+        if FileTest.exist?("#{reqpath}/#{@prog}.rb"); load_prog=true
+          break
+        end
+      end
+      load_prog
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** se_processing.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se_processing.rb"
+# <<sisu_document_header>>
+module SiSU_Processing_Settings
+  require_relative 'constants'                             # constants.rb
+  require_relative 'utils'                                 # utils.rb
+  class ProcessingSettings
+    def initialize(md)
+      @md=md
+    end
+    def cnf_rc #sisurc.yml
+      @rc=SiSU_Env::GetInit.new.sisu_yaml.rc
+    end
+    def env_rc #env rc (including sisurc.yml)
+      @env_rc ||=SiSU_Env::InfoEnv.new(@md.fns)
+    end
+    def doc_rc #document rc, make instructions
+      (defined? @md.make) \
+      ? @md.make
+      : nil
+    end
+    def cmd_rc_act #command-line rc
+      @cmd_rc_act=@md.opt.opt_act
+    end
+    def build
+      def ocn?
+        if cmd_rc_act[:ocn][:set]==:on
+          true
+        elsif cmd_rc_act[:ocn][:set]==:off
+          false
+        elsif doc_rc.is_a?(Method) \
+        and defined? doc_rc.ocn? \
+        and doc_rc.toc? ==:off
+          false
+        elsif env_rc.build.ocn? ==:off
+          false
+        else
+          true
+        end
+      end
+      def plaintext_ocn?
+        if cmd_rc_act[:txt_ocn][:set]==:on \
+        or cmd_rc_act[:ocn][:set]==:on
+          true
+        elsif cmd_rc_act[:txt_ocn][:set]==:off \
+        or cmd_rc_act[:ocn][:set]==:off
+          false
+        elsif doc_rc.is_a?(Method) \
+        and defined? doc_rc.ocn? \
+        and doc_rc.toc? ==:off
+          false
+        elsif env_rc.build.ocn? ==:off
+          false
+        else
+          true
+        end
+      end
+      def odt_ocn?
+        if cmd_rc_act[:odt_ocn][:set]==:on \
+        or cmd_rc_act[:ocn][:set]==:on
+          true
+        elsif cmd_rc_act[:odt_ocn][:set]==:off \
+        or cmd_rc_act[:ocn][:set]==:off
+          false
+        elsif doc_rc.is_a?(Method) \
+        and defined? doc_rc.ocn? \
+        and doc_rc.toc? ==:off
+          false
+        elsif env_rc.build.ocn? ==:off
+          false
+        else
+          true
+        end
+      end
+      def html_strict?
+        if cmd_rc_act[:html_strict][:set]==:on
+          true
+        elsif cmd_rc_act[:html_strict][:set]==:off
+          false
+        elsif doc_rc.is_a?(Method) \
+        and defined? doc_rc.html_strict? \
+        and doc_rc.html_strict? ==:on
+          true
+        else
+          false
+        end
+      end
+      def toc?
+        if cmd_rc_act[:toc][:set]==:on
+          true
+        elsif cmd_rc_act[:toc][:set]==:off
+          false
+        elsif doc_rc.is_a?(Method) \
+        and defined? doc_rc.toc? \
+        and doc_rc.toc? ==:off
+          false
+        elsif env_rc.build.toc? ==:off
+          false
+        else
+          true
+        end
+      end
+      def manifest?
+        if cmd_rc_act[:manifest][:set]==:on
+          true
+        elsif cmd_rc_act[:manifest][:set]==:off
+          false
+        elsif doc_rc.is_a?(Method) \
+        and defined? doc_rc.manifest? \
+        and doc_rc.manifest? ==:off
+          false
+        elsif env_rc.build.manifest? ==:off
+          false
+        else
+          true
+        end
+      end
+      def links_to_manifest?
+        if cmd_rc_act[:links_to_manifest][:set]==:on
+          true
+        elsif cmd_rc_act[:links_to_manifest][:set]==:off
+          false
+        elsif doc_rc.is_a?(Method) \
+        and defined? doc_rc.links_to_manifest? \
+        and doc_rc.links_to_manifest? ==:off
+          false
+        elsif env_rc.build.links_to_manifest? ==:off
+          false
+        else
+          true
+        end
+      end
+      def metadata?
+        if cmd_rc_act[:metadata][:set]==:on
+          true
+        elsif cmd_rc_act[:metadata][:set]==:off
+          false
+        elsif doc_rc.is_a?(Method) \
+        and defined? doc_rc.metadata? \
+        and doc_rc.metadata? ==:off
+          false
+        elsif env_rc.build.metadata? ==:off
+          false
+        else
+          true
+        end
+      end
+      def minitoc?
+        if html_top_band? == false #one form of navigation necessary
+          true
+        elsif cmd_rc_act[:minitoc][:set]==:on
+          true
+        elsif cmd_rc_act[:minitoc][:set]==:off
+          false
+        elsif doc_rc.is_a?(Method) \
+        and defined? doc_rc.minitoc? \
+        and doc_rc.minitoc? ==:off
+          false
+        elsif env_rc.build.minitoc? ==:off
+          false
+        else
+          false
+        end
+      end
+      def manifest_minitoc?
+        if html_top_band? == false #one form of navigation necessary
+          true
+        elsif cmd_rc_act[:manifest_minitoc][:set]==:on \
+        || cmd_rc_act[:minitoc][:set]==:on
+          true
+        elsif cmd_rc_act[:manifest_minitoc][:set]==:off \
+        || cmd_rc_act[:minitoc][:set]==:off
+          false
+        elsif doc_rc.is_a?(Method) \
+        and defined? doc_rc.manifest_minitoc? \
+        and (doc_rc.manifest_minitoc? ==:off \
+        || doc_rc.minitoc? ==:off)
+          false
+        elsif env_rc.build.manifest_minitoc? ==:off \
+        || env_rc.build.minitoc? ==:off
+          false
+        elsif minitoc? == false
+          false
+        else
+          false
+        end
+      end
+      def html_minitoc?
+        if html_top_band? == false #one form of navigation necessary
+          true
+        elsif cmd_rc_act[:html_minitoc][:set]==:on \
+        || cmd_rc_act[:minitoc][:set]==:on
+          true
+        elsif cmd_rc_act[:html_minitoc][:set]==:off \
+        || cmd_rc_act[:minitoc][:set]==:off
+          false
+        elsif doc_rc.is_a?(Method) \
+        and defined? doc_rc.html_minitoc? \
+        and (doc_rc.html_minitoc? ==:off \
+        || doc_rc.minitoc? ==:off)
+          false
+        elsif env_rc.build.html_minitoc? ==:off \
+        || env_rc.build.minitoc? ==:off
+          false
+        elsif minitoc? == false
+          false
+        else
+          false
+        end
+      end
+      def html_top_band?
+        if cmd_rc_act[:html_top_band][:set]==:on
+          true
+        elsif cmd_rc_act[:html_top_band][:set]==:off
+          false
+        elsif doc_rc.is_a?(Method) \
+        and defined? doc_rc.html_top_band? \
+        and doc_rc.html_top_band? ==:off
+          false
+        elsif env_rc.build.html_top_band? ==:off
+          false
+        else
+          true
+        end
+      end
+      def html_navigation?
+        if cmd_rc_act[:html_navigation][:set]==:on
+          true
+        elsif cmd_rc_act[:html_navigation][:set]==:off
+          false
+        elsif doc_rc.is_a?(Method) \
+        and defined? doc_rc.html_navigation? \
+        and doc_rc.html_navigation? ==:off
+          false
+        elsif env_rc.build.html_navigation? ==:off
+          false
+        else
+          true
+        end
+      end
+      def html_navigation_bar?
+        if cmd_rc_act[:html_navigation_bar][:set]==:on
+          true
+        elsif cmd_rc_act[:html_navigation_bar][:set]==:off
+          false
+        elsif doc_rc.is_a?(Method) \
+        and defined? doc_rc.html_navigation_bar? \
+        and doc_rc.html_navigation_bar? ==:off
+          false
+        elsif env_rc.build.html_navigation_bar? ==:off
+          false
+        else
+          false
+        end
+      end
+      def search_form?
+        if cmd_rc_act[:search_form][:set]==:on
+          true
+        elsif cmd_rc_act[:search_form][:set]==:off
+          false
+        elsif doc_rc.is_a?(Method) \
+        and defined? doc_rc.html_search_form? \
+        and doc_rc.search_form? ==:off
+          false
+        elsif env_rc.build.search_form? ==:off
+          false
+        else
+          true
+        end
+      end
+      def html_search_form?
+        if cmd_rc_act[:html_search_form][:set]==:on \
+        || cmd_rc_act[:search_form][:set]==:on
+          true
+        elsif cmd_rc_act[:html_search_form][:set]==:off \
+        || cmd_rc_act[:search_form][:set]==:off
+          false
+        elsif doc_rc.is_a?(Method) \
+        and defined? doc_rc.html_search_form? \
+        and (doc_rc.html_search_form? ==:off \
+        || doc_rc.search_form? ==:off)
+          false
+        elsif env_rc.build.html_search_form? ==:off \
+        || env_rc.build.search_form? ==:off
+          false
+        elsif search_form? == false
+          false
+        else
+          true
+        end
+      end
+      def html_right_pane?
+        if cmd_rc_act[:html_right_pane][:set]==:on
+          true
+        elsif cmd_rc_act[:html_right_pane][:set]==:off
+          false
+        elsif doc_rc.is_a?(Method) \
+        and defined? doc_rc.html_right_pane? \
+        and doc_rc.html_right_pane? ==:off
+          false
+        elsif env_rc.build.html_right_pane? ==:off
+          false
+        else
+          true
+        end
+      end
+      def segsubtoc?
+        if cmd_rc_act[:segsubtoc][:set]==:on
+          true
+        elsif cmd_rc_act[:segsubtoc][:set]==:off
+          false
+        elsif doc_rc.is_a?(Method) \
+        and defined? doc_rc.segsubtoc? \
+        and doc_rc.segsubtoc? ==:off
+          false
+        elsif env_rc.build.segsubtoc? ==:off
+          false
+        else
+          true
+        end
+      end
+      self
+    end
+    def ocn_html_identifier
+      (build.html_strict?) \
+      ? Mx[:ocn_id_char]
+      : ''
+    end
+    def output_dir_structure
+      def by_language_code?
+        if cmd_rc_act[:output_by][:set] == :language
+          true
+        elsif cmd_rc_act[:output_by][:set] == :filetype \
+        or cmd_rc_act[:output_by][:set] == :filename
+          false
+        elsif cmd_rc_act[:output_by][:set] == :language
+          true
+        else
+          env_rc.output_dir_structure.by_language_code?
+        end
+      end
+      def by_filetype?
+        if cmd_rc_act[:output_by][:set] == :filetype
+          true
+        elsif cmd_rc_act[:output_by][:set] == :language \
+        or cmd_rc_act[:output_by][:set] == :filename
+          false
+        elsif cmd_rc_act[:output_by][:set] == :filetype
+          true
+        else
+          env_rc.output_dir_structure.by_filetype?
+        end
+      end
+      def by_filename?
+        if cmd_rc_act[:output_by][:set] == :filename
+          true
+        elsif cmd_rc_act[:output_by][:set] == :language \
+        or cmd_rc_act[:output_by][:set] == :filetype
+          false
+        elsif cmd_rc_act[:output_by][:set] == :filename
+          true
+        else
+          env_rc.output_dir_structure.by_filename?
+        end
+      end
+      def multilingual?
+        by_language_code?
+      end
+      def dump?
+        ((cmd_rc_act[:dump][:bool] \
+        &&  cmd_rc_act[:dump][:inst]) \
+        || (env_rc.output_dir_structure.dump?)) \
+        ? true
+        : false
+      end
+      def redirect?
+        ((cmd_rc_act[:redirect][:bool] \
+        &&  cmd_rc_act[:redirect][:inst]) \
+        || (env_rc.output_dir_structure.redirect?)) \
+        ? true
+        : false
+      end
+      def dump_or_redirect?
+        ((dump?) || (redirect?)) \
+        ? true
+        : false
+      end
+      def by?
+        if dump?
+          :dump
+        elsif redirect?
+          :redirect
+        elsif by_language_code?
+          :language
+        elsif by_filetype?
+          :filetype
+        elsif by_filename?
+          :filename
+        else #recheck current default
+          :language
+        end
+      end
+      self
+    end
+  end
+end
+module SiSU_Info_Processing_Flag
+  class InfoProcessingFlag
+    attr_accessor :color,:act_0,:act_1,:act_2,:act_3,:act_4,:act_5,:act_6,:act_7,:act_8,:act_9
+    def initialize
+      @rc=SiSU_Get_Init::GetInit.new.sisu_yaml.rc
+    end
+    def color                          #configurable processing flag shortcuts
+      (defined? @rc['flag']['color']) \
+      ? @rc['flag']['color']
+      : false
+    end
+    def act_0                           #configurable processing flag shortcuts
+      def default
+        '--manifest --digest --qrcode --text --html --epub --concordance --pdf --odf --docbook --xhtml --xml-sax --xml-dom --sqlite --verbose'
+      end
+      def str
+        if defined? @rc['flag']['act0'] \
+        and @rc['flag']['act0'].is_a?(String)
+          @rc['flag']['act0']
+        elsif defined? @rc['flag']['default'] \
+        and @rc['flag']['default'].is_a?(String)
+          @rc['flag']['default']
+        else default
+        end
+      end
+      def arr
+        str.scan(/\S+/)
+      end
+      self
+    end
+    def act_1                           #configurable processing flag shortcuts
+      def default
+        '--manifest --text --html'
+      end
+      def str
+        if defined? @rc['flag']['act1'] \
+        and @rc['flag']['act1'].is_a?(String)
+          @rc['flag']['act1']
+        elsif defined? @rc['flag']['i'] \
+        and @rc['flag']['i'].is_a?(String)
+          @rc['flag']['i']
+        else default
+        end
+      end
+      def arr
+        str.scan(/\S+/)
+      end
+      self
+    end
+    def act_2                           #configurable processing flag shortcuts
+      def default
+        '--manifest --text --html --epub --pdf'
+      end
+      def str
+        if defined? @rc['flag']['act2'] \
+        and @rc['flag']['act2'].is_a?(String)
+          @rc['flag']['act2']
+        elsif defined? @rc['flag']['ii'] \
+        and @rc['flag']['ii'].is_a?(String)
+          @rc['flag']['ii']
+        else default
+        end
+      end
+      def arr
+        str.scan(/\S+/)
+      end
+      self
+    end
+    def act_3                           #configurable processing flag shortcuts
+      def default
+        '--manifest --text --html --epub --pdf --concordance --qrcode'
+      end
+      def str
+        if defined? @rc['flag']['act3'] \
+        and @rc['flag']['act3'].is_a?(String)
+          @rc['flag']['act3']
+        elsif defined? @rc['flag']['iii'] \
+        and @rc['flag']['iii'].is_a?(String)
+          @rc['flag']['iii']
+        else default
+        end
+      end
+      def arr
+        str.scan(/\S+/)
+      end
+      self
+    end
+    def act_4                           #configurable processing flag shortcuts
+      def default
+        '--manifest --text --html --epub --pdf --concordance --qrcode --digest --odf --docbook'
+      end
+      def str
+        if defined? @rc['flag']['act4'] \
+        and @rc['flag']['act4'].is_a?(String)
+          @rc['flag']['act4']
+        elsif defined? @rc['flag']['iv'] \
+        and @rc['flag']['iv'].is_a?(String)
+          @rc['flag']['iv']
+        else default
+        end
+      end
+      def arr
+        str.scan(/\S+/)
+      end
+      self
+    end
+    def act_5                           #configurable processing flag shortcuts
+      def default
+        '--manifest --text --html --epub --pdf --concordance --qrcode --digest --odf --docbook --sqlite'
+      end
+      def str
+        if defined? @rc['flag']['act5'] \
+        and @rc['flag']['act5'].is_a?(String)
+          @rc['flag']['act5']
+        elsif defined? @rc['flag']['v'] \
+        and @rc['flag']['v'].is_a?(String)
+          @rc['flag']['v']
+        else default
+        end
+      end
+      def arr
+        str.scan(/\S+/)
+      end
+      self
+    end
+    def act_6                           #configurable processing flag shortcuts
+      def default
+        '--manifest --text --html --epub --pdf --concordance --qrcode --digest --odf --docbook --sqlite --xhtml --xml-sax --xml-dom'
+      end
+      def str
+        if defined? @rc['flag']['act6'] \
+        and @rc['flag']['act6'].is_a?(String)
+          @rc['flag']['act6']
+        else default
+        end
+      end
+      def arr
+        str.scan(/\S+/)
+      end
+      self
+    end
+    def act_7                           #configurable processing flag shortcuts
+      def default
+        '--manifest --text --html --epub --pdf --concordance --qrcode --digest --odf --docbook --sqlite --xhtml --xml-sax --xml-dom --source --sisupod'
+      end
+      def str
+        if defined? @rc['flag']['act7'] \
+        and @rc['flag']['act7'].is_a?(String)
+          @rc['flag']['act7']
+        else default
+        end
+      end
+      def arr
+        str.scan(/\S+/)
+      end
+      self
+    end
+    def act_8                           #configurable processing flag shortcuts
+      def default
+        '--manifest --text --html --epub --pdf --concordance --qrcode --digest --odf --docbook --xhtml --xml-sax --xml-dom --pg --update'
+      end
+      def str
+        if defined? @rc['flag']['act8'] \
+        and @rc['flag']['act8'].is_a?(String)
+          @rc['flag']['act8']
+        else default
+        end
+      end
+      def arr
+        str.scan(/\S+/)
+      end
+      self
+    end
+    def act_9                           #configurable processing flag shortcuts
+      def default
+        '--manifest --text --html --epub --pdf --concordance --qrcode --digest --odf --docbook --xhtml --xml-sax --xml-dom --pg --update --source --sisupod'
+      end
+      def str
+        if defined? @rc['flag']['act9'] \
+        and @rc['flag']['act9'].is_a?(String)
+          @rc['flag']['act9']
+        else default
+        end
+      end
+      def arr
+        str.scan(/\S+/)
+      end
+      self
+    end
+    def act_info
+      puts 'current "act" settings:'
+      acts=%w[ act_0 act_1 act_2 act_3 act_4 act_5 act_6 act_7 act_8 act_9 ]
+      acts.each_with_index do |m,i|
+        puts '--act-' + i.to_s + ' == ' \
+        + send(m).str
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** se_programs.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se_programs.rb"
+# <<sisu_document_header>>
+module SiSU_Sys_Call
+  begin
+    require 'singleton'
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('singleton NOT FOUND (LoadError)')
+  end
+  class SystemCall
+    @@locale_flag=false
+    def initialize(input='',output='',opt_or_cmd='')
+      @input,@output=input,output
+      (opt_or_cmd.is_a?(SiSU_Commandline::Options)) \
+      ? (@cmd,@opt=opt_or_cmd.cmd,opt_or_cmd)
+      : (@cmd,@opt=opt_or_cmd,nil) #cmd.is_a?(String)
+      @prog=SiSU_Env::InfoProgram.new
+      @sys=SiSU_Info_Sys::InfoSystem.instance
+    end
+    def program_found?(program)
+      found=`which #{program} 2>&1` #`whereis #{program}`
+      (found =~/bin\/#{program}\b/) ? true : false
+    end
+    def locale                         #locales utf8 or other
+      unless @@locale_flag
+        @@locale_flag=true
+      end
+      @sys.locale
+    end
+    def file_encoding(filename,act='') #file encoding
+      program='file'
+      fnsp=SiSU_Env::InfoEnv.new(filename).source_file_with_path
+      if program_found?(program)
+        encoding=%x{file -L #{fnsp}}.strip
+        encoding=encoding.gsub(/#{fnsp}:(\s+|$)/,'')
+        encoding=if encoding \
+        and not encoding.empty?
+          encoding
+        else 'UTF-8 assumed, encoding undetermined'
+        end
+        if act[:verbose_plus][:set] ==:on \
+        or  act[:maintenance][:set] ==:on
+          puts encoding
+        end
+        encoding
+      else
+        'UTF-8 assumed, file encoding check program unavailable'
+      end
+    end
+    def wc                             #word count
+      program='wc'
+      if program_found?(program) \
+      and locale !~/utf-?8/i
+        true
+      else
+        program_ref="(not available)" \
+          unless program_found?(program)
+        program_ref="(UTF-8)" \
+          if locale =~/utf-?8/i
+        false
+      end
+    end
+    def rcs                            #rcs for document markup data
+      program='rcs'
+      program_ref="\n\t\tdocument version information requested"
+      if program_found?(program); true
+      else
+        SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+          warn("#{program} is not installed #{program_ref}")
+        false
+      end
+    end
+    def cvs                            #cvs for document markup data
+      program='cvs'
+      program_ref="\n\t\tdocument version information requested"
+      if program_found?(program); true
+      else
+        SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+          warn("#{program} is not installed #{program_ref}")
+        false
+      end
+    end
+    def po4a                           #po4a
+      program='po4a'
+      program_ref="\n\t\tpo4a"
+      if program_found?(program); true
+      else
+        SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+          warn("#{program} is not installed #{program_ref}")
+        false
+      end
+    end
+    def zip                            #zip
+      program='zip'
+      program_ref="\n\t\tused to in the making of number of file formats, odf, epub"
+      if program_found?(program); true
+      else
+        SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+          mark("*WARN* #{program} is not installed #{program_ref}")
+        false
+      end
+    end
+    def openssl                        #openssl for digests
+      program='openssl'
+      program_ref="\n\t\tused to generate requested source document identification digest"
+      if program_found?(program); true
+      else
+        SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+          warn("#{program} is not installed #{program_ref}")
+        false
+      end
+    end
+    def md5(filename)                  #md5 dgst
+      program='openssl'
+      program_ref="\n\t\tmd5 digest requested"
+      if program_found?(program)
+        pwd=Dir.pwd
+        Dir.chdir(File.dirname(filename))
+        dgst=%x{openssl dgst -md5 #{File.basename(filename)}}.strip #use file name without file path
+        Dir.chdir(pwd)
+        dgst.scan(/\S+/)
+      else
+        SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+          warn("#{program} is not installed #{program_ref}")
+        false
+      end
+    end
+    def sha256(filename)               #sha dgst
+      program='openssl'
+      program_ref="\n\t\tsha digest requested"
+      if program_found?(program)
+        pwd=Dir.pwd
+        Dir.chdir(File.dirname(filename))
+        dgst=%x{openssl dgst -sha256 #{File.basename(filename)}}.strip #use file name without file path
+        Dir.chdir(pwd)
+        dgst.scan(/\S+/)
+      else
+        SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+          warn("#{program} is not installed #{program_ref}")
+        false
+      end
+    end
+    def sha512(filename)               #sha dgst
+      program='openssl'
+      program_ref="\n\t\tsha digest requested"
+      if program_found?(program)
+        pwd=Dir.pwd
+        Dir.chdir(File.dirname(filename))
+        dgst=%x{openssl dgst -sha512 #{File.basename(filename)}}.strip #use file name without file path
+        Dir.chdir(pwd)
+        dgst.scan(/\S+/)
+      else
+        SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+          warn("#{program} is not installed #{program_ref}")
+        false
+      end
+    end
+    def psql                           #psql
+      program='psql'
+      program_ref="\n\t\tpsql requested"
+      if program_found?(program); true
+      else
+        SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+          warn("#{program} is not installed #{program_ref}")
+        false
+      end
+    end
+    def create_pg_db(dbname_stub=nil)  #createdb
+      unless dbname_stub
+        @pwd ||=Dir.pwd
+        m=/.+\/(?:src\/)?(\S+)/im # m=/.+?\/(?:src\/)?([^\/]+)$/im # m=/.+\/(\S+)/m
+        dbname_stub=@pwd[m,1]
+      end
+      program='createdb'
+      db_name="#{Db[:name_prefix]}#{dbname_stub}"
+      program_ref="\n\t\tcreatedb dbname #{db_name} #for postgresql database creation"
+      (program_found?(program)) \
+      ? system("#{program} #{dbname_name}")
+      : (STDERR.puts "\t*WARN* #{program} is not available #{program_ref}")
+    end
+    def relaxng(cmd='')                #trang - convert between different schema languages for XML
+      program='trang'
+      program_ref="\n\t\tsee <http://www.thaiopensource.com/relaxng/trang.html>"
+      (program_found?(program)) \
+      ? system("#{program} #{@input} #{@output}")
+      : (STDERR.puts "\t*WARN* #{program} is not installed #{program_ref}" if cmd =~/V/)
+    end
+    def qrencode                       #qrcode - for generating QR code
+      program='qrencode'
+      program_ref="\n\t\tsee <http://megaui.net/fukuchi/works/qrencode/index.en.html>"
+      found=(program_found?(program)) ? true : false
+      found \
+      ? (system(%{
+          echo "#{@input}" | #{program} -s 3 -o #{@output}
+        }))
+      : (STDERR.puts "\t*WARN* #{program} is not installed #{program_ref}" if @cmd =~/V/)
+      #found
+    end
+    def imagemagick                    #imagemagick is a image manipulation program
+      program='identify'
+      #program_ref="\n\t\tsee <http://www.imagemagick.org/>"
+      found=(program_found?(program)) ? true : false
+      #STDERR.puts "\t*WARN* #{program} is not installed #{program_ref}" unless found
+      found
+    end
+    def graphicsmagick                #graphicsmagick is a image manipulation program
+      program='gm'
+      #program_ref="\n\t\tsee <http://www.graphicsmagick.org/>"
+      found=(program_found?(program)) ? true : false
+      #STDERR.puts "\t*WARN* #{program} is not installed #{program_ref}" unless found
+      found
+    end
+    def well_formed?                   #tidy - check for well formed xml xhtml etc.
+      program=@prog.tidy
+      program_ref="\n\t\tsee <http://tidy.sourceforge.net/>"
+      (program_found?(program)) \
+      ? system("#{@prog.tidy} -xml #{@input} > #{@output}")
+      : (STDERR.puts "\t*WARN* #{program} is not installed #{program_ref}")
+    end
+    def tex2pdf_engine
+      progs=['xetex','xelatex','pdflatex','pdfetex','pdftex']
+      @pdfetex_flag=false
+      @cmd ||=''
+      @texpdf=nil
+      progs.each do |program|
+        if program_found?(program)
+          @texpdf=program if program =~/xetex|xelatex|pdftex|pdflatex/
+          @pdfetex_flag=true
+          break
+        end
+      end
+      if @pdfetex_flag==false
+        @texpdf=progs.join(', ')
+      end
+      @texpdf
+    end
+    def latex2pdf(md,papersize='a4')   #convert from latex to pdf
+      tell=if @cmd =~/[MV]/
+        ''
+      elsif @cmd =~/[v]/
+        %q{2>&1 | grep -v ' WARNING '}
+      else %q{2>&1 | grep -v '$'}
+      end
+      mode='batchmode' #mode='nonstopmode'
+      texpdf=tex2pdf_engine
+      if @pdfetex_flag
+        texpdf_cmd=case texpdf
+        when /xetex/
+          %{#{texpdf} -interaction=#{mode} -fmt=xelatex #{@input} #{tell}\n}
+        when /xelatex/
+          %{#{texpdf} -interaction=#{mode} -papersize="#{papersize}" #{@input} #{tell}\n}
+        when /pdftex/
+          "#{texpdf} -interaction=#{mode} -fmt=pdflatex #{@input} #{tell}\n"
+        when /pdflatex/
+          "#{texpdf} -interaction=#{mode} #{@input} #{tell}\n"
+        end
+        system(texpdf_cmd)
+      else STDERR.puts "\t*WARN* none of the following programs are installed: #{@texpdf}"
+      end
+    end
+    def makeinfo                       #texinfo
+      program='makeinfo'
+      options='' #'--force' #''
+      program_ref="\n\t\tsee http://www.gnu.org/software/texinfo/"
+      (program_found?(program)) \
+      ? system("#{program} #{options} #{@input}\n")
+      : (STDERR.puts "\t*WARN* #{program} is not installed #{program_ref}")
+    end
+    def scp
+      puts "scp -Cr #{@input} #{@output}" if @cmd =~/[vVM]/
+      puts "scp disabled"
+    end
+    def rsync(action='',chdir=nil)
+      program='rsync'
+      if program_found?(program)
+        vb=if @cmd =~/q/; 'q'
+        elsif @cmd =~/v/; 'v'
+        else              ''
+        end
+        cX=SiSU_Screen::Ansi.new(@cmd).cX
+        msg=(@cmd =~/q/) ? '' : %{ && echo " #{cX.grey}OK: #{@input} -> #{@output}#{cX.off}"}
+        amp=(@opt \
+        && @opt.files.length > 1) \
+        ? ''
+        : ((@cmd =~/[vVM]/) ? '' : '&')
+        rsync_cmd="rsync -az#{vb} #{action} #{@input} #{@output}"
+        puts rsync_cmd if @cmd =~/[vVM]/
+        dir_change=dir_return=nil
+        if not chdir.nil? \
+        && chdir != Dir.pwd
+          dir_change=Dir.chdir(chdir)
+          dir_return=Dir.pwd
+        end
+        dir_change if dir_change
+        system("
+          #{rsync_cmd} #{msg} #{amp}
+        ")
+        dir_return if dir_return
+      else STDERR.puts "\t*WARN* #{program} not found"
+      end
+    end
+    def rm
+      if @cmd =~/^-Z[mMvVq]*$/;      FileUtils::rm_rf(@input)
+      elsif @cmd =~/V/;              FileUtils::rm(@input)
+      elsif @cmd !~/q/;              FileUtils::rm(@input)
+      elsif @cmd =~/q/;              FileUtils::rm(@input)
+      else                           STDERR.puts "\t*WARN* operation ignored"
+      end
+    end
+  end
+end
+module SiSU_Info_Program
+  require_relative 'constants'                             # constants.rb
+  require_relative 'utils'                                 # utils.rb
+  require_relative 'se_info_env'                           # se_info_env.rb
+  class InfoProgram < SiSU_Info_Env::InfoEnv               # se_info_env.rb
+    attr_accessor :editor,:wc,:tidy,:rexml,:pdflatex,:postgresql,:sqlite
+    def initialize
+      prog=SiSU_Env::InfoEnv.new.program
+      @editor,           @wc,    @tidy,    @rexml,    @pdflatex,    @postgresql,    @sqlite=
+        prog.text_editor,prog.wc,prog.tidy,prog.rexml,prog.pdflatex,prog.postgresql,prog.sqlite
+    end
+  end
+end
+module SiSU_Info_Set
+  require_relative 'se_info_env'                           # se_info_env.rb
+  class InfoSettings < SiSU_Info_Env::InfoEnv              # se_info_env.rb
+    def permission?(prog)                                  # program defaults
+      (defined? @rc['permission_set'][prog]) \
+      ? @rc['permission_set'][prog]
+      : false
+    end
+    def program?(prog)                                     # program defaults
+      (defined? @rc['program_set'][prog]) \
+      ? @rc['program_set'][prog]
+      : false
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** se_remotes.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se_remotes.rb"
+# <<sisu_document_header>>
+module SiSU_Info_Remote_Host
+  require_relative 'constants'                             # constants.rb
+  require_relative 'utils'                                 # utils.rb
+  class InfoRemoteHost
+    def initialize
+      @rc=SiSU_Env::GetInit.new.sisu_yaml.rc
+    end
+    def remote_host #see InfoRemote remote_host_base_general
+      r=[]
+      r=if (defined? @rc['remote'] \
+      and @rc['remote'].is_a?(Array))
+        r_array=@rc['remote']
+        r_array.each_with_index do |renv,i|
+          r[i]={}
+          if defined? renv['user'] \
+          and defined? renv['host']
+          end
+          r[i][:user]=renv['user']
+          r[i][:host]=renv['host']
+          r[i][:path]=if defined? renv['path']
+            renv['path']
+          else ''
+          end
+          r[i][:name]="#{r[i][:user]}@#{r[i][:host]}:#{r[i][:path]}"
+        end
+        r
+      elsif (defined? @rc['remote'] \
+      and @rc['remote'].is_a?(Hash) \
+      and defined? @rc['remote']['user'] \
+      and defined? @rc['remote']['host'])
+        r[0]={}
+        r[0][:user]=@rc['remote']['user']
+        r[0][:host]=@rc['remote']['host']
+        r[0][:path]=if defined? @rc['remote']['path']
+          @rc['remote']['path']
+        else ''
+        end
+        r[0][:name]="#{r[0][:user]}@#{r[0][:host]}:#{r[0][:path]}"
+        r
+      else
+        r[0]={}
+        r[0][:name]='.'
+        r[0][:user]=''
+        r[0][:host]=''
+        r[0][:path]=''
+        #puts "no remote host or user"
+        r
+      end
+    end
+    def rhost
+      def r1
+        (defined? SiSU_Env::InfoRemoteHost.new.remote_host[0][:name]) \
+        ? (SiSU_Env::InfoRemoteHost.new.remote_host[0][:name])
+        : nil
+      end
+      def r2
+        (defined? SiSU_Env::InfoRemoteHost.new.remote_host[1][:name]) \
+        ? (SiSU_Env::InfoRemoteHost.new.remote_host[1][:name])
+        : nil
+      end
+      def r3
+        (defined? SiSU_Env::InfoRemoteHost.new.remote_host[2][:name]) \
+        ? (SiSU_Env::InfoRemoteHost.new.remote_host[2][:name])
+        : nil
+      end
+      def r4
+        (defined? SiSU_Env::InfoRemoteHost.new.remote_host[3][:name]) \
+        ? (SiSU_Env::InfoRemoteHost.new.remote_host[3][:name])
+        : nil
+      end
+      def r5
+        (defined? SiSU_Env::InfoRemoteHost.new.remote_host[4][:name]) \
+        ? (SiSU_Env::InfoRemoteHost.new.remote_host[4][:name])
+        : nil
+      end
+      def r6
+        (defined? SiSU_Env::InfoRemoteHost.new.remote_host[5][:name]) \
+        ? (@ls + SiSU_Env::InfoRemoteHost.new.remote_host[5][:name])
+         : nil
+      end
+      self
+    end
+  end
+end
+module SiSU_Info_Remote
+  require_relative 'constants'                             # constants.rb
+  require_relative 'utils'                                 # utils.rb
+  require_relative 'se_filemap'                            # se_filemap.rb
+  begin
+    require 'fileutils'
+      include FileUtils::Verbose
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('fileutils NOT FOUND (LoadError)')
+  end
+  class InfoRemote < SiSU_File_Map::FileMap                # se_filemap.rb
+    @@flag_remote=false
+    begin
+      require 'socket'
+    rescue LoadError
+      SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+        error('socket NOT FOUND (LoadError)')
+    end
+    def initialize(opt)
+      super(opt) #
+      @opt=opt
+      @rc=GetInit.new.sisu_yaml.rc
+    end
+    def remote_host_base_general
+      SiSU_Env::InfoRemoteHost.new.remote_host
+    end
+    def remote_host_base
+      remote_host_base_general.each do |remote_conn|
+        @@flag_remote=true if remote_conn[:name] =~/\S+?@\S+/
+      end
+      remote_host_base_general
+    end
+    def scp                            #sort out later using ruby libraries #not ideal, first time each file is sent, -r must be called separately for subdir to be built
+      def document
+        self.remote_host_base.each do |remote_conn|
+          local_gen=@source_path
+          remote_gen=case @opt.cmd
+          when /u/
+            remote_conn[:name] + '/' \
+              + @env.path.base_markup_dir_stub + '/.'             #creates remote directory tree, this is not the usual function of u
+          when /[abhHNopwxXy]/
+            remote_conn[:name] + '/' \
+              + @env.path.base_markup_dir_stub + '/' \
+              + @fnb + '/.'
+          else
+            remote_conn[:name] + '/' \
+              + @env.path.base_markup_dir_stub \
+              + '/.'
+          end
+          local_epub=@source_path_epub
+          local_src=@source_path_src
+          local_pod=@source_path_pod
+          remote_epub=
+            remote_conn[:name] + '/' + @env.path.stub_epub + '/.'
+          remote_src=
+            remote_conn[:name] + '/' + @env.path.stub_src + '/.'
+          remote_pod=
+            remote_conn[:name] + '/' + @env.path.stub_pod + '/.'
+          src_txt=@opt.fnc
+          src_pod=@opt.fncb.gsub(/(\.ss[mt])(?:\.sst)?$/,'\1.txz')
+          if (local_gen =~/\S/ \
+          and local_gen !~/\/\//) \
+          and (remote_gen =~/\S/ \
+          and remote_gen !~/\/\//) \
+          and @@flag_remote==true \
+          and @opt.cmd !~/U/
+            SiSU_Env::SystemCall.new(local_gen,remote_gen).scp
+            if FileTest.file?("#{local_src}/#{src_txt}")
+              SiSU_Env::SystemCall.new("#{local_src}/#{src_txt}",remote_src).scp
+            end
+            if FileTest.file?("#{local_pod}/#{src_pod}")
+              SiSU_Env::SystemCall.new("#{local_src}/#{src_pod}",remote_pod).scp
+            end
+            if FileTest.file?("#{local_epub}/#{@opt.fnb}.epub")
+              SiSU_Env::SystemCall.new(
+                "#{local_epub}/#{@opt.fnb}.epub",
+                remote_epub,@opt.cmd
+              ).scp
+            end
+          elsif  @opt.cmd =~/U/
+            puts "#{__FILE__} #{__LINE__}" if @opt.cmd =~/M/
+            puts "#{local_gen} -> #{remote_gen}"
+            if FileTest.file?("#{local_src}/#{src_doc}")
+              puts "#{local_src}/#{src_doc}* -> #{remote_src}"
+            end
+            if FileTest.file?("#{local_pod}/#{src_doc}.txz")
+              puts "#{local_pod}/#{src_doc}* -> #{remote_pod}"
+            end
+          else
+            puts 'suspect scp request, ignored'
+            puts "#{local_gen} -> #{remote_gen} remote flag: #{@@flag_remote}"
+            puts "permission not granted #{__FILE__} #{__LINE__}" if @opt.cmd =~/M/
+          end
+        end
+      end
+      def site_base                    #base site
+        self.remote_host_base.each do |remote_conn|
+          local=@source_path
+          remote="#{remote_conn[:name]}/#{@env.path.base_markup_dir_stub}/."
+          if defined? @rc['permission_set']['remote_base_site'] \
+          and @rc['permission_set']['remote_base_site'] \
+          and @@flag_remote==true \
+          and @opt.cmd !~/U/
+            puts "begin scp_base: #{local} -> #{remote}"
+            SiSU_Env::SystemCall.new("#{local}/#{@env.path.style}/",remote).scp
+          elsif @opt.cmd =~/U/
+            puts "#{__FILE__} #{__LINE__}" if @opt.cmd =~/M/
+            puts "begin scp_base: #{local} -> #{remote}"
+            puts "#{local}/#{@env.path.style}/ -> #{remote}"
+          else  puts "permission not granted #{__FILE__} #{__LINE__}" if @opt.cmd =~/M/
+          end
+        end
+      end
+      def site_base_all                #base site
+        self.remote_host_base.each do |remote_conn|
+          local=@source_path
+          remote=
+            remote_conn[:name] + '/' \
+              + @env.path.base_markup_dir_stub + '/.'
+          if defined? @rc['permission_set']['remote_base_site'] \
+          and @rc['permission_set']['remote_base_site'] \
+          and @@flag_remote==true \
+          and @opt.cmd !~/U/
+            puts "begin scp_base_all: #{local} -> #{remote}"
+            SiSU_Env::SystemCall.new("#{local}/_sisu/image_sys/",remote).scp
+            SiSU_Env::SystemCall.new("#{local}/_sisu/image/",remote).scp
+            SiSU_Env::SystemCall.new("#{local}/#{@env.path.style}/",remote).scp
+          elsif @opt.cmd =~/U/
+            puts "#{__FILE__} #{__LINE__}" if @opt.cmd =~/M/
+            puts "scp_base_all: #{local} -> #{remote}"
+            puts "#{local}/_sisu/image_sys/ -> #{remote}"
+            puts "#{local}/_sisu/image/ -> #{remote}"
+            puts "#{local}/#{@env.path.style}/ -> #{remote}"
+          else
+            puts "permission not granted #{__FILE__} #{__LINE__}" \
+              if @opt.cmd =~/M/
+          end
+        end
+      end
+      self
+    end
+    def rsync
+      def document
+        f=(@opt.act[:ao][:set]==:on) \
+        ? SiSU_Env::FileOp.new(@md)
+        : nil
+        if f
+          self.remote_host_base.each do |remote_conn|
+            local_gen=@source_path
+            #local_gen_image="#{@env.path.webserv}/#{@env.path.base_markup_dir_stub}/_sisu/image"
+            #local_gen_image_external="#{@env.path.webserv}/#{@env.path.base_markup_dir_stub}/_sisu/image_external"
+            remote_gen=
+              remote_conn[:name] + '/' \
+                + @env.path.base_markup_dir_stub + '/.'
+            remote_rel=
+              remote_conn[:name] + '/' \
+                + f.output_path.stub.rcp
+            @opt.fnc
+            if (local_gen =~/\S/ \
+            and local_gen !~/\/\//) \
+            and (remote_gen =~/\S/ \
+            and remote_gen !~/\/\//) \
+            and @@flag_remote==true \
+            and @opt.cmd !~/U/
+#             SiSU_Env::SystemCall.new("#{local_src}/#{src_txt}",remote_src,@opt.cmd).rsync
+              #delete_extra_files='--delete' # '--delete-after'
+              inp=[]
+              if (@opt.act[:html][:set]==:on \
+              || @opt.cmd =~/^-[mqvVM]*R[mqvVM]*$/) \
+              && FileTest.file?(f.place_file.html_scroll.dir)
+                inp \
+                  << f.output_path.html_seg.rel \
+                  << f.place_file.html_scroll.rel
+              end
+              if (@opt.act[:concordance][:set]==:on \
+              || @opt.cmd =~/^-[mqvVM]*R[mqvVM]*$/) \
+              && FileTest.file?(f.place_file.html_concordance.dir)
+                inp << f.place_file.html_concordance.rel
+              end
+              if (@opt.act[:epub][:set]==:on \
+              || @opt.cmd =~/^-R[mqvVM]*$/) \
+              && FileTest.file?(f.place_file.epub.dir)
+                inp << f.place_file.epub.rel
+              end
+              if (@opt.act[:odt][:set]==:on \
+              || @opt.cmd =~/^-[mqvVM]*R[mqvVM]*$/) \
+              && FileTest.file?(f.place_file.odt.dir)
+                inp << f.place_file.odt.rel
+              end
+              if (@opt.act[:xhtml][:set]==:on \
+              || @opt.cmd =~/^-[mqvVM]*R[mqvVM]*$/) \
+              && FileTest.file?(f.place_file.xhtml.dir)
+                inp << f.place_file.xhtml.rel
+              end
+              if (@opt.act[:xml_sax][:set]==:on \
+              || @opt.cmd =~/^-[mqvVM]*R[mqvVM]*$/) \
+              && FileTest.file?(f.place_file.xml_sax.dir)
+                inp << f.place_file.xml_sax.rel
+              end
+              if (@opt.act[:xml_dom][:set]==:on \
+              || @opt.cmd =~/^-[mqvVM]*R[mqvVM]*$/) \
+              && FileTest.file?(f.place_file.xml_dom.dir)
+                inp << f.place_file.xml_dom.rel
+              end
+              if (@opt.act[:xml_scaffold_structure_sisu][:set]==:on \
+              || @opt.cmd =~/^-[mqvVM]*R[mqvVM]*$/) \
+              && FileTest.file?(f.place_file.xml_scaffold_structure_sisu.dir)
+                inp << f.place_file.xml_scaffold_structure_sisu.rel
+              end
+              if (@opt.act[:xml_scaffold_structure_collapse][:set]==:on \
+              || @opt.cmd =~/^-[mqvVM]*R[mqvVM]*$/) \
+              && FileTest.file?(f.place_file.xml_scaffold_structure_collapse.dir)
+                inp << f.place_file.xml_scaffold_structure_collapse.rel
+              end
+              if (@opt.act[:txt][:set]==:on \
+              || @opt.cmd =~/^-[mqvVM]*R[mqvVM]*$/) \
+              && FileTest.file?(f.place_file.txt.dir)
+                inp << f.place_file.txt.rel
+              end
+              if (@opt.act[:manpage][:set]==:on \
+              || @opt.cmd =~/^-[mqvVM]*i[mqvVM]*$/) \
+              && FileTest.file?(f.place_file.manpage.dir)
+                inp << f.place_file.manpage.rel
+              end
+              if (@opt.act[:texinfo][:set]==:on \
+              || @opt.cmd =~/^-[mqvVM]*I[mqvVM]*$/) \
+              && FileTest.file?(f.place_file.info.dir)
+                inp << f.place_file.info.rel
+              end
+              if (@opt.act[:hash_digests][:set]==:on \
+              || @opt.cmd =~/^-[mqvVM]*R[mqvVM]*$/) \
+              && FileTest.file?(f.place_file.hash_digest.dir)
+                inp << f.place_file.hash_digest.rel
+              end
+              if (@opt.act[:share_source][:set]==:on \
+              || @opt.cmd =~/^-[mqvVM]*R[mqvVM]*$/) \
+              && FileTest.file?(f.place_file.src.dir)
+                inp << f.place_file.src.rel
+              end
+              if (@opt.act[:sisupod][:set]==:on \
+              || @opt.cmd =~/^-[mqvVM]*R[mqvVM]*$/) \
+              && FileTest.file?(f.place_file.sisupod.dir)
+                inp << f.place_file.sisupod.rel
+              end
+              if (@opt.act[:pdf][:set]==:on \
+              || @opt.cmd =~/^-[mqvVM]*R[mqvVM]*$/)
+                inp <<=(@opt.dir_structure_by == :filename) \
+                ? (f.output_path.pdf.rel + '/*.pdf')
+                : (f.output_path.pdf.rel + '/' + @opt.fnb + '*.pdf')
+              end
+              if (@opt.act[:sqlite_discrete][:set]==:on \
+              || @opt.cmd =~/^-[mqvVM]*R[mqvVM]*$/) \
+              && FileTest.file?(f.place_file.sqlite_discrete.dir)
+                inp << f.place_file.sqlite_discrete.rel
+              end
+              if (@opt.act[:qrcode][:set]==:on \
+              || @opt.cmd =~/^-[mqvVM]*R[mqvVM]*$/) \
+              && FileTest.file?(f.place_file.qrcode_md.dir)
+                inp \
+                  << f.place_file.qrcode_md.rel \
+                  << f.place_file.qrcode_title.rel
+              end
+              if (@opt.act[:manifest][:set]==:on \
+              || @opt.cmd =~/^-[mqvVM]*R[mqvVM]*$/) \
+              && FileTest.file?(f.place_file.manifest.dir)
+                inp << f.place_file.manifest.rel
+              end
+              local_gen=if inp.length > 0
+                inp.join(' ')
+              else ''
+              end
+              local_css,images,images_system='','',''
+              images=images_skin=images_system=local_css=''
+              if @opt.cmd =~/[hwbxX]/ \
+              && (defined? @md.ec[:image]) \
+              && (@md.ec[:image].length > 0)
+                images=
+                  f.place_file.images.rel + '/' \
+                    + @md.ec[:image].join(" #{f.output_path.images.rel}/")
+              end
+              if @opt.cmd =~/[yhwbxX]/ \
+              && (defined? @md.ec[:image]) \
+              && (@md.ec[:image].length > 0)
+                local_css=f.output_path.css.rel
+                images_system='_sisu/image_sys'
+              end
+              begin
+                ##create file structure without copying files?:
+                ##rsync -av -f"+ */" -f"- *" f.output_path.base.dir remote:./path/.
+                #local_dirs=%{-f"+ */" -f"- *" #{f.output_path.base.dir}/*}
+                #SiSU_Env::SystemCall.new(local_dirs,remote_gen,@opt.cmd).rsync
+                local=local_gen + ' ' + images + ' ' + images_skin + ' ' + images_system + ' ' + local_css
+                SiSU_Env::SystemCall.new(local,remote_rel,@opt.cmd).
+                  rsync('--relative',f.output_path.base.dir)
+              rescue
+                p __LINE__.to_s + ':' + __FILE__
+                local_dirs=%{--include='*/' --exclude='*' #{f.output_path.base.dir}}
+                SiSU_Env::SystemCall.new(local_dirs,remote_gen,@opt.cmd).rsync
+              end
+            elsif @opt.cmd =~/U/
+              puts "#{__FILE__} #{__LINE__}" if @opt.cmd =~/M/
+              puts "#{local_gen} -> #{remote_gen}"
+              if FileTest.file?("#{local_src}/#{src_doc}") \
+              or FileTest.file?("#{local_src}/#{src_doc}.txz")
+                puts "#{local_src}/#{src_doc}* -> #{remote_src}"
+              end
+            else
+              puts 'suspect rsync request, ignored'
+              puts "#{local_gen} -> #{remote_gen} remote flag: #{@@flag_remote}"
+              puts "permission not granted #{__FILE__} #{__LINE__}" \
+                if @opt.cmd =~/M/
+            end
+          end
+        end
+      end
+      def site_harvest
+        self.remote_host_base.each do |remote_conn|
+          local=@source_path_harvest
+          l_rel="#{@env.path.webserv}/#{@env.path.base_markup_dir_stub}"
+          lng='en'
+          if @env.output_dir_structure.by? == :language
+            ldest=lng + '/manifest'
+            files=
+              ldest + '/authors.html' + ' ' \
+                + ldest + '/topics.html'
+          elsif @env.output_dir_structure.by? == :filetype
+            ldest="manifest"
+            files=
+              ldest + '/authors.' + lng + '.html' + ' ' \
+                + ldest + '/topics.' + lng + '.html'
+          elsif @env.output_dir_structure.by? == :filename
+            files=
+              l_rel + '/authors.' + lng + '.html' + ' ' \
+                + l_rel + '/topics.' + lng + '.html'
+          end
+          remote="#{remote_conn[:name]}/#{@opt.base_stub}"
+          if @opt.act[:harvest][:set] \
+          && @opt.act[:rsync][:set]
+            (@env.output_dir_structure.by? == :filename) \
+            ? (SiSU_Env::SystemCall.new(files,remote).rsync)
+            : (SiSU_Env::SystemCall.new(ldest,remote).
+                rsync('--relative',l_rel))
+          elsif @opt.cmd =~/U/
+            puts "#{__FILE__} #{__LINE__}" if @opt.cmd =~/M/
+            puts "rsync_harvest: #{local} -> #{remote}"
+          else
+            puts "permission not granted #{__FILE__} #{__LINE__}" \
+              if @opt.cmd =~/M/
+          end
+        end
+      end
+      def site_base                    #base site
+        ldest='_sisu/*'
+        l_rel="#{@env.path.webserv}/#{@env.path.base_markup_dir_stub}"
+        image_sys="#{@env.path.webserv}/_sisu/image_sys"
+        self.remote_host_base.each do |remote_conn|
+          remote="#{remote_conn[:name]}/#{@env.path.base_markup_dir_stub}"
+          remote_conf="#{remote_conn[:name]}/_sisu"
+            SiSU_Env::SystemCall.new(image_sys,remote_conf).rsync
+            SiSU_Env::SystemCall.new(ldest,remote).rsync('--relative',l_rel)
+        end
+      end
+      def site_base_sync
+        self.remote_host_base.each do |remote_conn|
+          local=@source_path
+          remote="#{remote_conn[:name]}/#{@env.path.base_markup_dir_stub}/."
+          if defined? @rc['permission_set']['remote_base_site'] \
+          and @rc['permission_set']['remote_base_site'] \
+          and @@flag_remote==true \
+          and @opt.cmd !~/U/
+            delete_extra_files='--delete' # '--delete-after'
+            puts "begin rsync_base_sync: #{local} -> #{remote}"
+            SiSU_Env::SystemCall.new("#{local}/_sisu/image_sys/",remote).
+              rsync(delete_extra_files)
+            SiSU_Env::SystemCall.new("#{local}/_sisu/image/",remote).
+              rsync(delete_extra_files)
+            SiSU_Env::SystemCall.new("#{local}/#{@env.path.style}/",remote).
+              rsync(delete_extra_files)
+          elsif @opt.cmd =~/U/
+            puts "#{__FILE__} #{__LINE__}" if @opt.cmd =~/M/
+            puts "rsync_base_sync: #{local} -> #{remote}"
+            puts "#{local}/_sisu/image_sys/ -> #{remote}"
+            puts "#{local}/_sisu/image/ -> #{remote}"
+            puts "#{local}/#{@env.path.style}/ -> #{remote}"
+          else
+            puts "permission not granted #{__FILE__} #{__LINE__}" \
+              if @opt.cmd =~/M/
+          end
+        end
+      end
+      self
+    end
+    def rsync_sitemaps                 #sitemap directory
+      self.remote_host_base.each do |remote_conn|
+        local=
+          @source_path + '/sitemapindex.xml'
+        remote="#{remote_conn[:name]}/#{@env.path.base_markup_dir_stub}/."
+        if @@flag_remote
+          delete_extra_files='--delete' # '--delete-after'
+          SiSU_Env::SystemCall.new(local,remote).rsync(delete_extra_files)
+        elsif @opt.cmd =~/U/
+          puts "#{__FILE__} #{__LINE__}" if @opt.cmd =~/M/
+          puts "rsync_sitemaps: #{local} -> #{remote}"
+        else
+          puts "permission not granted #{__FILE__} #{__LINE__}" \
+            if @opt.cmd =~/M/
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** se_standardise_lang.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se_standardise_lang.rb"
+# <<sisu_document_header>>
+@@lang_info=nil
+module SiSU_Standardise_Lang
+  class StandardiseLanguage
+    require_relative 'i18n'                  # i18n.rb
+    def initialize(l='')
+      @language=(l.nil? || l.empty?) \
+      ? SiSU_Env::InfoEnv.new.language_default_set
+      : l
+      @r=%{(?:#{Px[:lng_lst_rgx]})}
+      @lang_info=SiSU_i18n::Languages.new
+    end
+    def lang_lst                       # from i18n
+      @@lang_info ||=@lang_info.language.list
+    end
+    def lang(l='')                     # from i18n
+      if l =~/^#{@r}$/
+        @lang_info.language.list[l]
+      elsif @language =~/^#{@r}$/
+        @lang_info.language.list[@language]
+      else nil
+      end
+    end
+    def language
+      lng={}
+      case @language
+      when /^am$|Amharic/i                    then d,c,l=false,lang_lst['am'][:c],    lang_lst['am'][:n]
+      when /^bg$|Bulgarian/i                  then d,c,l=false,lang_lst['bg'][:c],    lang_lst['bg'][:n]
+      when /^bn$|Bengali/i                    then d,c,l=false,lang_lst['bn'][:c],    lang_lst['bn'][:n]
+      when /^br$|Breton/i                     then d,c,l=false,lang_lst['br'][:c],    lang_lst['br'][:n]
+      when /^ca$|Catalan/i                    then d,c,l=false,lang_lst['ca'][:c],    lang_lst['ca'][:n]
+      when /^cs$|Czech/i                      then d,c,l=false,lang_lst['cs'][:c],    lang_lst['cs'][:n]
+      when /^cy$|Welsh/i                      then d,c,l=false,lang_lst['cy'][:c],    lang_lst['cy'][:n]
+      when /^da$|Danish|Dansk/i               then d,c,l=false,lang_lst['da'][:c],    lang_lst['da'][:n]
+      when /^de$|German/i                     then d,c,l=false,lang_lst['de'][:c],    lang_lst['de'][:n]
+      when /^el$|Greek/i                      then d,c,l=false,lang_lst['el'][:c],    lang_lst['el'][:n]
+      when /^en$|English/i                    then d,c,l=false,lang_lst['en'][:c],    lang_lst['en'][:n]
+      when /^eo$|Esperanto/i                  then d,c,l=false,lang_lst['eo'][:c],    lang_lst['eo'][:n]
+      when /^es$|Spanish|Espanol/i            then d,c,l=false,lang_lst['es'][:c],    lang_lst['es'][:n]
+      when /^et$|Estonian/i                   then d,c,l=false,lang_lst['et'][:c],    lang_lst['et'][:n]
+      when /^eu$|Basque/i                     then d,c,l=false,lang_lst['eu'][:c],    lang_lst['eu'][:n]
+      when /^fi$|Finnish|Finsk|Suomi/i        then d,c,l=false,lang_lst['fi'][:c],    lang_lst['fi'][:n]
+      when /^fr$|French|Francais/i            then d,c,l=false,lang_lst['fr'][:c],    lang_lst['fr'][:n]
+      when /^ga$|Irish/i                      then d,c,l=false,lang_lst['ga'][:c],    lang_lst['ga'][:n]
+      when /^gl$|Galician/i                   then d,c,l=false,lang_lst['gl'][:c],    lang_lst['gl'][:n]
+      when /^he$|Hebrew/i                     then d,c,l=false,lang_lst['he'][:c],    lang_lst['he'][:n]
+      when /^hi$|Hindi/i                      then d,c,l=false,lang_lst['hi'][:c],    lang_lst['hi'][:n]
+      when /^hr$|Croatian/i                   then d,c,l=false,lang_lst['hr'][:c],    lang_lst['hr'][:n]
+      when /^hy$|Armenian/i                   then d,c,l=false,lang_lst['hy'][:c],    lang_lst['hy'][:n]
+      when /^ia$|Interlingua/i                then d,c,l=false,lang_lst['ia'][:c],    lang_lst['ia'][:n]
+      when /^is$|Icelandic/i                  then d,c,l=false,lang_lst['is'][:c],    lang_lst['is'][:n]
+      when /^it$|Italian/i                    then d,c,l=false,lang_lst['it'][:c],    lang_lst['it'][:n]
+      when /^la$|Latin/i                      then d,c,l=false,lang_lst['la'][:c],    lang_lst['la'][:n]
+      when /^lo$|Lao/i                        then d,c,l=false,lang_lst['lo'][:c],    lang_lst['lo'][:n]
+      when /^lt$|Lithuanian/i                 then d,c,l=false,lang_lst['lt'][:c],    lang_lst['lt'][:n]
+      when /^lv$|Latvian/i                    then d,c,l=false,lang_lst['lv'][:c],    lang_lst['lv'][:n]
+      when /^ml$|Malayalam/i                  then d,c,l=false,lang_lst['ml'][:c],    lang_lst['ml'][:n]
+      when /^mr$|Marathi/i                    then d,c,l=false,lang_lst['mr'][:c],    lang_lst['mr'][:n]
+      when /^nl$|Dutch/i                      then d,c,l=false,lang_lst['nl'][:c],    lang_lst['nl'][:n]
+      when /^no$|Norwegian|Norsk/i            then d,c,l=false,lang_lst['no'][:c],    lang_lst['no'][:n]
+      when /^nn$|Norwegian Nynorsk/i          then d,c,l=false,lang_lst['nn'][:c],    lang_lst['nn'][:n]
+      when /^oc$|Occitan/i                    then d,c,l=false,lang_lst['oc'][:c],    lang_lst['oc'][:n]
+      when /^pl$|Polish/i                     then d,c,l=false,lang_lst['pl'][:c],    lang_lst['pl'][:n]
+      when /^pt$|Portuguese/i                 then d,c,l=false,lang_lst['pt'][:c],    lang_lst['pt'][:n]
+      when /^pt_BR$|Portuguese Brazil/i       then d,c,l=false,lang_lst['pt_BR'][:c], lang_lst['pt_BR'][:n]
+      when /^ro$|Romanian/i                   then d,c,l=false,lang_lst['ro'][:c],    lang_lst['ro'][:n]
+      when /^ru$|Russian/i                    then d,c,l=false,lang_lst['ru'][:c],    lang_lst['ru'][:n]
+      when /^sa$|Sanskrit/i                   then d,c,l=false,lang_lst['sa'][:c],    lang_lst['sa'][:n]
+      when /^se$|Sami/i                       then d,c,l=false,lang_lst['se'][:c],    lang_lst['se'][:n]
+      when /^sk$|Slovak/i                     then d,c,l=false,lang_lst['sk'][:c],    lang_lst['sk'][:n]
+      when /^sl$|Slovenian/i                  then d,c,l=false,lang_lst['sl'][:c],    lang_lst['sl'][:n]
+      when /^sq$|Albanian/i                   then d,c,l=false,lang_lst['sq'][:c],    lang_lst['sq'][:n]
+      when /^sr$|Serbian/i                    then d,c,l=false,lang_lst['sr'][:c],    lang_lst['sr'][:n]
+      when /^sv$|Swedish|Svensk/i             then d,c,l=false,lang_lst['sv'][:c],    lang_lst['sv'][:n]
+      when /^ta$|Tamil/i                      then d,c,l=false,lang_lst['ta'][:c],    lang_lst['ta'][:n]
+      when /^te$|Telugu/i                     then d,c,l=false,lang_lst['te'][:c],    lang_lst['te'][:n]
+      when /^th$|Thai/i                       then d,c,l=false,lang_lst['th'][:c],    lang_lst['th'][:n]
+      when /^tk$|Turkmen/i                    then d,c,l=false,lang_lst['tk'][:c],    lang_lst['tk'][:n]
+      when /^tr$|Turkish/i                    then d,c,l=false,lang_lst['tr'][:c],    lang_lst['tr'][:n]
+      when /^uk$|Ukranian/i                   then d,c,l=false,lang_lst['uk'][:c],    lang_lst['uk'][:n]
+      when /^ur$|Urdu/i                       then d,c,l=false,lang_lst['ur'][:c],    lang_lst['ur'][:n]
+      when /^us|American$|/i                  then d,c,l=false,lang_lst['en'][:c],    lang_lst['en'][:n]
+      when /^vi$|Vietnamese/i                 then d,c,l=false,lang_lst['vi'][:c],    lang_lst['vi'][:n]
+      else                                     d,c,l=true, lang_lst['en'][:c],    lang_lst['en'][:n] #default
+      end
+      lng[:d],lng[:c],lng[:n]=d,c,l
+      lng
+    end
+    def name
+      language[:n].downcase
+    end
+    def title
+      language[:n]
+    end
+    def code
+      language[:c]
+    end
+    def tex_name
+      language[:xlp]
+    end
+    def file_to_language(file)         # used, fix and remove
+      m=/.+?\~(\w{2,3})\.(?:-|ssm\.)?sst$/
+      @language=if file =~m ; file[m,1]
+      else ''
+      end
+      language
+    end
+    def codes
+      # Language List po4a
+      #   <http://www.debian.org/international/l10n/po/>
+      #   Px[:lng_lst] see constants.rb
+      # see polyglossia for subset
+      #   <http://mirrors.ctan.org/macros/xetex/latex/polyglossia/polyglossia.pdf>
+      # also note ISO_639-2
+      #   <http://en.wikipedia.org/wiki/ISO_639-2>
+      #   <http://en.wikipedia.org/wiki/List_of_ISO_639-2_codes>
+      Px[:lng_lst] # constants.rb
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** se_version.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/se_version.rb"
+# <<sisu_document_header>>
+module SiSU_Info_Version
+  require_relative 'constants'                             # constants.rb
+  require_relative 'utils'                                 # utils.rb
+  require_relative 'se_info_env'                           # se_info_env.rb
+  begin
+    require 'singleton'
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('singleton NOT FOUND (LoadError)')
+  end
+  class InfoVersion < SiSU_Info_Env::InfoEnv               # se_info_env.rb
+    include Singleton
+    begin
+      require 'rbconfig'
+      require 'yaml'
+    rescue LoadError
+      SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+        error('rbconfig or yaml NOT FOUND (LoadError)')
+    end
+    @@lib_path=nil
+    def get_version
+      version={}
+      @pwd=ENV['PWD']
+      lib_path=
+        @@lib_path \
+        ? @@lib_path
+        : `echo $RUBYLIB`.split(':')
+      @@lib_path ||=lib_path
+      if File.exist?(SiSU_is.version_info_path?)
+        version=YAML::load(File::open(SiSU_is.version_info_path?))
+      end
+      version[:install_method]=if SiSU_is.runtime_type? ==:gem_install
+        spec = Gem::Specification.find_by_name("sisu")
+        gem_root = spec.gem_dir
+        (File.dirname(__FILE__.gsub(/\/lib\/sisu}/,'')) == gem_root) \
+        ? ' (ruby gem install)' : ''
+      else ''
+      end
+      @version=version
+      def version_details_hash
+        @version
+      end
+      def project
+        version_details_hash[:project]
+      end
+      def date
+        version_details_hash[:date]
+      end
+      def date_stamp
+        version_details_hash[:date_stamp]
+      end
+      def version
+        version_details_hash[:version]
+      end
+      def version_major
+        @version_major=version_details_hash[:version].gsub(/([0-9]+)\.[0-9]+\.[0-9]+/,'\1')
+      end
+      def install_method
+        version_details_hash[:install_method]
+      end
+      self
+    end
+    def rbversion
+      %x{ruby -v}.strip
+    end
+  end
+end
+module SiSU_Info_About
+  require_relative 'constants'                             # constants.rb
+  require_relative 'utils'                                 # utils.rb
+  begin
+    require 'singleton'
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('singleton NOT FOUND (LoadError)')
+  end
+  class InfoAbout
+    def initialize(color='')
+      @color=color
+    end
+    def sisu_version
+      version=SiSU_Env::InfoVersion.instance.get_version
+      rb_ver=SiSU_Env::InfoVersion.instance.rbversion
+      if version.version
+        opt_cmd=if defined? @color.cmd \
+        and @color.cmd =~/[ck]/
+          @color.cmd
+        else '-v'
+        end
+        SiSU_Screen::Ansi.new(
+          opt_cmd,
+          version.project,
+          version.version,
+          version.date_stamp,
+          version.date,
+          version.install_method,
+          rb_ver
+        ).version
+      else puts 'SiSU (version information not available)'
+      end
+    end
+    def sisu_about
+      puts <<-WOK
+     sisu: documents; markup, structuring, publishing in multiple standard formats, & search
+     most (not all) useful commands (are made in a directory containing a sisu markup file &) take the form:
+       sisu [action(s)] [filename(s)]
+     where filename refers to a valid sisu marked up file, e.g.:
+       cd /usr/share/doc/sisu/markup-samples/sisu_manual
+       sisu --html --verbose sisu_commands.sst
+       sisu --txt --html --epub --odt --pdf --sqlite --manpage --texinfo --concordance --qrcode --verbose sisu.ssm
+       cd -
+     See output produced, or see man pages: man sisu
+     <http://www.sisudoc.org/> <http://www.jus.uio.no/sisu/>
+        WOK
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    se
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/harvest.org b/org/harvest.org
new file mode 100644
index 00000000..ccc55123
--- /dev/null
+++ b/org/harvest.org
@@ -0,0 +1,1454 @@
+-*- mode: org -*-
+#+TITLE:       sisu harvest
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:harvest:
+#+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
+
+* harvest
+** html_harvest.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/html_harvest.rb"
+# <<sisu_document_header>>
+module SiSU_Harvest
+  @@the_idx_topics,@@the_idx_authors={},{}
+  class Source
+    require_relative 'hub_options'                          # hub_options.rb
+    require_relative 'html_harvest_topics'                  # html_harvest_topics.rb
+    require_relative 'html_harvest_authors'                 # html_harvest_authors.rb
+    require_relative 'se'                                   # se.rb
+      include SiSU_Env
+    def initialize(opt)
+      @opt=opt
+      @env=SiSU_Env::InfoEnv.new
+    end
+    def read
+      begin
+        harvest_pth=@env.path.webserv + '/' + @opt.base_stub
+        FileUtils::mkdir_p(harvest_pth) unless FileTest.directory?(harvest_pth)
+        cases(@opt,@env)
+      rescue
+      ensure
+        SiSU_Env::CreateSite.new(@opt).cp_css
+      end
+    end
+    def help
+      puts <<WOK
+      harvest --harvest   extracts document index metadata
+
+WOK
+    end
+    def css(opt)
+      require_relative 'css'                                # css.rb
+      css=SiSU_Style::CSS.new
+      fn_css=SiSU_Env::CSS_Default.new
+      style=File.new("#{@env.path.pwd}/#{fn_css.harvest}",'w')
+      style << css.harvest
+      style.close
+    end
+    def cases(opt,env)
+      case opt.selections.str.inspect
+      when/--harvest/i
+        css(opt) if @opt.act[:maintenance][:set]==:on
+        SiSU_HarvestAuthors::Songsheet.new(opt,env).songsheet
+        SiSU_HarvestTopics::Songsheet.new(opt,env).songsheet
+        if @opt.act[:rsync][:set]==:on
+          require_relative 'remote'                         # remote.rb
+          SiSU_Remote::Put.new(opt).rsync_harvest
+        end
+      else
+        help
+      end
+    end
+  end
+end
+#+END_SRC
+
+** topics
+*** html_harvest_topics.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/html_harvest_topics.rb"
+# <<sisu_document_header>>
+module SiSU_HarvestTopics
+  require_relative 'html_harvest_author_format'          # html_harvest_author_format.rb
+  require_relative 'html_parts'                          # html_parts.rb
+  class Songsheet
+    @@the_idx_topics={}
+    def initialize(opt,env)
+      @opt,@env=opt,env
+      @file_list=opt.files
+    end
+    def songsheet
+      idx_array={}
+      @opt.f_pths.each do |y|
+        lang_hash_file_array={}
+        name=y[:f]
+        filename=y[:pth] + '/' + y[:f]
+        File.open(filename,'r') do |file|
+          file.each_line("\n\n") do |line|
+            if line =~/^@(?:title|creator|classify):(?:\s|$)/m
+              lang_hash_file_array[y[:lng_is]] ||= []
+              lang_hash_file_array[y[:lng_is]] << line
+            elsif line =~/^@\S+?:(?:\s|$)/m \
+            or line =~/^(?:\s*\n|\s*$|%+ )/
+            else break
+            end
+          end
+        end
+        lang_hash_file_array.each_pair do |lang,a|
+          idx_array[lang] ||=[]
+          idx_array=SiSU_HarvestTopics::Harvest.new(
+            @opt,
+            @env,
+            a,
+            filename,
+            name,
+            idx_array,
+            lang
+          ).extract_harvest
+        end
+      end
+      the_hash=SiSU_HarvestTopics::Index.new(
+        @opt,
+        @env,
+        idx_array,
+        @@the_idx_topics
+      ).song
+      SiSU_HarvestTopics::OutputIndex.new(
+        @opt,
+        the_hash
+      ).html_print.html_songsheet
+    end
+  end
+  class Mix
+    def spaces
+      Ax[:spaces]
+    end
+  end
+  class Harvest
+    def initialize(opt,env,data,filename,name,idx_array,lang)
+      @opt, @env,@data,@filename,@name,@idx_array,@lang=
+        opt,env, data, filename, name, idx_array, lang
+    end
+    def extract_harvest
+      data,   filename, name, idx_array, lang=
+        @data,@filename,@name,@idx_array,@lang
+      @idx_lst=@title=@subtitle=@fulltitle=@author=@author_format=nil
+      rgx={}
+      rgx[:author]=/^@creator:(?:[ ]+|.+?:author:[ ]+)(.+?)(?:\||\n)/m
+      rgx[:title]=/^@title:[ ]+(.+)/
+      rgx[:subtitle]=/^@title:.+?:subtitle:[ ]+(.+?)\n/m
+      rgx[:idx]=/^@classify:.+?:topic_register:[ ]+(.+?)(?:\n\n|\n\s+:\S|\n%)/m
+      data.each do |para|
+        if para=~ rgx[:idx]
+          @idx_list=(rgx[:idx].match(para)[1]).split(/\s*\n\s*/).join
+        end
+        if para=~ rgx[:title]
+          @title=rgx[:title].match(para)[1]
+        end
+        if para=~ rgx[:subtitle]
+          @subtitle=rgx[:subtitle].match(para)[1]
+        end
+        if para=~ rgx[:author]
+          @author_format=rgx[:author].match(para)[1]
+        end
+        break if @title && @subtitle && @author && @idx_lst
+      end
+      @fulltitle=@subtitle ? (@title + ' - ' + @subtitle) : @title
+      if @title \
+      and @author_format \
+      and @idx_list
+        creator=SiSU_FormatAuthor::Author.new(@author_format.strip).author_details
+        @authors,@authorship=creator[:authors],creator[:authorship]
+        file=if name=~/~[a-z]{2,3}\.ss[mt]$/
+          name.sub(/~[a-z]{2,3}\.ss[mt]$/,'')
+        else
+          name.sub(/\.ss[mt]$/,'')
+        end
+        page=if @env.output_dir_structure.by? == :language
+          "#{lang}/sisu_manifest.html"
+        else
+          "sisu_manifest.#{lang}.html"
+        end
+        idx_array[lang] <<=if @idx_list =~/;/
+          g=@idx_list.scan(/[^;]+/)
+          g.each.map do |i|
+            i=i.strip
+            {
+              filename: filename,
+              file: file,
+              rough_idx: i,
+              title: @fulltitle,
+              author: creator,
+              page: page,
+              lang: lang
+            }
+          end
+        else {
+            filename: filename,
+            file: file,
+            rough_idx: @idx_list,
+            title: @fulltitle,
+            author: creator,
+            page: page,
+            lang: lang,
+          }
+        end
+      else
+        if (@opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on)
+          p "missing required field in #{@filename} - [title]: <#{@title}>; [author]: <#{@author_format}>; [idx]: <#{@idx_list}>"
+        end
+      end
+      idx_array[lang]=idx_array[lang].flatten
+      idx_array
+    end
+  end
+  class Index < Mix
+    def initialize(opt,env,idx_array,the_idx)
+      @opt, @env,@idx_array,@the_idx=
+        opt,env, idx_array, the_idx
+      @@the_idx_topics=@the_idx
+    end
+    def song
+      the_idx=construct_book_topic_keys
+      construct_book_topic_hash(the_idx)
+    end
+    def capital(txt)
+      txt_a=txt.scan(/\S+/)
+      tx=''
+      txt_a.each do |t|
+        tx += t[0].chr.capitalize + t[1,txt.length] + ' '
+      end
+      tx.strip
+    end
+    def capital_(txt)
+      txt[0].chr.capitalize + txt[1,txt.length]
+    end
+    def contents(idx,lang)
+      names=''
+      idx[:author][:last_first_format_a].each do |n|
+        s=n.sub(/(.+?)(?:,.+|$)/,'\1').gsub(/\s+/,'_')
+        names=if @env.output_dir_structure.by? == :language
+          names += %{<a href="authors.html##{s}">#{n}</a>, }
+        else
+          names += %{<a href="authors.#{lang}.html##{s}">#{n}</a>, }
+        end
+      end
+      {
+        filename: idx[:filename],
+        file: idx[:file],
+        author: names,
+        title: idx[:title],
+        page: idx[:page]
+      }
+    end
+    def capital_(txt)
+      txt[0].chr.capitalize + txt[1,txt.length]
+    end
+    def key_create(c,alt)
+      x=nil
+      x=if c.length==6
+        c[0].to_s + '|' +
+          capital(c[1][0].to_s) + '|' +
+          capital(c[2][0].to_s) + '|' +
+          capital(c[3][0].to_s) + '|' +
+          capital(alt.to_s)
+      elsif c.length==5
+        c[0].to_s + '|' +
+          capital(c[1][0].to_s) + '|' +
+          capital(c[2][0].to_s) + '|' +
+          capital(alt.to_s)
+      elsif c.length==4
+        c[0].to_s + '|' +
+          capital(c[1][0].to_s) + '|' +
+          capital(alt.to_s)
+      elsif c.length==3
+        c[0].to_s + '|' +
+          capital(alt.to_s)
+      end
+    end
+    def construct_book_topic_keys
+      idx_array=@idx_array
+      @idx_a=[]
+      @the_a=[]
+      idx_array.each_pair do |lang,idx_arr|
+        @@the_idx_topics[lang] ||= {}
+        idx_arr.each do |idx|
+          if idx[:rough_idx]
+            idx_lst=idx[:rough_idx].scan(/[^:]+/)
+          else
+            puts "no topic register in: << #{idx[:filename]} >>"
+            next
+          end
+          idx_a=[]
+          idx_lst.each do |c|
+            idx_a << c.scan(/[^|\n]+/m)
+          end
+          idx_a << contents(idx,lang)
+          @idx_a << [lang] + idx_a
+        end
+      end
+      @idx_a.each do |c|
+        if c.length > 1 \
+        and c.is_a?(Array)
+          if c[2].is_a?(Hash)
+            c[1].each do |alt|
+              v=key_create(c,alt)
+              @the_a << [v, c[2]] if v
+            end
+          end
+        end
+        if c.length > 2 \
+        and c.is_a?(Array)
+          if c[3].is_a?(Hash)
+            c[2].each do |alt|
+              v=key_create(c,alt)
+              @the_a << [v, c[3]] if v
+            end
+          end
+        end
+        if c.length > 3 \
+        and c.is_a?(Array)
+          if c[4].is_a?(Hash)
+            c[3].each do |alt|
+              v=key_create(c,alt)
+              @the_a << [v, c[4]] if v
+            end
+          end
+        end
+        if c.length > 4 \
+        and c.is_a?(Array)
+          if c[5].is_a?(Hash)
+            c[4].each do |alt|
+              v=key_create(c,alt)
+              @the_a << [v, c[5]] if v
+            end
+          end
+        end
+        if c.length > 5 \
+        and c.is_a?(Array)
+          if c[6].is_a?(Hash)
+            c[5].each do |alt|
+              v=key_create(c,alt)
+              @the_a << [v, c[6]] if v
+            end
+          end
+        end
+      end
+      @the_a.sort_by { |x| x[0] } #; y.each {|z| puts z}
+    end
+    def construct_book_topic_hash(t)
+      @the_h={}
+      t.each do |z|
+        x=z[0].scan(/[^|]+/)
+        depth=x.length
+        extract=(depth-1)
+        k=case extract
+        when 4
+          { x[0] => { x[1] => { x[2] => { x[3] => { x[4] => z[1] } } } } }
+        when 3
+          { x[0] => { x[1] => { x[2] => { x[3] => z[1] } } } }
+        when 2
+          { x[0] => { x[1] => { x[2] => z[1] } } }
+        when 1
+          { x[0] => { x[1] => z[1] } }
+        when 0
+          { x[0] => z[1] }
+        end
+        if extract >= 0
+          k.each_pair do |x0,y0|
+            if extract == 0
+              @the_h[x0] ||={ md: [] }
+              @the_h[x0][:md] << y0
+            else
+              @the_h[x0] ||={}
+            end
+            #puts spaces*0 + x0
+            if extract >= 1
+              y0.each_pair do |x1,y1|
+                if extract == 1
+                  @the_h[x0][x1] ||={ md: [] }
+                  @the_h[x0][x1][:md] << y1
+                else
+                  @the_h[x0][x1] ||={}
+                end
+                #puts spaces*1 + x1
+                if extract >= 2
+                  y1.each_pair do |x2,y2|
+                    if extract == 2
+                      @the_h[x0][x1][x2] ||={ md: [] }
+                      @the_h[x0][x1][x2][:md] << y2
+                    else
+                      @the_h[x0][x1][x2] ||={}
+                    end
+                    #puts spaces*2 + x2
+                    if extract >= 3
+                      y2.each_pair do |x3,y3|
+                        if extract == 3
+                          @the_h[x0][x1][x2][x3] ||={ md: [] }
+                          @the_h[x0][x1][x2][x3][:md] << y3
+                        else
+                          @the_h[x0][x1][x2][x3] ||={}
+                        end
+                        #puts spaces*3 + x3
+                        if extract == 4
+                          y3.each_pair do |x4,y4|
+                            if extract == 4
+                              @the_h[x0][x1][x2][x3][x4] ||={ md: [] }
+                              @the_h[x0][x1][x2][x3][x4][:md] << y4
+                            else
+                              @the_h[x0][x1][x2][x3][x4] ||={}
+                            end
+                            #puts spaces*4 + x4
+                            if extract == 5
+                              y4.each_pair do |x5,y5|
+                                if extract == 5
+                                  @the_h[x0][x1][x2][x3][x4][x5] ||={ md: [] }
+                                  @the_h[x0][x1][x2][x3][x4][x5][:md] << y5
+                                end
+                                #puts spaces*5 + x5
+                              end
+                            end
+                          end
+                        end
+                      end
+                    end
+                  end
+                end
+              end
+            end
+          end
+        end
+      end
+      #@the_h.each_pair { |x,y| p x; p y }
+      @the_h
+    end
+    def traverse_base
+      @the_h.each_pair do |x0,y0|
+        puts spaces*0 + x0 if x0.is_a?(String)
+        if y0.is_a?(Hash)
+          y0.each_pair do |x1,y1|
+            puts spaces*1 + x1 if x1.is_a?(String)
+            if y1.is_a?(Hash)
+              y1.each_pair do |x2,y2|
+                puts spaces*2 + x2 if x2.is_a?(String)
+                if y2.is_a?(Hash)
+                  y2.each_pair do |x3,y3|
+                    puts spaces*3 + x3 if x3.is_a?(String)
+                    if y3.is_a?(Hash)
+                      y3.each_pair do |x4,y4|
+                        puts spaces*4 + x4 if x4.is_a?(String)
+                        if y4.is_a?(Hash)
+                          y4.each_pair do |x5,y5|
+                            puts spaces*5 + x5 if x5.is_a?(String)
+                          end
+                        end
+                      end
+                    end
+                  end
+                end
+              end
+            end
+          end
+        end
+      end
+    end
+    def traverse
+      @the_h.each_pair do |x0,y0|
+        puts spaces*0 + x0 if x0.is_a?(String)
+        if y0.is_a?(Hash)
+          if y0.has_key?(:md)
+            y0[:md].each { |x| puts spaces*5 + x[:title] }
+          end
+          y0.each_pair do |x1,y1|
+            puts spaces*1 + x1 if x1.is_a?(String)
+            if y1.is_a?(Hash)
+              if y1.has_key?(:md)
+                y1[:md].each { |x| puts spaces*5 + x[:title] }
+              end
+              y1.each_pair do |x2,y2|
+                puts spaces*2 + x2 if x2.is_a?(String)
+                if y2.is_a?(Hash)
+                  if y2.has_key?(:md)
+                    y2[:md].each { |x| puts spaces*5 + x[:title] }
+                  end
+                  y2.each_pair do |x3,y3|
+                    puts spaces*3 + x3 if x3.is_a?(String)
+                    if y3.is_a?(Hash)
+                      if y3.has_key?(:md)
+                        y3[:md].each { |x| puts spaces*5 + x[:title] }
+                      end
+                      y3.each_pair do |x4,y4|
+                        puts spaces*4 + x4 if x4.is_a?(String)
+                        if y4.is_a?(Hash)
+                          if y4.has_key?(:md)
+                            y4[:md].each { |x| puts spaces*5 + x[:title] }
+                          end
+                          y4.each_pair do |x5,y5|
+                            puts spaces*5 + x4 if x4.is_a?(String)
+                          end
+                        end
+                      end
+                    end
+                  end
+                end
+              end
+            end
+          end
+        end
+      end
+    end
+  end
+  class OutputIndex < Mix
+    require_relative 'i18n'                               # i18n.rb
+    def initialize(opt,the_idx)
+      @opt,@the_idx=opt,the_idx
+      @env=SiSU_Env::InfoEnv.new
+      @rc=SiSU_Env::GetInit.new.sisu_yaml.rc
+      @alphabet_list=%W[9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z]
+      @alph=@alphabet_list.dup
+      @letter=@alph.shift
+    end
+    def html_file_open
+      @the_idx.keys.each do |lng|
+        @output ||={}
+        @output[lng] ||={}
+        harvest_pth,file='',''
+        if @env.output_dir_structure.by? == :language
+          harvest_pth=@env.path.webserv + '/' \
+          + @opt.base_stub + '/' \
+          + lng + '/' \
+          + 'manifest'
+          file=harvest_pth + '/' + 'topics.html'
+        elsif @env.output_dir_structure.by? == :filetype
+          harvest_pth=@env.path.webserv + '/' \
+          + @opt.base_stub + '/' \
+          + 'manifest'
+          file=harvest_pth + '/' + 'topics.' + lng + '.html'
+        elsif @env.output_dir_structure.by? == :filename
+          harvest_pth=@env.path.webserv + '/' \
+          + @opt.base_stub
+          file=harvest_pth + '/' + 'topics.' + lng + '.html'
+        end
+        FileUtils::mkdir_p(harvest_pth) \
+          unless FileTest.directory?(harvest_pth)
+        fileinfo=(@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:urls_selected][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on) \
+        ? ("file://#{file}")
+        : ''
+        SiSU_Screen::Ansi.new(
+          @opt.act[:color_state][:set],
+          "harvest topics(#{@opt.files.length} files)",
+          fileinfo
+        ).dark_grey_title_hi unless @opt.act[:quiet][:set]==:on
+        @output[lng][:html]=File.new(file,'w')
+        if @opt.act[:maintenance][:set]==:on
+          @output[lng][:html_mnt]=File.new("#{@env.path.pwd}/topics.html",'w')
+        end
+      end
+    end
+    def html_file_close
+      @the_idx.keys.each do |lng|
+        @output[lng][:html].close
+        @output[lng][:html_mnt].close if @output[lng][:html_mnt].is_a?(File)
+      end
+    end
+    def html_print
+      def html_songsheet
+        #traverse
+        html_file_open
+        html_head
+        html_alph
+        html_body_traverse
+        html_tail
+        html_file_close
+      end
+      def html_body_traverse
+        @the_idx.each_pair do |x0,y0|
+          lng=x0
+          if x0.is_a?(String)
+            #do_string_name(lng,'lev0',x0)
+            #puts spaces*0 + x0
+          end
+          if y0.is_a?(Hash)
+            if y0.has_key?(:md)
+              y0[:md].each do |x|
+                #do_hash(lng,attrib,x) #lv==0 ?
+                #puts spaces*5 + x[:title]
+              end
+            end
+            y0.each_pair do |x1,y1|
+              if x1.is_a?(String)
+                do_string_name(lng,'lev0',x1)
+                #puts spaces*1 + x1
+              end
+              if y1.is_a?(Hash)
+                if y1.has_key?(:md)
+                  y1[:md].each do |x|
+                    do_hash(lng,0,x)
+                    #puts spaces*5 + x[:title]
+                  end
+                end
+                y1.each_pair do |x2,y2|
+                  if x2.is_a?(String)
+                    do_string(lng,'lev1',x2)
+                    #puts spaces*2 + x2
+                  end
+                  if y2.is_a?(Hash)
+                    if y2.has_key?(:md)
+                      y2[:md].each do |x|
+                        do_hash(lng,1,x)
+                        #puts spaces*5 + x[:title]
+                      end
+                    end
+                    y2.each_pair do |x3,y3|
+                      if x3.is_a?(String)
+                        do_string(lng,'lev2',x3)
+                        #puts spaces*3 + x3
+                      end
+                      if y3.is_a?(Hash)
+                        if y3.has_key?(:md)
+                          y3[:md].each do |x|
+                            do_hash(lng,2,x)
+                            #puts spaces*5 + x[:title]
+                          end
+                        end
+                        y3.each_pair do |x4,y4|
+                          if x4.is_a?(String)
+                            do_string(lng,'lev3',x4)
+                            #puts spaces*4 + x4
+                          end
+                          if y4.is_a?(Hash)
+                            if y4.has_key?(:md)
+                              y4[:md].each do |x|
+                                do_hash(lng,3,x)
+                                #puts spaces*5 + x[:title]
+                              end
+                            end
+                            y4.each_pair do |x5,y5|
+                              if x5.is_a?(String)
+                                do_string(lng,'lev4',x5)
+                                #puts spaces*5 + x5
+                              end
+                            end
+                          end
+                        end
+                      end
+                    end
+                  end
+                end
+              end
+            end
+          end
+        end
+      end
+      def html_head_adjust(lng,type='')
+        css_path,authors='',''
+        if @env.output_dir_structure.by? == :language
+          css_path=(type !~/maintenance/) \
+          ? '../../_sisu/css/harvest.css'
+          : 'harvest.css'
+          authors='authors.html'
+        elsif @env.output_dir_structure.by? == :filetype
+          css_path=(type !~/maintenance/) \
+          ? '../_sisu/css/harvest.css'
+          : 'harvest.css'
+          authors="authors.#{lng}.html"
+        elsif @env.output_dir_structure.by? == :filename
+          css_path=(type !~/maintenance/) \
+          ? './_sisu/css/harvest.css'
+          : 'harvest.css'
+          authors="authors.#{lng}.html"
+        end
+        ln=SiSU_i18n::Languages.new.language.list
+        harvest_languages=''
+        @the_idx.keys.each do |lg|
+          if @env.output_dir_structure.by? == :language
+            harvest_pth="../../#{lg}/manifest"
+            file=harvest_pth + '/' + 'topics.html'
+          elsif @env.output_dir_structure.by? == :filetype
+            harvest_pth='.'
+            file=harvest_pth + '/' + 'topics.' + lg + '.html'
+          elsif @env.output_dir_structure.by? == :filename
+            harvest_pth='.'
+            file=harvest_pth + '/topics.' + lg + '.html'
+          end
+          l=ln[lg][:t]
+          harvest_languages +=
+            %{<a href="#{file}">#{l}</a>&nbsp;&nbsp;&nbsp;}
+        end
+        sv=SiSU_Env::InfoVersion.instance.get_version
+        if @env.output_dir_structure.by? == :language
+          home_pth='../..'
+          output_structure_by='(output organised by language &amp; filetype)'
+        elsif @env.output_dir_structure.by? == :filetype
+          home_pth='..'
+          output_structure_by='(output organised by filetype)'
+        elsif @env.output_dir_structure.by? == :filename
+          home_pth='.'
+          output_structure_by='(output organised by filename)'
+        else
+          home_pth='.'
+          output_structure_by='(output organised by ?)'
+        end
+        <<WOK
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>SiSU Metadata Harvest - Topics</title>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+<meta name="dc.title" content= "SiSU metadata harvest, Topics - SiSU 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="#{sv.project} #{sv.version} of #{sv.date_stamp} (n*x and Ruby!)" />
+<link rel="generator" href="http://www.jus.uio.no/sisu/SiSU" />
+<link href="#{css_path}" rel="stylesheet">
+<link rel="shortcut icon" href="../_sisu/image/rb7.ico" />
+</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>SiSU Metadata Harvest - Topics #{output_structure_by}</h1>
+<p>[<a href="#{home_pth}/index.html">&nbsp;HOME&nbsp;</a>] also see <a href="#{authors}">SiSU Metadata Harvest - Authors</a></p>
+<p>#{@env.widget_static.search_form}</p>
+<hr />
+<p class="tiny">#{harvest_languages}</p>
+<hr />
+WOK
+      end
+      def html_head
+        @the_idx.keys.each do |lng|
+          @output[lng][:html_mnt] \
+          << html_head_adjust(lng,'maintenance') \
+            if @opt.act[:maintenance][:set]==:on
+          @output[lng][:html] << html_head_adjust(lng)
+        end
+      end
+      def html_alph
+        a=[]
+        a << '<p>'
+        @alph.each do |x|
+          a << ((x =~/[0-9]/) \
+          ? ''
+          : %{<a href="##{x}">#{x}</a>,&nbsp;})
+        end
+        a=a.join
+        @the_idx.keys.each do |lng|
+          @output[lng][:html_mnt] << a \
+            if @opt.act[:maintenance][:set]==:on
+          @output[lng][:html] << a
+        end
+      end
+      def html_tail
+        a =<<WOK
+<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>
+#{SiSU_Proj_HTML::Bits.new.credits_sisu}
+</body>
+</html>
+WOK
+        @the_idx.keys.each do |lng|
+          @output[lng][:html_mnt] << a \
+            if @output[lng][:html_mnt].is_a?(File)
+          @output[lng][:html] << a
+        end
+      end
+      def do_html(lng,html)
+        @output[lng][:html] << html
+      end
+      def do_html_maintenance(lng,html)
+        @output[lng][:html_mnt] << html \
+          if @output[lng][:html_mnt].is_a?(File)
+      end
+      def do_string(lng,attrib,string)
+        html=%{<p class="#{attrib}">#{string}</p>}
+        do_html(lng,html)
+        do_html_maintenance(lng,html) \
+          if @output[lng][:html_mnt].is_a?(File)
+      end
+      def do_string_default(lng,attrib,string)
+        html=%{<p class="#{attrib}">#{string}</p>}
+        do_html(lng,html)
+      end
+      def do_string_maintenance(lng,attrib,string)
+        html=%{<p class="#{attrib}">#{string}</p>}
+        do_html_maintenance(lng,html) \
+          if @output[lng][:html_mnt].is_a?(File)
+      end
+      def do_string_name(lng,attrib,string)
+        f=/^(\S)/.match(string)[1]
+        if @lng != lng
+          @alph=@alphabet_list.dup
+          @letter=@alph.shift
+          @lng = lng
+        end
+        if @letter < f
+          while @letter < f
+            if @alph.length > 0
+              @letter=@alph.shift
+              if @output[lng][:html_mnt].is_a?(File)
+                @output[lng][:html_mnt] \
+                << %{\n<p class="letter"><a name="#{@letter}">#{@letter}</a></p><p class="book_index_lev1"><a name="#{@letter.downcase}"></a></p>}
+              end
+              @output[lng][:html] \
+              << %{\n<p class="letter"><a name="#{@letter}">#{@letter}</a></p><p class="book_index_lev1"><a name="#{@letter.downcase}"></a></p>}
+            else break
+            end
+          end
+        end
+        name=string.strip.gsub(/\s+/,'_')
+        html=%{<p class="#{attrib}"><a name="#{name}">#{string}</a></p>}
+        do_html(lng,html)
+        do_html_maintenance(lng,html) \
+          if @output[lng][:html_mnt].is_a?(File)
+      end
+      def do_array(lng,lv,array)
+        lv+=1
+        array.each do |b|
+          do_case(lng,lv,b)
+        end
+      end
+      def do_hash_md(lng,attrib,hash)
+        lang_code_insert=SiSU_Env::FilenameLanguageCodeInsert.new(@opt,lng).language_code_insert
+        manifest_at=if @env.output_dir_structure.by? == :language
+          hash[:file] + Sfx[:html]
+        elsif @env.output_dir_structure.by? == :filetype
+          hash[:file] + lang_code_insert +  Sfx[:html]
+        elsif @env.output_dir_structure.by? == :filename
+          "./#{hash[:file]}/#{hash[:page]}"
+        else '' #error
+        end
+        html=%{<a href="#{manifest_at}">#{hash[:title]}</a> - #{hash[:author]}}
+        do_string_default(lng,attrib,html)
+      end
+      def do_hash_md_maintenance(lng,attrib,hash)
+        if @output[lng][:html_mnt].is_a?(File) #should not be run for presentation output
+          html=%{[<a href="#{hash[:file]}.sst">src</a>]&nbsp;&nbsp;<a href="file://#{@env.path.output}/#{hash[:file]}/#{hash[:page]}">#{hash[:title]}</a> - #{hash[:author]}}
+          do_string_maintenance(lng,attrib,html)
+        end
+      end
+      def do_hash(lng,lv,hash)
+        lv+=1
+        key=[]
+        hash.each_key do |m|
+          if m == :md
+            do_case(lng,lv,hash[m])
+          elsif m != :title \
+          and m != :author \
+          and m != :filename \
+          and m != :file \
+          and m != :rough_idx \
+          and m != :page
+            key << m
+          elsif m == :title
+            do_hash_md(lng,'work',hash)
+            do_hash_md_maintenance(lng,'work',hash)
+          end
+        end
+        if key.length > 0
+          key.sort.each do |m|
+            attrib="lev#{lv}"
+            lv==0 ? do_string_name(lng,attrib,m) : do_string(lng,attrib,m)
+            do_case(lng,lv,hash[m])
+          end
+        end
+      end
+      def do_case(lng,lv,a)
+        case a
+        when String
+          attrib="lev#{lv}"
+          if a=~/S/
+            lv==0 ? do_string_name(lng,attrib,a) : do_string(lng,attrib,a)
+          end
+        when Array
+          do_array(lng,lv,a)
+        when Hash
+          do_hash(lng,lv,a)
+        end
+      end
+      #def html_body
+      #  the_idx=@the_idx
+      #  the_idx.each_pair do |lng,lng_array|
+      #    lng_array.sort.each do |a|
+      #      do_case(lng,-1,a)
+      #    end
+      #  end
+      #end
+      self
+    end
+  end
+end
+__END__
+terms -|_  t{tl1} -|_ {fa}[fa]{filenames and other details}
+       |           |_ {tl2} -|_ {fa}[fa]{filenames and other details}
+       |           |         |_{tl3} -|_ {fa}[fa]{filenames and other details}
+       |           |         |        |_{tl4} - {fa}[fa]{filenames and other details}
+       |           |         |        |
+       |           |         |        |_{tl4a} - {fa}[fa]{filenames and other details}
+       |           |         |        |
+       |           |         |        |_{tl4b} - {fa}[fa]{filenames and other details}
+       |           |         |        |
+       |           |         |        |_ ...
+       |           |         |
+       |           |         |_{tl3a} - {fa}[fa]{filenames and other details}
+       |           |
+       |           |_{tl2a} - {fa}[fa]{filenames and other details}
+       |
+       |_ t{tl1a} -|_ {fa}[fa]{filenames and other details}
+                   |_ ...
+#+END_SRC
+
+** authors
+*** html_harvest_authors.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/html_harvest_authors.rb"
+# <<sisu_document_header>>
+module SiSU_HarvestAuthors
+  require_relative 'html_harvest_author_format'          # html_harvest_author_format.rb
+  require_relative 'html_parts'                          # html_parts.rb
+  class Songsheet
+    @@the_idx_authors={}
+    def initialize(opt,env)
+      @opt,@env=opt,env
+      @file_list=opt.files
+    end
+    def songsheet
+      idx_array={}
+      @opt.f_pths.each do |y|
+        lang_hash_file_array={}
+        name=y[:f]
+        filename=y[:pth] + '/' + y[:f]
+        File.open(filename,'r') do |file|
+          file.each_line("\n\n") do |line|
+            if line =~/^@(?:title|creator|date):(?:\s|$)/m
+              lang_hash_file_array[y[:lng_is]] ||= []
+              lang_hash_file_array[y[:lng_is]] << line
+            elsif line =~/^@\S+?:(?:\s|$)/m \
+            or line =~/^(?:\s*\n|%+ )/
+            else break
+            end
+          end
+        end
+        lang_hash_file_array.each_pair do |lang,a|
+          idx_array[lang] ||= []
+          idx_array=SiSU_HarvestAuthors::Harvest.new(
+            @opt,
+            @env,
+            a,
+            filename,
+            name,
+            idx_array,
+            lang
+          ).extract_harvest
+        end
+      end
+      the_idx=SiSU_HarvestAuthors::Index.new(
+        idx_array,
+        @@the_idx_authors
+      ).construct_book_author_index
+      SiSU_HarvestAuthors::OutputIndex.new(
+        @opt,
+        the_idx
+      ).html_print.html_songsheet
+    end
+  end
+  class Harvest
+    def initialize(opt,env,data,filename,name,idx_array,lang)
+      @opt, @env,@data,@filename,@name,@idx_array,@lang=
+        opt,env, data, filename, name, idx_array, lang
+    end
+    def extract_harvest
+      data,   filename, name, idx_array, lang =
+        @data,@filename,@name,@idx_array,@lang
+      @title=@subtitle=@fulltitle=@author=@author_format=@date=nil
+      @authors=[]
+      rgx={}
+      rgx[:author]=/^@creator:(?:[ ]+|.+?:author:[ ]+)(.+?)(?:\||\n)/m
+      rgx[:title]=/^@title:[ ]+(.+)/
+      rgx[:subtitle]=/^@title:.+?:subtitle:[ ]+(.+?)\n/m
+      rgx[:date]=/^@date:(?:[ ]+|.+?:published:[ ]+)(\d{4})/m
+      data.each do |para|
+        if para=~ rgx[:title]
+          @title=rgx[:title].match(para)[1]
+        end
+        if para=~ rgx[:subtitle]
+          @subtitle=rgx[:subtitle].match(para)[1]
+        end
+        if para=~ rgx[:author]
+          @author_format=rgx[:author].match(para)[1]
+        end
+        if para=~ rgx[:date]
+          @date=rgx[:date].match(para)[1]
+        end
+        break if @title && @subtitle && @author && @date
+      end
+      @fulltitle=@subtitle \
+      ? (@title + ' - ' + @subtitle)
+      : @title
+      if @title \
+      and @author_format
+        creator=SiSU_FormatAuthor::Author.new(@author_format.strip).author_details
+        @authors,@authorship=creator[:authors],creator[:authorship]
+        file=if name=~/~[a-z]{2,3}\.ss[mt]$/
+          name.sub(/~[a-z]{2,3}\.ss[mt]$/,'')
+        else
+          name.sub(/\.ss[mt]$/,'')
+        end
+        page=if @env.output_dir_structure.by? == :language
+          "#{lang}/sisu_manifest.html"
+        else
+          "sisu_manifest.#{lang}.html"
+        end
+        idx_array[lang] <<= {
+          filename: filename,
+          file: file,
+          date: @date,
+          title: @fulltitle,
+          author: creator,
+          page: page,
+          lang: lang
+        }
+      else
+        #p "missing author field: #{@filename} title: #{@title}; author: #{@author_format}"
+      end
+      idx_array[lang]=idx_array[lang].flatten
+      idx_array
+    end
+  end
+  class Index
+    def initialize(idx_array,the_idx)
+      @idx_array,@the_idx=idx_array,the_idx
+      @@the_idx_authors=@the_idx
+    end
+    def capital(txt)
+      txt[0].chr.capitalize + txt[1,txt.length]
+    end
+    def construct_book_author_index
+      idx_array=@idx_array
+      idx_array.each_pair do |lang,idx_arr|
+        @@the_idx_authors[lang] ||= {}
+        idx_arr.each do |idx|
+          idx[:author][:last_first_format_a].each do |author|
+            author=author.strip
+            if @@the_idx_authors[lang][author].is_a?(NilClass)
+              @@the_idx_authors[lang][author]={ md: [] }
+            end
+            @@the_idx_authors[lang][author][:md] << {
+              filename: idx[:filename],
+              file: idx[:file],
+              author: idx[:author],
+              title: idx[:title],
+              date: idx[:date],
+              page: idx[:page],
+              lang: idx[:lang]
+            }
+          end
+        end
+      end
+      @the_idx=@@the_idx_authors
+    end
+  end
+  class OutputIndex
+    require_relative 'i18n'                               # i18n.rb
+    def initialize(opt,the_idx)
+      @opt,@the_idx=opt,the_idx
+      @env=SiSU_Env::InfoEnv.new
+      @rc=SiSU_Env::GetInit.new.sisu_yaml.rc
+      @alphabet_list=%W[9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z]
+      @alph=@alphabet_list.dup
+      @letter=@alph.shift
+    end
+    def html_file_open
+      @the_idx.keys.each do |lng|
+        @output ||={}
+        @output[lng] ||={}
+        harvest_pth,file='',''
+        if @env.output_dir_structure.by? == :language
+          harvest_pth=@env.path.webserv + '/' \
+          + @opt.base_stub + '/' \
+          + lng + '/' \
+          + 'manifest'
+          file="#{harvest_pth}/authors.html"
+        elsif @env.output_dir_structure.by? == :filetype
+          harvest_pth=@env.path.webserv + '/' \
+          + @opt.base_stub + '/' \
+          + 'manifest'
+          file="#{harvest_pth}/authors.#{lng}.html"
+        elsif @env.output_dir_structure.by? == :filename
+          harvest_pth=@env.path.webserv + '/' \
+          + @opt.base_stub
+          file="#{harvest_pth}/authors.#{lng}.html"
+        end
+        FileUtils::mkdir_p(harvest_pth) \
+          unless FileTest.directory?(harvest_pth)
+        fileinfo=(@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:urls_selected][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on) \
+        ? ("file://#{file}") : ''
+        SiSU_Screen::Ansi.new(
+          @opt.act[:color_state][:set],
+          "harvest authors (#{@opt.files.length} files)",
+          fileinfo
+        ).dark_grey_title_hi unless @opt.act[:quiet][:set]==:on
+        @output[lng][:html]=File.new(file,'w')
+      end
+    end
+    def html_file_close
+      @the_idx.keys.each do |lng|
+        @output[lng][:html].close
+        @output[lng][:html_mnt].close \
+          if @output[lng][:html_mnt].is_a?(File)
+      end
+    end
+    def html_print
+      def html_songsheet
+        html_file_open
+        html_head
+        html_alph
+        html_body
+        html_tail
+        html_file_close
+      end
+      def html_head_adjust(lng,type='')
+        css_path,topics='',''
+        if @env.output_dir_structure.by? == :language
+          css_path=(type !~/maintenance/) \
+          ? '../../_sisu/css/harvest.css'
+          : 'harvest.css'
+          topics='topics.html'
+        elsif @env.output_dir_structure.by? == :filetype
+          css_path=(type !~/maintenance/) \
+          ? '../_sisu/css/harvest.css'
+          : 'harvest.css'
+          topics="topics.#{lng}.html"
+        elsif @env.output_dir_structure.by? == :filename
+          css_path=(type !~/maintenance/) \
+          ? './_sisu/css/harvest.css'
+          : 'harvest.css'
+          topics="topics.#{lng}.html"
+        end
+        ln=SiSU_i18n::Languages.new.language.list
+        harvest_languages=''
+        @the_idx.keys.each do |lg|
+          if @env.output_dir_structure.by? == :language
+            harvest_pth="../../#{lg}/manifest"
+            file="#{harvest_pth}/authors.html"
+          elsif @env.output_dir_structure.by? == :filetype
+            harvest_pth='.'
+            file="#{harvest_pth}/authors.#{lg}.html"
+          elsif @env.output_dir_structure.by? == :filename
+            harvest_pth='.'
+            file="#{harvest_pth}/authors.#{lg}.html"
+          end
+          l=ln[lg][:t]
+          harvest_languages +=
+            %{<a href="#{file}">#{l}</a>&nbsp;&nbsp;&nbsp;}
+        end
+        sv=SiSU_Env::InfoVersion.instance.get_version
+        if @env.output_dir_structure.by? == :language
+          home_pth='../..'
+          output_structure_by=
+            '(output organised by language &amp; filetype)'
+        elsif @env.output_dir_structure.by? == :filetype
+          home_pth='..'
+          output_structure_by=
+            '(output organised by filetype)'
+        elsif @env.output_dir_structure.by? == :filename
+          home_pth='.'
+          output_structure_by=
+            '(output organised by filename)'
+        else
+          home_pth='.'
+          output_structure_by='(output organised by ?)'
+        end
+        <<WOK
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>SiSU Metadata Harvest - Authors</title>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+<meta name="dc.title" content= "SiSU metadata harvest, Authors - SiSU 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="#{sv.project} #{sv.version} of #{sv.date_stamp} (n*x and Ruby!)" />
+<link rel="generator" href="http://www.jus.uio.no/sisu/SiSU" />
+<link href="#{css_path}" rel="stylesheet" >
+<link rel="shortcut icon" href="../_sisu/image/rb7.ico" />
+</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>SiSU Metadata Harvest - Authors #{output_structure_by}</h1>
+<p>[<a href="#{home_pth}/index.html">&nbsp;HOME&nbsp;</a>] also see <a href="#{topics}">SiSU Metadata Harvest - Topics</a></p>
+<p>#{@env.widget_static.search_form}</p>
+<hr />
+<p class="tiny">#{harvest_languages}</p>
+<hr />
+WOK
+      end
+      def html_head
+        @the_idx.keys.each do |lng|
+          @output[lng][:html_mnt] \
+          << html_head_adjust(lng,'maintenance') \
+            if @opt.act[:maintenance][:set]==:on
+          @output[lng][:html] \
+          << html_head_adjust(lng)
+        end
+      end
+      def html_alph
+        a=[]
+        a << '<p>'
+        @alph.each do |x|
+          a << ((x =~/[0-9]/) \
+          ? ''
+          : %{<a href="##{x}">#{x}</a>,&nbsp;})
+        end
+        a=a.join
+        @the_idx.keys.each do |lng|
+          @output[lng][:html_mnt] << a \
+            if @opt.act[:maintenance][:set]==:on
+          @output[lng][:html] << a
+        end
+      end
+      def html_tail
+        a =<<WOK
+<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>
+#{SiSU_Proj_HTML::Bits.new.credits_sisu}
+</body>
+</html>
+WOK
+        @the_idx.keys.each do |lng|
+          @output[lng][:html_mnt] << a \
+            if @output[lng][:html_mnt].is_a?(File)
+          @output[lng][:html] << a
+        end
+      end
+      def do_html(lng,html)
+        @output[lng][:html_mnt] << html \
+          if @output[lng][:html_mnt].is_a?(File)
+        @output[lng][:html] << html
+      end
+      def do_string_name(lng,attrib,string)
+        f=/^(\S)/.match(string[0])[1]
+        if @lng != lng
+          @alph=@alphabet_list.dup
+          @letter=@alph.shift
+          @lng = lng
+        end
+        if @letter < f
+          while @letter < f
+            if @alph.length > 0
+              @letter=@alph.shift
+              if @output[lng][:html_mnt].is_a?(File)
+                @output[lng][:html_mnt] \
+                << %{\n<p class="letter"><a name="#{@letter}"></p>#{@letter}</a><p class="book_index_lev1"><a name="#{@letter.downcase}"></a></p>}
+              end
+              @output[lng][:html] \
+              << %{\n<p class="letter"><a name="#{@letter}">#{@letter}</a></p><p class="book_index_lev1"><a name="#{@letter.downcase}"></a></p>}
+            else break
+            end
+          end
+        end
+      end
+      def html_body
+        the_idx=@the_idx
+        the_idx.each_pair do |lng,lng_array|
+          lng_array.sort.each do |a|
+            do_string_name(lng,'',a)
+            name=a[0].sub(/(.+?)(?:,.+|$)/,'\1').gsub(/\s+/,'_')
+            x = %{<p class="author"><a name="#{name}">#{a[0]}</a></p>}
+            if @output[lng][:html_mnt].is_a?(File)
+              @output[lng][:html_mnt] << x
+            end
+            @output[lng][:html] << x
+            lang_code_insert=SiSU_Env::FilenameLanguageCodeInsert.new(@opt,lng).language_code_insert
+            works=[]
+            a[1][:md].each do |i|
+              manifest_at=if @env.output_dir_structure.by? == :language
+                i[:file] + Sfx[:html]
+              elsif @env.output_dir_structure.by? == :filetype
+                i[:file] + lang_code_insert + Sfx[:html]
+              elsif @env.output_dir_structure.by? == :filename
+                './' + i[:file] + '/' + i[:page]
+              else '' #error
+              end
+              work=[
+                "#{i[:date]} #{i[:title]}",
+                %{<p class="publication">#{i[:date]} <a href="#{manifest_at}">#{i[:title]}</a>, #{i[:author][:authors_s]}</p>}
+              ]
+              works<<=(@output[lng][:html_mnt].is_a?(File)) \
+              ? (work.concat([%{<p class="publication">[<a href="#{i[:file]}.sst">src</a>]&nbsp;&nbsp;#{i[:date]} <a href="file://#{manifest_at}">#{i[:title]}</a>, #{i[:author][:authors_s]} -- [<a href="#{i[:file]}.sst">#{i[:file]}.sst</a>]</p>}]))
+              : work
+            end
+            works.sort_by {|y| y[0]}.each do |z|
+              @output[lng][:html] << z[1]
+              @output[lng][:html_mnt] << z[2] \
+                if @output[lng][:html_mnt].is_a?(File)
+            end
+          end
+        end
+      end
+      self
+    end
+    def screen_print
+      def cycle
+        the_idx=@the_idx
+        the_idx.sort.each do |a|
+          puts a[0]
+          a[1][:md].each do |x|
+            puts "\t" + x[:file]
+          end
+        end
+      end
+      self
+    end
+  end
+end
+__END__
+#+END_SRC
+
+*** html_harvest_author_format.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/html_harvest_author_format.rb"
+# <<sisu_document_header>>
+module SiSU_FormatAuthor
+  class Author
+    def initialize(author_param)
+      @author_param=author_param
+    end
+    def author_details
+      @authors,@author_array=[],[]
+      authors=@author_param.scan(/[^;]+/)
+      authors.each do |a|
+        a=a.strip
+        if a =~/"(.+?)"/
+          @authors << { the: $1 }
+          @author_array << $1.upcase
+        else #if a =~/,/
+          x=a.scan(/[^,]+/)
+          x[0]=x[0].strip
+          x[1]=x[1].strip if x[1]
+          if x.length==1
+            @authors << { the: x[0] }
+            @author_array << x[0].upcase
+          elsif x.length==2
+            @authors << { the: x[0], others: x[1] }
+            @author_array << "#{x[0].upcase}, #{x[1]}"
+          else #p x.length
+          end
+        end
+      end
+      l = @authors.length
+      authors_string=''
+      @authors.each_with_index do |a,i|
+        authors_string += if a[:others]
+          if (l - i) > 1
+            "#{a[:others]} #{a[:the]}, "
+          else
+            "#{a[:others]} #{a[:the]}"
+          end
+        else
+          if (l - i) > 2
+            "#{a[:the]}, "
+          else
+            "#{a[:the]}"
+          end
+        end
+      end
+      {
+        last_first_a: authors,
+        last_first_format_a: @author_array,
+        authors_h: @authors,
+        authors_s: authors_string,
+        authors_param: @author_param
+      }
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    harvest
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/html.org b/org/html.org
new file mode 100644
index 00000000..1454226d
--- /dev/null
+++ b/org/html.org
@@ -0,0 +1,5971 @@
+-*- mode: org -*-
+#+TITLE:       sisu html
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:html:
+#+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
+
+* html
+** part
+*** html.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/html.rb"
+# <<sisu_document_header>>
+module SiSU_HTML
+  begin
+    require 'pstore'
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('pstore NOT FOUND (LoadError)')
+  end
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+    include SiSU_Particulars
+  require_relative 'html_table'                         # html_table.rb
+  require_relative 'html_parts'                         # html_parts.rb
+  require_relative 'html_format'                        # html_format.rb
+    include SiSU_HTML_Format
+  require_relative 'html_segments'                      # html_segments.rb
+    include SiSU_HTML_Seg
+  require_relative 'html_scroll'                        # html_scroll.rb
+  require_relative 'html_promo'                         # html_promo.rb
+    include SiSU_HTML_Promo
+  require_relative 'html_tune'                          # html_tune.rb
+    include SiSU_HTML_Tune
+  class Source
+    def initialize(opt)
+      @opt=opt
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+    end
+    def read
+      begin
+        songsheet
+      ensure
+        SiSU_Env::CreateSite.new(@opt).cp_css
+        SiSU_Env::CreateSite.new(@opt).cp_base_images
+        Dir.chdir(@opt.f_pth[:pth])
+      end
+    end
+    def songsheet
+      begin
+        @md=@particulars.md
+        @fnb=@md.fnb
+        @env=@particulars.env
+        primary_output_file=(@opt.act[:html_seg][:set]==:on) \
+        ? (@md.file.output_path.html_seg.dir + '/' + @md.file.base_filename.html_segtoc)
+        : (@md.file.output_path.html_scroll.dir + '/' + @md.file.base_filename.html_scroll)
+        unless @opt.act[:quiet][:set]==:on
+          tool=(@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on) \
+          ? ("#{@env.program.web_browser} file://#{primary_output_file}")
+          : ("[#{@opt.f_pth[:lng_is]}] #{@opt.fno}")
+          (@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on) \
+          ? SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'HTML',
+              tool
+            ).green_hi_blue
+          : SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'HTML',
+              tool
+            ).green_title_hi
+          if (@opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on)
+            SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              @opt.fns,
+              "file://#{primary_output_file}"
+            ).flow
+          end
+        end
+        data=nil
+        tuned_file_array=SiSU_HTML::Source::HTML_Environment.new(@particulars).tuned_file_instructions
+        data=tuned_file_array
+        if @opt.act[:html_scroll][:set]==:on
+          scr_endnotes=SiSU_HTML::Source::Endnotes.new(data,@md).scroll
+        end
+        toc=SiSU_HTML::Source::Toc.new(@md,data).songsheet
+        links_guide=SiSU_HTML::Source::LinksGuide.new(data,@md).toc
+        data=tuned_file_array
+        scr_toc=SiSU_HTML::Source::ScrollHeadAndSegToc.new(@md,toc,links_guide).in_common #watch
+        if @opt.act[:html_seg][:set]==:on
+          SiSU_HTML::Source::Seg.new(@md,data).songsheet
+        end
+        data=tuned_file_array
+        if @opt.act[:html_scroll][:set]==:on
+          scr=SiSU_HTML::Source::Scroll.new(@md,data,scr_endnotes).songsheet
+          scroll=SiSU_HTML::Source::ScrollOutput.new(
+            scr_toc,
+            scr[:body],
+            scr[:metadata],
+            scr[:owner_details],
+            scr[:tails],
+            @md
+          ).publish
+          SiSU_HTML::Source::Output.new(scroll,@md).scroll
+        end
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        unless (@opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on)
+          texfiles=Dir["#{@env.processing_path.tune}/#{@opt.fns}*"]
+          texfiles.each do |f|
+            if FileTest.file?(f)
+              File.unlink(f)
+            end
+          end
+        end
+        SiSU_Env::Clear.new(@opt.selections.str,@opt.fns,@md).param_instantiate
+        @@flag,@@scr,@@seg,@@seg_endnotes,@@seg_subtoc={},{},{},{},{}
+        @@tracker=0
+        @@seg_name,@@seg_name_x,@@seg_subtoc_array,@@seg_endnotes_array,@@tablefoot=Array.new(5){[]}
+        @@filename_seg,@@seg_url,@@to_lev4,@@get_hash_to,@@get_hash_fn='','','','',''
+      end
+    end
+    private
+    class HTML_Environment
+      def initialize(particulars)
+        @particulars=particulars
+        @md,@env=particulars.md,particulars.env
+        @env,@css=particulars.env,SiSU_Style::CSS.new
+      end
+      def tuned_file_instructions
+        @tell=SiSU_Screen::Ansi.new(@md.opt.act[:color_state][:set])
+        ao_array=@particulars.ao_array # ao file drawn here
+        tuned_file_array=SiSU_HTML_Tune::Tune.new(ao_array,@md).songsheet
+        tuned_file_array
+      end
+    end
+    class LinksGuide
+      @links_guide_toc=[]
+      def initialize(data,md)
+        @data,@md=data,md
+        @links_guide_=SiSU_Env::CreateSite.new(@md.opt).html_quick_ref?
+      end
+      def toc
+        @links_guide_toc=[]
+        if @links_guide_
+          format_head_toc=SiSU_HTML_Format::HeadToc.new(@md)
+          guide_type='horzontal' #values: horizontal or vertical
+          @links_guide_toc << format_head_toc.links_guide_open(guide_type)
+          if defined? @md.lnk \
+          and @md.lnk
+            @md.lnk.each do |l|
+              if defined? l[:say]
+                target=(l[:url] !~/^\.(\.)?\//) \
+                ? 'external'
+                : '_top'
+                s_lnk_url,s_lnk_lnk=l[:url],l[:say]
+                txt_obj={
+                  lnk_url: s_lnk_url,
+                  lnk_txt: s_lnk_lnk,
+                  target: target,
+                }
+                lev_dob_ocn=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+                @links_guide_toc << lev_dob_ocn.links_guide if s_lnk_lnk
+              end
+            end
+          end
+          format_head_toc=SiSU_HTML_Format::HeadToc.new(@md)
+          @links_guide_toc << format_head_toc.links_guide_close #(guide_type)
+          @links_guide_toc
+        else ''
+        end
+      end
+    end
+    class Endnotes
+      include SiSU_HTML_Format
+      def initialize(data,md)
+        @data,@md=data,md
+      end
+      def scroll
+        @scr_endnotes=[]
+        SiSU_HTML_Format::HeadScroll.new(@md)
+        @data.each do |dob|
+          pg=dob.dup
+          unless pg.is ==:code
+            if pg.obj =~/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})[\d*+]+ /
+              endnote_array=[]
+              if pg.obj=~/#{Mx[:en_a_o]}[\d*+].+?#{Mx[:en_a_c]}/m
+                endnote_array = pg.obj.scan(/#{Mx[:en_a_o]}[\d*+]+(.+?)#{Mx[:en_a_c]}/m)
+              end
+              if pg.obj=~/#{Mx[:en_b_o]}[\d*]+\s.+?#{Mx[:en_b_c]}/m
+                endnote_array = pg.obj.scan(/#{Mx[:en_b_o]}[\d*]+(.+?)#{Mx[:en_b_c]}/m)
+              end
+              if pg.obj=~/#{Mx[:en_b_o]}[\d+]+\s.+?#{Mx[:en_b_c]}/m
+                endnote_array = pg.obj.scan(/#{Mx[:en_b_o]}[\d+]+(.+?)#{Mx[:en_b_c]}/m)
+              end
+              endnote_array.flatten.each do |note|
+                txt_obj={ txt: note }
+                format_scroll=SiSU_HTML_Format::FormatScroll.new(@md,txt_obj)
+                @scr_endnotes << format_scroll.endnote_body
+              end
+            end
+          end
+        end
+        @scr_endnotes
+      end
+    end
+    class Toc <LinksGuide
+      @@toc={ seg: [], seg_mini: [], scr: [] }
+      @@seg_url=''
+      @@firstseg=nil
+      def initialize(md=nil,data='')
+        @data,@md=data,md
+        @tell=SiSU_Screen::Ansi.new(@md.opt.act[:color_state][:set]) if @md
+      end
+      def songsheet #extracts toc for scroll & seg
+        if (@md.opt.act[:verbose][:set]==:on \
+        || @md.opt.act[:verbose_plus][:set]==:on \
+        || @md.opt.act[:maintenance][:set]==:on)
+          SiSU_Screen::Ansi.new(
+            @md.opt.act[:color_state][:set],
+            'Toc'
+          ).txt_grey
+        end
+        toc=nil
+        @@firstseg=nil
+        @@toc={ seg: [], seg_mini: [], scr: [] }
+        @data.each do |dob|
+          if dob.is==:heading \
+          || dob.is==:heading_insert
+            dob_toc=dob.dup
+            toc=if dob_toc.is ==:heading \
+            || dob.is==:heading_insert
+              toc=case dob_toc.ln
+              when 0 then SiSU_HTML::Source::Toc.new(@md,dob_toc).level_0
+              when 1 then SiSU_HTML::Source::Toc.new(@md,dob_toc).level_1
+              when 2 then SiSU_HTML::Source::Toc.new(@md,dob_toc).level_2
+              when 3 then SiSU_HTML::Source::Toc.new(@md,dob_toc).level_3
+              when 4 then SiSU_HTML::Source::Toc.new(@md,dob_toc).level_4
+              when 5 then SiSU_HTML::Source::Toc.new(@md,dob_toc).level_5
+              when 6 then SiSU_HTML::Source::Toc.new(@md,dob_toc).level_6
+              else nil
+              end
+            end
+            toc.each do |k,d|
+              d.gsub!(/(?:#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})\s*/m,' ')
+            end if toc
+            if @@firstseg.nil? \
+            and dob.ln==4 \
+            and dob.name =~/\S+/
+              @@firstseg=dob.name
+            end
+            if toc
+              begin
+                @@toc[:seg] << toc[:seg] if toc[:seg]
+                @@toc[:seg_mini] << toc[:seg_mini] if toc[:seg_mini]
+                @@toc[:scr] << toc[:scr] if toc[:scr]
+              rescue
+                SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+                  __LINE__.to_s + ':' + __FILE__
+                end
+              end
+            end
+          end
+        end
+        @md.firstseg=@@firstseg
+        @@toc
+      end
+      def minitoc
+        minitoc=@@toc[:seg_mini].join("\n")
+        '<div class="toc">' + minitoc + '</div>'
+      end
+    protected
+      def rss #sort all wrong, disabled but kept
+        @@toc[:seg] <<<<WOK
+<center>
+<table><tr><td>
+<p><font color="#222222" #{the_font.set_face} size="2">
+(relatively static) RSS feeds for DOCUMENTS:<br>
+<a href="../rssfeed/documents.xml"><img border="0" height="14" width="36" src="../_sisu/image/rss.png" alt="RSS feed"></a>&nbsp;http://www.jus.uio.no/lm/rssfeed/documents.xml<br>
+<a href="../rssfeed/tradelaw.xml"><img border="0" height="14" width="36" src="../_sisu/image/rss.png" alt="RSS feed"></a>&nbsp;http://www.jus.uio.no/lm/rssfeed/tradelaw.xml<br>
+<a href="../rssfeed/environmental.xml"><img border="0" height="14" width="36" src="../_sisu/image/rss.png" alt="RSS feed"></a>&nbsp;http://www.jus.uio.no/lm/rssfeed/environmental.xml<br>
+<center><a href="mailto:info@address.com" target="_top">info@address.com</a></center>
+</font></p>
+</td></tr></table>
+WOK
+      end
+#not used -->
+      def level_endnotes
+        if @md.flag_endnotes
+          format_head_scroll=SiSU_HTML_Format::HeadScroll.new(@md)
+          @@toc[:scr] << format_head_scroll.toc_endnote
+        end
+      end
+      def level_concordance
+        format_head_toc=SiSU_HTML_Format::HeadToc.new(@md)
+        @@toc[:seg_mini] << format_head_toc.mini_seg_concordance
+      end
+      def level_metadata
+        format_head_toc=SiSU_HTML_Format::HeadToc.new(@md)
+        @@toc[:scr] << format_head_toc.metadata
+        @@toc[:seg] << format_head_toc.seg_metadata
+        @@toc[:seg_mini] << format_head_toc.mini_seg_metadata
+      end
+      def level_word_index
+        format_head_toc=SiSU_HTML_Format::HeadToc.new(@d0c)
+        @@toc[:scr] << format_head_toc.concordance
+        @@toc[:seg] << format_head_toc.concordance
+        @@toc[:seg_mini] << format_head_toc.mini_concordance
+      end
+# <-- not used
+      def level_0
+        dob=@data
+        linkname,link=dob.obj.strip,dob.ocn
+        if link \
+        and link.to_s !~/#/ #% keep eye on link
+          SiSU_HTML_Format::ParagraphNumber.new(@md,link)
+        end
+        title=linkname
+        toc={}
+        txt_obj={ txt: title }
+        format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+        toc[:seg]=format_toc.lev0
+        toc[:seg_mini]=format_toc.mini_lev0
+        title=if dob.ocn ==0 then linkname
+        else
+          @@toc[:scr] <<  '<br>'
+          %{<b><a href="##{dob.ocn}">#{linkname}</a></b>}
+        end
+        txt_obj={ txt: title }
+        format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+        toc[:scr]=format_toc.lev0
+        toc
+      end
+      def level_1
+        dob=@data
+        linkname,link=dob.obj.strip,dob.ocn
+        if link \
+        and link.to_s !~/#/ #% keep eye on link
+          SiSU_HTML_Format::ParagraphNumber.new(@md,link)
+        end
+        title=if dob.obj !~/^Metadata$/ then linkname
+        else
+          link='metadata'
+          %{<b><a href="#{link}#{@md.lang_code_insert}#{Sfx[:html]}">#{linkname}</a></b>}
+        end
+        toc={}
+        txt_obj={ txt: title }
+        format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+        toc[:seg]=if dob.name =~/^meta/ \
+        and dob.obj =~/Document Information/
+          format_toc.lev0
+        else format_toc.lev1
+        end
+        toc[:seg_mini]=if dob.name =~/^meta/ \
+        and dob.obj =~/Document Information/
+          @md.concord_make \
+          ? format_toc.mini_concord_tail
+          : format_toc.mini_tail
+        else format_toc.mini_lev1
+        end
+        title=if dob.ocn ==0
+          if dob.name =~/^meta/ \
+          and dob.obj =~/Document Information/
+            %{<a href="#docinfo">#{linkname}</a>}
+          else linkname
+          end
+        else
+          @@toc[:scr] <<  '<br>'
+          %{<b><a href="##{dob.ocn}">#{linkname}</a></b>}
+        end
+        txt_obj={ txt: title }
+        format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+        toc[:scr]=if dob.obj =~/^Metadata$/ then ''
+        elsif txt_obj[:txt] =~/<a href="#">/
+          format_toc.lev1.gsub(/<a href="#">|<\/a>/,'')
+        else format_toc.lev1
+        end
+        toc
+      end
+      def level_2
+        dob=@data
+        linkname,ocn=dob.obj.strip,dob.ocn
+        p_num=if ocn \
+        and ocn.to_s !~/#/
+          SiSU_HTML_Format::ParagraphNumber.new(@md,ocn)
+        else nil
+        end
+        txt_obj={ txt: linkname }
+        format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+        toc={}
+        toc[:seg]=format_toc.lev2
+        toc[:seg_mini]=format_toc.mini_lev2
+        if p_num
+          title=%{#{p_num.goto}#{linkname}</a>}
+          txt_obj={ txt: title }
+          format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+          toc[:scr]=if txt_obj[:txt] =~/<a href="#">/
+            format_toc.lev2.gsub(/<a href="#">|<\/a>/,'')
+          else format_toc.lev2
+          end
+        end
+        toc
+      end
+      def level_3
+        dob=@data
+        linkname,ocn=dob.obj.strip,dob.ocn
+        p_num=if ocn \
+        and ocn.to_s !~/#/
+          SiSU_HTML_Format::ParagraphNumber.new(@md,ocn)
+        else nil
+        end
+        txt_obj={ txt: linkname }
+        format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+        toc={}
+        toc[:seg]=format_toc.lev3
+        toc[:seg_mini]=format_toc.mini_lev3
+        if p_num
+          title=%{#{p_num.goto}#{linkname}</a>}
+          txt_obj={ txt: title }
+          format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+          toc[:scr]=if txt_obj[:txt] =~/<a href="#">/
+            format_toc.lev3.gsub(/<a href="#">|<\/a>/,'')
+          else format_toc.lev3
+          end
+        end
+        toc
+      end
+      def level_4
+        dob=@data
+        linkname,ocn=dob.obj.strip,dob.ocn
+        p_num=SiSU_HTML_Format::ParagraphNumber.new(@md,ocn) if ocn
+        if dob.ln ==4
+          fnh={
+            fn: dob.name,
+          }
+          f=@md.file.base_filename.html_seg(fnh)
+          seg_link=%{  <a href="#{f}" target="_top">
+    #{dob.obj}
+  </a> }
+          @@seg_url=dob.name
+        elsif dob.obj =~/\d+.\d+.\d+.\d+|\d+.\d+.\d+|\d+.\d+|\d+/
+          fn,hd=/^(\d+.\d+.\d+.\d+|\d+.\d+.\d+|\d+.\d+|\d+)(.*)/.match(dob.obj)[1,2]
+          fnh={
+            fn: fn,
+          }
+          f=@md.file.base_filename.html_seg(fnh)
+          seg_link=%{<a href="#{f}" target="_top">#{fn} #{hd}</a> }
+        end
+        p_num=SiSU_HTML_Format::ParagraphNumber.new(@md,ocn) if ocn
+        @file=SiSU_Env::FileOp.new(@md) if @md
+        txt_obj=if seg_link=~/sisu_manifest\.html/
+          man_link=if @file.output_dir_structure.by_language_code? \
+          or @file.output_dir_structure.by_filetype?
+            seg_link.gsub(/sisu_manifest\.html/,"../../manifest/#{@file.base_filename.manifest}")
+          else seg_link
+          end
+          { txt: man_link }
+        else { txt: seg_link }
+        end
+        format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+        toc={}
+        toc[:seg]=format_toc.lev4
+        toc[:seg_mini]=format_toc.mini_lev4
+        title=%{#{p_num.goto}#{linkname}</a>} if p_num
+        txt_obj=if title=~/sisu_manifest.html/
+          man_link=title.gsub(/sisu_manifest.html/,"../manifest/#{@file.base_filename.manifest}")
+          { txt: man_link }
+        else { txt: title }
+        end
+        format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+        toc[:scr]=format_toc.lev4
+        toc
+       #end
+      end
+      def level_5
+        dob=@data
+        linkname,ocn=dob.obj.strip,dob.ocn
+        toc={}
+        if ocn \
+        and ocn.to_s !~/#/
+          fnh={
+            fn: @@seg_url,
+          }
+          f=@md.file.base_filename.html_seg(fnh)
+          p_num=SiSU_HTML_Format::ParagraphNumber.new(@md,ocn)
+          lnk_n_txt=%{  <a href="#{f}##{ocn}">
+    #{linkname}
+  </a>}
+          txt_obj={ txt: lnk_n_txt }
+          format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+          toc[:seg]=format_toc.lev5
+          toc[:seg_mini]=format_toc.mini_lev5
+          title=%{#{p_num.goto}#{linkname}</a>}
+          txt_obj={ txt: title }
+          format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+          toc[:scr]=format_toc.lev5
+        end
+        toc
+      end
+      def level_6
+        dob=@data
+        linkname,ocn=dob.obj.strip,dob.ocn
+        toc={}
+        if ocn \
+        and ocn.to_s !~/#/
+          fnh={
+            fn: @@seg_url,
+          }
+          f=@md.file.base_filename.html_seg(fnh)
+          p_num=SiSU_HTML_Format::ParagraphNumber.new(@md,ocn)
+          lnk_n_txt=%{  <a href="#{f}##{ocn}">
+  #{linkname}
+</a>}
+          txt_obj={ txt: lnk_n_txt }
+          format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+          toc[:seg]=format_toc.lev6
+          toc[:seg_mini]=format_toc.mini_lev6
+          title=%{#{p_num.goto}#{linkname}</a>}
+          txt_obj={ txt: title }
+          format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+          toc[:scr]=format_toc.lev6
+        end
+        toc
+      end
+      def level_crosslink
+        dob=@data
+        dob=if dob !~/^4~!/
+          dob.gsub(/^4~!\s+(\S+)\s+(.+)/,
+            %{<table><tr><td width =\"80\"></td>
+  <td><a href="http://\\1" target="_top">
+    #{@png.crosslink_ext}
+      &nbsp;&nbsp;\\2
+    <\/a>
+  </td></tr></table>
+})
+        else
+          dob.gsub(/^4~!\s+(\S+)\s+(.+)/,
+            %{<table><tr><td width ="80">
+  </td><td>
+    <a href="\\1" target="_top">
+      #{@png.crosslink}
+        &nbsp;&nbsp;\\2
+    <\/a>
+  </td></tr></table>
+})
+        end
+      end
+    end
+    class ScrollHeadAndSegToc < Toc
+      include SiSU_Parts_HTML
+      def initialize(md='',toc='',links_guide_toc='')
+        @md,@toc,@links_guide_toc=md,toc,links_guide_toc
+        @make=SiSU_Env::ProcessingSettings.new(@md)
+      end
+      def in_common
+        toc_shared=[]
+        @segtoc=[]
+        if (@md.opt.act[:verbose][:set]==:on \
+        || @md.opt.act[:verbose_plus][:set]==:on \
+        || @md.opt.act[:maintenance][:set]==:on)
+          SiSU_Screen::Ansi.new(
+            @md.opt.act[:color_state][:set],
+            'Scroll & Segtoc'
+          ).txt_grey
+        end
+        format_head_toc=SiSU_HTML_Format::HeadToc.new(@md)
+        dochead=format_head_toc.head
+        dochead=dochead.gsub(/toc\.(html)/,'doc.\1') #kludge
+        toc_shared << dochead
+        @segtoc << format_head_toc.head
+        if @make.build.html_top_band?
+          toc_shared << format_head_toc.scroll_head_navigation_band
+        end
+        if defined? @md.rights.all
+          rights=format_head_toc.rights.all
+          rights=SiSU_HTML_Tune::CleanHTML.new(rights).clean
+        end
+        if @md.prefix_b
+          prefix_b=format_head_toc.notes.prefix_b
+          prefix_b=SiSU_HTML_Tune::CleanHTML.new(prefix_b).clean
+        end
+        if @make.build.html_top_band?
+          @segtoc << format_head_toc.seg_head_navigation_band
+        end
+        toc_shared << format_head_toc.scroll_head_title_banner_open
+        @segtoc << format_head_toc.seg_head_title_banner_open
+        tmp_head=nil
+        doc_title_endnote=@md.title.full.gsub(/(\*+)/,
+          '<sup><a href="#endnotes">\1</a></sup>')
+        tmp_head=doc_title_endnote + "\n"
+        txt_obj={ txt: tmp_head }
+        format_txt_obj=SiSU_HTML_Format::FormatTextObject.new(@md,txt_obj)
+        toc_shared << format_txt_obj.center_bold
+        @segtoc << format_txt_obj.center_bold
+        if defined? @md.creator.author
+          creator=SiSU_HTML_Tune::CleanHTML.new(@md.creator.author).clean_for_html
+          creator_endnote=creator.gsub(/(\*+)/,
+            %{&nbsp;<sup><a href="#notes">\\1</a></sup>})
+          tmp_head=creator_endnote + "\n"
+          txt_obj={ txt: tmp_head }
+          format_txt_obj=SiSU_HTML_Format::FormatTextObject.new(@md,txt_obj)
+          toc_shared << format_txt_obj.center_bold
+          @segtoc << format_txt_obj.center_bold
+        end
+        toc_shared << "#{the_table_close*1}\n"
+        @segtoc << "#{the_table_close*1}\n"
+        tmp_head=nil
+        if @md.prefix_a
+          tmp_head ||= %{<p>#{@md.prefix_a}\n}
+          toc_shared << tmp_head.dup
+          @segtoc << tmp_head.dup
+        end
+        tmp_head=nil
+        toc_shared << @links_guide_toc
+        if defined? @md.rights.all #and ? @md.rights.all
+          toc_shared << rights
+        end
+        if defined? @md.prefix_b
+          toc_shared << prefix_b
+        end
+        if @make.build.toc? #Table of Contents added/appended here
+          toc_shared << @toc[:scr]
+        end
+        @segtoc << @links_guide_toc
+        @segtoc << @toc[:seg]
+        if defined? @md.rights.all \
+        and not @md.rights.all.empty?
+          @segtoc << rights
+        end
+        @segtoc << prefix_b if @md.prefix_b
+        #Segtoc tail added here
+        @segtoc << "</p>\n" #bugfix sort later DEBUGNOW
+        @segtoc << @seg_toc_band_bottom
+        @segtoc << format_head_toc.seg_navigation_tail << format_head_toc.html_close
+        @segtoc=@segtoc.flatten.compact #watch
+        if @md.opt.act[:html_seg][:set]==:on
+          SiSU_HTML::Source::Output.new(@segtoc,@md).segtoc
+        end
+        @segtoc=[]
+        @toc[:scr],@toc[:seg]=[],[]
+        toc_shared
+      end
+    end
+    class Table < SiSU_HTML_Table::TableHTML
+    end
+    class Scroll < SiSU_HTML_Scroll::Scroll
+    end
+    class ScrollOutput
+      def initialize(scr_toc,scr_body,scr_metadata,scr_owner_details,scr_tails,md)
+        @scr_toc,@scr_body,@scr_metadata,@scr_owner_details,@scr_tails,@md=scr_toc,scr_body,scr_metadata,scr_owner_details,scr_tails,md
+      end
+      def publish
+        scroll=[]
+        scroll << @scr_toc << '<div class="scroll">' << @scr_body << @scr_endnotes << @scr_owner_details << '</div>' << @scr_tails
+        scroll=scroll.flatten.compact #watch
+      end
+    end
+    class Seg < SiSU_HTML_Seg::Seg
+    end
+    class Output
+      def initialize(data='',md='')
+        @data,@md=data,md
+        @file=SiSU_Env::FileOp.new(md)
+        @o_str ||=SiSU_Env::ProcessingSettings.new(md).output_dir_structure
+      end
+      def scroll
+        if @md.opt.act[:html_scroll][:set]==:on
+          begin
+            @filename_html_scroll=@file.write_file.html_scroll
+            @data.each do |para|
+              para=para.strip.
+                gsub(/<:.+?>/,'').
+                gsub(Xx[:html_relative2],@file.path_rel_links.html_scroll_2).
+                gsub(Xx[:html_relative1],@file.path_rel_links.html_scroll_1).
+               #gsub(/#{Xx[:html_relative]}/,@file.path_rel_links.html_scroll).
+                gsub(/#{Rx[:mx_fa_clean]}/,'')
+              unless para =~/\A\s*\Z/
+                @filename_html_scroll.puts para,"\n"
+              end
+            end
+          rescue
+            SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+              __LINE__.to_s + ':' + __FILE__
+            end
+          ensure
+            @filename_html_scroll.close
+          end
+        end
+      end
+      def segtoc
+        if @md.opt.act[:html_seg][:set]==:on
+          begin
+            @filename_html_segtoc=@file.write_file.html_segtoc
+            @data.each do |para|
+              para=para.strip.
+                gsub(/<!.+?!>/,'').
+                gsub(Xx[:html_relative2],@file.path_rel_links.html_seg_2).
+                gsub(Xx[:html_relative1],@file.path_rel_links.html_seg_1)
+              unless para =~/\A\s*\Z/
+                @filename_html_segtoc.puts para,"\n"
+              end
+            end
+          rescue
+            SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+              __LINE__.to_s + ':' + __FILE__
+            end
+          ensure
+            @filename_html_segtoc.close
+            pwd_set=Dir.pwd
+            idx_lnk=(@o_str.dump_or_redirect?) \
+            ? @file.base_filename.manifest
+            : @file.base_filename.html_segtoc
+            mlnk=@file.base_filename.html_seg_index
+            Dir.chdir(@file.output_path.html_seg.dir)
+            FileUtils::rm_f(mlnk)
+            FileUtils::ln_s(idx_lnk,mlnk)
+            Dir.chdir(pwd_set)
+          end
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+*** html_parts.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/html_parts.rb"
+# <<sisu_document_header>>
+module SiSU_Parts_HTML
+  require_relative 'generic_parts'                       # generic_parts.rb
+  include SiSU_Parts_Generic
+  def the_line_break
+    '<br>'
+  end
+  def the_table_close
+    '</td></tr>
+</table>'
+  end
+  def the_table_cellpad_box
+    '"20"'
+  end
+  def the_color
+    def white
+      '#ffffff'
+    end
+    def black
+      '#000000'
+    end
+    def grey_pale
+      '#eeeeee'
+    end
+    def grey_medium
+      '#cccccc'
+    end
+    def grey
+      '#999999'
+    end
+    def blue_ink
+      '#003399'
+    end
+    def blue_tinge
+      '#e3ecef'
+    end
+    def yellow_light
+      '#fff3b6'
+    end
+    def table1
+      'ffffcc'
+    end
+    def table2
+      'c0d0f0'
+    end
+    def band1
+      %{"#{white}"}
+    end
+    def band2
+      %{"#{white}"}
+    end
+    self
+  end
+  def the_url_decoration
+    #def tex_open                     #'{\UseTextSymbol{OML}{<}}'
+    #  Dx[:url_o]
+    #end
+    #def tex_close                    #'{\UseTextSymbol{OML}{>}}'
+    #  Dx[:url_c]
+    #end
+    def xml_open                     #'&lt;'
+      Dx[:url_o]
+    end
+    def xml_close                    #'&gt;'
+      Dx[:url_c]
+    end
+    def txt_open
+      '<'
+    end
+    def txt_close
+      '>'
+    end
+    self
+  end
+  def the_width
+    def table1
+      '"100%"'
+    end
+    def table2
+      '"99%"'
+    end
+    def table_txt
+      '"94%"'
+    end
+    def table_txt_r
+      '"96%"'
+    end
+    self
+  end
+  def the_png
+    def _url_path_image_base #used for html image display
+      "#{Xx[:html_relative2]}_sisu/image"
+    end
+    def ico
+      %{  <link rel="shortcut icon" href="../_sisu/image/#{the_icon.i_ico}" />}
+    end
+    def png_home
+      %{<img border="0" src="#{_url_path_image_base}/#{the_icon.home_button}" alt="#{the_text.home} --&gt;" />}
+    end
+    def png_home_button
+      rel=@dir.path_rel_links.html_scroll_2
+      %{<img border="0" src="#{rel}/#{the_icon.home_button}" alt="#{the_text.home} --&gt;" />}
+    end
+    self
+  end
+  def the_font
+    def set_fonts
+      'verdana, arial, georgia, tahoma, sans-serif, helvetica, times, roman'
+     #'verdana, arial, georgia, tahoma, sans-serif, helvetica, "times new roman", times, roman'
+    end
+    def set_face
+      %{face="#{set_fonts}"}
+    end
+    def set_color
+      'color="#000000"'
+    end
+    def set_size_endnote
+      'size="3"'
+    end
+    def set_small
+      'size="3"'
+    end
+    def set_tiny
+      'size="2"'
+    end
+    def paragraph_font_tiny
+      %{<font #{set_tiny} #{set_face}>}
+    end
+    def paragraph_font_small
+      %{<font #{set_small} #{set_face}>}
+    end
+    self
+  end
+  def the_nav
+    def txt_homepage
+      %{  <font face="#{the_font.set_fonts}" size="2">
+    &nbsp;home&nbsp;
+  </font> }
+    end
+    def txt_toc_link
+      %{  <font face="#{the_font.set_fonts}" size="2">
+    &nbsp;&nbsp;toc&nbsp;
+  </font> }
+    end
+    def txt_doc_link
+      %{  <font face="#{the_font.set_fonts}" size="2">
+    &nbsp;scroll&nbsp;
+  </font> }
+    end
+    def txt_manifest
+      #{png_manifest}&nbsp;document&nbsp;manifest
+      %{  <font face="#{the_font.set_fonts}" size="2">
+    [&nbsp;document&nbsp;manifest&nbsp;]
+  </font> }
+    end
+    def txt_concordance
+      %{  <font face="#{the_font.set_fonts}" size="2">
+    &nbsp;&nbsp;A-Z&nbsp;
+  </font> }
+    end
+    self
+  end
+  def the_banner
+    def home_button_only
+      %{<a href="#{url.site}/">
+  #{the_png.png_home_button}
+  </a>}
+    end
+    def banner_band
+      %{<table summary="home button" width="100%" border="0" cellpadding="3" align="center">
+<tr><td align="left" valign="middle">
+  <a href="#{url.site}/" target="_top">
+    #{the_png.png_home}
+  </a>
+</td>
+<td width="90%">
+#{the_table_close}}
+    end
+    def instrument_cover_band_scr
+      '<table summary="scroll instrument cover band" width="100%" border="0" cellpadding="8" align="center">
+<tr><td align="center">'
+    end
+    def instrument_cover_band_seg
+      '<table summary="segment instrument cover band, title, author, location" width="100%" border="0" cellpadding="8" align="center">
+<tr><td align="center">'
+    end
+    self
+  end
+  def the_margin
+    def txt_0
+      %{<table summary="" width=#{the_width.table_txt} border="0" cellpadding="2" align="center">
+<tr><td width=#{indent_level_0} align="right">
+</td><td valign="top" align="justify">}
+    end
+    def txt_1
+      %{<table summary="" width=#{the_width.table_txt} border="0" cellpadding="2" align="center">
+<tr><td width=#{indent_level_1} align="right"></td><td valign="top" align="justify">}
+    end
+    def txt_2
+      %{<table summary="" width=#{the_width.table_txt} border="0" cellpadding="2" align="center">
+<tr><td width=#{indent_level_2} align="right">
+</td>
+<td valign="top" align="justify">}
+    end
+    def txt_3
+      %{<table summary="" width=#{the_width.table_txt} border="0" cellpadding="2" align="center">
+<tr><td width=#{indent_level_3} align="right">
+</td>
+<td valign="top" align="justify">}
+    end
+    def css
+      '<table summary="normal text css" width="100%" border="0" cellpadding="2" align="center">
+<tr><td valign="top" align="justify"> '
+    end
+    def num
+      '</p> </td><td width="4%" align="right" valign="top">'
+    end
+    def numless
+      '</td><td width="4%" align="right" valign="top">'
+    end
+    def num_css
+      '</td>
+<td width="2%" align="right" valign="top">  '
+    end
+    self
+  end
+end
+module SiSU_Proj_HTML
+  require_relative 'se'                                 # se.rb
+  include SiSU_Env
+  #require_relative 'css'                                # css.rb
+  #  include SiSU_Style
+  class Bits
+    include SiSU_Parts_HTML
+    def initialize
+      @v=SiSU_Env::InfoVersion.instance.get_version
+      #@dir=SiSU_Env::InfoEnv.new
+      #@date=SiSU_Env::InfoDate.new #{@date.year}
+    end
+    def txt_generator
+      %{  <meta name="generator" content="#{@v.project} #{@v.version} of #{@v.date_stamp} (#{@v.date}) (n*x and Ruby!)" />
+    <link rel="generator" href="http://www.sisudoc.org/" />}
+    end
+    def widget_sisu_text
+<<WOK
+  <p class="tiny"><font color="#666666" size="2">
+    Output generated by
+    <a href="#{the_url.sisu}">
+      #{@v.project}
+    </a>
+    #{@v.version} #{@v.date} (#{@v.date_stamp})
+  </font></p>
+WOK
+    end
+    def credits_sisu_manifest
+      widget_sisu_text
+    end
+    def widget_sisu
+<<WOK
+<!-- widget sisu -->
+<tr><td valign="top" width="100%">
+<!-- SiSU Rights -->
+#{widget_sisu_text}
+</td></tr>
+WOK
+    end
+    def credits_sisu
+      %{<div class="substance">
+<table summary="SiSU summary" cellpadding="4" border="0">
+<tr><td>
+  #{widget_sisu}
+</table></div>}
+      ''
+    end
+    def widget_promo # Array used to build promo from list.yml and promo.yml
+    #  ['sisu_icon','sisu','sisu_search_libre','open_society','fsf','ruby']
+    end
+  end
+  class Home
+    def initialize
+      @v=SiSU_Env::InfoVersion.instance.get_version
+      @dir=SiSU_Env::InfoEnv.new
+      @date=SiSU_Env::InfoDate.new #{@date.year}
+    end
+    def redirect
+      <<WOK
+<html><head>
+<title>SiSU</title>
+<meta http-equiv="refresh" content="0, url=http://www.sisudoc.org/sisu/SiSU/">
+</head>
+<body>
+SiSU informtion provided at <a href="http://www.sisudoc.org/sisu/SiSU/">www.sisudoc.org/sisu/SiSU</a><p />
+If your browser supports redirection, you will be escorted there shortly.
+</body>
+</html>
+WOK
+    end
+    def homepage
+      <<WOK
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+<title>SiSU information Structuring Universe - Structured information, Serialized Units - software for electronic texts, documents, books, digital libraries in plaintext, HTML, EPUB, XHTML, XML, ODF (OpenDocument), LaTeX, PDF, SQL (PostgreSQL and SQLite), and for search</title>
+<meta name="dc.title" content="SiSU - SiSU information Structuring Universe, Structured information Serialised Units, #{@date.year_static}" />
+<meta name="dc.creator" content="Ralph Amissah" />
+<meta name="dc.subject" content= "document structuring, ebook, publishing, PDF, LaTeX, XML, ODF, EPUB, SQL, postgresql, sqlite, electronic book, electronic publishing, electronic document, electronic citation, data structure, citation systems, granular search, digital library" />
+<meta name="dc.publisher" content= "SiSU http://www.sisudoc.org/" />
+<meta name="dc.language" content="en" />
+<meta name="dc.rights" content="Copyright Ralph Amissah" />
+<meta name="generator" content="#{@v.project} #{@v.version} of #{@v.date_stamp} (#{@v.date}) (n*x and Ruby!)" />
+<link rel="generator" href="http://www.sisudoc.org/" />
+<link rel="stylesheet" href="./#{@dir.path.style}/harvest.css" type="text/css" />
+<link rel="shortcut icon" href="./_sisu/image/rb7.ico" />
+</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>SiSU</h1>
+<p>
+[<a href="http://sisudoc.org/sisu_manual/en/html/sisu/toc.html">Manual</a>]
+</p>
+<p>
+[<a href="http://git.sisudoc.org/gitweb/?p=code/sisu.git;a=summary">Source</a>]
+[<a href="http://lists.sisudoc.org/listinfo/sisu">List Info (sisu@lists.sisudoc.org)</a>]
+</p>
+
+<h1>SiSU Markup Samples</h1>
+<p>
+[<a href="http://git.sisudoc.org/gitweb/?p=doc/sisu-markup-samples.git;a=summary">Source</a>]
+[<a href="http://sisudoc.org/sisu_markup_samples.html">Output</a>]
+</p>
+
+<hr />
+
+<h2 class="top_band_tiny">
+  Structured information, Serialized Units
+  &nbsp;&nbsp;
+  <a href="http://www.sisudoc.org" target="_top">
+    &lt;www.sisudoc.org&gt;
+  </a>
+  &nbsp;&nbsp;or&nbsp;&nbsp;
+  <a href="http://www.jus.uio.no/sisu/" target="_top">
+    &lt;www.jus.uio.no/sisu/&gt;
+  </a>
+software for electronic texts, document collections, books, digital libraries &amp; search, with "atomic search" &amp; text locating system (shared object citation numbering: "<i>ocn</i>").
+Outputs include: plaintext, HTML, EPUB, ODT (OpenDocumentText), (XHTML, XML,) LaTeX, PDF, SQL (PostgreSQL and SQLite).
+</h2>
+<p class="small">
+<a href="mailto:sisu@lists.sisudoc.org">
+&lt;sisu@lists.sisudoc.org&gt;
+</a>
+<a href="http://lists.sisudoc.org/listinfo/sisu">
+&lt;http://lists.sisudoc.org/listinfo/sisu&gt;
+</a>
+</p>
+<p class="small">
+<a href="mailto:ralph@amissah.com">
+&lt;ralph@amissah.com&gt;
+</a>
+<a href="mailto:ralph.amissah@gmail.com">
+&lt;ralph.amissah@gmail.com&gt;
+</a>
+</p>
+<p class="tiny">
+#{@v.project} #{@v.version} of #{@v.date_stamp} (#{@v.date}) (n*x and Ruby!), #{@date.year_static}.
+</p>
+<p class="tiny">
+w3 since October 3 1993.
+</p>
+</body>
+</html>
+WOK
+    end
+    def home_toc
+      ' '
+    end
+  end
+end
+__END__
+#+END_SRC
+
+*** html_tune.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/html_tune.rb"
+# <<sisu_document_header>>
+require_relative 'dp'                                   # dp.rb
+module SiSU_HTML_Tune
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env; include SiSU_Screen
+  require_relative 'html_parts'                         # html_parts.rb
+  require_relative 'html_format'                        # html_format.rb #watch
+  @@line_mode=''
+  @@endnote_array=[]
+  @@endnote_call_counter=1
+  @@table_align='<table summary='' width="96%" border="0" cellpadding="0" col="3">
+<tr ...><td width="2%" align="right">
+&nbsp\;</td>
+<td width="94%" valign="top" align="justify">'
+  @@table_align_close='</td>
+<td width="4%" align="right" valign="top">
+<font size="1" color="#777777">
+&nbsp;&nbsp;&nbsp;</font> </td></tr></table>'
+  @@counter,@@column,@columns=0,0,0
+  class Output
+    def initialize(data,md)
+      @data,@md=data,md
+      @file=SiSU_Env::InfoFile.new(@md.fns)
+      @cX=SiSU_Screen::Ansi.new(@md.opt.act[:color_state][:set]).cX
+    end
+    def hard_output
+      @filename_tune=@file.write_file_processing.html_tune
+      data=[]
+      @data.each do |x|
+        unless x.obj.empty?
+          x.obj=x.obj.strip
+          data << x
+        end
+      end
+      data.each do |dob|
+        @filename_tune.puts dob, "\n"
+      end
+    end
+    def marshal
+      File.open(@file.marshal.html_tune,'w') {|f| Marshal.dump(@data.to_a,f)}
+    end
+  end
+  class CleanHTML
+    def initialize(html='')
+      @html=html
+    end
+    def clean_for_html
+      html=@html
+      str=if html.is_a?(String)
+        html
+      else html.obj
+      end
+      str=str.gsub(/#{Mx[:gl_o]}(#[0-9]{3})#{Mx[:gl_c]}/u,'&\1;').
+        gsub(/#{Mx[:gl_o]}#([a-z]{2,4})#{Mx[:gl_c]}/u,'&\1;').
+        gsub(/[<]/m,'&lt;').gsub(/[>]/m,'&gt;')
+    end
+    def clean
+      html=@html
+      str=if html.is_a?(String)
+        html
+      else html.obj
+      end
+      str=str.gsub(/#{Mx[:gl_o]}(#[0-9]{3})#{Mx[:gl_c]}/u,'&\1;').
+        gsub(/#{Mx[:gl_o]}#([a-z]{2,4})#{Mx[:gl_c]}/u,'&\1;').
+        gsub(/[\\]{2}/m,'<br>')
+    end
+  end
+  class Tune
+    include SiSU_Parts_HTML
+    def initialize(data,md)
+      @data,@md=data,md
+      @sys=SiSU_Env::SystemCall.new
+      @env=SiSU_Env::InfoEnv.new(@md.fns,@md)
+    end
+    def songsheet
+      begin
+        @cX=SiSU_Screen::Ansi.new(@md.opt.act[:color_state][:set]).cX
+        if (@md.opt.act[:verbose][:set]==:on \
+        || @md.opt.act[:verbose_plus][:set]==:on \
+        || @md.opt.act[:maintenance][:set]==:on)
+          SiSU_Screen::Ansi.new(@md.opt.act[:color_state][:set],'Tune').txt_grey
+        end
+        songsheet_array(@data)
+        #data=songsheet_array(@data)
+        if @md.opt.act[:maintenance][:set]==:on #Hard Output Tune Optional on/off here
+          SiSU_HTML_Tune::Output.new(@data,@md).hard_output
+          SiSU_HTML_Tune::Output.new(@data,@md).marshal
+        end
+        SiSU_HTML_Tune::Tune.new(@data,@md).output
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    def songsheet_array(data)
+      data_tuned=[]
+      data.each do |dob|
+        dob=amp_angle_brackets(dob)
+        dob=endnotes_html(dob)
+        dob=url_markup(dob)
+        dob=markup(dob)
+        data_tuned << dob
+      end
+      data_tuned
+    end
+    def urls(data)
+      @words=data.each.map do |word|
+        if word=~/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)/
+          http_=true
+          if word =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/
+            m,u=/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/.match(word).captures
+          elsif word =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:rel_o]}:\S+?#{Mx[:rel_c]}/
+            #http_=false
+            m,u=/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}:(\S+?)#{Mx[:rel_c]}/.match(word).captures
+            u="#{Xx[:html_relative2]}/" + u
+          elsif word =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}/
+            http_=false
+            m,u=/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}(\S+?)#{Mx[:rel_c]}/.match(word).captures
+          elsif word =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}image/
+            m,u=/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}(image)/.match(word).captures
+          end
+          case m
+          when /\.png|\.jpg|\.gif|c=|\s\d+x\d+/
+            w,h=/\s(\d+)x(\d+)/.match(m).captures if m =~/\s\d+x\d+/
+            w=%{width="#{w}"} if w
+            h=%{height="#{h}"} if h
+            c=m[/"(.+?)"/m,1]
+            caption=%{<br><p class="caption">#{c}</p>} if c
+            png=m.scan(/\S+/)[0]
+            image_path=@md.file.output_path.html_seg.rel_image
+            #image_path=(@md.fns =~/\.-ss[tm]$/) \
+            #? @env.url.images_external
+            #: @env.url.images_local
+            ins=if u \
+            and u.strip !~/^image$/
+              %{<a href="#{u}"><img src="#{image_path}/#{png}" #{w} #{h} naturalsizeflag="0" align="bottom" border="0"></a>#{caption}}
+            else %{<img src="#{image_path}/#{png}" #{w} #{h} naturalsizeflag="0" align="bottom" border="0">#{caption}}
+            end
+            word=word.gsub(/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|image)/,ins)
+          else
+            link=m[/(.+)/m]
+            png=m.scan(/\S+/)[0].strip
+            link=link.strip
+            u=u.gsub(/(\S+)/,"#{Xx[:segment]}#\\1") if u !~/\// unless http_ #marker: in scroll remove; in seg replace
+            ins=%{<a href="#{u}">#{link}</a>}
+            word=word.gsub(/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/,ins).
+              gsub(/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}/,ins)
+          end
+          word
+        else word
+        end
+      end.join(' ')
+    end
+    def url_markup(dob)
+      unless dob.is==:code
+        if dob.obj =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)/
+          @word_mode=dob.obj.scan(/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)[()\[\]]*[,.;:!?'"]{0,2}|(?:#{Mx[:gl_o]}\S+?#{Mx[:gl_c]})+|[^#{Mx[:lnk_o]}#{Mx[:lnk_c]}]+/mu)
+          words=urls(@word_mode)
+          dob.obj=dob.obj.gsub(/.+/m,words)
+        end #consider change, do a while loop
+        dob.obj=dob.obj.gsub(/\\copyright/i,%{<sup>&copy;</sup>})
+        if (dob.obj !~/\<:ad\s+\.\.\//)
+          dob.obj=dob.obj.gsub(/\<:ad\s+(\S+)?\s+(\S+\.png)\s+(.+)?\;\s+(.+)?\;\s*!\>/,
+            %{\n<center><a href="http:\/\/\\1" target="external"><img src="#{@env.url.images_local}/\\2" alt="\\3"></a></center>\n})
+        else
+          dob.obj=dob.obj.gsub(/\<:ad\s+(\S+)?\s+(\S+\.png)\s+(.+)?\;\s+(.+)?\;\s*\>/,
+            %{\n<center><a href="\\1" target="_top"><img src="#{@env.url.images_local}/\\2" alt="\\3"></a></center>\n})
+        end
+        dob.obj=dob.obj.gsub(/!pick/,%{<img border="0" height="15" width="15" src="#{@env.url.images}/#{the_icon.i_choice}" alt="stellar">}).
+          gsub(/!new/,%{&nbsp;<img border="0" height="15" width="15" src="#{@env.url.images}/#{the_icon.i_new}" alt="new">}).
+          gsub(/<:h(.{1,7}?)>/,'<a href="#h\1">\1</a>').
+          gsub(/<:to(\d{1,7}?)>/,'<a href="#to\1">to&nbsp;{&nbsp;\1&nbsp;}</a> ').
+          gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,'<a href="\1" target="_top">\1</a>'). #http ftp matches escaped, no decoration
+          gsub(/#{Mx[:url_o]}([a-zA-Z0-9._-]+\@\S+?\.[a-zA-Z0-9._-]+)#{Mx[:url_c]}/,%{#{the_url_decoration.xml_open}<a href="mailto:\\1">\\1</a>#{the_url_decoration.xml_close}}).
+          gsub(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,%{#{the_url_decoration.xml_open}<a href="\\1" target="_top">\\1</a>#{the_url_decoration.xml_close}}) #http ftp matches with decoration
+        if dob.obj =~/#{Xx[:html_relative2]}\/\S+/ \
+        and dob.obj !~/(\"#{Xx[:html_relative2]}\/\S+?\"|>\s*#{Xx[:html_relative2]}\/\S+<)/
+          dob.obj=dob.obj.gsub(/(#{Xx[:html_relative2]}\/\S+)/,'<a href="\1">\1</a>')
+        end
+        if dob.obj =~/..\/\S+/ \
+        and dob.obj !~/(\"..\/\S+?\"|>\s*..\/\S+<)/
+          dob.obj=dob.obj.gsub(/\.\.(\/\S+)/,%{<a href="#{Xx[:html_relative2]}\1">\1</a>})
+        end
+        dob.obj=dob.obj.gsub(/<a href=":/,%{<a href="#{the_url.site}/}).
+          gsub(/<a href="\.\.\//,%{<a href="#{the_url.site}/}).
+          gsub(/<a href="#{Xx[:html_relative2]}\//,%{<a href="#{the_url.site}/})
+      else
+        dob.obj=dob.obj.gsub(/</m,'&lt;').gsub(/>/m,'&gt;')
+      end
+      dob
+    end
+    def amp_angle_brackets(dob)
+      dob.obj=dob.obj.
+        gsub(/&/u,'&amp;').
+        gsub(/<([a-z:\/]+)>/,"#{Dx[:lt_xml]}\\1#{Dx[:gt_xml]}").
+        gsub(/</u,'&lt;').gsub(/>/u,'&gt;')
+      dob
+    end
+    def endnotes_html(dob)
+      unless dob.is ==:code
+        dob.obj=dob.obj.gsub(/(#{Mx[:en_a_o]}|#{Mx[:en_b_o]})(\d+)\s+(.+?)(#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/,
+            %{&nbsp;<a href="##{Mx[:note]}\\2"><note id="#{Mx[:note_ref]}\\2">&nbsp;<sup>\\2</sup>&nbsp;</note></a> } +
+            %{\\1\\2 <a href="##{Mx[:note_ref]}\\2"><note id="#{Mx[:note]}\\2">&nbsp;<sup>\\2.</sup></note></a> \\3 \\4}).
+          gsub(/(#{Mx[:en_b_o]})([*+]\d+)\s+(.+?)(#{Mx[:en_b_c]})/,
+            %{&nbsp;<a href="##{Mx[:note]}\\2"><note id="#{Mx[:note_ref]}\\2">&nbsp;<sup>\\2</sup>&nbsp;</note></a> } +
+            %{\\1\\2 <a href="##{Mx[:note_ref]}\\2"><note id="#{Mx[:note]}\\2">&nbsp;<sup>\\2.</sup></note></a> \\3 \\4}).
+          gsub(/(#{Mx[:en_a_o]})([*+]+)\s+(.+?)(#{Mx[:en_a_c]})/,
+            %{&nbsp;<a href="##{Mx[:note]}\\2"><note id="#{Mx[:note_ref]}\\2">&nbsp;<sup>\\2</sup>&nbsp;</note></a> } +
+            %{\\1\\2 <a href="##{Mx[:note_ref]}\\2"><note id="#{Mx[:note]}\\2">&nbsp;<sup>\\2</sup></note></a> \\3 \\4})
+      end
+      dob
+    end
+    def markup(dob)
+      dob.obj=dob.obj.gsub(/#{Mx[:mk_o]}#([a-zA-Z]+)#{Mx[:mk_c]}/,'&\1;').
+        gsub(/#{Mx[:mk_o]}(#[0-9]+)#{Mx[:mk_c]}/,'&\1;')
+      dob.obj=dob.obj.gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/,'<br>') unless dob.is==:table
+      dob.obj=dob.obj.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'<b>\1</b>').
+        gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'<i>\1</i>').
+        gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'<u>\1</u>').
+        gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'<sup>\1</sup>').
+        gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'<sub>\1</sub>').
+        gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'<ins>\1</ins>').
+        gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'<cite>\1</cite>').
+        gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'<del>\1</del>').
+        gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,'<tt>\1</tt>'). # tt, kbd
+        gsub(/#{Mx[:mk_o]}:name#(\S+?)#{Mx[:mk_c]}/,'<a name="\1"></a>').
+        gsub(/#{Mx[:gl_bullet]}/m,'●&nbsp;&nbsp;').
+        gsub(/#{Mx[:nbsp]}/,'&nbsp;').
+        gsub(/<(p|br) \/>/,'<\1>')
+      dob=SiSU_HTML_Tune::CleanHTML.new(dob).clean
+      dob
+    end
+    def output
+      data=@data
+      @tuned_file=data.each.map do |dob|
+        dob.obj=dob.obj.strip.chomp
+        dob
+      end
+      @tuned_file << "\n<EOF>" if (@md.fns =~/\.sst0/) #remove
+      @tuned_file
+    end
+  end
+end
+__END__
+#+END_SRC
+
+*** html_scroll.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/html_scroll.rb"
+# <<sisu_document_header>>
+module SiSU_HTML_Scroll
+  require_relative 'html_shared'                        # html_shared.rb
+  require_relative 'html'                               # html.rb
+  require_relative 'shared_metadata'                    # shared_metadata.rb
+  require_relative 'html_promo'                         # html_promo.rb
+  class Scroll
+    def initialize(md='',data='',endnotes='')
+      @md,@data,@endnotes=md,data,endnotes
+    end
+    def songsheet
+      begin
+        scr=SiSU_HTML_Scroll::Scroll.new(@md,@data,@endnotes).markup
+        scr[:tails]=SiSU_HTML_Scroll::Scroll.new(@md).tails
+        scr
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+  protected
+    def markup
+      data=@data
+      @rcdc=false
+      @scr={ body: [], metadata: [], owner_details: [] }
+      data.each do |dob|
+        dob.obj=dob.obj.gsub(/#{@md.file.output_path.html_seg.rel_image}/m,
+          @md.file.output_path.html_scroll.rel_image)
+        if defined? dob.name and dob.name =~/^meta/ \
+        and dob.obj =~/Document Information/
+          dob.obj=dob.obj.
+            gsub(/(Document Information(?: \(metadata\))?)/,
+              '\1<a name="docinfo"></a>')
+        end
+        if dob.obj =~/^Metadata$/ \
+        and dob.lv =='B'
+          dob.obj=dob.obj.gsub(/Metadata/,'') #dob.obj=''
+        end
+        if defined? dob.name \
+        and dob.name =~/^metadata/ \
+        and dob.lv =='1' \
+        and dob.obj =~/SiSU Metadata, document information/
+          @rcdc=true
+        end
+        dob.obj=dob.obj.gsub(/href="[a-z0-9._-]+(#\S+?")/m,'href="\1'). # internal document links
+          gsub(/href="#{Xx[:segment]}/m,'href="')
+        if dob.obj !~/(^#{Rx[:meta]}|#{Mx[:br_eof]})/
+          unless dob.is ==:code
+            dob.obj=dob.obj.
+              gsub(/(?:#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})\s*/m,' ')
+          end
+          if defined? dob.ocn
+            @p_num=SiSU_HTML_Format::ParagraphNumber.new(@md,dob.ocn)
+          end
+          sto=SiSU_HTML_Format::FormatTextObject.new(@md,dob)
+          para_html=if dob.is==:heading
+            x=if dob.ln==0
+              sto.heading_body0
+            elsif dob.ln==1
+              sto.heading_body1
+            elsif dob.ln==2
+              sto.heading_body2
+            elsif dob.ln==3
+              sto.heading_body3
+            elsif dob.ln==4
+              sto.heading_body4
+            elsif dob.ln==5
+              sto.heading_body5
+            elsif dob.ln==6
+              sto.heading_body6
+            elsif dob.ln==7
+              sto.heading_body7
+            end
+          elsif dob.is==:break \
+          and dob.from==:markup
+            '<br><hr width=90% /><br>'
+          elsif dob.is==:heading_insert
+            x=if dob.ln==0
+              unless dob.obj.empty?
+                sto.heading_body0
+              end
+            elsif dob.ln==1
+              unless dob.obj.empty?
+                sto.heading_body1
+              end
+            elsif dob.ln==2
+              unless dob.obj.empty?
+                sto.heading_body2
+              end
+            elsif dob.ln==3
+              unless dob.obj.empty?
+                sto.heading_body3
+              end
+            elsif dob.ln==4 \
+            and dob.obj !~/^(?:Endnotes|Index|Metadata|Manifest)$/
+              unless dob.obj.empty?
+                sto.heading_body4
+              end
+            elsif dob.ln==4 \
+            and dob.obj=='Endnotes'
+              sto.heading_body4
+              @endnotes.join("\n")
+            elsif dob.ln==4 \
+            and dob.obj=='Index'
+              sto.heading_body4
+              book_idx=SiSU_Particulars::CombinedSingleton.
+                instance.get_idx_html(@md.opt).html_idx
+              book_idx.each do |y| #takes book index prepared for segments & strips segment identifying info
+                y.gsub!(/<a href="\S+?\.html#(\d+)">(\1(?:-\d+)?)<\/a>/,
+                  '<a href="#\1">\2</a>')
+              end
+              book_idx.join("\n")
+            elsif dob.ln==5
+              unless dob.obj.empty?
+                sto.heading_body5
+              end
+            elsif dob.ln==6
+              unless dob.obj.empty?
+                sto.heading_body6
+              end
+            elsif dob.ln==7
+              unless dob.obj.empty?
+                sto.heading_body7
+              end
+            end
+          elsif dob.is==:para
+            if dob.indent \
+            and dob.hang \
+            and dob.indent =~/[0-9]/ \
+            and dob.hang =~/[0-9]/
+              if dob.bullet_
+                (dob.indent =~/[1-9]/) \
+                ? sto.format('li',"i#{dob.indent}")
+                : sto.format('li','bullet')
+              elsif dob.indent == dob.hang
+                sto.format('p',"i#{dob.indent}")
+              elsif dob.indent != dob.hang
+                sto.format('p',"h#{dob.hang}i#{dob.indent}")
+              else sto.para
+              end
+            else sto.para
+            end
+          elsif dob.is==:block
+            sto.block
+          elsif dob.is==:group
+            sto.group
+          elsif dob.is==:alt
+            sto.alt
+          elsif dob.is==:verse
+            sto.verse
+          elsif dob.is==:code
+            sto.code
+          elsif dob.is==:table
+            sto.table
+          elsif dob.is==:break
+          end
+          if dob.obj =~/<a name="n\d+">/ \
+          and dob.obj =~/^(?:\^~\d+\s|<!e[:_]\d+!>)/ # hmmm re-adjusted 200507, for alt endnote which should again be matched ^~ ... not in response to problem though
+            dob.obj=''
+          end
+          unless @rcdc
+            @scr[:body] << para_html unless para_html =~/\A\s*\Z/
+          end
+        end
+      end
+      @scr
+    end
+    def tails
+      scr_tail=[]
+      format_head_scroll=SiSU_HTML_Format::HeadToc.new(@md)
+      scr_tail \
+      << format_head_scroll.scroll_tail \
+      << format_head_scroll.html_close
+      scr_tail
+    end
+  end
+end
+__END__
+#+END_SRC
+
+*** html_segments.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/html_segments.rb"
+# <<sisu_document_header>>
+module SiSU_HTML_Seg
+  require_relative 'html_shared'                        # html_shared.rb
+  require_relative 'html'                               # html.rb
+  require_relative 'html_persist'                       # html_persist.rb
+  require_relative 'html_promo'                         # html_promo.rb
+  require_relative 'shared_metadata'                    # shared_metadata.rb
+  class Output
+    def initialize(md,outputfile,per,minitoc,type='')
+      @md, @output_seg_file,@per,@minitoc,@type=
+        md,outputfile,      per,minitoc,  type
+      @title_banner_=SiSU_Env::CreateSite.new(@md.opt).html_seg_title_banner?
+      @file=SiSU_Env::FileOp.new(@md)
+      @make=SiSU_Env::ProcessingSettings.new(@md)
+      @cl=(@make.build.html_minitoc?) \
+      ? 'content'
+      : 'content0'
+    end
+    def output
+      if @per.title =~/\S/
+        filename_seg=[]
+        if @make.build.html_top_band?
+          filename_seg \
+          << @per.title \
+          << @per.tocband_banner
+        else
+          filename_seg \
+          << @per.title
+        end
+        if @type=='endnotes'
+          @per.headings=[]
+          format_head_seg=SiSU_HTML_Format::HeadSeg.new(@md)
+          if @title_banner_
+            @per.headings \
+            << format_head_seg.
+              title_banner(@md.title.main,@md.title.sub,@author)
+          end
+          txt_obj={ txt: 'Endnotes', ocn_display: '' }
+          format_seg=SiSU_HTML_Format::FormatSeg.new(@md,txt_obj)
+          @per.headings \
+          << format_seg.title_heading1
+          filename_seg \
+          << @per.heading_endnotes \
+          << @minitoc << @per.headings \
+          << %{\n<div class="#{@cl}">\n} \
+          << @per.endnote_all \
+          << '</div>' # << '</div>'
+        elsif @type=='idx'
+          @per.headings=[]
+          format_head_seg=SiSU_HTML_Format::HeadSeg.new(@md)
+          if @title_banner_
+            @per.headings \
+            << format_head_seg.
+              title_banner(@md.title.main,@md.title.sub,@author)
+          end
+          txt_obj={ txt: 'Index', ocn_display: '' }
+          format_seg=SiSU_HTML_Format::FormatSeg.new(@md,txt_obj)
+          @per.headings << format_seg.title_heading1
+          filename_seg \
+          << @per.heading_idx \
+          << @minitoc << @per.headings \
+          << %{\n<div class="#{@cl}">\n} \
+          << @per.idx \
+          << '</div>' # << '</div>'
+        elsif @type=='metadata'
+          metadata=SiSU_Metadata::Summary.new(@md).html_display.metadata
+          @per.headings=[]
+          format_head_seg=SiSU_HTML_Format::HeadSeg.new(@md)
+          if @title_banner_
+            @per.headings \
+            << format_head_seg.
+              title_banner(@md.title.main,@md.title.sub,@author)
+          end
+          txt_obj={ txt: 'Metadata', ocn_display: '' }
+          format_seg=SiSU_HTML_Format::FormatSeg.new(@md,txt_obj)
+          @per.headings \
+          << format_seg.title_heading1
+          filename_seg \
+          << @per.heading_idx \
+          << @minitoc \
+          << @per.headings \
+          << %{\n<div class="#{@cl}">\n} \
+          << metadata \
+          << '</div>' # << '</div>'
+        else
+          if @make.build.html_top_band?
+            filename_seg \
+            << @minitoc \
+            << @per.headings \
+            << @per.main \
+            << "\n</div>\n"
+          else
+            filename_seg \
+            << @minitoc \
+            << @per.main \
+            << "\n</div>\n"
+          end
+        end
+        filename_seg <<=if @make.build.html_top_band?
+          @per.tail \
+          << @per.tocband_bannerless \
+          << @per.credits
+        else
+          @per.tail \
+          << @per.credits
+        end
+        filename_seg=filename_seg.flatten.compact #watch
+        filename_seg.each do |str|
+          unless str =~/\A\s*\Z/
+            str=str.strip.
+              gsub(Xx[:html_relative2],
+                @file.path_rel_links.html_seg_2).
+              gsub(Xx[:html_relative1],
+                @file.path_rel_links.html_seg_1)
+            @output_seg_file << str
+          end
+        end
+        @output_seg_file.close
+      end
+    end
+  end
+  class Seg
+    @@seg_url=''
+    @@tracker=0
+    @@seg_name=[]
+    attr_reader :seg_name_x,:seg_name_x_tracker
+    def initialize(md=nil,data='')
+      @md,@data=md,data
+      @per=SiSU_HTML_Persist::Persist.new
+      @seg_name_x=@per.seg_name_x=(@@seg_name || [])
+      @seg_name_x_tracker=@per.seg_name_x_tracker=(@@tracker || 0)
+      @env=SiSU_Env::InfoEnv.new(@md.fns) if @md
+      if @md
+        @make=SiSU_Env::ProcessingSettings.new(@md)
+        @cl=(@make.build.html_minitoc?) \
+        ? 'content'
+        : 'content0'
+      else @cl='content'
+      end
+      if @md
+        @title_banner_=SiSU_Env::CreateSite.new(@md.opt).html_seg_title_banner?
+      end
+    end
+    def songsheet
+      begin
+        @minitoc=SiSU_HTML::Source::Toc.new(@md,@data).minitoc
+        @per=SiSU_HTML_Persist::Persist.new
+        data=get_subtoc_endnotes(@data,@per)
+        data=articles(data,@per)
+        cleanup(@md,@per) # (((( added ))))
+        #### (((( END )))) ####
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        SiSU_HTML_Persist::Persist.new.persist_init
+        @@seg_name=@per.seg_name=[]
+      end
+    end
+  protected
+    def articles(data,per)
+      @per=per
+      tracking,newfile=0,0
+      printed_endnote_seg='n'
+      idx_html=nil
+      if @md.book_idx
+        #my_make_source_file=SiSU_Env::CreateFile.new(@md.fns)
+        idx_html=SiSU_Particulars::CombinedSingleton.
+          instance.get_idx_html(@md.opt).html_idx
+        idx_html.each do |x|
+          @per.idx << x
+        end
+        @per.heading_idx=''
+      end
+      data.each do |dob|
+        if (dob.is == :heading \
+        || dob.is == :heading_insert) \
+        && dob.ln == 4
+          @@seg_name << dob.name
+          @per.seg_name = @@seg_name
+          dob.name
+        end
+      end
+      @per.seg_name_x=@per.seg_name
+      @per.seg_name.length
+      testforartnum=@per.seg_name_x
+      if (@md.opt.act[:verbose][:set]==:on \
+      || @md.opt.act[:verbose_plus][:set]==:on \
+      || @md.opt.act[:maintenance][:set]==:on)
+        SiSU_Screen::Ansi.new(
+          @md.opt.act[:color_state][:set],
+          @per.seg_name.length
+        ).segmented
+      end
+      map_nametags=SiSU_Particulars::CombinedSingleton.
+        instance.get_map_nametags(@md).nametags_map #p map_nametags
+      data.each do |dob|
+        if defined? dob.obj \
+        and dob.obj =~/href="#{Xx[:segment]}#+\S+?"/
+          while dob.obj =~/href="#{Xx[:segment]}#+(\S+?)"/
+            m=$1
+            if map_nametags[m] \
+            and map_nametags[m][:segname]
+              inf=SiSU_Env::FileOp.new(@md) if @md
+              lng=(inf.output_dir_structure.by_language_code?) \
+              ? ''
+              : '.' + @md.opt.lng
+              dob.obj.sub!(/href="#{Xx[:segment]}#+(\S+?)"/,
+                %{href="#{map_nametags[m][:segname]}#{lng}#{Sfx[:html]}#\\1"})
+            else
+              p "NOT FOUND name_tags: #{m}"
+              dob.obj.sub!(/href="#{Xx[:segment]}#+(\S+?)"/,
+                %{href="#\\1"}) # not satisfactory
+            end
+          end
+        end
+        if (dob.is==:heading \
+        || dob.is==:heading_insert) \
+        && dob.ln==4
+          @per.heading4=dob.obj
+          @per.is4=newfile=1
+        end
+        if (dob.is==:heading \
+        || dob.is==:heading_insert) \
+        && dob.ln==3
+          @per.heading3=dob.obj
+          @per.is4,@per.is3=0,1
+        end
+        if (dob.is==:heading \
+        || dob.is==:heading_insert) \
+        && dob.ln==2
+          @per.heading2=dob.obj
+          @per.is4,@per.is3,@per.is2=0,0,1
+        end
+        if (dob.is==:heading \
+        || dob.is==:heading_insert) \
+        && dob.ln==1
+          @per.heading1=dob.obj
+          @per.is4,@per.is3,@per.is2,@per.is1=0,0,0,1
+        end
+        if (dob.is==:heading \
+        || dob.is==:heading_insert) \
+        && dob.ln==0
+          @per.heading0=dob.obj
+          @per.is4,@per.is3,@per.is2,@per.is1,@per.is0=0,0,0,0,1
+        end
+        if (@per.is1 && !@per.is2 && !@per.is3 && !@per.is4)
+          if not (dob.is==:heading \
+          || dob.is==:heading_insert) \
+          && dob.ln==0
+            $_ #; check
+          end
+        end
+        if @per.is4==1
+          if newfile==1 \
+          or dob.obj =~/^#{Mx[:br_endnotes]}|^#{Mx[:br_eof]}/
+            newfile=0
+            if (dob.is==:heading \
+            || dob.is==:heading_insert) \
+            && dob.ln==4
+              if tracking != 0
+                @file=SiSU_Env::FileOp.new(@md)
+                unless FileTest.directory?(@file.output_path.html_seg.dir)
+                  FileUtils::mkdir_p(@file.output_path.html_seg.dir) \
+                    if File.writable?("#{@file.output_path.base.dir}/.")
+                end
+                tail(@md,@per)
+                #SiSU_HTML_Seg::Seg.new(@md,@per).tail
+                fnh={
+                  fn: @per.seg_name_x[tracking-1],
+                }
+                fn=@md.file.base_filename.html_seg(fnh)
+                segfilename="#{@file.output_path.html_seg.dir}/#{fn}"
+                output_seg_file=File.new(segfilename,'w') if @per.seg_name_x[tracking-1]
+                minitoc=(@make.build.html_minitoc?) ? @minitoc : ''
+                if dob.is==:heading \
+                || (@per.seg_name_x[tracking-1] !~/endnotes|book_index|metadata/)
+                  SiSU_HTML_Seg::Output.new(@md,output_seg_file,@per,minitoc).output
+                elsif dob.is==:heading_insert
+                  if @per.seg_name_x[tracking-1]=='endnotes'
+                    SiSU_HTML_Seg::Output.new(@md,output_seg_file,@per,minitoc,'endnotes').output
+                  elsif @per.seg_name_x[tracking-1]=='book_index'
+                    SiSU_HTML_Seg::Output.new(@md,output_seg_file,@per,minitoc,'idx').output
+                    @per.idx=[]
+                  elsif @per.seg_name_x[tracking-1]=='metadata'
+                    SiSU_HTML_Seg::Output.new(@md,output_seg_file,@per,minitoc,'metadata').output
+                  else puts "#{__FILE__}::#{__LINE__}"
+                  end
+                else puts "#{__FILE__}::#{__LINE__}"
+                end
+                SiSU_HTML_Seg::Seg.new.reinitialise(per)
+                #per=persist_init
+                heading_art(dob)
+                head(dob)
+               #keep use for last segment, eg if metadata is last segment
+                if @per.seg_name_x[tracking] =='metadata' # this is for metadata
+                  fnh={
+                    fn: @per.seg_name_x[tracking],
+                  }
+                  fn=@md.file.base_filename.html_seg(fnh)
+                  segfilename="#{@file.output_path.html_seg.dir}/#{fn}"
+                  output_seg_file=File.new(segfilename,'w')
+                  SiSU_HTML_Seg::Output.new(@md,output_seg_file,@per,minitoc,'metadata').output
+                  #per=persist_init
+                  Seg.new.reinitialise(per)
+                end
+              end
+              if tracking==0
+                heading_art(dob)
+                head(dob)
+              end
+            end
+            tracking=tracking+1
+          end
+          if (dob.is==:heading \
+          || dob.is==:heading_insert) \
+          && dob.ln==4 \
+          && dob.name
+            @per.get_hash_to=dob.name
+            @per.get_hash_fn=dob.name
+          end
+          if dob.obj.is_a?(String)
+            markup(dob)
+          elsif dob.obj.is_a?(Array)
+            dob.obj.each do |pg|
+              markup(pg)
+            end
+          end
+          if testforartnum[tracking-1] =~/endnote/
+            if printed_endnote_seg=='n'
+              printed_endnote_seg='y'
+            end
+          end
+        end
+      end
+      data
+    end
+    def heading_art(dob)
+      format_head_seg=SiSU_HTML_Format::HeadSeg.new(@md)
+      @per.dot_nav=if (@make.build.html_navigation?) \
+      && (@make.build.html_navigation_bar?)
+        x=if (dob.is==:heading \
+        || dob.is==:heading_insert) \
+        && (dob.ln.to_s =~/^[0-7]/)
+          x=if @@tracker < @per.seg_name.length-1
+            format_head_seg.dot_control_pre_next
+          else
+            format_head_seg.dot_control_pre
+          end
+        else @per.dot_nav
+        end
+      else @per.dot_nav=''
+      end
+      ads=SiSU_HTML_Promo::Ad.new(@md)
+      @per.title=format_head_seg.head_seg << ads.div.major
+    end
+    def head(dob)
+      clean=/<!.*?!>|<:.*?>/
+      format_head_seg=SiSU_HTML_Format::HeadSeg.new(@md)
+      if @make.build.html_navigation?
+        if @@tracker < @per.seg_name.length-1
+          @per.segtocband=if @@tracker==0
+            format_head_seg.toc_next2
+          else
+            format_head_seg.toc_pre_next2
+          end
+        else @per.segtocband=format_head_seg.toc_pre2
+        end
+      else @per.segtocband=''
+      end
+      @p_num ||= ''
+      if @per.is0==1
+        @author=%{<b>#{@md.author}</b>\n} if @md.author.to_s =~/\S/
+        @per.tocband_banner \
+        << format_head_seg.navigation_band(@per.segtocband,@per.dot_nav)
+        @per.tocband_bannerless \
+        << '<br>' \
+        << format_head_seg.navigation_band_bottom(@per.segtocband,@per.dot_nav)
+        if @title_banner_
+          @per.headings \
+          << format_head_seg.title_banner(@md.title.main,@md.title.sub,@author).gsub(clean,'')
+        end
+        ocn=(@per.heading0[/.+?#{Mx[:id_o]}~(\d+);(?:[oh]|[0-6]:)\d+;\w\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}$/]) \
+        ? $1
+        : ''
+        @p_num=SiSU_HTML_Format::ParagraphNumber.new(@md,ocn)
+        txt_obj={ txt: @per.heading0, ocn_display: @p_num.ocn_display }
+        format_seg=SiSU_HTML_Format::FormatSeg.new(@md,txt_obj)
+        @per.headings \
+        << format_seg.title_heading0.gsub(clean,'')
+        @per.heading0=@per.heading0.
+          gsub(/&nbsp;<a name="-[\d*+]+" href="#_[\d*+]+">&nbsp;<sup>[\d*+]+<\/sup>&nbsp;<\/a>/,'')
+      end
+      if @per.is1==1
+        heading1=@per.heading1
+        ocn=(heading1[/.+?#{Mx[:id_o]}~(\d+);(?:[oh]|[0-6]:)\d+;\w\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}$/]) \
+        ? $1
+        : ''
+        @p_num=SiSU_HTML_Format::ParagraphNumber.new(@md,ocn)
+        txt_obj={ txt: heading1, ocn_display: @p_num.ocn_display }
+        format_seg=SiSU_HTML_Format::FormatSeg.new(@md,txt_obj)
+        @per.headings \
+        << format_seg.title_heading1.gsub(clean,'')
+        @per.heading1=@per.heading1.
+          gsub(/&nbsp;<a name="-[\d*+]+" href="#_[\d*+]+">&nbsp;<sup>[\d*+]+<\/sup>&nbsp;<\/a>/,'')
+      end
+      if @per.is2==1
+        heading2=@per.heading2
+        ocn=(heading2[/.+?#{Mx[:id_o]}~(\d+);(?:[oh]|[0-6]:)\d+;\w\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}$/]) \
+        ? $1
+        : ''
+        @p_num=SiSU_HTML_Format::ParagraphNumber.new(@md,ocn)
+        txt_obj={ txt: heading2, ocn_display: @p_num.ocn_display }
+        format_seg=SiSU_HTML_Format::FormatSeg.new(@md,txt_obj)
+        @per.headings \
+        << format_seg.title_heading2.gsub(clean,'')
+        @per.heading2=@per.heading2.
+          gsub(/&nbsp;<a name="-[\d*+]+" href="#_[\d*+]+">&nbsp;<sup>[\d*+]+<\/sup>&nbsp;<\/a>/,'')
+      end
+      if @per.is3==1
+        heading3=@per.heading3
+        ocn=(heading3[/.+?#{Mx[:id_o]}~(\d+);(?:[oh]|[0-6]:)\d+;\w\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}$/]) \
+        ? $1
+        : ''
+        @p_num=SiSU_HTML_Format::ParagraphNumber.new(@md,ocn)
+        txt_obj={ txt: heading3, ocn_display: @p_num.ocn_display }
+        format_seg=SiSU_HTML_Format::FormatSeg.new(@md,txt_obj)
+        @per.headings \
+        << format_seg.title_heading3.gsub(clean,'')
+        @per.heading3=@per.heading3.
+          gsub(/&nbsp;<a name="-[\d*+]+" href="#_[\d*+]+">&nbsp;<sup>[\d*+]+<\/sup>&nbsp;<\/a>/,'')
+      end
+      if @per.is4==1
+        heading4=@per.heading4
+        ocn=(heading4[/.+?#{Mx[:id_o]}~(\d+);(?:[oh]|[0-6]:)\d+;\w\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}$/]) \
+        ? $1
+        : ''
+        @p_num=SiSU_HTML_Format::ParagraphNumber.new(@md,ocn)
+        txt_obj={ txt: heading4, ocn_display: @p_num.ocn_display }
+        format_seg=SiSU_HTML_Format::FormatSeg.new(@md,txt_obj)
+        @per.headings \
+        << format_seg.title_heading4.gsub(clean,'')
+      end
+      @@tracker=@@tracker+1
+    end
+    def markup(dob)
+      @debug=[]
+      SiSU_HTML_Format::HeadSeg.new(@md)
+      if dob.is !=:meta
+        if dob.is==:heading \
+        || dob.is==:heading_insert \
+        || dob.is == :para
+          @p_num=SiSU_HTML_Format::ParagraphNumber.new(@md,dob.ocn)
+        end
+        sto=SiSU_HTML_Format::FormatTextObject.new(@md,dob)
+        dob_html=if dob.is == :heading \
+        || dob.is==:heading_insert \
+        || dob.is==:para
+          dob_html=if dob.is==:heading \
+          || dob.is==:heading_insert
+            if dob.ln==4
+              sto.seg_heading4
+            elsif dob.ln==5
+              sto.seg_heading5
+            elsif dob.ln==6
+              sto.seg_heading6
+            elsif dob.ln==7
+              sto.seg_heading6
+            end
+          elsif dob.is==:para
+            if dob.indent \
+            and dob.hang \
+            and dob.indent =~/[0-9]/ \
+            and dob.hang =~/[0-9]/
+              if dob.bullet_
+                if dob.indent =~/[1-9]/
+                  sto.format('li',"i#{dob.indent}")
+                else
+                  sto.format('li','bullet')
+                end
+              elsif dob.indent == dob.hang
+                sto.format('p',"i#{dob.indent}")
+              elsif dob.indent != dob.hang
+                sto.format('p',"h#{dob.hang}i#{dob.indent}")
+              else sto.para
+              end
+            else sto.para
+            end
+          end
+        elsif dob.is==:block
+          sto.block
+        elsif dob.is==:group
+          sto.group
+        elsif dob.is==:alt
+          sto.alt
+        elsif dob.is==:verse
+          sto.verse
+        elsif dob.is==:code
+          sto.code
+        elsif dob.is==:table
+          sto.table
+        elsif dob.is==:break \
+        and dob.from==:markup
+          '<br><hr width=90% /><br>'
+        end
+        if @md.flag_separate_endnotes
+          dob.obj=dob.obj.gsub(/"\s+href="#(#{Mx[:note]}\d+)">/,%{" href=\"endnotes#{Sfx[:html]}#\\1">})       #endnote- twice #removed file type
+        end
+        if (dob.is==:heading \
+        || dob.is==:heading_insert \
+        || dob.is==:para) \
+        && (not dob.ocn \
+        || (dob.ocn.to_s.empty?))
+          format_seg=SiSU_HTML_Format::FormatSeg.new(@md,dob)
+        end
+        dob.obj=dob.obj.gsub(/\s*(-\{{2}~\d+|<:e[:_]\d+>).*/,'')                   #potentially dagerous - removes all paragraphs with <!e_!> #?? workpoint
+        if dob.obj =~/<a name="_\d+" href="#-\d+">&nbsp;<sup>/                #endnote- note-
+          format_seg=SiSU_HTML_Format::FormatSeg.new(@md,dob)
+          dob=format_seg.no_paranum
+        end
+        if (dob.is==:heading \
+        || dob.is==:heading_insert) \
+        && dob.ln==4
+          @per.main << %{\n<div class="#{@cl}">\n}
+          @per.main << dob_html
+          if @make.build.segsubtoc?
+            @per.main << @per.seg_subtoc[@per.get_hash_fn]                       #% insertion of sub-toc
+          end
+        else
+          @per.main << dob_html #unless @@flag_alt==true
+        end
+      end
+    end
+    def tail(md,per)
+      @md,@per=md,per
+      format_head_seg=SiSU_HTML_Format::HeadSeg.new(@md)
+      if @md.flag_auto_endnotes \
+      and @per.seg_endnotes[@per.get_hash_fn]
+        @per.tail <<  %{\n<div class="#{@cl}">\n<div class="endnote">\n}
+        if @per.seg_endnotes[@per.get_hash_fn].flatten.length > 0
+          @per.tail << format_head_seg.endnote_mark
+          @per.tail << @per.seg_endnotes[@per.get_hash_fn].flatten #endnotes deposited at end of individual segments ||@|EXTRACTION OF ENDNOTES|
+        end
+        @per.tail << '</div>'
+        @per.tail << '</div>' #this div closes div class content
+      end
+      ads=SiSU_HTML_Promo::Ad.new(@md)
+      @per.credits \
+      << format_head_seg.credit \
+      << ads.div.close \
+      << ads.display \
+      << format_head_seg.html_close
+    end
+    def reinitialise(per)
+      per.title,per.dot_nav,per.tocband_banner,per.tocband_bannerless,per.headings,per.main,per.tail,per.credits=Array.new(8){[]}
+      @per.segtocband=nil
+    end
+    def cleanup(md,per)
+      #per=persist_init
+      reinitialise(per)
+      @@tracker=0
+      @per.seg_endnotes,@per.seg_subtoc={},{}
+      @per.seg_endnotes_array,@per.seg_subtoc_array=[],[]
+      per.endnote_all=[]
+    end
+    def get_subtoc_endnotes(data,per) #get endnotes & sub-table of contents subtoc
+      @per=per
+      data.each do |dob|
+        dob.obj=dob.obj.gsub(/<a name=\"h\d.*?\">(.+?)<\/a>/mi,'\1')
+        if @md.flag_auto_endnotes
+          if (dob.is==:heading \
+          || dob.is==:heading_insert) \
+          && (dob.ln.to_s =~/^[0-4]/) \
+          and not @per.fn.to_s.empty?
+            @per.seg_endnotes[@per.fn]=[]
+            @per.seg_endnotes[@per.fn] << @per.seg_endnotes_array
+            @per.seg_endnotes_array=[] if dob.ln==4
+          end
+          if (dob.is==:heading \
+          || dob.is==:heading_insert) \
+          && dob.ln==4                                              #%  EXTRACTION OF SUB-TOCs & SEGMENT NAME, after EXTRACTION OF ENDNOTES & SUB-TOCs
+            @per.seg_subtoc[@per.fn]=@per.seg_subtoc_array
+            @per.seg_subtoc_array=[]
+            if dob.name \
+            and dob.obj
+              @per.fn=dob.name
+            else
+              if dob.name =~/\S+/
+                @per.fn=dob.name
+              else @per.fn=''
+              end
+            end
+          end
+        end
+        if dob.is==:heading \
+        && (dob.ln.to_s =~/^[5-7]/)
+          case dob.ln
+          when 5
+            txt_obj={ txt: dob.obj.strip, ocn: dob.ocn }
+            format_seg=SiSU_HTML_Format::FormatSeg.new(@md,txt_obj)
+            subtoc=format_seg.subtoc_lev5 #keep and make available, this is the subtoc
+          when 6
+            txt_obj={ txt: dob.obj.strip, ocn: dob.ocn }
+            format_seg=SiSU_HTML_Format::FormatSeg.new(@md,txt_obj)
+            subtoc=format_seg.subtoc_lev6 #keep and make available, this is the subtoc
+          when 7
+            txt_obj={ txt: dob.obj.strip, ocn: dob.ocn }
+            format_seg=SiSU_HTML_Format::FormatSeg.new(@md,txt_obj)
+            subtoc=format_seg.subtoc_lev7 #keep and make available, this is the subtoc
+          end
+          @per.seg_subtoc_array << subtoc
+        end
+        if @md.flag_auto_endnotes
+          if (dob.obj =~/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})[\d*+]+\s*<a href="##{Mx[:note_ref]}[\d*+]+"/) \
+          && dob.is !=:code # endnote-
+            endnote_array=[]
+            if dob.obj=~/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}/m
+              endnote_array << dob.obj.scan(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}/m)
+            end
+            if dob.obj=~/#{Mx[:en_b_o]}[*]\d+\s.+?#{Mx[:en_b_c]}/m
+              endnote_array \
+              << dob.obj.scan(/#{Mx[:en_b_o]}[*]\d+\s.+?#{Mx[:en_b_c]}/m)
+            end
+            if dob.obj=~/#{Mx[:en_b_o]}[+]\d+\s.+?#{Mx[:en_b_c]}/m
+              endnote_array \
+              << dob.obj.scan(/#{Mx[:en_b_o]}[+]\d+\s.+?#{Mx[:en_b_c]}/m)
+            end
+            endnote_array=endnote_array.flatten.compact #watch, check compacting
+            endnote_array.each do |note|
+              note_match=note.dup
+              note_match_seg=note.dup
+              e_n=note_match_seg[/(?:#{Mx[:en_a_o]}[\d*+]+|#{Mx[:en_b_o]}[*+]\d+)\s+(.+?)(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/m,1]
+              try=e_n.split(/<br(?: \/)?>/)
+              try.each do |e|
+                txt_obj={ txt: e }
+                format_seg=SiSU_HTML_Format::FormatSeg.new(@md,txt_obj)
+                note_match=if e =~/#{Mx[:pa_o]}i[1-9]#{Mx[:pa_c]}/
+                  format_seg.endnote_body_indent
+                else format_seg.endnote_body
+                end
+                @per.seg_endnotes_array << note_match
+              end
+              try.join('<br>')
+              #% creation of separate end segment/page of all endnotes referenced back to reference segment
+              m=/(?:#{Mx[:en_a_o]}[\d*+]+|#{Mx[:en_b_o]}[*+]\d+)\s+(.+?href=")(##{Mx[:note_ref]}[\d*+]+".+)(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/mi
+              endnote_part_a=note_match_seg[m,1]
+              endnote_part_b=note_match_seg[m,2]
+              txt_obj={ endnote_part_a: endnote_part_a, endnote_part_b: endnote_part_b }
+              format_seg=SiSU_HTML_Format::FormatSeg.new(@md,txt_obj)
+              note_match_all_seg=format_seg.endnote_seg_body(@per.fn) #BUG WATCH 200408
+              @per.endnote_all << note_match_all_seg
+            end
+            dob.obj=dob.obj.gsub(/(?:#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})\s*/m,' ')
+          end
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+*** html_format.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/html_format.rb"
+# <<sisu_document_header>>
+module SiSU_HTML_Format
+  require_relative 'html_parts'                         # html_parts.rb
+  class ParagraphNumber
+    def initialize(md,ocn)
+      @md,@ocn=md,ocn.to_s
+      @ocn ||=''
+      @make=SiSU_Env::ProcessingSettings.new(@md)
+    end
+    def ocn_display
+      if @make.build.ocn?
+        if @ocn.to_i==0 \
+        or @ocn.empty?
+          ''
+        else
+          %{<label class="ocn"><a href="##{@ocn}" class="lnkocn">#{@ocn}</a></label>}
+        end
+      else
+        ''
+      end
+    end
+    def name
+      if @make.build.html_strict? \
+      or @ocn==(nil || @ocn.empty?)
+        ''
+      else
+        %{<a name="#{@ocn}"></a>}
+      end
+    end
+    def id #w3c? "tidy" complains about numbers as identifiers ! annoying
+      (@ocn==nil || @ocn.empty?) \
+      ? '' : %{id="#{Mx[:ocn_id_char]}#{@ocn}"}
+    end
+    def goto
+      (@ocn==nil || @ocn.empty?) \
+      ? '' : %{<a href="##{@ocn}">}
+    end
+  end
+  class HeadInformation
+    require_relative 'css'                              # css.rb
+    include SiSU_Parts_HTML
+    require_relative 'xml_shared'                       # xml_shared.rb
+    attr_reader :md,:rdf
+    def initialize(md)
+      @md=md
+      # DublinCore 1 - title
+      @bits=SiSU_Proj_HTML::Bits.new
+      @per=SiSU_HTML_Persist::Persist.new
+      @per.seg_name_x=SiSU_HTML::Seg.new.seg_name_x
+      @per.seg_name_x_tracker=SiSU_HTML::Seg.new.seg_name_x_tracker
+      @tocband_scroll,@tocband_segtoc=nil,nil
+      @stylesheet=SiSU_Style::CSS_HeadInfo.new(md).stylesheet
+      @o_str ||=SiSU_Env::ProcessingSettings.new(md).output_dir_structure
+      @index,@metalink='index','#metadata'
+      @toc=@md.file.base_filename.html_segtoc
+    end
+    def url_path_image_sys
+      (@o_str.dump_or_redirect?) \
+      ? './image'
+      : "#{Xx[:html_relative2]}_sisu/image_sys"
+    end
+    def icon
+      def up
+        'arrow_up_red.png'
+      end
+      def next
+        'arrow_next_red.png'
+      end
+      def previous
+        'arrow_prev_red.png'
+      end
+      def dot_clear
+        'dot_clear.png'
+      end
+      def dot_white
+        'dot_white.png'
+      end
+      def dot
+        dot_white
+      end
+      self
+    end
+    def png_nav
+      def toc
+        %{<img border="0" width="22" height="22" src="#{url_path_image_sys}/#{icon.up}" alt="toc" />}
+      end
+      def pre
+        %{<img border="0" width="22" height="22" src="#{url_path_image_sys}/#{icon.previous}" alt="&lt;&lt;&nbsp;previous" />}
+      end
+      def nxt
+        %{<img border="0" width="22" height="22" src="#{url_path_image_sys}/#{icon.next}" alt="next&nbsp;&gt;&gt;" />}
+      end
+      def dot_toc
+        %{<img border="0" width="100%" height="20" src="#{url_path_image_sys}/#{icon.dot}" alt="&#094;" />}
+      end
+      def dot_pre
+        %{<img border="0" width="100%" height="20" src="#{url_path_image_sys}/#{icon.dot}" alt="&lt;" />}
+      end
+      def dot_nxt
+        %{<img border="0" width="100%" height="20" src="#{url_path_image_sys}/#{icon.dot}" alt="&gt;" />}
+      end
+      self
+    end
+    def doc_types(page=:seg) #used in toc & seg_nav_band
+      wgt=SiSU_HTML_Format::Widget.new(@md)
+      %{
+<table summary="segment navigation available documents types: toc,doc,pdf,concordance" border="0" cellpadding="3" cellspacing="0">
+<tr>
+<td align="center" bgcolor=#{the_color.band2}>
+  #{wgt.manifest(page)}
+  #{wgt.search}
+</tr></table>}
+    end
+    def rdf
+      SiSU_XML_Tags::RDF.new(md)
+    end
+    def button_home(page=:seg)
+      button=%{ <table summary="home button / home information" border="0" cellpadding="3" cellspacing="0">\n <tr><td align="left" bgcolor="#ffffff">\n}
+      if @md.make.home_button_image.is_a?(Hash)
+        image_path=if page==:manifest
+          @md.file.output_path.manifest.rel_image
+        elsif  page==:scroll
+          @md.file.output_path.html_scroll.rel_image
+        else
+          @md.file.output_path.html_seg.rel_image
+        end
+        SiSU_Env::FileOp.new(@md)
+        button +=%{   <p class="tiny_left"><a href="#{@md.make.home_button_image[:link]}" target="_top"><img border="0" src="#{image_path}/#{@md.make.home_button_image[:home_button]}"  width="#{@md.make.home_button_image[:w]}" height="#{@md.make.home_button_image[:h]}" alt="home icon --&gt;" /></a></p>\n}
+      elsif @md.home_button_links.is_a?(Array)
+        @md.home_button_links.each do |links|
+          button +=%{  <p class="tiny_left"><a href="#{links[:url]}" target="_top">\n    #{links[:say]}\n  </a></p>\n}
+        end
+      end
+      button +=%{ </td></tr>\n </table>}
+      button
+    end
+    def html_close #moved
+    %{</body>
+</html>}
+    end
+  end
+  class Widget < HeadInformation
+    include SiSU_Parts_HTML
+    def initialize(md)
+      super(md)
+      @md=md
+      @cf_defaults=SiSU_Env::InfoProcessingFlag.new
+      @env=SiSU_Env::InfoEnv.new(md.fns)
+      @file=SiSU_Env::FileOp.new(md)
+      @o_str ||=SiSU_Env::ProcessingSettings.new(md).output_dir_structure
+      @make=SiSU_Env::ProcessingSettings.new(md)
+    end
+    def home
+      %{<td align="center" bgcolor=#{the_color.band2}>
+  <a href="../index.html" target="_top">
+  #{the_nav.txt_homepage}</a>
+</td>
+}
+    end
+    def scroll(text)
+      if @md.fns =~ /\.(?:-|ssm\.)?sst$/
+        %{<td align="center" bgcolor=#{the_color.band2}>
+  <a href="#{Xx[:html_relative1]}html/#{@file.base_filename.html_scroll}" target="_top">
+    #{text}
+  </a>
+</td>
+}
+      end
+    end
+    def seg(text)
+      %{<td align="center" bgcolor="#99CC66">
+  <a href="#{@md.file.base_filename.html_segtoc}" target="_top">
+    #{text}
+  </a>
+</td>
+}
+    end
+    def search
+      if @make.build.html_search_form?
+        env=SiSU_Env::InfoEnv.new(@md.fns,@md)
+        env.widget.search_form('sisusearch',nil,nil,true)
+      else ''
+      end
+    end
+    def manifest(page=:seg)
+      if @make.build.links_to_manifest? \
+      and not @o_str.dump_or_redirect?
+        manifest_lnk=if @file.output_dir_structure.by_language_code? \
+        or @file.output_dir_structure.by_filetype?
+          "#{Xx[:html_relative1]}manifest/#{@file.base_filename.manifest}"
+        else @file.base_filename.manifest
+        end
+        if page==:manifest
+          manifest_lnk="#{@md.file.output_path.manifest.url}/#{@file.base_filename.manifest}"
+          %{<td align="center" bgcolor=#{the_color.band2}>
+  <font face="#{the_font.set_fonts}" size="2">
+  #{the_url_decoration.xml_open}<a href="#{manifest_lnk}" target="_top">#{@md.file.output_path.manifest.url}/#{@file.base_filename.manifest}</a>#{the_url_decoration.xml_close}
+  </font>
+</td>}
+        else
+          %{<td align="center" bgcolor=#{the_color.band2}>
+  <a href="#{manifest_lnk}" target="_top">
+    #{the_nav.txt_manifest}
+  </a>
+</td>}
+        end
+      else ''
+      end
+    end
+  end
+  class XML
+  end
+  class HeadToc < HeadInformation
+    def initialize(md)
+      super(md)
+      @md=md
+      @o_str ||=SiSU_Env::ProcessingSettings.new(md).output_dir_structure
+      @make=SiSU_Env::ProcessingSettings.new(@md)
+      @file=SiSU_Env::FileOp.new(@md)
+    end
+    def scroll_head_navigation_band
+      if @make.build.html_top_band?
+        <<WOK
+<td align="center" width="60%">
+  #{make_scroll_search_form_and_manifest_link}
+</td>
+WOK
+        %{<table summary="table of contents scroll navigation band" id="toc" width="100%" bgcolor=#{the_color.band1}>
+<tr><td width="20%">
+  #{button_home(:scroll)}
+</td>
+<td width="75%" align="center">
+  #{doc_types}
+</td>
+<td width="20%">
+  &nbsp;
+#{the_table_close}
+<p>}
+      else ''
+      end
+    end
+    def concordance_navigation_band
+      up_button=if @make.build.html_navigation?
+        %{</td>
+<td width="5%" align="right">
+  &nbsp;<a href="toc.html" target="_top" alt="-&gt;">
+      #{png_nav.toc}
+    </a>&nbsp;
+}
+      else ''
+      end
+      if @make.build.html_top_band?
+        %{<table summary="concordance navigation band" id="toc" width="100%" bgcolor=#{the_color.band1}>
+<tr><td width="20%">
+  #{button_home}
+</td>
+<td width="75%" align="center">
+  #{doc_types}
+#{up_button}
+#{the_table_close}
+<p>}
+      else ''
+      end
+    end
+    def seg_head_navigation_band(page=:seg)
+      if @make.build.html_navigation?
+        if page==:manifest
+          nxt=(@file.output_dir_structure.by_language_code? \
+          || @file.output_dir_structure.by_filetype?) \
+          ? "../html/#{@md.fnb}/toc#{@md.lang_code_insert}#{Sfx[:html]}"
+          : "toc#{@md.lang_code_insert}#{Sfx[:html]}"
+          firstseg=%{<a href="#{nxt}" target="_top" alt="-&gt;">
+          #{png_nav.nxt}</a>}
+        elsif @md.firstseg =~/\S+/
+          firstseg=%{<a href="#{@md.firstseg}#{@md.lang_code_insert}#{Sfx[:html]}" target="_top" alt="-&gt;">
+        #{png_nav.nxt}</a>}
+        end
+      else ''
+      end
+      if @make.build.html_top_band?
+        %{<table summary="table of contents segment navigation band" id="toc" width="100%" bgcolor=#{the_color.band1}>
+<tr><td width="20%">
+#{button_home(page)}
+</td>
+<td width="75%" align="center">
+  #{doc_types(page)}
+</td>
+<td width="5%" align="right">
+  &nbsp;#{firstseg}&nbsp;
+#{the_table_close}
+<p>}
+      else ''
+      end
+    end
+    def manifest_link(text)
+#     @file=SiSU_Env::FileOp.new(@md) if @md
+  %{<font size=2>
+    <a href="#{@md.file.base_filename.manifest}" target="_top">#{text}</a>
+  </font>}
+    end
+    def concordance_link(text)
+      if @md.concord_make
+  %{<font size=2>
+    <a href="#{@md.file.base_filename.html_concordance}" target="_top">
+      #{text}
+    </a>
+  </font>}
+      else ''
+      end
+    end
+    def make_scroll_search_form_and_manifest_link
+      wgt=SiSU_HTML_Format::Widget.new(@md)
+      %{<td align="center" bgcolor=#{the_color.band2}>
+  #{the_nav.txt_doc_link}
+</td>
+}
+      %{<table summary="toc segment and scroll with pdf" border="0" cellpadding="3" cellspacing="0">
+<tr>
+  #{wgt.manifest}
+  #{wgt.search}
+</tr></table>}
+    end
+    def make_scroll_seg_pdf
+      seg=''
+      wgt=SiSU_HTML_Format::Widget.new(@md)
+      seg=%{<td align="center" bgcolor=#{the_color.band2}>
+  #{the_nav.txt_toc_link}
+</td>
+}
+      %{<table summary="toc scroll and segment with pdf" border="0" cellpadding="3" cellspacing="0">
+<tr>
+<td align="center" bgcolor=#{the_color.band2}>
+  #{wgt.manifest}
+  #{wgt.search}
+</tr></table>}
+    end
+    def make_concordance
+      wgt=SiSU_HTML_Format::Widget.new(@md)
+      %{<table summary="toc scroll and segment with pdf" border="0" cellpadding="3" cellspacing="0">
+<tr>
+<td align="center" bgcolor=#{the_color.band2}>
+  #{wgt.manifest}
+  #{wgt.search}
+</tr></table>}
+    end
+    def head
+      rdf=SiSU_XML_Tags::RDF.new(@md)
+      %{<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>
+    #{@md.title.full}
+  </title>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+#{rdf.metatag_html}
+#{@stylesheet.css_head}
+</head>
+<body lang="#{@md.opt.lng}">
+<a name="top" id="top"></a>}
+    end
+    def concordance
+      if @md.concord_make
+      %{#{the_margin.css}
+  <h4 class="toc">
+    <a href="./#{@md.file.base_filename.html_concordance}">
+      <i>Concordance</i>
+    </a>
+  </h4>
+#{table_close}}
+      else
+      %{#{the_margin.css}
+#{table_close}}
+      end
+    end
+    def links_guide_vertical_open
+#     @file=SiSU_Env::FileOp.new(@md) if @md
+      %{
+<div id="vertical_links">
+  <ul id="vertical">
+  <li class="refbold">
+    <a href="#{the_url.home}">
+      #{the_text.txt_hp}
+    </a>
+  </li>
+  <li class="ref">
+     Quick Ref.:
+  </li>
+  <li class="ref">
+    <a href="#{@md.file.base_filename.manifest}" alt="Document Manifest" target="_top">
+      Manifest
+    </a>
+  </li>
+<!- quick ref -!>}
+    end
+    def links_guide_horizontal_open
+#     @file=SiSU_Env::FileOp.new(@md) if @md
+      %{
+<div id="horizontal_links">
+  <ul id="horizontal">
+  <li class="refbold">
+    <a href="#{the_url.home}">
+      #{the_text.txt_hp}
+    </a>
+  </li>
+  <li class="ref">
+     Quick Ref.:
+  </li>
+  <li class="ref">
+    <a href="#{@md.file.base_filename.manifest}" alt="Document Manifest" target="_top">
+      Manifest
+    </a>
+  </li>
+<!- quick ref -!>}
+    end
+    def links_guide_open(type='horizontal')
+      (type=='vertical') \
+      ? links_guide_vertical_open
+      : links_guide_horizontal_open
+    end
+    def links_guide_close
+      insert=''
+      insert=if @md.sfx_src =~/s?/
+        link='http://sisudoc.org'                          #get from defaults
+        url='sisudoc.org'
+        name='SiSU electronic documents'                   #get from defaults
+        insert= %{
+  <li class="ref">
+    <a href="#{link}" alt="#{name}" target="_top">
+      #{url}
+    </a>
+  </li>
+  </ul>
+</div>
+}
+      end
+      %{ #{insert}
+<!- quick ref -!>}
+    end
+    def prefix_a
+    end
+    def rights
+      def all
+        rights=SiSU_HTML_Tune::CleanHTML.new(@md.rights.all).clean_for_html
+        rights=rights.gsub(/^\s*Copyright\s+\(C\)/,'Copyright <sup>&copy;</sup>&nbsp;')
+        %{<p class="small_left">Rights: #{rights}</p>
+<p>}
+      end
+      self
+    end
+    def prefix_b
+      %{<p class="small_left">Prefix: #{@md.prefix_b}<p />}
+    end
+    def scroll_head_title_banner_open
+      icon=@md.icon ? %{<center>\n#{@md.icon}\n</center>} : ''
+      %{#{icon}
+#{the_banner.instrument_cover_band_scr}}
+    end
+    def seg_head_title_banner_open
+      icon=@md.icon ? %{<center>\n#{@md.icon}\n</center>} : ''
+      %{#{icon}
+#{the_banner.instrument_cover_band_seg}}
+    end
+    def make_scroll
+      concord=concordance_link(the_nav.txt_concordance)
+      %{<table summary="toc scroll" border="0" cellpadding="3" cellspacing="0">
+<tr><td align="center" bgcolor="white" border="0">
+  #{the_nav.txt_doc_link}
+</td>
+<td align="center" bgcolor="white">
+   #{concord}
+#{the_table_close}}
+    end
+    def make_seg
+      concord=concordance_link(the_nav.txt_concordance)
+      %{<table summary="toc segment" border="0" cellpadding="3" cellspacing="0">
+<tr><td align="center" bgcolor="white">
+  #{the_nav.txt_toc_link}
+</td>
+<td align="center" bgcolor="white">
+  <font size=2>
+   #{concord}
+#{the_table_close}}
+    end
+    def manifest #check structure
+      if not @o_str.dump_or_redirect?
+        manifest=manifest_link(the_nav.txt_manifest)
+        %{#{the_margin.txt_3}
+  #{the_font.paragraph_font_small}
+   #{manifest}
+    </font>
+#{the_table_close}}
+      else ''
+      end
+    end
+    def concordance #check structure
+      concord=concordance_link(the_nav.txt_concordance)
+      %{#{the_margin.txt_3}
+  #{the_font.paragraph_font_small}
+   #{concord}
+    </font>
+#{the_table_close}}
+    end
+    def metadata
+      %{#{the_margin.css}
+  <h4 class="toc">
+    <a href="#{@metalink}">
+      <i>MetaData</i>
+    </a>
+  </h4>
+#{the_table_close}}
+    end
+    def seg_tail
+      %{
+<div class="main_column">
+<p>&nbsp;<p>
+<table summary="toc segment tail" bgcolor=#{the_color.band1}>
+<tr><td width="20%">
+  #{the_banner.banner_band}
+</td>
+<td width="60%">
+  <center>
+    #{@tocband_segtoc}
+  </center>
+</td></tr>
+</table>
+<p>&nbsp;</p>
+#{@bits.credits_sisu}
+<a name="bottom" id="bottom"></a>
+<a name="end" id="end"></a>
+</div>
+</div>
+</div>
+}
+    end
+    def scroll_tail #debug
+      nav=scroll_head_navigation_band
+      %{
+<div class="main_column">
+#{nav}
+#{@bits.credits_sisu}
+<a name="bottom" id="bottom"></a>
+<a name="end" id="end"></a>
+</div>
+}
+    end
+    def seg_navigation_tail #this is a bug area, look up and "tidy"
+      %{
+<div class="main_column">
+<p>&nbsp;</p>
+#{@bits.credits_sisu}
+<a name="bottom" id="bottom"></a>
+<a name="end" id="end"></a>
+</div>
+</div>
+</div>
+}
+    end
+  end
+  class HeadSeg < HeadInformation
+    def initialize(md)
+      super(md)
+    end
+    def dot_control_pre_next
+      pre="#{@per.seg_name_x[@per.seg_name_x_tracker-1]}#{@md.lang_code_insert}#{Sfx[:html]}"
+      up=@toc
+      nxt="#{@per.seg_name_x[@per.seg_name_x_tracker+1]}#{@md.lang_code_insert}#{Sfx[:html]}"
+      if nxt=~/sisu_manifest\.html/
+        @file=SiSU_Env::FileOp.new(@md) if @md
+        if @file.output_dir_structure.by_language_code? \
+        or @file.output_dir_structure.by_filetype?
+          nxt=nxt.gsub(/sisu_manifest\.html/,"../../manifest/#{@file.base_filename.manifest}")
+        end
+      end
+      %{<table summary="segment hidden control pre and next" width="100%" border="0" cellpadding="0" bgcolor=#{the_color.grey_pale} align="center">
+<tr><td align="left">
+  <a href="#{pre}" target="_top">
+    #{png_nav.dot_pre}
+  </a>
+</td>
+<td align="center">
+  <a href="#{up}" target="_top">
+    #{png_nav.dot_toc}
+  </a>
+</td>
+<td align="right">
+  <a href="#{nxt}" target="_top">
+    #{png_nav.dot_nxt}
+  </a>
+#{the_table_close}}
+    end
+    def dot_control_pre
+      pre="#{@per.seg_name_x[@per.seg_name_x_tracker-2]}#{@md.lang_code_insert}#{Sfx[:html]}"
+      up=@toc
+      nxt="#{@md.file.base_filename.html_segtoc}"
+      %{<table summary="segment hidden control pre" width="100%" border="0" cellpadding="0" bgcolor=#{the_color.grey_pale} align="center">
+<tr><td align="left">
+  <a href="#{pre}" target="_top">
+    #{png_nav.dot_pre}
+  </a>
+</td>
+<td align="center">
+  <a href="#{up}" target="_top">
+    #{png_nav.dot_toc}
+  </a>
+</td>
+<td align="right">
+  <a href="#{nxt}" target="_top">
+    #{png_nav.dot_nxt}
+  </a>
+#{the_table_close}}
+    end
+    def toc_nav(f_pre=false,f_nxt=false,use=1)
+      pre=nxt=''
+      toc=%{<td align="center" bgcolor=#{the_color.band1}>
+  <a href="#{@toc}" target="_top">
+    #{png_nav.toc}
+  </a>
+</td>}
+      pre=%{<td align="center" bgcolor=#{the_color.band1}>
+  <a href="#{@per.seg_name_x[@per.seg_name_x_tracker-use]}#{@md.lang_code_insert}#{Sfx[:html]}" target="_top">
+    #{png_nav.pre}
+  </a>
+</td>} if f_pre==true
+      nxt=%{<td align="center" bgcolor=#{the_color.band1}>
+  <a href="#{@per.seg_name_x[@per.seg_name_x_tracker+1]}#{@md.lang_code_insert}#{Sfx[:html]}" target="_top">
+    #{png_nav.nxt}
+  </a>
+</td>} if f_nxt==true
+      if nxt =~/sisu_manifest.html/
+        @file=SiSU_Env::FileOp.new(@md) if @md
+        if @file.output_dir_structure.by_language_code? \
+        or @file.output_dir_structure.by_filetype?
+          nxt=nxt.gsub(/sisu_manifest\.html/,"../../manifest/#{@file.base_filename.manifest}")
+        end
+      end
+      %{<table summary="segment navigation pre/next" border="0" cellpadding="3" cellspacing="0">
+<tr>
+#{pre}
+#{toc}
+#{nxt}
+<td>
+#{the_table_close}}
+    end
+    def toc_next2
+      toc_nav(false,true).dup
+    end
+    def toc_pre_next2
+      toc_nav(true,true).dup
+    end
+    def toc_pre2
+      toc_nav(true,false,2).dup
+    end
+    def manifest_link(text)
+  %{<font size=2>
+    <a href="#{@md.file.base_filename.manifest}" target="_top">
+      #{text}
+    </a>
+  </font>}
+    end
+    def concordance_link(text)
+      if @md.concord_make
+  %{<font size=2>
+    <a href="#{@md.file.base_filename.html_concordance}" target="_top">
+      #{text}
+    </a>
+  </font>}
+      else ''
+      end
+    end
+    def credit
+      %{
+<div class="main_column">
+#{@bits.credits_sisu}
+<a name="bottom" id="bottom"></a>
+<a name="end" id="end"></a>
+</div></div>
+}
+    end
+    def navigation_band(segtocband,seg_table_top_control) #change name to navigation_band_banner
+      %{<table summary="segment navigation band with banner" bgcolor=#{the_color.band1} width="100%"><tr>
+<td width="20%" align="left">
+#{button_home}
+</td>
+<td width="75%" align="center">
+  #{doc_types}
+</td>
+<td width="5%" align="right">
+  #{segtocband}
+</td></tr>
+</table>
+#{seg_table_top_control}}
+    end
+    def navigation_band_bottom(segtocband,seg_table_top_control) #change name to navigation_band_bannerless
+      %{
+<div class="main_column">
+  <table summary="segment navigation band" bgcolor=#{the_color.band1} width="100%"><tr>
+  <td width="70%" align="center">
+    #{doc_types}
+  </td>
+  <td width="5%" align="right">
+    #{segtocband}
+  </td></tr>
+  </table>
+  #{seg_table_top_control}
+</div>
+}
+    end
+    def endnote_mark
+%{
+<p class="center" id="endnotes">
+  <hr class="endnote" />
+</p>}
+    end
+    def endnote_section_open
+%{
+<div class="endnote">
+}
+    end
+    def endnote_section_close
+%{
+</div>
+} #revisit
+    end
+    def head_seg
+      rdf=SiSU_XML_Tags::RDF.new(@md)
+      %{<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>
+    #{@per.seg_name_x[@per.seg_name_x_tracker]} -
+    #{@md.title.main}
+  </title>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+#{rdf.metatag_html}
+#{@stylesheet.css_head_seg}
+</head>
+<body lang="#{@md.opt.lng}">
+<a name="top" id="top"></a>}
+    end
+    def title_banner(title,subtitle,creator)
+      %{
+<div class="summary">
+  <p class="tiny">
+    #{title}
+  </p>
+  <p class="tiny">
+    #{subtitle}
+  </p>
+  <p class="tiny">
+    #{creator}
+  </p>
+  <p class="tiny">
+    copy @
+    <a href="#{the_url.home}">
+      #{the_text.txt_home}
+    </a>
+  </p>
+</div>
+}
+    end
+  end
+  class HeadScroll < HeadToc
+    def initialize(md)
+      super(md)
+    end
+    def toc_owner_details
+      %{#{the_margin.txt_3}
+#{the_font.paragraph_font_small}
+  <a href="#owner.details">
+    Owner Details
+    <font size="1" color="#777777">
+      &nbsp;&nbsp;&nbsp;
+    </font>
+  </a>
+  </font>
+#{the_table_close}}
+    end
+  end
+  class FormatTextObject
+    include SiSU_Parts_HTML
+    attr_accessor :md,:t_o,:txt,:ocn,:format,:table,:link,:linkname,:paranum,:p_num,:headname,:banner,:url
+    def initialize(md,t_o)
+      @md,@t_o=md,t_o
+      @make=SiSU_Env::ProcessingSettings.new(@md)
+      if t_o.is_a?(Hash)
+        @txt            =t_o[:txt]            || nil
+        @ocn            =t_o[:ocn]            || nil
+        @ocn_display    =t_o[:ocn_display]    || nil
+        @headname       =t_o[:headname]       || nil
+        @trailer        =t_o[:trailer]        || nil
+        @endnote_part_a =t_o[:endnote_part_a] || nil
+        @endnote_part_b =t_o[:endnote_part_b] || nil
+        @lnk_url        =t_o[:lnk_url]        || nil
+        @lnk_txt        =t_o[:lnk_txt]        || nil
+        @format         =t_o[:format]         || nil
+      elsif t_o.class.inspect =~/^(?:#<)?SiSU_AO_DocumentStructure/
+        @dob=t_o if defined? t_o.is
+        @named=nametags_seg(@dob)
+        @txt=((defined? t_o.obj) ? t_o.obj : nil)
+        @ocn=((defined? t_o.ocn) ? t_o.ocn.to_s : nil)
+        @headname=((t_o.is==:heading and defined? t_o.name) ? t_o.name : nil)
+      else
+        if @md.opt.act[:maintenance][:set]==:on
+          p t_o.class
+          p caller
+        end
+      end
+      @headnamed=(@headname ? %{<a id="h#{@headname}"></a>} : nil)
+      if @txt and not @txt.empty?
+        @txt=@txt.gsub(/#{Mx[:mk_o]}[-~]##{Mx[:mk_c]}/,'')
+      end
+      @p_num=ParagraphNumber.new(@md,@ocn)
+    end
+    def nametags_scroll(dob)
+      tags=''
+      if defined? dob.tags \
+      and dob.tags.length > 0 # insert tags "hypertargets"
+        dob.tags.each do |t|
+          t=t.gsub(/[^a-z0-9._-]/,'') #use for all html tags? consider limiting to strict? or implementing earlier
+          tags=tags << %{<named id="#{t}" />}
+        end
+      end
+      tags
+    end
+    def nametags_seg(dob) #FIX
+      tags=''
+      if defined? dob.tags \
+      and dob.tags.length > 0 # insert tags "hypertargets"
+        dob.tags.compact.each do |t| # .compact hides a problem, nil should not occur fix (upstream)
+          t=t.gsub(/[^a-z0-9._-]/,'') #use for all html tags? consider limiting to strict? or implementing earlier
+          tags=(t =~/^[0-9.]+$/) \
+          ? tags             #check what can be sorted in ao
+          : (tags << %{<a name="#{t}" ></a>})
+        end
+      end
+      tags
+    end
+    def headname #check whether used
+      hn=if @t_o.is ==:heading \
+      and not @t_o.name.empty? #determine use
+        hn=(@t_o.is ==:heading) \
+        ? (%{<a id="h#{@t_o.name}"></a>})
+        : (%{<a id="#{@t_o.name}"></a>})
+      else nil
+      end
+      hn
+    end
+    def endnote_body
+      %{
+<p class="endnote">
+  #{@txt}
+</p>
+}
+    end
+    def endnote_body_indent
+      %{
+  <p class="endnote_indent">
+    #{@txt}
+  </p>
+}
+    end
+    def no_paranum
+      %{
+<div class="substance">
+  <label class="ocn">&nbsp;</label>
+  <p class="norm">
+    #{@txt}
+  </p>
+</div>
+}
+    end
+    def para_form_css(tag,attrib)                                                    # regular paragraphs shaped here
+      ul=ulc=''
+      if tag =~/li/
+        ul,ulc="<ul>\n  ","\n  </ul>"
+      end
+      %{
+<div class="substance">
+  #{@p_num.ocn_display}
+  #{ul}<#{tag} class="#{attrib}" #{@p_num.id}>
+    #{@named}#{@txt}
+  </#{tag}>#{ulc}
+</div>
+}
+    end
+    def para
+      para_form_css('p','norm')
+    end
+    def block
+      para_form_css('p','block')
+    end
+    def group
+      para_form_css('p','group')
+    end
+    def alt
+      para_form_css('p','alt')
+    end
+    def verse
+      para_form_css('p','verse')
+    end
+    def code
+      para_form_css('p','code')
+    end
+    def center
+      para_form_css('p','center')
+    end
+    def bold
+      para_form_css('p','bold')
+    end
+    def bullet
+      para_form_css('li','bullet')
+    end
+    def table
+      @txt=if @t_o.obj !~/^<table\s/
+        table=SiSU_HTML_Shared::TableHTML.new(@t_o) #move, make happen earlier
+        @txt=table.table.obj
+      else @txt
+      end
+      para_form_css('p','norm')
+    end
+    def format(tag,attrib)
+      para_form_css(tag,attrib)
+    end
+    def heading_normal(tag,attrib)
+      section_break=(tag=~/h[1-5]/) \
+      ? '<br><hr width=90% /><br>'
+      : ''
+      %{#{section_break}
+<div class="substance">
+  #{@p_num.ocn_display}
+  <#{tag} class="#{attrib}" #{@p_num.id}>#{@p_num.name}
+    #{@named}#{@txt}
+  </#{tag}>
+</div>
+}
+    end
+    def heading_body
+      heading_normal('p','norm')
+    end
+    def heading_body0
+      heading_normal('h1','norm')
+    end
+    def heading_body1
+      heading_normal('h1','norm')
+    end
+    def heading_body2
+      heading_normal('h2','norm')
+    end
+    def heading_body3
+      heading_normal('h3','norm')
+    end
+    def heading_body4
+      heading_normal('h4','norm')
+    end
+    def heading_body5
+      heading_normal('h5','norm')
+    end
+    def heading_body6
+      heading_normal('h6','norm')
+    end
+    def heading_body7
+      heading_normal('h7','norm')
+    end
+    def title_heading(tag,attrib)
+      cl=(@make.build.html_minitoc?) \
+      ? 'content'
+      : 'content0'
+      %{
+<div class="#{cl}">
+<#{tag} class="#{attrib}">
+    #{@named}#{@txt}
+  </#{tag}>
+</div>
+}
+    end
+    def title_heading0
+      title_heading('h1','tiny')
+    end
+    def title_heading1
+      title_heading('h1','tiny')
+    end
+    def title_heading2
+      title_heading('h2','tiny')
+    end
+    def title_heading3
+      title_heading('h3','tiny')
+    end
+    def title_heading4
+      ''
+    end
+    def seg_heading_sub(tag,attrib)
+      @txt=@txt.gsub(/(?:#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})\s*/m,' ')
+      %{
+<div class="substance">
+  #{@p_num.ocn_display}
+  <#{tag} class="#{attrib}" #{@p_num.id}>#{@p_num.name} #{@headnamed}
+    #{@named}#{@txt}
+  </#{tag}>
+</div>
+}
+    end
+    def seg_heading4
+      %{
+<div class="substance">
+  #{@p_num.ocn_display}
+  <h1 class="norm" #{@p_num.id}>#{@p_num.name}
+    #{@txt}
+  </h1>
+</div>
+}
+    end
+    def seg_heading5
+      seg_heading_sub('p','bold')
+    end
+    def seg_heading6
+      seg_heading_sub('p','bold')
+    end
+    def dl #check :trailer
+      "<dl><b>#{@txt}</b> #{@trailer}</dl>"
+    end
+    def table_css_end
+      '</table>
+    </p>
+  </div>'
+    end
+    def gsub_body #fix
+      @txt=case @txt
+      when /^\((i+|iv|v|vi+|ix|x|xi+)\)/
+        @txt.gsub(/^\((i+|iv|v|vi+|ix|x|xi+)\)/,'<b>(\1)</b>')
+      when /^\(?(\d|[a-z])+\)/
+        @txt.gsub(/^\((\d+|[a-z])+\)/,'<b>(\1)</b>')
+      when /^\s*\d{1,3}\.\s/
+        @txt.gsub(/^\s*(\d+\.)/,'<b>\1</b>')
+      when /^\s*[A-Z]\.\s/
+        @txt.gsub(/^\s*([A-Z]\.)/,'<b>\1</b>')
+      else @txt
+      end
+    end
+    def bold_para
+      %{#{the_margin.txt_0}
+  <p class="bold">
+    #{@txt}
+  </p>
+#{the_margin.num_css}
+  &nbsp;&nbsp;&nbsp;
+#{the_table_close}}
+    end
+    def bold_heading
+      %{<p class="bold">
+    #{@txt}
+  </p>
+#{the_margin.num_css}
+  &nbsp;&nbsp;&nbsp;
+#{the_table_close}}
+    end
+    def toc_head_copy_at
+      %{<p class="center">#{@txt}</p>\n}
+    end
+    def center
+      %{<p class="center">#{@txt}</p>\n}
+    end
+    def bold
+      %{<p class="bold">#{@txt}</p>\n}
+    end
+    def center_bold
+      %{<p class="centerbold">#{@txt}</p>\n}
+    end
+  end
+  class FormatScroll < FormatTextObject
+    def initialize(md,txt)
+      super(md,txt)
+    end
+  end
+  class FormatSeg < FormatTextObject
+    def initialize(md,txt)
+      super(md,txt)
+    end
+    def endnote_seg_body(fn='')
+      fn="../#{@md.fnb}" if fn.to_s.empty?
+      %{
+  <p class="endnote">
+    #{@endnote_part_a}#{fn}#{@md.lang_code_insert}#{Sfx[:html]}#{@endnote_part_b}
+  </p>
+}
+    end
+    def clean(txt)
+      txt=txt.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}/,'').
+        gsub(/#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'')
+    end
+    def subtoc_lev(tag,attrib)
+      @txt=clean(@txt)
+      txt=if @txt \
+      and @txt =~/<\/?i>|<a\s+name="\S+?">/mi
+        @txt.gsub(/<\/?i>|<a\s+name="\S+?">/mi,'') #removes name markers from subtoc, go directly to substantive text
+      else @txt
+      end
+      note=''
+      if txt =~/(#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})/m # had \s* at end
+        note=$1
+        note=note.gsub(/[\s]+/m,' ')
+        txt=txt.gsub(/(?:#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})\s*/m,' ').
+          gsub(/<a[\s]+name="-\d+"[\s]+href="#_\d+">&nbsp;<sup>\d+<\/sup>&nbsp;/m,'')
+      end
+      %{<#{tag} class="#{attrib}">
+    <a href="##{@ocn}"><i>#{txt}</i></a> #{note}
+  </#{tag}>}
+    end
+    def subtoc_lev5
+      subtoc_lev('h5','subtoc') if @txt
+    end
+    def subtoc_lev6
+      subtoc_lev('h6','subtoc') if @txt
+    end
+    def subtoc_lev7
+      subtoc_lev('h7','subtoc') if @txt
+    end
+    def heading_sub(tag,attrib)
+      @txt=@txt.gsub(/(?:#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})\s*/m,' ')
+      %{
+<div class="substance">
+  #{@p_num.ocn_display}
+  <#{tag} class="#{attrib}" #{@p_num.id}>#{@p_num.name} #{@headnamed}
+    #{@txt}
+  </#{tag}>
+</div>
+}
+    end
+    def heading5
+      heading_sub('p','bold')
+    end
+    def heading6
+      heading_sub('p','bold')
+    end
+    def heading4
+      %{
+<div class="substance">
+  #{@p_num.ocn_display}
+  <h1 class="norm" #{@p_num.id}>#{@p_num.name}
+    #{@t_o[:format]}
+    #{@txt}
+  </h1>
+</div>
+}
+    end
+    def navigation_heading4
+      %{<table summary="navigation segment heading 4" width=100% bgcolor="#08163f" border="0">
+<tr><td align="center">
+<p class="bold">
+  #{@txt}
+</p>
+#{the_table_close}}
+    end
+    def navigation_heading5
+      %{<p class="bold">
+  #{@txt}
+</p>}
+    end
+    def navigation_heading6
+      %{<p class="bold">
+  #{@txt}
+</p>}
+    end
+    def navigation_center
+      "<center>#{@txt}</center>"
+    end
+  end
+  class FormatToc < FormatTextObject
+    def initialize(md,txt)
+      super(md,txt)
+    end
+    def links_guide
+      %{  <li class="doc">
+    <a href="#{@lnk_url}" target="_top">
+      #{@lnk_txt}
+    </a>
+  </li>
+}
+    end
+    def lev(tag,attrib)
+      if @txt
+        %{<#{tag} class="#{attrib}">
+    #{@txt}
+  </#{tag}>
+}
+      else ''
+      end
+    end
+    def lev0 #docinfo
+      lev('h1','toc')
+    end
+    def lev1
+      lev('h1','toc')
+    end
+    def lev2
+      lev('h2','toc')
+    end
+    def lev3
+      lev('h3','toc')
+    end
+    def lev4
+      lev('h4','toc')
+    end
+    def lev5
+      lev('h5','toc')
+    end
+    def lev6
+      lev('h6','toc')
+    end
+    def lev7
+      lev('h7','toc')
+    end
+    def strip_endnotes(txt)
+      txt=txt.gsub(/(?:#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})\s*/m,' ')
+      txt
+    end
+    def mini_lev0
+      @txt=strip_endnotes(@txt)
+      lev('h1','minitoc')
+    end
+    def mini_lev1
+      @txt=strip_endnotes(@txt)
+      lev('h1','minitoc')
+    end
+    def mini_lev2
+      @txt=strip_endnotes(@txt)
+      lev('h2','minitoc')
+    end
+    def mini_lev3
+      @txt=strip_endnotes(@txt)
+      lev('h3','minitoc')
+    end
+    def mini_lev4
+      @txt=strip_endnotes(@txt)
+      lev('h4','minitoc')
+    end
+    def mini_lev5
+      @txt=strip_endnotes(@txt)
+      lev('h5','minitoc')
+    end
+    def mini_lev6
+      @txt=strip_endnotes(@txt)
+      lev('h6','minitoc')
+    end
+    def mini_lev7
+      @txt=strip_endnotes(@txt)
+      lev('h7','minitoc')
+    end
+    def mini_lev0 #docinfo
+      lev('h1','minitoc')
+    end
+    def mini_tail
+  %{
+  <h4 class="minitoc">
+    <a href="sisu_manifest.html">Manifest (alternative outputs)</a>
+  </h4>
+}
+    end
+    def mini_concord_tail
+  %{
+  <h4 class="minitoc">
+    <a href="concordance.html">Concordance (wordlist)</a>
+  </h4>
+  <h4 class="minitoc">
+    <a href="sisu_manifest.html">Manifest (alternative outputs)</a>
+  </h4>
+}
+    end
+  end
+  class FormatStr
+    def initialize(md,str)
+      @str=str
+    end
+    def center
+      %{<p class="center">#{@str}</p>\n}
+    end
+    def bold
+      %{<p class="bold">#{@str}</p>\n}
+    end
+    def center_bold
+      %{<p class="centerbold">#{@str}</p>\n}
+    end
+    def endnote_body
+      %{
+<p class="endnote">
+  #{@str}
+</p>
+}
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** shared
+*** html_shared.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/html_shared.rb"
+# <<sisu_document_header>>
+module SiSU_HTML_Shared
+  require_relative 'html_table'                         # html_table.rb
+  class TableHTML < SiSU_HTML_Table::TableHTML
+  end
+end
+__END__
+#+END_SRC
+
+*** html_lite_shared.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/html_lite_shared.rb"
+# <<sisu_document_header>>
+module SiSU_FormatShared
+  require_relative 'html_parts'                         # html_parts.rb
+  class CSS_Format
+    require_relative 'se_hub_particulars'               # se_hub_particulars.rb
+    include SiSU_Parts_HTML
+    @@fns=nil
+    def initialize(md,t_o)
+      @md,@t_o=md,t_o
+      @txt=@t_o.obj
+      @id=@ocn=@t_o.ocn if defined? @t_o.ocn
+      @lv=@t_o.lv.to_s if @t_o.is==:heading
+      if @md.fns != @@fns
+        @@fns,@@hname=@md.fns,''
+      end
+      @hname=if defined? @t_o.name \
+      and not @t_o.name.to_s.empty?
+        @@hname=@t_o.name
+      else @@hname
+      end
+      @tab="\t"
+      @@tablehead,@@tablefoot=[],[]
+      @env=SiSU_Env::InfoEnv.new(@md.fns)
+      @base_url="#{@env.url.root}/#{@md.fnb}/#{@hname}.html"
+    end
+    def urls(data)
+      @words=[]
+      map_nametags=SiSU_Particulars::CombinedSingleton.instance.get_map_nametags(@md).nametags_map
+      data.each do |word|
+        @words << if word=~/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}(#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)/
+          if word =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/
+            m,u=/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/.match(word).captures
+          elsif word =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}/
+            m,u=/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}(\S+?)#{Mx[:rel_c]}/.match(word).captures
+          elsif word =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}image/
+            m,u=/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}(image)/.match(word).captures
+          end
+          word=case m
+          when /\.png|\.jpg|\.gif|c=|\d+x\d+/
+            w,h=/(\d+)x(\d+)/.match(m).captures if m =~/\d+x\d+/
+            w=%{width="#{w}"} if w
+            h=%{height="#{h}"} if h
+            c=m[/"(.+?)"/m,1]
+            caption=%{<br><p class="caption">#{c}</p>} if c
+            png=m.scan(/\S+/)[0]
+            ins=if u \
+            and u.strip !~/^image$/
+              %{<a href="#{u}">[#{png}]</a>#{caption}}
+            else %{[#{png}] #{caption}}
+            end
+            word=word.gsub(/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}(#{Mx[:url_o]}\S+?#{Mx[:url_c]}|image)/,ins)
+          else
+            u=case u
+            when /^https?:\/\//
+              u
+            when /^:/
+              u=u.gsub(/^:/,'')
+              "#{@env.url.root}/#{u}"
+            when /^\.\.\// # can remove
+              u=u.gsub(/^\.\.\//,'')
+              "#{@env.url.root}/#{u}"
+            else
+              if not map_nametags[u].nil?
+                @env.url.root + '/' \
+                + @md.fnb + '/' \
+                + map_nametags[u][:segname] \
+                + Sfx[:html] \
+                + '#' + u
+              else ''
+              end
+            end
+            link=m[/(.+)/m]
+            png=m.scan(/\S+/)[0].strip
+            link=link.strip
+            ins=%{<a href="#{u}">#{link}</a>}
+            word=word.gsub(/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/,ins).
+              gsub(/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}/,ins)
+            word
+          end
+          word
+        else word
+        end
+        word
+      end
+      @words=@words.join(' ')
+    end
+    def markup_generic(s)
+      s=s.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'<b>\1</b>').
+        gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'<i>\1</i>').
+        gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'<u>\1</u>').
+        gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'"\1"').
+        gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'+{\1}+').
+        gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strke_c]}/,'-{\1}-').
+        gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'<sup>\1</sup>').
+        gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'<sub>\1</sub>').
+        gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,'<tt>\1</tt>'). # tt, kbd
+        gsub(/#{Mx[:gl_o]}#(?:126|152)#{Mx[:gl_c]}/i,'~')
+    end
+    def markup_object(t_o)
+      s=t_o.obj
+      s=if t_o.is !=:code
+        s=markup_generic(s)
+        if s =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)/
+          wm=s.scan(/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)|\S+/)
+          words=urls(wm)
+          s=s.gsub(/.+/m,words)
+        end
+        s.gsub(/#{Mx[:gl_o]}(#[0-9]{3})#{Mx[:gl_c]}/u,'&\1;').
+          gsub(/#{Mx[:gl_o]}#([a-z]{2,4})#{Mx[:gl_c]}/u,'&\1;').
+          gsub(/#{Mx[:url_o]}[_\\](\S+?)#{Mx[:url_c]}/,'<a href="\1" target="_top">\1</a>'). #http ftp matches escaped, no decoration
+          gsub(/(#{Mx[:lnk_c]})#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,'\1<a href="\2" target="_top">\2</a>'). #special case \{ e.g. \}http://url
+          gsub(/(^|#{Mx[:gl_c]}|\s)#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,%{\\1#{the_url_decoration.xml_open}<a href="\\2" target="_top">\\2</a>#{the_url_decoration.xml_close}\\3}) #http ftp matches with decoration
+      else
+        s.gsub(/</m,'&lt;').
+          gsub(/>/m,'&gt;')
+      end
+      s
+    end
+    def markup_note(s)
+      s=markup_generic(s)
+      if s =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}(#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)/
+        wm=s.scan(/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)|\S+/)
+        words=urls(wm)
+        s=s.gsub(/.+/m,words)
+      end
+      s=s.gsub(/#{Mx[:gl_o]}(#[0-9]{3})#{Mx[:gl_c]}/u,'&\1;').
+        gsub(/#{Mx[:gl_o]}#([a-z]{2,4})#{Mx[:gl_c]}/u,'&\1;').
+        gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,'<a href="\1" target="_top">\1</a>\2'). #http ftp matches escaped, no decoration
+        gsub(/(#{Mx[:lnk_c]})#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,'\1<a href="\2" target="_top">\2</a>'). #special case \{ e.g. \}http://url
+        gsub(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,%{#{the_url_decoration.xml_open}<a href="\\1" target="_top">\\1</a>#{the_url_decoration.xml_close}}) #http ftp matches with decoration
+    end
+    def paragraph
+      %{<p class="h#{@lv}" type="substantive" header="#{@hname}">#{@txt}</p>\n} # << "\n"
+    end
+    def endnote(nr,en) #used only by db
+      txt=markup_note(en)
+      <<GSUB
+<p class="endnote" name="note_#{nr}" from="#{@t_o.ocn}">
+<a href="#{@base_url}#-#{nr}" name="_#{nr}">#{nr}.</a> <note>#{txt}</note>
+</p>
+GSUB
+    end
+    def tag_header(h)
+      %{<p class="#{h[:class]}" type="#{h[:type]}" header="#{h[:header]}">#{h[:txt]}</a></p>\n} # << "\n"
+    end
+    def tag_para(h)
+      %{<p class="#{h[:class]}" type="#{h[:type]}">#{h[:txt]}</a></p>\n}  << "\n"
+    end
+    def lev_toc_hname
+      %{<p class="toc#{@lv}" header="#{@hname}"><a href="##{@ocn}">#{@txt}</a></p>\n}  #<< "\n"
+    end
+    def lev_toc
+      h={ txt: txt, class: "toc#{@lv}", type: 'toc' }
+      tag_para(h)
+    end
+    def lev4_plus
+      txt=markup_object(@t_o)
+      h={ txt: txt, class: "h#{@lv}", type: 'substantive', id: @ocn, header: @hname }
+      tag_header(h)
+    end
+    def lev4_minus
+      txt=markup_object(@t_o)
+      h={ txt: txt, class: "h#{@t_o.ln}", type: 'substantive', id: @ocn }
+      tag_para(h)
+    end
+    def norm_comment
+      h={ txt: @t_o.obj, class: 'norm', type: 'comment' }
+      tag_para(h)
+    end
+    def norm
+      txt=markup_object(@t_o)
+      h={ txt: txt, class: 'norm', type: 'substantive', id: @ocn }
+      tag_para(h)
+    end
+    def code
+      txt=markup_object(@t_o)
+      h={ txt: "<tt>#{txt}</tt>", class: 'code', type: 'substantive', id: @ocn }
+      tag_para(h)
+    end
+    def indent(t)
+      txt=markup_object(@t_o)
+      h={ txt: txt, class: "indent#{t}", type: 'substantive', id: @ocn }
+      tag_para(h)
+    end
+    def hang_indent(f,t)
+      txt=markup_object(@t_o)
+      h={ txt: txt, class: "hang#{f}indent#{t}", type: 'substantive', id: @ocn }
+      #h={ txt: txt, class: "h#{f}i#{t}", type: 'substantive', id: @ocn }
+      tag_para(h)
+    end
+    def para_table
+      %{<p class="norm" align="left"><font #{the_font.set_small} #{the_font.set_color} #{the_font.set_face}>}
+    end
+    def ocn
+      %{<label class="ocn">#{@ocn}</label>} << "\n"
+    end
+    def html_table # get rid of use html_table
+      @new_content=[]
+      @txt.split(/\n/).each do |parablock|
+        m=parablock[/<!f(.+?)!>/,1]
+        @@tablefoot << m if m
+        parablock=parablock.gsub(/<!f.+?!>/,'')
+        @@tablehead=1 if parablock =~/#{Mx[:gr_o]}Th#{Mx[:tc_p]}/u
+        parablock=parablock.gsub(/#{Mx[:gr_o]}Th?#{Mx[:tc_p]}.+?#{Mx[:tc_p]}~(\d+)#{Mx[:gr_c]}/,
+          %{<table summary="normal text css" width="100%" border="0" cellpadding="2" align="center">})
+        if parablock =~/#{Mx[:gr_o]}TZ#{Mx[:gr_c]}/
+          tablefoot=[]
+          @@tablefoot.each {|x| tablefoot << %{<p align="center"><font size=2><i>#{x}</i></font></p>\n}}
+          @@tablefoot=[]
+          parablock=parablock.gsub(/#{Mx[:gr_o]}TZ#{Mx[:gr_c]}/,
+            %{#{the_table_close}\n}) # +
+        end
+        if @@tablehead==1
+          if parablock =~/#{Mx[:tc_p]}#{Mx[:tc_p]}/u
+            parablock=parablock.gsub(/#{Mx[:tc_o]}#{Mx[:tc_p]}#{Mx[:tc_p]}(\d+?)#{Mx[:tc_p]}/u,
+                %{\n<tr>} +
+                %{\n<td width="\\1%" valign="top">} +
+                %{#{para_table}<b>}).
+              gsub(/#{Mx[:tc_p]}#{Mx[:tc_p]}(\d+?)#{Mx[:tc_p]}/u,
+                %{</b></td><td width="\\1%" valign="top">} +
+                %{#{para_table}<b>}).
+              gsub(/#{Mx[:tc_c]}/, '</b></td></tr>')
+            @@tablehead=0
+          end
+          parablock
+        else
+          parablock=parablock.gsub(/#{Mx[:tc_o]}#{Mx[:tc_p]}#{Mx[:tc_p]}(\d+?)#{Mx[:tc_p]}/u,
+              %{\n<tr>} +
+              %{\n<td width="\\1%" valign="top">} +
+              %{#{para_table}}).
+            gsub(/#{Mx[:tc_p]}#{Mx[:tc_p]}(\d+?)#{Mx[:tc_p]}/u,
+              %{</td><td width="\\1%" valign="top">} +
+              %{#{para_table}}).
+            gsub(/#{Mx[:tc_c]}/, '</td></tr>')
+          parablock
+        end
+        @new_content << parablock
+      end
+      @new_content.join
+    end
+  end
+  class CSS_FormatGeneric #does CSS_Format in one definition, needs to be told about attrib, despite brevity of generic, easier to see structure with CSS_Format
+    def initialize(attrib='',txt='',id=nil,ocnd=nil,ocns=nil,lv='',hname=nil)
+      @tab="\t"
+      @attrib=attrib
+      @txt=txt
+      @lv=lv.to_s
+      @hname=hname.to_s
+      @id=@ocn=id
+    end
+    def paragraph
+      attrib=%{class="#{@attrib}" }
+      if @ocn
+        id=%{id="#{Mx[:ocn_id_char]}#{@ocn}" }
+        type=%{type="substantive" }
+      else
+        id=''
+        type=%{type="comment" }
+      end
+      header=%{header="#{@hname}" } if @hname
+      %{<p #{attrib}#{type}#{header}>#{@txt}</p>\n} #<< "\n"
+    end
+    def para
+      paragraph
+    end
+  end
+end
+__END__
+#+END_SRC
+
+*** html_table.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/html_table.rb"
+# <<sisu_document_header>>
+module SiSU_HTML_Table
+  require_relative 'xhtml_table'                         # xhtml_table.rb
+  require_relative 'html_parts'                          # html_parts.rb
+  class TableHTML < SiSU_XHTML_Table::TableXHTML
+    include SiSU_Parts_HTML
+  end
+end
+__END__
+#+END_SRC
+
+#+RESULTS:
+
+** misc
+*** html_minitoc.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/html_minitoc.rb"
+# <<sisu_document_header>>
+module SiSU_HTML_MiniToc
+  require_relative 'html_tune'                        # html_tune.rb
+    include SiSU_HTML_Tune
+  class TocMini
+    @@seg_mini=nil
+    @@seg_url=''
+    @@firstseg=nil
+    def initialize(md,data)
+      @md,@data=md,data
+      @pat_strip_heading_name=/<a name="h?\d.*?">(.+?)<\/a>/
+      @tell=SiSU_Screen::Ansi.new(@md.opt.act[:color_state][:set]) if @md
+    end
+    def songsheet
+      if (@md.opt.act[:verbose][:set]==:on \
+      || @md.opt.act[:verbose_plus][:set]==:on \
+      || @md.opt.act[:maintenance][:set]==:on)
+        SiSU_Screen::Ansi.new(@md.opt.act[:color_state][:set],'Toc').txt_grey
+      end
+      toc=nil
+      @toc=[]
+      @data.each do |txt|
+        if txt.is ==:heading \
+        || txt.is ==:heading_insert
+          txt.obj=txt.obj.gsub(/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]}).+?(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/m,''). #remove endnotes from toc
+            gsub(/<a name="-\d+" href="#_\d+">&nbsp;<sup>\d+<\/sup>&nbsp;<\/a>/,'').
+            gsub(@pat_strip_heading_name,'\1')
+            #gsub(/(.*?)<a name="(\d+)"><\/a>(.*)/,'\1') #2002w42 altered gsub - problematic? - suspect
+          toc=case txt.ln
+          when 0 then SiSU_HTML_MiniToc::TocMini.new(@md,txt).level_0
+          when 1 then SiSU_HTML_MiniToc::TocMini.new(@md,txt).level_1
+          when 2 then SiSU_HTML_MiniToc::TocMini.new(@md,txt).level_2
+          when 3 then SiSU_HTML_MiniToc::TocMini.new(@md,txt).level_3
+          when 4 then SiSU_HTML_MiniToc::TocMini.new(@md,txt).level_4
+          when 5 then SiSU_HTML_MiniToc::TocMini.new(@md,txt).level_5
+          when 6 then SiSU_HTML_MiniToc::TocMini.new(@md,txt).level_6
+          else
+          end
+          @toc << toc
+        end
+      end
+      @toc
+    end
+  protected
+    def level_concordance
+      format_head_toc=SiSU_HTML_Format::HeadToc.new(@md)
+      @@seg_mini << format_head_toc.mini_seg_concordance
+    end
+    def level_metadata
+      format_head_toc=SiSU_HTML_Format::HeadToc.new(@md)
+      @@seg_mini << format_head_toc.mini_seg_metadata
+    end
+    def level_word_index
+      format_head_toc=SiSU_HTML_Format::HeadToc.new(@d0c)
+      @@seg_mini << format_head_toc.mini_concordance
+    end
+    def level_0
+      txt=@data
+      if (txt.is ==:heading \
+      || txt.is ==:heading_insert) \
+      && txt.ocn !=0
+        txt.obj=txt.obj.gsub(@pat_strip_heading_name,'\1')
+      end
+      txt_obj={ txt: txt.obj }
+      format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+      toc_mini=format_toc.mini_lev0
+      toc_mini
+    end
+    def level_1
+      txt=@data
+      if (txt.is ==:heading \
+      || txt.is ==:heading_insert) \
+      && txt.ocn !=0
+        txt.obj=txt.obj.gsub(@pat_strip_heading_name,'\1')
+      end
+      title=unless txt.obj =~/Document Information/ then txt.obj
+      else
+        link='metadata'
+        %{<b><a href="#{link}#{@md.lang_code_insert}#{Sfx[:html]}">#{txt.obj}</a></b>}
+      end
+      txt_obj={ txt: title }
+      format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+      toc_mini=if txt.name =~/^meta/ \
+      and txt.obj=~/Document Information/
+        format_toc.mini_tail
+      else format_toc.mini_lev1
+      end
+      toc_mini
+    end
+    def level_2
+      txt=@data
+      if (txt.is ==:heading \
+      || txt.is ==:heading_insert) \
+      && txt.ocn !=0
+        txt.obj=txt.obj.gsub(@pat_strip_heading_name,'\1')
+      end
+      txt_obj={ txt: txt.obj }
+      format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+      toc_mini=format_toc.mini_lev2
+      toc_mini
+    end
+    def level_3
+      txt=@data
+      txt_obj={ txt: txt.obj }
+      format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+      toc_mini=format_toc.mini_lev3
+      toc_mini
+    end
+    def level_4
+      txt=@data
+      unless txt.obj =~/~metadata/
+        if txt.ln ==4
+          fnh={
+            fn: txt.name,
+          }
+          f=@md.file.base_filename.html_seg(fnh)
+          seg_link=%{  <a href="#{f}" target="_top">
+    #{txt.obj}
+  </a> }
+          @@seg_url=txt.name
+        elsif txt.obj =~/\d+.\d+.\d+.\d+|\d+.\d+.\d+|\d+.\d+|\d+/
+          fn,hd=/^(\d+.\d+.\d+.\d+|\d+.\d+.\d+|\d+.\d+|\d+)(.*)/.match(dob.obj)[1,2]
+          fnh={
+            fn: fn,
+          }
+          f=@md.file.base_filename.html_seg(fnh)
+          seg_link=%{<a href="#{f}" target="_top">#{fn} #{hd}</a> }
+        end
+        txt_obj={ txt: seg_link }
+        format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+        toc_mini=format_toc.mini_lev4
+        toc_mini
+      end
+    end
+    def level_5
+      txt=@data
+      if (txt.is ==:heading \
+      || txt.is ==:heading_insert) \
+      && txt.ocn !=0
+        txt.obj=txt.obj.gsub(@pat_strip_heading_name,'\1')
+      end
+      fnh={
+        fn: @@seg_url,
+      }
+      f=@md.file.base_filename.html_seg(fnh)
+      lnk_n_txt=%{  <a href="#{f}##{txt.ocn}">
+    #{txt.obj}
+  </a>}
+        txt_obj={ txt: lnk_n_txt }
+        format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+        toc_mini=format_toc.mini_lev5
+      toc_mini
+    end
+    def level_6
+      txt=@data
+      if (txt.is ==:heading \
+      || txt.is ==:heading_insert) \
+      && txt.ocn !=0
+        txt.obj=txt.obj.gsub(@pat_strip_heading_name,'\1')
+      end
+      fnh={
+        fn: @@seg_url,
+      }
+      f=@md.file.base_filename.html_seg(fnh)
+      lnk_n_txt=%{  <a href="#{f}##{txt.ocn}">
+    #{txt.obj}
+  </a>}
+        txt_obj={ txt: lnk_n_txt }
+        format_toc=SiSU_HTML_Format::FormatToc.new(@md,txt_obj)
+        toc_mini=format_toc.mini_lev6
+      toc_mini
+    end
+  end
+end
+__END__
+#+END_SRC
+
+*** html_concordance.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/html_concordance.rb"
+# <<sisu_document_header>>
+module SiSU_Concordance
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+    include SiSU_Particulars
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'html_format'                        # html_format.rb
+    include SiSU_HTML_Format
+  require_relative 'html_minitoc'                       # html_minitoc.rb
+  class Source
+    def initialize(opt)
+      @opt=opt
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+    end
+    def read
+      begin
+        @env,@md=@particulars.env,@particulars.md
+        @env.url.output_tell
+        unless @md.opt.act[:quiet][:set]==:on
+          tool=(@md.opt.act[:verbose][:set]==:on \
+          || @md.opt.act[:verbose_plus][:set]==:on \
+          || @md.opt.act[:maintenance][:set]==:on) \
+          ? "#{@env.program.web_browser} #{@md.file.output_path.html_concordance.dir}/#{@md.file.base_filename.html_concordance}"
+          : "[#{@opt.f_pth[:lng_is]}] #{@opt.fno}"
+          (@md.opt.act[:verbose][:set]==:on \
+          || @md.opt.act[:verbose_plus][:set]==:on \
+          || @md.opt.act[:maintenance][:set]==:on) \
+          ? SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              "Concordance",
+              tool
+            ).green_hi_blue
+          : SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'Concordance',
+              tool
+            ).green_title_hi
+        end
+        wordmax=@env.concord_max
+        unless @md.wc_words.nil?
+          if @md.wc_words < wordmax
+            SiSU_Concordance::Source::Words.new(@particulars).songsheet
+          else
+            SiSU_Screen::Ansi.new(
+              @md.opt.act[:color_state][:set],
+              "concordance skipped, large document has over #{wordmax} words (#{@md.wc_words})"
+            ).warn unless @md.opt.act[:quiet][:set]==:on
+          end
+        else
+          SiSU_Screen::Ansi.new(
+            @md.opt.act[:color_state][:set],
+            "wc (word count) is off, concordance will be processed for all files including those over the max set size of: #{wordmax} words"
+          ).warn unless @md.opt.act[:quiet][:set]==:on
+          SiSU_Concordance::Source::Words.new(@particulars).songsheet
+        end
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        SiSU_Env::CreateSite.new(@opt).cp_css
+        Dir.chdir(@opt.f_pth[:pth])
+      end
+    end
+    private
+    class DocTitle
+      #revisit, both requires (html & xml_shared) needed for stand alone operation (sisu -w [filename])
+      require_relative 'xml_shared'                     # xml_shared.rb
+      require_relative 'html'                           # html.rb
+      def initialize(particulars)
+        @particulars,@md=particulars,particulars.md
+        @data=SiSU_HTML::Source::HTML_Environment.new(particulars).tuned_file_instructions
+        @file=SiSU_Env::FileOp.new(@md)
+        @fnb=@md.fnb
+        @lex_button=%{<a href="http://www.jus.uio.no/sisu/" target="_top"><img border="0" height="44" width="144" valign="center" src="#{@file.path_rel_links.html_seg_2}_sisu/image/sisu.png" alt="SiSU home --&gt;"></a>}
+        @doc_details =<<WOK
+<table summary="links to text related to this rudimentary index" width="96%" border="0" cellpadding="0" align="center"><tr><td width="2%" align="right">&nbsp;</td><td width="94%" valign="top" align="justify"><h1 class="small"><a href="#{@md.file.base_filename.html_segtoc}"><b>#{@md.title.full}</b></a></h1><p class="bold">#{@md.author}</p></td></tr></table>
+WOK
+        @make=SiSU_Env::ProcessingSettings.new(@md)
+      end
+      def create
+        head_banner=SiSU_HTML_Format::HeadToc.new(@md)
+        minitoc=SiSU_HTML_MiniToc::TocMini.new(@md,@data).songsheet.join("\n")
+        stylesheet=SiSU_Style::CSS_HeadInfo.new(@md).stylesheet
+        if @make.build.manifest_minitoc?
+          toc='<div class="toc">' + minitoc + '</div>'
+          div_class='content'
+        else
+          toc=''
+          div_class='content0'
+        end
+        top_band=if @make.build.html_top_band?
+          head_banner.concordance_navigation_band
+        else ''
+        end
+        <<WOK
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>
+    SiSU created WordIndex for: #{@md.title.full}
+  </title>
+  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+  <meta name="Description" content="&nbsp;SiSU created">
+  <meta name="keywords" content="word index for #{@md.title.full}">
+  <meta name="generator" content="SiSU (Linux &amp; Ruby!)">
+  <link rel="generator" href="http://www.jus.uio.no/sisu" />
+  <link rel="shortcut icon" href="../_sisu/image/rb7.ico" />
+  #{stylesheet.css_head_seg}
+</head>
+<body>
+  #{top_band}
+  #{toc}
+<div class="#{div_class}">
+ #{@doc_details}
+<p>Word index links are to html versions of the text the segmented version followed by the scroll (single document) version.<br>[For segmented text references [T1], [T2] or [T3] appearing without a link, indicates that the word appears in a title (or subtitle) of the text (that is identifiable by the appended object citation number).]</p>
+<p>(The word listing/index is Case sensitive: Capitalized words appear before lower case)</p>
+  <p>
+    <b>word</b> (number of occurences)<br>linked references to word within document <br>
+    [if number of occurences exceed number of references - word occurs more than once in at least one reference. Footnote/endnotes are either assigned to the paragraph from which they are referenced or ignored, so it is relevant to check the footnotes referenced from within a paragraph as well.]
+  </p>
+  <p>
+    (After the page is fully loaded) you can jump directly to a word by appending a hash (#) and the word to the url for this text, (do not forget that words are case sensitive, and may be listed twice (starting with and without an upper case letter)), #your_word # [&nbsp;http://[web host]/#{@fnb}/concordance.html#your_word&nbsp;]
+  </p>
+WOK
+      end
+    end
+    class Word
+      @@word_previous=''
+      def initialize(word,freq)
+        @word,@freq=word,freq
+      end
+      def html
+        w=if @word.capitalize==@@word_previous
+          %{\n<p class="concordance_word">#{@word}</p><p class="concordance_count">(#{@freq})</p>\n\t<p class="concordance_object"> }
+        else n=@word.strip.gsub(/\s+/,'_') #also need to convert extended character set to html
+          %{\n<p class="concordance_word"><a name="#{n}">#{@word}</a></p><p class="concordance_count">(#{@freq})</p>\n\t<p class="concordance_object"> }
+        end
+        @@word_previous=@word.capitalize
+        w
+      end
+    end
+    class Words
+      require_relative 'i18n'                           # i18n.rb
+        include SiSU_i18n
+      require_relative 'html_format'                    # html_format.rb
+        include SiSU_HTML_Format
+      require_relative 'se'                             # se.rb
+        include SiSU_Screen
+      @@dp=nil
+      def initialize(particulars)
+        @particulars=particulars
+        begin
+          @env,@md,@ao_array=particulars.env,particulars.md,particulars.ao_array
+          @file=SiSU_Env::FileOp.new(@md)
+          @freq=Hash.new(0)
+          @dp=@@dp ||=SiSU_Env::InfoEnv.new.digest.pattern
+          @rxp_lv1=/^#{Mx[:lv_o]}1:/ #fix @rxp_lv #  Mx[:lv_o]
+          @rxp_lv2=/^#{Mx[:lv_o]}2:/ #fix @rxp_lv #  Mx[:lv_o]
+          @rxp_lv3=/^#{Mx[:lv_o]}3:/ #fix @rxp_lv #  Mx[:lv_o]
+          @rxp_title=Regexp.new("^#{Mx[:meta_o]}title#{Mx[:meta_c]}\s*(.+?)\s*$")
+          @rxp_t1=Regexp.new('^T1')
+          @rxp_t2=Regexp.new('^T2')
+          @rxp_t3=Regexp.new('^T3')
+          @rxp_excluded1=/#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}/
+          @rxp_excluded0=/^(?:#{Mx[:fa_bold_o]}|#{Mx[:fa_italics_o]})?(?:to\d+|\d+|&nbsp;|#{Mx[:br_endnotes]}|EOF|#{Mx[:br_eof]}|thumb_\S+|snap_\S+|_+|-+|[(]?(?:ii+|iv|vi+|ix|xi+|xiv|xv|xvi+|xix|xx)[).]?|\S+?_\S+|[\d_]+\w\S+|[\w\d]{1,2}|\d{1,3}\w?|#{@dp}|[0-9a-f]{16,64}|\d{2,3}x\d{2,3}|\S{0,2}sha\d|\S{0,3}\d{4}w\d\d|\b\w\d+|\d_all\b|e\.?g\.?)(?:#{Mx[:fa_bold_c]}|#{Mx[:fa_italics_c]})?$/mi #this regex causes and cures a stack dump in ruby 1.9 !!!
+          @rgx_splitlist=%r{[—.,;:#{Mx[:nbsp]}-]}mi
+          @alph=SiSU_i18n::Alphabet.new(@md.opt.lng).hash_arrays
+          @alphlst=SiSU_i18n::Alphabet.new(@md.opt.lng).hash_strings
+          @rgx_scanlist=%r{#{Mx[:fa_italics_o]}[#{@alphlst[:l]}#{@alphlst[:u]}0-9"\s]{2,12}#{Mx[:fa_italics_c]}|#{Mx[:fa_bold_o]}[#{@alphlst[:l]}#{@alphlst[:u]}0-9"\s]{2,12}#{Mx[:fa_bold_c]}|(?:https?|file)://\S+|<\S+?>|[#{@alphlst[:l]}#{@alphlst[:u]}]+|\w+}mi
+        rescue
+          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+        end
+      end
+      def songsheet
+        begin
+          FileUtils::mkdir_p(@file.output_path.html_concordance.dir) \
+            unless FileTest.directory?(@file.output_path.html_concordance.dir)
+          @file_concordance=File.open(@file.place_file.html_concordance.dir,'w')
+          map_para
+        rescue
+          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+        ensure
+          @file_concordance.close
+        end
+      end
+    protected
+      def location_scroll(wordlocation,show)                    # not used
+        %{<a href="doc#{@md.lang_code_insert}#{Sfx[:html]}\##{Mx[:ocn_id_char]}#{wordlocation}">#{wordlocation}</a>;  }
+      end
+      def location_seg(wordlocation,show)
+        unless wordlocation.nil?
+          wl=wordlocation.gsub(/(.+?)\#(\d+)/,
+            "\\1#{@md.lang_code_insert}#{Sfx[:html]}##{Mx[:ocn_id_char]}\\2")     # id="o\d+" always available; a name="\d+" not available if html strict used
+          case wordlocation
+          when /#{@rxp_t1}|@rxp_t2}|#{@rxp_t3}/
+            %{[<a href="doc#{@md.lang_code_insert}#{Sfx[:html]}##{show}">H</a>]#{show},  }
+          when /(.+?)\#(\d+)/
+             %{<a href="#{wl}">#{show}</a>,  }
+          end
+        end
+      end
+      def map_para
+        @seg,ocn=nil,nil
+        @word_map={}
+        @ao_array.each do |line|
+          if defined? line.ocn \
+          and line.ocn.to_s =~/\d/
+            if (line.is ==:heading \
+            || line.is ==:heading_insert) \
+            && line.ln==4
+              @seg=line.name
+            end
+            ocn=line.ocn.to_s
+            if ocn =~/\d+/ \
+            and ocn !~/^0$/
+              line.obj=line.obj.gsub(/#{@rxp_excluded1}/,' ')
+              line.obj=line.obj.split(@rgx_splitlist).join(' ') #%take in word or other match
+              for word in line.obj.scan(@rgx_scanlist) #%take in word or other match
+                if word =~ /^([#{@alphlst[:l]}])/
+                  firstletter=$1
+                  flu=firstletter.tr(@alphlst[:l],@alphlst[:u])
+                  word=word.gsub(/^#{firstletter}/,flu )
+                end
+                word=word.gsub(/#{Mx[:lnk_o]}|#{Mx[:lnk_c]}|#{Mx[:url_o]}|#{Mx[:url_c]}/,'').
+                  gsub(/#{Mx[:fa_o]}\S+?#{Mx[:fa_o_c]}/,'').
+                  gsub(/#{Mx[:fa_c_o]}\S+?#{Mx[:fa_c]}/,'').
+                  gsub(/#{Mx[:gl_o]}#[a-z]+#{Mx[:gl_c]}/,'').
+                  gsub(/#{Mx[:gl_o]}#[0-9]+#{Mx[:gl_c]}/,'')
+                word=word.gsub(/[0-9a-f]{10,}/,' ') if word =~/[0-9]/
+                word=word.gsub(/#{Mx[:br_line]}/,' ').
+                  gsub(/^ +/,'').
+                  gsub(/^\S$/,'')
+                word=nil if word.empty?
+                word=nil if word =~@rxp_excluded0 #watch
+                word=nil if word =~/^\S$/
+                if word
+                  word=word.gsub(/#{Mx[:br_nl]}|#{Mx[:br_line]}/,' ').
+                    gsub(/#{Mx[:fa_o]}[a-z]{1,7}#{Mx[:fa_o_c]}|#{Mx[:fa_c_o]}[a-z]{1,7}#{Mx[:fa_c]}/,'').
+                    gsub(/#{Mx[:en_a_o]}(?:\d|[*+])*|#{Mx[:en_b_o]}(?:\d|[*+])*|#{Mx[:en_a_c]}|#{Mx[:en_b_c]}/mi,'').
+                    gsub(/#{Mx[:fa_o]}\S+?#{Mx[:fa_o_c]}/,'').
+                    gsub(/#{Mx[:fa_c_o]}\S+?#{Mx[:fa_c]}/,'').
+                    gsub(/<\/?\S+?>/,'').
+                    gsub(/^\@+/,'').
+                    strip.
+                    gsub(/#{Mx[:tc_p]}.+/,'').
+                    gsub(/[\.,;:"]$/,'').
+                    gsub(/["]/,'').
+                    gsub(/^\s*[\(]/,'').
+                    gsub(/[\(]\s*$/,'').
+                    gsub(/^(?:See|e\.?g\.?).+/,'').
+                    gsub(/^\s*[.,;:]\s*/,'').
+                    strip.
+                    gsub(/^\(?[a-zA-Z]\)$/,'').
+                    gsub(/^\d+(st|nd|rd|th)$/,'').
+                    gsub(/^(\d+\.?)+$/, '').
+                    gsub(/#{Mx[:mk_o]}|#{Mx[:mk_c]}/,'').
+                    gsub(/:name#\S+/,'').
+                    gsub(/^\S$/,'')
+                  word=nil if word =~/^\S$/
+                  word=nil if word =~/^\s*$/ #watch
+                  if word
+                    unless word =~/[A-Z][A-Z]/ \
+                    or word =~/\w+\s\w+/
+                      word=word.capitalize
+                    end
+                    @freq[word] +=1
+                    @word_map[word] ||= []
+                    if line !~ /#{@rxp_lv1}|#{@rxp_lv2}|#{@rxp_lv3}/
+                      loc_=%{#{location_seg("#{@seg}\##{ocn}",ocn).to_s}}
+                      unless loc_.empty?
+                        @word_map[word] << loc_
+                      end
+                    else
+                      @word_map[word] << case line
+                      when @rxp_lv1 then location_seg('T1',ocn) #fix @rxp_lv #  Mx[:lv_o]
+                      when @rxp_lv2 then location_seg('T2',ocn) #fix @rxp_lv #  Mx[:lv_o]
+                      when @rxp_lv3 then location_seg('T3',ocn) #fix @rxp_lv #  Mx[:lv_o]
+                      end
+                    end
+                  end
+                end
+              end
+            end
+          end
+        end
+        seg=''
+        head=SiSU_Concordance::Source::DocTitle.new(@particulars).create
+        head=head.gsub(/#{Xx[:html_relative2]}/m,@file.path_rel_links.html_seg_2).
+          gsub(/#{Xx[:html_relative1]}/m,@file.path_rel_links.html_seg_1)
+        @file_concordance << head
+        @file_concordance << '<p>'
+        alph=@alph[:u]
+        alph.each {|x| @file_concordance << %{<a href="##{x}">#{x}</a>,&nbsp;}}
+        @file_concordance << '</p>'
+        letter=alph.shift
+        @file_concordance << %{\n<p class="letter"><a name="A">A</a></p>}
+        for word in @freq.keys.sort! {|a,b| a.downcase<=>b.downcase}
+          f=/^(\S)/.match(word)[1]
+          if letter < f.upcase
+            while letter < f.upcase
+              if alph.length > 0
+                letter=alph.shift
+                @file_concordance << %{\n<p class="letter"><a name="#{letter}">#{letter}</a></p>}
+              else break
+              end
+            end
+          end
+          keyword=SiSU_Concordance::Source::Word.new(word,@freq[word]).html
+          if keyword !~ @rxp_excluded0
+            if @word_map[word][0] =~ /\d+/
+              @file_concordance << %{#{keyword}#{seg}#{@word_map[word].uniq.compact.join}}
+            end
+            @file_concordance << '</p>'
+          end
+          # special cases endnotes and header levels 1 - 3
+        end
+        @file_concordance << %{</div></body>\n</html>} # footer
+        if @md.opt.act[:verbose_plus][:set]==:on \
+        || @md.opt.act[:maintenance][:set]==:on
+          SiSU_Screen::Ansi.new(
+            @md.opt.act[:color_state][:set],
+            @md.fns,
+            "#{@md.file.output_path.html_concordance.dir}/#{@md.file.base_filename.html_concordance}"
+          ).flow
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+*** html_manifest.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/html_manifest.rb"
+# <<sisu_document_header>>
+module SiSU_Manifest
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'prog_text_translation'              # prog_text_translation.rb
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+    include SiSU_Particulars
+  require_relative 'html_parts'                         # html_parts.rb
+  require_relative 'html_minitoc'                       # html_minitoc.rb
+  require_relative 'html'                               # html.rb
+    include SiSU_HTML_Format
+  require_relative 'dp'                                 # dp.rb
+    include SiSU_Param
+  require_relative 'i18n'                               # i18n.rb
+  class Source
+    def initialize(opt)
+      @opt=opt
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+      l=SiSU_Env::StandardiseLanguage.new(opt.lng).language
+      @doc_language=l[:n]
+    end
+    def read
+      begin
+        @env=SiSU_Env::InfoEnv.new(@opt.fns)
+        @md=SiSU_Param::Parameters.new(@opt).get
+        xbrowser=@env.program.web_browser
+        browser=@env.program.console_web_browser
+#       webserv_url=@env.path.url.output_tell #fix in sysenv
+        unless @opt.act[:quiet][:set]==:on
+          url_html='file://' \
+          + @md.file.output_path.manifest.dir + '/' \
+          + @md.file.base_filename.manifest
+          (@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on) \
+          ? SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'Manifest',
+              "#{xbrowser} #{url_html}"
+            ).green_hi_blue
+          : SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'Manifest',
+              "[#{@opt.f_pth[:lng_is]}]",
+              "#{url_html}"
+            ).grey_title_grey_blue
+          if (@md.opt.act[:verbose][:set]==:on \
+          || @md.opt.act[:verbose_plus][:set]==:on)
+            SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              "#{browser} #{url_html}"
+            ).grey_tab
+          end
+        end
+        data=SiSU_HTML::Source::HTML_Environment.new(@particulars).tuned_file_instructions
+        SiSU_Manifest::Source::Output.new(@md).check_output(data)
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        SiSU_Env::CreateSite.new(@opt).cp_css
+        Dir.chdir(@opt.f_pth[:pth])
+      end
+    end
+    private
+    class Output <Source
+      include SiSU_Parts_HTML
+      def initialize(md)
+        @manifest={ txt: [], html: [] }
+        @md,@fns=md,md.fns
+        @env=SiSU_Env::InfoEnv.new(md.fns)
+        @f=SiSU_Env::FileOp.new(md)
+        @fnb=md.fnb
+        @base_url="#{@env.url.root}/#{@fnb}"
+        @o_str=SiSU_Env::FileOp.new(md).output_dir_structure
+        @image_path=(@o_str.dump_or_redirect?) \
+        ? './image'
+        : %{#{@f.path_rel_links.html_scroll_2}_sisu/image_sys}
+        @base_path=@f.output_path.manifest.dir
+        @@dg ||=SiSU_Env::InfoEnv.new(md.fns,md).digest(md.opt).type
+        @dg=@@dg
+        l=SiSU_Env::StandardiseLanguage.new(md.opt.lng).language
+        @language=l[:n]
+        @translate=SiSU_Translate::Source.new(md,@language)
+        @stylesheet=SiSU_Style::CSS_HeadInfo.new(md).stylesheet
+        @fn_lng=(@f.output_dir_structure.by_language_code?) \
+        ? ''
+        : ('.' + md.opt.lng)
+      end
+      def output
+        manifest=@f.write_file.manifest
+        @manifest[:html].each do |x|
+          x=x.gsub(Xx[:html_relative2],@f.path_rel_links.html_scroll_2).
+            gsub(Xx[:html_relative1],@f.path_rel_links.html_scroll_1)
+          manifest << x
+        end
+      end
+      def url_make(url,file,src=nil)
+        if @o_str.dump_or_redirect?
+          ''
+        elsif src==:src #check
+          %{<br>#{the_url_decoration.xml_open}<a href="#{url}/#{file}">#{url}/#{file}</a>#{the_url_decoration.xml_close}}
+        else
+          %{<p class="tiny">#{the_url_decoration.xml_open}<a href="#{url}/#{file}">#{url}/#{file}</a>#{the_url_decoration.xml_close}</p>}
+        end
+      end
+      def summarize(desc,id,file,pth='',rel='',url='',img='● ')
+        size=(File.size("#{pth}/#{file}")/1024.00).to_s
+        kb=/([0-9]+\.[0-9]{0,1})/m.match(size)[1]
+        @manifest[:txt] << "#{file} #{desc} #{kb}\n"
+        @manifest[:html] << %{<tr><th class="left"><p class="norm"><a href="#{rel}/#{file}">#{img}#{desc}</a></p></th><td><p class="small"><a href="#{rel}/#{file}">#{file}</a></p>#{url_make(url,file)}</td><td class="right"><p class="right">#{kb}</p></td></tr>\n}
+      end
+      def summarize_html_seg(desc,id,file,pth='',rel='',url='',img='● ')
+        size=(File.size("#{pth}/#{file}")/1024.00).to_s
+        kb=/([0-9]+\.[0-9]{0,1})/m.match(size)[1]
+        @manifest[:txt] << "#{file} #{desc} #{kb}\n"
+        @manifest[:html] << %{<tr><th class="left"><p class="norm"><a href="#{rel}/#{file}">#{img}#{desc}</a></p></th><td><p class="small"><a href="#{rel}/#{file}">#{file}</a></p>#{url_make(url,file)}</td><td class="right"><p class="right">#{kb}</p></td></tr>\n}
+      end
+      def summarize_sources(desc,id,file,pth,rel,url)
+        sys=SiSU_Env::SystemCall.new
+        dgst=case @dg
+        when :sha512
+          sys.sha512("#{pth}/#{file}")
+        when :sha256
+          sys.sha256("#{pth}/#{file}")
+        when :md5
+          sys.md5("#{pth}/#{file}")
+        else
+        end
+        dgst=dgst ? dgst : [ '', 'n/a' ]
+        if (@md.opt.act[:verbose][:set]==:on \
+        || @md.opt.act[:verbose_plus][:set]==:on \
+        || @md.opt.act[:maintenance][:set]==:on)
+          SiSU_Screen::Ansi.new(
+            @md.opt.act[:color_state][:set],
+            "#{dgst[1]} #{file}"
+          ).warn
+        end
+        size=(File.size("#{pth}/#{file}")/1024.00).to_s
+        kb=/([0-9]+\.[0-9]{0,1})/m.match(size)[1]
+        @manifest[:txt] << "#{file} #{desc} #{kb}\n"
+        @manifest[:html] << %{<tr>} \
+        + %{<th class="left"><p class="norm" id="#{id}"><a href="#{rel}/#{file}">#{desc}</a></p></th>} \
+        + %{<td class="right"><p class="tiny"><a href="#{rel}/#{file}">#{file}</a> &nbsp;&nbsp;#{dgst[1]}#{url_make(url,file,:src)}</p></td>} \
+        + %{<td class="right"><p class="right">#{kb}</p></td>} \
+        + %{</tr>\n} \
+          if kb and kb =~/\d+/
+      end
+      def published_manifests?
+        @f=SiSU_Env::FileOp.new(@md) #.base_filename
+        @m=[]
+        url=@f.output_path.base.url
+        manifests={}
+        mp,mn,mt,mr=nil,nil,nil,nil
+        ln=SiSU_i18n::Languages.new.language.list
+        Px[:lng_lst].each do |lc|
+          lngc=SiSU_Env::FilenameLanguageCodeInsert.new(@md.opt,lc).language_code_insert
+          fnh={
+             fn: @md.fnb,
+             lng: lngc,
+          }
+          mn=@f.base_filename.manifest(fnh)
+          if @o_str.dump_or_redirect? #does not work for --redirect or --dump
+            mp="#{@f.output_path.base.dir}"
+            mt="#{mp}/#{mn}"
+            mr="../../#{lc}/manifest/#{mn}"
+            mu="#{url}/#{mn}"
+          elsif @f.output_dir_structure.by_language_code?
+            mp="#{@f.output_path.base.dir}/#{lc}/manifest"
+            mt="#{mp}/#{mn}"
+            mr="../../#{lc}/manifest/#{mn}"
+            mu="#{url}/#{lc}/manifest/#{mn}"
+          elsif @f.output_dir_structure.by_filetype?
+            mp="#{@f.output_path.base.dir}/manifest"
+            mt="#{mp}/#{mn}"
+            mr=mn
+            mu="#{url}/manifest/#{mn}"
+          else
+            mp="#{@f.output_path.base.dir}/#{@md.fnb}"
+            mt="#{mp}/#{mn}"
+            mr=mn
+            mu="#{url}/#{mn}"
+          end
+          if FileTest.directory?(mp) \
+          &&  FileTest.file?(mt)
+            lng=ln[lc][:t]
+            manifests[lc]={ ln: lng, fn: mn, rel: mr }
+            @m << { mu: mu, l: lng, rel: mr }
+          end
+        end
+        @m=@m.uniq
+      end
+      def languages(desc,file)
+        @manifest[:html] << %{<tr><th class="left"><div id="horizontal_links"><ul id="horizontal">\n}
+        published_manifests?.each do |l|
+          SiSU_Translate::Source.new(@md,@language,l[:n]).language_list
+          @manifest[:txt] << "#{l[:mu]} #{l[:l]}\n"
+          @manifest[:html] << %{<li class="norm"><a href="#{l[:rel]}">#{l[:l]}</a>&nbsp;&nbsp;&nbsp;</li>}
+        end
+        @manifest[:html] << %{</ul></div></th></tr>\n}
+      end
+      def published_languages(desc)
+        published_manifests?.each do |l|
+          @manifest[:txt] << "#{l[:mu]} #{l[:l]}\n"
+          @manifest[:html] << %{<tr><th class="left"><p class="bold"><a href="#{l[:mu]}">#{l[:l]}</a></p></th><td><p class="norm">#{l[:l]}</p><p class="tiny">#{the_url_decoration.xml_open}<a href="#{l[:mu]}">#{l[:mu]}</a>#{the_url_decoration.xml_close}</p></td><td class="right"><p class="right">&nbsp;</p></td></tr>\n}
+        end
+      end
+      def metadata(desc,id,info)
+        info=info.to_s.gsub(/(?:#{Mx[:br_line]}|\\)+/,'<br>')
+        @manifest[:html] << %{<tr><th class="left"><p class="bold_left" id="#{id}">#{desc}:</p></th><td><p class="left">#{info}</p></td></tr>\n}
+      end
+      def links(url,lnk,target)
+        static=if url =~/^\.\// then url.gsub(/^\.(\.)?/,@base_url)
+        elsif url =~/^\.\.\//   then url.gsub(/^\.(\.)?/,@env.url.root)
+        else                         url
+        end
+        @manifest[:html] << %{<tr><th class="right" width=5%><p class="norm">●</p></th><td class="left"><p class="norm"><a href="#{url}">#{lnk}</a></p><p class="tiny">&nbsp;&nbsp;#{the_url_decoration.xml_open}<a href="#{static}">#{static}</a>#{the_url_decoration.xml_close}</p></td></tr>\n}
+      end
+      def output_tests
+        if FileTest.file?(@f.place_file.html_segtoc.dir)==true
+          img=%{<img border="0" height="18" width="15" src="#{@image_path}/b_toc.png" alt="TOC linked" /> }
+          pth=@f.output_path.html_seg.dir
+          rel=@f.output_path.html_seg.rel_sm
+          url=@f.output_path.html_seg.url
+          desc,id,file='HTML, table of contents (for segmented text)','html',@f.base_filename.html_segtoc
+          summarize_html_seg(desc,id,file,pth,rel,url,img)
+        end
+        if FileTest.file?(@f.place_file.html_scroll.dir)==true
+          img=%{<img border="0" height="15" width="15" src="#{@image_path}/b_doc.png" alt="Full Text" /> }
+          pth=@f.output_path.html_scroll.dir
+          rel=@f.output_path.html_scroll.rel_sm
+          url=@f.output_path.html_scroll.url
+          desc,id,file='HTML, full length document','html_scroll',@f.base_filename.html_scroll
+          summarize(desc,id,file,pth,rel,url,img)
+        end
+        if FileTest.file?(@f.place_file.html_book_index.dir)==true
+          pth=@f.output_path.html_seg.dir
+          rel=@f.output_path.html_seg.rel_sm
+          url=@f.output_path.html_seg.url
+          desc,id,file='HTML, (book type) index','html_book',@f.base_filename.html_book_index
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.html_concordance.dir)==true
+          pth=@f.output_path.html_seg.dir
+          rel=@f.output_path.html_seg.rel_sm
+          url=@f.output_path.html_seg.url
+          desc,id,file='HTML, concordance file','concordance',@f.base_filename.html_concordance
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.epub.dir)==true
+          img=%{<img border="0" height="18" width="18" src="#{@image_path}/b_epub.png" alt="EPUB" /> }
+          desc,id,file='EPUB (Electronic Publication, e-book standard)','epub',@f.base_filename.epub
+          pth=@f.output_path.epub.dir
+          rel=@f.output_path.epub.rel_sm
+          url=@f.output_path.epub.url
+          summarize(desc,id,file,pth,rel,url,img)
+        end
+        if FileTest.file?("#{@f.output_path.pdf.dir}/#{@f.base_filename.pdf_p_letter}")==true
+          img=%{<img border="0" height="18" width="15" src="#{@image_path}/b_pdf.png" alt="PDF portrait" /> }
+          pth=@f.output_path.pdf.dir
+          rel=@f.output_path.pdf.rel_sm
+          url=@f.output_path.pdf.url
+          desc,id,file="PDF, U.S. letter size, portrait/vertical document (recommended for printing)",'pdf_letter',"#{@f.base_filename.pdf_p_letter}"
+          summarize(desc,id,file,pth,rel,url,img)
+        end
+        if FileTest.file?("#{@f.output_path.pdf.dir}/#{@f.base_filename.pdf_l_letter}")==true
+          img=%{<img border="0" height="15" width="18" src="#{@image_path}/b_pdf.png" alt="PDF landscape" /> }
+          pth=@f.output_path.pdf.dir
+          rel=@f.output_path.pdf.rel_sm
+          url=@f.output_path.pdf.url
+          desc,id,file="PDF, U.S. letter size, landscape/horizontal document (recommended for screen viewing)",'pdf_letter_landscape',"#{@f.base_filename.pdf_l_letter}"
+          summarize(desc,id,file,pth,rel,url,img)
+        end
+        if FileTest.file?("#{@f.output_path.pdf.dir}/#{@f.base_filename.pdf_p_a4}")==true
+          img=%{<img border="0" height="18" width="15" src="#{@image_path}/b_pdf.png" alt="PDF portrait" /> }
+          pth=@f.output_path.pdf.dir
+          rel=@f.output_path.pdf.rel_sm
+          url=@f.output_path.pdf.url
+          desc,id,file="PDF, A4 size, portrait/vertical document (recommended for printing)",'pdf_a4',"#{@f.base_filename.pdf_p_a4}"
+          summarize(desc,id,file,pth,rel,url,img)
+        end
+        if FileTest.file?("#{@f.output_path.pdf.dir}/#{@f.base_filename.pdf_l_a4}")==true
+          img=%{<img border="0" height="15" width="18" src="#{@image_path}/b_pdf.png" alt="PDF landscape" /> }
+          pth=@f.output_path.pdf.dir
+          rel=@f.output_path.pdf.rel_sm
+          url=@f.output_path.pdf.url
+          desc,id,file="PDF, A4 size, landscape/horizontal document (recommended for screen viewing)",'pdf_a4_landscape',"#{@f.base_filename.pdf_l_a4}"
+          summarize(desc,id,file,pth,rel,url,img)
+        end
+        if FileTest.file?("#{@f.output_path.pdf.dir}/#{@f.base_filename.pdf_p_a5}")==true
+          img=%{<img border="0" height="18" width="15" src="#{@image_path}/b_pdf.png" alt="PDF portrait" /> }
+          pth=@f.output_path.pdf.dir
+          rel=@f.output_path.pdf.rel_sm
+          url=@f.output_path.pdf.url
+          desc,id,file="PDF, A5 (book) size, portrait/vertical document (recommended for printing)",'pdf_a5',"#{@f.base_filename.pdf_p_a5}"
+          summarize(desc,id,file,pth,rel,url,img)
+        end
+        if FileTest.file?("#{@f.output_path.pdf.dir}/#{@f.base_filename.pdf_l_a5}")==true
+          img=%{<img border="0" height="15" width="18" src="#{@image_path}/b_pdf.png" alt="PDF landscape" /> }
+          pth=@f.output_path.pdf.dir
+          rel=@f.output_path.pdf.rel_sm
+          url=@f.output_path.pdf.url
+          desc,id,file="PDF, A5 (book) size, landscape/horizontal document (recommended for screen viewing)",'pdf_a5_landscape',"#{@f.base_filename.pdf_l_a5}"
+          summarize(desc,id,file,pth,rel,url,img)
+        end
+        if FileTest.file?("#{@f.output_path.pdf.dir}/#{@f.base_filename.pdf_p_b5}")==true
+          img=%{<img border="0" height="18" width="15" src="#{@image_path}/b_pdf.png" alt="PDF portrait" /> }
+          pth=@f.output_path.pdf.dir
+          rel=@f.output_path.pdf.rel_sm
+          url=@f.output_path.pdf.url
+          desc,id,file="PDF, B5 (book) size, portrait/vertical document (recommended for printing)",'pdf_b5',"#{@f.base_filename.pdf_p_b5}"
+          summarize(desc,id,file,pth,rel,url,img)
+        end
+        if FileTest.file?("#{@f.output_path.pdf.dir}/#{@f.base_filename.pdf_l_b5}")==true
+          img=%{<img border="0" height="15" width="18" src="#{@image_path}/b_pdf.png" alt="PDF landscape" /> }
+          pth=@f.output_path.pdf.dir
+          rel=@f.output_path.pdf.rel_sm
+          url=@f.output_path.pdf.url
+          desc,id,file="PDF, B5 (book) size, landscape/horizontal document (recommended for screen viewing)",'pdf_a5_landscape',"#{@f.base_filename.pdf_l_b5}"
+          summarize(desc,id,file,pth,rel,url,img)
+        end
+        if FileTest.file?("#{@f.output_path.pdf.dir}/#{@f.base_filename.pdf_p_legal}")==true
+          img=%{<img border="0" height="18" width="15" src="#{@image_path}/b_pdf.png" alt="PDF portrait" /> }
+          pth=@f.output_path.pdf.dir
+          rel=@f.output_path.pdf.rel_sm
+          url=@f.output_path.pdf.url
+          desc,id,file="PDF, U.S. legal size, portrait/vertical document (recommended for printing)",'pdf_legal',"#{@f.base_filename.pdf_p_legal}"
+          summarize(desc,id,file,pth,rel,url,img)
+        end
+        if FileTest.file?("#{@f.output_path.pdf.dir}/#{@f.base_filename.pdf_l_legal}")==true
+          img=%{<img border="0" height="15" width="18" src="#{@image_path}/b_pdf.png" alt="PDF landscape" /> }
+          pth=@f.output_path.pdf.dir
+          rel=@f.output_path.pdf.rel_sm
+          url=@f.output_path.pdf.url
+          desc,id,file="PDF, U.S. legal size, landscape/horizontal document (recommended for screen viewing)",'pdf_legal_landscape',"#{@f.base_filename.pdf_l_legal}"
+          summarize(desc,id,file,pth,rel,url,img)
+        end
+        if FileTest.file?(@f.place_file.odt.dir)==true
+          img=%{<img border="0" height="18" width="18" src="#{@image_path}/b_odf.png" alt="ODF/ODT" /> }
+          pth=@f.output_path.odt.dir
+          rel=@f.output_path.odt.rel_sm
+          url=@f.output_path.odt.url
+          desc,id,file='ODF:ODT (Open Document Format)','odt',@f.base_filename.odt
+          summarize(desc,id,file,pth,rel,url,img)
+        end
+        if FileTest.file?(@f.place_file.xhtml.dir)==true
+          pth=@f.output_path.xhtml.dir
+          rel=@f.output_path.xhtml.rel_sm
+          url=@f.output_path.xhtml.url
+          desc,id,file='XHTML','xhtml',@f.base_filename.xhtml
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.xml_sax.dir)==true
+          pth=@f.output_path.xml_sax.dir
+          rel=@f.output_path.xml_sax.rel_sm
+          url=@f.output_path.xml_sax.url
+          desc,id,file='XML SAX','xml_sax',@f.base_filename.xml_sax
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.xml_dom.dir)==true
+          pth=@f.output_path.xml_dom.dir
+          rel=@f.output_path.xml_dom.rel_sm
+          url=@f.output_path.xml_dom.url
+          desc,id,file='XML DOM','xml_dom',@f.base_filename.xml_dom
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.xml_docbook_article.dir)==true
+          pth=@f.output_path.xml_docbook_article.dir
+          rel=@f.output_path.xml_docbook_article.rel_sm
+          url=@f.output_path.xml_docbook_article.url
+          desc,id,file='XML Docbook Article','docbook_article',@f.base_filename.xml_docbook_article
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.xml_docbook_book.dir)==true
+          pth=@f.output_path.xml_docbook_book.dir
+          rel=@f.output_path.xml_docbook_book.rel_sm
+          url=@f.output_path.xml_docbook_book.url
+          desc,id,file='XML Docbook Book','docbook',@f.base_filename.xml_docbook_book
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.xml_fictionbook.dir)==true
+          pth=@f.output_path.xml_fictionbook.dir
+          rel=@f.output_path.xml_fictionbook.rel_sm
+          url=@f.output_path.xml_fictionbook.url
+          desc,id,file='XML Fictionbook','fictionbook',@f.base_filename.xml_fictionbook
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.xml_scaffold_structure_sisu.dir)==true
+          pth=@f.output_path.xml_scaffold_structure_sisu.dir
+          rel=@f.output_path.xml_scaffold_structure_sisu.rel_sm
+          url=@f.output_path.xml_scaffold_structure_sisu.url
+          desc,id,file='XML Scaffold sisu structure','xml_scaffold',@f.base_filename.xml_scaffold_structure_sisu
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.xml_scaffold_structure_collapse.dir)==true
+          pth=@f.output_path.xml_scaffold_structure_collapse.dir
+          rel=@f.output_path.xml_scaffold_structure_collapse.rel_sm
+          url=@f.output_path.xml_scaffold_structure_collapse.url
+          desc,id,file='XML Scaffold collapsed structure','xml_collapsed',@f.base_filename.xml_scaffold_structure_collapse
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.info.dir)==true
+          pth=@f.output_path.texinfo.dir
+          rel=@f.output_path.texinfo.rel_sm
+          url=@f.output_path.texinfo.url
+          desc,id,file='Info file','info',@f.base_filename.info
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.manpage.dir)==true
+          pth=@f.output_path.manpage.dir
+          rel=@f.output_path.manpage.rel_sm
+          url=@f.output_path.manpage.url
+          desc,id,file='Manpage','manpage',@f.base_filename.manpage
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.sqlite_discrete.dir)==true
+          desc,id,file='SQLite3 file','sqlite',@f.base_filename.sqlite_discrete
+          pth=@f.output_path.sqlite_discrete.dir
+          rel=@f.output_path.sqlite_discrete.rel_sm
+          url=@f.output_path.sqlite_discrete.url
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.txt.dir)==true
+          desc,id='Plaintext (UTF-8)','text'
+          pth=@f.output_path.txt.dir
+          rel=@f.output_path.txt.rel_sm
+          url=@f.output_path.txt.url
+          file=@f.base_filename.txt
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.textile.dir)==true
+          desc,id='Textile text (UTF-8)','textile'
+          pth=@f.output_path.textile.dir
+          rel=@f.output_path.textile.rel_sm
+          url=@f.output_path.textile.url
+          file=@f.base_filename.textile
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.asciidoc.dir)==true
+          desc,id='AsciiDoc text (UTF-8)','asciidoc'
+          pth=@f.output_path.asciidoc.dir
+          rel=@f.output_path.asciidoc.rel_sm
+          url=@f.output_path.asciidoc.url
+          file=@f.base_filename.asciidoc
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.markdown.dir)==true
+          desc,id='Markdown text (UTF-8)','markdown'
+          pth=@f.output_path.markdown.dir
+          rel=@f.output_path.markdown.rel_sm
+          url=@f.output_path.markdown.url
+          file=@f.base_filename.markdown
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.rst.dir)==true
+          desc,id='rST text (UTF-8)','rst'
+          pth=@f.output_path.rst.dir
+          rel=@f.output_path.rst.rel_sm
+          url=@f.output_path.rst.url
+          file=@f.base_filename.rst
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.orgmode.dir)==true
+          desc,id='OrgMode structure text (UTF-8)','org'
+          pth=@f.output_path.orgmode.dir
+          rel=@f.output_path.orgmode.rel_sm
+          url=@f.output_path.orgmode.url
+          file=@f.base_filename.orgmode
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?("#{@base_path}/#{@md.fns}.tex")==true
+          desc,id,file='LaTeX (portrait)','latex',"#{@md.fns}.tex"
+          pth,rel,url='','',''
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?("#{@base_path}/#{@md.fns}.tex")==true
+          desc,id,file='LaTeX (landscape)','latex_landscape',"#{@md.fns}.landscape.tex"
+          pth,rel,url='','',''
+          summarize(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.hash_digest.dir)==true
+          pth=@f.output_path.hash_digest.dir
+          rel=@f.output_path.hash_digest.rel_sm
+          url=@f.output_path.hash_digest.url
+          desc,id,file="Digest/DCC - Document Content Certificate (#{@dg})",'digests',@f.base_filename.hash_digest
+          summarize(desc,id,file,pth,rel,url)
+        end
+      end
+      def published_versions
+        desc,file='Markup (SiSU source)','source',@md.fns
+        languages(desc,file)
+      end
+      def language_versions
+        if FileTest.file?(@f.place_file.manifest.dir)==true
+          desc='Markup (SiSU source)'
+          published_languages(desc)
+        end
+      end
+      def qrc_image
+        fn=(@f.output_dir_structure.by_filename?) \
+        ? 'sisu_manifest'
+        : @md.fnb
+        pth=((@o_str.dump_or_redirect?) \
+        || (@f.output_dir_structure.by_filename?)) \
+        ? '.'
+        : 'qrcode'
+        img_md="#{pth}/#{fn}#{@fn_lng}.md.png"
+        img_title="#{pth}/#{fn}#{@fn_lng}.title.png"
+        if FileTest.file?(@f.place_file.qrcode_md.dir)==true
+          @manifest[:html] <<<<WOK
+<tr><td class="left">
+  <p class="tiny">QR code SiSU document metadata:</p>
+  <p class="tiny">
+    <img border="0" src="#{img_md}" alt="qrcode metadata" />
+  </p>
+</td></tr>
+WOK
+        end
+        if FileTest.file?(@f.place_file.qrcode_title.dir)==true
+          @manifest[:html] <<<<WOK
+<tr><td class="left">
+  <p class="tiny">QR code document title info:</p>
+  <p class="tiny">
+    <img border="0" src="#{img_title}" alt="qrcode title" />
+  </p>
+</td></tr>
+WOK
+        end
+      end
+      def source_tests
+        if @md.fno =~/\.ssm$/                                                  #% decide whether to extract and include requested/required documents
+          if FileTest.file?(@f.place_file.src.dir)==true
+            pth=@f.output_path.src.dir
+            rel=@f.output_path.src.rel_sm
+            url=@f.output_path.src.url
+            desc,id,file='Markup Composite File (SiSU source)','source',@f.base_filename.src
+            summarize_sources(desc,id,file,pth,rel,url)
+          end
+        else
+          if FileTest.file?(@f.place_file.src.dir)==true
+            pth=@f.output_path.src.dir
+            rel=@f.output_path.src.rel_sm
+            url=@f.output_path.src.url
+            desc,id,file='Markup (SiSU source)','composite',@f.base_filename.src
+            summarize_sources(desc,id,file,pth,rel,url)
+          end
+        end
+        if FileTest.file?(@f.place_file.sisupod.dir)==true
+          pth=@f.output_path.sisupod.dir
+          rel=@f.output_path.sisupod.rel_sm
+          url=@f.output_path.sisupod.url
+          desc,id,file='SiSUdoc pod (tar.xz)','sisupod',@f.base_filename.sisupod
+          summarize_sources(desc,id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.pot.dir)==true
+          pth=@f.output_path.pot.dir
+          rel=@f.output_path.pot.rel_sm
+          url=@f.output_path.pot.url
+          desc,id,file='SiSU pot','pot',@f.base_filename.pot
+          summarize_sources(desc,id,file,pth,rel,url)
+        end
+      end
+      def metadata_tests
+        if defined? @md.title                                                   #%
+          if defined? @md.title.full \
+          and @md.title.full=~/\S+/
+            desc,id,info=@translate.full_title,'title',@md.title.full
+            metadata(desc,id,info)
+          end
+        end
+        if defined? @md.creator                                                 #%
+          if defined? @md.creator.author \
+          and @md.creator.author=~/\S+/
+            desc,id,info=@translate.author,'author',@md.creator.author
+            metadata(desc,id,info)
+          end
+          if defined? @md.creator.editor \
+          and @md.creator.editor=~/\S+/
+            desc,id,info=@translate.editor,'editor',@md.creator.editor
+            metadata(desc,id,info)
+          end
+          if defined? @md.creator.contributor \
+          and @md.creator.contributor=~/\S+/
+            desc,id,info=@translate.contributor,'contributor',@md.creator.contributor
+            metadata(desc,id,info)
+          end
+          if defined? @md.creator.translator \
+          and @md.creator.translator=~/\S+/
+            desc,id,info=@translate.translator,'creator',@md.creator.translator
+            metadata(desc,id,info)
+          end
+          if defined? @md.creator.illustrator \
+          and @md.creator.illustrator=~/\S+/
+            desc,id,info=@translate.illustrator,'illustrator',@md.creator.illustrator
+            metadata(desc,id,info)
+          end
+          if defined? @md.creator.prepared_by \
+          and @md.creator.prepared_by=~/\S+/
+            desc,id,info=@translate.prepared_by,'prepared_by',@md.creator.prepared_by
+            metadata(desc,id,info)
+          end
+          if defined? @md.creator.digitized_by \
+          and @md.creator.digitized_by=~/\S+/
+            desc,id,info=@translate.digitized_by,'designed_by',@md.creator.digitized_by
+            metadata(desc,id,info)
+          end
+        end
+        if defined? @md.rights
+          if defined? @md.rights.all \
+          and @md.rights.all=~/\S+/ #dc
+            desc,id,info=@translate.rights,'rights',@md.rights.all
+            metadata(desc,id,info)
+          end
+        end
+        if defined? @md.date                                                    #%
+          if defined? @md.date.published \
+          and @md.date.published=~/\S+/ #dc
+            desc,id,info=@translate.date,'date',@md.date.published
+            metadata(desc,id,info)
+          end
+          if defined? @md.date.created \
+          and @md.date.created=~/\S+/ #dc
+            desc,id,info=@translate.date_created,'date_created',@md.date.created
+            metadata(desc,id,info)
+          end
+          if defined? @md.date.issued \
+          and @md.date.issued=~/\S+/ #dc
+            desc,id,info=@translate.date_issued,'date_issued',@md.date.issued
+            metadata(desc,id,info)
+          end
+          if defined? @md.date.available \
+          and @md.date.available=~/\S+/ #dc
+            desc,id,info=@translate.date_available,'date_available',@md.date.available
+            metadata(desc,id,info)
+          end
+          if defined? @md.date.modified \
+          and @md.date.modified=~/\S+/ #dc
+            desc,id,info=@translate.date_modified,'date_modified',@md.date.modified
+            metadata(desc,id,info)
+          end
+          if defined? @md.date.valid \
+          and @md.date.valid=~/\S+/ #dc
+            desc,id,info=@translate.date_valid,'date_valid',@md.date.valid
+            metadata(desc,id,info)
+          end
+        end
+        if defined? @md.publisher \
+        and @md.publisher=~/\S+/ #dc
+          desc,id,info=@translate.publisher,'publisher',@md.publisher
+          metadata(desc,id,info)
+        end
+        if defined? @md.notes                                                   #%
+          if defined? @md.notes.description \
+          and @md.notes.description=~/\S+/
+            desc,id,info=@translate.description,'description',@md.notes.description
+            metadata(desc,id,info)
+          end
+          if defined? @md.notes.abstract \
+          and @md.notes.abstract=~/\S+/
+            desc,id,info=@translate.abstract,'abstract',@md.notes.abstract
+            metadata(desc,id,info)
+          end
+          if defined? @md.notes.comment \
+          and @md.notes.comment=~/\S+/
+            desc,id,info=@translate.comments,'comment',@md.notes.comment
+            metadata(desc,id,info)
+          end
+          if defined? @md.notes.prefix_a \
+          and @md.notes.prefix_a=~/\S+/
+            desc,id,info=@translate.prefix_a,'prefix',@md.notes.prefix_a
+            metadata(desc,id,info)
+          end
+          if defined? @md.notes.prefix_b \
+          and @md.notes.prefix_b=~/\S+/
+            desc,id,info=@translate.prefix_b,'prefix_b',@md.notes.prefix_b
+            metadata(desc,id,info)
+          end
+        end
+        if defined? @md.title                                                   #%
+          if defined? @md.title.language \
+          and @md.title.language=~/\S+/
+            desc,id,info=@translate.language,'language',@md.title.language
+            metadata(desc,id,info)
+          end
+          if defined? @md.original.language \
+          and @md.original.language=~/\S+/
+            desc,id,info=@translate.language_original,'language_original',@md.original.language
+            metadata(desc,id,info)
+          end
+        end
+        if defined? @md.classify                                                #%
+          if defined? @md.topic_register_array \
+          and @md.topic_register_array.length > 0
+            @manifest[:html] << %{<tr><th class="left"><p class="bold_left" id="topics">#{@translate.topic_register}:</p></th><td>\n}
+            @md.topic_register_array.each do |t|
+              t.each_with_index do |st,i|
+                if st.is_a?(Array)
+                  st.each do |v|
+                    if v.is_a?(Array)
+                      v.each do |w|
+                        @manifest[:html] << %{<p class="it#{i}">#{w}</p>\n}
+                      end
+                    else
+                      @manifest[:html] << %{<p class="it#{i}">#{v}</p>\n}
+                    end
+                  end
+                else @manifest[:html] << %{<p class="it#{i}">#{st}</p>\n}
+                end
+              end
+            end
+            @manifest[:html] << %{</td></tr>\n}
+          end
+          if defined? @md.classify.subject \
+          and @md.classify.subject=~/\S+/
+            desc,id,info=@translate.subject,'subject',@md.classify.subject
+            metadata(desc,id,info)
+          end
+          if defined? @md.classify.keywords \
+          and @md.classify.keywords=~/\S+/
+            desc,id,info=@translate.keywords,'keywords',@md.classify.keywords
+            metadata(desc,id,info)
+          end
+          if defined? @md.classify.loc \
+          and @md.classify.loc=~/\S+/
+            desc,id,info=@translate.cls_loc,'loc',@md.classify.loc
+            metadata(desc,id,info)
+          end
+          if defined? @md.classify.dewey \
+          and @md.classify.dewey=~/\S+/
+            desc,id,info=@translate.cls_dewey,'dewey',@md.classify.dewey
+            metadata(desc,id,info)
+          end
+          if defined? @md.notes.coverage \
+          and @md.notes.coverage=~/\S+/
+            desc,id,info=@translate.coverage,'coverage',@md.notes.coverage
+            metadata(desc,id,info)
+          end
+          if defined? @md.notes.relation \
+          and @md.notes.relation=~/\S+/
+            desc,id,info=@translate.relation,'relation',@md.notes.relation
+            metadata(desc,id,info)
+          end
+          if defined? @md.notes.type \
+          and @md.notes.type=~/\S+/ #dc
+            desc,id,info=@translate.type,'type',@md.notes.type
+            metadata(desc,id,info)
+          end
+          if defined? @md.notes.format \
+          and @md.notes.format=~/\S+/
+            desc,id,info=@transate.format,'format',@md.notes.format
+            metadata(desc,id,info)
+          end
+        end
+        if defined? @md.identifier                                              #%
+          if defined? @md.identifier.oclc \
+          and @md.identifier.oclc=~/\S+/
+            desc,id,info=@translate.cls_oclc,'',@md.identifier.oclc
+            @manifest[:html] << %{<tr><th class="left"><p class="bold_left">#{desc}:</p></th><td>\n}
+            @manifest[:html] << %{<p class="left"><a href="http://worldcat.org/oclc/#{info}">#{info}</a></p>\n}
+            @manifest[:html] << %{</td></tr>\n}
+          end
+          if defined? @md.identifier.pg \
+          and @md.identifier.pg=~/\S+/
+            desc,id,info=@translate.cls_gutenberg,'ocalc',@md.identifier.pg
+            metadata(desc,id,info)
+          end
+          if defined? @md.identifier.isbn \
+          and @md.identifier.isbn=~/\S+/
+            desc,id,info=@translate.cls_isbn,'isbn',@md.identifier.isbn
+            metadata(desc,id,info)
+          end
+        end
+        if defined? @md.original.source \
+        and @md.original.source=~/\S+/
+          desc,id,info=@translate.source,'source_original',@md.original.source
+          metadata(desc,id,info)
+        end
+        if @md.fns
+          desc,id,info=@translate.sourcefile,'source_filename',@md.fns
+          metadata(desc,id,info)
+        end
+        if @md.en[:mismatch] > 0
+          desc,id,info='WARNING document error in endnote markup, number mismatch','',"endnotes: #{@md.en[:note]} != endnote reference marks: #{@md.en[:mark]} (difference = #{@md.en[:mismatch]})"
+          metadata(desc,id,info)
+        end
+        if @md.wc_words
+          desc,id,info=@translate.word_count,'wordcount',@md.wc_words
+          metadata(desc,id,info)
+        end
+        if @md.dgst
+          desc,id,info="#{@translate.sourcefile_digest} (#{@dg})",'digests',@md.dgst[1]
+          metadata(desc,id,info)
+        end
+        if @md.sc_number
+          desc,id,info=@translate.sc_number,'sc_number',@md.sc_number
+          metadata(desc,id,info)
+        end
+        if @md.sc_date
+          desc,id,info=@translate.sc_date,'sc_date',"#{@md.sc_date} at #{@md.sc_time}"
+          metadata(desc,id,info)
+        end
+        if @md.generated
+          desc,id,info=@translate.last_generated,'generated',@md.generated
+          metadata(desc,id,info)
+        end
+        if @md.project_details
+          desc,id,info=@translate.sisu_version,'project',"#{@md.project_details.project} #{@md.project_details.version} #{@md.project_details.date_stamp} (#{@md.project_details.date})#{@md.project_details.install_method}"
+          metadata(desc,id,info)
+        end
+        if @md.ruby_version
+          desc,id,info=@translate.ruby_version,'ruby',@md.ruby_version
+          metadata(desc,id,info)
+        end
+      end
+      def links_tests
+        if defined? @md.lnk \
+        and @md.lnk
+          @md.lnk.each do |l|
+            if defined? l[:say]
+              target=(l[:url] !~/^\.(\.)?\//) \
+              ? 'external'
+              : '_top'
+              url,lnk=l[:url],l[:say]
+              unless url.nil? \
+              or url.empty?
+                links(url,lnk,target)
+              end
+            end
+          end
+        end
+      end
+      def check_output(data)
+        begin
+          make=SiSU_Env::ProcessingSettings.new(@md)
+          minitoc=SiSU_HTML_MiniToc::TocMini.new(@md,data).songsheet.join("\n")
+          format_head_toc=SiSU_HTML_Format::HeadToc.new(@md)
+          @manifest[:html] <<<<WOK
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>
+SiSU manifest: #{@md.title.full}
+</title>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+<meta name="sourcefile" content="#{@md.fns}" />
+<link rel="generator" href="http://www.jus.uio.no/sisu" />
+<link rel="shortcut icon" href="#{@f.path_rel_links.html_scroll_css}_sisu/image_sys/rb7.ico" />
+#{@stylesheet.css_head}
+</head>
+<body lang="#{@md.opt.lng}">
+#{format_head_toc.seg_head_navigation_band(:manifest)}
+WOK
+          if make.build.manifest_minitoc?
+            if @o_str.dump_or_redirect?
+            elsif @f.output_dir_structure.by_language_code? \
+            or @f.output_dir_structure.by_filetype?
+              minitoc=minitoc.gsub(/<a href="(\S+?)"/m,%{<a href="../html/#{@md.fnb}/\\1"}).
+                gsub(/<a href="\.\.\/html\/#{@md.fnb}\/(?:sisu_manifest\.html|#{@f.base_filename.manifest})"/m,
+              %{<a href="#{@f.base_filename.manifest}"})
+            end
+            @manifest[:html] <<<<WOK
+<div class="toc">
+#{minitoc.to_s}
+</div>
+<div class="content">
+WOK
+          else
+            @manifest[:html] <<<<WOK
+<div>
+WOK
+          end
+          if @o_str.dump_or_redirect?
+          elsif @f.output_dir_structure.by_language_code? \
+          or @f.output_dir_structure.by_filetype?
+            pth_local=@f.output_path.manifest.dir
+            pth_rel='.'
+          else
+            pth_local=@f.output_path.base.dir
+            pth_rel='..'
+          end
+          pth_rel_home=if @env.output_dir_structure.by? == :language
+            '../..'
+          elsif @env.output_dir_structure.by? == :filetype
+            '..'
+          elsif @env.output_dir_structure.by? == :filename
+            '..'
+          else '..'
+          end
+          output_organised_by="(output organised by #{@env.output_dir_structure.by?})"
+          harvest=(FileTest.file?("#{pth_local}/authors#{@fn_lng}.html") \
+          && FileTest.file?("#{pth_local}/topics#{@fn_lng}.html")) \
+          ? %{<p class="small"><a href="#{pth_rel_home}/index.html">.:</a> other document manifests: [<a href="#{pth_rel}/authors#{@fn_lng}.html">authors</a>] [<a href="#{pth_rel}/topics#{@fn_lng}.html">topics</a>] #{output_organised_by}</p>}
+          : %{<p class="small"><a href="#{pth_rel_home}">#{output_organised_by}</a></p>}
+          manifest_title=%{<p class="bold">#{@translate.manifest_description}</p>#{harvest}}
+          @manifest[:html] <<<<WOK
+<div id="horizontal_links">
+#{manifest_title}
+</div>
+<h1 class="small">#{@md.title.full}</h1>
+<p class="bold">#{@md.author}</p>
+<div id="horizontal_links"><p class="bold">
+<p class="small">
+&nbsp;&nbsp;<a href="#output">Document, Available Filetypes</a>
+</p>
+<p class="small">
+&nbsp;&nbsp;<a href="#metadata">Document Metadata</a>
+</p>
+<p class="tiny">
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#links">metadata suggested links (if any)</a>
+</p>
+</div>
+<table summary="normal text css" width="100%" border="0" cellpadding="2" align="center">
+WOK
+          published_versions
+          @manifest[:html] << '</table>'
+          @manifest[:html] <<<<WOK
+<h2 class="small"><a name="output">#{@translate.manifest_description_output}</a></h2>
+<table summary="available output/filetypes" width="100%" border="0" cellpadding="2" align="center">
+<tr> <th class="left"><p class="bold">#{@translate.filetype_description}</p></th><th class="left"><p class="bold">#{@translate.filename}</p></th><th class="right"><p class="right"><b>#{@translate.file_size}</b></p><p class="tiny_right">(kB)</p></th></tr>
+
+WOK
+          output_tests
+          @manifest[:html] << '</table>'
+          @manifest[:html] <<<<WOK
+<table summary="normal text css" width="100%" border="0" cellpadding="2" align="center">
+WOK
+          source_tests
+          @manifest[:html] << '</table>'
+          @manifest[:html] <<<<WOK
+<h2 class="small"><a name="metadata">#{@translate.manifest_description_metadata}</a></h2>
+<table summary="document metadata" width="100%" border="0" cellpadding="2" align="center">
+<tr> <th class="left"><p class="bold" id="metadata">#{@translate.metadata}</p></th><th class="left"><p class="bold">#{@translate.description}</p></th></tr>
+WOK
+          metadata_tests
+          @manifest[:html] <<<<WOK
+</table>
+WOK
+          @manifest[:html] <<<<WOK
+<p class="bold"><a name="links">#{@translate.suggested_links}:</a></p>
+<table summary="suggested links" width="100%" border="0" cellpadding="2" align="center">
+WOK
+          links_tests
+          @manifest[:html] <<<<WOK
+</table>
+WOK
+          @manifest[:html] <<<<WOK
+<h2 class="small"><a name="languages">#{@translate.language_version_list}</a></h2>
+<table summary="language versions" width="100%" border="0" cellpadding="2" align="center">
+<tr> <th class="left"><p class="bold">#{@translate.filename}</p></th><th class="left"><p class="bold">#{@translate.description}</p></th><th class="right"><p class="right">&nbsp;</p></th></tr>
+
+WOK
+          language_versions
+          qrc_image
+          @manifest[:html] <<<<WOK
+</table>
+</div>
+<div>
+<br>
+#{SiSU_Proj_HTML::Bits.new.credits_sisu_manifest}
+</div>
+</body>
+</html>
+WOK
+          output
+        rescue
+          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+        ensure
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+*** html_persist.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/html_persist.rb"
+# <<sisu_document_header>>
+Module SiSU_HTML_Persist
+  class Persist
+    @@persist=nil
+    attr_accessor :is0,:is1,:is2,:is3,:is4,:heading0,:heading1,:heading2,:heading3,:heading4, :title, :dot_nav, :tocband_banner, :tocband_bannerless, :headings, :heading_endnotes, :main, :endnote_all, :tail, :credits, :heading_idx, :idx, :seg_endnotes, :seg_endnotes_array, :segtocband, :get_hash_fn, :get_hash_to, :seg_subtoc, :seg_subtoc_array, :fn, :seg_name ,:seg_name_x,:seg_name_x_tracker
+    def initialize(args=nil)
+      @@persist=args=(args ? args : (@@persist || persist_init_hash_values))
+      @is0=args[:is0]
+      @is1=args[:is1]
+      @is2=args[:is2]
+      @is3=args[:is3]
+      @is4=args[:is4]
+      @heading0=args[:heading0]
+      @heading1=args[:heading1]
+      @heading2=args[:heading2]
+      @heading3=args[:heading3]
+      @heading4=args[:heading4]
+      @title=args[:title]
+      @dot_nav=args[:dot_nav]
+      @tocband_banner=args[:tocband_banner]
+      @tocband_bannerless=args[:tocband_bannerless]
+      @headings=args[:headings]
+      @heading_endnotes=args[:heading_endnotes]
+      @main=args[:main]
+      @endnote_all=args[:endnote_all]
+      @tail=args[:tail]
+      @credits=args[:credits]
+      @heading_idx=args[:heading_idx]
+      @idx=args[:idx]
+      @seg_endnotes=args[:seg_endnotes]
+      @seg_endnotes_array=args[:seg_endnotes_array]
+      @get_hash_to=args[:get_hash_to]
+      @get_hash_fn=args[:get_hash_fn]
+      @seg_subtoc=args[:seg_subtoc]
+      @seg_subtoc_array=args[:seg_subtoc_array]
+      @segtocband=args[:fn]
+      @fn=args[:fn]
+      @seg_name=args[:seg_name]
+      @seg_name_x=args[:seg_name_x]
+      @seg_name_x_tracker=args[:seg_name_x_tracker]
+    end
+    def is0
+      @is0
+    end
+    def is1
+      @is1
+    end
+    def is2
+      @is2
+    end
+    def is3
+      @is3
+    end
+    def is4
+      @is4
+    end
+    def heading0
+      @heading0
+    end
+    def heading1
+      @heading1
+    end
+    def heading2
+      @heading2
+    end
+    def heading3
+      @heading3
+    end
+    def heading4
+      @heading4
+    end
+    def title
+      @title
+    end
+    def dot_nav
+      @dot_nav
+    end
+    def tocband_banner
+      @tocband_banner
+    end
+    def tocband_bannerless
+      @tocband_bannerless
+    end
+    def headings
+      @headings
+    end
+    def heading_endnotes
+      @heading_endnotes
+    end
+    def main
+      @main
+    end
+    def endnote_all
+      @endnote_all
+    end
+    def tail
+      @tail
+    end
+    def credits
+      @credits
+    end
+    def heading_idx
+      @heading_idx
+    end
+    def idx
+      @idx
+    end
+    def seg_endnotes
+      @seg_endnotes
+    end
+    def seg_endnotes_array
+      @seg_endnotes_array
+    end
+    def get_hash_to
+      @get_hash_to
+    end
+    def get_hash_fn
+      @get_hash_fn
+    end
+    def seg_subtoc
+      @seg_subtoc
+    end
+    def seg_subtoc_array
+      @seg_subtoc_array
+    end
+    def segtocband
+      @segtocband
+    end
+    def fn
+      @fn
+    end
+    def seg_name
+      @seg_name
+    end
+    def seg_name_x
+      @seg_name_x
+    end
+    def seg_name_x_tracker
+      @seg_name_x_tracker
+    end
+    def persist_init_hash_values
+      {
+        is0: 0,
+        is1: 0,
+        is2: 0,
+        is3: 0,
+        is4: 0,
+        heading0: '',
+        heading1: '',
+        heading2: '',
+        heading3: '',
+        heading4: '',
+        tocband_banner: [],
+        tocband_bannerless: [],
+        title: [],
+        headings: [],
+        main: [],
+        idx: [],
+        tail: [],
+        credits: [],
+        endnote_all: [],
+        heading_endnotes: '',
+        seg_endnotes: {},
+        seg_endnotes_array: [],
+        get_hash_fn: '',
+        get_hash_to: '',
+        seg_subtoc: {},
+        seg_subtoc_array: [],
+        segtocband: '',
+        fn: '',
+        seg_name: [],
+        seg_name_x: [],
+        seg_name_x_tracker: 0,
+      }
+    end
+    def persist_init
+      @@persist=nil
+      Persist.new(persist_init_hash_values)
+    end
+  end
+end
+__END__
+#+END_SRC
+
+*** html_promo.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/html_promo.rb"
+# <<sisu_document_header>>
+module SiSU_HTML_Promo
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  class Ad
+    def initialize(md)
+      @md=md
+      @env=SiSU_Env::InfoEnv.new(@md.fns,@md)
+      @rc=SiSU_Env::GetInit.new.sisu_yaml.rc
+      @ad=SiSU_Env::GetInit.new.ads
+      @flag=@env.widget.promo?
+      @make=SiSU_Env::ProcessingSettings.new(@md)
+    end
+    def div
+      def major
+        (@make.build.html_right_pane? \
+         && @flag[:ad]) \
+        ? '<div id="pane_major">'
+        : ''
+      end
+      def minor
+        (@make.build.html_right_pane? \
+         && @flag[:ad]) \
+        ? '<div id="pane_minor">'
+        : ''
+      end
+      def close
+        (@make.build.html_right_pane? \
+         && @flag[:ad]) \
+        ? '</div>'
+        : ''
+      end
+      self
+    end
+    def display
+      ads_array,promo_array=[],[]
+      if @make.build.html_right_pane? \
+      && @flag[:ad]
+        ads=if @md.promo && @md.promo.length > 0           #promo set in document
+          promo_array=@md.promo
+        elsif @flag[:rc]                                   #promo set in rc file
+          promo_array=if @rc['html']['promo'].is_a?(String)
+            @rc['html']['promo'].split(/[,;]\s*/)
+          else @rc['html']['promo']
+          end
+        else advert_extract_all
+        end
+        ads=if promo_array.length > 0
+          promo_array.each do |x|
+            ads_array << advert_extract_subject(x)
+          end
+          ads_array
+        end
+        adverts(ads.join)
+      end
+    end
+    def cell(prod,id)
+      @prod,@id=prod,id
+      def title
+        @prod['title'] ? %{<b>#{@prod['title']}</b>} : ''
+      end
+      def subtitle
+        @prod['subtitle'] ? %{ - #{@prod['subtitle']}} : ''
+      end
+      def author
+        @prod['author'] ? %{<p class="pane">#{@prod['author']}</p>} : ''
+      end
+      def editor
+        @prod['editor'] ? %{<p class="pane">#{@prod['editor']}</p>} : ''
+      end
+      def year
+        @prod['year'] ? %{<p class="pane">#{@prod['year']}</p>} : ''
+      end
+      def date
+        @prod['date'] ? %{<p class="pane">On: #{@prod['date']}</p>} : ''
+      end
+      def location
+        @prod['at'] ? %{<p class="pane">At: #{@prod['at']}</p>} : ''
+      end
+      def pages
+        @prod['pages'] ? %{<p class="pane">Pages: #{@prod['pages']} pages</p>} : ''
+      end
+      def form
+        @prod['form'] ? %{<p class="pane">#{@prod['form']}</p>} : ''
+      end
+      def nick
+        @prod['nick'] ? %{(#{@prod['nick']})<br>} : ''
+      end
+      def update
+        @prod['update'] ? %{<p class="pane">Updated: #{@prod['update']}</p>} : ''
+      end
+      def issn
+        @prod['issn'] ? %{<p class="pane">issn: #{@prod['issn']}</p>} : ''
+      end
+      def blurb
+        @prod['blurb'] ? %{<p class="pane_blurb">#{@prod['blurb']}</p>} : ''
+      end
+      def search_form_sisu(table=true)
+        db=if @prod['db']=~/\S+/
+          (@prod['db']=~/^#{Db[:name_prefix]}\S+/) ? @prod['db'] : "#{Db[:name_prefix]}#{@prod['db']}"
+        elsif defined? @rc['search']['sisu']['db'] \
+        and @rc['search']['sisu']['db'] =~/\S+/
+          (@rc['search']['sisu']['db']=~/^#{Db[:name_prefix]}\S+/) \
+          ? @prod['search']['sisu']['db']
+          : "#{Db[:name_prefix]}#{@prod['db']}"
+        else nil
+        end
+        action=if @prod['action']=~/^https?:\/\//
+          @prod['action']
+        elsif defined? @rc['search']['sisu']['action'] \
+        and @rc['search']['sisu']['action'] =~/^https?:\/\//
+          @rc['search']['sisu']['action']
+        else nil
+        end
+        if action \
+        and db
+          @env.widget.search_form('sisusearch',action,db,table)
+        else ''
+        end
+      end
+      def search_form_hyperestraier(table=true)
+        action=if defined? @rc['search']['hyperestraier']['action'] \
+        and @rc['search']['hyperestraier']['action'] =~/^https?:\/\//
+          @rc['search']['hyperestraier']['action']
+        else nil
+        end
+        form=if action
+          '<br>' + @env.widget.search_form('hyperestraier',action,'',table)
+        else ''
+        end
+        form
+      end
+      def links
+        if @prod['links'] #and @prod['links']==Array
+          links_a=[]
+          @prod['links'].each do |x|
+            if x \
+            and x['url'] \
+            and x['title']
+              subtitle=x['subtitle'] ? %{ - #{x['subtitle']}} : ''
+              url_=(x['url'] =~/https?:/) ? x['url'] : "../#{x['url']}"
+              links_a << %{<p class="pane_link"><a href="#{url_}">#{x['title']}#{subtitle}</a></p>\n}
+            end
+          end
+          links_a.join
+        else ''
+        end
+      end
+      def image
+        @prod['image'] ? %{<img border="0" src="../_sisu/image/#{@prod['image']}" /><br>} : ''
+      end
+      def url_link
+        @url_=if @prod['url'] =~/https?:/
+          "#{@prod['url']}"
+        else "../#{@prod['url']}" # "#{@env.url.root}/#{@prod['url']}"
+        end
+        def show
+          @prod['url'] ? %{<p class="pane_link"><a href="#{@url_}">#{@url_}</a></p>} : ''
+        end
+        def url
+          @prod['url'] ? %{<a href="#{@url_}">} : ''
+        end
+        def url_relative
+          @prod['url'] ? %{<a href="../#{@prod['url']}/toc.html">} : ''
+        end
+        self
+      end
+      def flyer
+        if @prod['flyer']
+          %{<p class="pane"><a href="../man/pdf/#{@id}.pdf"><img border="0" height="18" width="15" src="../_sisu/image/b_pdf.png">&nbsp;PDF&nbsp;flyer</a></p>}
+        else ''
+        end
+      end
+      def price
+        def gbp
+          if defined? @prod['price']['gbp'] \
+          and @prod['price']['gbp']
+            " &nbsp;&pound;&nbsp;#{@prod['price']['gbp']}&nbsp;(GBP)&nbsp;"
+          else ''
+          end
+        end
+        def euro
+          if defined? @prod['price']['euro'] \
+          and @prod['price']['euro']
+            " &nbsp;&euro;&nbsp;#{@prod['price']['euro']}&nbsp;(Euro)&nbsp;"
+          else ''
+          end
+        end
+        def usd
+          if defined? @prod['price']['usd'] \
+          and @prod['price']['usd']
+            " &nbsp;$&nbsp;#{@prod['price']['usd']}&nbsp;(USD)&nbsp;"
+          else ''
+          end
+        end
+        %{<p class="pane">Price:#{gbp}#{euro}#{usd}</p>}
+      end
+      def adsense #draw content from a configuration file
+        def column_right
+          if defined? @ad[:promo]['ad']['adsense']['column_right']
+            @ad[:promo]['ad']['adsense']['column_right'].join("\n")
+          else ''
+          end
+        end
+        def line_single
+          if defined? @ad[:promo]['ad']['adsense']['line_single']
+            @ad[:promo]['ad']['adsense']['line_single'].join("\n")
+          else ''
+          end
+        end
+        self
+      end
+      def site_link #Work area
+        if url_link.url
+           <<-WOK
+<p class="pane">
+#{url_link.url}
+#{image}
+#{title}
+#{subtitle}
+</a>#{nick}</p>
+          WOK
+        else
+         <<-WOK
+<p class="pane">
+#{image}
+#{title}
+#{subtitle}
+</p>
+          WOK
+        end
+      end
+      self
+    end
+    def output_form_sponsor(type,id)
+      cell=cell(@ad[:promo][type][id],prod_id)
+      <<-WOK
+<br>
+#{cell.site_link}
+#{cell.blurb}
+#{cell.links}
+      WOK
+    end
+    def output_form_link(type,id)
+      prod_id=id.gsub(/id_/,'')
+      cell=cell(@ad[:promo][type][id],prod_id)
+       <<WOK
+<br>
+#{cell.site_link}
+#{cell.author}
+#{cell.year}
+#{cell.blurb}
+#{cell.links}
+WOK
+    end
+    def output_form_search_sisu(type,id)
+      prod_id=id.gsub(/id_/,'')
+      cell=cell(@ad[:promo][type][id],prod_id)
+      cell.search_form_sisu(false)
+    end
+    def output_form_search_hyperestraier(type,id)
+      prod_id=id.gsub(/id_/,'')
+      cell=cell(@ad[:promo][type][id],prod_id)
+      cell.search_form_hyperestraier(false)
+    end
+    def output_form_book(type,id)
+      prod_id=id.gsub(/id_/,'')
+      cell=cell(@ad[:promo][type][id],prod_id)
+      prod_type=((id=~/id_(?:[0-9x]){10,13}/i) ? 'isbn' : 'id')
+      id_detail=%{<p class="pane">#{prod_type}: #{prod_id}</p>}
+       <<WOK
+<br>
+#{cell.site_link}
+#{cell.author}
+#{cell.year}
+#{id_detail}
+#{cell.pages}#{cell.form}
+#{cell.price}
+#{cell.flyer}
+#{cell.blurb}
+#{cell.links}
+WOK
+    end
+    def output_form_journal(type,id)
+      prod_id=id.gsub(/id_/,'')
+      cell=cell(@ad[:promo][type][id],prod_id)
+       <<WOK
+<br>
+#{cell.site_link}
+#{cell.editor}
+#{cell.issn}
+#{cell.update}
+#{cell.form}
+#{cell.price.gsub(/Price:/,'Subscription:')}
+#{cell.flyer}
+#{cell.blurb}
+#{cell.links}
+WOK
+    end
+    def output_form_conference(type,id)
+      prod_id=id.gsub(/id_/,'')
+      cell=cell(@ad[:promo][type][id],prod_id)
+#translate date (dd month yyyy) from 2007-03-04 and ruby conversion
+       <<WOK
+<br>
+#{cell.site_link}
+#{cell.date}
+#{cell.location}
+#{cell.price}
+#{cell.flyer}
+#{cell.blurb}
+#{cell.links}
+WOK
+    end
+    def output_form_select(type,id)
+      case type
+      when /site/
+        output_form_link(type,id)
+      when /sponsor/
+        output_form_sponsor(type,id)
+      when /search/
+        if id=~/hyperestraier/
+          output_form_search_hyperestraier(type,id)
+        else output_form_search_sisu(type,id)
+        end
+      when /book/
+        output_form_book(type,id)
+      when /journal/
+        output_form_journal(type,id)
+      when /conference/
+        output_form_conference(type,id)
+      end
+    end
+    def advert_extract_subject(category) #extracts products from category/subject list
+      adverts=[]
+      if defined? @ad[:promo_list][category] \
+      and @ad[:promo_list][category]
+        @ad[:promo_list][category].keys.each do |type|
+          @ad[:promo_list][category][type].each do |i|
+            if i
+              id=((i.inspect =~/^\d/) ? "id_#{i.to_s.strip}" : i.to_s.strip) #watch remove .to_s ?
+              if defined? @ad[:promo][type][id] \
+              and not @ad[:promo][type][id].nil?
+                adverts << output_form_select(type,id)
+              else
+                if defined? @ad[:promo][category][type][id] \
+                and @ad[:promo][category][type][id].is_a?(Array) \
+                and @ad[:promo][category][type][id].length > 0
+                  adverts << @ad[:promo][category][type][id].join("\n")
+                end
+              end
+            end
+          end
+        end
+      else
+        SiSU_Screen::Ansi.new(
+          @md.opt.act[:color_state][:set],
+          "*WARN* category not found: #{category}"
+        ).warn unless @md.opt.act[:quiet][:set]==:on
+      end
+      adverts.join
+    end
+    def advert_extract_all #extracts all products from list (which is broken down into categories)
+      adverts=[]
+      @ad[:promo_list].keys.each do |category|
+        adverts << advert_extract_subject(category)
+      end
+      adverts.flatten
+    end
+    def adverts(ads)
+      <<WOK
+#{div.minor}
+#{ads}
+#{div.close}
+WOK
+    end
+    def no_adverts
+      <<WOK
+#{div.minor}
+#{div.close}
+WOK
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    html
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/hub.org b/org/hub.org
new file mode 100644
index 00000000..3199aa35
--- /dev/null
+++ b/org/hub.org
@@ -0,0 +1,3163 @@
+-*- mode: org -*-
+#+TITLE:       sisu hub
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:hub:
+#+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
+
+* hub
+** hub.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/hub.rb"
+# <<sisu_document_header>>
+module SiSU
+  require_relative 'constants'                         # constants.rb
+  require_relative 'se'                                # se.rb
+    include SiSU_Env
+    include SiSU_Screen
+  require_relative 'hub_actions'                       # hub_actions.rb
+  require_relative 'hub_loop_markup_files'             # hub_loop_markup_files.rb
+  require_relative 'hub_options'                       # hub_options.rb
+  require_relative 'dp'                                # dp.rb
+    include SiSU_Param
+  require_relative 'utils'                             # utils.rb
+  begin
+    require 'uri'
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('uri NOT FOUND (LoadError)')
+  end
+  class HubMaster
+    def initialize(argv,sisu_runtime)
+      begin
+        opt=SiSU_Commandline::Options.new(argv,sisu_runtime)
+        SiSU::Processing.new(opt).actions_without_files
+        SiSU::Processing.new(opt).actions_on_files
+        SiSU::Processing.new(opt).actions_without_files_post
+      rescue
+        selection=(opt ? opt.selections.src : argv)
+        SiSU_Screen::Ansi.new(selection,$!,$@).rescue do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        Dir.chdir(sisu_runtime[:call_path])
+      end
+    end
+  end
+  class Processing
+    begin
+      require 'fileutils'
+        include FileUtils
+    rescue LoadError
+      SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+        error('fileutils NOT FOUND (LoadError)')
+    end
+    @@env=nil
+    attr_accessor :op
+    def initialize(opt)
+      @opt=opt
+      @@env=@env=SiSU_Env::InfoEnv.new
+      @msg,@msgs='',nil
+      @tell=lambda {
+        SiSU_Screen::Ansi.new(
+          @opt.selections.str,
+          @msg,
+          "#{@msgs.inspect if @msgs}"
+        )
+      }
+    end
+    def remove_skipped_files_if_any_from_processing_files_array
+      if @remove_faulty_markup_files_array.length > 0
+        @opt.files = (@opt.files - @remove_faulty_markup_files_array)
+      end
+    end
+    def print_error_message_if_files_skipped
+      if @remove_faulty_markup_files_array.length > 0
+        puts '---'
+        STDERR.puts 'ERROR with file(s), did not process: ' +
+          @remove_faulty_markup_files_array.join(',')
+      end
+    end
+    def do_each_file_loop_check_and_perform_selected_actions(opt)
+      actions=SiSU_Hub_Actions::HubActions.new(opt)
+      actions.outputs.each_file.abstract_objects?
+      actions.outputs.each_file.qrcode?
+      actions.outputs.each_file.hash_digests?
+      actions.outputs.each_file.text?
+      actions.outputs.each_file.html?
+      actions.outputs.each_file.xhtml?
+      actions.outputs.each_file.xml?
+      actions.outputs.each_file.json?
+      actions.outputs.each_file.pdf?
+      actions.outputs.each_file.man_or_info?
+      actions.outputs.each_file.po4a_make?
+      actions.outputs.each_file.sqlite_discrete?
+      actions.outputs.each_file.manifest?
+    end
+    def do_each_file_loop_options
+      if @opt.files.length > 0
+        @opt.files.each_with_index do |fno,i|
+          @opt.fno=fno
+          @opt.fns=fno.
+            gsub(/(?:https?|file):\/\/\S+\/(\S+)\.sst$/,'\1.-sst').
+            gsub(/\.ssm$/,'.ssm.sst')
+          @opt.f_pth=@opt.f_pths[i]
+          if @opt.fns !~/\.-sst$/
+            @opt.pth=@opt.f_pths[i][:pth]
+            @opt.lng=@opt.f_pths[i][:lng]
+          else
+            @opt.pth=Dir.pwd
+            @opt.lng='en'
+          end
+          unless @opt.pth.nil?
+            @@pwd=@opt.pth
+            Dir.chdir(@opt.pth) #watch
+          end
+          #@env=SiSU_Env::InfoEnv.new(@opt.fns)
+          do_each_file_loop_check_and_perform_selected_actions(@opt)
+        end
+      else
+        do_each_file_loop_check_and_perform_selected_actions(@opt)
+      end
+    end
+    def do_loop_files_on_given_option_pre
+      begin
+        if @opt.act[:zap][:set]==:on                   #% --zap, -Z
+          SiSU_Hub_Loops::OptionLoopFiles.new(@opt).loop_files_on_given_option do
+            require_relative 'zap'
+            SiSU_Zap::Source.new(@opt).read            # -Z     zap.rb
+          end
+        end
+      ensure
+      end
+    end
+    def do_loop_files_on_given_option_post
+      actions=SiSU_Hub_Actions::HubActions.new(@opt)
+      if defined? actions.outputs.loop_files.share_source?
+        actions.outputs.loop_files.share_source?
+      end
+      if defined? actions.outputs.loop_files.run_termsheet?
+        actions.outputs.loop_files.run_termsheet?
+      end
+      if defined? actions.outputs.loop_files.po4a_setup?
+        actions.outputs.loop_files.po4a_setup?
+      end
+      if defined? actions.outputs.loop_files.sql?
+        actions.outputs.loop_files.sql?
+      end
+      SiSU_Hub_Actions::Operations.new.counter
+      if defined? actions.outputs.loop_files.manifest?
+        actions.outputs.loop_files.manifest?
+      end
+      if defined? actions.outputs.loop_files.sitemaps?
+        actions.outputs.loop_files.sitemaps?
+      end
+      if defined? actions.outputs.loop_files.urls?
+        actions.outputs.loop_files.urls?
+      end
+    end
+    def actions_without_files
+      actions=SiSU_Hub_Actions::HubActions.new(@opt)
+      actions.report.version_info?
+      actions.report.version_info_extra?
+      actions.prepare.site?
+      actions.prepare.sql?
+    end
+    def actions_without_files_post
+      actions=SiSU_Hub_Actions::HubActions.new(@opt)
+      actions.prepare.remote_site?
+      actions.prepare.search_form?
+      actions.prepare.webrick?
+    end
+    def actions_on_files
+      if @opt.act[:profile][:set]==:on
+        begin
+          require 'profile'
+        rescue LoadError
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+            error('profile NOT FOUND (LoadError)')
+        end
+      end
+      actions=SiSU_Hub_Actions::HubActions.new(@opt)
+      actions.outputs.each_file.harvest?
+      actions.outputs.init?
+      do_loop_files_on_given_option_pre
+      do_each_file_loop_options
+      #remove_skipped_files_if_any_from_processing_files_array # NEEDS WORK
+      do_loop_files_on_given_option_post
+      #print_error_message_if_files_skipped
+      if (@opt.act[:verbose][:set]==:on \
+      || @opt.act[:verbose_plus][:set]==:on \
+      || @opt.act[:maintenance][:set]==:on)
+        @msg,@msgs="\tsisu -W [to start ruby web-server on output directory]\n",nil
+      end
+      if (@opt.act[:verbose][:set]==:on \
+      || @opt.act[:verbose_plus][:set]==:on \
+      || @opt.act[:maintenance][:set]==:on \
+      || @opt.act[:urls_selected][:set]==:on \
+      || @opt.act[:urls_all][:set]==:on)
+        @tell.call.print_brown unless @opt.files.join.empty?
+      end
+      if defined? @@env.processing_path.processing \
+      and @@env.user \
+      and FileTest.directory?(@@env.processing_path.processing) \
+      and @@env.processing_path.processing =~/#{@@env.user}$/
+        #clean tmp processing dir of content as is located in public area
+        if @@env.processing_path.processing_base_tmp =~/^\/tmp\/\S+/
+          FileUtils::cd(@@env.processing_path.processing_base_tmp) do
+            FileUtils::rm_rf('.') unless @opt.act[:maintenance][:set] ==:on
+          end
+        end
+      end
+    end
+  end
+  class HubClose
+    def initialize(call_path,argv)
+      begin
+        env=SiSU_Env::InfoEnv.new
+      rescue
+      ensure
+        if FileTest.directory?(env.processing_path.processing) \
+        and FileTest.directory?(env.processing_path.processing_base_tmp) \
+        and env.processing_path.processing_base_tmp =~ /#{env.processing_path.processing}/ \
+        and env.processing_path.processing_base_tmp =~/^\/tmp\/\S+/ \
+        and not argv.inspect =~/"--maintenance"|"-M"/
+          FileUtils::cd(env.processing_path.processing_base_tmp) do
+            FileUtils::rm_rf('.')
+          end
+        end
+        Dir.chdir(call_path)
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** hub_options.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/hub_options.rb"
+# <<sisu_document_header>>
+module SiSU_Commandline
+  begin
+    require 'pathname'
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('pathname NOT FOUND (LoadError)')
+  end
+  require_relative 'se'                                 # se.rb
+  require_relative 'dp_make'                            # dp_make.rb
+  class HeaderCommon
+    def sisu_document_make_instructions(make_instruct_array=:nil)
+      @pagenew=
+        @pagebreak=
+        @pageline=
+        @toc=
+        @lv1=@lv2=@lv3=@lv4=@lv5=@lv6=
+        @num_top=
+        @i18n=
+        @man_section=
+        @emphasis_set_to=
+        @bold_match_list=
+        @italics_match_list=
+        @substitution_match_list=
+        @footer_links=
+        @home_button_links=
+        @links=
+        nil
+      make_instruct_array=make_instruct_array==:nil \
+      ? SiSU_Env::GetInit.new.sisu_document_make.makefile_read
+      : make_instruct_array
+      @makeset=false
+      if make_instruct_array
+        make_instruct_array.each do |para|                                     #% scan document
+          if para =~/^(?:@make:|@links:)[+-]?\s/
+            case para
+            when /^@make:(.+)/m                                                #% header processing - make
+              @env=SiSU_Env::InfoEnv.new
+              @make=SiSU_Param_Make::MdMake.new($1.strip,@opt,@env).make
+              makes=SiSU_Param_Make::MakeHead.new(@make).make_instruct
+              @makeset=true
+              @pagenew=makes[:pagenew]
+              @pagebreak=makes[:pagenew]
+              @pageline=makes[:pageline]
+              @toc=makes[:toc]
+              @lv1=makes[:lv1]
+              @lv2=makes[:lv2]
+              @lv3=makes[:lv3]
+              @lv4=makes[:lv4]
+              @lv5=makes[:lv5]
+              @lv6=makes[:lv6]
+              @num_top=makes[:num_top]
+              @i18n=makes[:i18n]
+              @man_section=makes[:man_section]
+              @emphasis_set_to=makes[:emphasis_set_to]
+              @bold_match_list=makes[:bold_match_list]
+              @italics_match_list=makes[:italics_match_list]
+              @substitution_match_list=makes[:substitution_match_list]
+              @footer_links=makes[:footer_links]
+              @home_button_links=makes[:home_button_links]
+              @home_button_image=makes[:home_button_image]
+              @cover_image=makes[:cover_image]
+            when /^@links:(.+)/m                                                #% header processing - make
+              make_links=SiSU_Param::Parameters::MdMake.new($1.strip,@opt,@env).make_links
+              @links,@links_append=make_links.links,make_links.append?
+            end
+          end
+        end                                                                    #% here endeth the common header loop
+      end
+      { makeset: @makeset,
+        pagenew: @pagenew,
+        pagebreak: @pagebreak,
+        pageline: @pageline,
+        toc: @toc,
+        lv1: @lv1,
+        lv2: @lv2,
+        lv3: @lv3,
+        lv4: @lv4,
+        lv5: @lv5,
+        lv6: @lv6,
+        num_top: @num_top,
+        i18n: @i18n,
+        man_section: @man_section,
+        emphasis_set_to: @emphasis_set_to,
+        bold_match_list: @bold_match_list,
+        italics_match_list: @italics_match_list,
+        substitution_match_list: @substitution_match_list,
+        footer_links: @footer_links,
+        home_button_links: @home_button_links,
+        home_button_image: @home_button_image,
+        cover_image: @cover_image,
+        links: @links,
+        links_append: @links_append
+      }
+    end
+  end
+  class Options
+    attr_accessor :selections,:opt_ch,:act,:dir_structure_by,:lingual,:f_pths,:files,:files_mod,:call_path,:base_path,:base_stub,:sub_location,:image_src_path,:paths,:lngs,:f_pth,:pth,:fno,:fns,:fnb,:fnc,:fng,:fncb,:lng,:lng_base,:what,:make_instructions,:make_instructions_pod,:sisu_run_path,:sisu_install_type
+    @@act=nil
+    def initialize(a,sisu_runtime)
+      @opt_ch=@f_pth=@pth=@fno=@fns=@fnb=@fnc=@fng=@fncb=@what=@lng=@lng_base=@call_path=@base_path=@base_stub=@image_src_path=@sub_location=''
+      @f_pths,@files,@files_mod,@paths,@select_arr,@act=Array.new(5){[]}
+      @select_str=nil
+      @env=SiSU_Env::InfoEnv.new
+      @lng_base=@env.language_default_set
+      @dir_structure_by=SiSU_Env::EnvCall.new.output_dir_structure.by?
+      @lingual=SiSU_Env::EnvCall.new.mono_multi_lingual?
+      @sisu_run_from=sisu_runtime[:runtime_path]
+      @sisu_install_type=sisu_runtime[:runtime_type]
+      @call_path=sisu_runtime[:call_path]
+      pth=SiSU_Utils::Path.new(call_path)
+      @base_path=pth.base_markup
+      @base_stub=pth.base_markup_stub
+      @image_src_path=pth.image_src
+      @a=sisu_glob_rules(a)
+      @a.freeze
+      @make_instructions=HeaderCommon.new.sisu_document_make_instructions
+      @make_instructions_pod=nil
+      init
+    end
+    def sisu_called_from?
+      @call_path
+    end
+    def sisu_bin_filepath?
+      @sisu_run_from
+    end
+    def sisu_install_type?
+      @sisu_install_type
+    end
+    def sisu_lib_dir?
+      File.dirname(__FILE__)
+    end
+    def sisu_data_dir?
+      env=RbConfig::CONFIG
+      if sisu_install_type? ==:full_path_to_sisu_bin_in_sisu_dir_tree
+        sisu_bin_filepath?.gsub(/\/bin\/sisu\S*/,'/data/sisu')
+        #sisu_lib_dir?.gsub(/\/lib\/sisu\/(?:current|develop)\S*/,'/data/sisu')
+      elsif sisu_install_type? ==:gem_install
+        #sisu_run_from?.gsub(/\/bin\/.+/,'/data/sisu')
+        env['datadir']
+      elsif sisu_install_type? ==:system_install
+        #SiSU_Info_Env::InfoEnv.new.path.share
+        env['datadir']
+      else
+        env['datadir']
+      end
+    end
+    def find_all(find_flag,opt)
+      if find_flag
+        x=Dir.glob('*.ss[tm]')
+        Px[:lng_lst].each do |d|
+          if FileTest.directory?(d)
+            x << Dir.glob("#{d}/*.ss[tm]")
+          end
+        end
+        x=x.flatten
+        opt + x
+      end
+    end
+    def find_select(find_flag,opt)
+      if find_flag
+        x=[]
+        if opt.inspect =~/"[a-zA-Z][a-zA-Z0-9._-]+?"/
+          opt.each do |g|
+            x <<=if g =~/.ss[tm]/
+              Dir.glob("*#{g}")
+            else
+              Dir.glob("*#{g}*.ss[tm]")
+            end
+            Px[:lng_lst].each do |d|
+              if FileTest.directory?(d)
+                x <<=if g =~/.ss[tm]/
+                  Dir.glob("#{d}/*#{g}")
+                else
+                  Dir.glob("#{d}/*#{g}*.ss[tm]")
+                end
+              end
+            end
+          end
+        end
+        x.flatten
+      end
+    end
+    def sisu_glob_rules(a)
+      a=if a.inspect =~/"-[A-Za-z0-9]*[fG]/ \
+      or a.inspect =~/"--find"|"--glob"/
+        b,f=[],[]
+        find_flag=false
+        a.each do |y|
+          if y =~ /^-/
+            if y =~/^-/ \
+            && y =~/[fG]|--find|--glob/
+              find_flag=true
+            end
+            b << y
+          end
+          if find_flag \
+          && y !~ /^-/ \
+          && y =~ /\S+/
+            if y !~/\//
+              f << y
+            else
+              find_flag=false
+              puts %{sub-directories "#{y}" cannot be provided for --find or --glob at this time}
+            end
+          end
+        end
+        r=Px[:lng_lst_rgx].gsub(/\|#{lng_base}\|/,'|')
+        @lang_regx=%r{(?:#{r})}
+        if find_flag
+          (f.length > 0) \
+          ? (b + find_select(find_flag,f))
+          : find_all(find_flag,b)
+        elsif a.inspect =~/"(?:-\S+?|--\S+?)"/ \
+        && a.inspect =~/"#{@lang_regx}\/?"/ \
+        && a.inspect =~/"#{lng_base}\/\S+?\.ss[tm]"/
+          init_selected_lang_dirs(a)
+        else b
+        end
+      else a
+      end
+    end
+    def init_selected_lang_dirs(a)
+      @z=a.each.map do |y|
+        if y =~/^#{lng_base}\/(\S+?\.ss[tm])$/
+          @fn=$1
+          y
+        elsif y =~/^#{@lang_regx}\/?$/
+          "#{y}/#{@fn}"
+        else y
+        end
+      end
+    end
+    def init
+      a=@a
+      s=expand_numeric_shortcuts(a)
+      q=set_files_and_paths_and_general_extract(s)
+      files=(q[:files].length > 0) ? :true : :false
+      @select_arr=opt_cmd_and_mod_adjust(q[:opt_ch],q[:selections],files)
+      if a.length > 0
+        @what=q[:what] unless q[:what].empty?
+        @paths = q[:paths]
+        @files = q[:files]
+        @f_pths = q[:f_pths]
+        @lngs = q[:lngs]
+        if @files.length > 0 \
+        and @opt_ch.empty? \
+        and @select_arr.length==0 #% if no other action called on filename given, default is sisu --v5 -0 [filename(s)] configured as flag default
+          shortcut=SiSU_Env::InfoProcessingFlag.new
+          @select_arr=['--v5']
+          @select_arr << shortcut.act_0.arr #+ ' --dal'
+        end
+        if @select_arr.inspect =~/--verbose/ \
+        && @opt_ch !~/-[ku]*v[ku]*$/
+          SiSU_Screen::Ansi.new(
+            @opt_ch,
+            "\tsisu " + @opt_ch +  ' ' + @select_arr.join(' ') + ' ' + @files.join(' ') + "\n"
+          ).print_brown
+        end
+      end
+      @@act ? @act=@@act : @@act=@act=opt_act
+      self
+    end
+    def sisu_document_make_pod
+      def makefile_name
+        SiSU_Env::GetInit.new.sisu_document_make.makefile_name
+      end
+      def makefile(pod_make_path)
+        "#{pod_make_path}/#{makefile_name}"
+      end
+      def makefile_read(pod_make_path)
+        if FileTest.file?(makefile(pod_make_path))
+          sisu_doc_makefile=IO.read(makefile(pod_make_path), mode: 'r:utf-8')
+          sisu_doc_makefile.split(/\s*\n\s*\n/m)
+        else nil
+        end
+      end
+      self
+    end
+    def set_files_and_paths_and_general_extract(s)
+      c,w='',''
+      m,f,pth,lng,lngs=[],[],[],[],[]
+      lng_is=''
+      a=(s.nil?) \
+      ? ['-v']
+      : s.split(/\s+/)
+      r_l=Px[:lng_lst].join('|')
+      a.uniq.each do |x|
+        if x =~/^-[a-z0-5]+/i \
+        or x =~/^--\S+/
+          if x =~/^-([a-z0-5]+)/i
+            c << $1
+          end
+          if x =~/^--\S+/
+            m << x
+          end
+        elsif x =~ /(?:\.(?:(?:-|ssm\.)?sst(?:\.xml)?|ssm|ssi|sx[sdn]\.xml|s[1-3]|kdi|ssp)|\S+?\.ss[mt]\.(?:txz|zip)|sisupod\.(?:txz|zip))$/
+          if x =~/\S+?\.ss[mt]\.(?:txz|zip)|sisupod\.(?:txz|zip)/
+            if x =~/^(?:https?|file):\/\/\S+/ #\
+            end
+            pwd=Dir.pwd
+            fn_pod=x.gsub(/([^\/]+)\.txz$/,'\1')
+            fullname=@env.processing_path.processing + '/sisupod/' + fn_pod
+            pt=Pathname.new(fullname)
+            FileUtils::mkdir_p(pt.to_s)
+            pod_make_path=fullname + '/sisupod/doc/_sisu'
+            make_instruct_array=sisu_document_make_pod.makefile_read(pod_make_path)
+            @make_instructions_pod=
+              HeaderCommon.new.sisu_document_make_instructions(make_instruct_array)
+            Dir.chdir(pt.realpath)
+            system("
+              chdir #{fullname}
+              tar xaf #{pwd}/#{x}
+              chdir #{pwd}
+            ")
+            Dir.chdir(pt.realpath.to_s + '/sisupod/doc')
+            r=Px[:lng_lst_rgx]
+            Dir.entries("#{fullname}/sisupod/doc").each do |d_lng|
+              if d_lng =~/^(?:#{r})$/
+                Dir.chdir(pt.realpath.to_s + "/sisupod/doc/#{d_lng}")
+                filenames=Dir.glob("*.ss[mt]")
+                filenames.each do |fn|
+                  f_pths << {
+                    pth: "#{fullname}/sisupod/doc/#{d_lng}",
+                    f: "#{fn}",
+                    pth_stub: 'doc',
+                    lng: d_lng,
+                    lng_is: d_lng,
+                    url_base: '',
+                    url: ''
+                  }
+                  Dir.chdir(pwd)
+                  f << fn
+                end
+              end
+            end
+          elsif x =~/^(?:https?|file):\/\/\S+/ \
+          and x =~/\S+?\.ss[mt]$/
+            r_url=/(http:\/\/\S+?\/\S+?\/src(?:\/(?:#{r_l}))?)\//
+            url_base = (x[r_url,1])
+            url = x
+            y=x.gsub(/http:\/\/\S+?\/\S+?\/src\//,'')
+            t=/(#{r_l})\/[^\/]+?\.ss[tm]$/
+            l_p = (y[t,1]) \
+              ? y[t,1]
+              : nil
+            lng << l_p
+            lngs << if l_p
+              l_p
+            elsif x =~/~(#{r_l})\.ss[tm]/
+              $1
+            else lng_base
+            end
+            r_f=/(?:#{r_l})\/([^\/]+?\.ss[tm])$/
+            fn = (y[r_f,1]) \
+              ? y[r_f,1]
+              : y
+            fn=fn.gsub(/\.((?:ssm\.)?sst)/,'.-\1')
+            fullname=Dir.pwd + '/' + fn
+            pt=Pathname.new(fullname)
+            pth << Dir.pwd
+            r_u=/.+?\/([^\/]+)(?:\/(?:#{r_l})$|$)/
+            lng_is =if l_p
+              l_p
+            elsif x =~/~(#{r_l})\.ss[tm]/
+              $1
+            else lng_base
+            end
+            f_pths << {
+              pth: pt.split[0].realpath.to_s,
+              f: pt.split[1].to_s,
+              pth_stub: pt.split[0].realpath.to_s[r_u,1],
+              lng: (pt.split[0].realpath.to_s[t,1]) \
+                ? pt.split[0].realpath.to_s[t,1]
+                : nil,
+              lng_is: lng_is,
+              url_base: url_base,
+              url: url
+            }
+            f << fn
+          elsif FileTest.file?(x)
+            pt=Pathname.new(x)
+            pth << pt.split[0].realpath.to_s     #remove?
+            f << pt.split[1].to_s                #remove?
+            r_u=/.+?\/([^\/]+)(?:\/(?:#{r_l})$|$)/
+            t=/.+\/(#{r_l})$/
+            l_p = (pt.split[0].realpath.to_s[t,1]) \
+              ? pt.split[0].realpath.to_s[t,1]
+              : nil
+            lngs << lng_is = if l_p
+              l_p
+            elsif x =~/~(#{r_l})\.ss[tm]/
+              $1
+            else lng_base
+            end
+            f_pths << {
+              pth: pt.split[0].realpath.to_s,
+              f: pt.split[1].to_s,
+              pth_stub: pt.split[0].realpath.to_s[r_u,1],
+              lng: lng_is,
+              lng_is: lng_is,
+              url_base: nil,
+              url: nil,
+            }
+          else  puts "file not found: #{x}"
+          end
+        elsif x =~ /\.termsheet\.rb$/
+          (FileTest.file?(x)) \
+          ? (f << x)
+          : (puts "file not found: #{x}")
+        else w=x
+          puts "#{x} in #{a.join(' ')}?"
+        end
+      end
+      {
+        opt_ch: c,
+        selections: m,
+        what: w,
+        paths: pth,
+        files: f,
+        f_pths: f_pths,
+        lng: lng_is,
+        lngs: lngs,
+      }
+    end
+    def expand_numeric_shortcuts(a)
+      s=''
+      a.each do |x|
+        y=case x
+        when /0/
+          (x=~/^-0\S+/) \
+          ? x.gsub(/^-0(\S+)/,'--act0' + ' -\1')
+          : x.gsub(/^-0/,'--act0' + ' ')
+        when /1/
+          (x=~/^-1\S+/) \
+          ? x.gsub(/^-1(\S+)/,'--act1' + ' -\1')
+          : x.gsub(/^-1/,'--act1' + ' ')
+        when /2/
+          (x=~/^-2\S+/) \
+          ? x.gsub(/^-2(\S+)/,'--act2' + ' -\1')
+          : x.gsub(/^-2/,'--act2' + ' ')
+        when /3/
+          (x=~/^-3\S+/) \
+          ? x.gsub(/^-3(\S+)/,'--act3' + ' -\1')
+          : x.gsub(/^-3/,'--act3' + ' ')
+        when /4/
+          (x=~/^-4\S+/) \
+          ? x.gsub(/^-4(\S+)/,'--act4' + ' -\1')
+          : x.gsub(/^-4/,'--act4' + ' ')
+        when /5/
+          (x=~/^-5\S+/) \
+          ? x.gsub(/^-5(\S+)/,'--act5' + ' -\1')
+          : x.gsub(/^-5/,'--act5' + ' ')
+        when /6/
+          (x=~/^-6\S+/) \
+          ? x.gsub(/^-6(\S+)/,'--act6' + ' -\1')
+          : x.gsub(/^-6/,'--act6' + ' ')
+        when /7/
+          (x=~/^-7\S+/) \
+          ? x.gsub(/^-7(\S+)/,'--act7' + ' -\1')
+          : x.gsub(/^-7/,'--act7' + ' ')
+        when /8/
+          (x=~/^-8\S+/) \
+          ? x.gsub(/^-8(\S+)/,'--act8' + ' -\1')
+          : x.gsub(/^-8/,'--act8' + ' ')
+        when /9/
+          (x=~/^-9\S+/) \
+          ? x.gsub(/^-9(\S+)/,'--act9' + ' -\1')
+          : x.gsub(/^-9/,'--act9' + ' ')
+        else x
+        end
+        s << " #{y}" unless y.empty?
+      end
+      s.strip!
+    end
+    def opt_cmd_and_mod_adjust(ch,select_arr,files)
+      select_arr=select_arr.flatten
+      sel_init=select_arr.flatten
+      shortcut=SiSU_Env::InfoProcessingFlag.new
+      if files ==:true
+        if not sel_init.empty? \
+        and sel_init.inspect =~/"--act[s0-9]?/
+          sel_init.each do |s|
+            select_arr <<=case s
+            when /--act0/ then shortcut.act_0.arr
+            when /--act1/ then shortcut.act_1.arr
+            when /--act2/ then shortcut.act_2.arr
+            when /--act3/ then shortcut.act_3.arr
+            when /--act4/ then shortcut.act_4.arr
+            when /--act5/ then shortcut.act_5.arr
+            when /--act6/ then shortcut.act_6.arr
+            when /--act7/ then shortcut.act_7.arr
+            when /--act8/ then shortcut.act_8.arr
+            when /--act9/ then shortcut.act_9.arr
+            when /--act/  then shortcut.act_info
+            end
+          end
+        end
+        if not sel_init.empty? \
+        and sel_init.inspect =~/"--pdf-/
+          select_arr << '--pdf'
+          sel_init.each do |s|
+            if s =~ /^--pdf-(?:(?:l|landscape)(?:-(?:a4|letter|a5|b5|legal))?|(?:a4|letter|a5|b5|legal)-(?:l|landscape))$/
+              select_arr << '--landscape'
+            end
+            if s =~ /^--pdf-(?:(?:p|portrait)(?:-(?:a4|letter|a5|b5|legal))?|(?:a4|letter|a5|b5|legal)-(?:p|portrait))$/
+              select_arr << '--portrait'
+            end
+            if s =~ /^--pdf(?:-(?:a4|letter|a5|b5|legal)(?:-(?:[lp]|landscape|portrait))?|(?:-(?:[lp]|landscape|portrait))(?:-(?:a4|letter|a5|b5|legal)))$/
+              if s =~ /^--pdf(?:-a4(?:-(?:[lp]|landscape|portrait))?|(?:-(?:[lp]|landscape|portrait))-a4)$/
+                select_arr << '--papersize-a4'
+              end
+              if s =~ /^--pdf(?:-a5(?:-(?:[lp]|landscape|portrait))?|(?:-(?:[lp]|landscape|portrait))-a5)$/
+                select_arr << '--papersize-a5'
+              end
+              if s =~ /^--pdf(?:-b5(?:-(?:[lp]|landscape|portrait))?|(?:-(?:[lp]|landscape|portrait))-b5)$/
+                select_arr << '--papersize-b5'
+              end
+              if s =~ /^--pdf(?:-letter(?:-(?:[lp]|landscape|portrait))?|(?:-(?:[lp]|landscape|portrait))-letter)$/
+                select_arr << '--papersize-letter'
+              end
+              if s =~ /^--pdf(?:-legal(?:-(?:[lp]|landscape|portrait))?|(?:-(?:[lp]|landscape|portrait))-legal)$/
+                select_arr << '--papersize-legal'
+              end
+            end
+          end
+          select_arr=select_arr.uniq
+        end
+        if ch.empty? \
+        and sel_init.length == 0
+          select_arr << shortcut.act_0.arr ################ & --flag empty
+        elsif not ch.empty?
+          if ch =~/c/ then select_arr << '--color-toggle'
+            ch=ch.gsub(/[c]/,'')
+          end
+          if ch =~/k/ then select_arr << '--color-off'
+            ch=ch.gsub(/[k]/,'')
+          end
+          if ch =~/C/ then select_arr << '--config'
+            ch=ch.gsub(/[C]+/,'')
+          end
+          if ch =~/m/ then select_arr << '--dal'
+            ch=ch.gsub(/[m]/,'')
+          end
+          if ch =~/t/ then select_arr << '--txt'
+            ch=ch.gsub(/[t]/,'')
+          end
+          if ch =~/h/ then select_arr << '--html'
+            ch=ch.gsub(/[h]/,'')
+          end
+          if ch =~/e/ then select_arr << '--epub'
+            ch=ch.gsub(/[e]/,'')
+          end
+          if ch =~/o/ then select_arr << '--odt'
+            ch=ch.gsub(/[o]/,'')
+          end
+          if ch =~/d/ then select_arr << '--docbook'
+            ch=ch.gsub(/[d]/,'')
+          end
+          if ch =~/p/ then select_arr << '--pdf'
+            ch=ch.gsub(/[p]/,'')
+          end
+          if ch =~/w/ then select_arr << '--concordance'
+            ch=ch.gsub(/[w]/,'')
+          end
+          if ch =~/i/ then select_arr << '--manpage'
+            ch=ch.gsub(/[i]/,'')
+          end
+          if ch =~/I/ then select_arr << '--texinfo'
+            ch=ch.gsub(/[I]/,'')
+          end
+          if ch =~/b/ then select_arr << '--xhtml'
+            ch=ch.gsub(/[b]/,'')
+          end
+          if ch =~/x/ then select_arr << '--xml-sax'
+            ch=ch.gsub(/[x]/,'')
+          end
+          if ch =~/X/ then select_arr << '--xml-dom'
+            ch=ch.gsub(/[X]/,'')
+          end
+          if ch =~/j/ then select_arr << '--images'
+            ch=ch.gsub(/[j]/,'')
+          end
+          if ch =~/J/ then select_arr << '--json'
+            ch=ch.gsub(/[J]/,'')
+          end
+          if ch =~/N/ then select_arr << '--digests'
+            ch=ch.gsub(/[N]/,'')
+          end
+          if ch =~/P/ then select_arr << '--po4a-sst'
+            ch=ch.gsub(/[P]/,'')
+          end
+          if ch =~/d/ then select_arr << '--sqlite'
+            ch=ch.gsub(/[d]/,'')
+          end
+          if ch =~/D/ then select_arr << '--pg'
+            ch=ch.gsub(/[D]/,'')
+          end
+          if ch =~/Q/ then select_arr << '--qrcode'
+            ch=ch.gsub(/[Q]/,'')
+          end
+          if ch =~/s/ then select_arr << '--source'
+            ch=ch.gsub(/[s]/,'')
+          end
+          if ch =~/S/ then select_arr << '--sisupod'
+            ch=ch.gsub(/[S]/,'')
+          end
+          if ch =~/m/ then select_arr << '--manifest'
+            ch=ch.gsub(/[m]/,'')
+          end
+          if ch =~/R/ then select_arr << '--rsync'
+            ch=ch.gsub(/[R]/,'')
+          end
+          if ch =~/r/ then select_arr << '--scp'
+            ch=ch.gsub(/[r]/,'')
+          end
+          if ch =~/g/ then select_arr << '--git'
+            ch=ch.gsub(/[g]/,'')
+          end
+          if ch =~/U/ then select_arr << '--urls'
+            ch=ch.gsub(/[u]/,'')
+          end
+          if ch =~/Z/ then select_arr << '--zap'
+            ch=ch.gsub(/[Z]/,'')
+          end
+          if ch =~/F/ then select_arr << '--sample-search-form'
+            ch=ch.gsub(/[F]/,'')
+          end
+          if ch =~/W/ then select_arr << '--webrick'
+            ch=ch.gsub(/[w]/,'')
+          end
+          if ch =~/M/ then select_arr << '--maintenance'
+            ch=ch.gsub(/[M]/,'')
+          end
+          if ch =~/V/ then select_arr << '--very-verbose'
+            ch=ch.gsub(/[V]/,'')
+          end
+          if ch =~/v/ then select_arr << '--verbose'
+            ch=ch.gsub(/[v]/,'')
+          end
+          if ch =~/q/ then select_arr << '--quiet'
+            ch=ch.gsub(/[q]/,'')
+          end
+          if select_arr.inspect !~/--urls/ \
+          and select_arr.inspect \
+          !~/"--harvest/
+            select_arr << '--urls'
+          end
+          if select_arr.inspect !~/--dal/ \
+          and select_arr.inspect =~/txt|text|html|odt|epub|docbook|xml|pdf|manpage|texinfo|concordance|qrcode|source|sisupod|pg|sqlite|zap/
+            select_arr << '--dal'
+          end
+          if select_arr.inspect !~/--manifest/ \
+          and select_arr.inspect =~/txt|text|html|odt|epub|docbook|xml|pdf|manpage|texinfo|concordance|qrcode|source|sisupod|pg|sqlite|zap/
+            select_arr << '--manifest'
+          end
+          if select_arr.inspect !~/--images/ \
+          and select_arr.inspect =~/html|odt|docbook|xml|qrcode/
+            select_arr << '--images'
+          end
+        end
+      else
+        if not sel_init.empty? \
+        and sel_init.inspect =~/"--acts?/
+          shortcut.act_info
+          exit
+        end
+        if ch =~/c/ then select_arr << '--color-toggle'
+          ch=ch.gsub(/[c]/,'')
+        end
+        if ch =~/k/ then select_arr << '--color-off'
+          ch=ch.gsub(/[k]/,'')
+        end
+        if ch =~/C/ then select_arr << '--config'
+          ch=ch.gsub(/[C]+/,'')
+        end
+        if sel_init.inspect =~/"--createdb"|"--create(?:all)?"|"--dropall"|"--recreate(?:all)?"/
+          if ch =~/d/ then select_arr << '--sqlite'
+            ch=ch.gsub(/[d]/,'')
+          end
+          if ch =~/D/ then select_arr << '--pg'
+            ch=ch.gsub(/[D]/,'')
+          end
+        end
+        if ch =~/W/ then select_arr << '--webrick'
+          ch=ch.gsub(/[w]/,'')
+        end
+        if ch =~/v/ then select_arr << '--version'
+          ch=ch.gsub(/[v]/,'')
+        end
+        if ch =~/M/ then select_arr << '--maintenance'
+          ch=ch.gsub(/[M]/,'')
+        end
+        if ch =~/V/ then select_arr << '--very-verbose'
+          ch=ch.gsub(/[V]/,'')
+        end
+        if ch =~/q/ then select_arr << '--quiet'
+          ch=ch.gsub(/[q]/,'')
+        end
+      end
+      select_arr=select_arr.flatten.compact.uniq.sort
+    end
+    def opt_act
+      select_arr=@select_arr
+      @@act=if @@act
+        @act=@@act
+      else
+        act={}
+        act[:no_stop]=if select_arr.inspect \
+        =~/"--no-stop"|"--errors-as-warnings"/
+          { bool: true, set: :on }
+        else
+          { bool: false, set: :na }
+        end
+        act[:license]=(select_arr.inspect \
+        =~/"--license/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:site_init]=(select_arr.inspect \
+        =~/"--init"|"--initialize"|"--init-site"|"--conf"|"--config"|"--configure"/) \
+        ? { bool: true, set: :on  }
+        : { bool: false, set: :na }
+        act[:rc]=if select_arr.inspect \
+        =~/"--rc=/
+          x=Dir.pwd + '/' + select_arr.join.gsub(/--rc=/,'')
+          { bool: true, set: :on, inst: x }
+        else
+          { bool: false, set: :na, inst: '' }
+        end
+        act[:processing_path]=if select_arr.inspect \
+        =~/"--processing-path=/
+          base_pth=select_arr.join(';').gsub(/^.*--processing-path=['"]?(.+?)(?:['"]?;.+)?$/,'\1')
+          { bool: true, set: :on, inst: base_pth }
+        elsif select_arr.inspect \
+        =~/"--processing-path/
+          { bool: true, set: :on, inst: @base_path }
+        else
+          { bool: false, set: :na, inst: nil }
+        end
+        act[:dump]=if select_arr.inspect \
+        =~/"--dump=/
+          base_pth=select_arr.join(';').
+            gsub(/^.*--dump=['"]?(.+?)(?:['"]?;.+)?$/,'\1')
+          { bool: true, set: :on, inst: base_pth }
+        elsif select_arr.inspect =~/"--dump/
+          { bool: true, set: :on, inst: @base_path }
+        else
+          { bool: false, set: :na, inst: nil }
+        end
+        act[:redirect]=if select_arr.inspect \
+        =~/"--redirect=/
+          base_pth=select_arr.join(';').
+            gsub(/^.*--redirect=['"]?(.+?)(?:['"]?;.+)?$/,'\1')
+          { bool: true, set: :on, inst: base_pth }
+        elsif select_arr.inspect \
+        =~/"--redirect/
+          { bool: true, set: :on, inst: @base_path }
+        else
+          { bool: false, set: :na, inst: nil }
+        end
+        act[:switch]=if select_arr.inspect \
+        =~/"--switch-off=/
+          off_list=select_arr.join(';').
+            gsub(/^.*--switch-off=['"]?(.+?)(?:['"];.+)?$/,'\1')
+          off_list=off_list.scan(/[^,;\s]+/)
+          { bool: false, set: :off, off: off_list}
+        else { bool: true, set: :na, off: [] }
+        end
+        act[:default_language]=if select_arr.inspect \
+        =~/"--(?:default-)?language[-=](\S{2})"/
+          { set: :on, code: $1 }
+        elsif lng_base
+          { set: :on, code: lng_base }
+        else { set: :na, code: 'en' }
+        end
+        act[:i18n]=if select_arr.inspect \
+        =~/"(?:--monolingual|--i18n-mono(?:lingual)?)"/ #if monolingual possible outputs output_by :filename & :filetype only, without language code in default language name; give warning of conflict settings if monolingual & :language selected
+          @lingual=:mono
+          { set: :mono }
+        elsif select_arr.inspect \
+        =~/"(?:--multilingual|--i18n-multi(?:lingual)?)"/
+          @lingual=:multi
+          { set: :multi }
+        else { set: :na }
+        end
+        act[:output_by]=if select_arr.inspect \
+        =~/"--(?:output-)?by-language"/
+          @dir_structure_by=:language
+          { set: :language }
+        elsif select_arr.inspect \
+        =~/"--(?:output-)?by-filename"/
+          @dir_structure_by=:filename
+          { set: :filename }
+        elsif select_arr.inspect \
+        =~/"--(?:output-)?by-filetype"/
+          @dir_structure_by=:filetype
+          { set: :filetype }
+        else { set: :na }
+        end
+        act[:ocn]=if select_arr.inspect \
+        =~/"--ocn"|"--inc-ocn"|"--numbering"|"--inc-numbering"/
+          { bool: true, set: :on }
+        elsif select_arr.inspect \
+        =~/"--no-ocn"|"--exc-ocn"|"--no-numbering"|"--exc-numbering"/ \
+        || act[:switch][:off].inspect =~/"ocn"|"--numbering"/
+          { bool: false, set: :off }
+        else { bool: true, set: :na }
+        end
+        act[:toc]=if select_arr.inspect \
+        =~/"--inc-toc"/
+          { bool: true, set: :on }
+        elsif select_arr.inspect \
+        =~/"--(?:exc|no)-toc"/ \
+        || act[:switch][:off].inspect =~/"toc"/
+          { bool: false, set: :off }
+        else { bool: true, set: :na }
+        end
+        act[:minitoc]=if select_arr.inspect \
+        =~/"--minitoc"|"--inc-minitoc"/
+          { bool: true, set: :on }
+        elsif select_arr.inspect \
+        =~/"--(?:exc|no)-minitoc"/ \
+        || act[:switch][:off].inspect =~/"minitoc"/
+          { bool: false, set: :off }
+        else { bool: false, set: :na }
+        end
+        act[:links_to_manifest]=if select_arr.inspect \
+        =~/"--inc-links-to-manifest"|"--inc-manifest-links"/
+          { bool: true, set: :on }
+        elsif select_arr.inspect \
+        =~/"--(?:exc|no)-manifest"/ \
+        || act[:switch][:off].inspect =~/"manifest"/ #place lower
+          { bool: false, set: :off }
+        elsif select_arr.inspect \
+        =~/"--(?:exc|no)-links-to-manifest"|"--(?:exc|no)-manifest-links"/ \
+        || act[:switch][:off].inspect \
+        =~/"links_to_manifest"|"manifest_links"|"--(?:exc|no)-manifest"/ \
+        || select_arr.inspect \
+        =~/"--(?:redirect|dump)/
+          { bool: false, set: :off }
+        else { bool: true, set: :na }
+        end
+        act[:manifest_minitoc]=if select_arr.inspect \
+        =~/"--inc-manifest-minitoc"|"--inc-minitoc"/
+          { bool: true, set: :on }
+        elsif select_arr.inspect \
+        =~/"--(?:exc|no)-manifest-minitoc"|"--(?:exc|no)-minitoc"/ \
+        || act[:switch][:off].inspect =~/"manifest_minitoc"|"minitoc"/
+          { bool: false, set: :off }
+        else { bool: false, set: :na }
+        end
+        act[:metadata]=if select_arr.inspect \
+        =~/"--metadata"|"--inc-metadata"/
+          { bool: true, set: :on }
+        elsif select_arr.inspect \
+        =~/"--(?:exc|no)-metadata"/ \
+        || act[:switch][:off].inspect =~/"metadata"/
+          { bool: false, set: :off }
+        else { bool: true, set: :na }
+        end
+        act[:html_minitoc]=if select_arr.inspect \
+        =~/"--inc-html-minitoc"|"--inc-minitoc"/
+          { bool: true, set: :on }
+        elsif select_arr.inspect \
+        =~/"--(?:exc|no)-html-minitoc"|"--(?:exc|no)-minitoc"/ \
+        || act[:switch][:off].inspect =~/"html_minitoc"|"minitoc"/
+          { bool: false, set: :off }
+        else { bool: false, set: :na }
+        end
+        act[:html_navigation]=if select_arr.inspect \
+        =~/"--inc-html-navigation"|"--inc-navigation"/
+          { bool: true, set: :on }
+        elsif select_arr.inspect \
+        =~/"--(?:exc|no)-html-navigation"|"--(?:exc|no)-navigation"/ \
+        || act[:switch][:off].inspect =~/"html_navigation"|"nav"/
+          { bool: false, set: :off }
+        else { bool: true, set: :na }
+        end
+        act[:html_navigation_bar]=if select_arr.inspect \
+        =~/"--inc-html-navigation-bar"|"--inc-navigation-bar"/
+          { bool: true, set: :on }
+        elsif select_arr.inspect \
+        =~/"--(?:exc|no)-html-navigation-bar"|"--(?:exc|no)-navigation-bar"/ \
+        || act[:switch][:off].inspect =~/"html_navigation_bar"|"navbar"/
+          { bool: false, set: :off }
+        else { bool: false, set: :na }
+        end
+        act[:segsubtoc]=if select_arr.inspect \
+        =~/"--inc-segsubtoc"/
+          { bool: true, set: :on }
+        elsif select_arr.inspect \
+        =~/"--(?:exc|no)-segsubtoc"/ \
+        || act[:switch][:off].inspect =~/"segsubtoc"/
+          { bool: false, set: :off }
+        else { bool: true, set: :na }
+        end
+        act[:search_form]=if select_arr.inspect \
+        =~/"--inc-search-form"/
+          { bool: true, set: :on }
+        elsif select_arr.inspect \
+        =~/"--(?:exc|no)-search-form"/ \
+        || act[:switch][:off].inspect =~/"search_form"|"search"/
+          { bool: false, set: :off }
+        else { bool: true, set: :na }
+        end
+        act[:html_search_form]=if select_arr.inspect \
+        =~/"--inc-html-search-form"|"--inc-search-form"/
+          { bool: true, set: :on }
+        elsif select_arr.inspect \
+        =~/"--(?:exc|no)-html-search-form"|"--(?:exc|no)-search-form"/ \
+        || act[:switch][:off].inspect \
+        =~/"html_search_form"|"search_form"|"search"/
+          { bool: false, set: :off }
+        else { bool: true, set: :na }
+        end
+        act[:html_right_pane]=if select_arr.inspect \
+        =~/"--inc-html-right-pane"|"--inc-right-pane"|"--inc-html-right-column"|"--inc-right-column"/
+          { bool: true, set: :on }
+        elsif select_arr.inspect \
+        =~/"--(?:exc|no)-html-right-pane"|"--(?:exc|no)-right-pane"|"--(?:exc|no)-html-right-column"|"--(?:exc|no)-right-column"/ \
+        || act[:switch][:off].inspect =~/"html_right_pane"|"html_right_column"|"promo"/
+          { bool: false, set: :off }
+        else { bool: true, set: :na }
+        end
+        act[:html_top_band]=if select_arr.inspect \
+        =~/"--inc-html-top-band"|"--inc-top-band"/
+          { bool: true, set: :on }
+        elsif select_arr.inspect \
+        =~/"--(?:exc|no)-html-top-band"|"--(?:exc|no)-top-band"/ \
+        || act[:switch][:off].inspect =~/"html-top-band"|"top-band"/
+          { bool: false, set: :off }
+        else { bool: true, set: :na }
+        end
+        act[:html]=if select_arr.inspect \
+        =~/"--html-strict"/ \
+        or ((select_arr.inspect \
+        =~/"--html"/) \
+        && select_arr.inspect \
+        =~/"--strict"/)
+          act[:html_strict]={ bool: true, set: :on }
+          act[:html_scroll]={ bool: true, set: :on }
+          act[:html_seg]={ bool: true, set: :on }
+          { bool: true, set: :on }
+        elsif (select_arr.inspect \
+        =~/"--html"/)
+          act[:html_strict]={ bool: false, set: :off }
+          act[:html_scroll]={ bool: true, set: :on }
+          act[:html_seg]={ bool: true, set: :on }
+          { bool: true, set: :on }
+        else
+          act[:html_strict]=(select_arr.inspect \
+          =~/"--strict"/) \
+          ? { bool: true, set: :on }
+          : { bool: false, set: :na }
+          act[:html_scroll]=(select_arr.inspect \
+          =~/"--html-scroll"/) \
+          ? { bool: true, set: :on }
+          : { bool: false, set: :na }
+          act[:html_seg]=(select_arr.inspect \
+          =~/"--html-seg"/) \
+          ? { bool: true, set: :on }
+          : { bool: false, set: :na }
+          { bool: false, set: :na }
+        end
+        act[:concordance]=(select_arr.inspect \
+        =~/"--concordance"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:images]=(select_arr.inspect \
+        =~/"--images"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:json]=(select_arr.inspect \
+        =~/"--json"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        if select_arr.inspect \
+        =~/"--pdf"/
+          if select_arr.inspect \
+          =~/"--portrait"/
+            act[:pdf]=  { bool: false, set: :na }
+            act[:pdf_l]={ bool: false, set: :na }
+            act[:pdf_p]={ bool: true, set: :on }
+          elsif select_arr.inspect \
+          =~/"--landscape"/
+            act[:pdf]=  { bool: false, set: :na }
+            act[:pdf_l]={ bool: true, set: :on }
+            act[:pdf_p]={ bool: false, set: :na }
+          else
+            act[:pdf]=  { bool: true, set: :on }
+            act[:pdf_l]={ bool: true, set: :on }
+            act[:pdf_p]={ bool: true, set: :on }
+          end
+        else
+          act[:pdf]=       { bool: false, set: :na }
+          act[:pdf_p]=     { bool: false, set: :na }
+          act[:pdf_l]=     { bool: false, set: :na }
+          act[:pdf_a4]=    { bool: false, set: :na }
+          act[:pdf_a5]=    { bool: false, set: :na }
+          act[:pdf_b5]=    { bool: false, set: :na }
+          act[:pdf_letter]={ bool: false, set: :na }
+          act[:pdf_legal]= { bool: false, set: :na }
+        end
+        if act[:pdf][:set]==:on \
+        or act[:pdf_p][:set]==:on \
+        or act[:pdf_l][:set]==:on
+          act[:pdf_a4]=if select_arr.inspect \
+          =~/"--a4"|--papersize-a4"/ \
+          or select_arr.inspect \
+          =~/"--papersize=\S*a4\b\S*"/ #--papersize=a4,a5
+            { bool: true, set: :on }
+          else
+            { bool: false, set: :na }
+          end
+          act[:pdf_a5]=if select_arr.inspect \
+          =~/"--a5"|"--papersize-a5"/ \
+          or select_arr.inspect \
+          =~/"--papersize=\S*a5\b\S*"/ #--papersize=a4,a5
+            { bool: true, set: :on }
+          else
+            { bool: false, set: :na }
+          end
+          act[:pdf_b5]=if select_arr.inspect \
+          =~/"--b5"|"--papersize-b5"/ \
+          or select_arr.inspect \
+          =~/"--papersize=\S*b5\b\S*"/
+            { bool: true, set: :on }
+          else
+            { bool: false, set: :na }
+          end
+          act[:pdf_letter]=if select_arr.inspect \
+          =~/"--letter"|"--papersize-letter"/ \
+          or select_arr.inspect \
+          =~/"--papersize=\S*letter\b\S*"/
+            { bool: true, set: :on }
+          else
+            { bool: false, set: :na }
+          end
+          act[:pdf_legal]=if select_arr.inspect \
+          =~/"--legal"|"--papersize-legal"/ \
+          or select_arr.inspect \
+          =~/"--papersize=\S*legal\b\S*"/
+            { bool: true, set: :on }
+          else
+            { bool: false, set: :na }
+          end
+        end
+        act[:epub]=(select_arr.inspect \
+        =~/"--epub"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:odt]=if select_arr.inspect \
+        =~/"--odt"|"--odf"|"--odt-(?:ocn|numbering)"|"--odf-(?:ocn|numbering)"/
+          act[:odt_ocn]=if (select_arr.inspect \
+          =~/"--odt-(?:ocn|numbering)"|"--odf-(?:ocn|numbering)"/ \
+          or select_arr.inspect \
+          =~/"--ocn"|"--inc-ocn"|"--numbering"|"--inc-numbering"/)
+            { bool: true, set: :on }
+          elsif select_arr.inspect \
+          =~/"--no-ocn"|"--exc-ocn"|"--no-numbering"|"--exc-numbering"/
+            { bool: false, set: :off }
+          else
+            { bool: false, set: :na }
+          end
+          { bool: true, set: :on }
+        else
+          { bool: false, set: :na }
+        end
+        act[:xml_sax]=(select_arr.inspect \
+        =~/"--xml-sax"|"--sax"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:xml_dom]=(select_arr.inspect \
+        =~/"--xml-dom"|"--dom"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:xml_docbook_book]=(select_arr.inspect \
+        =~/"--docbook"|"--docbook-book"|"--xml-docbook"|"--xml-docbook_book"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:xml_fictionbook]=(select_arr.inspect \
+        =~/"--fictionbook"|"--xml-fictionbook"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:xml_scaffold_structure_sisu]=select_arr.inspect \
+        =~/"--xml-scaffold"|"--xml-scaffold-sisu"/ \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:xml_scaffold_structure_collapse]=select_arr.inspect \
+        =~/"--xml-scaffold-collapse"/ \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:xhtml]=(select_arr.inspect \
+        =~/"--xhtml"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:txt]=if select_arr.inspect \
+        =~/"--txt"|"--text"|"--plaintext"|"--txt-(?:ocn|numbering)"|"--text-(?:ocn|numbering)"|"--plaintext-(?:ocn|numbering)"/
+          act[:txt_ocn]=if (select_arr.inspect \
+          =~/"--txt-(?:ocn|numbering)"|"--text-(?:ocn|numbering)"|"--plaintext-(?:ocn|numbering)"/ \
+          or select_arr.inspect \
+          =~/"--ocn"|"--inc-ocn"|"--numbering"|"--inc-numbering"/)
+            { bool: true, set: :on }
+          elsif select_arr.inspect \
+          =~/"--no-ocn"|"--exc-ocn"|"--no-numbering"|"--exc-numbering"/
+            { bool: false, set: :off }
+          else
+            { bool: false, set: :na }
+          end
+          { bool: true, set: :on }
+        else
+          { bool: false, set: :na }
+        end
+        act[:txt_textile]=(select_arr.inspect \
+        =~/"--textile"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:txt_asciidoc]=(select_arr.inspect \
+        =~/"--asciidoc"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:txt_markdown]=(select_arr.inspect \
+        =~/"--markdown"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:txt_rst]=(select_arr.inspect \
+        =~/"--rst"|"--rest"|"--restructuredtext"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:txt_orgmode]=(select_arr.inspect \
+        =~/"--org"|"--orgmode"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:manpage]=(select_arr.inspect \
+        =~/"--manpage"|"--man"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:texinfo]=(select_arr.inspect \
+        =~/"--texinfo"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:psql]=if select_arr.inspect \
+        =~/"--pg-\S+"/ \
+        or ((select_arr.inspect =~/"--pg"/) \
+        && (select_arr.inspect \
+        =~/"--createdb"|"--create(?:all)?"|"--dropall"|"--recreate(?:all)?"|"--import"|"--update"|"--remove"/))
+          act[:psql_createdb]=if select_arr.inspect \
+          =~/"--pg-createdb"|"--createdb"/
+            { bool: true, set: :on }
+          else
+            { bool: false, set: :na }
+          end
+          if select_arr.inspect \
+          =~/"--pg-recreate(?:all)?"|"--recreate(?:all)?"/
+            act[:psql_drop]={ bool: true, set: :on }
+            act[:psql_create]={ bool: true, set: :on }
+          else
+            act[:psql_drop]=if select_arr.inspect \
+            =~/"--pg-dropall"|"--dropall"/
+              { bool: true, set: :on }
+            else
+              { bool: false, set: :na }
+            end
+            act[:psql_create]=if select_arr.inspect \
+            =~/"--pg-create(?:all)?"|"--create(?:all)?"/
+              { bool: true, set: :on }
+            else
+              { bool: false, set: :na }
+            end
+          end
+          act[:psql_import]=if select_arr.inspect \
+          =~/"--pg-import"|"--import"/
+            { bool: true, set: :on }
+          else
+            { bool: false, set: :na }
+          end
+          act[:psql_update]=if select_arr.inspect \
+          =~/"--pg-update"|"--update"/
+            act[:psql_remove]={ bool: true, set: :on }
+            { bool: true, set: :on }
+          else
+            act[:psql_remove]=if select_arr.inspect \
+            =~/"--pg-remove"|"--remove"/
+              { bool: true, set: :on }
+            else
+              { bool: false, set: :na }
+            end
+            { bool: false, set: :na }
+          end
+          { bool: true, set: :on }
+        else
+          act[:psql_createdb]=
+            { bool: false, set: :na }
+          act[:psql_drop]=
+            { bool: false, set: :na }
+          act[:psql_create]=
+            { bool: false, set: :na }
+          act[:psql_import]=
+            { bool: false, set: :na }
+          act[:psql_update]=
+            { bool: false, set: :na }
+          act[:psql_remove]=
+            { bool: false, set: :na }
+          { bool: false, set: :na }
+        end
+        act[:sqlite]=if select_arr.inspect \
+        =~/"--sqlite-\S+"/ \
+        or (select_arr.inspect \
+        =~/"--sqlite"/ \
+        && select_arr.inspect \
+        =~/"--createdb"|"--create(?:all)?"|"--dropall"|"--recreate(?:all)?"|"--import"|"--update"|"--remove"/)
+          act[:sqlite_createdb]=if select_arr.inspect \
+          =~/"--sqlite-createdb"|"--createdb"/
+            { bool: true, set: :on }
+          else
+            { bool: false, set: :na }
+          end
+          if select_arr.inspect \
+          =~/"--sqlite-recreate(?:all)?"|"--recreate(?:all)?"/
+            act[:sqlite_drop]={ bool: true, set: :on }
+            act[:sqlite_create]={ bool: true, set: :on }
+          else
+            act[:sqlite_create]=if select_arr.inspect \
+            =~/"--sqlite-create(?:all)?"|"--create(?:all)?"/
+              { bool: true, set: :on }
+            else
+              { bool: false, set: :na }
+            end
+            act[:sqlite_drop]=if select_arr.inspect \
+            =~/"--sqlite-dropall"|"--dropall"/
+              { bool: true, set: :on }
+            else
+              { bool: false, set: :na }
+            end
+          end
+          act[:sqlite_import]=if select_arr.inspect \
+          =~/"--sqlite-import"|"--import"/
+            { bool: true, set: :on }
+          else
+            { bool: false, set: :na }
+          end
+          act[:sqlite_update]=if select_arr.inspect \
+          =~/"--sqlite-update"|"--update"/
+            act[:sqlite_remove]={ bool: true, set: :on }
+            { bool: true, set: :on }
+          else
+            act[:sqlite_remove]=if select_arr.inspect \
+            =~/"--sqlite-remove"|"--sqlite-remove"/
+              { bool: true, set: :on }
+            else
+              { bool: false, set: :na }
+            end
+            { bool: false, set: :na }
+          end
+          { bool: true, set: :on }
+        else
+          act[:sqlite_createdb]=
+            { bool: false, set: :na }
+          act[:sqlite_drop]=
+            { bool: false, set: :na }
+          act[:sqlite_create]=
+            { bool: false, set: :na }
+          act[:sqlite_import]=
+            { bool: false, set: :na }
+          act[:sqlite_update]=
+            { bool: false, set: :na }
+          act[:sqlite_remove]=
+            { bool: false, set: :na }
+          { bool: false, set: :na }
+        end
+        act[:sqlite_discrete]=select_arr.inspect \
+        =~/"--sql"|"--sqlite"/ \
+        && (select_arr.inspect \
+        !~/"--createdb"|"--create(?:all)?"|"--dropall"|"--recreate(?:all)?"|"--import"|"--update"|"--remove"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:harvest]=(select_arr.inspect \
+        =~/"--harvest"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:po4a_sstm]=(select_arr.inspect \
+        =~/"--po4a-ss[tm]"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:po4a_sst_ao_sst]=(select_arr.inspect \
+        =~/"--po4a-ao(?:-ss[tm])?"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:po4a_shelf]=(select_arr.inspect \
+        =~/"--po4a-shelf"|"--pot?-shelf"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        if act[:po4a_shelf][:set]==:on \
+        or act[:po4a_sst_ao_sst][:set]==:on \
+        or act[:po4a_sstm][:set]==:on
+          act[:po4a_lang]=if select_arr.inspect \
+          =~/"--(?:trans|init)-([a-z]{2}):((?:(?:[a-z]{2}\b),?)+)/
+            lng_src,lng_trn=$1,$2.split(',')
+            { bool: true, set: :on, src: lng_src, trn: lng_trn }
+          elsif select_arr.inspect \
+          =~/"--trans"/
+            { bool: true, set: :on }
+            { bool: true, set: :on, src: 'en', trn: [] }
+          else
+            { bool: false, set: :na }
+          end
+          act[:po4a_lang_trans]=if select_arr.inspect \
+          =~/"--trans-([a-z]{2}):((?:(?:[a-z]{2}\b),?)+)/
+            lng_src,lng_trn=$1,$2.split(',')
+            { bool: true, set: :on, src: lng_src, trn: lng_trn }
+          elsif select_arr.inspect \
+          =~/"--trans"/
+            { bool: true, set: :on }
+            { bool: true, set: :on, src: 'en', trn: [] }
+          else
+            { bool: false, set: :na }
+          end
+          act[:po4a_lang_init]=if select_arr.inspect \
+          =~/"--init-([a-z]{2}):((?:(?:[a-z]{2}\b),?)+)/
+            lng_src,lng_trn=$1,$2.split(',')
+            { bool: true, set: :on, src: lng_src, trn: lng_trn }
+          else
+            { bool: false, set: :na }
+          end
+        else
+          act[:po4a_lang_trans]= \
+          { bool: false, set: :na }
+          act[:po4a_lang_init]= \
+          { bool: false, set: :na }
+        end
+        act[:git]=(select_arr.inspect \
+        =~/"--git"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:hash_digests]=(select_arr.inspect \
+        =~/"--digests?"|"--hash-digests"/) \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:pdf_font_size]=if select_arr.inspect \
+        =~/"--(?:pdf-)?font-?size[=-](\d{1,2})(?:pt)?"/
+          $1
+        else :na
+        end
+        act[:pdf_hyperlink_colors]=if select_arr.inspect \
+        =~/"--pdf-hyperlinks-(?:mono(?:chrome)?|no-color)"/
+          :mono
+        elsif select_arr.inspect \
+        =~/"--pdf-hyperlinks-color"/
+          :color
+        else :na
+        end
+        act[:hash_digest_algo]=if select_arr.inspect \
+        =~/"--hash-(?:sha)?512"/
+          :sha512
+        elsif select_arr.inspect \
+        =~/"--hash-(?:sha)?256"/
+          :sha256
+        elsif select_arr.inspect \
+        =~/"--hash-md5"/
+          :md5
+        else :na
+        end
+        act[:sample_search_form]=if select_arr.inspect \
+        =~/"--sample-search-form"/
+          if select_arr.inspect \
+          =~/"--db[-=]pg"/
+            { bool: true, set: :on, db: :pg }
+          elsif select_arr.inspect \
+          =~/"--db[-=]sqlite"/
+            { bool: true, set: :on, db: :sqlite }
+          else
+            { bool: true, set: :on, db: :na }
+          end
+        else
+          { bool: false, set: :na, db: :na }
+        end
+        act[:webrick]=select_arr.inspect \
+        =~/"--webrick"/ \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:share_source]=select_arr.inspect \
+        =~/"--source"/ \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:sisupod]=select_arr.inspect \
+        =~/"--sisupod"/ \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:scp]=select_arr.inspect \
+        =~/"--scp"/ \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:rsync]=select_arr.inspect \
+        =~/"--rsync"|"--remote"/ \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:zap]=select_arr.inspect \
+        =~/"--zap"|"--delete"/ \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:urls_all]=select_arr.inspect \
+        =~/"--urls-all"/ \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:urls_selected]=if select_arr.inspect \
+        =~/"--urls"/
+          { bool: true, set: :on }
+        elsif select_arr.inspect \
+        =~/"--harvest/
+          { bool: false, set: :off }
+        elsif select_arr.inspect \
+        =~/"--verbose"|"--maintenance"/
+          { bool: true, set: :on }
+        else
+          { bool: false, set: :na }
+        end
+        act[:sitemap]=select_arr.inspect \
+        =~/"--sitemap"/ \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:qrcode]=select_arr.inspect \
+        =~/"--qrcode"/ \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:help]=select_arr.inspect \
+        =~/"--help/ \
+        ? { bool: true, set: :on }
+        : { bool: false, set: :na }
+        act[:ao]=if select_arr.inspect \
+        =~/"--ao"|"--dal"/
+          { bool: true, set: :on }
+        elsif (act[:txt][:set]==:on \
+        || act[:txt_textile][:set]==:on \
+        || act[:txt_asciidoc][:set]==:on \
+        || act[:txt_markdown][:set]==:on \
+        || act[:txt_rst][:set]==:on \
+        || act[:txt_orgmode][:set]==:on \
+        || act[:xhtml][:set]==:on \
+        || act[:epub][:set]==:on \
+        || act[:html][:set]==:on \
+        || act[:html_seg][:set]==:on \
+        || act[:html_scroll][:set]==:on \
+        || act[:json][:set]==:on \
+        || act[:texinfo][:set]==:on \
+        || act[:manpage][:set]==:on \
+        || act[:hash_digests][:set]==:on \
+        || act[:odt][:set]==:on \
+        || act[:pdf][:set]==:on \
+        || act[:pdf_p][:set]==:on \
+        || act[:pdf_l][:set]==:on \
+        || act[:qrcode][:set]==:on \
+        || act[:sisupod][:set]==:on \
+        || act[:share_source][:set]==:on \
+        || act[:po4a_sstm][:set]==:on \
+        || act[:concordance][:set]==:on \
+        || act[:sqlite_discrete][:set]==:on \
+        || act[:sqlite_import][:set]==:on \
+        || act[:sqlite_update][:set]==:on \
+        || act[:sqlite_remove][:set]==:on \
+        || act[:psql_import][:set]==:on \
+        || act[:psql_update][:set]==:on \
+        || act[:psql_remove][:set]==:on \
+        || act[:xml_dom][:set]==:on \
+        || act[:xml_sax][:set]==:on \
+        || act[:xml_docbook_book][:set]==:on \
+        || act[:xml_fictionbook][:set]==:on \
+        || act[:xml_scaffold_structure_sisu][:set]==:on \
+        || act[:xml_scaffold_structure_collapse][:set]==:on )
+          { bool: true, set: :on }
+        else
+          { bool: false, set: :na }
+        end
+        act[:manifest]=if select_arr.inspect \
+        =~/"--inc-manifest"/
+          { bool: true, set: :on }
+        elsif select_arr.inspect \
+        =~/"--(?:exc|no)-manifest"/ \
+        || act[:switch][:off].inspect =~/"manifest"/
+          { bool: false, set: :off }
+        elsif select_arr.inspect \
+        =~/"--manifest"/
+          { bool: true, set: :on }
+        elsif (act[:txt][:set]==:on \
+        || act[:txt_textile][:set]==:on \
+        || act[:txt_asciidoc][:set]==:on \
+        || act[:txt_markdown][:set]==:on \
+        || act[:txt_rst][:set]==:on \
+        || act[:txt_orgmode][:set]==:on \
+        || act[:xhtml][:set]==:on \
+        || act[:epub][:set]==:on \
+        || act[:html][:set]==:on \
+        || act[:html_seg][:set]==:on \
+        || act[:html_scroll][:set]==:on \
+        || act[:json][:set]==:on \
+        || act[:texinfo][:set]==:on \
+        || act[:manpage][:set]==:on \
+        || act[:hash_digests][:set]==:on \
+        || act[:odt][:set]==:on \
+        || act[:pdf][:set]==:on \
+        || act[:pdf_p][:set]==:on \
+        || act[:pdf_l][:set]==:on \
+        || act[:qrcode][:set]==:on \
+        || act[:sisupod][:set]==:on \
+        || act[:share_source][:set]==:on \
+        || act[:po4a_sstm][:set]==:on \
+        || act[:concordance][:set]==:on \
+        || act[:xml_dom][:set]==:on \
+        || act[:xml_sax][:set]==:on \
+        || act[:xml_docbook_book][:set]==:on \
+        || act[:xml_fictionbook][:set]==:on \
+        || act[:xml_scaffold_structure_sisu][:set]==:on \
+        || act[:xml_scaffold_structure_collapse][:set]==:on )
+          { bool: true, set: :on }
+        else { bool: true, set: :na }
+        end
+        act[:console_messages] = ''
+        act[:verbose]=if select_arr.inspect \
+        =~/"--verbose"/
+          act[:console_messages] << ' --verbose '
+          { bool: true, set: :on }
+        else
+          { bool: false, set: :na }
+        end
+        act[:verbose_plus]=if select_arr.inspect \
+        =~/"--very-verbose"|"--verbose-very"/
+          act[:console_messages] << ' --very-verbose '
+          { bool: true, set: :on }
+        else
+          { bool: false, set: :na }
+        end
+        act[:version_info]=if select_arr.inspect \
+        =~/"--version"|"--verbose"|"--maintenance"/
+          act[:console_messages] << ' --maintenance '
+          { bool: true, set: :on }
+        else
+          { bool: false, set: :na }
+        end
+        act[:quiet]=if (select_arr.inspect =~/"--quiet"/)
+          act[:console_messages] << ' --quiet '
+          { bool: true, set: :on }
+        else
+          { bool: false, set: :na }
+        end
+        act[:color_state]=if select_arr.inspect =~/"--color-on"|"--color"/
+          act[:console_messages] << ' --color-on '
+          { bool: true, set: :on }
+        elsif (select_arr.inspect =~/"--color-off"/)
+          act[:console_messages] << ' --color-off '
+          { bool: false, set: :off }
+        else { bool: true, set: :na } #fix default color
+        end
+#       act[:color_toggle]=if select_arr.inspect =~/"--color-toggle"/
+#         true
+#       else false
+#       end
+        act[:maintenance]=if (select_arr.inspect =~/"--maintenance|--keep-processing-files"/)
+          act[:console_messages] << ' --maintenance '
+          { bool: true, set: :on }
+        else
+          { bool: false, set: :na }
+        end
+        act[:profile]=if (select_arr.inspect =~/"--profile"/)
+          act[:console_messages] << ' --color-off '
+          { bool: true, set: :on }
+        else
+          { bool: false, set: :na }
+        end
+        @act=act
+      end
+    end
+    def opt_ch
+      @opt_ch
+    end
+    def selections
+      def arr
+        @select_arr.sort
+      end
+      def str
+        @select_str ||= arr.join(' ')
+      end
+      self
+    end
+    def act
+      @@act
+    end
+    def files_mod
+      files_mod=files
+      @files_mod=files_mod
+    end
+    def files
+      @files
+    end
+    def f_pth
+      @f_pth
+    end
+    def pth
+      @pth
+    end
+    def sub_location
+      pth.gsub(/#{base_path}/,'')
+    end
+    def lng
+      @lng
+    end
+    def lng_base
+      @lng_base
+    end
+    def fno
+      @fno=(fns.nil? || fns.empty?) \
+      ? '' \
+      : (fns[/(.+?(?:sst|ssm))(?:\.sst)?/,1])
+    end
+    def fng
+      @fng=(fno.nil? || fno.empty?) \
+      ? '' \
+      : (fno.gsub(/(?:~(?:#{Px[:lng_lst_rgx]}))?(\.ss[tm])$/,'\1'))
+    end
+    def fns
+      @fns
+    end
+    def fnl
+      @fns.gsub(/(\S+?)((?:\.ssm)?\.sst)/,"\\1.#{lng}\\2")
+    end
+    def what
+      @what
+    end
+    def fnb
+      (fns.nil? || fns.empty?) \
+      ? '' \
+      : (fns[/(.+?)\.(?:(?:-|ssm\.)?sst|ssm)$/,1])
+    end
+    def fnc
+      @fnc=(@fns =~/\.(?:ssm\.sst|ssm)$/) \
+      ? fnb + '.ssm.sst'
+      : @fns
+    end
+    def fncb
+      @fncb=(@fns =~/(?:\~\S{2,3})?\.(?:ssm\.sst|ssm)$/) \
+      ? fnb + '.ssm.sst'
+      : @fns.gsub(/(?:\~\S{2,3})?(\.sst)$/,'\1')
+    end
+  end
+end
+__END__
+note usually named @opt is carried in dp document parameters (usually as @md.opt), @opt is a
+subset of @md where @md is passed, contents of @opt are available as @md.opt
+passing @opt as well is duplication check for fns & fnb
+#+END_SRC
+
+** hub_actions.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/hub_actions.rb"
+# <<sisu_document_header>>
+module SiSU_Hub_Actions
+  class HubActions
+    require_relative 'utils_composite'                    # utils_composite.rb
+    include SiSU_Composite_Doc_Utils                      # composite doc, .ssm, extract all related insert files, array of filenames test
+    def initialize(opt)
+      @opt=opt
+    end
+    def report
+      def version_info?
+        if @opt.act[:version_info][:set]==:on
+          SiSU_Env::InfoAbout.new(@opt).sisu_version
+        end
+      end
+      def version_number_git?
+        if @opt.act[:version_info][:set]==:on \
+        || @opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on
+          SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            ' ' + SiSU_is.git_version_info?
+          ).grey
+        end
+      end
+      def version_dir?
+        if @opt.act[:version_info][:set]==:on \
+        || @opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on
+          SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            ' ' + File.dirname(__FILE__)
+          ).grey
+        end
+      end
+      def version_info_extra?
+        if @opt.act[:version_info][:set]==:on \
+        || @opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on
+          if SiSU_is.git_version_info?
+            SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              ' ' + File.dirname(__FILE__) + \
+              '  vcr: ' + SiSU_is.git_version_info?
+            ).grey
+          else
+            SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              ' ' + File.dirname(__FILE__)
+            ).grey
+          end
+        end
+      end
+      self
+    end
+    def prepare
+      def site?
+        if @opt.act[:site_init][:set]==:on               #% --init-site, -C initialize/configure
+          require_relative 'conf'                        #% --init-site, -C initialize/configure
+          SiSU_Initialize::Source.new(@opt).read
+          if @opt.act[:rsync][:set]==:on
+            if @opt.selections.str =~/--init(?:ialize)?=site/ \
+            and @opt.selections.str =~/RZ/
+              SiSU_Hub_Actions::Operations.new(@opt).remote_put_base_site_rsync_match
+            else SiSU_Hub_Actions::Operations.new(@opt).remote_put_base_site_rsync
+            end
+          elsif @opt.act[:scp][:set]==:on
+            if @opt.selections.str =~/--init(?:ialize)?=site/ \
+            and @opt.selections.str =~/CCr/
+              SiSU_Hub_Actions::Operations.new(@opt).remote_put_base_site_all
+            else SiSU_Hub_Actions::Operations.new(@opt).remote_put_base_site
+            end
+          end
+        end
+      end
+      def remote_site?
+        if @opt.act[:site_init][:set]==:on
+          if @opt.act[:site_init][:set]==:on               #% --init-site, -C initialize/configure
+            #require_relative 'conf'                        #% --init-site, -C initialize/configure
+            #SiSU_Initialize::Source.new(@opt).read
+            #if @opt.act[:rsync][:set]==:on
+            #  if @opt.selections.str =~/--init(?:ialize)?=site/ \
+            #  and @opt.selection =~/RZ/
+            #    SiSU_Hub_Actions::Operations.new(@opt).remote_put_base_site_rsync_match
+            #  else SiSU_Hub_Actions::Operations.new(@opt).remote_put_base_site_rsync
+            #  end
+            #elsif @opt.act[:scp][:set]==:on
+            #  if @opt.selections.str =~/--init(?:ialize)?=site/ \
+            #  and @opt.selection =~/CCr/
+            #    SiSU_Hub_Actions::Operations.new(@opt).remote_put_base_site_all
+            #  else SiSU_Hub_Actions::Operations.new(@opt).remote_put_base_site
+            #  end
+            #end
+          end
+        end
+      end
+      def sql?
+        if @opt.act[:psql_createdb][:set]==:on \
+        or @opt.act[:psql_create][:set]==:on \
+        or @opt.act[:psql_drop][:set]==:on
+          done=:ok
+          if @opt.act[:psql][:set]==:on
+            require_relative 'dbi'
+            SiSU_DBI::SQL.new(@opt).connect
+          end
+        end
+        if @opt.act[:sqlite_createdb][:set]==:on \
+        or @opt.act[:sqlite_create][:set]==:on \
+        or @opt.act[:sqlite_drop][:set]==:on
+          done=:ok
+          if @opt.act[:sqlite][:set]==:on
+            require_relative 'dbi'
+            SiSU_DBI::SQL.new(@opt).connect
+          end
+        end
+      end
+      def search_form?
+        if @opt.act[:sample_search_form][:set]==:on      #% --sample-search-form, -F cgi sample search form
+          SiSU_Hub_Actions::Operations.new(@opt).cgi
+        end
+      end
+      def webrick?
+        if @opt.act[:webrick][:set]==:on                 #% --webrick, -W webrick
+          SiSU_Hub_Actions::Operations.new(@opt).webrick
+        end
+      end
+      self
+    end
+    def outputs
+      def each_file
+        def abstract_objects?
+          if @opt.act[:ao][:set]==:on                    #% --ao --dal, -m
+            if @opt.f_pths.length > 0
+              unless @opt.act[:po4a_shelf][:set]==:on    # --po4a-shelf
+                if @opt.fno =~ /\.ssm$/
+                  require_relative 'ao_composite'        # ao_composite.rb #pre-processing
+                  SiSU_Assemble::Composite.new(@opt).read
+                end
+                require_relative 'ao'                    # ao.rb
+                SiSU_AO::Source.new(@opt).read
+              end
+            else
+              msg='document abstraction request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+        end
+        def qrcode?
+          if @opt.act[:qrcode][:set]==:on                #% --qrcode, -Q
+            if @opt.f_pths.length > 0
+              require_relative 'qrcode'                  # qrcode.rb
+              SiSU_QRcode::Source.new(@opt).read
+            else
+              msg='qrcode request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+        end
+        def hash_digests?
+          if @opt.act[:hash_digests][:set]==:on          #% --hash-digests, -N digest tree
+            if @opt.f_pths.length > 0
+              require_relative 'digests'                 # digests.rb
+              SiSU_DigestView::Source.new(@opt).read
+            else
+              msg='hash digest request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+        end
+        def text?
+          if @opt.act[:txt][:set]==:on                   #% --txt, -t -a
+            if @opt.f_pths.length > 0
+              require_relative 'txt_plain'               #  txt_plain.rb
+              SiSU_Txt_Plain::Source.new(@opt).read
+            else
+              msg='text request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+          if @opt.act[:txt_textile][:set]==:on           #% --textile
+            if @opt.f_pths.length > 0
+              require_relative 'txt_textile'             #txt_textile.rb
+              SiSU_Txt_Textile::Source.new(@opt).read
+            else
+              msg='textile request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+          if @opt.act[:txt_asciidoc][:set]==:on          #% --asciidoc
+            if @opt.f_pths.length > 0
+              require_relative 'txt_asciidoc'            # txt_asciidoc.rb
+              SiSU_Txt_AsciiDoc::Source.new(@opt).read
+            else
+              msg='asciidoc request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+          if @opt.act[:txt_markdown][:set]==:on          #% --markdown
+            if @opt.f_pths.length > 0
+              require_relative 'txt_markdown'            # txt_markdown.rb
+              SiSU_Txt_Markdown::Source.new(@opt).read
+            else
+              msg='markdown request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+          if @opt.act[:txt_rst][:set]==:on               #% --rst, --rest
+            if @opt.f_pths.length > 0
+              require_relative 'txt_rst'                 # txt_rst.rb
+              SiSU_Txt_rST::Source.new(@opt).read
+            else
+              msg='rst request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+          if @opt.act[:txt_orgmode][:set]==:on          #% --orgmode
+            if @opt.f_pths.length > 0
+              require_relative 'txt_orgmode'            # txt_orgmode.rb
+              SiSU_Txt_OrgMode::Source.new(@opt).read
+            else
+              msg='orgmode request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+        end
+        def html?
+          if @opt.act[:html][:set]==:on                  #% --html, -h
+            if @opt.f_pths.length > 0
+              require_relative 'html'                    # html.rb
+              SiSU_HTML::Source.new(@opt).read
+            else
+              msg='html request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          else
+            if @opt.act[:html_seg][:set]==:on            #% --html-seg
+              if @opt.f_pths.length > 0
+                require_relative 'html'                  # html.rb
+                SiSU_HTML::Source.new(@opt).read
+              else
+                msg='html seg request requires sisu markup files'
+                if (@opt.act[:verbose_plus][:set]==:on \
+                || @opt.act[:maintenance][:set]==:on)
+                  SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                    mark(msg)
+                else puts msg
+                end
+              end
+            end
+            if @opt.act[:html_scroll][:set]==:on         #% --html-scroll
+              if @opt.f_pths.length > 0
+                require_relative 'html'                  # html.rb
+                SiSU_HTML::Source.new(@opt).read
+              else
+                msg='html scroll request requires sisu markup files'
+                if (@opt.act[:verbose_plus][:set]==:on \
+                || @opt.act[:maintenance][:set]==:on)
+                  SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                    mark(msg)
+                else puts msg
+                end
+              end
+            end
+          end
+          if @opt.act[:concordance][:set]==:on           #% --concordance, -w
+            if @opt.f_pths.length > 0
+              require_relative 'html_concordance'        # html_concordance.rb
+              SiSU_Concordance::Source.new(@opt).read
+            else
+              msg='concordance request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+        end
+        def json?
+          if @opt.act[:json][:set]==:on                 #% --js, -J
+            if @opt.f_pths.length > 0
+              require_relative 'json'                   # json.rb
+              SiSU_JSON::Source.new(@opt).read
+            else
+              msg='json request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+        end
+        def xhtml?
+          if @opt.act[:xhtml][:set]==:on                 #% --xhtml, -b
+            if @opt.f_pths.length > 0
+              require_relative 'xhtml'                   # xhtml.rb
+              SiSU_XHTML::Source.new(@opt).read
+            else
+              msg='xhtml request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+          if @opt.act[:epub][:set]==:on                  #% --epub, -e
+            if @opt.f_pths.length > 0
+              require_relative 'xhtml_epub2'             # xhtml_epub2.rb
+              SiSU_XHTML_EPUB2::Source.new(@opt).read
+            else
+              msg='epub request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+        end
+        def xml?
+          if @opt.act[:odt][:set]==:on                   #% --odt, -o
+            if @opt.f_pths.length > 0
+              require_relative 'xml_odf_odt'             # xml_odf_odt.rb
+              SiSU_XML_ODF_ODT::Source.new(@opt).read
+            else
+              msg='odt request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+          if @opt.act[:xml_scaffold_structure_sisu][:set]==:on #% --xml-scaffold --xml-scaffold-sisu
+            if @opt.f_pths.length > 0
+              require_relative 'xml_scaffold_structure_sisu'   #  xml_scaffold_structure_sisu.rb
+              SiSU_XML_Scaffold_Structure_Sisu::Source.new(@opt).read
+            else
+              msg='xml scaffold request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+          if @opt.act[:xml_scaffold_structure_collapse][:set]==:on #% --xml-scaffold-collapse
+            if @opt.f_pths.length > 0
+              require_relative 'xml_scaffold_structure_collapsed'  # xml_scaffold_structure_collapsed.rb
+              SiSU_XML_Scaffold_Structure_Collapse::Source.new(@opt).read
+            else
+              msg='xml scaffold request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+          if @opt.act[:xml_docbook_book][:set]==:on      #% --xml-docbook
+            if @opt.f_pths.length > 0
+              require_relative 'xml_docbook5'            # xml_docbook5.rb
+              SiSU_XML_Docbook_Book::Source.new(@opt).read
+            else
+              msg='docbook request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+          if @opt.act[:xml_fictionbook][:set]==:on       #% --xml-fictionbook
+            if @opt.f_pths.length > 0
+              require_relative 'xml_fictionbook2'        # xml_fictionbook2.rb
+              SiSU_XML_Fictionbook::Source.new(@opt).read
+            else
+              msg='fictionbook request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+          if @opt.act[:xml_sax][:set]==:on               #% --xml-sax, -x
+            if @opt.f_pths.length > 0
+              require_relative 'xml_sax'                 # xml_sax.rb
+              SiSU_XML_SAX::Source.new(@opt).read
+            else
+              msg='xml sax request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+          if @opt.act[:xml_dom][:set]==:on               #% --xml-dom, -X
+            if @opt.f_pths.length > 0
+              require_relative 'xml_dom'                 # xml_dom.rb
+              SiSU_XML_DOM::Source.new(@opt).read
+            else
+              msg='xml dom request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+        end
+        def pdf?
+          if @opt.act[:pdf][:set]==:on \
+          or @opt.act[:pdf_p][:set]==:on \
+          or @opt.act[:pdf_l][:set]==:on                 #% --pdf-l --pdf, -p
+            if @opt.f_pths.length > 0
+              require_relative 'texpdf'                  # texpdf.rb
+              SiSU_TeX::Source.new(@opt).read
+            else
+              msg='pdf request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+        end
+        def man_or_info?
+          if @opt.act[:manpage][:set]==:on               #% --manpage, -i
+            if @opt.f_pths.length > 0
+              require_relative 'manpage'                 # manpage.rb
+              SiSU_Manpage::Source.new(@opt).read
+            else
+              msg='manpage request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+          if @opt.act[:texinfo][:set]==:on               #% --texinfo, -I
+            if @opt.f_pths.length > 0
+              require_relative 'texinfo'                 # texinfo.rb
+              SiSU_TexInfo::Source.new(@opt).read
+            else
+              msg='texinfo request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+        end
+        def sqlite_discrete?
+          if @opt.act[:sqlite_discrete][:set]==:on       #% --sqlite, -d
+            if @opt.f_pths.length > 0
+              require_relative 'dbi_discrete'            # dbi_discrete.rb
+              SiSU_DBI_Discrete::SQL.new(@opt).build
+            else
+              msg='sqlite (discrete) request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+        end
+        def po4a_make?
+          if @opt.act[:po4a_sst_ao_sst][:set]==:on               #% --po4a-ao
+            if @opt.f_pths.length > 0
+              require_relative 'src_po4a_sst_ao_sst'
+              SiSU_SStm_AO_SStm::Source.new(@opt).read_process_src_files # src_po4a_sst_ao_sst.rb
+            else
+              msg='sst request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:cyan).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+        end
+        def elasticsearch?
+          if @opt.act[:elasticsearch][:set]==:on         #% --elastic, -x
+            if @opt.f_pths.length > 0
+              require_relative 'json_elastic'            # json_elastic.rb
+              SiSU_Elastic::Source.new(@opt).read
+            else
+              msg='easticsearch request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+        end
+        def manifest?
+          if @opt.act[:manifest][:set]==:on              #% --manifest, -y
+            if @opt.f_pths.length > 0
+              begin
+                require_relative 'html_manifest'           # html_manifest.rb
+                ((@opt.act[:sisupod][:set]==:on \
+                || @opt.act[:share_source][:set]==:on \
+                || @opt.act[:po4a_sstm][:set]==:on) \
+                && @opt.f_pths.length < 2 ) \
+                ? nil
+                : SiSU_Manifest::Source.new(@opt).read
+              rescue
+              end
+            else
+              msg='manifest request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+        end
+        def harvest?
+          if @opt.act[:harvest][:set]==:on               #% --harvest
+            if @opt.f_pths.length > 0
+              require_relative 'html_harvest'            # html_harvest.rb
+              SiSU_Harvest::Source.new(@opt).read
+            else
+              msg='harvest request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+        end
+        self
+      end
+      def loop_files
+        def share_source?
+          if @opt.act[:sisupod][:set]==:on \
+          or @opt.act[:share_source][:set]==:on \
+          or @opt.act[:po4a_sstm][:set]==:on \
+          or @opt.act[:git][:set]==:on
+            begin
+              if @opt.f_pths.length > 0
+                require_relative 'src_shared'
+                SiSU_Hub_Loops::OptionLoopFiles.new(@opt).
+                loop_files_on_given_option do
+                  SiSU_Source::SiSUpodSource.new(@opt).read
+                end
+              else
+                msg='share markup source request requires sisu markup files'
+                if (@opt.act[:verbose_plus][:set]==:on \
+                || @opt.act[:maintenance][:set]==:on)
+                  SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:cyan).
+                    mark(msg)
+                else puts msg
+                end
+              end
+              if @opt.act[:sisupod][:set]==:on           #% --sisupod, -S
+                if @opt.f_pths.length > 0
+                  require_relative 'src_sisupod_make'    # src_sisupod_make.rb
+                  begin
+                    SiSU_Hub_Loops::OptionLoopFiles.new(@opt).
+                    loop_files_on_given_option_bundle do
+                      SiSU_Doc::Source.new(@opt).sisupod_tar_xz
+                    end
+                  ensure
+                  end
+                else
+                  msg='sisupod (share markup source) request requires sisu markup files'
+                  if (@opt.act[:verbose_plus][:set]==:on \
+                  || @opt.act[:maintenance][:set]==:on)
+                    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:cyan).
+                      mark(msg)
+                  else puts msg
+                  end
+                end
+              end
+              if @opt.act[:git][:set]==:on               #% --git, -g
+                if @opt.f_pths.length > 0
+                  require_relative 'git'                 # git.rb
+                  begin
+                    SiSU_Hub_Loops::OptionLoopFiles.new(@opt).
+                    loop_files_on_given_option do
+                      SiSU_Git::Source.new(@opt).read
+                    end
+                  ensure
+                    SiSU_Hub_Loops::OptionLoopFiles.new(@opt).
+                    loop_files_on_given_option_bundle do
+                      SiSU_Git::Source.new(@opt).git_commit
+                    end
+                  end
+                else
+                  msg='git request requires sisu markup files'
+                  if (@opt.act[:verbose_plus][:set]==:on \
+                  || @opt.act[:maintenance][:set]==:on)
+                    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:cyan).
+                      mark(msg)
+                  else puts msg
+                  end
+                end
+              end
+              if (@opt.act[:sisupod][:set]==:on \
+              || @opt.act[:share_source][:set]==:on \
+              || @opt.act[:po4a_sstm][:set]==:on) \
+              and @opt.act[:manifest][:set]==:on         #% --manifest, -y
+                if @opt.f_pths.length > 0
+                  require_relative 'html_manifest'            # html_manifest.rb
+                  begin
+                  ensure
+                    SiSU_Hub_Loops::OptionLoopFiles.new(@opt).
+                    loop_files_on_given_option_bundle do
+                      SiSU_Manifest::Source.new(@opt).read
+                    end
+                  end
+                else
+                  msg='manifest request requires sisu markup files'
+                  if (@opt.act[:verbose_plus][:set]==:on \
+                  || @opt.act[:maintenance][:set]==:on)
+                    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:cyan).
+                      mark(msg)
+                  else puts msg
+                  end
+                end
+              end
+            ensure
+              if @opt.f_pths.length > 0
+                env=SiSU_Env::InfoEnv.new(@opt.fns)
+                path_pod=env.processing_path.processing_sisupod(@opt).paths
+                unless @opt.act[:maintenance][:set]==:on
+                  FileUtils::rm_rf("#{path_pod[:sisupod]}/*") \
+                    if FileTest.directory?(path_pod[:sisupod])
+                end
+              else
+                #SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:cyan).
+                #  mark('*** request requires sisu markup files')
+              end
+            end
+          end
+          if @opt.act[:share_source][:set]==:on
+            if @opt.f_pths.length > 0
+              require_relative 'src_sisupod_sstm'           # src_sisupod_sstm.rb
+              begin
+              ensure
+                SiSU_Hub_Loops::OptionLoopFiles.new(@opt).
+                loop_files_on_given_option_bundle do
+                  SiSU_Markup::Source_Sisupod.new(@opt).read
+                end
+              end
+            else
+              msg='share markup source request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:cyan).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+          if @opt.act[:po4a_sstm][:set]==:on                    #% --po4a-sst
+            if @opt.f_pths.length > 0
+              require_relative 'src_po4a_sstm'
+              begin
+                SiSU_Hub_Loops::OptionLoopFiles.new(@opt).
+                loop_files_on_given_option do
+                  SiSU_Markup::Source_Po4a.new(@opt).read       # src_po4a_sstm.rb
+                end
+              ensure
+              end
+            else
+              msg='sst request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:cyan).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+          if @opt.act[:po4a_sst_ao_sst][:set]==:on               #% --po4a-ao
+            if @opt.f_pths.length > 0
+              require_relative 'src_po4a_sst_ao_sst'
+              begin
+                SiSU_Hub_Loops::OptionLoopFiles.new(@opt).
+                loop_files_on_given_option do
+                  SiSU_SStm_AO_SStm::Source.new(@opt).read_setup # src_po4a_sst_ao_sst.rb
+                end
+              ensure
+              end
+            else
+              msg='sst request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:cyan).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+          if @opt.act[:po4a_shelf][:set]==:on            #% --po4a-shelf
+            if @opt.f_pths.length > 0
+              require_relative 'src_po4a_shelf'
+              begin
+                SiSU_Hub_Loops::OptionLoopFiles.new(@opt).
+                loop_files_on_given_option do
+                  SiSU_Po4a::Source.new(@opt).read       # src_po4a_shelf.rb
+                end
+              ensure
+              end
+            else
+              msg='src_po4a_shelf request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:cyan).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+          if @opt.act[:images][:set]==:on                #% --images, -j
+            if @opt.f_pths.length > 0
+              require_relative 'shared_images'
+              SiSU_Hub_Loops::OptionLoopFiles.new(@opt).
+              loop_files_on_given_option do
+                SiSU_Images::Source.new(@opt).read       # shared_images.rb
+              end
+            else
+              msg='place images request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:cyan).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+        end
+        def run_termsheet? #broken, revisit later
+          if @opt.selections.str =~/--termsheet/         #% -T termsheet/standard form #fix later
+            if @opt.f_pths.length > 0
+              @opt.files.each do |fns|
+                if FileTest.file?(fns)
+                  @opt.fns=fns
+                  case @opt.fns
+                  when /\.(termsheet.rb)$/
+                    SiSU_Hub_Actions::Operations.new(@opt).termsheet
+                  else                                   #print "not processed --> ", fns, "\n"
+                  end
+                else SiSU_Hub_Actions::Operations.new(@opt).not_found
+                end
+              end
+            else
+              msg='process termsheet request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:cyan).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+        end
+        def sql?
+          if @opt.act[:psql][:set]==:on                  #% --pg, -D
+            if @opt.f_pths.length > 0
+              require_relative 'dbi'
+              SiSU_Hub_Loops::OptionLoopFiles.new(@opt).
+              loop_files_on_given_option do
+                SiSU_DBI::SQL.new(@opt).connect          # dbi.rb
+              end
+            else
+              msg='pgsql request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:cyan).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+          if @opt.act[:sqlite][:set]==:on                #% --sqlite, -d
+            if @opt.f_pths.length > 0
+              require_relative 'dbi'
+              SiSU_Hub_Loops::OptionLoopFiles.new(@opt).
+              loop_files_on_given_option do
+                SiSU_DBI::SQL.new(@opt).connect          # dbi.rb
+              end
+            else
+              msg='sqlite request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:cyan).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+        end
+        def manifest?
+          if @opt.act[:manifest][:set]==:on              #% --manifest, -y
+            if @opt.f_pths.length > 1
+              require_relative 'html_manifest'
+              SiSU_Hub_Loops::OptionLoopFiles.new(@opt).manifest_on_files_translated do
+                SiSU_Manifest::Source.new(@opt).read     # html_manifest.rb
+              end
+            end
+          end
+        end
+        def sitemaps?
+          if @opt.act[:sitemap][:set]==:on               #% --sitemap, -Y
+            if @opt.f_pths.length > 0
+              require_relative 'sitemaps'
+              SiSU_Hub_Loops::OptionLoopFiles.new(@opt).
+              loop_files_on_given_option do
+                SiSU_Sitemaps::Source.new(@opt).read     # sitemaps.rb
+              end
+            end
+          end
+        end
+        def remote_placement?
+          if @opt.act[:harvest][:set] !=:on
+            if @opt.act[:scp][:set]==:on                 #% -r copy to remote server
+              if @opt.f_pths.length > 0
+                require_relative 'remote'                # remote.rb
+                SiSU_Hub_Loops::OptionLoopFiles.new(@opt).
+                loop_files_on_given_option do
+                  SiSU_Remote::Put.new(@opt).scp
+                end
+              end
+            end
+            if @opt.act[:rsync][:set]==:on               #% -R copy to remote server
+              if @opt.f_pths.length > 0
+                require_relative 'remote'                # remote.rb
+                SiSU_Hub_Loops::OptionLoopFiles.new(@opt).
+                loop_files_on_given_option do
+                  SiSU_Remote::Put.new(@opt).rsync
+                end
+              end
+            end
+          else
+          end
+        end
+        def urls?
+          if @opt.act[:urls_selected][:set]==:on         #% --urls
+            if @opt.f_pths.length > 0
+              require_relative 'urls'
+              SiSU_Hub_Loops::OptionLoopFiles.new(@opt).
+              loop_files_on_given_option do
+                SiSU_Urls::Source.new(@opt).read         #% urls.rb
+              end
+            else
+              msg='urls request requires sisu markup files'
+              if (@opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:cyan).
+                  mark(msg)
+              else puts msg
+              end
+            end
+          end
+        end
+        self
+      end
+      def init?
+        SiSU_Env::InfoProcessingFlag.new
+        if @opt.act[:ao][:set]==:on \
+        or @opt.act[:maintenance][:set]==:on             #% --maintenance, -M
+          env=SiSU_Env::InfoEnv.new(@opt.fns)
+          path={}
+          path[:css]=env.path.output + '/_sisu/css'
+          path[:xml]=env.path.output + '/_sisu/xml'
+          path[:xsd]=path[:xml] + '/xsd'
+          path[:xsd]=path[:xml] + '/rnc'
+          path[:xsd]=path[:xml] + '/rng'
+          re_p3=/(sisupod(?:\.txz)?|\S+?\.ss[mt]\.txz|[^\/]+?\.ssp)$/
+          unless @opt.files.join(',') =~ re_p3 #do not mix pods with source markup files in command line
+            if @opt.act[:maintenance][:set] ==:on
+              $VERBOSE=false                             #debug $VERBOSE=true
+            end
+          end
+          re_p2=/(sisupod(?:\.zip)?|\S+?\.ss[mt]\.zip)$/
+          unless @opt.files.join(',') =~ re_p2 #do not mix pods with source markup files in command line
+            if @opt.act[:maintenance][:set] ==:on
+              $VERBOSE=false                             #debug $VERBOSE=true
+            end
+          end
+        end
+        if @opt.act[:ao][:set]==:on
+          @retry_count= -1
+          begin
+            @get_s,@get_p,@get_pl=[],[],[]
+            re_s=/(\S+?\.-sst)$/
+            re_p3=/((?:https?|file):\/\/\S+?(?:\/\S+?\.ss[mt]\.txz|sisupod(?:\.txz)?|\.ssp))/
+            re_pl3=/^(\/\S+?\.ss[mt]\.txz)/
+            @opt.files.each do |fns|
+              if fns =~re_s
+                @get_s << @opt.f_pths[0][:url]
+              end
+              if fns =~re_p3
+                @get_p << re_p3.match(fns)[1] if re_p3
+              end
+              if fns =~re_pl3
+                @get_pl << re_pl3.match(fns)[1] if re_p3
+              end
+            end
+            if @get_s.length > 0                         #% remote markup file .sst
+              require_relative 'remote'                  # remote.rb
+              SiSU_Remote::Get.new(@opt,@get_s).fns
+              SiSU_Hub_Actions::Operations.new.counter
+            end
+            if @get_p.length > 0                         #% remote sisupod
+              require_relative 'remote'                  # remote.rb
+              SiSU_Remote::Get.new(@opt,@get_p).sisupod
+            end
+          rescue
+            SiSU_Errors::Rescued.new($!,$@,@opt,@fns).location do
+              __LINE__.to_s + ':' + __FILE__
+            end
+            @retry_count +=1
+            retry unless @retry_count > 1
+          ensure
+          end
+        end
+      end
+      self
+    end
+  end
+  class Operations
+    @@n_do=0
+    def initialize(opt='')
+      @opt=opt
+      @cX=SiSU_Screen::Ansi.new(@opt).cX
+    end
+    def counter
+      @@n_do=0
+    end
+    def remote_put_base_site_rsync                       # -CR
+      SiSU_Utils::CodeMarker.new(__LINE__,__FILE__).mark(:cyan) \
+        if @opt.act[:maintenance][:set] ==:on
+      require_relative 'remote'                          # remote.rb
+      SiSU_Remote::Put.new(@opt).rsync_base
+    end
+    def remote_put_base_site_rsync_match                 # -CCRZ
+      SiSU_Utils::CodeMarker.new(__LINE__,__FILE__).mark(:cyan) \
+        if @opt.act[:maintenance][:set] ==:on
+      require_relative 'remote'                          # remote.rb
+      SiSU_Remote::Put.new(@opt).rsync_base_sync
+    end
+    def remote_put_base_site                             # -Cr
+      SiSU_Utils::CodeMarker.new(__LINE__,__FILE__).mark(:cyan) \
+        if @opt.act[:maintenance][:set] ==:on
+      require_relative 'remote'                          # remote.rb
+      SiSU_Remote::Put.new(@opt).scp_base
+    end
+    def remote_put_base_site_all                         # -CCr
+      SiSU_Utils::CodeMarker.new(__LINE__,__FILE__).mark(:cyan) \
+        if @opt.act[:maintenance][:set] ==:on
+      require_relative 'remote'                          # remote.rb
+      SiSU_Remote::Put.new(@opt).scp_base_all
+    end
+    def cgi                                              # -F
+      require_relative 'cgi'                             # cgi.rb
+      SiSU_CGI::SearchSQL.new(@opt).read
+    end
+    def termsheet                                        # -t
+      system("sisu_termsheet #{@opt.selections.str} #{@opt.fns}\n")
+      @@n_do=@@n_do+1
+      SiSU_Screen::Ansi.new(
+        @opt.selections.str,@@n_do,
+        'Termsheet(s) processed'
+      ).term_sheet_title unless @opt.act[:quiet][:set] ==:on
+    end
+    def webrick                                          # -W
+      prt=SiSU_Env::InfoEnv.new(@fns).port.webrick_port
+      puts %{#{@cX.blue}[#{@cX.off}#{@cX.green}Start Webrick web server on port: #{prt}#{@cX.off}#{@cX.blue}] #{@cX.off*2} }
+      require_relative 'webrick'
+      SiSU_Webserv::WebrickStart.new
+    end
+    def not_found
+      puts "\n#{@cX.fuchsia}FILE NOT FOUND:#{@cX.off} [ #{@opt.fns} ] - requested #{@opt.selections.str} processing skipped\n"
+    end
+    def convert_name_message(fns,type,i,o,rune)
+      %{\nIn filename: "#{@cX.fuchsia}#{fns}#{@cX.off}" [ #{type} ] #{@cX.fuchsia}is apre 0.36 markup filename.#{@cX.off} #{@cX.brown}Please rename your file.#{@cX.off}\n\tAs of sisu-0.37, SiSU markup files with #{@cX.brown}the extensions #{i} should be re-named #{o}#{@cX.off}\n\tif you have the program called 'rename' installed, the following rune should do the trick:\n\t\t#{rune}\n\talternatively try:\n\t\tsisu --convert --36to37 #{fns}\n\trequested #{@opt.selections.str} processing skipped\n}
+    end
+    def not_recognised
+      case @opt.fns
+      when /(\.s[123])$/
+        type=@opt.fns.gsub(/\S+?(#{$1})/,'\1')
+        rune=%q{rename 's/\.s[123]$/\.sst/' *.s{1,2,3}}
+        puts convert_name_message(@opt.fns,type,'.s1 .s2 and .s3','.sst',rune)
+      when /(\.r[123])$/
+        type=@opt.fns.gsub(/\S+?(#{$1})/,'\1')
+        rune=%q{rename 's/\.r[123]$/\.ssm/' *.r{1,2,3}}
+        puts convert_name_message(@opt.fns,type,'.r1 .r2 and .r3','.sst',rune)
+        puts %{\n\tNote also that you will need to change the names of the files called/required\n\twithin the document text to build the composite document\n\t\t.s1 .s2 .s3 should be .sst \n\t\t.si should be .ssi\n\trequested #{@opt.selections.str} processing skipped\n}
+      when /(\.ssi)$/
+        puts "\n#{@cX.fuchsia}component filetype:#{@cX.off} [ #{@opt.fns} ] - is not a processed filetype, (it may be used as a component of a .ssm markup file)\n\trequested #{@opt.selections.str} processing skipped\n"
+      else
+        puts "\n#{@cX.fuchsia}FILETYPE NOT RECOGNISED:#{@cX.off} [ #{@opt.fns} ] - is not a recognized filetype,\n\trequested #{@opt.selections.str} processing skipped\n"
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** hub_loop_markup_files.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/hub_loop_markup_files.rb"
+# <<sisu_document_header>>
+module SiSU_Hub_Loops
+  require_relative 'constants'                         # constants.rb
+  require_relative 'se'                                # se.rb
+    include SiSU_Env
+    include SiSU_Screen
+  require_relative 'hub_actions'                       # hub_actions.rb
+  require_relative 'hub_options'                       # hub_options.rb
+  require_relative 'dp'                                # dp.rb
+    include SiSU_Param
+  require_relative 'utils'                             # utils.rb
+  begin
+    require 'uri'
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('uri NOT FOUND (LoadError)')
+  end
+  class OptionLoopFiles
+    attr_reader :opt
+    def initialize(opt)
+      @opt=opt
+      @r=Px[:lng_lst_rgx]
+    end
+    def loop_files_on_given_option
+      @opt.files.each_with_index do |fno,i|
+        @opt.fno,@opt.fns=fno,fno
+        @opt.f_pth=@opt.f_pths[i]
+        if fno !~/\.-sst$/
+          @opt.pth=@opt.paths[i]
+          @opt.lng=@opt.lngs[i]
+        end
+        @@pwd=@opt.pth
+        @opt.pth=@opt.f_pths[i][:pth]
+        @opt.lng=@opt.f_pths[i][:lng]
+        Dir.chdir(@opt.f_pth[:pth]) #watch
+        SiSU_Env::FilenameLanguageCodeInsert.new(@opt,@opt.lng).language_code_insert # ... track
+        @env=SiSU_Env::InfoEnv.new(fno)
+        yield
+      end
+    end
+    def loop_files_on_given_option_bundle
+      @files_bundle={}
+      @opt.files.each_with_index do |fno,i|
+        fn_base_bundle=fno.gsub(/(?:~(?:#{@r}))?\.ss[tm]$/,'')
+        unless @files_bundle[fn_base_bundle]
+          @files_bundle[fn_base_bundle]={ status: :todo }
+        end
+      end
+      @opt.files.each_with_index do |fno,i|
+        fn_base_bundle=fno.gsub(/(?:~(?:#{@r}))?\.ss[tm]$/,'')
+        unless @files_bundle[fn_base_bundle][:status] == :done
+          @files_bundle[fn_base_bundle][:status] = :done
+          @opt.fns=fno
+          @opt.fno=fno
+          @opt.f_pth=@opt.f_pths[i]
+          if fno !~/\.-sst$/
+            @opt.pth=@opt.paths[i]
+            @opt.lng=@opt.lngs[i]
+          end
+          @@pwd=@opt.pth
+          @opt.pth=@opt.f_pths[i][:pth]
+          @opt.lng=@opt.f_pths[i][:lng]
+          Dir.chdir(@opt.f_pth[:pth]) #watch
+          @env=SiSU_Env::InfoEnv.new(fno)
+          yield
+        else next
+        end
+      end
+    end
+    def manifest_on_files_translated
+      number_of_files={}
+      @opt.files.each_with_index do |fns,i|
+        fn=fns.gsub(/(?:~(?:#{@r}))?\.ss[tm]$/,'')
+        (number_of_files[fn].is_a?(Array)) \
+        ? (number_of_files[fn] << i)
+        : (number_of_files.store(fn,[i]))
+      end
+      files_translated_idx=[]
+      number_of_files.each do |x|
+        if x[1].length > 1
+          files_translated_idx << x[1]
+        end
+      end
+      #files_translated_idx=number_of_files.select do |x|
+      #  x[1] if x[1].length > 1
+      #end
+      if files_translated_idx.flatten.length > 1
+        SiSU_Screen::Ansi.new(
+          @opt.act[:color_state][:set],
+          'Manifest re-run on (currently generated) translated files',
+          ''
+        ).grey_title_hi unless @opt.act[:quiet][:set] ==:on
+        files_translated_idx.flatten.each do |i|
+          @opt.fns=@opt.files[i]
+          @opt.f_pth=@opt.f_pths[i]
+          if @opt.fns =~/\.-sst$/
+            @opt.pth=Dir.pwd
+            @opt.lng='en'
+          elsif @opt.fno =~/\.txz$/
+            @opt.pth=@opt.f_pths[i][:pth]
+            @opt.lng=@opt.f_pths[i][:lng]
+          else
+            @opt.pth=@opt.f_pths[i][:pth]
+            @opt.lng=@opt.f_pths[i][:lng]
+          end
+          @@pwd=@opt.pth
+          Dir.chdir(@opt.pth) #watch
+          @env=SiSU_Env::InfoEnv.new(@opt.fns)
+          yield
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    hub
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/i18n.org b/org/i18n.org
new file mode 100644
index 00000000..0aea09d6
--- /dev/null
+++ b/org/i18n.org
@@ -0,0 +1,2453 @@
+-*- mode: org -*-
+#+TITLE:       sisu i18n
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:i18n:
+#+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
+
+* i18n
+** i18n.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/i18n.rb"
+# <<sisu_document_header>>
+module SiSU_i18n
+  @@language_table,@@language_list=nil,nil
+  class Languages
+    def language
+      def table
+        @@language_table ||= {
+          am:    { c: 'am',    n: 'Amharic',           t: 'Amharic',                     xlp: 'amharic'          },
+          bg:    { c: 'bg',    n: 'Bulgarian',         t: 'Български (Bəlgarski)',       xlp: 'bulgarian'        },
+          bn:    { c: 'bn',    n: 'Bengali',           t: 'Bengali',                     xlp: 'bengali'          },
+          br:    { c: 'br',    n: 'Breton',            t: 'Breton',                      xlp: 'breton'           },
+          ca:    { c: 'ca',    n: 'Catalan',           t: 'catalan',                     xlp: 'catalan'          },
+          cs:    { c: 'cs',    n: 'Czech',             t: 'česky',                       xlp: 'czech'            },
+          cy:    { c: 'cy',    n: 'Welsh',             t: 'Welsh',                       xlp: 'welsh'            },
+          da:    { c: 'da',    n: 'Danish',            t: 'dansk',                       xlp: 'danish'           },
+          de:    { c: 'de',    n: 'German',            t: 'Deutsch',                     xlp: 'german'           },
+          el:    { c: 'el',    n: 'Greek',             t: 'Ελληνικά (Ellinika)',         xlp: 'greek'            },
+          en:    { c: 'en',    n: 'English',           t: 'English',                     xlp: 'english'          },
+          eo:    { c: 'eo',    n: 'Esperanto',         t: 'Esperanto',                   xlp: 'esperanto'        },
+          es:    { c: 'es',    n: 'Spanish',           t: 'español',                     xlp: 'spanish'          },
+          et:    { c: 'et',    n: 'Estonian',          t: 'Estonian',                    xlp: 'estonian'         },
+          eu:    { c: 'eu',    n: 'Basque',            t: 'basque',                      xlp: 'basque'           },
+          fi:    { c: 'fi',    n: 'Finnish',           t: 'suomi',                       xlp: 'finnish'          },
+          fr:    { c: 'fr',    n: 'French',            t: 'français',                    xlp: 'french'           },
+          ga:    { c: 'ga',    n: 'Irish',             t: 'Irish',                       xlp: 'irish'            },
+          gl:    { c: 'gl',    n: 'Galician',          t: 'Galician',                    xlp: 'galician'         },
+          he:    { c: 'he',    n: 'Hebrew',            t: 'Hebrew',                      xlp: 'hebrew'           },
+          hi:    { c: 'hi',    n: 'Hindi',             t: 'Hindi',                       xlp: 'hindi'            },
+          hr:    { c: 'hr',    n: 'Croatian',          t: 'Croatian',                    xlp: 'croatian'         },
+          hy:    { c: 'hy',    n: 'Armenian',          t: 'Armenian',                    xlp: 'armenian'         },
+          ia:    { c: 'ia',    n: 'Interlingua',       t: 'Interlingua',                 xlp: 'interlingua'      },
+          is:    { c: 'is',    n: 'Icelandic',         t: 'Icelandic',                   xlp: 'icelandic'        },
+          it:    { c: 'it',    n: 'Italian',           t: 'Italiano',                    xlp: 'italian'          },
+          ja:    { c: 'ja',    n: 'Japanese',          t: '日本語 (Nihongo)',            xlp: 'japanese'         },
+          ko:    { c: 'ko',    n: 'Korean',            t: 'Korean',                      xlp: 'korean'           },
+          la:    { c: 'la',    n: 'Latin',             t: 'Latin',                       xlp: 'latin'            },
+          lo:    { c: 'lo',    n: 'Lao',               t: 'Lao',                         xlp: 'lao'              },
+          lt:    { c: 'lt',    n: 'Lithuanian',        t: 'Lithuanian',                  xlp: 'lithuanian'       },
+          lv:    { c: 'lv',    n: 'Latvian',           t: 'Latvian',                     xlp: 'latvian'          },
+          ml:    { c: 'ml',    n: 'Malayalam',         t: 'Malayalam',                   xlp: 'malayalam'        },
+          mr:    { c: 'mr',    n: 'Marathi',           t: 'Marathi',                     xlp: 'marathi'          },
+          nl:    { c: 'nl',    n: 'Dutch',             t: 'Nederlands',                  xlp: 'dutch'            },
+          no:    { c: 'no',    n: 'Norwegian',         t: 'norsk',                       xlp: 'norsk'            },
+          nn:    { c: 'nn',    n: 'Norwegian Nynorsk', t: 'nynorsk',                     xlp: 'nynorsk'          },
+          oc:    { c: 'oc',    n: 'Occitan',           t: 'Occitan',                     xlp: 'occitan'          },
+          pl:    { c: 'pl',    n: 'Polish',            t: 'polski',                      xlp: 'polish'           },
+          pt:    { c: 'pt',    n: 'Portuguese',        t: 'Português',                   xlp: 'portuges'         },
+          pt_BR: { c: 'pt_BR', n: 'Portuguese Brazil', t: 'Brazilian Português',         xlp: 'brazilian'        },
+          ro:    { c: 'ro',    n: 'Romanian',          t: 'română',                      xlp: 'romanian'         },
+          ru:    { c: 'ru',    n: 'Russian',           t: 'Русский (Russkij)',           xlp: 'russian'          },
+          sa:    { c: 'sa',    n: 'Sanskrit',          t: 'Sanskrit',                    xlp: 'sanskrit'         },
+          se:    { c: 'se',    n: 'Sami',              t: 'Samin',                       xlp: 'samin'            },
+          sk:    { c: 'sk',    n: 'Slovak',            t: 'slovensky',                   xlp: 'slovak'           },
+          sl:    { c: 'sl',    n: 'Slovenian',         t: 'Slovenian',                   xlp: 'slovenian'        },
+          sq:    { c: 'sq',    n: 'Albanian',          t: 'Albanian',                    xlp: 'albanian'         },
+          sr:    { c: 'sr',    n: 'Serbian',           t: 'Serbian',                     xlp: 'serbian'          },
+          sv:    { c: 'sv',    n: 'Swedish',           t: 'svenska',                     xlp: 'swedish'          },
+          ta:    { c: 'ta',    n: 'Tamil',             t: 'Tamil',                       xlp: 'tamil'            },
+          te:    { c: 'te',    n: 'Telugu',            t: 'Telugu',                      xlp: 'telugu'           },
+          th:    { c: 'th',    n: 'Thai',              t: 'Thai',                        xlp: 'thai'             },
+          tk:    { c: 'tk',    n: 'Turkmen',           t: 'Turkmen',                     xlp: 'turkmen'          },
+          tr:    { c: 'tr',    n: 'Turkish',           t: 'Türkçe',                      xlp: 'turkish'          },
+          uk:    { c: 'uk',    n: 'Ukranian',          t: 'українська (ukrajins\'ka)',   xlp: 'ukrainian'        },
+          ur:    { c: 'ur',    n: 'Urdu',              t: 'Urdu',                        xlp: 'urdu'             },
+          us:    { c: 'en',    n: 'English (American)',t: 'English',                     xlp: 'english'          },
+          vi:    { c: 'vi',    n: 'Vietnamese',        t: 'Vietnamese',                  xlp: 'vietnamese'       },
+          zh:    { c: 'zh',    n: 'Chinese',           t: '中文',                        xlp: 'chinese'          },
+          en:    { c: 'en',    n: 'English',           t: 'English',                     xlp: 'english'          },
+          xx:    { c: 'xx',    n: 'Default',           t: 'English',                     xlp: 'english'          },
+        }
+      end
+      def list
+        @@language_list ||= {
+          'am'    => table[:am],
+          'bg'    => table[:bg],
+          'bn'    => table[:bn],
+          'br'    => table[:br],
+          'ca'    => table[:ca],
+          'cs'    => table[:cs],
+          'cy'    => table[:cy],
+          'da'    => table[:da],
+          'de'    => table[:de],
+          'el'    => table[:el],
+          'en'    => table[:en],
+          'eo'    => table[:eo],
+          'es'    => table[:es],
+          'et'    => table[:et],
+          'eu'    => table[:eu],
+          'fi'    => table[:fi],
+          'fr'    => table[:fr],
+          'ga'    => table[:ga],
+          'gl'    => table[:gl],
+          'he'    => table[:he],
+          'hi'    => table[:hi],
+          'hr'    => table[:hr],
+          'hy'    => table[:hy],
+          'ia'    => table[:ia],
+          'is'    => table[:is],
+          'it'    => table[:it],
+          'ja'    => table[:ja],
+          'ko'    => table[:ko],
+          'la'    => table[:la],
+          'lo'    => table[:lo],
+          'lt'    => table[:lt],
+          'lv'    => table[:lv],
+          'ml'    => table[:ml],
+          'mr'    => table[:mr],
+          'nl'    => table[:nl],
+          'no'    => table[:no],
+          'nn'    => table[:nn],
+          'oc'    => table[:oc],
+          'pl'    => table[:pl],
+          'pt'    => table[:pt],
+          'pt_BR' => table[:pt_BR],
+          'ro'    => table[:ro],
+          'ru'    => table[:ru],
+          'sa'    => table[:sa],
+          'se'    => table[:se],
+          'sk'    => table[:sk],
+          'sl'    => table[:sl],
+          'sq'    => table[:sq],
+          'sr'    => table[:sr],
+          'sv'    => table[:sv],
+          'ta'    => table[:ta],
+          'te'    => table[:te],
+          'th'    => table[:th],
+          'tk'    => table[:tk],
+          'tr'    => table[:tr],
+          'uk'    => table[:uk],
+          'ur'    => table[:ur],
+          'us'    => table[:en],
+          'vi'    => table[:vi],
+          'zh'    => table[:zh],
+          'en'    => table[:en],
+          'xx'    => table[:en]
+        }
+      end
+      self
+    end
+  end
+  class Alphabet
+    def initialize(lng_code)
+      @lng_code=lng_code
+    end
+    def hash_arrays
+      @alph=case @lng_code
+      when /en/                                                              #english
+        {
+          u: %w[A B C D E F G H I J K L M N O P Q R S T U V W X Y Z],
+          l: %w[a b c d e f g h i j k l m n o p q r s t u v w x y z]
+        }
+      when /da|no|nn/                                                        #danish, norwegian
+        {
+          u: %w[A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Å Æ Ø],
+          l: %w[a b c d e f g h i j k l m n o p q r s t u v w x y z å æ ø]
+          #u: %W[A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Æ Ø Å],
+          #l: %w[a b c d e f g h i j k l m n o p q r s t u v w x y z æ ø å]
+        }
+      when /sv/                                                              #swedish
+        {
+          u: %w[A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Å Ä Ö],
+          l: %w[a b c d e f g h i j k l m n o p q r s t u v w x y z å ä ö]
+        }
+      else                                                                   #english default
+        {
+          u: %w[A B C D E F G H I J K L M N O P Q R S T U V W X Y Z],
+          l: %w[a b c d e f g h i j k l m n o p q r s t u v w x y z]
+        }
+      end
+    end
+    def hash_strings
+      { u: hash_arrays[:u].join, l: hash_arrays[:l].join }
+    end
+  end
+end
+__END__
+Language Lists
+,* po4a c:
+  <http://www.debian.org/international/l10n/po/>
+  Px[:lng_lst] see constants.rb
+,* polyglossia xlp:
+  <http://mirrors.ctan.org/macros/xetex/latex/polyglossia/polyglossia.pdf>
+  missing from (:c) list:
+    arabic asturian bahasai bahasam coptic divehi farsi lsorbian magyar scottish syriac usorbian
+note ISO_639-1
+  <http://en.wikipedia.org/wiki/ISO_639-1>
+  <http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes>
+also note ISO_639-2
+  <http://en.wikipedia.org/wiki/ISO_639-2>
+  <http://en.wikipedia.org/wiki/List_of_ISO_639-2_codes>
+
+Px[:lng_lst] # constants.rb
+
+module SiSU_TextTranslation
+  class Language
+    def initialize(md)
+      @md=md
+    end
+    def tex_name(char)
+      @lang=if char
+        case char
+        when 'sq'    then 'albanian'
+        when 'am'    then 'amharic'
+       #when 'ar'    then 'arabic'         # see polyglossia
+        when 'hy'    then 'armenian'
+       #when ''      then 'asturian'       # polyglossia
+       #when ''      then 'bahasai'        # polyglossia
+       #when ''      then 'bahasam'        # polyglossia
+        when 'eu'    then 'basque'
+        when 'bn'    then 'bengali'
+        when 'pt_BR' then 'brazilian'
+        when 'br'    then 'breton'
+        when 'bg'    then 'bulgarian'
+        when 'ca'    then 'catalan'        # see polyglossia
+       #when ''      then 'coptic'         # polyglossia
+        when 'hr'    then 'croatian'
+        when 'cs'    then 'czech'
+        when 'da'    then 'danish'
+       #when ''      then 'divehi'         # polyglossia
+        when 'nl'    then 'dutch'          # see polyglossia
+        when 'en'    then 'english'        # see polyglossia
+        when 'eo'    then 'esperanto'      # see polyglossia
+        when 'et'    then 'estonian'
+        when 'gl'    then 'galician'
+        when 'de'    then 'german'
+        when 'el'    then 'greek'          #gl ?
+        when 'he'    then 'hebrew'
+        when 'hi'    then 'hindi'
+        when 'is'    then 'icelandic'
+        when 'ia'    then 'interlingua'
+        when 'ga'    then 'irish'
+        when 'it'    then 'italian'
+       #when ''      then 'farsi'          # polyglossia
+        when 'fi'    then 'finnish'
+        when 'fr'    then 'french'
+        when 'lo'    then 'lao'
+        when 'la'    then 'latin'
+        when 'lv'    then 'latvian'
+        when 'lt'    then 'lithuanian'
+       #when ''      then 'lsorbian'       # polyglossia
+       #when ''      then 'magyar'         # polyglossia
+        when 'ml'    then 'malayalam'
+        when 'mr'    then 'marathi'
+       #when 'hu'    then 'magyar'
+        when 'no'    then 'norske'
+        when 'nn'    then 'nynorsk'
+        when 'oc'    then 'occitan'
+        when 'pl'    then 'polish'
+        when 'pt'    then 'portuges'
+        when 'ro'    then 'romanian'
+        when 'ru'    then 'russian'
+        when 'se'    then 'samin'          #(check sami?)
+        when 'sa'    then 'sanskrit'
+        when 'sr'    then 'serbian'
+       #when ''      then 'scottish'       # polyglossia  (gd (Gaelic (Scots)))
+        when 'sk'    then 'slovak'
+        when 'sl'    then 'slovenian'
+        when 'es'    then 'spanish'
+        when 'sv'    then 'swedish'
+        when 'ta'    then 'tamil'
+        when 'te'    then 'telugu'
+        when 'th'    then 'thai'
+        when 'tr'    then 'turkish'
+        when 'tk'    then 'turkmen'
+        when 'uk'    then 'ukrainian'
+        when 'ur'    then 'urdu'
+       #when ''      then 'usorbian'       # polyglossia
+        when 'vi'    then 'vietnamese'
+        when 'cy'    then 'welsh'
+        when 'us'    then 'USenglish'      # depreciated, see iso-639-2
+        else         then 'english'
+        end
+      else            'english'
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* prog_text_translation.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/prog_text_translation.rb"
+# <<sisu_document_header>>
+module SiSU_Translate
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env; include SiSU_Param
+  class Source
+    def initialize(md,doc_lang,trans_str='')
+      @md,@doc_lang,@trans_str=md,doc_lang,trans_str
+      @lang_class=case @doc_lang
+      when /American/i       then English.new(md,doc_lang,trans_str)    # tag depreciated, see iso 639-2
+      when /English/i        then English.new(md,doc_lang,trans_str)
+      when /French/i         then French.new(md,doc_lang,trans_str)
+      when /German/i         then German.new(md,doc_lang,trans_str)
+      when /Italian/i        then Italian.new(md,doc_lang,trans_str)
+      when /Spanish/i        then Spanish.new(md,doc_lang,trans_str)
+      when /Portuguese Brazil|Brazilian(?: Portuguese)?/i
+                                  Portuguese.new(md,doc_lang,trans_str) # tag depreciated, see iso 639-2
+      when /Portuguese/i     then Portuguese.new(md,doc_lang,trans_str)
+      when /Swedish/i        then Swedish.new(md,doc_lang,trans_str)
+      when /Danish/i         then Danish.new(md,doc_lang,trans_str)
+      when /Finnish/i        then Finnish.new(md,doc_lang,trans_str)
+      when /Norwegian/i      then Norwegian.new(md,doc_lang,trans_str)
+      when /Icelandic/i      then Icelandic.new(md,doc_lang,trans_str)
+      when /Dutch/i          then Dutch.new(md,doc_lang,trans_str)
+      when /Estonian/i       then Estonian.new(md,doc_lang,trans_str)
+      when /Hungarian/i      then Hungarian.new(md,doc_lang,trans_str)
+      when /Polish/i         then Polish.new(md,doc_lang,trans_str)
+      when /Romanian/i       then Romanian.new(md,doc_lang,trans_str)
+      when /Russian/i        then Russian.new(md,doc_lang,trans_str)
+      when /Greek/i          then Greek.new(md,doc_lang,trans_str)
+      when /Ukranian/i       then Ukranian.new(md,doc_lang,trans_str)
+      when /Turkish/i        then Turkish.new(md,doc_lang,trans_str)
+      when /Slovenian/i      then Slovenian.new(md,doc_lang,trans_str)
+      when /Croatian/i       then Croatian.new(md,doc_lang,trans_str)
+      when /Slovak(?:ian)?/i then Slovak.new(md,doc_lang,trans_str)
+      when /Czech/i          then Czech.new(md,doc_lang,trans_str)
+      when /Bulgarian/i      then Bulgarian.new(md,doc_lang,trans_str)
+      else                        English.new(md,doc_lang,trans_str)
+      end
+    end
+    def filename
+      @lang_class.filename
+    end
+    def metadata
+      @lang_class.metadata
+    end
+    def filetype_description
+      @lang_class.filetype_description
+    end
+    def file_size
+      @lang_class.file_size
+    end
+    def sourcefile
+      @lang_class.sourcefile
+    end
+    def sourcefile_digest
+      @lang_class.sourcefile_digest
+    end
+    def full_title #dc
+      @lang_class.full_title
+    end
+    def title
+      @lang_class.title
+    end
+    def subtitle
+      @lang_class.subtitle
+    end
+    def author
+      @lang_class.author
+    end
+    def contributor
+      @lang_class.contributor
+    end
+    def translator
+      @lang_class.translator
+    end
+    def illustrator
+      @lang_class.illustrator
+    end
+    def publisher
+      @lang_class.publisher
+    end
+    def prepared_by
+      @lang_class.prepared_by
+    end
+    def digitized_by
+      @lang_class.digitized_by
+    end
+    def contents
+      @lang_class.contents
+    end
+    def subject
+      @lang_class.subject
+    end
+    def description #dc (watch)
+      @lang_class.description
+    end
+    def abstract
+      @lang_class.abstract
+    end
+    def type
+      @lang_class.type
+    end
+    def rights
+      @lang_class.rights
+    end
+    def date
+      @lang_class.date
+    end
+    def date_created
+      @lang_class.date_created
+    end
+    def date_available
+      @lang_class.date_available
+    end
+    def date_valid
+      @lang_class.date_valid
+    end
+    def date_modified
+      @lang_class.date_modified
+    end
+    def date_issued
+      @lang_class.date_issued
+    end
+    def language
+      @lang_class.language
+    end
+    def language_original
+      @lang_class.language_original
+    end
+    def format
+      @lang_class.format
+    end
+    def identifier
+      @lang_class.identifier
+    end
+    def source
+      @lang_class.source
+    end
+    def relation
+      @lang_class.relation
+    end
+    def coverage
+      @lang_class.coverage
+    end
+    def keywords
+      @lang_class.keywords
+    end
+    def comments
+      @lang_class.comments
+    end
+    def cls_loc
+      @lang_class.cls_loc
+    end
+    def cls_dewey
+      @lang_class.cls_dewey
+    end
+    def cls_oclc
+      @lang_class.cls_oclc
+    end
+    def cls_gutenberg
+      @lang_class.cls_gutenberg
+    end
+    def cls_isbn
+      @lang_class.cls_isbn
+    end
+    def prefix_a
+      @lang_class.prefix_a
+    end
+    def prefix_b
+      @lang_class.prefix_b
+    end
+    def topic_register
+      @lang_class.topic_register
+    end
+    def fns
+      @lang_class.fns
+    end
+    def word_count
+      @lang_class.word_count
+    end
+    def dgst
+      @lang_class.dgst
+    end
+    def sc_number
+      @lang_class.sc_number
+    end
+    def sc_date
+      @lang_class.sc_date
+    end
+    def last_generated
+      @lang_class.last_generated
+    end
+    def sisu_version
+      @lang_class.sisu_version
+    end
+    def ruby_version
+      @lang_class.ruby_version
+    end
+    def suggested_links
+      @lang_class.suggested_links
+    end
+    def language_version_list
+      @lang_class.language_version_list
+    end
+    def language
+      @lang_class.language
+    end
+    def manifest_description
+      @lang_class.manifest_description
+    end
+    def manifest_description_output
+      @lang_class.manifest_description_output
+    end
+    def manifest_description_metadata
+      @lang_class.manifest_description_metadata
+    end
+    def language_list_translated
+      @lang_class.language_list
+    end
+    def language_list
+      case @trans_str
+      when /American/i       then 'American English'                    # tag depreciated, see iso 639-2
+      when /English/i        then 'English'
+      when /French/i         then 'français'
+      when /German/i         then 'Deutsch'
+      when /Italian/i        then 'Italiano'
+      when /Spanish/i        then 'español'
+      when /Portuguese Brazil|Brazilian(?: Portuguese)?/i
+                                  'Brazilian Português'                 # tag depreciated, see iso 639-2
+      when /Portuguese/i     then 'Português'
+      when /Swedish/i        then 'svenska'
+      when /Danish/i         then 'dansk'
+      when /Finnish/i        then 'suomi'
+      when /Norwegian/i      then 'norsk'
+      when /Icelandic/i      then 'Icelandic'
+      when /Dutch/i          then 'Nederlands'
+      when /Estonian/i       then 'Estonian'
+      when /Hungarian/i      then 'Hungarian'
+      when /Polish/i         then 'polski'
+      when /Romanian/i       then 'română'
+      when /Russian/i        then 'Русский (Russkij)'
+      when /Greek/i          then 'Ελληνικά (Ellinika)'
+      when /Ukranian/i       then 'українська (ukrajins\'ka)'
+      when /Turkish/i        then 'Türkçe'
+      when /Slovenian/i      then 'Slovenian'
+      when /Croatian/i       then 'Croatian'
+      when /Slovak(?:ian)?/i then 'slovensky'            #slovensky ?
+      when /Czech/i          then 'česky'
+      when /Bulgarian/i      then 'Български (Bəlgarski)'
+      when /Japanese/i       then '日本語 (Nihongo)'
+      when /Korean/i         then '한국어 (Hangul)'
+     #when /Catalan/i        then 'català'
+      else                         'English'
+      end
+      #check on 中文  and عربي
+    end
+  end
+  <<language_english>>
+  <<language_french>>
+  <<language_german>>
+  <<language_spanish>>
+  <<language_italian>>
+  <<language_finnish>>
+  <<language_protuguese>>
+  <<language_swedish>>
+  <<language_remaining>>
+end
+__END__
+#+END_SRC
+
+* translations
+** English
+
+#+NAME: language_english
+#+BEGIN_SRC  ruby
+class English
+  def initialize(md,doc_lang,trans_str)
+    @md,@doc_lang,@trans_str=md,doc_lang,trans_str
+  end
+  def filename
+    'filename'
+  end
+  def filetype_description
+    'filetype description'
+  end
+  def metadata
+    'metadata'
+  end
+  def file_size
+    'file size'
+  end
+  def full_title #dc
+    'Title'
+  end
+  def title
+    'Title'
+  end
+  def subtitle
+    'Subtitle'
+  end
+  def author
+    'Author'
+  end
+  def creator #dc
+    'Creator'
+  end
+  def contributor #dc
+    'Contributor'
+  end
+  def translator
+    'Translator'
+  end
+  def illustrator
+    'Illustrator'
+  end
+  def publisher #dc
+    'Publisher'
+  end
+  def prepared_by
+    'Prepared by'
+  end
+  def digitized_by
+    'Digitized by'
+  end
+  def contents
+    'Contents'
+  end
+  def subject #dc
+    'Subject'
+  end
+  def description #dc (watch)
+    'Description'
+  end
+  def abstract #dc
+    'Abstract'
+  end
+  def type #dc
+    'Type'
+  end
+  def rights #dc
+    'Rights'
+  end
+  def date #dc
+    'Date'
+  end
+  def date_created #dc
+    'Date created'
+  end
+  def date_issued #dc
+    'Date issued'
+  end
+  def date_available #dc
+    'Date available'
+  end
+  def date_modified #dc
+    'Date modified'
+  end
+  def date_valid #dc
+    'Date valid'
+  end
+  def language #dc
+    'Language'
+  end
+  def language_original
+    'Original Language'
+  end
+  def format #dc
+    'Format'
+  end
+  def identifier #dc
+    'Identifier'
+  end
+  def source #dc
+    'Source'
+  end
+  def relation #dc
+    'Relation'
+  end
+  def coverage #dc
+    'Coverage'
+  end
+  def keywords
+    'Keywords'
+  end
+  def comments
+    'Comments'
+  end
+  def cls_loc
+    'Classify Library of Congress'
+  end
+  def cls_dewey
+    'Classify Dewey'
+  end
+  def cls_oclc
+    'Classify OCLC number'
+  end
+  def cls_gutenberg
+    'Classify Project Gutenberg'
+  end
+  def cls_isbn
+    'Classify ISBN'
+  end
+  def prefix_a
+    'Prefix (a)'
+  end
+  def prefix_b
+    'Prefix (b)'
+  end
+  def topic_register
+    'Topics Registered'
+  end
+  def sourcefile
+    'Sourcefile'
+  end
+  def word_count
+    'Word Count approximate'
+  end
+  def sourcefile_digest
+    'Sourcefile Digest'
+  end
+  def digest_md5
+    'Sourcefile Digest (md5)'
+  end
+  def digest_sha256
+    'Sourcefile Digest (sha256)'
+  end
+  def sc_number
+    'Document (RCS/CVS) number'
+  end
+  def sc_date
+    'Document (RCS/CVS) number'
+  end
+  def last_generated
+    'Document (ao) last generated'
+  end
+  def sisu_version
+    'Generated by'
+  end
+  def ruby_version
+    'Ruby version'
+  end
+  def suggested_links
+    'metadata suggested links'
+  end
+  def language_version_list
+    'Document Language Versions, manifests'
+  end
+  def manifest_description
+    'SiSU manifest of document filetypes and metadata'
+  end
+  def manifest_description_output
+    'Available document filetypes'
+  end
+  def manifest_description_metadata
+    'Document Metadata'
+  end
+  def language_list_translated
+    case @trans_str
+    when /American/i       then 'American English'                    # tag depreciated, see iso 639-2
+    when /English/i        then 'English'
+    when /French/i         then 'French'
+    when /German/i         then 'German'
+    when /Italian/i        then 'Italian'
+    when /Spanish/i        then 'Spanish'
+    when /Portuguese Brazil|Brazilian(?: Portuguese)?/i
+                                'Brazilian Portuguese'                # tag depreciated, see iso 639-2
+    when /Portuguese/i     then 'Portuguese'
+    when /Swedish/i        then 'Swedish'
+    when /Danish/i         then 'Danish'
+    when /Finnish/i        then 'Finnish'
+    when /Norwegian/i      then 'Norwegian'
+    when /Icelandic/i      then 'Icelandic'
+    when /Dutch/i          then 'Dutch'
+    when /Estonian/i       then 'Estonian'
+    when /Hungarian/i      then 'Hungarian'
+    when /Polish/i         then 'Polish'
+    when /Romanian/i       then 'Romanian'
+    when /Russian/i        then 'Russian'
+    when /Greek/i          then 'Greek'
+    when /Ukranian/i       then 'Ukranian'
+    when /Turkish/i        then 'Turkish'
+    when /Slovenian/i      then 'Slovenian'
+    when /Croatian/i       then 'Croatian'
+    when /Slovak(?:ian)?/i then 'Slovakian'
+    when /Czech/i          then 'Czech'
+    when /Bulgarian/i      then 'Bulgarian'
+    else @trans_str
+    end
+  end
+end
+#+END_SRC
+
+** French
+
+#+NAME: language_french
+#+BEGIN_SRC text
+class French
+  def initialize(md,doc_lang,trans_str)
+    @md,@doc_lang,@trans_str=md,doc_lang,trans_str
+  end
+  def filename
+    'nom de fichier'
+  end
+  def filetype_description
+    description
+  end
+  def metadata
+    'metadonnées'
+  end
+  def file_size
+    'taille'
+  end
+  def full_title #dc
+    'Titre'
+  end
+  def title
+    'Titre'
+  end
+  def subtitle
+    'Sous titre'
+  end
+  def author
+    'Auteur'
+  end
+  def author #dc
+    'Auteur'
+  end
+  def contributor #dc
+    'Contributeur'
+  end
+  def translator
+    'Traducteur'
+  end
+  def illustrator
+    'Illustrateur'
+  end
+  def publisher #dc
+    'Éditeur'
+  end
+  def prepared_by
+    'Préparé par'
+  end
+  def digitized_by
+    'Numérisé par'
+  end
+  def contents
+    'Contents' #translate
+  end
+  def subject #dc
+    'Sujet'
+  end
+  def description #dc (watch)
+    'Description'
+  end
+  def abstract #dc
+    'Résumé'
+  end
+  def type #dc
+    'Type'
+  end
+  def rights #dc
+    'Droits relatifs à la ressource'
+  end
+  def date #dc
+    'Date'
+  end
+  def date_created #dc
+    'Date de création'
+  end
+  def date_issued #dc
+    'Date de publication'
+  end
+  def date_available #dc
+    'Date de mise à disposition'
+  end
+  def date_modified #dc
+    'Date de modification'
+  end
+  def date_valid #dc
+    'Date de validité'
+  end
+  def language #dc
+    'Langue'
+  end
+  def language_original
+    'Langue originale'
+  end
+  def format #dc
+    'Format'
+  end
+  def identifier #dc
+    'Identifiant'
+  end
+  def source #dc
+    'Source'
+  end
+  def relation #dc
+    'Lien'
+  end
+  def coverage #dc
+    'Portée du document'
+  end
+  def keywords
+    'Mots clef'
+  end
+  def comments
+    'Commentaires'
+  end
+  def cls_loc
+    'Classification de la bibliothèque du congres'
+  end
+  def cls_dewey
+    'Classification Dewey'
+  end
+  def cls_oclc # fix
+    'Classify OCLC number'
+  end
+  def cls_gutenberg
+    'Classification du project Gutenberg'
+  end
+  def cls_isbn
+    'Classification ISBN'
+  end
+  def prefix_a
+    'Préfixe (a)'
+  end
+  def prefix_b
+    'Préfixe (b)'
+  end
+  def topic_register
+    'Topics Registered'
+  end
+  def sourcefile
+    'Fichier source'
+  end
+  def word_count
+    'Nombre approximatif de mots'
+  end
+  def sourcefile_digest
+    'Condensé du fichier source'
+  end
+  def digest_md5
+    'Condensé du fichier source (md5)'
+  end
+  def digest_sha256
+    'Condensé du fichier source (sha256)'
+  end
+  def sc_number
+    'Numéro (RCS/CVS) du document'
+  end
+  def sc_date
+    'Numéro (RCS/CVS) du document'
+  end
+  def last_generated
+    'Dernière production du document (metaverse)'
+  end
+  def sisu_version
+    'Généré par'
+  end
+  def ruby_version
+    'Version de Ruby'
+  end
+  def suggested_links
+    'Liens suggérés'
+  end
+  def language_version_list
+    'Versions des langues du document, manifestes'
+  end
+  def manifest_description
+    'SiSU manifest of document filetypes and metadata'
+  end
+  def manifest_description_output
+    'Manifeste SiSU du document généré'
+  end
+  def manifest_description_metadata
+    'Manifeste SiSU des métadonnées du document'
+  end
+  def language_list_translated
+    case @trans_str
+    when /American/i       then 'Anglais americain'                   # tag depreciated, see iso 639-2
+    when /English/i        then 'Anglais'
+    when /French/i         then 'Français'
+    when /German/i         then 'Allemand'
+    when /Italian/i        then 'Italien'
+    when /Spanish/i        then 'Espagnol'
+    when /Portuguese Brazil|Brazilian(?: Portuguese)?/i
+                                'Portugais brésilien'                 # tag depreciated, see iso 639-2
+    when /Portuguese/i     then 'Portugais'
+    when /Swedish/i        then 'Suédois'
+    when /Danish/i         then 'Danois'
+    when /Finnish/i        then 'Finnois'
+    when /Norwegian/i      then 'Norvégien'
+    when /Icelandic/i      then 'Islandais'
+    when /Dutch/i          then 'Néerlandais'
+    when /Estonian/i       then 'Estonien'
+    when /Hungarian/i      then 'Hongrois'
+    when /Polish/i         then 'Polonais'
+    when /Romanian/i       then 'Roumain'
+    when /Russian/i        then 'Russe'
+    when /Greek/i          then 'Grec'
+    when /Ukranian/i       then 'Ukrainien'
+    when /Turkish/i        then 'Turc'
+    when /Slovenian/i      then 'Slovène'
+    when /Croatian/i       then 'Croate'
+    when /Slovak(?:ian)?/i then 'Slovaque'
+    when /Czech/i          then 'Tcheque'
+    when /Bulgarian/i      then 'Bulgare'
+    else @trans_str
+    end
+  end
+end
+#+END_SRC
+
+** German
+
+#+NAME: language_german
+#+BEGIN_SRC text
+class German
+  def initialize(md,doc_lang,trans_str)
+    @md,@doc_lang,@trans_str=md,doc_lang,trans_str
+  end
+  def filename
+    'Dateiname'
+  end
+  def filetype_description
+    description
+  end
+  def metadata
+    'Metadata'
+  end
+  def file_size
+    'Dateigrösse'
+  end
+  def full_title #dc
+    'Titel'
+  end
+  def title
+    'Titel'
+  end
+  def subtitle
+    'Untertitel'
+  end
+  def author
+    'Autor'
+  end
+  def contributor #dc
+    'Mitautor'
+  end
+  def translator
+    'Übersetzung'
+  end
+  def illustrator
+    'Illustrator'
+  end
+  def publisher
+    'Herausgeber'
+  end
+  def prepared_by
+    'gesetzt von'
+  end
+  def digitized_by
+    'digitalisiert von'
+  end
+  def contents
+    'Contents' #translate
+  end
+  def subject
+    'Titel'
+  end
+  def description #dc (watch)
+    'Beschreibung'
+  end
+  def abstract #dc
+    'Abstract'
+  end
+  def type
+    'Typ'
+  end
+  def rights
+    'Rechte'
+  end
+  def date
+    'Datum'
+  end
+  def date_created
+    'Erstellung'
+  end
+  def date_issued
+    'Herausgabe'
+  end
+  def date_available
+    'Veröffentlichung'
+  end
+  def date_modified
+    'Modifikation'
+  end
+  def date_valid
+    'Gültigkeit'
+  end
+  def language
+    'Sprache'
+  end
+  def language_original
+    'Ursprungssprache'
+  end
+  def format #dc
+    'Format'
+  end
+  def identifier #dc
+    'Bezeichnung'
+  end
+  def source #dc
+    'Quelle'
+  end
+  def relation #dc
+    'Beziehung'
+  end
+  def coverage #dc
+    'Eingrenzung'
+  end
+  def keywords
+    'Schlüsselwörter'
+  end
+  def comments
+    'Kommentare'
+  end
+  def cls_loc
+    'Klassifikation nach Library of Congress'
+  end
+  def cls_dewey
+    'Klassifikation nach Dewey'
+  end
+  def cls_oclc # fix
+    'Classify OCLC number'
+  end
+  def cls_gutenberg
+    'Klassifikation nach Projekt Gutenberg'
+  end
+  def cls_isbn
+    'Klassifikation nach ISBN'
+  end
+  def prefix_a
+    'Präfix (a)'
+  end
+  def prefix_b
+    'Präfix (b)'
+  end
+  def topic_register
+    'Topics Registered'
+  end
+  def sourcefile
+    'Quelldatei'
+  end
+  def word_count
+    'Anzahl Wörter'
+  end
+  def sourcefile_digest
+    'Quelldatei Digest'
+  end
+  def digest_md5
+    'Prüfsumme der Quelldatei (MD5)'
+  end
+  def digest_sha256
+    'Prüfsumme der Quelldatei (SHA256)'
+  end
+  def sc_number
+    'Dokumentversion (RCS/CVS)'
+  end
+  def sc_date
+    'Dokumentdatum (RCS/CVS)'
+  end
+  def last_generated
+    'Letzte Erstellung (metaverse)'
+  end
+  def sisu_version
+    'erstellt bei'
+  end
+  def ruby_version
+    'Ruby Version'
+  end
+  def suggested_links
+    'empfohlene Links'
+  end
+  def language_version_list
+    'verfügbare Sprachen'
+  end
+  def manifest_description
+    'SiSU manifest of document filetypes and metadata'
+  end
+  def manifest_description_output
+    'SiSU Zusammenfassung des Dokumentes'
+  end
+  def manifest_description_metadata
+    'SiSU Zusammenfassung der Metadaten'
+  end
+  def language_list_translated
+    case @trans_str
+    when /American/i       then 'Amerikanisch-Englisch'               # tag depreciated, see iso 639-2
+    when /English/i        then 'Englisch'
+    when /French/i         then 'Französisch'
+    when /German/i         then 'Deutsch'
+    when /Italian/i        then 'Italienisch'
+    when /Spanish/i        then 'Spanisch'
+    when /Portuguese Brazil|Brazilian(?: Portuguese)?/i
+                                'Brasilianisch-Portugiesisch'         # tag depreciated, see iso 639-2
+    when /Portuguese/i     then 'Portugiesisch'
+    when /Swedish/i        then 'Schwedisch'
+    when /Danish/i         then 'Dänisch'
+    when /Finnish/i        then 'Finnisch'
+    when /Norwegian/i      then 'Norwegisch'
+    when /Icelandic/i      then 'Isländisch'
+    when /Dutch/i          then 'Niederländisch'
+    when /Estonian/i       then 'Estnisch'
+    when /Hungarian/i      then 'Ungarisch'
+    when /Polish/i         then 'Polnisch'
+    when /Romanian/i       then 'Rumänisch'
+    when /Russian/i        then 'Russisch'
+    when /Greek/i          then 'Griechisch'
+    when /Ukranian/i       then 'Ukrainisch'
+    when /Turkish/i        then 'Türkisch'
+    when /Slovenian/i      then 'Slovenisch'
+    when /Croatian/i       then 'Kroatisch'
+    when /Slovak(?:ian)?/i then 'Slovakisch'
+    when /Czech/i          then 'Tschechisch'
+    when /Bulgarian/i      then 'Bulgarisch'
+    else @trans_str
+    end
+  end
+end
+#+END_SRC
+
+** Spanish
+
+#+NAME: language_spanish
+#+BEGIN_SRC text
+class Spanish
+  def initialize(md,doc_lang,trans_str)
+    @md,@doc_lang,@trans_str=md,doc_lang,trans_str
+  end
+  def filename
+   'nombre del fichero'
+  end
+  def filetype_description
+    description
+  end
+  def metadata
+    'metadatos'
+  end
+  def file_size
+    'tamaño del fichero'
+  end
+  def full_title #dc
+    'Título'
+  end
+  def title
+    'Título'
+  end
+  def subtitle
+    'Subtítulo'
+  end
+  def author #dc
+    'Creador'
+  end
+  def contributor #dc
+    'Contribuidor'
+  end
+  def translator
+    'Traductor'
+  end
+  def illustrator
+    'Ilustrador'
+  end
+  def publisher #dc
+    'Editor'
+  end
+  def prepared_by
+    'Preparado por'
+  end
+  def digitized_by
+    'Digitalizado por'
+  end
+  def contents
+    'Contents' #translate
+  end
+  def subject #dc
+    'Asunto'
+  end
+  def description #dc (watch)
+    'Descripción'
+  end
+  def abstract #dc
+    'Resumen'
+  end
+  def type #dc
+    'Tipo'
+  end
+  def rights #dc
+    'Derechos'
+  end
+  def date #dc
+    'Fecha'
+  end
+  def date_created #dc
+    'Fecha de creación'
+  end
+  def date_issued #dc
+    'Fecha de publicación'
+  end
+  def date_available #dc
+    'Fecha de disponibilidad'
+  end
+  def date_modified #dc
+    'Fecha de modificación'
+  end
+  def date_valid #dc
+    'Fecha de valided'
+  end
+  def language #dc
+    'Idioma'
+  end
+  def language_original
+    'Lenguaje original'
+  end
+  def format #dc
+    'Formato'
+  end
+  def identifier #dc
+    'Identificador'
+  end
+  def source #dc
+    'Fuente'
+  end
+  def relation #dc
+    'Relación'
+  end
+  def coverage #dc
+    'Cobertura'
+  end
+  def keywords
+    'Palabras claves'
+  end
+  def comments
+    'Comentarios'
+  end
+  def cls_loc
+    'Clasificación Biblioteca del Congreso'
+  end
+  def cls_dewey
+    'Clasificación Dewey'
+  end
+   def cls_oclc # fix
+     'Classify OCLC number'
+   end
+  def cls_gutenberg
+    'Clasificación Proyecto Gutenberg'
+  end
+  def cls_isbn
+    'Clasificación ISBN'
+  end
+  def prefix_a
+    'Prefijo (a)'
+  end
+  def prefix_b
+    'Prefijo (b)'
+  end
+   def topic_register
+     'Topics Registered'
+   end
+  def sourcefile
+    'Fichero fuente'
+  end
+  def word_count
+    'Número de palabras apróximado'
+  end
+  def sourcefile_digest
+    'Resumen del fichero fuente'
+  end
+  def digest_md5
+    'Resumen del fichero fuente (md5)'
+  end
+  def digest_sha256
+    'Resumen del fichero fuente (sha256)'
+  end
+  def sc_number
+    'Versión (RCS/CVS) del documento'
+  end
+  def sc_date
+    'Versión (RCS/CVS) del documento'
+  end
+  def last_generated
+    'Última generación (metaverse) del documento'
+  end
+  def sisu_version
+    'Generado por'
+  end
+  def ruby_version
+    'Versión de Ruby'
+  end
+  def suggested_links
+    'enlaces sugeridos de metadatos'
+  end
+  def language_version_list
+    'Document Language Versions, manifests'
+  end
+   def manifest_description
+     'SiSU manifest of document filetypes and metadata'
+   end
+  def manifest_description_output
+    'Manifiesto SiSU de salida generada'
+  end
+  def manifest_description_metadata
+    'Manifiesto SiSU de metadatos de documento'
+  end
+  def language_list_translated
+    case @trans_str
+    when /American/i       then 'Inglés Americano'                     # tag depreciated, see iso 639-2
+    when /English/i        then 'Inglés'
+    when /French/i         then 'Francés'
+    when /German/i         then 'Alemán'
+    when /Italian/i        then 'Italiano'
+    when /Spanish/i        then 'Español'
+    when /Portuguese Brazil|Brazilian(?: Portuguese)?/i
+                                'Portugués de Brasil'                  # tag depreciated, see iso 639-2
+    when /Portuguese/i     then 'Portugués'
+    when /Swedish/i        then 'Sueco'
+    when /Danish/i         then 'Danés'
+    when /Finnish/i        then 'Finés'
+    when /Norwegian/i      then 'Noruego'
+    when /Icelandic/i      then 'Islandés'
+    when /Dutch/i          then 'Holandés'
+    when /Estonian/i       then 'Estonio'
+    when /Hungarian/i      then 'Húngaro'
+    when /Polish/i         then 'Polaco'
+    when /Romanian/i       then 'Rumano'
+    when /Russian/i        then 'Ruso'
+    when /Greek/i          then 'Griego'
+    when /Ukranian/i       then 'Ucraniano'
+    when /Turkish/i        then 'Turco'
+    when /Slovenian/i      then 'Eslovaco'
+    when /Croatian/i       then 'Croata'
+    when /Slovak(?:ian)?/i then 'Eslovaco'
+    when /Czech/i          then 'Checo'
+    when /Bulgarian/i      then 'Búlgaro'
+    else @trans_str
+    end
+  end
+end
+#+END_SRC
+
+** Italian
+
+#+NAME: language_italian
+#+BEGIN_SRC text
+class Italian
+  def initialize(md,doc_lang,trans_str)
+    @md,@doc_lang,@trans_str=md,doc_lang,trans_str
+  end
+  def filename
+    'nome del file'
+  end
+  def filetype_description
+    description
+  end
+  def metadata
+    'metadati'
+  end
+  def file_size
+    'dimensione'
+  end
+  def full_title #dc
+    'Titolo'
+  end
+  def title
+    'Titolo'
+  end
+  def subtitle
+    'Sottotitolo'
+  end
+  def author #dc
+    'Autore'
+  end
+  def contributor #dc
+    'Contributore'
+  end
+  def translator
+    'Traduttore'
+  end
+  def illustrator
+    'Illustratore'
+  end
+  def publisher #dc
+    'Casa editrice'
+  end
+  def prepared_by
+    'Preparato da'
+  end
+  def digitized_by
+    'Convertito in digitale da'
+  end
+  def contents
+    'Contents' #translate
+  end
+  def subject #dc
+    'Oggetto'
+  end
+  def description #dc (watch)
+    'Descrizione'
+  end
+  def abstract #dc
+    'Abstract'
+  end
+  def type #dc
+    'Tipo'
+  end
+  def rights #dc
+    'Diritti del lettore'
+  end
+  def date #dc
+    'Data'
+  end
+  def date_created #dc
+    'Data di creazione'
+  end
+  def date_issued #dc
+    'Data di pubblicazione'
+  end
+  def date_available #dc
+    'Data di effettiva disponibilità'
+  end
+  def date_modified #dc
+    'Data di ultima modifica'
+  end
+  def date_valid #dc
+    'Data di inizo validità'
+  end
+  def language #dc
+    'Lingua'
+  end
+  def language_original
+    'Lingua originale'
+  end
+  def format #dc
+    'Formato'
+  end
+  def identifier #dc
+    'Indentificatore'
+  end
+  def source #dc
+    'Fonte'
+  end
+  def relation #dc
+    'Collegamento'
+  end
+  def coverage #dc
+    'Ambito'
+  end
+  def keywords
+    'Parole chiave'
+  end
+  def comments
+    'Commenti'
+  end
+  def cls_loc
+    'Classificazione della Library of Congress'
+  end
+  def cls_dewey
+    'Classificazione Dewey'
+  end
+  def cls_oclc # fix
+    'Classify OCLC number'
+  end
+  def cls_gutenberg
+    'Classificazione del Progetto Gutenberg'
+  end
+  def cls_isbn
+    'Numero ISBN'
+  end
+  def prefix_a
+    'Premessa (a)'
+  end
+  def prefix_b
+    'Premessa (b)'
+  end
+  def topic_register
+    'Topics Registered'
+  end
+  def sourcefile
+    'Sorgente'
+  end
+  def word_count
+    'Numero approssimativo di parole'
+  end
+  def sourcefile_digest
+    'Checksum file sorgente'
+  end
+  def digest_md5
+    'Checksum file sorgente (md5)'
+  end
+  def digest_sha256
+    'Checksum file sorgente (sha256)'
+  end
+  def sc_number
+    'Numero di revisione (RCS/CVS)'
+  end
+  def sc_date
+    'Numero di revisione (RCS/CVS)'
+  end
+  def last_generated
+    'Data di ultima generazione (ao metaverse)'
+  end
+  def sisu_version
+    'Generato da'
+  end
+  def ruby_version
+    'Ruby versione'
+  end
+  def suggested_links
+    'Link suggeriti'
+  end
+  def language_version_list
+    'Traduzioni disponibili'
+  end
+  def manifest_description
+    'SiSU manifest of document filetypes and metadata'
+  end
+  def manifest_description_output
+    'Inventario SiSU dell\'output generato'
+  end
+  def manifest_description_metadata
+    'Inventario SiSU dei metadati'
+  end
+  def language_list_translated
+    case @trans_str
+    when /American/i       then 'Inglese USA'                         # tag depreciated, see iso 639-2
+    when /English/i        then 'Inglese'
+    when /French/i         then 'Francese'
+    when /German/i         then 'Tedesco'
+    when /Italian/i        then 'Italiano'
+    when /Spanish/i        then 'Spagnolo'
+    when /Portuguese Brazil|Brazilian(?: Portuguese)?/i
+                                'Portoguese (Brasile)'                # tag depreciated, see iso 639-2
+    when /Portuguese/i     then 'Portoguese'
+    when /Swedish/i        then 'Svedese'
+    when /Danish/i         then 'Danese'
+    when /Finnish/i        then 'Finlandese'
+    when /Norwegian/i      then 'Norvegese'
+    when /Icelandic/i      then 'Islandese'
+    when /Dutch/i          then 'Olandese'
+    when /Estonian/i       then 'Estone'
+    when /Hungarian/i      then 'Ungherese'
+    when /Polish/i         then 'Polacco'
+    when /Romanian/i       then 'Romeno'
+    when /Russian/i        then 'Russo'
+    when /Greek/i          then 'Greco'
+    when /Ukranian/i       then 'Ucraino'
+    when /Turkish/i        then 'Turco'
+    when /Slovenian/i      then 'Sloveno'
+    when /Croatian/i       then 'Croato'
+    when /Slovak(?:ian)?/i then 'Slovacco'
+    when /Czech/i          then 'Ceco'
+    when /Bulgarian/i      then 'Bulgaro'
+    else @trans_str
+    end
+  end
+end
+#+END_SRC
+
+** Finnish
+
+#+NAME: language_finnish
+#+BEGIN_SRC text
+class Finnish
+  def initialize(md,doc_lang,trans_str)
+    @md,@doc_lang,@trans_str=md,doc_lang,trans_str
+  end
+  def filename
+   'tiedostonimi'
+  end
+  def filetype_description
+    description
+  end
+  def metadata
+    'metadata'
+  end
+  def file_size
+    'tiedoston koko'
+  end
+  def full_title #dc
+    'otsikko'
+  end
+  def title
+    'Otsikko'
+  end
+  def subtitle
+    'Alaotsikko'
+  end
+  def author #dc
+    'tekijä'
+  end
+  def contributor #dc
+    'osallistuja'
+  end
+  def translator
+    'Kääntäjä'
+  end
+  def illustrator
+    'Kuvittaja'
+  end
+  def publisher #dc
+    'julkaisija'
+  end
+  def prepared_by
+    'Valmistaja'
+  end
+  def digitized_by
+    'Digitalisoinut'
+  end
+  def contents
+    'Contents' #translate
+  end
+  def subject #dc
+    'aihe'
+  end
+  def description #dc (watch)
+    'kuvaus'
+  end
+  def abstract #dc
+    'tiivistelmä'
+  end
+  def type #dc
+    'tyyppi'
+  end
+  def rights #dc
+    'oikeudet'
+  end
+  def date #dc
+    'päiväys'
+  end
+  def date_created #dc
+    'luontipäivä'
+  end
+  def date_issued #dc
+    'julkaisupäivä'
+  end
+  def date_available #dc
+    'saantipäivä'
+  end
+  def date_modified #dc
+    'muokkauspäivä'
+  end
+  def date_valid #dc
+    'kelpoisuuspäivä'
+  end
+  def language #dc
+    'kieli'
+  end
+  def language_original
+    'Alkuperäiskieli'
+  end
+  def format #dc
+    'muoto'
+  end
+  def identifier #dc
+    'tunnus'
+  end
+  def source #dc
+    'lähde'
+  end
+  def relation #dc
+    'suhde'
+  end
+  def coverage #dc
+    'kattavuus'
+  end
+  def keywords
+    'Avainsanat'
+  end
+  def comments
+    'Kommentit'
+  end
+  def cls_loc
+    'Classify Library of Congress'
+  end
+  def cls_dewey
+    'Classify Dewey'
+  end
+  def cls_oclc # fix
+    'Classify OCLC number'
+  end
+  def cls_gutenberg
+    'Classify Project Gutenberg'
+  end
+  def cls_isbn
+    'Classify ISBN'
+  end
+  def prefix_a
+    'Prefix (a)'
+  end
+  def prefix_b
+    'Prefix (b)'
+  end
+  def topic_register
+    'Topics Registered'
+  end
+  def sourcefile
+    'Lähdetiedosto'
+  end
+  def word_count
+    'Arvioitu sanamäärä'
+  end
+  def sourcefile_digest
+    'Lähdetiedoston tiiviste'
+  end
+  def digest_md5
+    'Lähdetiedoston tiiviste (md5)'
+  end
+  def digest_sha256
+    'Lähdetiedoston tiiviste (sha256)'
+  end
+  def sc_number
+    'Dokumentin RCS/CVS-numero'
+  end
+  def sc_date
+    'Dokumentin RCS/CVS-päiväys'
+  end
+  def last_generated
+    'Viimeksi tuotettu dokumentti (metaverse)'
+  end
+  def sisu_version
+    'Generoinut'
+  end
+  def ruby_version
+    'Ruby-versio'
+  end
+  def suggested_links
+    'metadatan ehdottamat linkit'
+  end
+  def language_version_list
+    'Dokumentin kieliversiot, manifestit'
+  end
+  def manifest_description
+    'SiSU manifest of document filetypes and metadata'
+  end
+  def manifest_description_output
+    'Tuotetun tuloksen SISU-manifesti'
+  end
+  def manifest_description_metadata
+    'Dokumenttimetadatan SISU-manifesti'
+  end
+  def language_list_translated
+    case @trans_str
+    when /American/i       then 'Amerikanenglanti'                    # tag depreciated, see iso 639-2
+    when /English/i        then 'Englanti'
+    when /French/i         then 'Ranska'
+    when /German/i         then 'Saksa'
+    when /Italian/i        then 'Italia'
+    when /Spanish/i        then 'Espanja'
+    when /Portuguese Brazil|Brazilian(?: Portuguese)?/i
+                                'Brasilian portugali'                 # tag depreciated, see iso 639-2
+    when /Portuguese/i     then 'Portugali'
+    when /Swedish/i        then 'Ruotsi'
+    when /Danish/i         then 'Tanska'
+    when /Finnish/i        then 'Suomi'
+    when /Norwegian/i      then 'Norja'
+    when /Icelandic/i      then 'Islanti'
+    when /Dutch/i          then 'Hollanti'
+    when /Estonian/i       then 'Viro'
+    when /Hungarian/i      then 'Unkari'
+    when /Polish/i         then 'Puola'
+    when /Romanian/i       then 'Romania'
+    when /Russian/i        then 'Venäjä'
+    when /Greek/i          then 'Kreikka'
+    when /Ukranian/i       then 'Ukraina'
+    when /Turkish/i        then 'Turkki'
+    when /Slovenian/i      then 'Slovenia'
+    when /Croatian/i       then 'Kroatia'
+    when /Slovak(?:ian)?/i then 'Slovakki'
+    when /Czech/i          then 'Tsekki'
+    when /Bulgarian/i      then 'Bulgaria'
+    else @trans_str
+    end
+  end
+end
+#+END_SRC
+
+** Portuguese
+
+#+NAME: language_protuguese
+#+BEGIN_SRC text
+class Portuguese            < English
+end
+#+END_SRC
+
+** Swedish
+
+#+NAME: language_swedish
+#+BEGIN_SRC text
+class Swedish               < English
+  def contents
+    'Innehåll'
+  end
+end
+#+END_SRC
+
+** remaining
+
+#+NAME: language_remaining
+#+BEGIN_SRC text
+class Danish                < English
+end
+class Norwegian             < English
+end
+class Icelandic             < English
+end
+class Dutch                 < English
+end
+class Estonian              < English
+end
+class Hungarian             < English
+end
+class Polish                < English
+end
+class Romanian              < English
+end
+class Russian               < English
+end
+class Greek                 < English
+end
+class Ukranian              < English
+end
+class Turkish               < English
+end
+class Croatian              < English
+end
+class Slovakian             < English
+end
+class Czech                 < English
+end
+class Bulgarian             < English
+end
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    i18n
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
+* NOTES
+** language list po4a
+
+#+BEGIN_SRC text
+#% Language List po4a
+http://www.debian.org/international/l10n/po/
+see polyglossia for subset
+- CSB (Unknown language)
+- KAB (Unknown language)
+- TLH (Unknown language)
+- aa (Afar)
+- ab (Abkhazian)
+- af (Afrikaans)
+- af_ZA (Afrikaans, as spoken in South Africa)
+- am (Amharic)
+- an (Unknown language)
+- ang (Unknown language)
+- ar (Arabic)
+- ar_AR (Arabic, as spoken in Argentina)
+- ar_EG (Arabic, as spoken in Egypt)
+- ar_OM (Arabic, as spoken in Oman)
+- ar_PS (Arabic, as spoken in Palestinian Territory, Occupied)
+- ar_SA (Arabic, as spoken in Saudi Arabia)
+- ar_SY (Arabic, as spoken in Syrian Arab Republic)
+- as (Assamese)
+- ast (Unknown language)
+- ay (Aymara)
+- az (Azerbaijani)
+- az_IR (Azerbaijani, as spoken in Iran)
+- be (Belarusian)
+- be@latin (Unknown language)
+- be@tarask (Unknown language)
+- bem (Unknown language)
+- bg (Bulgarian)
+- bg_BG (Bulgarian, as spoken in Bulgaria)
+- bi (Bislama)
+- bn (Bengali)
+- bn_BD (Bengali, as spoken in Bangladesh)
+- bn_IN (Bengali, as spoken in India)
+- bo (Tibetan)
+- br (Breton)
+- bs (Bosnian)
+- bs_BA (Bosnian, as spoken in Bosnia and Herzegovina)
+- bs_BS (Bosnian, as spoken in Bahamas)
+- byn (Unknown language)
+- ca (Catalan)
+- ca@valencia (Unknown language)
+- ca_AD (Catalan, as spoken in Andorra)
+- ca_ES (Catalan, as spoken in Spain)
+- ca_ES@valencia (Unknown language)
+- ca_FR (Catalan, as spoken in France)
+- ca_IT (Catalan, as spoken in Italy)
+- co (Corsican)
+- crh (Unknown language)
+- cs (Czech)
+- cs_CZ (Czech, as spoken in Czech Republic)
+- csb (Unknown language)
+- cy (Welsh)
+- cy_GB (Welsh, as spoken in Great Britain)
+- cz (Unknown language)
+- da (Danish)
+- da_DK (Danish, as spoken in Denmark)
+- de (German)
+- de_AT (German, as spoken in Austria)
+- de_CH (German, as spoken in Switzerland)
+- de_DE (German, as spoken in Germany)
+- dk (Unknown language)
+- dz (Dzongkha)
+- el (Greek)
+- el_GR (Greek, as spoken in Greece)
+- en (English)
+- en@boldquot (Unknown language)
+- en@quot (Unknown language)
+- en@shaw (Unknown language)
+- en_AU (English, as spoken in Australia)
+- en_CA (English, as spoken in Canada)
+- en_GB (English, as spoken in Great Britain)
+- en_NZ (English, as spoken in New Zealand)
+- en_US (English, as spoken in United States)
+- en_US@piglatin (Unknown language)
+- en_ZA (English, as spoken in South Africa)
+- eo (Esperanto)
+- es (Spanish)
+- es_AR (Spanish, as spoken in Argentina)
+- es_CL (Spanish, as spoken in Chile)
+- es_CO (Spanish, as spoken in Colombia)
+- es_CR (Spanish, as spoken in Costa Rica)
+- es_DO (Spanish, as spoken in Dominican Republic)
+- es_EC (Spanish, as spoken in Ecuador)
+- es_ES (Spanish, as spoken in Spain)
+- es_GA (Spanish, as spoken in Gabon)
+- es_GT (Spanish, as spoken in Guatemala)
+- es_HN (Spanish, as spoken in Honduras)
+- es_LA (Spanish, as spoken in Lao People''s Democratic Republic)
+- es_MX (Spanish, as spoken in Mexico)
+- es_NI (Spanish, as spoken in Nicaragua)
+- es_PA (Spanish, as spoken in Panama)
+- es_PE (Spanish, as spoken in Peru)
+- es_PR (Spanish, as spoken in Puerto Rico)
+- es_SV (Spanish, as spoken in El Salvador)
+- es_UY (Spanish, as spoken in Uruguay)
+- es_VE (Spanish, as spoken in Venezuela)
+- et (Estonian)
+- et_EE (Estonian, as spoken in Estonia)
+- eu (Basque)
+- eu_ES (Basque, as spoken in Spain)
+- fa (Persian)
+- fa_AF (Persian, as spoken in Afghanistan)
+- fa_IR (Persian, as spoken in Iran)
+- fi (Finnish)
+- fi_FI (Finnish, as spoken in Finland)
+- fil (Unknown language)
+- fo (Faeroese)
+- fo_FO (Faeroese, as spoken in Faroe Islands)
+- fr (French)
+- fr_BE (French, as spoken in Belgium)
+- fr_CA (French, as spoken in Canada)
+- fr_CH (French, as spoken in Switzerland)
+- fr_FR (French, as spoken in France)
+- fr_FX (French, as spoken in France, Metropolitan)
+- fr_LU (French, as spoken in Luxembourg)
+- frp (Unknown language)
+- fur (Unknown language)
+- fy (Frisian)
+- fy_NL (Frisian, as spoken in Netherlands)
+- ga (Irish)
+- gd (Gaelic (Scots))
+- gez (Unknown language)
+- gl (Galician)
+- gl_ES (Galician, as spoken in Spain)
+- gn (Guarani)
+- gu (Gujarati)
+- gv (Manx)
+- ha (Hausa)
+- he (Hebrew)
+- he_IL (Hebrew, as spoken in Israel)
+- hi (Hindi)
+- hne (Unknown language)
+- hr (Croatian)
+- hr_HR (Croatian, as spoken in Croatia)
+- ht (Unknown language)
+- hu (Hungarian)
+- hu_HU (Hungarian, as spoken in Hungary)
+- hy (Armenian)
+- ia (Interlingua)
+- id (Indonesian)
+- id_ID (Indonesian, as spoken in Indonesia)
+- ig (Unknown language)
+- io (Unknown language)
+- is (Icelandic)
+- is_IS (Icelandic, as spoken in Iceland)
+- it (Italian)
+- it_CH (Italian, as spoken in Switzerland)
+- it_IT (Italian, as spoken in Italy)
+- iu (Inuktitut)
+- ja (Japanese)
+- ja_JP (Japanese, as spoken in Japan)
+- jv (Unknown language)
+- jv_ID (Unknown language)
+- ka (Georgian)
+- kab (Unknown language)
+- kk (Kazakh)
+- kl (Kalaallisut)
+- km (Khmer)
+- km_KH (Khmer, as spoken in Cambodia)
+- kn (Kannada)
+- ko (Korean)
+- ko_KR (Korean, as spoken in Korea)
+- ks (Kashmiri)
+- ku (Kurdish)
+- kw (Cornish)
+- ky (Kirghiz)
+- la (Latin)
+- lb (Letzeburgesch)
+- lg (Unknown language)
+- li (Unknown language)
+- ln (Lingala)
+- lo (Lao)
+- lt (Lithuanian)
+- lt_LT (Lithuanian, as spoken in Lithuania)
+- lv (Latvian)
+- lv_LV (Latvian, as spoken in Latvia)
+- mai (Unknown language)
+- mal (Unknown language)
+- mg (Malagasy)
+- mi (Maori)
+- mk (Macedonian)
+- mk_MK (Macedonian, as spoken in Macedonia, the Former Yugoslav Republic of)
+- ml (Malayalam)
+- ml_IN (Malayalam, as spoken in India)
+- ml_ML (Malayalam, as spoken in Mali)
+- mn (Mongolian)
+- mr (Marathi)
+- ms (Malay)
+- ms_MY (Malay, as spoken in Malaysia)
+- mt (Maltese)
+- my (Burmese)
+- my_MM (Burmese, as spoken in Myanmar)
+- na (Nauru)
+- nb (Norwegian Bokmål)
+- nb_NO (Norwegian Bokmål, as spoken in Norway)
+- nds (Unknown language)
+- ne (Nepali)
+- new (Unknown language)
+- nl (Dutch)
+- nl_BE (Dutch, as spoken in Belgium)
+- nl_NL (Dutch, as spoken in Netherlands)
+- nn (Norwegian Nynorsk)
+- nn_NO (Norwegian Nynorsk, as spoken in Norway)
+- no (Norwegian)
+- no_NO (Norwegian, as spoken in Norway)
+- nr (Ndebele, South)
+- nso (Unknown language)
+- oc (Occitan (post 1500))
+- oc_FR (Occitan (post 1500), as spoken in France)
+- om (Oromo)
+- or (Oriya)
+- pa (Panjabi)
+- pl (Polish)
+- pl_PL (Polish, as spoken in Poland)
+- pms (Unknown language)
+- ps (Pushto)
+- pt (Portuguese)
+- pt_BR (Portuguese, as spoken in Brazil)
+- pt_PT (Portuguese, as spoken in Portugal)
+- qu (Quechua)
+- rm (Rhaeto-Romance)
+- ro (Romanian)
+- ro_RO (Romanian, as spoken in Romania)
+- ru (Russian)
+- ru_RU (Russian, as spoken in Russia)
+- rw (Kinyarwanda)
+- sa (Sanskrit)
+- sc (Sardinian)
+- sd (Sindhi)
+- se (Sami)
+- se_NO (Sami, as spoken in Norway)
+- si (Sinhalese)
+- si_LK (Sinhalese, as spoken in Sri Lanka)
+- si_SI (Sinhalese, as spoken in Slovenia)
+- sk (Slovak)
+- sk_SK (Slovak, as spoken in Slovakia)
+- sl (Slovenian)
+- sl_SI (Slovenian, as spoken in Slovenia)
+- sl_SL (Slovenian, as spoken in Sierra Leone)
+- so (Somali)
+- sp (Unknown language)
+- sq (Albanian)
+- sq_AL (Albanian, as spoken in Albania)
+- sr (Serbian)
+- sr@Latn (Unknown language)
+- sr@ije (Unknown language)
+- sr@ijekavian (Unknown language)
+- sr@ijekavianlatin (Unknown language)
+- sr@latin (Unknown language)
+- sr_SR (Serbian, as spoken in Suriname)
+- sr_YU (Serbian, as spoken in Yugoslavia)
+- st (Sotho)
+- su (Sundanese)
+- su_ID (Sundanese, as spoken in Indonesia)
+- sv (Swedish)
+- sv_SE (Swedish, as spoken in Sweden)
+- sw (Swahili)
+- ta (Tamil)
+- ta_LK (Tamil, as spoken in Sri Lanka)
+- te (Telugu)
+- tg (Tajik)
+- th (Thai)
+- th_TH (Thai, as spoken in Thailand)
+- ti (Tigrinya)
+- tig (Unknown language)
+- tk (Turkmen)
+- tl (Tagalog)
+- tlh (Unknown language)
+- to (Tonga)
+- tr (Turkish)
+- tr_TR (Turkish, as spoken in Turkey)
+- tt (Tatar)
+- ug (Uighur)
+- ug_CN (Uighur, as spoken in China)
+- uk (Ukrainian)
+- uk_UA (Ukrainian, as spoken in Ukraine)
+- ur (Urdu)
+- ur_PK (Urdu, as spoken in Pakistan)
+- uz (Uzbek)
+- uz@cyrillic (Unknown language)
+- ve (Unknown language)
+- vi (Vietnamese)
+- vi_AR (Vietnamese, as spoken in Argentina)
+- vi_DE (Vietnamese, as spoken in Germany)
+- vi_PL (Vietnamese, as spoken in Poland)
+- vi_TR (Vietnamese, as spoken in Turkey)
+- vi_VN (Vietnamese, as spoken in Vietnam)
+- wa (Unknown language)
+- wal (Unknown language)
+- wo (Wolof)
+- xh (Xhosa)
+- yi (Yiddish)
+- yo (Yoruba)
+- zh (Chinese)
+- zh_CN (Chinese, as spoken in China)
+- zh_HK (Chinese, as spoken in Hong Kong)
+- zh_TW (Chinese, as spoken in Taiwan)
+- zu (Zulu)
+
+ 'sq';    'albanian'
+ 'am';    'amharic'
+#'ar';    'arabic'         # see polyglossia
+ 'hy';    'armenian'
+#'';      'asturian'       # polyglossia
+#'';      'bahasai'        # polyglossia
+#'';      'bahasam'        # polyglossia
+ 'eu';    'basque'
+ 'bn';    'bengali'
+ 'pt_BR'; 'brazilian'
+ 'br';    'breton'
+ 'bg';    'bulgarian'
+ 'ca';    'catalan'        # see polyglossia
+#'';      'coptic'         # polyglossia
+ 'hr';    'croatian'
+ 'cs';    'czech'
+ 'da';    'danish'
+#'';      'divehi'         # polyglossia
+ 'nl';    'dutch'          # see polyglossia
+ 'en';    'english'        # see polyglossia
+ 'eo';    'esperanto'      # see polyglossia
+ 'et';    'estonian'
+ 'gl';    'galician'
+ 'de';    'german'
+ 'el';    'greek'          #gl ?
+ 'he';    'hebrew'
+ 'hi';    'hindi'
+ 'is';    'icelandic'
+ 'ia';    'interlingua'
+ 'ga';    'irish'
+ 'it';    'italian'
+#'';      'farsi'          # polyglossia
+ 'fi';    'finnish'
+ 'fr';    'french'
+ 'lo';    'lao'
+ 'la';    'latin'
+ 'lv';    'latvian'
+ 'lt';    'lithuanian'
+#'';      'lsorbian'       # polyglossia
+#'';      'magyar'         # polyglossia
+ 'ml';    'malayalam'
+ 'mr';    'marathi'
+#'hu';    'magyar'
+ 'no';    'norske'
+ 'nn';    'nynorsk'
+ 'oc';    'occitan'
+ 'pl';    'polish'
+ 'pt';    'portuges'
+ 'ro';    'romanian'
+ 'ru';    'russian'
+ 'se';    'samin'          #(check sami?)
+ 'sa';    'sanskrit'
+ 'sr';    'serbian'
+#'';      'scottish'       # polyglossia  (gd (Gaelic (Scots)))
+ 'sk';    'slovak'
+ 'sl';    'slovenian'
+ 'es';    'spanish'
+ 'sv';    'swedish'
+ 'ta';    'tamil'
+ 'te';    'telugu'
+ 'th';    'thai'
+ 'tr';    'turkish'
+ 'tk';    'turkmen'
+ 'uk';    'ukrainian'
+ 'ur';    'urdu'
+#'';      'usorbian'       # polyglossia
+ 'vi';    'vietnamese'
+ 'cy';    'welsh'
+ 'us';    'USenglish'      # depreciated, see iso-639-2
+#+END_SRC
+** language list po4a
+
+#+BEGIN_SRC text
+http://www.debian.org/international/l10n/po/
+http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
+http://www.loc.gov/standards/iso639-2/php/code_list.php
+albanian           sq
+amharic            am
+arabic             ar
+armenian           hy
+asturian
+bahasai
+bahasam
+basque             eu
+bengali            bn
+brazil[ian]        pt_BR
+breton             br
+bulgarian          bg
+catalan            ca
+coptic
+croatian           hr
+czech              cs
+danish             da
+divehi
+dutch              nl
+english            en
+esperanto          eo
+estonian           et
+galician           gl
+german             de
+greek              el
+hebrew             he
+hindi              hi
+icelandic          is
+interlingua        ia
+irish              ga
+italian            it
+farsi
+finnish            fi
+french             fr
+lao                lo
+latin              la
+latvian            lv
+lithuanian         lt
+lsorbian
+magyar
+malayalam          ml
+marathi            mr
+norsk              no
+nynorsk            nn
+occitan            oc
+polish             pl
+portuges           pt
+romanian           ro
+russian            ru
+samin              se (check sami?)
+sanskrit           sa
+scottish            #  (gd (Gaelic (Scots)))
+serbian            sr
+slovak             sk
+slovenian          sl
+spanish            es
+swedish            sv
+syriac             #  (ar_SY (Arabic, as spoken in Syrian Arab Republic))
+tamil              ta
+telugu             te
+thai               th
+turkish            tr
+turkmen            tk
+ukrainian          uk
+urdu               ur
+usorbian
+vietnamese         vi
+welsh              cy
+#+END_SRC
diff --git a/org/json.org b/org/json.org
new file mode 100644
index 00000000..c2c04a7c
--- /dev/null
+++ b/org/json.org
@@ -0,0 +1,1620 @@
+-*- mode: org -*-
+#+TITLE:       sisu json
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:json:
+#+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
+
+* json.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/json.rb"
+# <<sisu_document_header>>
+module SiSU_JSON
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+    include SiSU_Particulars
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'json_shared'                        # json_shared.rb
+    include SiSU_JSON_Munge
+  require_relative 'json_format'                        # json_format.rb
+    include SiSU_JSON_Format
+  require_relative 'json_persist'                       # json_persist.rb
+  require_relative 'shared_metadata'                    # shared_metadata.rb
+  @@alt_id_count=0
+  @@tablefoot=''
+  class Source
+    def initialize(opt)
+      @opt=opt
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+    end
+    def read
+      begin
+        @env,@md,@ao_array=@particulars.env,@particulars.md,@particulars.ao_array
+        unless @opt.act[:quiet][:set]==:on
+          tool=if (@opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on)
+            @env.program.web_browser +
+            ' file://' +
+            @md.file.output_path.json.dir + '/' +
+            @md.file.base_filename.json
+          elsif @opt.act[:verbose][:set]==:on
+            @env.program.web_browser +
+            ' file://' +
+            @md.file.output_path.json.dir + '/' +
+            @md.file.base_filename.json
+          else "[#{@opt.f_pth[:lng_is]}] #{@opt.fno}"
+          end
+          (@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on) \
+          ? SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'JSON',
+              tool
+            ).green_hi_blue
+          : SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'JSON',
+              tool
+            ).green_title_hi
+          if (@opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on)
+            SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              @opt.fns,
+                '/' + @md.file.output_path.json.dir +
+                '/' + @md.file.base_filename.json
+            ).flow
+          end
+        end
+        SiSU_JSON::Source::Songsheet.new(@particulars).song
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        SiSU_Env::CreateSite.new(@opt).cp_css
+        Dir.chdir(@opt.f_pth[:pth])
+      end
+    end
+    private
+    class Songsheet
+      def initialize(particulars)
+        @env,@md,@ao_array,@particulars=
+          particulars.env,particulars.md,particulars.ao_array,particulars
+        @file=SiSU_Env::FileOp.new(@md)
+      end
+      def song
+        begin
+          SiSU_JSON::Source::Scroll.new(@particulars).songsheet
+        rescue
+          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+        ensure
+        end
+      end
+    end
+    class Scroll
+      require_relative 'json_shared'                   # json_shared.rb #check already called
+      require_relative 'txt_shared'                     # txt_shared.rb
+        include SiSU_TextUtils
+      require_relative 'css'                            # css.rb
+      def initialize(particulars)
+        @env,@md,@ao_array=particulars.env,particulars.md,particulars.ao_array
+        @tab="\t"
+        @trans=SiSU_JSON_Munge::Trans.new(@md)
+        @sys=SiSU_Env::SystemCall.new
+        @per=SiSU_JSON_Persist::Persist.new
+      end
+      def songsheet
+        begin
+          pre
+          @data=markup(@ao_array)
+          post
+          publish
+        ensure
+          SiSU_JSON_Persist::Persist.new.persist_init
+        end
+      end
+    protected
+      def embedded_endnotes(dob='')
+        dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}(\d+)\s+(.+?)#{Mx[:en_a_c]}/,
+            '<endnote><number>\1</number><note>\2</note></endnote> ').
+          gsub(/#{Mx[:en_b_o]}([*+]\d+)\s+(.+?)#{Mx[:en_b_c]}/,
+            '<endnote><symbol>\1</symbol><note>\2</note></endnote> ').
+          gsub(/#{Mx[:en_a_o]}([*+]+)\s+(.+?)#{Mx[:en_a_c]}/,
+            '<endnote><symbol>\1</symbol><note>\2</note></endnote> ')
+      end
+      def extract_endnotes(dob='')
+        notes=dob.obj.scan(/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})([\d*+]+\s+.+?)(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/)
+        notes.flatten.each do |e|
+          s=e.to_s
+          util=SiSU_JSONutils::Clean.new(s)
+          wrap=util.line_json_clean
+          wrap=wrap.gsub(/^(\d+)\s+(.+?)\s*\Z/m, <<-WOK
+\\n[\\1.] \\2
+              WOK
+            ).
+            gsub(/^([*+]\d+)\s+(.+?)\s*\Z/m, <<-WOK
+\\n[\\1.] \\2
+              WOK
+            ).
+            gsub(/^([*+]+)\s+(.+?)\s*\Z/m, <<-WOK
+\\n[\\1.] \\2
+              WOK
+            ).strip
+#KEEP alternative presentation of endnotes
+#        wrap=wrap.gsub(/^(\d+)\s+(.+?)\s*\Z/m, <<WOK
+##{Ax[:tab]*1}<p class="endnote" notenumber="\\1">
+##{Ax[:tab]*2}\\1. \\2
+##{Ax[:tab]*1}</p>
+#WOK
+#)
+          @endnotes << wrap
+        end
+      end
+      def json_head
+        #metadata=SiSU_Metadata::Summary.new(@md).json.metadata
+        #@per.head << metadata
+      end
+      def name_tags(dob)
+        tags=''
+        if defined? dob.tags \
+        and dob.tags.length > 0 # insert tags "hypertargets"
+          dob.tags.each do |t|
+            tags=tags << %{<named id="#{t}" />}
+          end
+        end
+        tags
+      end
+      def json_structure(dob,attrib=nil)
+        if dob.is ==:para \
+        || dob.is ==:heading
+          if dob.is==:heading
+            lv=dob.ln
+            dob.ln + 2
+          else lv=nil
+          end
+          extract_endnotes(dob)
+          dob.obj=dob.obj.
+            gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'<en>\1</en>'). #footnote/endnote clean
+            gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'<en>\1</en>')
+          util=SiSU_JSONutils::Clean.new(dob.obj)
+          wrapped=util.line_json_clean
+          @per.body << Ax[:tab]*1 + '{'
+          if defined? dob.ocn and dob.ocn
+            @per.body << Ax[:tab]*2 + '"ocn": ' + dob.ocn.to_s + '",'
+          end
+          if lv                                                                 # main text, contents, body KEEP
+            @per.body <<
+              Ax[:tab]*2 + %{"object": "<h#{lv}>} + wrapped + %{</h#{lv}>} +
+              ((@endnotes.length > 0) ? '",' : '"')
+          else
+            @per.body <<
+              Ax[:tab]*2 + '"object": "' + wrapped +
+              ((@endnotes.length > 0) ? '",' : '"')
+          end
+          if @endnotes.length > 0                                               # main text, endnotes KEEP
+            @per.body <<
+              Ax[:tab]*2 + '"endnotes": "' +
+              @endnotes.compact.join.strip + '"'
+          end
+          @per.body << Ax[:tab]*1 + '},' # unless is last object then '}'
+          @endnotes=[]
+        end
+      end
+      def block_structure(dob)
+        dob=@trans.markup_block(dob)
+        dob.obj=dob.obj.strip.
+          gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'<en>\1</en>'). #footnote/endnote clean
+          gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'<en>\1</en>') #footnote/endnote clean
+        @per.body << Ax[:tab]*1 + '{'
+        if defined? dob.ocn and dob.ocn
+          @per.body << Ax[:tab]*2 + '"ocn": ' + dob.ocn.to_s + '",'
+        end
+        @per.body <<
+          Ax[:tab]*2 + '"object": "' + dob.obj + '"'
+          #((@endnotes.length > 0) ? '",' : '"')
+        @per.body << Ax[:tab]*1 + '},' # unless is last object then '}'
+      end
+      def group_structure(dob)
+        dob=@trans.markup_group(dob)
+        dob.obj=dob.obj.strip.
+          gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'<en>\1</en>'). #footnote/endnote clean
+          gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'<en>\1</en>') #footnote/endnote clean
+        @per.body << Ax[:tab]*1 + '{'
+        if defined? dob.ocn and dob.ocn
+          @per.body << Ax[:tab]*2 + '"ocn": ' + dob.ocn.to_s + '",'
+        end
+        @per.body <<
+          Ax[:tab]*2 + '"object": "' + dob.obj + '"'
+          #((@endnotes.length > 0) ? '",' : '"')
+        @per.body << Ax[:tab]*1 + '},' # unless is last object then '}'
+      end
+      def poem_structure(dob)
+        dob=@trans.markup_group(dob)
+        dob.obj=dob.obj.strip
+        @per.body << Ax[:tab]*1 + '{'
+        if defined? dob.ocn and dob.ocn
+          @per.body << Ax[:tab]*2 + '"ocn": ' + dob.ocn.to_s + '",'
+        end
+        @per.body <<
+          Ax[:tab]*2 + '"object": "' + dob.obj + '"'
+          #((@endnotes.length > 0) ? '",' : '"')
+        @per.body << Ax[:tab]*1 + '},' # unless is last object then '}'
+      end
+      def code_structure(dob)
+        dob=@trans.markup_group(dob)
+        dob.obj=dob.obj.gsub(/\s\s/,'&#160;&#160;').strip
+        @per.body << Ax[:tab]*1 + '{'
+        if defined? dob.ocn and dob.ocn
+          @per.body << Ax[:tab]*2 + '"ocn": ' + dob.ocn.to_s + '",'
+        end
+        @per.body <<
+          Ax[:tab]*2 + '"object": "' + dob.obj + '"'
+          #((@endnotes.length > 0) ? '",' : '"')
+        @per.body << Ax[:tab]*1 + '},' # unless is last object then '}'
+      end
+      def table_structure(dob)
+        table=SiSU_JSON_Shared::TableJSON.new(dob)
+        @per.body << Ax[:tab]*1 + '{'
+        if defined? dob.ocn and dob.ocn
+          @per.body << Ax[:tab]*2 + '"ocn": ' + dob.ocn.to_s + '",'
+        end
+        @per.body <<
+          Ax[:tab]*2 + '"object": "' + table.table.obj + '"'
+        #((@endnotes.length > 0) ? '",' : '"')
+        @per.body << Ax[:tab]*1 + '},' # unless is last object then '}'
+      end
+      def markup(data)
+        @endnotes=[]
+        @rcdc=false
+        @level,@cont,@copen,@json_contents_close=[],[],[],[]
+        json_head
+        (0..7).each { |x| @cont[x]=@level[x]=false }
+        (4..7).each { |x| @json_contents_close[x]='' }
+        data.each_with_index do |dob,i|
+          dob=@trans.char_enc.utf8(dob) if @sys.locale =~/utf-?8/i #% utf8
+          dob=@trans.markup(dob)
+          if @rcdc==false \
+          and (dob.obj =~/~meta/ \
+          and dob.obj =~/Document Information/)
+            @rcdc=true
+          end
+          if dob.obj !~/(^#{Rx[:meta]}|#{Mx[:br_eof]}|#{Mx[:br_endnotes]})/
+            if not @rcdc
+              x=SiSU_JSON_Format::FormatTextObject.new(@md,dob)
+              if dob.is==:heading
+                json_structure(dob)
+                dob.obj=case dob.ln
+                when 0 then x.heading_body0
+                when 1 then x.heading_body1
+                when 2 then x.heading_body2
+                when 3 then x.heading_body3
+                when 4 then x.heading_body4
+                when 5 then x.heading_body5
+                when 6 then x.heading_body6
+                when 7 then x.heading_body7
+                end
+              else
+                if dob.is ==:verse
+                  poem_structure(dob)
+                elsif dob.is ==:group
+                  group_structure(dob)
+                elsif dob.is ==:block
+                  block_structure(dob)
+                elsif dob.is ==:code
+                  code_structure(dob)
+                elsif dob.is ==:table
+                  table_structure(dob)
+                elsif dob.is ==:para \
+                and dob.indent.to_s =~/[1-9]/ \
+                and dob.bullet_==true
+                  json_structure(dob,"indent_bullet#{dob.indent}")
+                elsif dob.is ==:para \
+                and dob.indent.to_s =~/[1-9]/ \
+                and dob.indent == dob.hang
+                  json_structure(dob,"indent#{dob.indent}")
+                elsif dob.is==:para \
+                and dob.hang.to_s =~/[0-9]/ \
+                and dob.indent != dob.hang
+                  json_structure(dob,"hang#{dob.hang.to_s}_indent#{dob.indent.to_s}")
+                else json_structure(dob)
+                end
+              end
+            end
+            dob.obj=dob.obj.gsub(/#{Mx[:pa_o]}:\S+#{Mx[:pa_c]}/,'') if dob.obj
+          end
+        end
+        6.downto(4) do |x|
+          y=x - 1; v=x - 3
+          @per.body << "#{Ax[:tab]*5}</content>\n#{Ax[:tab]*y}</contents#{v}>" if @level[x]==true
+        end
+        3.downto(1) do |x|
+          y=x - 1
+          @per.body << "#{Ax[:tab]*y}</heading#{x}>" if @level[x]==true
+        end
+      end
+      def pre
+        @per.head,@per.body=[],[]
+        @per.open = '{'
+      end
+      def post
+        @per.close = '}'
+      end
+      def publish
+        content=[]
+        @per.body[-1] = @per.body[-1].gsub(/,$/, '') #= Ax[:tab]*1 + '}'
+        content << @per.open << @per.head << @per.body << @per.metadata
+        content << @per.tail << @per.close
+        content=content.flatten.compact
+        Output.new(content,@md).json
+      end
+    end
+    class Output
+      def initialize(data,md)
+        @data,@md=data,md
+        @file=SiSU_Env::FileOp.new(@md)
+      end
+      def json
+        SiSU_Env::FileOp.new(@md).mkdir
+        filename_json=@file.write_file.json
+        @data.each do |str|
+          str=str.gsub(/\A\s+\Z/m,'') #str.gsub(/^\s+$/,'')
+          filename_json.puts str unless str.empty?
+        end
+        filename_json.close
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* json_parts.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/json_parts.rb"
+# <<sisu_document_header>>
+module SiSU_Parts_JSON
+  require_relative 'generic_parts'                       # generic_parts.rb
+  include SiSU_Parts_Generic
+  def the_line_break
+    '<br>'
+  end
+  def the_table_close
+    '</td></tr>
+</table>'
+  end
+  def the_url_decoration
+    def xml_open                     #'&lt;'
+      Dx[:url_o]
+    end
+    def xml_close                    #'&gt;'
+      Dx[:url_c]
+    end
+    def txt_open
+      '['
+    end
+    def txt_close
+      ']'
+    end
+    self
+  end
+end
+module SiSU_Proj_XML
+  require_relative 'html_parts'                         # html_parts.rb
+  require_relative 'se'                                 # se.rb
+  include SiSU_Env
+  class Bits < SiSU_Proj_HTML::Bits
+  end
+end
+__END__
+#+END_SRC
+
+* json_shared.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/json_shared.rb"
+# <<sisu_document_header>>
+module SiSU_JSONutils
+  require_relative 'generic_parts'                      # generic_parts.rb
+  class Clean
+    def initialize(para='')
+      @para=para
+      #@para,@n_char_max,@n_indent,@post,=para,n_char_max,n_indent,post
+      #@n_char_max_extend = n_char_max
+      #@n_hang=n_hang ? n_hang : @n_indent
+    end
+    def line_json_clean
+      @para=@para.gsub(/<br>/,' \\ ').
+        gsub(/#{Mx[:br_nl]}/,"\n\n").
+        gsub(/"/,'\"').
+        gsub(/'/,"\\\\'")
+      @para
+    end
+  end
+end
+module SiSU_JSON_Munge
+  require_relative 'json_parts'                         # json_parts.rb
+  class Trans
+    include SiSU_Parts_JSON
+    def initialize(md)
+      @md=md
+      @sys=SiSU_Env::SystemCall.new
+      @dir=SiSU_Env::InfoEnv.new(@md.fns)
+      if @md.sem_tag
+        @ab ||=semantic_tags.default
+      end
+    end
+    def semantic_tags
+      def default
+        {
+          pub:   'publication',
+          conv:  'convention',
+          vol:   'volume',
+          pg:    'page',
+          cty:   'city',
+          org:   'organization',
+          uni:   'university',
+          dept:  'department',
+          fac:   'faculty',
+          inst:  'institute',
+          co:    'company',
+          com:   'company',
+          conv:  'convention',
+          dt:    'date',
+          y:     'year',
+          m:     'month',
+          d:     'day',
+          ti:    'title',
+          au:    'author',
+          ed:    'editor', #editor?
+          v:     'version', #edition
+          n:     'name',
+          fn:    'firstname',
+          mn:    'middlename',
+          ln:    'lastname',
+          in:    'initials',
+          qt:    'quote',
+          ct:    'cite',
+          ref:   'reference',
+          ab:    'abreviation',
+          def:   'define',
+          desc:  'description',
+          trans: 'translate',
+        }
+      end
+      self
+    end
+    def char_enc #character encode
+      def utf8(dob='')
+        if @sys.locale =~/utf-?8/i # instead ucs for utf8 # String#encode Iñtërnâtiônàlizætiøn
+          str=if defined? dob.obj then dob.obj
+          elsif dob.is_a?(String) then dob
+          end
+          if str
+            #¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûü
+            #¢£¥§©ª«®°±²³µ¶¹º»¼½¾×÷
+            str=str.gsub(/</um,'&#60;').    # '&lt;'     # &#060;
+              gsub(/>/um,'&#62;').    # '&gt;'     # &#062;
+              gsub(/¢/um,'&#162;').   # '&cent;'   # &#162;
+              gsub(/£/um,'&#163;').   # '&pound;'  # &#163;
+              gsub(/¥/um,'&#165;').   # '&yen;'    # &#165;
+              gsub(/§/um,'&#167;').   # '&sect;'   # &#167;
+              gsub(/©/um,'&#169;').   # '&copy;'   # &#169;
+              gsub(/ª/um,'&#170;').   # '&ordf;'   # &#170;
+              gsub(/«/um,'&#171;').   # '&laquo;'  # &#171;
+              gsub(/®/um,'&#174;').   # '&reg;'    # &#174;
+              gsub(/°/um,'&#176;').   # '&deg;'    # &#176;
+              gsub(/±/um,'&#177;').   # '&plusmn;' # &#177;
+              gsub(/²/um,'&#178;').   # '&sup2;'   # &#178;
+              gsub(/³/um,'&#179;').   # '&sup3;'   # &#179;
+              gsub(/µ/um,'&#181;').   # '&micro;'  # &#181;
+              gsub(/¶/um,'&#182;').   # '&para;'   # &#182;
+              gsub(/¹/um,'&#185;').   # '&sup1;'   # &#185;
+              gsub(/º/um,'&#186;').   # '&ordm;'   # &#186;
+              gsub(/»/um,'&#187;').   # '&raquo;'  # &#187;
+              gsub(/¼/um,'&#188;').   # '&frac14;' # &#188;
+              gsub(/½/um,'&#189;').   # '&frac12;' # &#189;
+              gsub(/¾/um,'&#190;').   # '&frac34;' # &#190;
+              gsub(/×/um,'&#215;').   # '&times;'  # &#215;
+              gsub(/÷/um,'&#247;').   # '&divide;' # &#247;
+              gsub(/¿/um,'&#191;').   # '&iquest;' # &#191;
+              gsub(/À/um,'&#192;').   # '&Agrave;' # &#192;
+              gsub(/Á/um,'&#193;').   # '&Aacute;' # &#193;
+              gsub(/Â/um,'&#194;').   # '&Acirc;'  # &#194;
+              gsub(/Ã/um,'&#195;').   # '&Atilde;' # &#195;
+              gsub(/Ä/um,'&#196;').   # '&Auml;'   # &#196;
+              gsub(/Å/um,'&#197;').   # '&Aring;'  # &#197;
+              gsub(/Æ/um,'&#198;').   # '&AElig;'  # &#198;
+              gsub(/Ç/um,'&#199;').   # '&Ccedil;' # &#199;
+              gsub(/È/um,'&#200;').   # '&Egrave;' # &#200;
+              gsub(/É/um,'&#201;').   # '&Eacute;' # &#201;
+              gsub(/Ê/um,'&#202;').   # '&Ecirc;'  # &#202;
+              gsub(/Ë/um,'&#203;').   # '&Euml;'   # &#203;
+              gsub(/Ì/um,'&#204;').   # '&Igrave;' # &#204;
+              gsub(/Í/um,'&#205;').   # '&Iacute;' # &#205;
+              gsub(/Î/um,'&#206;').   # '&Icirc;'  # &#206;
+              gsub(/Ï/um,'&#207;').   # '&Iuml;'   # &#207;
+              gsub(/Ð/um,'&#208;').   # '&ETH;'    # &#208;
+              gsub(/Ñ/um,'&#209;').   # '&Ntilde;' # &#209;
+              gsub(/Ò/um,'&#210;').   # '&Ograve;' # &#210;
+              gsub(/Ó/um,'&#211;').   # '&Oacute;' # &#211;
+              gsub(/Ô/um,'&#212;').   # '&Ocirc;'  # &#212;
+              gsub(/Õ/um,'&#213;').   # '&Otilde;' # &#213;
+              gsub(/Ö/um,'&#214;').   # '&Ouml;'   # &#214;
+              gsub(/Ø/um,'&#216;').   # '&Oslash;' # &#216;
+              gsub(/Ù/um,'&#217;').   # '&Ugrave;' # &#217;
+              gsub(/Ú/um,'&#218;').   # '&Uacute;' # &#218;
+              gsub(/Û/um,'&#219;').   # '&Ucirc;'  # &#219;
+              gsub(/Ü/um,'&#220;').   # '&Uuml;'   # &#220;
+              gsub(/Ý/um,'&#221;').   # '&Yacute;' # &#221;
+              gsub(/Þ/um,'&#222;').   # '&THORN;'  # &#222;
+              gsub(/ß/um,'&#223;').   # '&szlig;'  # &#223;
+              gsub(/à/um,'&#224;').   # '&agrave;' # &#224;
+              gsub(/á/um,'&#225;').   # '&aacute;' # &#225;
+              gsub(/â/um,'&#226;').   # '&acirc;'  # &#226;
+              gsub(/ã/um,'&#227;').   # '&atilde;' # &#227;
+              gsub(/ä/um,'&#228;').   # '&auml;'   # &#228;
+              gsub(/å/um,'&#229;').   # '&aring;'  # &#229;
+              gsub(/æ/um,'&#230;').   # '&aelig;'  # &#230;
+              gsub(/ç/um,'&#231;').   # '&ccedil;' # &#231;
+              gsub(/è/um,'&#232;').   # '&egrave;' # &#232;
+              gsub(/é/um,'&#233;').   # '&acute;'  # &#233;
+              gsub(/ê/um,'&#234;').   # '&circ;'   # &#234;
+              gsub(/ë/um,'&#235;').   # '&euml;'   # &#235;
+              gsub(/ì/um,'&#236;').   # '&igrave;' # &#236;
+              gsub(/í/um,'&#237;').   # '&acute;'  # &#237;
+              gsub(/î/um,'&#238;').   # '&icirc;'  # &#238;
+              gsub(/ï/um,'&#239;').   # '&iuml;'   # &#239;
+              gsub(/ð/um,'&#240;').   # '&eth;'    # &#240;
+              gsub(/ñ/um,'&#241;').   # '&ntilde;' # &#241;
+              gsub(/ò/um,'&#242;').   # '&ograve;' # &#242;
+              gsub(/ó/um,'&#243;').   # '&oacute;' # &#243;
+              gsub(/ô/um,'&#244;').   # '&ocirc;'  # &#244;
+              gsub(/õ/um,'&#245;').   # '&otilde;' # &#245;
+              gsub(/ö/um,'&#246;').   # '&ouml;'   # &#246;
+              gsub(/ø/um,'&#248;').   # '&oslash;' # &#248;
+              gsub(/ù/um,'&#250;').   # '&ugrave;' # &#250;
+              gsub(/ú/um,'&#251;').   # '&uacute;' # &#251;
+              gsub(/û/um,'&#252;').   # '&ucirc;'  # &#252;
+              gsub(/ü/um,'&#253;').   # '&uuml;'   # &#253;
+              gsub(/þ/um,'&#254;').   # '&thorn;'  # &#254;
+              gsub(/ÿ/um,'&#255;').   # '&yuml;'   # &#255;
+              gsub(/‘/um,'&#8216;').  # '&lsquo;'  # &#8216;
+              gsub(/’/um,'&#8217;').  # '&rsquo;'  # &#8217;
+              gsub(/“/um,'&#8220;').  # &ldquo;    # &#8220;
+              gsub(/”/um,'&#8221;').  # &rdquo;    # &#8221;
+              gsub(/–/um,'&#8211;').  # &ndash;    # &#8211;
+              gsub(/—/um,'&#8212;').  # &mdash;    # &#8212;
+              gsub(/∝/um,'&#8733;').  # &prop;     # &#8733;
+              gsub(/∞/um,'&#8734;').  # &infin;    # &#8734;
+              gsub(/™/um,'&#8482;').  # &trade;    # &#8482;
+              gsub(/✠/um,'&#10016;'). # &cross;    # &#10016;
+              gsub(/ /um,' ').       # space identify
+              gsub(/ /um,' ')       # space identify
+          end
+          dob=if defined? dob.obj
+            dob.obj=str
+            dob
+          elsif dob.is_a?(String)
+            str
+          end
+          dob
+        end
+      end
+      def html(dob='')
+        if @sys.locale =~/utf-?8/i # instead ucs for utf8 # String#encode Iñtërnâtiônàlizætiøn
+          dob.obj=dob.obj.gsub(/ /u,' ').           # space identify
+            gsub(/ /u,' ')           # space identify
+        end
+      end
+      self
+    end
+    def tidywords(wordlist)
+      wordlist_new=[]
+      wordlist.each do |x|
+        #imperfect solution will not catch all possible cases
+        x=x.gsub(/&/,'&amp;') unless x =~/&\S+;/
+        x=x.gsub(/&([A-Z])/,'&amp;\1')
+        wordlist_new << x
+      end
+      wordlist_new
+    end
+    def markup(dob='')
+      wordlist=dob.obj.scan(/&[#0-9a-z]+;|\S+|\n/) #\n needed for tables, check though added 2005w17
+      dob.obj=tidywords(wordlist).join(' ').strip
+      unless dob.is==:table
+        dob.obj=dob.obj.gsub(/#{Mx[:br_line]}/u,'<br>').
+          gsub(/#{Mx[:br_paragraph]}/u,'<br>').
+          gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/,'<br>')
+      end
+      dob.obj=dob.obj.gsub(/#{Mx[:mk_o]}:name#\S+?#{Mx[:mk_c]}/,'').
+        gsub(/#{Mx[:mk_o]}#([a-zA-Z]+)#{Mx[:mk_c]}/,'&\1;').
+        gsub(/#{Mx[:mk_o]}(#[0-9]+)#{Mx[:mk_c]}/,'&\1;').
+        gsub(/(^|#{Mx[:gl_c]}|\s+)<\s+/,'\1&lt; ').gsub(/\s+>(\s+|$)/,' &gt;\1').
+        #gsub(/#{Mx[:fa_emphasis_o]}(.+?)#{Mx[:fa_emphasis_c]}/,'<em>\1</em>'). #reinstate
+        gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/m,'<b>\1</b>').
+        gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/m,'<i>\1</i>').
+        gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'<u>\1</u>').
+        gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'<sup>\1</sup>').
+        gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'<sub>\1</sub>').
+        gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'<ins>\1</ins>').
+        gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'<cite>\1</cite>').
+        gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'<del>\1</del>').
+        gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,'<tt>\1</tt>').
+        gsub(/<:pb>\s*/,''). #Fix
+        gsub(/<+[-~]#>+/,'')
+      if dob.is !=:code
+        #embeds a red-bullet image -->
+        dob.obj=dob.obj.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'<b>\1</b>').
+          gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'<i>\1</i>').
+          gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'<u>\1</u>').
+          gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'<del>\1</del>')
+        dob.obj=dob.obj.gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/,'<br>') unless dob.is==:table
+        dob.obj=dob.obj.gsub(/#{Mx[:br_page]}\s*/,'').
+          gsub(/#{Mx[:br_page_new]}\s*/,'').
+          gsub(/#{Mx[:br_page_line]}\s*/,'').
+          gsub(/#{Mx[:pa_non_object_no_heading]}|#{Mx[:pa_non_object_dummy_heading]}/,'').
+          gsub(/<[-~]#>/,'').
+          gsub(/href="#{Xx[:segment]}/m,'href="').
+          gsub(/#{Mx[:lnk_o]}([^#{Mx[:lnk_o]}#{Mx[:lnk_c]}#{Mx[:rel_o]}#{Mx[:rel_c]}]+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}(\.\.\/\S+?)#{Mx[:rel_c]}/,
+            '<link xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:href="\2">\1</link>').
+          gsub(/#{Mx[:lnk_o]}([^#{Mx[:lnk_o]}#{Mx[:lnk_c]}#{Mx[:rel_o]}#{Mx[:rel_c]}]+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}:(\S+?)#{Mx[:rel_c]}/,
+            '<link xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:href="../\2">\1</link>').
+          gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}(\S+?)#{Mx[:rel_c]}/,
+            '<link xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:href="#\2">\1</link>').
+          gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}[ ]*(\S+?\.(?:jpg|png|gif))[ ]+(\d+)x(\d+)(\s+[^}]+)?#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,
+            %{<image xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:actuate="onLoad" xl:show="embed" xl:href="#{@md.file.output_path.xml.rel_image}/\\1" width="\\2" height="\\3" />[\\1] \\4}).
+          gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}[ ]*(\S+?\.(?:jpg|png|gif))([ ]+[^}]+)?#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,
+            %{<image xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:actuate="onLoad" xl:show="embed" xl:href="#{@md.file.output_path.xml.rel_image}/\\1"/>\\1}).
+          gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}[ ]*(\S+?\.(?:jpg|png|gif))[ ]+(\d+)x(\d+)(\s+[^}]+)?#{Mx[:lnk_c]}image/,
+            %{<image xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:actuate="onLoad" xl:show="embed" xl:href="#{@md.file.output_path.xml.rel_image}/\\1" width="\\2" height="\\3" />[\\1] \\4}).
+          gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}[ ]*(\S+?\.(?:jpg|png|gif))([ ]+[^}]+)?#{Mx[:lnk_c]}image/,
+            %{<image xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:actuate="onLoad" xl:show="embed" xl:href="#{@md.file.output_path.xml.rel_image}/\\1"/>\\1}).
+          gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,
+            '<link xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:href="\2">\1</link>'). #watch, compare html_tune
+          gsub(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,
+            %{#{the_url_decoration.xml_open}<link xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:href="\\1">\\1</link>#{the_url_decoration.xml_close}}).
+          gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,
+            '<link xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:href="\1">\1</link>') #escaped urls not linked, deal with later
+      else
+        dob.obj=dob.obj.gsub(/</m,'&lt;').gsub(/>/m,'&gt;')
+      end
+      if dob.of==:block
+        dob.obj=dob.obj.gsub(/#{Mx[:gl_bullet]}/,'● ')
+      end
+      dob.obj=dob.obj.gsub(/#{Mx[:url_o]}([a-zA-Z0-9._-]+\@\S+?\.[a-zA-Z0-9._-]+)#{Mx[:url_c]}/,
+          %{#{the_url_decoration.xml_open}\\1#{the_url_decoration.xml_close}}).
+        gsub(/#{Dx[:url_o]}/,"#{Dx[:url_o_xml]}").
+        gsub(/#{Dx[:url_c]}/,"#{Dx[:url_c_xml]}").
+        gsub(/&nbsp;|#{Mx[:nbsp]}/m,'&#160;').
+        gsub(/;&([^#]|(?:[^gl][^t]|[^a][^m][^p]|[^n][^b][^s][^p])[^;])/,';&amp;\1') # pattern not to match
+      dob
+    end
+    def markup_light(dob='')
+      dob.obj=dob.obj.gsub(/\/\{(.+?)\}\//,'<i>\1</i>').
+        gsub(/[*!]\{(.+?)\}[*!]/,'<b>\1</b>').
+        gsub(/_\{(.+?)\}_/,'<u>\1</u>').
+        gsub(/-\{(.+?)\}-/,'<del>\1</del>').
+        gsub(/<br(\s*\/)?>/,'<br>').
+        gsub(/<:pb>\s*/,'').
+        gsub(/<[-~]#>/,'').
+        gsub(/(^|#{Mx[:gl_c]}|\s)&\s+/,'\1&amp; '). #sort
+        gsub(/&([^;]{1,5})/,'&amp;\1'). #sort, rough estimate, revisit #WATCH found in node not sax
+        gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}(\S+?\.(?:png|jpg|gif))[ ]+.+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|image)/,
+          "<image.path>#{@md.file.output_path.xml.rel_image}\/\\1</image.path>").
+        gsub(/&nbsp;|#{Mx[:nbsp]}/,'&#160;').
+        gsub(/;&([^#]|(?:[^gl][^t]|[^a][^m][^p]|[^n][^b][^s][^p])[^;])/,';&amp;\1') # pattern not to match
+      wordlist=dob.obj.scan(/&[#0-9a-z]+;|\S+|\n/) #\n needed for tables, check though added 2005w17
+      dob.obj=tidywords(wordlist).join(' ').strip
+      dob
+    end
+    def clean(str)
+      str=str.gsub(/#{Mx[:gl_o]}(#[0-9]{3})#{Mx[:gl_c]}/u,'&\1;').
+        gsub(/#{Mx[:gl_o]}#([a-z]{2,4})#{Mx[:gl_c]}/u,'&\1;')
+    end
+    def markup_fictionbook(str='',is='')
+      str=str.gsub(/#{Mx[:en_a_o]}([\d+*]+).+?#{Mx[:en_a_c]}/m,'<a xl:href="#footnote\1" type="note">[\1]</a>').
+        gsub(/&/,'&amp;'). #sort
+        gsub(/#{Mx[:mk_o]}#([a-zA-Z]+)#{Mx[:mk_c]}/,'&\1;').
+        gsub(/(^|#{Mx[:gl_c]}|\s)&\s+/,'\1&amp; '). #sort
+        gsub(/#{Mx[:mk_o]}(#[0-9]+)#{Mx[:mk_c]}/,'&\1;')
+      str=str.gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/,'<br>') unless is==:table
+      str=str.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'<b>\1</b>').
+        gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'<i>\1</i>').
+        gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'<u>\1</u>').
+        gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'<sup>\1</sup>').
+        gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'<sub>\1</sub>').
+        gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'<ins>\1</ins>').
+        gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'<cite>\1</cite>').
+        gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'<del>\1</del>').
+        gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,'<tt>\1</tt>'). # tt, kbd
+        gsub(/#{Mx[:lnk_o]}\s*(\S+?\.(?:png|jpg|gif)).+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)/m,'<image xl:href="#\1" />').
+        gsub(/#{Mx[:url_o]}(.+?)#{Mx[:url_c]}/,"#{Dx[:url_o]}\\1#{Dx[:url_c]}").
+        gsub(/#{Mx[:mk_o]}:name#(\S+?)#{Mx[:mk_c]}/,'<a name="\1"></a>').
+        gsub(/#{Mx[:gl_bullet]}/m,'● '). #&nbsp; not available
+        gsub(/#{Mx[:nbsp]}/,' '). #&nbsp; not available
+        gsub(/<(p|br)>/,'<\1 />')
+      clean(str)
+    end
+    def markup_docbook(dob='')                                  # work on, initially a copy of fictionbook!
+      if dob.is !=:code
+        dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}(\d+)\s*(.+?)#{Mx[:en_a_c]}/m,'<footnote><para><!-- fn\1 -->\2</para></footnote>').
+          gsub(/\\\\/,'</para><para>').
+          gsub(/&/,'&amp;'). #sort
+          gsub(/#{Mx[:mk_o]}#([a-zA-Z]+)#{Mx[:mk_c]}/,'&\1;').
+          gsub(/(^|#{Mx[:gl_c]}|\s)&\s+/,'\1&amp; '). #sort
+          gsub(/#{Mx[:mk_o]}(#[0-9]+)#{Mx[:mk_c]}/,'&\1;')
+        dob.obj=dob.obj.gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/,'<br>') unless dob.is==:table
+        dob.obj=dob.obj.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'<b>\1</b>').
+          gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'<i>\1</i>').
+          gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'<u>\1</u>').
+          gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'<sup>\1</sup>').
+          gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'<sub>\1</sub>').
+          gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'<ins>\1</ins>').
+          gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'<cite>\1</cite>').
+          gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'<del>\1</del>').
+          gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,'<tt>\1</tt>'). # tt, kbd
+          gsub(/#{Mx[:lnk_o]}\s*(\S+?)\.(png|jpg|gif).+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)/m,
+            %{#{Xx[:split]}:spaces0:<figure id="fig-\\1">\n:spaces1:<title></title>\n:spaces1:<graphic fileref="../../_sisu/image/\\1.\\2" align="center" width="50%"></graphic>\n:spaces0:</figure>#{Xx[:split]}}). # common image location, else use ./images
+          gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(.+?)#{Mx[:url_c]}/,
+            '<ulink url="\2">\1</ulink>').
+          gsub(/#{Mx[:url_o]}(.+?)#{Mx[:url_c]}/,
+            '<ulink url="\1">\1</ulink>').
+          gsub(/#{Mx[:mk_o]}:name#(\S+?)#{Mx[:mk_c]}/,'<a name="\1"></a>').
+          gsub(/#{Mx[:gl_bullet]}/m,'● '). #&nbsp; not available
+          gsub(/#{Mx[:nbsp]}/,' '). #&nbsp; not available
+          gsub(/<(p|br)>/,'<\1 />')
+        dob.obj=clean(dob.obj)
+      elsif dob.is == :code
+        dob.obj=dob.obj.gsub(/&/m,'&amp;'). #sort
+          gsub(/</,'&lt;').gsub(/>/,'&gt;')
+      else # p dob.is ??
+      end
+      dob
+    end
+    def markup_group(dob='')
+      dob.obj=dob.obj.gsub(/</,'&lt;').gsub(/>/,'&gt;').
+        gsub(/&lt;:?br(?:\s+\/)?&gt;/,'<br>').
+        gsub(/&lt;(link xmlns:xl=".+?")&gt;/,'<\1>').
+        gsub(/&lt;(\/link)&gt;/,'<\1>').
+        gsub(/&lt;(\/?en)&gt;/,'<\1>')
+      dob
+    end
+    def markup_block(dob='')
+      dob.obj=dob.obj.gsub(/</,'&lt;').gsub(/>/,'&gt;').
+        gsub(/&lt;:?br(?:\s+\/)?&gt;/,'<br>').
+        gsub(/&lt;(link xmlns:xl=".+?")&gt;/,'<\1>').
+        gsub(/&lt;(\/link)&gt;/,'<\1>').
+        gsub(/&lt;(\/?en)&gt;/,'<\1>')
+      dob
+    end
+    def xml_sem_block_paired(matched) # colon depth: many, recurs
+      matched=matched.gsub(/\b(au):\{(.+?)\}:\1\b/m,  %{<sem:#{@ab[:au]} depth="many">\\2</sem:#{@ab[:au]}>}).
+        gsub(/\b(vol):\{(.+?)\}:\1\b/m, %{<sem:#{@ab[:vol]} depth="many">\\2</sem:#{@ab[:vol]}>}).
+        gsub(/\b(pub):\{(.+?)\}:\1\b/m, %{<sem:#{@ab[:pub]} depth="many">\\2</sem:#{@ab[:pub]}>}).
+        gsub(/\b(ref):\{(.+?)\}:\1\b/m, %{<sem:#{@ab[:ref]} depth="many">\\2</sem:#{@ab[:ref]}>}).
+        gsub(/\b(desc):\{(.+?)\}:\1\b/m,%{<sem:#{@ab[:desc]} depth="many">\\2</sem:#{@ab[:desc]}>}).
+        gsub(/\b(conv):\{(.+?)\}:\1\b/m,%{<sem:#{@ab[:conv]} depth="many">\\2</sem:#{@ab[:conv]}>}).
+        gsub(/\b(ct):\{(.+?)\}:\1\b/m,  %{<sem:#{@ab[:ct]} depth="many">\\2</sem:#{@ab[:ct]}>}).
+        gsub(/\b(cty):\{(.+?)\}:\1\b/m, %{<sem:#{@ab[:cty]} depth="many">\\2</sem:#{@ab[:cty]}>}).
+        gsub(/\b(org):\{(.+?)\}:\1\b/m, %{<sem:#{@ab[:org]} depth="many">\\2</sem:#{@ab[:org]}>}).
+        gsub(/\b(dt):\{(.+?)\}:\1\b/m,  %{<sem:#{@ab[:dt]} depth="many">\\2</sem:#{@ab[:dt]}>}).
+        gsub(/\b(n):\{(.+?)\}:\1\b/m,   %{<sem:#{@ab[:n]} depth="many">\\2</sem:#{@ab[:n]}>}).
+        gsub(/([a-z]+(?:[_:.][a-z]+)*)(?::\{(.+?)\}:\1)/m,'<sem:\1 depth="many">\2</sem:\1>')
+    end
+    def xml_semantic_tags(dob)
+      if @md.sem_tag
+        dob.obj.gsub!(/([a-z]+(?:[_:.][a-z]+)*)(?::\{(.+?)\}:\1)/m) {|c| xml_sem_block_paired(c) }
+        dob.obj.gsub!(/([a-z]+(?:[_:.][a-z]+)*)(?::\{(.+?)\}:\1)/m) {|c| xml_sem_block_paired(c) }
+        dob.obj.gsub!(/([a-z]+(?:[_:.][a-z]+)*)(?::\{(.+?)\}:\1)/m) {|c| xml_sem_block_paired(c) }
+        dob.obj=dob.obj.gsub(/:\{(.+?)\}:au\b/m,             %{<sem:#{@ab[:au]} depth="one">\\1</sem:#{@ab[:au]}>}).
+          gsub(/:\{(.+?)\}:n\b/m,              %{<sem:#{@ab[:n]} depth="one">\\1</sem:#{@ab[:n]}>}).
+          gsub(/:\{(.+?)\}:ti\b/m,             %{<sem:#{@ab[:ti]} depth="one">\\1</sem:#{@ab[:ti]}>}).
+          gsub(/:\{(.+?)\}:ref\b/m,            %{<sem:#{@ab[:ref]} depth="one">\\1</sem:#{@ab[:ref]}>}).
+          gsub(/:\{(.+?)\}:desc\b/m,           %{<sem:#{@ab[:desc]} depth="one">\\1</sem:#{@ab[:desc]}>}).
+          gsub(/:\{(.+?)\}:cty\b/m,            %{<sem:#{@ab[:cty]} depth="one">\\1</sem:#{@ab[:cty]}>}).
+          gsub(/:\{(.+?)\}:org\b/m,            %{<sem:#{@ab[:org]} depth="one">\\1</sem:#{@ab[:org]}>}).
+          gsub(/:\{(.+?)\}:([a-z]+(?:[_:.][a-z]+)*)/m,'<sem:\2 depth="one">\1</sem:\2>').
+          gsub(/;\{([^}]+(?![;]))\};ti\b/m,    %{<sem:#{@ab[:ti]} depth="zero">\\1</sem:#{@ab[:ti]}>}).
+          gsub(/;\{([^}]+(?![;]))\};qt\b/m,    %{<sem:#{@ab[:qt]} depth="zero">\\1</sem:#{@ab[:qt]}>}).
+          gsub(/;\{([^}]+(?![;]))\};ref\b/m,   %{<sem:#{@ab[:ref]} depth="zero">\\1</sem:#{@ab[:ref]}>}).
+          gsub(/;\{([^}]+(?![;]))\};ed\b/m,    %{<sem:#{@ab[:ed]} depth="zero">\\1</sem:#{@ab[:ed]}>}).
+          gsub(/;\{([^}]+(?![;]))\};v\b/m,     %{<sem:#{@ab[:v]} depth="zero">\\1</sem:#{@ab[:v]}>}).
+          gsub(/;\{([^}]+(?![;]))\};desc\b/m,  %{<sem:#{@ab[:desc]} depth="zero">\\1</sem:#{@ab[:desc]}>}).
+          gsub(/;\{([^}]+(?![;]))\};def\b/m,   %{<sem:#{@ab[:def]} depth="zero">\\1</sem:#{@ab[:def]}>}).
+          gsub(/;\{([^}]+(?![;]))\};trans\b/m, %{<sem:#{@ab[:trans]} depth="zero">\\1</sem:#{@ab[:trans]}>}).
+          gsub(/;\{([^}]+(?![;]))\};y\b/m,     %{<sem:#{@ab[:y]} depth="zero">\\1</sem:#{@ab[:y]}>}).
+          gsub(/;\{([^}]+(?![;]))\};ab\b/m,    %{<sem:#{@ab[:ab]} depth="zero">\\1</sem:#{@ab[:ab]}>}).
+          gsub(/;\{([^}]+(?![;]))\};pg\b/m,    %{<sem:#{@ab[:pg]} depth="zero">\\1</sem:#{@ab[:pg]}>}).
+          gsub(/;\{([^}]+(?![;]))\};fn?\b/m,   %{<sem:#{@ab[:fn]} depth="zero">\\1</sem:#{@ab[:fn]}>}).
+          gsub(/;\{([^}]+(?![;]))\};mn?\b/m,   %{<sem:#{@ab[:mn]} depth="zero">\\1</sem:#{@ab[:mn]}>}).
+          gsub(/;\{([^}]+(?![;]))\};ln?\b/m,   %{<sem:#{@ab[:ln]} depth="zero">\\1</sem:#{@ab[:ln]}>}).
+          gsub(/;\{([^}]+(?![;]))\};in\b/m,    %{<sem:#{@ab[:in]} depth="zero">\\1</sem:#{@ab[:in]}>}).
+          gsub(/;\{([^}]+(?![;]))\};uni\b/m,   %{<sem:#{@ab[:uni]} depth="zero">\\1</sem:#{@ab[:uni]}>}).
+          gsub(/;\{([^}]+(?![;]))\};fac\b/m,   %{<sem:#{@ab[:fac]} depth="zero">\\1</sem:#{@ab[:fac]}>}).
+          gsub(/;\{([^}]+(?![;]))\};inst\b/m,  %{<sem:#{@ab[:inst]} depth="zero">\\1</sem:#{@ab[:inst]}>}).
+          gsub(/;\{([^}]+(?![;]))\};dept\b/m,  %{<sem:#{@ab[:dpt]} depth="zero">\\1</sem:#{@ab[:dept]}>}).
+          gsub(/;\{([^}]+(?![;]))\};org\b/m,   %{<sem:#{@ab[:org]} depth="zero">\\1</sem:#{@ab[:org]}>}).
+          gsub(/;\{([^}]+(?![;]))\};com?\b/m,  %{<sem:#{@ab[:com]} depth="zero">\\1</sem:#{@ab[:com]}>}).
+          gsub(/;\{([^}]+(?![;]))\};cty\b/m,   %{<sem:#{@ab[:cty]} depth="zero">\\1</sem:#{@ab[:cty]}>}).
+          gsub(/;\{([^}]+(?![;]))\};([a-z]+(?:[_:.][a-z]+)*)/m,'<sem:\2 depth="zero">\1</sem:\2>')
+      end
+      dob
+    end
+  end
+end
+module SiSU_XML_Tags #Format
+  require_relative 'dp'                                 # dp.rb
+    include SiSU_Param
+  class RDF
+    include SiSU_Parts_JSON
+    def initialize(md='',seg_name=[],tracker=0)
+      @full_title=@subtitle=@author=@subject=@description=@publisher=@contributor=@date=@date_created=@date_issued=@date_available=@date_valid=@date_modified=@type=@format=@identifier=@source=@language=@relation=@coverage=@rights=@copyright=@owner=@keywords=''
+      @md=md
+      @rdfurl=%{  rdf:about="http://www.jus.uio.no/lm/toc"\n}
+      if defined? @md.title.full \
+      and @md.title.full                          # DublinCore 1 - title
+        @rdf_title=%{    dc.title="#{seg_name}#{@md.title.full}"\n}
+        @full_title=%{  <meta name="dc.title" content="#{@md.title.full}" />\n}
+      end
+      if defined? @md.creator.author \
+      and @md.creator.author=~/\S+/                                            # DublinCore 2 - creator/author (author)
+        @rdf_author=%{    dc.author="#{@md.creator.author}"\n}
+        content=meta_content_clean(@md.creator.author)
+        @author=%{  <meta name="dc.author" content="#{content}" />\n}
+      end
+      if defined? @md.publisher \
+      and @md.publisher                                                        # DublinCore 5 - publisher (current copy published by)
+        @rdf_publisher=%{    dc.publisher="#{@md.publisher}"\n}
+        content=meta_content_clean(@md.publisher)
+        @publisher=%{  <meta name="dc.publisher" content="#{content}" />\n}
+      end
+      if defined? @md.creator.contributor \
+      and @md.creator.contributor=~/\S+/                                      # DublinCore 6 - contributor
+        @rdf_contributor=%{    dc.contributor="#{@md.creator.contributor}"\n}
+        content=meta_content_clean(@md.creator.contributor)
+        @contributor=%{  <meta name="dc.contributor" content="#{content}" />\n}
+      end
+      if defined? @md.date.published \
+      and @md.date.published=~/\S+/                                           # DublinCore 7 - date year-mm-dd
+        @rdf_date=%{    dc.date="#{@md.date.published}"\n}
+        @date=%{  <meta name="dc.date" content="#{@md.date.published}" #{@md.date_scheme} />\n} # fix @md.date_scheme
+      end
+      if defined? @md.date.created \
+      and @md.date.created=~/\S+/                                             # DublinCore 7 - date.created year-mm-dd
+        @rdf_date_created=%{    dc.date.created="#{@md.date.created}"\n}
+        @date_created=%{  <meta name="dc.date.created" content="#{@md.date.created}" #{@md.date_scheme} />\n}
+      end
+      if defined? @md.date.issued \
+      and @md.date.issued=~/\S+/                                              # DublinCore 7 - date.issued year-mm-dd
+        @rdf_date_issued=%{    dc.date.issued="#{@md.date.issued}"\n}
+        @date_issued=%{  <meta name="dc.date.issued" content="#{@md.date.issued}" #{@md.date_scheme} />\n}
+      end
+      if defined? @md.date.available \
+      and @md.date.available=~/\S+/                                           # DublinCore 7 - date.available year-mm-dd
+        @rdf_date_available=%{    dc.date.available="#{@md.date.available}"\n}
+        @date_available=%{  <meta name="dc.date.available" content="#{@md.date.available}" #{@md.date_scheme} />\n}
+      end
+      if defined? @md.date.valid \
+      and @md.date.valid=~/\S+/                                               # DublinCore 7 - date.valid year-mm-dd
+        @rdf_date_valid=%{    dc.date.valid="#{@md.date.valid}"\n}
+        @date_valid=%{  <meta name="dc.date.valid" content="#{@md.date.valid}" #{@md.date_scheme} />\n}
+      end
+      if defined? @md.date.modified \
+      and @md.date.modified=~/\S+/                                            # DublinCore 7 - date.modified year-mm-dd
+        @rdf_date_modified=%{    dc.date.modified="#{@md.date.modified}"\n}
+        @date_modified=%{  <meta name="dc.date.modified" content="#{@md.date.modified}" #{@md.date_scheme} />\n}
+      end
+      if defined? @md.rights.all \
+      and @md.rights.all                                                      # DublinCore 15 - rights
+        @rdf_rights=%{    dc.rights="#{@md.rights.all}"\n}
+        content=meta_content_clean(@md.rights.all)
+        @rights=%{  <meta name="dc.rights" content="#{content}" />\n}
+      end
+      if defined? @md.classify.subject \
+      and @md.classify.subject=~/\S+/                                          # DublinCore 3 - subject (us library of congress, eric or udc, or schema???)
+        @rdf_subject=%{    dc.subject="#{@md.classify.subject}"\n}
+        content=meta_content_clean(@md.classify.subject)
+        @subject=%{  <meta name="dc.subject" content="#{content}" />\n}
+      end
+      if defined? @md.notes.description \
+      and @md.notes.description=~/\S+/                                         # DublinCore 4 - description
+        @rdf_description=%{    dc.description="#{@md.notes.description}"\n}
+        content=meta_content_clean(@md.notes.description)
+        @description=%{  <meta name="dc.description" content="#{content}" />\n}
+      end
+      if defined? @md.notes.coverage \
+      and @md.notes.coverage=~/\S+/                                            # DublinCore 14 - coverage
+        @rdf_coverage=%{    dc.coverage="#{@md.notes.coverage}"\n}
+        content=meta_content_clean(@md.notes.coverage)
+        @coverage=%{  <meta name="dc.coverage" content="#{content}" />\n}
+      end
+      if defined? @md.notes.relation \
+      and @md.notes.relation=~/\S+/                                            # DublinCore 13 - relation
+        @rdf_relation=%{    dc.relation="#{@md.notes.relation}"\n}
+        content=meta_content_clean(@md.notes.relation)
+        @relation=%{  <meta name="dc.relation" content="#{content}" />\n}
+      end
+      if defined? @md.notes.type \
+      and @md.notes.type                                                       # DublinCore 8 - type (genre eg. report, convention etc)
+        @rdf_type=%{    dc.type="#{@md.notes.type}"\n}
+        content=meta_content_clean(@md.notes.type)
+        @type=%{  <meta name="dc.type" content="#{content}" />\n}
+      end
+      if defined? @md.notes.format \
+      and @md.notes.format=~/\S+/                                              # DublinCore 9 - format (use your mime type)
+        @rdf_format=%{    dc.format="#{@md.notes.format}"\n}
+        content=meta_content_clean(@md.notes.format)
+        @format=%{  <meta name="dc.format" content="#{content}" />\n}
+      end
+      #if defined? @md.identifier.sisupod \
+      #and @md.identifier.sisupod=~/\S+/                                       # DublinCore 10 - identifier (your identifier, could use urn which is free)
+      #  @rdf_identifier=%{    dc.identifier="#{@md.identifier.sisupod}"\n}
+      #  content=meta_content_clean(@md.identifier.sisupod)
+      #  @identifier=%{  <meta name="dc.identifier" content="#{content}" />\n}
+      #end
+      if defined? @md.original.source \
+      and @md.original.source=~/\S+/                                           # DublinCore 11 - source (document source)
+        @rdf_source=%{    dc.source="#{@md.original.source}"\n}
+        content=meta_content_clean(@md.original.source)
+        @source=%{  <meta name="dc.source" content="#{content}" />\n}
+      end
+      if defined? @md.title.language \
+      and @md.title.language=~/\S+/                                            # DublinCore 12 - language (English)
+        @rdf_language=%{    dc.language="#{@md.title.language}"\n}
+        @language=%{  <meta name="dc.language" content="#{@md.title.language}" />\n}
+      end
+      if defined? @md.original.language \
+      and @md.original.language=~/\S+/
+        @rdf_language_original=%{    dc.language="#{@md.original.language}"\n}
+        @language_original=%{  <meta name="dc.language" content="#{@md.original.language}" />\n}
+      end
+      content=meta_content_clean(@md.keywords)
+      @keywords=%{  <meta name="keywords" content="#{content}" />\n} if @md.keywords
+    end
+    def meta_content_clean(content='')
+      content=if not content.nil?
+        content=content.tr('"',"'").
+           gsub(/&/,'&amp;')
+        content=SiSU_XML_Munge::Trans.new(@md).char_enc.utf8(content)
+      else content
+      end
+    end
+    def rdfseg #segHead
+      rdftoc
+    end
+    def comment_xml(extra='')
+      generator="Generated by: #{@md.project_details.project} #{@md.project_details.version} of #{@md.project_details.date_stamp} (#{@md.project_details.date})"  if @md.project_details.version
+      lastdone="Last Generated on: #{Time.now}"
+      rubyv="Ruby version: #{@md.ruby_version}"
+      sc=if @md.sc_info
+        "Source file: #{@md.sc_filename} version: #{@md.sc_number} of: #{@md.sc_date}"
+      else ''
+      end
+      if extra.empty?
+<<WOK
+<!-- Document processing information:
+     * #{generator}
+     * #{rubyv}
+     * #{sc}
+     * #{lastdone}
+     * SiSU http://www.jus.uio.no/sisu
+-->
+WOK
+     else
+<<WOK
+<!-- Document processing information:
+     * #{extra}
+     * #{generator}
+     * #{rubyv}
+     * #{sc}
+     * #{lastdone}
+     * SiSU http://www.jus.uio.no/sisu
+-->
+WOK
+      end
+    end
+    def comment_xml_sax
+      desc='SiSU XML, SAX type representation'
+      comment_xml(desc)
+    end
+    def comment_xml_node
+      desc='SiSU XML, Node type representation'
+      comment_xml(desc)
+    end
+    def comment_xml_dom
+      desc='SiSU XML, DOM type representation'
+      comment_xml(desc)
+    end
+    def metatag_html #values strung together, because some empty, and resulting output (line breaks) is much better
+<<WOK
+#{@full_title}#{@subtitle}#{@author}#{@subject}#{@description}#{@publisher}#{@contributor}#{@date}#{@date_created}#{@date_issued}#{@date_available}#{@date_valid}#{@date_modified}#{@type}#{@format}#{@identifier}#{@source}#{@language}#{@relation}#{@coverage}#{@rights}#{@copyright}#{@owner}
+#{SiSU_Proj_XML::Bits.new.txt_generator}
+#{the_png.ico}
+WOK
+    end
+  end
+end
+module SiSU_JSON_Shared
+  require_relative 'xhtml_table'                        # xhtml_table.rb
+  class TableJSON < SiSU_XHTML_Table::TableXHTML
+  end
+end
+__END__
+#+END_SRC
+
+* json_format.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/json_format.rb"
+# <<sisu_document_header>>
+module SiSU_JSON_Format
+  require_relative 'dp'                                 # dp.rb
+  require_relative 'json_parts'                         # json_parts.rb
+  include SiSU_Param
+  class ParagraphNumber
+    def initialize(md,paranum)
+      @md=md
+      @paranum=(paranum \
+      ? (/(\d+)/m.match(paranum)[1])
+      : nil)
+    end
+    def display
+      p_num_display=if @paranum
+        @paranum.gsub(/(\d+)/,
+        '<font size="1" color="#777777">' +
+        '&nbsp;&nbsp;\1</font>')
+      else ''
+      end
+      p_num_display
+    end
+    def name
+      p_num_name=@paranum.gsub(/(\d+)/,'<a name="\1"></a>')
+      p_num_name
+    end
+    def goto
+      p_num_goto=@paranum.gsub(/(\d+)/,'<a href="#\1">')
+      p_num_goto
+    end
+  end
+  class HeadInformation
+    include SiSU_Parts_JSON
+    def initialize #dc rdf
+      @full_title=@subtitle=@author=@subject=@description=@publisher=@contributor=@date=@type=@format=@identifier=@source=@language=@relation=@coverage=@rights=@copyright=@owner=@keywords=''
+      @md=@@md
+      # DublinCore 1 - title
+      @rdfurl=%{  rdf:about="http://www.jus.uio.no/lm/toc"\n}
+      if defined? @md.title.full \
+      and @md.title.full                                                      # DublinCore 1 - title
+        @rdf_title=%{    dc.title="#{seg_name}#{@md.title.full}"\n}
+        @full_title=%{<meta name="dc.title" content="#{seg_name}#{@md.title.full}" />\n}
+      end
+      if defined? @md.creator.author \
+      and @md.creator.author                                                  # DublinCore 2 - creator/author (author)
+        @rdf_author=%{    dc.author="#{@md.creator.author}"\n}
+        @author=%{<meta name="dc.author" content="#{@md.creator.author}" />\n}
+      end
+      if defined? @md.classify.subject \
+      and @md.classify.subject=~/\S+/                                          # DublinCore 3 - subject (us library of congress, eric or udc, or schema???)
+        @rdf_subject=%{    dc.subject="#{@md.classify.subject}"\n}
+        @subject=%{<meta name="dc.subject" content="#{@md.classify.subject}" />\n}
+      end
+      if defined? @md.notes.description \
+      and @md.notes.description=~/\S+/                                        # DublinCore 4 - description
+        @rdf_description=%{    dc.description="#{@md.notes.description}"\n}
+        @description=%{<meta name="dc.description" content="#{@md.notes.description}" />\n}
+      end
+      if defined? @md.publisher \
+      and @md.publisher=~/\S+/                                                # DublinCore 5 - publisher (current copy published by)
+        @rdf_publisher=%{    dc.publisher="#{@md.publisher}"\n}
+        @publisher=%{<meta name="dc.publisher" content="#{@md.publisher}" />\n}
+      end
+      if defined? @md.creator.contributor \
+      and @md.creator.contributor=~/\S+/                                      # DublinCore 6 - contributor
+        @rdf_contributor=%{    dc.contributor="#{@md.creator.contributor}"\n}
+        @contributor=%{<meta name="dc.contributor" content="#{@md.creator.contributor}" />\n}
+      end
+      if defined? @md.date.published \
+      and @md.date.published                                                  # DublinCore 7 - date year-mm-dd
+        @rdf_date=%{    dc.date="#{@md.date.published}"\n}
+        @date=%{<meta name="dc.date" content="#{@md.date.published}" #{@md.date_scheme} />\n}
+      end
+      if defined? @md.date.created \
+      and @md.date.created                                                    # DublinCore 7 - date.created year-mm-dd
+        @rdf_date_created=%{    dc.date.created="#{@md.date.created}"\n}
+        @date_created=%{<meta name="dc.date.created" content="#{@md.date.created}" #{@md.date_created_scheme} />\n}
+      end
+      if defined? @md.date.issued \
+      and @md.date.issued                                                      # DublinCore 7 - date.issued year-mm-dd
+        @rdf_date_issued=%{    dc.date.issued="#{@md.date.issued}"\n}
+        @date_issued=%{<meta name="dc.date.issued" content="#{@md.date.issued}" #{@md.date_issued_scheme} />\n}
+      end
+      if defined? @md.date.available \
+      and @md.date.available                                                  # DublinCore 7 - date.available year-mm-dd
+        @rdf_date_available=%{    dc.date.available="#{@md.date.available}"\n}
+        @date_available=%{<meta name="dc.date.available" content="#{@md.date.available}" #{@md.date_available_scheme} />\n}
+      end
+      if defined? @md.date.valid \
+      and @md.date.valid                                                      # DublinCore 7 - date.valid year-mm-dd
+        @rdf_date_valid=%{    dc.date.valid="#{@md.date.valid}"\n}
+        @date_valid=%{<meta name="dc.date.valid" content="#{@md.date.valid}" #{@md.date_valid_scheme} />\n}
+      end
+      if defined? @md.date.modified \
+      and @md.date.modified                                                   # DublinCore 7 - date.modified year-mm-dd
+        @rdf_date_modified=%{    dc.date.modified="#{@md.date.modified}"\n}
+        @date_modified=%{<meta name="dc.date.modified" content="#{@md.date.modified}" #{@md.date_modified_scheme} />\n}
+      end
+      if defined? @md.notes.coverage \
+      and @md.notes.coverage=~/\S+/                                        # DublinCore 14 - coverage
+        @rdf_coverage=%{    dc.coverage="#{@md.notes.coverage}"\n}
+        @coverage=%{<meta name="dc.coverage" content="#{@md.notes.coverage}" />\n}
+      end
+      if defined? @md.notes.relation \
+      and @md.notes.relation=~/\S+/                                         # DublinCore 13 - relation
+        @rdf_relation=%{    dc.relation="#{@md.notes.relation}"\n}
+        @relation=%{<meta name="dc.relation" content="#{@md.notes.relation}" />\n}
+      end
+      if defined? @md.notes.type \
+      and @md.notes.type                                                            # DublinCore 8 - type (genre eg. report, convention etc)
+        @rdf_type=%{    dc.type="#{@md.notes.type}"\n}
+        @type=%{<meta name="dc.type" content="#{@md.notes.type}" />\n}
+      end
+      if defined? @md.notes.format \
+      and @md.notes.format=~/\S+/                                              # DublinCore 9 - format (use your mime type)
+        @rdf_format=%{    dc.format="#{@md.notes.format}"\n}
+        @format=%{<meta name="dc.format" content="#{@md.notes.format}" />\n}
+      end
+      #if defined? @md.identifier.sisupod \
+      #and @md.identifier.sisupod=~/\S+/                                       # DublinCore 10 - identifier (your identifier, could use urn which is free)
+      #  @rdf_identifier=%{    dc.identifier="#{@md.identifier.sisupod}"\n}
+      #  @identifier=%{<meta name="dc.identifier" content="#{@md.identifier.sisupod}" />\n}
+      #end
+      if defined? @md.original.source \
+      and @md.original.source=~/\S+/                                           # DublinCore 11 - source (document source)
+        @rdf_source=%{    dc.source="#{@md.original.source}"\n}
+        @source=%{<meta name="dc.source" content="#{@md.source}" />\n}
+      end
+      if defined? @md.original.language \
+      and @md.original.language=~/\S+/                                         # DublinCore 12 - language (English)
+        @rdf_language=%{    dc.language="#{@md.original.title}"\n}
+        @language=%{<meta name="dc.language" content="#{@md.language[:name]}" />\n}
+      end
+      if defined? @md.rights.all \
+      and @md.rights.all=~/\S+/                                               # DublinCore 15 - rights
+        rights=meta_content_clean(@md.rights.all)
+        copyright=meta_content_clean(@md.rights.copyright.all)
+        @rdf_rights=%{    dc.rights="#{rights}"\n}
+        @rights=%{<meta name="dc.rights" content="#{rights}" />\n}
+      end
+      @copyright=%{<meta name="copyright" content="#{copyright}" />\n} \
+        if @md.rights.copyright.all # possibly redundant see dc.rights
+      @owner=%{<meta name="owner" content="#{@md.owner}" />\n} if @md.owner
+      @keywords=%{<meta name="keywords" content="#{@md.keywords}" />\n} if @md.keywords
+      @index='index'
+    end
+    def meta_content_clean(content='')
+      content=if not content.nil?
+        content=content.tr('"',"'").
+           gsub(/&/,'&amp;')
+        content=SiSU_XML_Munge::Trans.new(@md).char_enc.utf8(content)
+      else content
+      end
+    end
+    def table_close
+      '</font> </td></tr></table>'
+    end
+    def toc_head
+      <<WOK
+<html>
+<head>
+<title>#{@md.html_title}</title>
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+         xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <rdf:Description
+#{@rdfurl}
+#{@rdf_title}
+#{@rdf_subtitle}
+#{@rdf_author}
+#{@rdf_subject}
+#{@rdf_description}
+#{@rdf_publisher}
+#{@rdf_contributor}
+#{@rdf_date}
+#{@rdf_date_created}
+#{@rdf_date_issued}
+#{@rdf_date_available}
+#{@rdf_date_valid}
+#{@rdf_date_modified}
+#{@rdf_type}
+#{@rdf_format}
+#{@rdf_identifier}
+#{@rdf_source}
+#{@rdf_language}
+#{@rdf_relation}
+#{@rdf_coverage}
+#{@rdf_rights}
+  />
+</rdf:RDF>
+#{@full_title}
+#{@author}
+#{@subject}
+#{@description}
+#{@publisher}
+#{@contributor}
+#{@date}
+#{@date_created}
+#{@date_issued}
+#{@date_available}
+#{@date_valid}
+#{@date_modified}
+#{@type}
+#{@format}
+#{@identifier}
+#{@source}
+#{@language}
+#{@relation}
+#{@coverage}
+#{@rights}
+#{@copyright}
+#{@owner}
+#{@png.ico}
+#{@txt.generator}
+#{@js.head}
+\n</head>
+#{@color.body}
+#{@font.css_table_file}
+<a name="top"></a>
+<a name="up"></a>
+<a name="start"></a>
+#{@js.top}
+WOK
+    end
+  end
+  class ParagraphNumber
+    def initialize(md,ocn)
+      @md,@ocn=md,ocn.to_s
+      @ocn ||=''
+    end
+    def ocn_display
+      @make=SiSU_Env::ProcessingSettings.new(@md)
+      if @make.build.ocn?
+        ocn_class='ocn'
+        if @ocn.to_i==0
+          @ocn.gsub(/^(\d+|)$/,
+            %{<label class="#{ocn_class}"><a name="#{@ocn}">&nbsp;</a></label>})
+        else
+          @ocn.gsub(/^(\d+|)$/,
+            %{<label class="#{ocn_class}"><a name="#{@ocn}">\\1</a></label>})
+        end
+      else
+        ocn_class='ocn_off'
+        @ocn.gsub(/^(\d+|)$/,
+          %{<label class="#{ocn_class}">&nbsp;</label>})
+      end
+    end
+    def name
+      %{<a name="#{@ocn}"></a>}
+    end
+    def id #w3c? "tidy" complains about numbers as identifiers ! annoying
+      %{id="o#{@ocn}"}
+    end
+    def goto
+      %{<a href="##{@ocn}">}
+    end
+  end
+  class FormatTextObject
+    include SiSU_Parts_JSON
+    attr_accessor :md,:dob,:txt,:ocn,:format,:table,:link,:linkname,:paranum,:p_num,:headname,:banner,:url
+    def initialize(md,t_o)
+      @md,@t_o=md,t_o
+      if t_o.class.inspect =~/Object/
+        @txt=if defined? t_o.obj; t_o.obj
+        else nil
+        end
+        @ocn=if defined? t_o.ocn; t_o.ocn.to_s
+        else nil
+        end
+        @headname=if t_o.is==:heading and defined? t_o.name; t_o.name
+        else nil
+        end
+      else
+        if @md.opt.act[:maintenance][:set]==:on
+          p __FILE__ << ':' << __LINE__.to_s
+          p t_o.class
+          p caller
+        end
+      end
+      if defined? @t_o.ocn
+        ocn=((@t_o.ocn.to_s =~/\d+/) ? @t_o.ocn : nil)
+        @p_num=ParagraphNumber.new(@md,ocn)
+      end
+      if @format and not @format.empty?
+        if @format=~/^\d:(\S+)/ #need more reliable marker #if @format =~ /#{Rx[:lv]}/
+          headname=$1 #format[/\d~(\S+)/m,1]
+          @headname=if headname =~/^[a-zA-Z]/; %{<a name="#{headname}" id="#{headname}"></a>} #consider: h_#{headname}
+          else %{<a name="h#{headname}" id="h#{headname}"></a>}
+          end
+        end
+      end
+      @dob=t_o if defined? t_o.is
+    end
+    def para
+      para_form_css('p','norm')
+    end
+    def code
+      para_form_css('p','code')
+    end
+    def center
+      para_form_css('p','center')
+    end
+    def bold
+      para_form_css('p','bold')
+    end
+    def bullet
+      para_form_css('li','bullet')
+    end
+    def format(tag,attrib)
+      para_form_css(tag,attrib)
+    end
+    def heading_normal(tag,attrib)
+      %{
+<div class="substance">
+  #{@p_num.ocn_display}
+  <#{tag} class="#{attrib}" #{@p_num.id}>#{@p_num.name}
+    #{@headname}#{@txt}
+  </#{tag}>
+</div>
+}
+    end
+    def heading_body
+      heading_normal('p','norm')
+    end
+    def heading_body0
+      heading_normal('h1','norm')
+    end
+    def heading_body1
+      heading_normal('h1','norm')
+    end
+    def heading_body2
+      heading_normal('h2','norm')
+    end
+    def heading_body3
+      heading_normal('h3','norm')
+    end
+    def heading_body4
+      heading_normal('h4','norm')
+    end
+    def heading_body5
+      heading_normal('h5','norm')
+    end
+    def heading_body6
+      heading_normal('h6','norm')
+    end
+    def heading_body7
+      heading_normal('h7','norm')
+    end
+    def title_header(tag,attrib)
+      %{
+<div class="content">
+<#{tag} class="#{attrib}">
+    #{@txt}
+  </#{tag}>
+</div>
+}
+    end
+    def title_header1
+      title_header('h1','tiny')
+    end
+    def title_header2
+      title_header('h2','tiny')
+    end
+    def title_header3
+      title_header('h3','tiny')
+    end
+    def title_header4
+      ''
+    end
+    def dl #check :trailer
+      "<dl><b>#{@txt}</b> #{@trailer}</dl>"
+    end
+    def table_css_end      #<!TZ!>
+      '</table>
+    </p>
+  </div>'
+    end
+    def gsub_body
+#fix
+      @txt=case @txt
+      when /^\s*\((i+|iv|v|vi+|ix|x|xi+)\)/
+        @txt.gsub(/^\((i+|iv|v|vi+|ix|x|xi+)\)/,'<b>(\1)</b>').
+          gsub(/^(#{Mx[:pa_o]}i[1-9]#{Mx[:pa_c]})\s*\((i+|iv|v|vi+|ix|x|xi+)\)/,'\1<b>(\2)</b>')
+      when /^\s*\(?(\d|[a-z])+\)/
+        @txt.gsub(/^\((\d+|[a-z])+\)/,'<b>(\1)</b>').
+          gsub(/^(#{Mx[:pa_o]}i[1-9]#{Mx[:pa_c]})\s*\((\d+|[a-z])+\)/,'\1<b>(\2)</b>')
+      when /^\s*\d{1,3}\.\s/
+        @txt.gsub(/^\s*(\d+\.)/,'<b>\1</b>')
+      when /^\s*[A-Z]\.\s/
+        @txt.gsub(/^\s*([A-Z]\.)/,'<b>\1</b>')
+      else @txt
+      end
+    end
+    def bold_para
+      %{#{the_margin.txt_0}
+  <p class="bold">
+    #{@txt}
+  </p>
+#{the_margin.num_css}
+  &nbsp;&nbsp;&nbsp;
+#{the_table_close}}
+    end
+    def bold_header
+      @txt=@txt.gsub(/[1-9]~(\S+)/,'<a name="\1"></a>').
+        gsub(/[1-9]~/,'')
+      %{<p class="bold">
+    #{@txt}
+  </p>
+#{the_margin.num_css}
+  &nbsp;&nbsp;&nbsp;
+#{the_table_close}}
+    end
+    def toc_head_copy_at
+      %{<p class="center">#{@txt}</p>\n}
+    end
+    def center
+      %{<p class="center">#{@txt}</p>\n}
+    end
+    def bold
+      %{<p class="bold">#{@txt}</p>\n}
+    end
+    def center_bold
+      %{<p class="centerbold">#{@txt}</p>\n}
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* json_persist.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/json_persist.rb"
+# <<sisu_document_header>>
+module SiSU_JSON_Persist
+  class Persist
+    @@persist=nil
+    attr_accessor :head,:toc,:body,:tail,:open,:close,:sc,:endnotes,:book_idx,:metadata
+    #attr_accessor :head,:body,:tail,:open,:close,:sc
+#@@odf={ body: [], head: [], toc: [],  metadata: [], tail: [], book_idx: [], endnotes: [] }
+    def initialize(args=nil)
+      @@persist=args=(args ? args : (@@persist || persist_init_hash_values))
+      @head=args[:head]
+      @toc=args[:toc]
+      @body=args[:body]
+      @tail=args[:tail]
+      @open=args[:open]
+      @close=args[:close]
+      @sc=args[:sc]
+      @endnotes=args[:endnotes]
+      @book_idx=args[:book_idx]
+      @metadata=args[:metadata]
+    end
+    def head
+      @head
+    end
+    def toc
+      @toc
+    end
+    def body
+      @body
+    end
+    def tail
+      @tail
+    end
+    def open
+      @open
+    end
+    def close
+      @close
+    end
+    def sc
+      @sc
+    end
+    def endnotes
+      @endnotes
+    end
+    def book_idx
+      @book_idx
+    end
+    def metadata
+      @metadata
+    end
+    def persist_init_hash_values
+      {
+        head: [],
+        toc: [],
+        body: [],
+        tail: [],
+        open: [],
+        close: [],
+        sc: [],
+        endnotes: [],
+        book_idx: [],
+        metadata: [],
+      }
+    end
+    def persist_init
+      @@persist=nil
+      Persist.new(persist_init_hash_values)
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    json
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/manpage.org b/org/manpage.org
new file mode 100644
index 00000000..67c3efc9
--- /dev/null
+++ b/org/manpage.org
@@ -0,0 +1,436 @@
+-*- mode: org -*-
+#+TITLE:       sisu manpage
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:manpage:
+#+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
+
+* manpage.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/manpage.rb"
+# <<sisu_document_header>>
+module SiSU_Manpage
+  require_relative 'ao'                                 # ao.rb
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  include SiSU_Param
+  require_relative 'manpage_format'                     # manpage_format.rb
+    include SiSU_ManpageFormat
+  require_relative 'shared_metadata'                    # shared_metadata.rb
+  require_relative 'generic_parts'                      # generic_parts.rb
+  require_relative 'txt_read'                           # txt_read.rb
+  require_relative 'txt_output'                         # txt_output.rb
+  require_relative 'txt_shared'                         # txt_shared.rb
+  @@alt_id_count,@@alt_id_count=0,0
+  @@tablefoot=''
+  class Source
+    include SiSU_Txt_Read
+    def initialize(opt)
+      @opt=opt
+      if @opt.fns =~/(.+?)\.(?:-|ssm\.)?sst$/
+        @@notes=:end
+      else
+        puts "#{sf} not a processed file type"
+      end
+    end
+    def read
+      begin
+        md=SiSU_Param::Parameters.new(@opt).get
+        specific={
+          description:     'Manpage',
+          output_path:     md.file.output_path.manpage.dir,
+          output_file:     md.file.base_filename.manpage,
+        }
+        read_generic(@opt,specific)
+        SiSU_Manpage::Source::Scroll.new(md,@ao_array,@wrap_width).songsheet
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        Dir.chdir(@opt.f_pth[:pth])
+      end
+    end
+    private
+    class Scroll <Source
+      include SiSU_Parts_Generic
+      include SiSU_TextUtils
+      @@endnotes={ para: [], end: [] }
+      def initialize(md,data,wrap_width)
+        @md,@data,@wrap_width=md,data,wrap_width
+        @tab="\t"
+        @@notes=:end
+        @manpage={ body: [], open: [], close: [], head: [], metadata: [], tail: [], endnotes: [] }
+      end
+      def songsheet
+        manpage=markup(@data)
+        publish(manpage)
+      end
+      def break_line
+        "\n"
+      end
+      # Used for extraction of endnotes from paragraphs
+      def extract_endnotes(dob='')
+        para=dob.obj.gsub(/#{Mx[:br_line]}/,"\n")
+        notes=para.scan(/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})([\d*+]+(?:\s|\n)+.+?)(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/m)
+        @n=[]
+        notes.flatten.each do |n| #high cost to deal with <br> appropriately within manpage, consider
+          n=n.dup.to_s
+          if n =~/#{Mx[:br_line]}|#{Mx[:br_nl]}/
+            fix = n.split(/#{Mx[:br_line]}|#{Mx[:br_nl]}/) #watch #added
+            fix.each do |x|
+              unless x.empty?; @n << x
+              end
+            end
+          else                 @n << n
+          end
+        end
+        notes=@n.flatten
+        notes.each do |e|
+          util=(e.to_s =~/^\[[\d*+]+\]:/) \
+          ? (SiSU_TextUtils::Wrap.new(e.to_s,@wrap_width,4,1))
+          : (SiSU_TextUtils::Wrap.new(e.to_s,@wrap_width,0,1))
+          wrap=util.line_wrap
+          wrap=if wrap =~ /^\s*[\d*+]+\s+.+?\s*\Z/m
+            wrap.gsub(/(^|&nbsp;|#{Mx[:nbsp]}|\s|\*)\\\*/,'\1\\\\\*'). #man page requires
+              gsub(/\s(.[BI])\s/,' ').
+              gsub(/\s\.(\S+)/,' \\.\1').
+              gsub(/^\s*([\d*+]+)\s+(.+?)\s*\Z/m, <<GSUB
+.TP
+.BI \\1.
+\\2
+GSUB
+                      )
+          else
+            wrap.gsub(/^\s*(.+)\Z/m, <<GSUB
+\\1
+GSUB
+                      )
+          end
+          @@endnotes[:para] << wrap
+          @@endnotes[:end] << wrap << "\n.BR"
+          @@endnotes
+        end
+      end
+      def manpage_metadata
+        @manpage[:metadata]=SiSU_Metadata::Summary.new(@md).manpage.metadata
+      end
+      def manpage_tail
+        @manpage[:tail] <<<<WOK
+#{break_line}
+.TP
+.SH SEE ALSO
+       sisu(1),
+       sisu-epub(1),
+       sisu-harvest(1),
+       sisu-html(1),
+       sisu-odf(1),
+       sisu-pdf(1),
+       sisu-pg(1),
+       sisu-sqlite(1),
+       sisu-txt(1).
+       sisu_vim(7)
+.TP
+.SH HOMEPAGE
+       More information about SiSU can be found at <http://www.sisudoc.org/> or <http://www.jus.uio.no/sisu/>
+.TP
+.SH SOURCE
+       <http://git.sisudoc.org/>
+.TP
+.SH AUTHOR
+       SiSU is written by Ralph Amissah [ralph@amissah.com]
+WOK
+      end
+      def manpage_structure(dob='',hname='') #% Used to extract the structure of a document
+        if dob.is==:heading
+          lv=dob.ln
+          dob.ln + 2
+        else lv=nil
+        end
+        wrapped=if dob.is==:para \
+        || dob.is==:heading
+          paragraph=dob.obj
+          if dob.is==:para
+            if dob.indent =~/[1-9]/ \
+            and dob.indent == dob.hang
+              util=if dob.bullet_
+                SiSU_TextUtils::Wrap.new("* #{paragraph}",@wrap_width,dob.indent.to_i*2)
+              else SiSU_TextUtils::Wrap.new(paragraph,@wrap_width,dob.indent.to_i*2)
+              end
+            elsif dob.hang =~/[0-9]/ \
+            and dob.indent != dob.hang                     # NOT yet implemented
+              util=SiSU_TextUtils::Wrap.new(paragraph,@wrap_width,dob.indent.to_i*2)
+            else
+              util=if dob.bullet_
+                SiSU_TextUtils::Wrap.new("* #{paragraph}",@wrap_width,0)
+              else SiSU_TextUtils::Wrap.new(paragraph,@wrap_width,0)
+              end
+            end
+          else util=SiSU_TextUtils::Wrap.new(paragraph,@wrap_width,0)
+          end
+          w=util.line_wrap
+          w=w.gsub(/^(\\\.)/,' \1')
+          w
+        end
+        if lv
+          times=wrapped.length
+          times=@wrap_width if times > @wrap_width
+          @manpage[:body] << case lv
+          when 0    then '.SH ' << wrapped.upcase << break_line << break_line
+          when 1..3 then '.SH ' << wrapped.upcase << break_line << break_line
+          when 4    then '.SH ' << wrapped.upcase << break_line << break_line
+          when 5..6 then '.SH ' << wrapped.upcase << break_line << break_line
+          end
+        else
+          @manpage[:body] << if  wrapped =~/^\.BI\s/ # main text, contents, body KEEP
+            '.TP' << break_line << wrapped.gsub(/(^\.B)I\s/,'\1 ') # sleight ... simpler output (check gsub!)
+          else
+            break_line + '.BR' + break_line << wrapped
+          end
+        end
+        if @@endnotes[:para] \
+        and @@notes==:foot #edit out to switch off endnotes following paragraph to which they belong
+          @@endnotes[:para].each { |e| @manpage[:body] << e << break_line }
+        elsif @@endnotes[:para] \
+        and @@notes==:end
+        end
+        @@endnotes[:para]=[]
+      end
+      def markup(data)                                                       # Used for major markup instructions
+        SiSU_Env::InfoEnv.new(@md.fns)
+        @data_mod,@endnotes,@level,@cont,@copen,@manpage_contents_close=Array.new(6){[]}
+        (0..6).each { |x| @cont[x]=@level[x]=false }
+        (4..6).each { |x| @manpage_contents_close[x]='' }
+        #manpage_tail # stop call
+        table_message='[table omitted, see other document formats]'
+        #manpage_metadata
+        data.each do |dob|
+          if dob.is==:comment \
+          || dob.is==:heading_insert
+            dob.obj=''
+          end
+          dob.obj=dob.obj.gsub(/.+?<-#>/,'').                                           # remove dummy headings (used by html) #check
+            gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'^\1^').
+            gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'[\1]').
+            gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'++\1++').
+            gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'--\1--').
+            gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'"\1"').
+            gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,'\1').
+            gsub(/\A\s*#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}#{Mx[:br_line]}([,.:!?](?: |$))?/m,
+              "#{Mx[:br_line]}.I \\1\\2#{Mx[:br_line]}").
+            gsub(/\s*#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}([,.:!?](?: |$))?/m,
+              "#{Mx[:br_line]}.I \\1\\2#{Mx[:br_line]}").
+            gsub(/\A\s*#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}([,.:!?](?: |$))?#{Mx[:br_line]}/m,
+              "\n.BI \\1\\2#{Mx[:br_line]}").
+            gsub(/\s*#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}([,.:!?](?: |$))?/m,
+              "#{Mx[:br_line]}.B \\1\\2#{Mx[:br_line]}").
+            gsub(/\s*#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}([,.:!?](?: |$))?/,
+              "\n.I \\1\\2#{Mx[:br_line]}")
+          unless dob.is==:code
+            dob.obj=dob.obj.gsub(/(?:^|\s)#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}([,.:!?](?: |$))?/,
+                "\\1 #{the_text.url_open}\\2#{the_text.url_close}\\3").
+              gsub(/(^|#{Mx[:gl_c]}|\s)#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}([,.:!?](?: |$))?/,
+                "\\1#{the_text.url_open}\\2#{the_text.url_close}\\3")
+            @manpage[:endnotes]=extract_endnotes(dob)
+            dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}([\d*+]+)\s*(?:.+?)#{Mx[:en_a_c]}/m,'[^\1]'). # endnote marker marked up
+              gsub(/#{Mx[:en_b_o]}([\d*+]+)\s*(?:.+?)#{Mx[:en_b_c]}/m,'[^\1]'). # endnote marker marked up
+              gsub(/#{Mx[:gl_o]}#amp#{Mx[:gl_c]}/,'&'). ##{Mx[:gl_o]}#095#{Mx[:gl_c]}
+              gsub(/#{Mx[:gl_o]}#033#{Mx[:gl_c]}/,'!').
+              gsub(/#{Mx[:gl_o]}#035#{Mx[:gl_c]}/,'#').
+              gsub(/#{Mx[:gl_o]}#042#{Mx[:gl_c]}/,'*').
+              gsub(/#{Mx[:gl_o]}#045#{Mx[:gl_c]}/,'-').
+              gsub(/#{Mx[:gl_o]}#092#{Mx[:gl_c]}/,'\e').
+              gsub(/#{Mx[:gl_o]}#047#{Mx[:gl_c]}/,'/').
+              gsub(/#{Mx[:gl_o]}#095#{Mx[:gl_c]}/,'_').
+              gsub(/#{Mx[:gl_o]}#123#{Mx[:gl_c]}/,'{').
+              gsub(/#{Mx[:gl_o]}#125#{Mx[:gl_c]}/,'}').
+              gsub(/#{Mx[:gl_o]}#126#{Mx[:gl_c]}/,'~').
+              gsub(/#{Mx[:gl_o]}#169#{Mx[:gl_c]}/,'©')
+          else
+            dob.obj=dob.obj.gsub(/\\/,'\e').
+              gsub(/(?:#{Mx[:br_line]}|#{Mx[:br_nl]})\s*/,"\n")                          # watch
+          end
+          dob.obj=dob.obj.gsub(/(^|&nbsp;|#{Mx[:nbsp]}|\s|\*)\\\*/,'\1\\\\\*').          #man page requires
+            gsub(/┆/,'|').
+            gsub(/^(\.\S{3,})/m,' \1')                                                   # ^\. used by interpreter, disable when use not intended
+          dob.obj=dob.obj.gsub(/&#126;/,'~') if dob.obj #manpages use this
+          if dob.is ==:code
+            dob.obj=dob.obj.gsub(/(^|[^}])_([<>])/m,'\1\2'). # _> _<
+              gsub(/(^|[^}])_([<>])/m,'\1\2'). # _<_<
+              gsub(/(?:#{Mx[:br_line]}|#{Mx[:br_nl]})+(\s*)/m,"\n\\1").                  # watch
+              gsub(/\A(.+?)\s*\Z/m,".nf\n\\1\n.fi")
+          end
+          dob.obj=dob.obj.gsub(/(?:#{Mx[:br_line]}|#{Mx[:br_nl]})+\s*/m,"\n\n")          # watch
+          dob.obj=dob.obj.gsub(/#{Mx[:gl_o]}:name#\S+?#{Mx[:gl_c]}/mi,'').               #added
+            gsub(/#{Mx[:br_page]}\s*|#{Mx[:br_page_new]}|#{Mx[:br_page_line]}/,'').      # remove page breaks, you may wish to have a line across the page break instead
+            gsub(/(^|#{Mx[:gl_c]}|\s)#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,'\1\2').
+            gsub(/<a href=".+?">(.+?)<\/a>/m,'\1').
+            gsub(/#{Mx[:mk_o]}name#\S+?#{Mx[:mk_c]}/,'').                                # remove name links
+            gsub(/&nbsp;|#{Mx[:nbsp]}/,' ').                                             # decide on
+            gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}\s*(\S+?\.(?:png|jpg|gif)) .+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/,'    [ \1 ]'). #"[ #{dir.url.images_local}\/\\1 ]")
+            gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}\s*(\S+?\.(?:png|jpg|gif)) .+?#{Mx[:lnk_c]}image/,'    [ \1 ]'). #"[ #{dir.url.images_local}\/\\1 ]")
+            gsub(/^(?:^|[^_\\])#{Mx[:lnk_o]}\s*\S+?\.(?:png|jpg|gif)\s+.+?"(.*?)"\s*#{Mx[:lnk_c]}\S+/,'[image: "\1"]')
+          if dob.obj !~/(^#{Rx[:meta]}|#{Mx[:br_eof]}|#{Mx[:br_endnotes]})/
+            if dob.obj =~@regx #/.+?<~\d+;\w\d+;\w\d+>.*/ #watch change
+              paranum=dob.obj[@regx,3]
+              @p_num=SiSU_ManpageFormat::ParagraphNumber.new(paranum)
+            end
+            SiSU_ManpageFormat::FormatTextObject.new(@md,dob) #check
+            if dob.is==:heading
+              manpage_structure(dob)
+            elsif dob.is==:para
+              manpage_structure(dob)
+            else
+              if dob.obj =~/#{table_message}/
+                @manpage[:body] << dob.obj << break_line
+              end
+            end
+            if (dob.obj =~/<a name="n\d+">/ \
+            and dob.obj =~/^(-\{{2}~\d+|<!e[:_]\d+!>)/) # -endnote
+              dob.obj=''
+            end
+            if dob.obj
+              dob.obj=dob.obj.gsub(/(?:#{Mx[:br_line]}|#{Mx[:br_nl]})\s*/,"\n\n").                                   # watch
+                gsub(/#{Mx[:gl_o]}#126#{Mx[:gl_c]}/,'~').
+                gsub(/#{Mx[:gl_o]}#123#{Mx[:gl_c]}/,'{').
+                gsub(/#{Mx[:pa_o]}\S+#{Mx[:pa_c]}/,' ')
+              unless dob.is ==:code
+                dob.obj=dob.obj.gsub(/<!.+!>/,' ').
+                  gsub(/<:\S+>/,' ')
+              end
+            end
+            dob
+          end
+        end
+        @manpage
+      end
+      def publish(manpage)
+        content=[]
+        date=if defined? @md.date.modified \
+        and @md.date.modified
+          @md.date.modified
+        elsif defined? @md.date.published \
+        and @md.date.published
+          @md.date.published
+        else SiSU_Env::InfoDate.new.year #date missing decide on action
+        end
+        proj=SiSU_Env::InfoVersion.instance.get_version
+        manpage[:open] = %{.TH "#{@md.fnb}" "#{@md.make.manpage['section']}" "#{date}" "#{proj.version}" "#{@md.title.main}"#{@md.make.manpage['name']}#{@md.make.manpage['synopsis']}}
+        content << manpage[:open]
+        content << manpage[:head]
+        content << manpage[:body]
+        content << @@endnotes[:end] if @@notes==:end
+        content << manpage[:metadata]
+        content << manpage[:tail]
+        outputfile=SiSU_Env::FileOp.new(@md).write_file.manpage
+        Txt_Output::Output.new.document(content,outputfile)
+        @@endnotes={ para: [], end: [] }
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* manpage_format.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/manpage_format.rb"
+# <<sisu_document_header>>
+module SiSU_ManpageFormat
+  require_relative 'dp'                                 # dp.rb
+    include SiSU_Param
+  class ParagraphNumber
+    def initialize(paranum)
+      @paranum=/(\d+)/m.match(paranum)[1]
+    end
+    def display
+      @paranum.gsub(/(\d+)/,'<font size="1" color="#777777">&nbsp;&nbsp;\1</font>')
+    end
+    def name
+      @paranum.gsub(/(\d+)/,'<a name="\1"></a>')
+    end
+    def goto
+      @paranum.gsub(/(\d+)/,'<a href="#\1">')
+    end
+  end
+  class FormatTextObject
+    def initialize(md,dob)
+      @md,@dob=md,dob
+      rgx=/#{Mx[:en_a_o]}[\d*+]+\s+(.+?)#{Mx[:en_a_c]}/
+      @dob.obj.gsub!(rgx,'\1') if @dob.obj =~rgx
+    end
+    def scr_endnote_body
+      "<endnote>#{@dob.obj}</endnote> "
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    manpage
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/misc.org b/org/misc.org
new file mode 100644
index 00000000..fb212b61
--- /dev/null
+++ b/org/misc.org
@@ -0,0 +1,4107 @@
+-*- mode: org -*-
+#+TITLE:       sisu misc
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:misc:
+#+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
+
+* misc sort
+** air.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/air.rb"
+# <<sisu_document_header>>
+module SiSU_Air
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+  class Source
+    @@ao_array=[]
+    @@fns=nil
+    def initialize(opt)
+      @opt=opt
+      @@fns||@opt.fns
+      @particulars=SiSU_Particulars::Combined.new(opt)
+      #@env=@particulars.env
+      #@md=@particulars.md
+      #@ao_array=@particulars.ao_array
+    end
+    def read
+    end
+  protected
+    def print
+      puts @particulars.md.inspect
+      puts @particulars.env.inspect
+      puts @particulars.ao_array
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** embedded.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/embedded.rb"
+# <<sisu_document_header>>
+module SiSU_Embedded
+  require_relative 'dp'                                 # dp.rb
+    include SiSU_Param
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  class Source
+    def initialize(opt)
+      @opt=opt
+      @md=SiSU_Param::Parameters.new(@opt).get
+      @env=SiSU_Env::InfoEnv.new(@md.fns)
+      @rhost=SiSU_Env::InfoRemote.new(@opt).remote_host_base
+      @base_src_dir=@opt.f_pth[:pth].sub(/\/#{@opt.f_pth[:lng]}$/,'')
+      @f=SiSU_Env::FileOp.new(@md)
+    end
+    def read
+      songsheet
+    end
+    def songsheet
+      images
+      audio
+      multimedia
+      begin
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    def images
+      src="#{@base_src_dir}/_sisu/image"
+      ldest=@env.path.output
+      img_dir="#{@env.path.output}/_sisu/image"
+      @rhost.each do |remote_conn|
+        if (@md.opt.act[:verbose][:set]==:on \
+        || @md.opt.act[:verbose_plus][:set]==:on \
+        || @md.opt.act[:maintenance][:set]==:on \
+        || @md.opt.act[:rsync][:set]==:on) \
+        and FileTest.directory?(src)
+          FileUtils::mkdir_p(img_dir) unless FileTest.directory?(img_dir)
+          src_ec=@f.place_file.images.rel + '/' + @md.ec[:image].join(" #{@f.output_path.images.rel}/")
+          unless @opt.fns =~/\.-sst$/
+            SiSU_Env::SystemCall.new(src_ec,ldest,'q').rsync('--relative',@opt.base_path)
+            #if @md.opt.selections.str.inspect =~/R/ #rsync to remote image directory
+            #  SiSU_Env::SystemCall.new(src_ec,remote_rel,'q').rsync('--relative')
+            #end
+          end
+        end
+      end
+    end
+    def audio
+      #p @md.ec[:audio]
+      src="#{@base_src_dir}/_sisu/mm/audio"
+      ldest="#{@env.path.webserv}/#{@env.path.base_markup_dir_stub}/_sisu/mm/audio"
+      @rhost.each do |remote_conn|
+        rdest="#{remote_conn[:name]}/#{@env.path.base_markup_dir_stub}/_sisu/mm/audio"
+        if (@md.opt.act[:verbose][:set]==:on \
+        || @md.opt.act[:verbose_plus][:set]==:on \
+        || @md.opt.act[:maintenance][:set]==:on \
+        || @md.opt.act[:rsync][:set]==:on) \
+        and FileTest.directory?(src)
+          FileUtils::mkdir_p(ldest) unless FileTest.directory?(ldest)
+          src_ec="#{src}/" + @md.ec[:audio].join(" #{src}/")
+          SiSU_Env::SystemCall.new(src_ec,"#{ldest}/.",'q').rsync
+          if @md.opt.act[:rsync][:set]==:on #rsync to remote audio directory
+            SiSU_Env::SystemCall.new(src_ec,"#{rdest}/.",'q').rsync
+          end
+        end
+      end
+    end
+    def multimedia
+      #p @md.ec[:multimedia]
+      src="#{@base_src_dir}/_sisu/mm/video"
+      ldest="#{@env.path.webserv}/#{@env.path.base_markup_dir_stub}/_sisu/mm/video"
+      @rhost.each do |remote_conn|
+        rdest="#{remote_conn[:name]}/#{@env.path.base_markup_dir_stub}/_sisu/mm/video"
+        if (@md.opt.act[:verbose][:set]==:on \
+        || @md.opt.act[:verbose_plus][:set]==:on \
+        || @md.opt.act[:maintenance][:set]==:on \
+        || @md.opt.act[:rsync][:set]==:on) \
+        and FileTest.directory?(src)
+          FileUtils::mkdir_p(ldest) unless FileTest.directory?(ldest)
+          src_ec="#{src}/" + @md.ec[:multimedia].join(" #{src}/")
+          SiSU_Env::SystemCall.new(src_ec,"#{ldest}/.",'q').rsync
+          if @md.opt.act[:rsync][:set]==:on #rsync to remote video directory
+            SiSU_Env::SystemCall.new(src_ec,"#{rdest}/.",'q').rsync
+          end
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** errors.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/errors.rb"
+# <<sisu_document_header>>
+module SiSU_Errors
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env; include SiSU_Screen
+  class Rescued <CreateFile
+    def initialize(error,errorlist,cmd,fns='')
+      @fns,@cmd,@error,@errorlist=fns,cmd,error,errorlist
+      @cmd=(cmd \
+      && (cmd =~/c/)) \
+      ?  'Vc'
+      : 'V'
+    end
+    def location
+      file=@fns \
+      ? (SiSU_Env::CreateFile.new(@fns).file_error)
+      : (File.new('/tmp/errorlog.sisu','w+'))
+      file << @fns << "\n" << @error << "\n" << @errorlist
+      file.close
+      if @cmd=~/[vVM]/
+        SiSU_Screen::Ansi.new('',$!,$@).rescue do
+          (block_given?) ? yield : __LINE__.to_s + ':' + __FILE__
+        end
+      else
+        SiSU_Screen::Ansi.new('',"rescued, exception raised, silenced").puts_grey
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** git.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/git.rb"
+# <<sisu_document_header>>
+module SiSU_Git
+  require_relative 'dp'                                 # dp.rb
+  require_relative 'se'                                 # se.rb
+  require_relative 'ao'                                 # ao.rb
+  class Source
+    def initialize(opt,process=:complete)
+      @opt,@process=opt,process
+      @env=SiSU_Env::InfoEnv.new
+      @md=SiSU_Param::Parameters.new(@opt).get
+      @file=SiSU_Env::FileOp.new(@md)
+      l=SiSU_Env::StandardiseLanguage.new(@md.opt.lng).language
+      unless @opt.lng==l[:c] # @md.i18n[0]==l[:c]
+        p "using: #{@opt.lng} (@make: :language:); filename #{@md.fns} filename language: #{l[:c]}, mismatch"
+      end
+      if @env.output_dir_structure.multilingual?
+        m=/((.+?)(?:\~\w{2,3})?)\.((?:-|ssm\.)?sst|ssm)$/ #watch added match for sss
+        fnb,fnt=@opt.fns[m,2],@opt.fns[m,3]
+      else m=/(.+?)\.((?:-|ssm\.)?sst|ssm)$/
+        fnb=@fnn=@opt.fns[m,1]
+        fnt=@opt.fns[m,2]
+      end
+      git_path_fnb=@env.processing_path.git + '/' + fnb
+      lng=(@md.opt.lng) ? (@md.opt.lng) : (@md.i18n[0])
+      @git_path={
+        fnb:       git_path_fnb,
+        doc:       git_path_fnb + '/' + Gt[:sisupod] + '/' + Gt[:doc] + '/' + lng,
+        po:        git_path_fnb + '/' + Gt[:po] + '/' + lng,
+        pot:       git_path_fnb + '/' + Gt[:pot],
+        conf:      git_path_fnb + '/' + Gt[:sisupod] + '/' + Gt[:conf],
+        image:     git_path_fnb + '/' + Gt[:sisupod] + '/' + Gt[:image],
+        audio:     git_path_fnb + '/' + Gt[:sisupod] + '/' + Gt[:audio],
+        video:     git_path_fnb + '/' + Gt[:sisupod] + '/' + Gt[:video],
+        conf:      git_path_fnb + '/' + Gt[:sisupod] + '/' + Gt[:conf]
+      }
+      SiSU_AO::Source.new(@opt,nil,@process).read                            # -m
+    end
+    def create_file_structure_git
+      make_dir_fnb
+      if program_found?
+        git_init
+      end
+    end
+    def read
+      create_file_structure_git
+      populate.sisusrc_files
+      #if program_found?
+      #  git_commit
+      #end
+      unless @opt.act[:quiet][:set]==:on
+        (@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on) \
+        ? SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'Git path',
+            @git_path[:fnb]
+          ).green_hi_blue
+        : SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'Git path',
+            @git_path[:fnb]
+          ).green_title_hi
+        if (@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on)
+          SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            "Git path",
+            "#{@opt.fns} -> #{@git_path[:fnb]}"
+          ).warn
+        end
+      end
+    end
+    def program_found?
+      found=`whereis git`
+      (found =~/bin\/git\b/) ? true : false
+    end
+    def make_dir_fnb
+      FileUtils::mkdir_p(@git_path[:fnb]) \
+        unless FileTest.directory?(@git_path[:fnb])
+      FileUtils::mkdir_p(@git_path[:doc]) \
+        unless FileTest.directory?(@git_path[:doc])
+      FileUtils::mkdir_p(@git_path[:po]) \
+        unless FileTest.directory?(@git_path[:po])
+      FileUtils::mkdir_p(@git_path[:pot]) \
+        unless FileTest.directory?(@git_path[:pot])
+      FileUtils::mkdir_p(@git_path[:conf]) \
+        unless FileTest.directory?(@git_path[:conf])
+      FileUtils::mkdir_p(@git_path[:image]) \
+        unless FileTest.directory?(@git_path[:image])
+      #FileUtils::mkdir_p(@git_path[:audio]) \
+      #  unless FileTest.directory?(@git_path[:audio])
+      #FileUtils::mkdir_p(@git_path[:video]) \
+      #  unless FileTest.directory?(@git_path[:video])
+    end
+    def git_init
+      unless FileTest.directory?("#{@git_path[:fnb]}/.git")
+        pwd=Dir.pwd
+        Dir.chdir(@git_path[:fnb])
+        system("git init ")
+        Dir.chdir(pwd)
+      end
+    end
+    def git_commit
+      if program_found?
+        if FileTest.directory?("#{@git_path[:fnb]}")
+          pwd=Dir.pwd
+          Dir.chdir(@git_path[:fnb])
+          system("
+            git add . \
+            && git commit -a
+          ")
+          Dir.chdir(pwd)
+        end
+      end
+    end
+    def populate
+      def identify_language_versions
+        print __FILE__ + ':'
+        p __LINE__
+      end
+      def copy_src_head
+        if @opt.f_pth[:lng] \
+        and File.exist?("#{@env.path.pwd}/#{@opt.f_pth[:lng]}/#{@opt.fns}")
+          FileUtils::cp_r(
+            "#{@env.path.pwd}/#{@opt.f_pth[:lng]}/#{@opt.fns}",
+            @git_path[:doc]
+          )
+        elsif @opt.fns =~/\.ssm\.sst/
+          ssm=@opt.fns.gsub(/\.ssm\.sst/,'.ssm')
+          FileUtils::cp_r(
+            "#{@env.path.pwd}/#{ssm}",
+            @git_path[:doc]
+          )
+        elsif File.exist?("#{@env.path.pwd}/#{@opt.fns}")
+          FileUtils::cp_r(
+            "#{@env.path.pwd}/#{@opt.fns}",
+            @git_path[:doc]
+          )
+        end
+      end
+      def copy_related_sst_ssi
+        doc_import=[]
+        @rgx_doc_import=/^<<\s(\S+?\.ss[ti])/
+        file_array=IO.readlines(@opt.fns,'')
+        file_array.each do |f|
+          if f =~@rgx_doc_import
+            doc_import = doc_import \
+            + f.scan(@rgx_doc_import).uniq.flatten
+          end
+        end
+        doc_import.each do |f|
+          if @opt.f_pth[:lng]
+            FileUtils::cp_r(
+              "#{@env.path.pwd}/#{@opt.f_pth[:lng]}/#{f}",
+              @git_path[:doc]
+            )
+          else
+            FileUtils::cp_r(
+              "#{@env.path.pwd}/#{f}",
+              @git_path[:doc]
+            )
+          end
+        end
+      end
+      def locate_parse_file
+        composite_src=@opt.fns=~/\.ssm$/ ? true : false
+        if composite_src \
+        and not @opt.act[:ao][:set]==:on
+          ##SiSU_Assemble::Composite.new(@opt).read
+          #SiSU_AO::Source.new(@opt).read                                         # -m
+          @env.processing_path.composite_file \
+          + '/' \
+          + @opt.fnb \
+          + '.ssm.sst'
+        elsif composite_src
+          @env.processing_path.composite_file \
+          + '/' \
+          + @opt.fnb \
+          + '.ssm.sst'
+        else
+          @env.path.pwd
+          + '/' \
+          + @opt.fns
+        end
+      end
+      def read_composite
+        #print __FILE__ + ':'
+        #p __LINE__
+      end
+      def sisuyaml_rc
+        sisurc=@env.path.sisurc_path
+        if FileTest.file?(sisurc)
+          FileUtils::cp_r(sisurc,@git_path[:conf])
+        end
+      end
+      def read_src
+        print __FILE__ + ':'
+        p __LINE__
+      end
+      def composite_src?
+        @opt.fns=~/\.ssm$/ ? true : false
+      end
+      def sisusrc_files
+        populate.copy_src_head
+        if composite_src?
+          populate.copy_related_sst_ssi
+        end
+        #parse_file_name=locate_parse_file
+        #parse_file=IO.readlines(parse_file_name,'')
+        populate.sisuyaml_rc #(parse_file)
+        #populate.extract_composite_source
+        #populate.read_composite # or read_each_composite
+        populate.identify_language_versions
+      end
+      self
+    end
+  end
+end
+__END__
+@file.output_path.sisugit
+#+END_SRC
+
+** qrcode.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/qrcode.rb"
+# <<sisu_document_header>>
+module SiSU_QRcode
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'prog_text_translation'              # prog_text_translation.rb
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+    include SiSU_Particulars
+  require_relative 'html'                               # html.rb
+  require_relative 'dp'                                 # dp.rb
+    include SiSU_Param
+  require_relative 'generic_parts'                      # generic_parts.rb
+  require_relative 'i18n'                               # i18n.rb
+  class Source
+    def initialize(opt)
+      @opt=opt
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+      l=SiSU_Env::StandardiseLanguage.new(@opt.lng).language
+      @doc_language=l[:n]
+    end
+    def read
+      begin
+        @env=SiSU_Env::InfoEnv.new(@opt.fns,@opt)
+        @md=SiSU_Param::Parameters.new(@opt).get
+        xbrowser=@env.program.web_browser
+        browser=@env.program.console_web_browser
+        unless @opt.act[:quiet][:set]==:on
+          url_html="file://#{@md.file.output_path.manifest.dir}/#{@md.file.base_filename.manifest}"
+          (@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on) \
+          ? SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'QR code',
+              "#{xbrowser} #{url_html}"
+            ).green_hi_blue
+          : SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'QR code',
+              "[#{@opt.f_pth[:lng_is]}] #{@opt.fns}"
+            ).green_title_hi
+          if (@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on)
+            SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              "#{browser} #{url_html}"
+            ).grey_tab
+          end
+        end
+        data=SiSU_HTML::Source::HTML_Environment.new(@particulars).tuned_file_instructions
+        OutputInfo.new(@md).check_output(data)
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    private
+    class OutputInfo <Source
+      include SiSU_Parts_Generic
+      def initialize(md)
+        @manifest={ txt: [], txt_title: [] }
+        @md,@fns=md,md.fns
+        @env=SiSU_Env::InfoEnv.new(@md.fns,@md.opt)
+        @fnb=@md.fnb
+        @base_url="#{@env.url.root}/#{@fnb}"
+        @f=SiSU_Env::FileOp.new(@md)
+        @base_path=@f.output_path.manifest.dir
+        @@dg ||=SiSU_Env::InfoEnv.new.digest(@md.opt).type
+        @dg=@@dg
+        l=SiSU_Env::StandardiseLanguage.new(@md.opt.lng).language
+        @language=l[:n]
+        @translate=SiSU_Translate::Source.new(@md,@language)
+        @f.make_path(@f.output_path.qrcode.dir)
+      end
+      def spaces
+        Ax[:spaces]
+      end
+      def output_metadata
+        fn=@f.base_filename.manifest_txt
+        mn=''
+        if @md.opt.act[:maintenance][:set]==:on
+          fn=@f.base_filename.manifest_txt
+          manifest=@f.write_file.manifest_txt
+        end
+        @manifest[:txt].each do |x|
+          x=x.gsub(/\\\\/m,"\n")
+          puts x if @md.opt.act[:verbose_plus][:set]==:on
+          manifest << x if @md.opt.act[:maintenance][:set]==:on
+          mn += x
+        end
+        manifest.close if @md.opt.act[:maintenance][:set]==:on
+        cmd=SiSU_Env::SystemCall.new(mn,@f.place_file.qrcode_md.dir,@md.opt.selections.str)
+        cmd.qrencode
+      end
+      def output_metadata_short
+        mn=''
+        @manifest[:txt_title].each do |x|
+          mn += x
+        end
+        cmd=SiSU_Env::SystemCall.new(mn,@f.place_file.qrcode_title.dir,@md.opt.selections.str)
+        cmd.qrencode
+      end
+      def summarize(id,file,pth='',rel='',url='',img='● ')
+        size=(File.size("#{pth}/#{file}")/1024.00).to_s
+        kb=/([0-9]+\.[0-9]{0,1})/m.match(size)[1]
+        @manifest[:txt] <<<<WOK
+#{id} #{kb}
+  #{the_text.url_open}#{url}/#{file}#{the_text.url_close}
+WOK
+      end
+      def summarize_html_seg(id,file,pth='',rel='',url='',img='● ')
+        size=(File.size("#{pth}/#{file}")/1024.00).to_s
+        kb=/([0-9]+\.[0-9]{0,1})/m.match(size)[1]
+        @manifest[:txt] <<<<WOK
+#{id} #{kb}
+  #{the_text.url_open}#{url}/#{file}#{the_text.url_close}
+WOK
+      end
+      def summarize_sources(id,file,pth,rel,url)
+        sys=SiSU_Env::SystemCall.new
+        dgst=case @dg
+        when :sha512
+          (sys.sha512("#{pth}/#{file}")) #check
+        when :md5
+          (sys.md5("#{pth}/#{file}"))
+        else
+          (sys.sha256("#{pth}/#{file}"))
+        end
+        dgst=dgst ? dgst : [ '', 'n/a' ]
+        if (@md.opt.act[:verbose][:set]==:on \
+        || @md.opt.act[:verbose_plus][:set]==:on \
+        || @md.opt.act[:maintenance][:set]==:on)
+          SiSU_Screen::Ansi.new(
+            @md.opt.selections.str,
+            "#{dgst[1]} #{file}"
+          ).warn
+        end
+        size=(File.size("#{pth}/#{file}")/1024.00).to_s
+        kb=/([0-9]+\.[0-9]{0,1})/m.match(size)[1]
+        @manifest[:txt] <<<<WOK
+#{id} #{dgst[1]} #{kb}
+  #{the_text.url_open}#{url}/#{file}#{the_text.url_close}
+WOK
+      end
+      def published_manifests?
+        @f=SiSU_Env::FileOp.new(@md) #.base_filename
+        @m=[]
+        url=@f.output_path.base.url
+        manifests={}
+        mp,mn,mt=nil,nil,nil
+        ln=SiSU_i18n::Languages.new.language.list
+        Px[:lng_lst].each do |lc|
+          if @env.output_dir_structure.by_language_code?
+            mp="#{@f.output_path.base.dir}/#{lc}/manifest"
+            mn="#{@md.fnb}.html"
+            mt="#{mp}/#{mn}"
+            mu="#{url}/#{lc}/manifest/#{mn}"
+          elsif @env.output_dir_structure.by_filetype?
+            mp="#{@f.output_path.base.dir}/manifest"
+            mn="#{@md.fnb}.#{lc}.html"
+            mt="#{mp}/#{mn}"
+            mu="#{url}/manifest/#{mn}"
+          else
+            mp="#{@f.output_path.base.dir}/#{@md.fnb}"
+            mn="sisu_manifest.#{lc}.html"
+            mt="#{mp}/#{mn}"
+            mu="#{url}/#{mn}"
+          end
+          if FileTest.directory?(mp) \
+          &&  FileTest.file?(mt)
+            lng=ln[lc][:t]
+            manifests[lc]={ ln: lng, fn: mn }
+            @m << { mu: mu, l: lng }
+          end
+        end
+        #manifests
+        @m=@m.uniq
+        @m
+      end
+      def languages(id,file)
+        flv=published_manifests?
+        flv.each do |l|
+          SiSU_Translate::Source.new(@md,@language,l[:n]).language_list
+          @manifest[:txt] << "#{l[:mu]} #{l[:l]}\n"
+        end
+      end
+      def published_languages(id,file)
+        flv=published_manifests?
+        flv.each do |l|
+          @manifest[:txt] << "#{l[:l]}  #{the_text.url_open}#{l[:mu]}#{the_text.url_close}\n"
+        end
+      end
+      def metadata(id,info)
+        info=info.to_s.gsub(/#{Mx[:br_line]}/,"\n")
+        @manifest[:txt] << %{#{id}: #{info}\n}
+      end
+      def md_title_info(id,info)
+        info=info.to_s.gsub(/#{Mx[:br_line]}/,"\n")
+        @manifest[:txt_title] << %{#{info}\n}
+      end
+      def links(url,lnk,target)
+        static=if url =~/^\.\// then url.gsub(/^\.(\.)?/,@base_url)
+        elsif url =~/^\.\.\//   then url.gsub(/^\.(\.)?/,@env.url.root)
+        else                         url
+        end
+        @manifest[:txt] << %{#{url} #{lnk} #{the_text.url_open}#{static}#{the_text.url_close}\n}
+      end
+      def output_tests
+        if FileTest.file?(@f.place_file.html_segtoc.dir)==true
+          pth=@f.output_path.html_seg.dir
+          rel=@f.output_path.html_seg.rel_sm
+          url=@f.output_path.html_seg.url
+          id,file='HTML, table of contents (for segmented text)',@f.base_filename.html_segtoc
+          summarize_html_seg(id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.html_scroll.dir)==true
+          pth=@f.output_path.html_scroll.dir
+          rel=@f.output_path.html_scroll.rel_sm
+          url=@f.output_path.html_scroll.url
+          id,file='HTML, full length document',@f.base_filename.html_scroll
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.html_book_index.dir)==true
+          pth=@f.output_path.html_seg.dir
+          rel=@f.output_path.html_seg.rel_sm
+          url=@f.output_path.html_seg.url
+          id,file='HTML, (book type) index',@f.base_filename.html_book_index
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.html_concordance.dir)==true
+          pth=@f.output_path.html_seg.dir
+          rel=@f.output_path.html_seg.rel_sm
+          url=@f.output_path.html_seg.url
+          id,file='HTML, concordance file',@f.base_filename.html_concordance
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.epub.dir)==true
+          id,file='EPUB (Electronic Publication, e-book standard)',@f.base_filename.epub
+          pth=@f.output_path.epub.dir
+          rel=@f.output_path.epub.rel_sm
+          url=@f.output_path.epub.url
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?("#{@f.output_path.pdf.dir}/#{@f.base_filename.pdf_p_letter}")==true
+          pth=@f.output_path.pdf.dir
+          rel=@f.output_path.pdf.rel_sm
+          url=@f.output_path.pdf.url
+          id,file="PDF, U.S. letter size, portrait/vertical","#{@f.base_filename.pdf_p_letter}"
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?("#{@f.output_path.pdf.dir}/#{@f.base_filename.pdf_l_letter}")==true
+          pth=@f.output_path.pdf.dir
+          rel=@f.output_path.pdf.rel_sm
+          url=@f.output_path.pdf.url
+          id,file="PDF, U.S. letter size, landscape/horizontal","#{@f.base_filename.pdf_l_letter}"
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?("#{@f.output_path.pdf.dir}/#{@f.base_filename.pdf_p_a4}")==true
+          pth=@f.output_path.pdf.dir
+          rel=@f.output_path.pdf.rel_sm
+          url=@f.output_path.pdf.url
+          id,file="PDF, A4 size, portrait/vertical","#{@f.base_filename.pdf_p_a4}"
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?("#{@f.output_path.pdf.dir}/#{@f.base_filename.pdf_l_a4}")==true
+          pth=@f.output_path.pdf.dir
+          rel=@f.output_path.pdf.rel_sm
+          url=@f.output_path.pdf.url
+          id,file="PDF, A4 size, landscape/horizontal","#{@f.base_filename.pdf_l_a4}"
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?("#{@f.output_path.pdf.dir}/#{@f.base_filename.pdf_p_a5}")==true
+          pth=@f.output_path.pdf.dir
+          rel=@f.output_path.pdf.rel_sm
+          url=@f.output_path.pdf.url
+          id,file="PDF, A5 (book) size, portrait/vertical","#{@f.base_filename.pdf_p_a5}"
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?("#{@f.output_path.pdf.dir}/#{@f.base_filename.pdf_l_a5}")==true
+          pth=@f.output_path.pdf.dir
+          rel=@f.output_path.pdf.rel_sm
+          url=@f.output_path.pdf.url
+          id,file="PDF, A5 (book) size, landscape/horizontal","#{@f.base_filename.pdf_l_a5}"
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?("#{@f.output_path.pdf.dir}/#{@f.base_filename.pdf_p_b5}")==true
+          pth=@f.output_path.pdf.dir
+          rel=@f.output_path.pdf.rel_sm
+          url=@f.output_path.pdf.url
+          id,file="PDF, B5 (book) size, portrait/vertical","#{@f.base_filename.pdf_p_b5}"
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?("#{@f.output_path.pdf.dir}/#{@f.base_filename.pdf_l_b5}")==true
+          pth=@f.output_path.pdf.dir
+          rel=@f.output_path.pdf.rel_sm
+          url=@f.output_path.pdf.url
+          id,file="PDF, B5 (book) size, landscape/horizontal","#{@f.base_filename.pdf_l_b5}"
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?("#{@f.output_path.pdf.dir}/#{@f.base_filename.pdf_p_legal}")==true
+          pth=@f.output_path.pdf.dir
+          rel=@f.output_path.pdf.rel_sm
+          url=@f.output_path.pdf.url
+          id,file="PDF, U.S. legal size, portrait/vertical","#{@f.base_filename.pdf_p_legal}"
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?("#{@f.output_path.pdf.dir}/#{@f.base_filename.pdf_l_legal}")==true
+          pth=@f.output_path.pdf.dir
+          rel=@f.output_path.pdf.rel_sm
+          url=@f.output_path.pdf.url
+          id,file="PDF, U.S. legal size, landscape/horizontal","#{@f.base_filename.pdf_l_legal}"
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.odt.dir)==true
+          pth=@f.output_path.odt.dir
+          rel=@f.output_path.odt.rel_sm
+          url=@f.output_path.odf.url
+          id,file='ODF:ODT (Open Document Format)',@f.base_filename.odt
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.xhtml.dir)==true
+          pth=@f.output_path.xhtml.dir
+          rel=@f.output_path.xhtml.rel_sm
+          url=@f.output_path.xhtml.url
+          id,file='ODF:ODT (Open Document Format)',@f.base_filename.odt
+          id,file='XHTML',@f.base_filename.xhtml
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.xml_sax.dir)==true
+          pth=@f.output_path.xml_sax.dir
+          rel=@f.output_path.xml_sax.rel_sm
+          url=@f.output_path.xml_sax.url
+          id,file='XML SAX',@f.base_filename.xml_sax
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.xml_dom.dir)==true
+          pth=@f.output_path.xml_dom.dir
+          rel=@f.output_path.xml_dom.rel_sm
+          url=@f.output_path.xml_dom.url
+          id,file='XML DOM',@f.base_filename.xml_dom
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.txt.dir)==true
+          id='Plaintext (UTF-8)'
+          #id=if @md.opt.selections.str =~/a/ then 'Plaintext (Unix (UTF-8) with footnotes)'
+          #elsif @md.opt.selections.str =~/e/ then 'Plaintext (Unix (UTF-8) with endnotes)'
+          #elsif @md.opt.selections.str =~/A/ then 'Plaintext (dos (UTF-8) with footnotes)'
+          #elsif @md.opt.selections.str =~/E/ then 'Plaintext (dos (UTF-8) with endnotes)'
+          #else                         'Plaintext (UTF-8)'
+          #end
+          pth=@f.output_path.txt.dir
+          rel=@f.output_path.txt.rel_sm
+          url=@f.output_path.txt.url
+          file=@f.base_filename.txt
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?("#{@base_path}/#{@md.fns}.tex")==true
+          id,file='LaTeX (portrait)',"#{@md.fns}.tex"
+          pth,rel,url='','',''
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?("#{@base_path}/#{@md.fns}.tex")==true
+          id,file='LaTeX (landscape)',"#{@md.fns}.landscape.tex"
+          pth,rel,url='','',''
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.manpage.dir)==true
+          pth=@f.output_path.manpage.dir
+          rel=@f.output_path.manpage.rel_sm
+          url=@f.output_path.manpage.url
+          id,file='Manpage',@f.base_filename.manpage
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.texinfo.dir)==true
+          pth=@f.output_path.texinfo.dir
+          rel=@f.output_path.texinfo.rel_sm
+          url=@f.output_path.texinfo.url
+          id,file='Texinfo',@f.base_filename.texinfo
+          summarize(id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.hash_digest.dir)==true
+          pth=@f.output_path.hash_digest.dir
+          rel=@f.output_path.hash_digest.rel_sm
+          url=@f.output_path.hash_digest.url
+          id,file="Digest/DCC - Document Content Certificate (#{@dg})",@f.base_filename.hash_digest
+          summarize(id,file,pth,rel,url)
+        end
+      end
+      def published_versions
+        id,file='Markup (SiSU source)',@md.fns
+        #languages(id,file)
+        published_languages(id,file)
+      end
+      def language_versions
+        if FileTest.file?(@f.place_file.manifest.dir)==true
+          id,file='Markup (SiSU source)',@md.fns
+          published_languages(id,file)
+        end
+      end
+      def source_tests
+        if @md.fns =~/\.ssm\.sst$/                                                  #% decide whether to extract and include requested/required documents
+          if FileTest.file?(@f.place_file.src.dir)==true
+            pth=@f.output_path.src.dir
+            rel=@f.output_path.src.rel
+            url=@f.output_path.src.url
+            id,file='Markup Composite File (SiSU source)',@f.base_filename.src
+            summarize_sources(id,file,pth,rel,url)
+          end
+        else
+          if FileTest.file?(@f.place_file.src.dir)==true
+            pth=@f.output_path.src.dir
+            rel=@f.output_path.src.rel
+            url=@f.output_path.src.url
+            id,file='Markup (SiSU source)',@f.base_filename.src
+            summarize_sources(id,file,pth,rel,url)
+          end
+        end
+        if FileTest.file?(@f.place_file.sisupod.dir)==true
+          pth=@f.output_path.sisupod.dir
+          rel=@f.output_path.sisupod.rel
+          url=@f.output_path.sisupod.url
+          id,file='SiSU doc (zip)',@f.base_filename.sisupod
+          summarize_sources(id,file,pth,rel,url)
+        end
+        if FileTest.file?(@f.place_file.pot.dir)==true
+          pth=@f.output_path.pot.dir
+          rel=@f.output_path.pot.rel_sm
+          url=@f.output_path.pot.url
+          id,file='SiSU pot',@f.base_filename.pot
+          summarize_sources(id,file,pth,rel,url)
+        end
+      end
+      def metadata_tests
+        if defined? @md.title.full \
+        and @md.title.full=~/\S+/
+          id,info=@translate.full_title,@md.title.full
+          #id,info=@translate.full_title,%{"#{@md.title.full}"}
+          metadata(id,info)
+          md_title_info(id,info)
+        end
+        if defined? @md.creator.author \
+        and @md.creator.author=~/\S+/
+          id,info=@translate.author,@md.creator.author
+          metadata(id,info)
+          md_title_info(id,info)
+        end
+        if defined? @md.creator.editor \
+        and @md.creator.editor=~/\S+/
+          id,info=@translate.editor,@md.creator.editor
+          metadata(id,info)
+        end
+        if defined? @md.creator.contributor \
+        and @md.creator.contributor=~/\S+/
+          id,info=@translate.contributor,@md.creator.contributor
+          metadata(id,info)
+        end
+        if defined? @md.creator.translator \
+        and @md.creator.translator=~/\S+/
+          id,info=@translate.translator,%{(#{@md.creator.translator})}
+          metadata(id,info)
+          md_title_info(id,info)
+        end
+        if defined? @md.creator.illustrator \
+        and @md.creator.illustrator=~/\S+/
+          id,info=@translate.illustrator,@md.creator.illustrator
+          metadata(id,info)
+        end
+        if defined? @md.publisher \
+        and @md.publisher=~/\S+/ #dc
+          id,info=@translate.publisher,@md.publisher
+          metadata(id,info)
+        end
+        if defined? @md.creator.prepared_by \
+        and @md.creator.prepared_by=~/\S+/
+          id,info=@translate.prepared_by,@md.creator.prepared_by
+          metadata(id,info)
+        end
+        if defined? @md.creator.digitized_by \
+        and @md.creator.digitized_by=~/\S+/
+          id,info=@translate.digitized_by,@md.creator.digitized_by
+          metadata(id,info)
+        end
+        if defined? @md.rights.all \
+        and @md.rights.all=~/\S+/ #dc
+          id,info=@translate.rights,@md.rights.all
+          metadata(id,info)
+        end
+        if defined? @md.date.published
+          if defined? @md.date.published \
+          and @md.date.published=~/\S+/ #dc
+            id,info=@translate.date,@md.date.published
+            metadata(id,info)
+            md_title_info(id,info)
+          end
+          if defined? @md.date.created \
+          and @md.date.created=~/\S+/ #dc
+            id,info=@translate.date_created,@md.date.created
+            metadata(id,info)
+          end
+          if defined? @md.date.issued \
+          and @md.date.issued=~/\S+/ #dc
+            id,info=@translate.date_issued,@md.date.issued
+            metadata(id,info)
+          end
+          if defined? @md.date.available \
+          and @md.date.available=~/\S+/ #dc
+            id,info=@translate.date_available,@md.date.available
+            metadata(id,info)
+          end
+          if defined? @md.date.modified \
+          and @md.date.modified=~/\S+/ #dc
+            id,info=@translate.date_modified,@md.date.modified
+            metadata(id,info)
+          end
+          if defined? @md.date.valid \
+          and @md.date.valid=~/\S+/ #dc
+            id,info=@translate.date_valid,@md.date.valid
+            metadata(id,info)
+          end
+        end
+        if defined? @md.title.language \
+        and @md.title.language=~/\S+/
+          id,info=@translate.language,@md.title.language
+          metadata(id,info)
+        end
+        if defined? @md.original.language \
+        and @md.original.language=~/\S+/
+          id,info=@translate.language_original,@md.original.language
+          metadata(id,info)
+        end
+        if defined? @md.classify.subject \
+        and @md.classify.subject=~/\S+/
+          id,info=@translate.subject,@md.classify.subject
+          metadata(id,info)
+        end
+        if defined? @md.classify.keywords \
+        and @md.classify.keywords=~/\S+/
+          id,info=@translate.keywords,@md.classify.keywords
+          metadata(id,info)
+        end
+        if defined? @md.classify.loc \
+        and @md.classify.loc=~/\S+/
+          id,info=@translate.cls_loc,@md.classify.loc
+          metadata(id,info)
+        end
+        if defined? @md.classify.dewey \
+        and @md.classify.dewey=~/\S+/
+          id,info=@translate.cls_dewey,@md.classify.dewey
+          metadata(id,info)
+        end
+        if defined? @md.notes.description \
+        and @md.notes.description=~/\S+/
+          id,info=@translate.description,@md.notes.description
+          metadata(id,info)
+        end
+        if defined? @md.notes.abstract \
+        and @md.notes.abstract=~/\S+/
+          id,info=@translate.abstract,@md.notes.abstract
+          metadata(id,info)
+        end
+        if defined? @md.notes.comment \
+        and @md.notes.comment=~/\S+/
+          id,info=@translate.comments,@md.notes.comment
+          metadata(id,info)
+        end
+        if defined? @md.notes.coverage \
+        and @md.notes.coverage=~/\S+/
+          id,info=@translate.coverage,@md.notes.coverage
+          metadata(id,info)
+        end
+        if defined? @md.notes.relation \
+        and @md.notes.relation=~/\S+/
+          id,info=@translate.relation,@md.notes.relation
+          metadata(id,info)
+        end
+        #if defined? @md.notes.source \
+        #and @md.notes.source=~/\S+/
+        #  id,info=@translate.source,@md.notes.source
+        #  metadata(id,info)
+        #end
+        #if defined? @md.notes.history \
+        #and @md.notes.history=~/\S+/
+        #  id,info=@translate.history,@md.notes.history
+        #  metadata(id,info)
+        #end
+        if defined? @md.notes.type \
+        and @md.notes.type=~/\S+/ #dc
+          id,info=@translate.type,@md.type
+          metadata(id,info)
+        end
+        if defined? @md.notes.format \
+        and @md.notes.format=~/\S+/
+          id,info=@transate.format,@md.notes.format
+          metadata(id,info)
+        end
+        if defined? @md.notes.prefix_a \
+        and @md.notes.prefix_a=~/\S+/
+          id,info=@translate.prefix_a,@md.notes.prefix_a
+          metadata(id,info)
+        end
+        if defined? @md.notes.prefix_b \
+        and @md.notes.prefix_b=~/\S+/
+          id,info=@translate.prefix_b,@md.notes.prefix_b
+          metadata(id,info)
+        end
+        if defined? @md.original.source \
+        and @md.original.source=~/\S+/
+          id,info=@translate.source,@md.original.source
+          metadata(id,info)
+        end
+        if defined? @md.identifier.oclc \
+        and @md.identifier.oclc=~/\S+/
+          id,info=@translate.cls_oclc,@md.identifier.oclc
+          @manifest[:txt] << %{#{id}:\n}
+          @manifest[:txt] << %{#{info}\n}
+        end
+        if defined? @md.identifier.isbn \
+        and @md.identifier.isbn=~/\S+/
+          id,info=@translate.cls_isbn,@md.identifier.isbn
+          metadata(id,info)
+        end
+        if defined? @md.topic_register_array \
+        and @md.topic_register_array.length > 0
+          @manifest[:txt] << %{#{@translate.topic_register}:\n}
+          @md.topic_register_array.each do |t|
+            t.each_with_index do |st,i|
+              if st.is_a?(Array)
+                st.each do |v|
+                  @manifest[:txt] << %{#{spaces*i}#{v}\n}
+                end
+              else @manifest[:txt] << %{#{spaces*i}#{st}\n}
+              end
+            end
+          end
+        end
+        if @md.fns
+          id,info=@translate.sourcefile,@md.fns
+          metadata(id,info)
+        end
+        if @md.en[:mismatch] > 0
+          id,info='WARNING document error in endnote markup, number mismatch',"endnotes: #{@md.en[:note]} != endnote reference marks: #{@md.en[:mark]} (difference = #{@md.en[:mismatch]})"
+          metadata(id,info)
+        end
+        if @md.wc_words
+          id,info=@translate.word_count,@md.wc_words
+          metadata(id,info)
+        end
+        if @md.dgst
+          id,info="#{@translate.sourcefile_digest} (#{@dg})",@md.dgst[1]
+          metadata(id,info)
+        end
+        if @md.sc_number
+          id,info=@translate.sc_number,@md.sc_number
+          metadata(id,info)
+        end
+        if @md.sc_date
+          id,info=@translate.sc_date,"#{@md.sc_date} at #{@md.sc_time}"
+          metadata(id,info)
+        end
+      end
+      def check_output(data)
+        begin
+          @f=SiSU_Env::FileOp.new(@md) #.base_filename
+          url=@f.output_path.base.url
+          @en_manifest=if @env.output_dir_structure.by_language_code?
+            "#{url}/en/manifest/#{@md.fnb}.html"
+          elsif @env.output_dir_structure.by_filetype?
+            "#{url}/manifest/#{@md.fnb}.#{@md.opt.lng}.html"
+          else
+            "#{url}/sisu_manifest.#{@md.opt.lng}.html"
+          end
+          @manifest[:txt] <<<<WOK
+#{@translate.manifest_description_metadata}
+  #{the_text.url_open}#{@en_manifest}#{the_text.url_close}
+WOK
+          metadata_tests
+          @manifest[:txt_title] <<<<WOK
+  #{the_text.url_open}#{@en_manifest}#{the_text.url_close}
+WOK
+          source_tests
+          @manifest[:txt] <<<<WOK
+#{@translate.language_version_list}
+WOK
+          language_versions
+          output_metadata
+          output_metadata_short
+        rescue
+          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+        ensure
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** relaxng.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/relaxng.rb"
+# <<sisu_document_header>>
+module SiSU_Relaxng
+  require_relative 'se'                                 # se.rb
+  class RelaxNG
+    def gpl3_or_later
+      @gpl3_or_later =<<RELAXNG
+=begin
+
+ * Name: SiSU generated relaxng
+
+ * Description: generated relaxng for SiSU
+   (SiSU is a framework for document structuring, publishing and search)
+
+ * Author: Ralph Amissah
+
+ * Copyright: (C) 1997 - 2013 Ralph Amissah All Rights Reserved.
+
+ * License: GPL 3 or later:
+
+   SiSU, a framework for document structuring, publishing and search
+
+   Copyright: (C) 1997 - 2013 Ralph Amissah
+
+   This program is free software: you can redistribute it and/or modify it
+   under the terms of the GNU 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 [http://www.gnu.org/licenses/].
+
+   If you have Internet connection, the latest version of the GPL should be
+   available at these locations:
+   <http://www.fsf.org/licenses/gpl.html>
+   [http://www.gnu.org/licenses/gpl.html]
+   <http://www.jus.uio.no/sisu/gpl.fsf>
+
+ * SiSU uses:
+   * Standard SiSU markup syntax,
+   * Standard SiSU meta-markup syntax, and the
+   * Standard SiSU object citation numbering and system
+
+ * Homepages:
+   [http://www.jus.uio.no/sisu]
+   [http://www.sisudoc.org]
+
+ * Ralph Amissah
+   [ralph@amissah.com]
+   [ralph.amissah@gmail.com]
+
+=end
+RELAXNG
+    end
+    def rnc_name
+      def output_sax
+        'sisu_sax.rnc'
+      end
+      def output_dom
+        'sisu_dom.rnc'
+      end
+      def output_xhtml
+        'sisu_xhtml.rnc'
+      end
+      def input_sax
+        'sisu_sax.rnc'
+      end
+      def input_dom
+        'sisu_dom.rnc'
+      end
+      def input_node
+        'sisu_node.rnc'
+      end
+      self
+    end
+    def rng_name
+      def output_sax
+        'sisu_sax.rng'
+      end
+      def output_dom
+        'sisu_dom.rng'
+      end
+      def output_xhtml
+        'sisu_xhtml.rng'
+      end
+      def input_sax
+        'sisu_sax.rng'
+      end
+      def input_dom
+        'sisu_dom.rng'
+      end
+      def input_node
+        'sisu_node.rng'
+      end
+      self
+    end
+    def xsd_name
+      def output_sax
+        'sisu_sax.xsd'
+      end
+      def output_dom
+        'sisu_dom.xsd'
+      end
+      def output_xhtml
+        'sisu_xhtml.xsd'
+      end
+      def input_sax
+        'sisu_sax.xsd'
+      end
+      def input_dom
+        'sisu_dom.xsd'
+      end
+      def input_node
+        'sisu_node.xsd'
+      end
+      self
+    end
+    def rnc_sisu_object_input
+      @relaxng =<<RELAXNG
+#%% sisu object model: input
+#{gpl3_or_later}
+#%% definitions
+# dublin core:
+element-semantic =
+  element semantic {
+  # dublin core:
+  element title { text }
+  & element creator { text }?
+  & element subject { text }?
+  & element description { text }?
+  & element publisher { text }?
+  & element contributor { text }?
+  & element date { text }?
+  & element date.created { text }?
+  & element date.issued { text }?
+  & element date.available { text }?
+  & element date.valid { text }?
+  & element date.modified { text }?
+  & element type { text }?
+  & element format { text }?
+  & element identifier { text }?
+  & element source { text }?
+  & element relation { text }?
+  & element coverage { text }?
+  & element rights { text }?
+  & element keywords { text }?
+  # extended semantic metadata:
+  & attribute subtitle { text }?
+  & attribute illustrator { text }?
+  & attribute translator { text }?
+  & attribute prepared_by { text }?
+  & attribute digitized_by { text }?
+  & attribute language { text }?
+  & attribute language.original { text }?
+  & attribute classify.pg { text }?
+  & attribute classify.isbn { text }?
+  & attribute classify.dewey { text }?
+  & attribute classify.loc { text }?
+  & attribute prefix.a { text }?
+  & attribute prefix.b { text }?
+  & attribute suffix { text }?
+  & attribute comments { text }?
+  & attribute abstract { text }?
+  # & attribute information { text }?
+  & attribute contact { text }?
+  & attribute links { text }?
+  }
+element-processing =
+  element processing {
+  attribute structure { text }?
+  & attribute level { text }?
+  & attribute markup { text }?
+  & attribute bold { text }?
+  & attribute italics { text }?
+  & attribute papersize { text }?
+  & attribute vocabulary { text }?
+  & element date_scheme { text }?
+  & element date.issued.scheme { text }?
+  & element date.available.scheme { text }?
+  & element date.valid.scheme { text }?
+  & element date.modified.scheme { text }?
+  }?
+element-head =
+  element head {
+    # processing instructions, and semantic data, distinguish?:
+    element metadata {
+      element title { text },
+      element file { text },
+      element generator { text },
+      element-semantic,
+      element-processing
+    }+
+  }
+# body text/contents
+# includes <b> <i> <u> <del> <ins> <indent1> <bullet> etc.
+element-txt =
+  element txt {
+    text*
+    & element b { text }*
+    & element i { text }*
+    & element u { text }*
+    & element ins { text }*
+    & element del { text }*
+  }
+element-endnote =
+  element endnote {
+    element number { text },
+    element note { element-txt }+
+  }+
+element-para =
+  element para {
+    # attribute paragraph_format { text },
+    element-txt+
+    & element-endnote?
+  }
+element-external_space =
+  element external_space {
+    # ignored by sisu, provide program needs
+    element program {
+      # e.g. kdissert
+      element name { text },
+      element xpos { text },
+      element ypos { text },
+      element font { text },
+      element outline_color { text },
+      element text_color { text },
+      element comment { text }
+    }*
+  }*,
+#%% structure
+  element document {
+    # document head:
+    element-head,
+    # document body:
+    element body {
+      # object, a unit of text, usually a paragraph with any associated endnotes
+      element node {
+        element structure {
+          # structure document using either node:heading levels or node:heading relationships:
+          # (i) sisu default uses node:heading levels (1-6 or A-C,1-3) to build document structure
+          element level { text }?,
+          # (ii) sisu alternatively could use node:heading relationship information to build document structure
+          element node.id { text },
+          element node.parent { text },
+          element node.child { text }*
+        },
+        element node.objects {
+          element object.heading {
+            # nametag used only in headings, especially important for segmented html
+            element nametag { text },
+            element-para
+          },
+          element object.para {
+            element-para
+          }*
+        }+,
+        element-external_space
+      }+
+    }
+  }
+RELAXNG
+    end
+    def rnc_sisu_object_ao
+      @relaxng =<<RELAXNG
+#%% sisu object model: ao
+#{gpl3_or_later}
+#%% definitions
+# dublin core:
+element-semantic =
+  element semantic {
+  # dublin core:
+  element title { text }
+  & element creator { text }?
+  & element subject { text }?
+  & element description { text }?
+  & element publisher { text }?
+  & element contributor { text }?
+  & element date { text }?
+  & element date.created { text }?
+  & element date.issued { text }?
+  & element date.available { text }?
+  & element date.valid { text }?
+  & element date.modified { text }?
+  & element type { text }?
+  & element format { text }?
+  & element identifier { text }?
+  & element source { text }?
+  & element relation { text }?
+  & element coverage { text }?
+  & element rights { text }?
+  & element keywords { text }?
+  # extended semantic metadata:
+  & attribute subtitle { text }?
+  & attribute illustrator { text }?
+  & attribute translator { text }?
+  & attribute prepared_by { text }?
+  & attribute digitized_by { text }?
+  & attribute language { text }?
+  & attribute language.original { text }?
+  & attribute classify.pg { text }?
+  & attribute classify.isbn { text }?
+  & attribute classify.dewey { text }?
+  & attribute classify.loc { text }?
+  & attribute prefix.a { text }?
+  & attribute prefix.b { text }?
+  & attribute suffix { text }?
+  & attribute comments { text }?
+  & attribute abstract { text }?
+  # & attribute information { text }?
+  & attribute contact { text }?
+  & attribute links { text }?
+  }
+element-processing =
+  element processing {
+  attribute structure { text }?
+  & attribute level { text }?
+  & attribute markup { text }?
+  & attribute bold { text }?
+  & attribute italics { text }?
+  & attribute papersize { text }?
+  & attribute vocabulary { text }?
+  & element date_scheme { text }?
+  & element date.issued.scheme { text }?
+  & element date.available.scheme { text }?
+  & element date.valid.scheme { text }?
+  & element date.modified.scheme { text }?
+  }?
+element-head =
+  element head {
+    # processing instructions, and semantic data, distinguish?:
+    element metadata {
+      element title { text },
+      element file { text },
+      element generator { text },
+      element-semantic,
+      element-processing
+    }+
+  }
+# body text/contents
+# includes <b> <i> <u> <del> <ins> <indent1> <bullet> etc.
+element-txt =
+  element txt {
+    text*
+    & element b { text }*
+    & element i { text }*
+    & element u { text }*
+    & element ins { text }*
+    & element del { text }*
+  }
+element-checksum.endnote = element checksum.clean { text }
+element-endnote =
+  element endnote {
+    element number { text },
+    element note { element-txt }+,
+    element-checksum.endnote
+  }+
+element-checksum.para =
+  element checksum.para {
+    element checksum.clean { text },
+    element checksum.marked { text }
+  }
+element-para =
+  element para {
+    # attribute paragraph_format { text },
+    element-txt+
+    & element-endnote?
+  }
+element-object =
+  element object {
+    element-para,
+    element-checksum.para
+  }
+# object citation number, unique sequential number for objects:
+element-ocn = element ocn { text }
+element-object_structure_summary =
+  element-ocn,
+  # type: heading level value 1 -6, or normal text
+  element type { text },
+  # type number: sequential number for designated type
+  element type_number { text },
+  # type category: sequential number for designated category, e.g. sequentially counting all headers
+  element category_number { text }
+element-external_space =
+  element external_space {
+    # ignored by sisu, provide program needs
+    element program {
+      # e.g. kdissert
+      element name { text },
+      element xpos { text },
+      element ypos { text },
+      element font { text },
+      element outline_color { text },
+      element text_color { text },
+      element comment { text }
+    }*
+  }*,
+#%% structure
+  element document {
+    # document head:
+    element-head,
+    # document body:
+    element body {
+      # object, a unit of text, usually a paragraph with any associated endnotes
+      element node {
+        element structure {
+          # structure document using either node:heading levels or node:heading relationships:
+          # (i) sisu default uses node:heading levels (1-6 or A-C,1-3) to build document structure
+          element level { text }?,
+          # (ii) sisu alternatively could use node:heading relationship information to build document structure
+          element node.id { text },
+          element node.parent { text },
+          element node.child { text }*
+        },
+        element node.objects {
+          element object.heading {
+            element-object_structure_summary,
+            # nametag used only in headings, especially important for segmented html
+            element nametag { text },
+            element-object
+          },
+          element object.para {
+            element-object_structure_summary,
+            element-object
+          }*
+        }+,
+        element-external_space
+      }+
+    }
+  }
+RELAXNG
+    end
+    def rnc_model_output_sax
+      @relaxng =<<RELAXNG
+#% sax output model, part of SiSU and distributed under the same license
+default namespace = ""
+namespace xl = "http://www.w3.org/1999/xlink"
+start =
+  element document {
+    element head {
+      (br
+       | meta
+       | element creator {
+           attribute class { xsd:NCName },
+           (text
+            | element link {
+                attribute xl:href { xsd:anyURI },
+                attribute xl:type { xsd:NCName },
+                xsd:anyURI
+              })+
+         }
+       | element date {
+           attribute class { xsd:NCName },
+           xsd:NMTOKEN
+         }
+       | element date_available {
+           attribute class { xsd:NCName },
+           xsd:NMTOKEN
+         }
+       | element date_created {
+           attribute class { xsd:NCName },
+           xsd:NMTOKEN
+         }
+       | element date_issued {
+           attribute class { xsd:NCName },
+           xsd:NMTOKEN
+         }
+       | element date_modified {
+           attribute class { xsd:NCName },
+           xsd:NMTOKEN
+         }
+       | element date_valid {
+           attribute class { xsd:NCName },
+           xsd:NMTOKEN
+         }
+       | element keywords {
+           attribute class { xsd:NCName },
+           text
+         }
+       | element language {
+           attribute class { xsd:NCName },
+           xsd:NCName
+         }
+       | element meta { xsd:NMTOKEN }
+       | element rights {
+           attribute class { xsd:NCName },
+           (text | link)+
+         }
+       | element source {
+           attribute class { xsd:NCName },
+           text
+         }
+       | element structure {
+           attribute class { xsd:NCName },
+           text
+         }
+       | element subject {
+           attribute class { xsd:NCName },
+           text
+         }
+       | element title {
+           attribute class { xsd:NCName },
+           text
+         }
+       | element type {
+           attribute class { xsd:NCName },
+           text
+         }
+       | element source_control {
+           (br
+            | meta
+            | element sc {
+                attribute class { xsd:NCName },
+                text
+              })+
+         })+
+    },
+    element body {
+      element object {
+        attribute id { text },
+        element ocn {
+          text
+        },
+        element text {
+          attribute class { xsd:NCName },
+          (text
+           | b
+           | br
+           | del
+           | en
+           | i
+           | link
+           | sub
+           | sup
+           | u
+           | element image {
+               attribute alt { text }?,
+               attribute height { xsd:integer }?,
+               attribute width { xsd:integer }?,
+               attribute xl:actuate { xsd:NCName },
+               attribute xl:href { text },
+               attribute xl:show { xsd:NCName },
+               attribute xl:type { xsd:NCName }
+             })+
+        }?,
+        element table {
+          attribute align { xsd:NCName },
+          attribute bgcolor { xsd:NCName },
+          attribute border { xsd:integer },
+          attribute cellpadding { xsd:integer },
+          attribute summary { text },
+          attribute width { text },
+          element tr {
+            element td {
+              attribute valign { xsd:NCName },
+              attribute width { text },
+              (text | b | i)+
+            }+
+          }+
+        }?,
+        element endnote {
+          attribute notenumber { xsd:integer }?,
+          attribute symbol { text }?,
+          (element number { xsd:integer }
+           | element symbol { text }),
+          element note {
+            (text
+             | b
+             | br
+             | del
+             | i
+             | link
+             | sup
+             | u
+             | element em { xsd:NCName }
+             | element sub { xsd:NCName })+
+          }
+        }*
+      }+
+    }
+  }
+meta = element meta { text }
+br = element br { empty }
+b = element b { (text | en | i | link | sup)+ }
+i = element i { (text | b | br | sup)+ }
+en = element en { text }
+sub = element sub { xsd:NCName }
+sup = element sup { xsd:NCName }
+link =
+  element link {
+    attribute xl:href { xsd:anyURI },
+    attribute xl:type { xsd:NCName },
+    (xsd:anyURI | text | b | i | sup)+
+  }
+u = element u { (text | b | i)+ }
+del = element del { (text | b | i | link)+ }
+RELAXNG
+    end
+    def rnc_model_output_dom
+      @relaxng =<<RELAXNG
+#% dom output model, part of SiSU and distributed under the same license
+default namespace = ""
+namespace xl = "http://www.w3.org/1999/xlink"
+start =
+  element document {
+    element head {
+      element header {
+        meta,
+        (element creator { text }
+         | element date { xsd:NMTOKEN }
+         | element date_available { xsd:NMTOKEN }
+         | element date_created { xsd:NMTOKEN }
+         | element date_issued { xsd:NMTOKEN }
+         | element date_modified { xsd:NMTOKEN }
+         | element date_valid { xsd:NMTOKEN }
+         | element keywords { text }
+         | element language { xsd:NCName }
+         | element rights { (text | link)+ }
+         | element source { text }
+         | element structure { text }
+         | element subject { text }
+         | element title { text }
+         | element type { text }
+         | element source_control {
+             (br
+              | meta
+              | element sc {
+                  attribute class { xsd:NCName },
+                  text
+                })+
+           })
+      }+
+    },
+    element body {
+      element heading1 {
+        heading,
+        contents1*,
+        element heading2 {
+          heading,
+          contents1*,
+          element heading3 {
+            heading,
+            element contents1 {
+              heading,
+              content,
+              element contents2 {
+                heading,
+                content,
+                element contents3 { heading, content }*
+              }*
+            }+
+          }*
+        }*
+      }+
+    }
+  }
+meta = element meta { text }
+br = element br { empty }
+heading = element heading { object }
+contents1 =
+  element contents1 {
+    heading,
+    content,
+    element contents2 {
+      heading,
+      content,
+      element contents3 { heading, content }*
+    }*
+  }
+content = element content { object* }
+object =
+  element object {
+    attribute id { xsd:integer },
+    element ocn { text },
+    element nametag { text }?,
+    (element table {
+       attribute align { xsd:NCName },
+       attribute bgcolor { xsd:NCName },
+       attribute border { xsd:integer },
+       attribute cellpadding { xsd:integer },
+       attribute summary { text },
+       attribute width { text },
+       element tr {
+         element td {
+           attribute valign { xsd:NCName },
+           attribute width { text },
+           (text | b | i)+
+         }+
+       }+
+     }
+     | element text {
+         attribute class { xsd:NCName }?,
+         (text
+          | b
+          | del
+          | endnote
+          | i
+          | link
+          | element br { empty }
+          | element endnote {
+              element number { xsd:integer },
+              element note { (text | i | link)+ }
+            }
+          | element image {
+              attribute height { xsd:integer },
+              attribute width { xsd:integer },
+              attribute xl:actuate { xsd:NCName },
+              attribute xl:href { text },
+              attribute xl:show { xsd:NCName },
+              attribute xl:type { xsd:NCName }
+            }
+          | element sub { text })+
+       })
+  }
+i = element i { text }
+b = element i { text }
+u = element u { (text | b | i)+ }
+sub = element sub { xsd:NCName }
+sup = element sup { xsd:NCName }
+del = element del { (text | b | i | link)+ }
+link =
+  element link {
+    attribute xl:href { xsd:anyURI },
+    attribute xl:type { xsd:NCName },
+    xsd:anyURI
+  }
+endnote =
+  element endnote {
+    (element number { xsd:integer }
+     | element symbol { text }),
+    element note {
+      (text
+       | b
+       | br
+       | del
+       | i
+       | link
+       | sub
+       | sup
+       | u
+       | element em { xsd:NCName }
+       | element sub { xsd:NCName })+
+    }
+  }
+RELAXNG
+    end
+    def rnc_model_output_xhtml #not done
+      @relaxng =<<RELAXNG
+#% xhtml output model, part of SiSU and distributed under the same license
+default namespace = ""
+namespace xl = "http://www.w3.org/1999/xlink"
+start =
+  element document {
+    element head {
+      (br
+       | element creator {
+           attribute class { xsd:NCName },
+           (text
+            | element link {
+                attribute xl:href { xsd:anyURI },
+                attribute xl:type { xsd:NCName },
+                xsd:anyURI
+              })+
+         }
+       | element date {
+           attribute class { xsd:NCName },
+           xsd:NMTOKEN
+         }
+       | element date_available {
+           attribute class { xsd:NCName },
+           xsd:NMTOKEN
+         }
+       | element date_created {
+           attribute class { xsd:NCName },
+           xsd:NMTOKEN
+         }
+       | element date_issued {
+           attribute class { xsd:NCName },
+           xsd:NMTOKEN
+         }
+       | element date_modified {
+           attribute class { xsd:NCName },
+           xsd:NMTOKEN
+         }
+       | element date_valid {
+           attribute class { xsd:NCName },
+           xsd:NMTOKEN
+         }
+       | element language {
+           attribute class { xsd:NCName },
+           xsd:NCName
+         }
+       | element keywords {
+           attribute class { xsd:NCName },
+           text
+         }
+       | element meta {
+           attribute content { text }?,
+           attribute http-equiv { xsd:NCName }?,
+           text
+         }
+       | element rights {
+           attribute class { xsd:NCName },
+           (text | link)+
+         }
+       | element source {
+           attribute class { xsd:NCName },
+           text
+         }
+       | element structure {
+           attribute class { xsd:NCName },
+           text
+         }
+       | element subject {
+           attribute class { xsd:NCName },
+           text
+         }
+       | element title {
+           attribute class { xsd:NCName },
+           text
+         }
+       | element type {
+           attribute class { xsd:NCName },
+           xsd:NCName
+         })+
+    },
+    element body {
+      element object {
+        attribute id { xsd:integer },
+        (element endnote {
+           attribute notenumber { xsd:integer }?,
+           attribute symbol { text }?,
+           (text
+            | b
+            | br
+            | del
+            | i
+            | link
+            | sup
+            | u
+            | element em { xsd:NCName }
+            | element sub { xsd:NCName })+
+         }
+         | element ocn { text }
+         | element text {
+             attribute class { xsd:NCName },
+             (text
+              | b
+              | br
+              | del
+              | en
+              | i
+              | link
+              | sup
+              | u
+              | element image {
+                  attribute alt { text }?,
+                  attribute height { xsd:integer }?,
+                  attribute width { xsd:integer }?,
+                  attribute xl:actuate { xsd:NCName },
+                  attribute xl:href { text },
+                  attribute xl:show { xsd:NCName },
+                  attribute xl:type { xsd:NCName }
+                }
+              | element sub { text })+
+           })+,
+        element table {
+          attribute align { xsd:NCName },
+          attribute bgcolor { xsd:NCName },
+          attribute border { xsd:integer },
+          attribute cellpadding { xsd:integer },
+          attribute summary { text },
+          attribute width { text },
+          element tr {
+            element td {
+              attribute valign { xsd:NCName },
+              attribute width { text },
+              (text | b | i)+
+            }+
+          }+
+        }?
+      }+
+    }
+  }
+br = element br { empty }
+en = element en { text }
+sup = element sup { xsd:NCName }
+i = element i { (text | b | br | sup)+ }
+link =
+  element link {
+    attribute xl:href { xsd:anyURI },
+    attribute xl:type { xsd:NCName },
+    (text | b | i | sup)+
+  }
+b = element b { (text | en | i | link | sup)+ }
+u = element u { (text | b | i)+ }
+del = element del { (text | b | i | link)+ }
+RELAXNG
+    end
+    def rnc_model_input_sax
+      @relaxng =<<RELAXNG
+#% sax input model, part of SiSU and distributed under the same license
+default namespace = ""
+start =
+  element document {
+    element head {
+      element header {
+        attribute class { xsd:NCName },
+        (element creator { text }
+         | element date { xsd:NMTOKEN }
+         | element date.available { xsd:NMTOKEN }
+         | element date.created { xsd:NMTOKEN }
+         | element date.issued { xsd:NMTOKEN }
+         | element date.modified { xsd:NMTOKEN }
+         | element date.valid { xsd:NMTOKEN }
+         | element italicize { text }
+         | element language { xsd:NCName }
+         | element links { text }
+         | element markup { text }
+         | element rights { text }
+         | element subject { text }
+         | element title { text }
+         | element type { xsd:NCName }
+         | element vocabulary { xsd:NCName })
+      }+
+    },
+    element body {
+      element object {
+        element text {
+          attribute class { xsd:NCName },
+          (text
+           | b
+           | i
+           | element endnote {
+               attribute symbol { xsd:NCName },
+               (text
+                | i
+                | element br { empty })+
+             }
+           | element u { i }
+           | element image.path { text })+
+        }?
+      }+
+    }
+  }
+i = element i { text }
+b = element b { text }
+RELAXNG
+    end
+    def rnc_model_input_dom
+      @relaxng =<<RELAXNG
+#% dom input model, part of SiSU and distributed under the same license
+default namespace = ""
+start =
+  element document {
+    element head {
+      element header {
+        attribute class { xsd:NCName },
+        (element creator { text }
+         | element date { xsd:NMTOKEN }
+         | element date.available { xsd:NMTOKEN }
+         | element date.created { xsd:NMTOKEN }
+         | element date.issued { xsd:NMTOKEN }
+         | element date.modified { xsd:NMTOKEN }
+         | element date.valid { xsd:NMTOKEN }
+         | element italicize { text }
+         | element language { xsd:NCName }
+         | element links { text }
+         | element markup { text }
+         | element rights { text }
+         | element subject { text }
+         | element title { text }
+         | element type { xsd:NCName }
+         | element vocabulary { xsd:NCName })
+      }+
+    },
+    element body {
+      element heading1 {
+        heading,
+        element heading2 {
+          heading,
+          contents1+,
+          element heading3 { heading, contents1+ }+
+        }
+      }
+    }
+  }
+heading = element heading { object }
+contents1 =
+  element contents1 {
+    heading,
+    content,
+    element contents2 {
+      heading,
+      content,
+      element contents3 { heading, content }*
+    }*
+  }
+object =
+  element object {
+    element text {
+      (text
+       | italic
+       | element bold { xsd:NMTOKEN }
+       | element endnote {
+           element symbol { text }?,
+           element note {
+             (text
+              | italic
+              | element br { empty })+
+           }
+         }
+       | element underscore { italic }
+       | element image.path { text }
+       | element italic { text })+
+    }
+  }
+italic = element italic { text }
+content = element content { object+ }
+RELAXNG
+    end
+    def rnc_model_input_node
+      @relaxng =<<RELAXNG
+#% node input model, part of SiSU and distributed under the same license
+default namespace = ""
+start =
+  element document {
+    element head {
+      element header {
+        attribute class { xsd:NCName },
+        (element creator { text }
+         | element date { xsd:NMTOKEN }
+         | element date.available { xsd:NMTOKEN }
+         | element date.created { xsd:NMTOKEN }
+         | element date.issued { xsd:NMTOKEN }
+         | element date.modified { xsd:NMTOKEN }
+         | element date.valid { xsd:NMTOKEN }
+         | element italicize { (text | i)+ }
+         | element language { xsd:NCName }
+         | element links { text }
+         | element markup { text }
+         | element rights { text }
+         | element subject { text }
+         | element title { text }
+         | element type { xsd:NCName }
+         | element vocabulary { xsd:NCName })
+      }+
+    },
+    element body {
+      element object {
+        (element text {
+           attribute class { xsd:NCName },
+           (text
+            | b
+            | i
+            | element br { empty }
+            | element endnote {
+                attribute symbol { xsd:NCName },
+                (text | i)+
+              }
+            | element image.path { text }
+            | element sub { text })+
+         }
+         | (element ocn { empty },
+            element table {
+              attribute align { xsd:NCName },
+              attribute bgcolor { xsd:NCName },
+              attribute border { xsd:integer },
+              attribute cellpadding { xsd:integer },
+              attribute summary { text },
+              attribute width { text },
+              element tr {
+                element td {
+                  attribute valign { xsd:NCName },
+                  attribute width { text },
+                  (text | b)+
+                }+
+              }+
+            })),
+        element node {
+          element id { xsd:integer },
+          element parent { xsd:integer },
+          element offspring { text }?
+        }
+      }+
+    }
+  }
+b = element b { text }
+i = element i { text }
+RELAXNG
+    end
+  end
+end
+__END__
+needs updating
+#+END_SRC
+
+** remote.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/remote.rb"
+# <<sisu_document_header>>
+module SiSU_Remote
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  class Put
+    def initialize(opt)
+      @opt=opt
+      @dir=SiSU_Env::InfoEnv.new(@opt.fns)
+      @put=(@opt.fns =~/\.ssm\.sst$/) \
+      ? opt.fns.gsub(/(.+)?\.ssm\.sst$/,'\1.ssm')
+      : opt.fns
+      @remote=SiSU_Env::InfoRemote.new(opt)
+    end
+    def rsync
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        'Remote placement ->',
+        @put
+      ).dark_grey_title_hi unless @opt.act[:quiet][:set]==:on
+      @remote.rsync.document
+    end
+    def rsync_base
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        'Remote placement ->',
+        'rsync'
+      ).dark_grey_title_hi unless @opt.act[:quiet][:set]==:on
+      @remote.rsync.site_base
+    end
+    def rsync_base_sync
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        'Remote placement ->',
+        'rsync and sync'
+      ).dark_grey_title_hi unless @opt.act[:quiet][:set]==:on
+      @remote.rsync.site_base_sync
+    end
+    def rsync_sitemaps
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        'Remote placement sitemaps ->',
+        'rsync'
+      ).dark_grey_title_hi unless @opt.act[:quiet][:set]==:on
+      @remote.rsync_sitemaps
+    end
+    def rsync_harvest
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        'Remote placement metadata harvest ->',
+        'rsync_harvest'
+      ).dark_grey_title_hi unless @opt.act[:quiet][:set]==:on
+      @remote.rsync.site_harvest
+    end
+    def scp
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        'Remote placement ->',
+        @put
+      ).dark_grey_title_hi unless @opt.act[:quiet][:set]==:on
+      @remote.scp.document
+    end
+    def scp_base
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        'Remote placement of base site ->',
+        'excluding images'
+      ).dark_grey_title_hi unless @opt.act[:quiet][:set]==:on
+      @remote.scp.site_base
+    end
+    def scp_base_all
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        'Remote placement ->',
+        'complete'
+      ).dark_grey_title_hi unless @opt.act[:quiet][:set]==:on
+      @remote.scp.site_base_all
+    end
+  end
+  class Get
+    def initialize(opt,get_s)
+      @opt,@get_s=opt,get_s
+      @msg,@msgs='',nil
+      @tell=lambda {
+        SiSU_Screen::Ansi.new(@opt.act[:color_state][:set],
+        @msg,
+        "#{@msgs.inspect if @msgs}")
+      }
+    end
+    def fns
+      begin
+        require 'open-uri'
+        require 'pp'
+      rescue LoadError
+        SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+          error('open-uri or pp NOT FOUND (LoadError)')
+      end
+      require_relative 'ao_composite'                   # ao_composite.rb
+      @rgx_image=/(?:^|[^_\\])\{\s*(\S+?\.(?:png|jpg|gif))/
+      threads=[]
+      for requested_page in @get_s
+        re_fnb=/((?:https?|file):\/\/[^\/ ]+?\/[^\/ ]+?)\/\S+?\/([^\/]+?)\.ss(t)/ #revisit and remove DO
+        threads << Thread.new(requested_page) do |url|
+          open(url) do |f|
+            raise "#{url} not found" unless f
+            base_uri,fnb=re_fnb.match(url)[1..2] if re_fnb
+            imagedir=base_uri + '/_sisu/image' #check on
+            downloaded_file=File.new("#{fnb}.-sst",'w+')
+            image_download_url=SiSU_Assemble::RemoteImage.new.image(imagedir)
+            images=[]
+            f.collect.each do |r|                            # work area
+              unless r =~/^%+\s/
+                if r !~/^%+\s/ \
+                and r =~@rgx_image
+                  images << r.scan(@rgx_image).uniq
+                end
+              end
+              downloaded_file << r
+            end
+            if images \
+            and images.length > 1
+              images=images.flatten.uniq
+              images.delete_if {|x| x =~/https?:\/\// }
+              images=images.sort
+              @msg,@msgs='downloading images:', [ images.join(',') ]
+              @tell.call.warn unless @opt.act[:quiet][:set]==:on
+              image_info=image_download_url + images
+              SiSU_Assemble::RemoteImage.new.download_images(image_info)
+              #SiSU_Assemble::RemoteImage.new.download_images(image_download_url,images)
+              @msg,@msgs='downloading done',nil
+              @tell.call.warn unless @opt.act[:quiet][:set]==:on
+            end
+            downloaded_file.close
+          end
+        end
+      end
+      threads.each {|thr| thr.join} if threads #and threads.length > 0
+    end
+    def sisupod
+      get_p=@get_s
+      if get_p.length > 0                                     #% remote sisupod
+        begin
+          require 'net/http'
+        rescue LoadError
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+            error('net/http NOT FOUND (LoadError)')
+        end
+        for requested_pod in get_p
+          pod_info=RemoteDownload.new(requested_pod)
+          Net::HTTP.start(pod_info.pod.site) do |http|
+            resp=http.get("#{pod_info.pod.path}/#{pod_info.pod.name_source}")
+            open(pod_info.pod.name,'wb') do |file|
+              file.write(resp.body)
+             end
+          end
+        end
+      end
+    end
+  end
+  class RemoteDownload
+    def initialize(requested_file)
+      @requested_file=requested_file
+    end
+    def pod
+      re_p_div=/https?:\/\/([^\/]+)(\/\S+)\/(sisupod\.(?:txz|zip)|\S+?(?:\.ss[mt]\.(?:txz|zip))?|[^\/]+?\.ssp)$/
+      re_p=/(sisupod\.(?:txz|zip)|\S+?\.ss[mt]\.(?:txz|zip)?|[^\/]+?\.ssp)$/
+      if @requested_file =~ re_p_div
+        @site,@pth,@pod= re_p_div.match(@requested_file).captures
+      elsif @requested_file =~ re_p
+        @pod=re_p.match(@requested_file).captures.join
+      end
+      def site
+        @site
+      end
+      def path
+        @pth
+      end
+      def dir_stub
+        re_p_stub=/.+?([^\/]+)$/
+        re_p_stub.match(path).captures.join if path
+      end
+      def name_source
+        @pod
+      end
+      def name
+        name_source
+      end
+      self
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** rexml.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/rexml.rb"
+# <<sisu_document_header>>
+module SiSU_Rexml
+  # load XML file for REXML parsing
+  begin
+    require 'rexml/document' \
+      if FileTest.directory?("#{RbConfig::CONFIG['rubylibdir']}/rexml") #RbConfig::CONFIG['sitedir']
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('rexml/document NOT FOUND (LoadError)')
+  end
+  require_relative 'dp'                                 # dp.rb
+    include SiSU_Param
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  class Rexml
+    begin
+      require 'rexml/document' \
+        if FileTest.directory?("#{RbConfig::CONFIG['rubylibdir']}/rexml") #RbConfig::CONFIG['sitedir']
+    rescue LoadError
+      SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+        error('rexml/document NOT FOUND (LoadError)')
+    end
+    def initialize(md,fno)
+      @md,@fno=md,fno
+      @env=SiSU_Env::InfoEnv.new(@md.fns)
+      @prog=SiSU_Env::InfoProgram.new #(md.fns) #if md
+      if File.file?(@fno)
+        @fnap=@fno #index.xml causes problems with index.html in server config
+      end
+      @e_head='/document/head'
+      @e_title='/document/head/title'
+      @e_object='/document/body/object'
+      @e_ocn='/document/body/object/ocn'
+      @e_text='/document/body/object/text'
+      @e_endnote='/document/body/object/endnote'
+    end
+    def xml
+      begin
+        if FileTest.file?(@fnap)
+          if @prog.rexml !=false \
+          and FileTest.directory?('/usr/lib/ruby/1.8/rexml/') #note values can be other than true
+            xmlfile=IO.readlines(@fnap,'').join
+            begin
+              @xmldoc=REXML::Document.new xmlfile
+              SiSU_Screen::Ansi.new(
+                @md.opt.act[:color_state][:set],
+                'invert',
+                'REXML',
+                "XML document #{@fnap} loaded"
+              ).colorize unless @md.opt.act[:quiet][:set]==:on
+              if (@opt.act[:verbose][:set]==:on \
+              || @opt.act[:verbose_plus][:set]==:on)
+                @xmldoc.elements.each(@e_head) do |e|
+                  SiSU_Screen::Ansi.new(
+                    @md.opt.act[:color_state][:set],
+                    'brown',
+                    e
+                  ).colorize unless @md.opt.act[:quiet][:set]==:on
+                end
+              end
+            rescue REXML::ParseException
+              puts 'broken XML'
+            end
+          end
+        else
+          SiSU_Screen::Ansi.new(
+            @md.opt.act[:color_state][:set],
+            'fuchsia',
+            "File Not Found #{xmlfile}",
+            'requested XML processing skipped'
+          ).colorize unless @md.opt.act[:quiet][:set]==:on
+          exit
+        end
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+  end
+end
+__END__
+ misc
+e.each do |element|
+  element.each do |child|
+    if child.is_a?(REXML::Text)
+      puts "Text: #{child.to_s.inspect}"
+    else
+      puts "SubElement: #{child.name}"
+    end
+  end
+end
+#+END_SRC
+
+** sitemaps.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/sitemaps.rb"
+# <<sisu_document_header>>
+module SiSU_Sitemaps
+  require_relative 'dp'                                 # dp.rb
+    include SiSU_Param
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'xml_shared'                         # xml_shared.rb
+    include SiSU_XML_Munge
+  class Source
+    def initialize(opt)
+      @opt=opt
+    end
+    def read
+      songsheet
+    end
+    def songsheet
+      begin
+        @sys=SiSU_Env::SystemCall.new
+        fn_set_lang=SiSU_Env::StandardiseLanguage.new(@opt.lng).language
+        @fn=SiSU_Env::EnvCall.new(@opt.fns).lang(fn_set_lang[:c])
+        if @opt.act[:sitemap][:set]==:on
+          @md=SiSU_Param::Parameters.new(@opt).get
+          @trans=SiSU_XML_Munge::Trans.new(@md) #check @md is required
+          @env=SiSU_Env::InfoEnv.new(@md.fns)
+#         @file=SiSU_Env::FileOp.new(@md)
+          @rdf=SiSU_XML_Tags::RDF.new(@md)
+          @fnb_utf8_xml=@md.fnb.dup
+          @trans.char_enc.utf8(@fnb_utf8_xml) \
+            if @sys.locale =~/utf-?8/i
+          output_map(sitemap)
+        elsif @opt.selections.str =~/--sitemaps/
+          @sitemap_idx_fn='sitemapindex.xml'
+          @env=SiSU_Env::InfoEnv.new
+          output_idx(sitemap_index)
+          SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'sitemap index:',
+            "#{@env.path.output}/#{@sitemap_idx_fn}"
+          ).result unless @opt.act[:quiet][:set]==:on
+        end
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.cmd,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    def make_file(path,filename)
+      (File.writable?("#{path}/.")) \
+      ? (File.new("#{path}/#{filename}",'w+'))
+      : (SiSU_Screen::Ansi.new(
+           '',
+           "is the file or directory writable?, could not create #{filename}"
+         ).warn)
+    end
+    def output_map(sitemap)
+      path=@md.file.output_path.sitemaps.dir
+      filename=@fn[:sitemap]
+      touch_path=@md.file.output_path.sitemaps.dir
+      touch_filename=@fn[:sitemap_touch]
+      SiSU_Env::FileOp.new(@md).make_path(path)
+      file=SiSU_Env::FileOp.new(@md).make_file(path,filename)
+      file << sitemap
+      if FileTest.file?("#{touch_path}/#{touch_filename}")
+        FileUtils::rm("#{touch_path}/#{touch_filename}")
+      end
+    end
+    def output_idx(sitemap)
+      path=@env.path.output
+      filename=@sitemap_idx_fn
+      make_path(path)
+      file=make_file(path,filename)
+      file << sitemap
+    end
+    def sitemap_index
+      sitemap_files=Dir.glob("#{@env.path.sitemaps}/sitemap_*.xml")
+      sitemap_idx=[]
+      sitemap_idx << <<WOK
+<?xml version="1.0" encoding="UTF-8"?>
+<sitemapindex xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+   xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemaps/0.9
+   http://www.sitemaps.org/schemas/sitemaps/sitemap.xsd"
+     xmlns="http://www.sitemaps.org/schemas/sitemapindex/0.9">
+WOK
+      sitemap_files.each do |s|
+        f=s.gsub(/.+?\/sitemap_([^\/]+?)\.xml$/,'\1')
+        @trans.char_enc.utf8(f) \
+          if @sys.locale =~/utf-?8/i
+sitemap_idx << <<WOK
+  <sitemap>
+    <loc>#{@env.path.url.remote}/#{f}/sitemap.xml</loc>
+  </sitemap>
+WOK
+      end
+      sitemap_idx << <<WOK
+</sitemapindex>
+WOK
+      sitemap_idx.join
+    end
+    def sitemap
+      if defined? @md.date.modified \
+      and @md.date.modified=~/\d{4}-\d{2}-\d{2}/
+        sitemap_date_modified
+      else sitemap_no_date
+      end
+    end
+    def sitemap_date_modified
+<<WOK
+<?xml version='1.0' encoding='UTF-8'?>
+<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemaps/0.9
+  http://www.sitemaps.org/schemas/sitemaps/sitemap.xsd"
+  xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
+#{@rdf.comment_xml}
+  <url>
+    <loc>#{@env.path.url.remote}/#{@fnb_utf8_xml}/#{@fn[:toc]}</loc>
+    <lastmod>#{@md.date.modified}</lastmod>
+    <changefreq>monthly</changefreq>
+    <priority>0.7</priority>
+  </url>
+  <url>
+    <loc>#{@env.path.url.remote}/#{@fnb_utf8_xml}/#{@fn[:doc]}</loc>
+    <lastmod>#{@md.date.modified}</lastmod>
+    <priority>0.5</priority>
+  </url>
+  <url>
+    <loc>#{@env.path.url.remote}/#{@fnb_utf8_xml}/#{@fn[:manifest]}</loc>
+    <lastmod>#{@md.date.modified}</lastmod>
+    <priority>0.5</priority>
+  </url>
+</urlset>
+WOK
+    end
+    def sitemap_no_date
+<<WOK
+<?xml version="1.0" encoding="UTF-8"?>
+<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
+#{@rdf.comment_xml}
+  <url>
+    <loc>#{@env.path.url.remote}/#{@fnb_utf8_xml}/#{@fn[:toc]}</loc>
+    <changefreq>monthly</changefreq>
+    <priority>0.7</priority>
+  </url>
+  <url>
+    <loc>#{@env.path.url.remote}/#{@fnb_utf8_xml}/#{@fn[:doc]}</loc>
+    <priority>0.5</priority>
+  </url>
+  <url>
+    <loc>#{@env.path.url.remote}/#{@fnb_utf8_xml}/#{@fn[:manifest]}</loc>
+    <priority>0.5</priority>
+  </url>
+</urlset>
+WOK
+    end
+  end
+end
+__END__
+,* sanitize xml, pass through filter to ensure is valid - done but needs testing
+,* remote placement of sitemaps --sitemaps -R (probably makes more sense than doing against -Y [filename/wildcard]) - done but needs testing
+,* gzip sitemaps - not before testing / after testing
+,* issue with master documnts, naming and mapping, check multilingual
+
+<!-- Document processing information:
+     * Generated by: SiSU 0.48.6 of 2006w45/6 (20061111)
+     * Ruby version: ruby 1.8.5 (2006-08-25) [i486-linux]
+     *
+     * Last Generated on: Sat Nov 18 15:28:08 +0000 2006
+     * SiSU http://www.jus.uio.no/sisu
+-->
+#+END_SRC
+
+** termsheet.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/termsheet.rb"
+# <<sisu_document_header>>
+require_relative 'se'                                   # se.rb
+require_relative 'dp'                                   # dp.rb
+  include SiSU_Param
+@do,@done,@used,@html_output,@txt_input,@txt_output,@@report=Array.new(7){[]}
+@@info=nil
+@c=0
+@cX=SiSU_Screen::Ansi.new('yes').cX
+@done << "\n#{@cX.blue_hi}#{@cX.black}Summary#{@cX.off*2}"
+def talent(termsheet,flag)
+  @@info=nil
+  @@info=termsheet.gsub(/(.+?)\.termsheet\.rb/,'../facility_data/\1.html')
+  @env=SiSU_Env::InfoEnv.new
+  @dir_fd="#{@env.path.output}/facility_data"
+  FileUtils::mkdir_p(@dir_fd) unless FileTest.directory?(@dir_fd)==true
+  html_output=[]
+  case termsheet
+  when /.+?\.(termsheet)\.rb$/
+    @basename=termsheet[/(.+?)\.termsheet\.rb/, 1]
+    @standard_form={}
+    require termsheet
+    include Termsheet
+    @standard_form=Termsheet::StandardForms.new.standardforms
+    puts %{\n#{@@cX.yellow_hi}#{@@cX.black}From#{@@cX.off*2}: #{@@cX.grey_hi}#{@@cX.black}#{@basename}.termsheet.rb#{@@cX.off*3}\n\n}
+    @standard_form.each do |k,v|
+      @c+=1
+      require v
+      puts %{\n#{@@cX.blue_hi}#{@@cX.black}Producing the following#{@@cX.off*2}: #{@@cX.green}#{@basename}.#{k}#{@@cX.off}\n\n}
+      @done << %{\n\t#{@@cX.grey}Documents generated#{@@cX.off}: #{@@cX.cyan}#{@basename}.#{k}#{@@cX.off}\n}
+      @used << %{\n\t#{@@cX.grey}Using#{@@cX.off}: #{@@cX.ruby}#{v}#{@@cX.off}\n}
+      html_output=<<WOK
+<br /><a href="../#{@basename}.#{k}/landscape.pdf">
+<img border="0" width="18" height="15" src="../_sisu/image/b_pdf.png" alt="pdf landscape"></a>&nbsp;
+<a href="../#{@basename}.#{k}/portrait.pdf">
+<img border="0" width="15" height="18" src="../_sisu/image/b_pdf.png" alt="pdf portrait"></a>&nbsp;
+<a href="../#{@basename}.#{k}/sisu_manifest.html">#{@basename}.#{k}.sisu_manifest.html</a>
+WOK
+      @html_output << html_output
+      @txt_input << %{\n\tForm #{@c}: <url:#{Dir.pwd}/#{v}>\n\t        |#{Dir.pwd}/#{v}|@|^|\n}
+      @txt_output << %{\n\t#{k}: |../#{@basename}.#{k}/sisu_manifest.html|@|^|\n}
+      @report_file_i=File.new("#{@dir_fd}/#{@basename}.txt",'w+')
+      @report_file_o=File.new("#{@dir_fd}/#{@basename}.html",'w+')
+      @filename_new=File.new("#{@basename}.#{k}.sst",'w+')
+      @do << %{#{k}}
+      @filename_new << @document
+        # "require v" pulls in the composite @document
+        # "termsheet" having all the variables required to complete the standard form @document
+      @filename_new.close
+    end
+    @do.each do |x|
+      system %{sisu -Nhwpo #{@basename}.#{x}.sst\n}
+    end
+  else print "not processed --> ", termsheet, "\n"
+  end
+  @done << %{\n\t#{@@cX.green}Summary:#{@@cX.off} #{@@cX.blue}#{@env.path.output}/facility_data/#{@basename}.html#{@@cX.off}\n}
+  @done << %{\n\t#{@@cX.grey}From details provided in#{@@cX.off}: #{@@cX.green}#{termsheet}#{@@cX.off}\n}
+  terms=%{\nTermsheet: <url:#{Dir.pwd}/#{termsheet}>\n           |#{Dir.pwd}/#{termsheet}|@|^|\n}
+  @report_file_i << "<url:all.txt>\n|all.txt|@|^|\n" << terms << "\nForms:\n" << @txt_input  << "\nOutput Files\n" << @txt_output
+  @report_file_o << %{<a href="toc.html">^</a><br />\n} << @html_output
+  @@report << @done << @used << "\n"
+  @done,@used=[],[]
+end
+require_relative 'dp'                                   # dp.rb
+@argv=$*
+@proc="#{@argv[0].to_s}"
+if @proc =~  /^-?[wft]/
+  @argv.shift
+  @argv.each do |termsheet|
+    talent(termsheet,@proc)
+  end
+end
+@env=SiSU_Env::InfoEnv.new
+@dir_fd="#{@env.path.output}/facility_data"
+@url="#{@env.url.webserv}/facility_data"
+@@report << %{\n#{@@cX.grey}See#{@@cX.off}: #{@@cX.blue}#{@dir_fd}/all.txt\t#{@dir_fd}/toc.html\t#{@dir_fd}/#{@@cX.off}\n\n#{@@cX.grey}See#{@@cX.off}: #{@@cX.blue}#{@url}/all.txt\t#{@url}/toc.html\t#{@url}/#{@@cX.off}\n\n}
+puts @@report
+File.unlink("#{@dir_fd}/all.txt") if FileTest.file?("#{@dir_fd}/all.txt")
+File.unlink("#{@dir_fd}/toc.html") if FileTest.file?("#{@dir_fd}/toc.html")
+summary_file=File.new("#{@dir_fd}/all.txt",'w+')
+summary_html=File.new("#{@dir_fd}/toc.html",'w+')
+ls_txt=%x{ls #{@dir_fd}/*.txt}
+report_thlnk=[]
+ls_txt.scan(/.+/)
+ls_txt.each {|x| report_thlnk << x.gsub!(/#{@dir_fd}\/(.+)/,"<url:\\1>\n|\\1|@|^|")}
+report_thlnk.join("\n")
+ls_html=%x{ls #{@dir_fd}/*.html}
+report_html=[]
+ls_html.split(/.+/)
+ls_html.each {|x| report_html << x.gsub!(/#{@dir_fd}\/(.+)/,'<a href="\1">\1</a><br />')}
+report_html.join("\n")
+summary_file << "#{report_thlnk}"
+summary_html << "#{report_html}"
+__END__
+,** NOTE wrapper makes little sense without additional components, additional
+   sample files must be provided - (saved till later as may confuse)
+,*** bits
+sisu -t x_bank.and.*
+e.g. sisu -t x_bank.and.*.termsheet.rb
+e.g. sisu_termsheet.rb -t x_bank.and.c*.termsheet.rb
+program calls upon termsheet file with extension termsheet.rb
+termsheet.rb calls upon relevant standard form files (to be used) with extension .sForm.rb
+there is also a standard_terms.rb file - with terms/details that are  constant
+the file produced is named after the termsheet.rb with that extension replaced with .er30
+from there scribbler.rb is called upon its usual metaVerse html and pdf  creation
+! :-)
+to test run
+termsheet.rb -f dev.export.import.trade.facility.termsheet.rb
+the term sheet calls the standard form or template that is to be run against it.
+#+END_SRC
+
+** update.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/update.rb"
+# <<sisu_document_header>>
+module SiSU_UpdateControlFlag
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  include SiSU_Param
+  class Check
+    def initialize(opt)
+      @opt=opt
+      @md=SiSU_Param::Parameters.new(@opt).get
+    end
+    def read
+      begin
+        @env=SiSU_Env::InfoEnv.new(@md.fns)
+        out=@env.path.output
+        base_path="#{out}/#{@md.fnb}"
+        SiSU_Screen::Ansi.new(
+          @md.opt.act[:color_state][:set],
+          'Checking previous output',
+          base_path
+        ).green_hi_blue unless @md.opt.act[:quiet][:set]==:on
+        SetCF.new(@md).set_flags
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    private
+    class SetCF
+      def initialize(md)
+        @md=md
+        @env=SiSU_Env::InfoEnv.new(@md.fns)
+        out=@env.path.output
+        @base_path="#{out}/#{@md.fnb}"
+        @pdf_fn=SiSU_Env::FileOp.new(@md).base_filename
+      end
+      def set_flags #-mNhwpoabxXyv
+        flag='-v'
+        if FileTest.file?("#{@md.file.output_path.txt.dir}/#{@md.file.base_filename.txt}")==true
+          flag=flag + 'a'
+        end
+        if FileTest.file?("#{@md.file.output_path.html_seg.dir}/#{@md.file.base_filename.html_seg}")==true \
+        or FileTest.file?("#{@md.file.output_path.html_scroll.dir}/#{@md.file.base_filename.html_scroll}")==true
+          flag=flag + 'h'
+        end
+        if FileTest.file?("#{@md.file.output_path.xhtml.dir}/#{@md.file.base_filename.xhtml}")==true
+          flag=flag + 'b'
+        end
+        if FileTest.file?("#{@md.file.output_path.xml_sax.dir}/#{@md.file.base_filename.xml_sax}")==true
+          flag=flag + 'x'
+        end
+        if FileTest.file?("#{@md.file.output_path.xml_dom.dir}/#{@md.file.base_filename.xml_dom}")==true
+          flag=flag + 'X'
+        end
+        if FileTest.file?("#{@md.file.output_path.epub.dir}/#{@md.file.base_filename.epub}")==true
+          flag=flag + 'e'
+        end
+        if FileTest.file?("#{@md.file.output_path.odt.dir}/#{@md.file.base_filename.odt}")==true
+          flag=flag + 'o'
+        end
+        if FileTest.file?("#{@md.file.output_path.pdf.dir}/#{@pdf_fn.pdf_p_a4}")==true \
+        or FileTest.file?("#{@md.file.output_path.pdf.dir}/#{@pdf_fn.pdf_l_a4}")==true \
+        or FileTest.file?("#{@md.file.output_path.pdf.dir}/#{@pdf_fn.pdf_p_letter}")==true \
+        or FileTest.file?("#{@md.file.output_path.pdf.dir}/#{@pdf_fn.pdf_l_letter}")==true
+          flag=flag + 'p'
+        end
+        if FileTest.file?("#{@md.file.output_path.html_concordance.dir}/#{@md.file.base_filename.html_concordance}")==true
+          flag=flag + 'w'
+        end
+        if FileTest.file?("#{@md.file.output_path.digest.dir}/#{@md.file.base_filename.digest}")==true
+          flag=flag + 'N'
+        end
+        if FileTest.file?("#{@md.file.output_path.src.dir}/#{@md.file.base_filename.src}")==true
+          flag=flag + 's'
+        end
+        if FileTest.file?("#{@md.file.output_path.sisupod.dir}/#{@md.file.base_filename.sisupod}")==true
+          flag=flag + 'S'
+        end
+        puts flag
+        flag
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** urls.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/urls.rb"
+# <<sisu_document_header>>
+module SiSU_Urls
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+    include SiSU_Particulars
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env; include SiSU_Screen
+  class Source
+    attr_reader :opt
+    def initialize(opt)
+      @opt=opt
+    end
+    def read
+      begin
+        SiSU_Urls::OutputUrls.new(@opt).songsheet if @opt.fnb
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+  end
+  class OutputUrls
+    attr_reader :fns,:fnb,:act,:dir,:m_regular,:u
+    def initialize(opt)
+      @opt=opt
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_env_md(opt)
+      if @particulars.is_a?(NilClass)
+        if @opt.act[:verbose_plus][:set]==:on \
+        or @opt.act[:maintenance][:set]==:on
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+            mark("@particulars is NilClass, acceptable e.g. for --harvest")
+        end
+        exit
+      end
+      @selections=@opt.selections.str
+      @act=@opt.act
+      @md=@particulars.md
+      @env=@particulars.env
+      @fnb=@env.fnb
+      fn_set_lang=SiSU_Env::StandardiseLanguage.new(@opt.lng).language
+      @fnl=@env.i18n.lang_filename(fn_set_lang[:c])
+      @fn=SiSU_Env::EnvCall.new(@opt.fns).lang(fn_set_lang[:c])
+      @m_regular=/(.+?)\.(?:(?:-|ssm\.)?sst|ssm)$/
+      @prog=@env.program
+    end
+    def songsheet
+      begin
+        (@opt.act[:urls_all][:set]==:on) \
+        ? urls_all \
+        : (urls_select unless @opt.act[:quiet][:set]==:on)
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    def show
+      def report(x)
+        SiSU_Screen::Ansi.new(
+          @opt.act[:color_state][:set],
+          "[#{@opt.f_pth[:lng_is]}]",
+          x[:cmd],
+          x[:viewer] + ' ' \
+          + x[:f_pth]
+        ).result
+      end
+      def maintenance(x)
+        if @opt.act[:maintenance][:set]==:on
+          SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            "[#{@opt.f_pth[:lng_is]}]",
+            x[:cmd],
+            x[:p_pth]
+          ).maintenance
+        end
+      end
+      self
+    end
+    def report_info
+      def dal
+        {
+          cmd: '--ao',
+          p_pth: @env.processing_path.ao + '/' \
+          + @opt.fns + '.meta',
+          fn: 'ao',
+         }
+      end
+      def hash_digests
+        {
+          cmd: '--hash-digests (sha512/sha256/md5)',
+          viewer: @prog.web_browser,
+          f_pth: @md.file.output_path.hash_digest.dir + '/' \
+          + @md.file.base_filename.hash_digest,
+          fn: @fn[:digest],
+         }
+      end
+      def text
+        def txt
+          {
+            cmd: '--txt',
+            viewer: @prog.web_browser,
+            f_pth: @md.file.output_path.txt.dir + '/' \
+            + @md.file.base_filename.txt,
+            fn: @fn[:plain],
+           }
+        end
+        def asciidoc
+          {
+            cmd: '--asciidoc',
+            viewer: @prog.web_browser,
+            f_pth: @md.file.output_path.asciidoc.dir + '/' \
+            + @md.file.base_filename.asciidoc,
+            fn: @fn[:txt_asciidoc],
+           }
+        end
+        def markdown
+          {
+            cmd: '--markdown',
+            viewer: @prog.web_browser,
+            f_pth: @md.file.output_path.markdown.dir + '/' \
+            + @md.file.base_filename.markdown,
+            fn: @fn[:txt_markdown],
+           }
+        end
+        def rst
+          {
+            cmd: '--rst',
+            viewer: @prog.web_browser,
+            f_pth: @md.file.output_path.rst.dir + '/' \
+            + @md.file.base_filename.rst,
+            fn: @fn[:txt_rst],
+           }
+        end
+        def textile
+          {
+            cmd: '--textile',
+            viewer: @prog.web_browser,
+            f_pth: @md.file.output_path.textile.dir + '/' \
+            + @md.file.base_filename.textile,
+            fn: @fn[:txt_textile],
+           }
+        end
+        def orgmode
+          {
+            cmd: '--orgmode',
+            viewer: @prog.web_browser,
+            f_pth: @md.file.output_path.orgmode.dir + '/' \
+            + @md.file.base_filename.orgmode,
+            fn: @fn[:txt_orgmode],
+           }
+        end
+        self
+      end
+      def html
+        def seg
+          {
+            cmd: '--html-seg',
+            viewer: @prog.web_browser,
+            f_pth: @md.file.output_path.html_seg.dir + '/' \
+            + @md.file.base_filename.html_segtoc,
+            p_pth: @env.processing_path.tune + '/' \
+            + @md.fns + '.tune',
+            fn: @fn[:toc],
+           }
+        end
+        def scroll
+          {
+            cmd: '--html-scroll',
+            viewer: @prog.web_browser,
+            f_pth: @md.file.output_path.html_scroll.dir + '/' \
+            + @md.file.base_filename.html_scroll,
+            p_pth: @env.processing_path.tune + '/' \
+            + @md.fns + '.tune',
+            fn: @fn[:doc],
+           }
+        end
+        def concordance
+          {
+            cmd: '--concordance',
+            viewer: @prog.web_browser,
+            f_pth: @md.file.output_path.html_concordance.dir + '/' \
+            + @md.file.base_filename.html_concordance,
+            fn: @fn[:concordance],
+           }
+        end
+        self
+      end
+      def xhtml
+        def xhtml
+          {
+            cmd: '--xhtml',
+            viewer: @prog.web_browser,
+            f_pth: @md.file.output_path.xhtml.dir + '/' \
+            + @md.file.base_filename.xhtml,
+            p_pth: @env.processing_path.tune + '/' \
+            + @md.fns + '.tune',
+            fn: @fn[:xhtml],
+           }
+        end
+        def epub
+          {
+            cmd: '--epub',
+            viewer: @prog.epub_viewer,
+            f_pth: @md.file.output_path.epub.dir + '/' \
+            + @md.file.base_filename.epub,
+            p_pth: @env.processing_path.epub + '/' \
+            + Ep[:d_oebps] + '/' \
+            + 'index.xhtml',
+            fn: @fn[:epub],
+           }
+        end
+        self
+      end
+      def xml
+        def odt
+          {
+            cmd: '--odt (ODF:ODT)',
+            viewer: @prog.odf_viewer,
+            f_pth: @md.file.output_path.odt.dir + '/' \
+            + @md.file.base_filename.odt,
+            p_pth: @env.processing_path.odf + '/' \
+            + @opt.fns + '/' \
+            + 'odt/content.xml',
+            fn: @fn[:odf],
+           }
+        end
+        def docbook
+          {
+            cmd: '--docbook',
+            viewer: @prog.web_browser,
+            f_pth: @md.file.output_path.xml_docbook_book.dir + '/' \
+            + @md.file.base_filename.xml_docbook_book,
+            fn: @fn[:xml_docbook_book],
+           }
+        end
+        def fictionbook
+          {
+            cmd: '--fictionbook',
+            viewer: @prog.web_browser,
+            f_pth: @md.file.output_path.xml_fictionbook.dir + '/' \
+            + @md.file.base_filename.xml_fictionbook,
+            fn: @fn[:xml_fictionbook],
+           }
+        end
+        def sax
+          {
+            cmd: '--xml-sax',
+            viewer: @prog.web_browser,
+            f_pth: @md.file.output_path.xml_sax.dir + '/' \
+            + @md.file.base_filename.xml_sax,
+            fn: @fn[:sax],
+           }
+        end
+        def dom
+          {
+            cmd: '--xml-dom',
+            viewer: @prog.web_browser,
+            f_pth: @md.file.output_path.xml_dom.dir + '/' \
+            + @md.file.base_filename.xml_dom,
+            fn: @fn[:dom],
+           }
+        end
+        def scaffold_sisu
+          {
+            cmd: '--xml-scaffold-sisu',
+            viewer: @prog.web_browser,
+            f_pth: @md.file.output_path.xml_scaffold_structure_sisu.dir + '/' \
+            + @md.file.base_filename.xml_scaffold_structure_sisu,
+            fn: @fn[:xml_scaffold_structure_sisu],
+           }
+        end
+        def scaffold_collapse
+          {
+            cmd: '--xml-scaffold-collapse',
+            viewer: @prog.web_browser,
+            f_pth: @md.file.output_path.xml_scaffold_structure_collapse.dir + '/' \
+            + @md.file.base_filename.xml_scaffold_structure_collapse,
+            fn: @fn[:xml_scaffold_structure_collapse],
+           }
+        end
+        self
+      end
+      def json
+        {
+          cmd: '--js (json)',
+          viewer: @prog.web_browser,
+          f_pth: @md.file.output_path.json.dir + '/' \
+          + @md.file.base_filename.json,
+          fn: @fn[:json],
+        }
+      end
+      def pdf
+        def landscape
+          {
+            cmd: '--pdf (landscape)',
+            viewer: @prog.pdf_viewer,
+            f_pth: @md.file.output_path.pdf.dir + '/' \
+            + @md.file.base_filename.pdf_l \
+            + @md.papersize_array[0] + '.pdf',
+            p_pth: @env.processing_path.tex + '/' \
+            + @opt.fns.gsub(/~/,'-') + '.' \
+            + @md.papersize_array[0] \
+            + '.landscape.tex',
+            fn: @fn[:pdf_l],
+           }
+        end
+        def portrait
+          {
+            cmd: '--pdf (portrait)',
+            viewer: @prog.pdf_viewer,
+            f_pth: @md.file.output_path.pdf.dir + '/' \
+            + @md.file.base_filename.pdf_p \
+            + @md.papersize_array[0] + '.pdf',
+            p_pth: @env.processing_path.tex + '/' \
+            + @opt.fns.gsub(/~/,'-') + '.' \
+            + @md.papersize_array[0] \
+            + '.tex',
+            fn: @fn[:pdf_p],
+           }
+        end
+        self
+      end
+      def manpage
+        {
+          cmd: '--manpage',
+          viewer: @prog.manpage_viewer,
+          f_pth: @md.file.output_path.manpage.dir + '/' \
+          + @md.file.base_filename.manpage,
+          fn: 'manpage',
+         }
+      end
+      def texinfo
+        {
+          cmd: '--texinfo',
+          viewer: '',
+          f_pth: 'cd ' \
+          + @md.file.output_path.texinfo.dir + ' && ' \
+          + @env.program.texinfo + ' ' \
+          + @md.file.base_filename.info \
+          + '; cd -',
+          fn: 'info',
+         }
+      end
+      def db
+        def psql
+          {
+            cmd: '--psql --update/--import',
+            viewer: '',
+            f_pth: @pwd_stub + '::' \
+            + @opt.fns \
+            + 'dbi psql',
+            p_pth: @env.processing_path.postgresql + '/' \
+            + @md.fns \
+            + '.sql',
+            fn: 'dbi psql',
+           }
+        end
+        def sqlite
+          {
+            cmd: '--sqlite --update/--import',
+            viewer: 'sqlite3 ',
+            f_pth: @env.path.webserv + '/' \
+            + @md.opt.f_pth[:pth_stub] + '/' \
+            + 'sisu_sqlite.db',
+            p_pth: @env.processing_path.sqlite + '/' \
+            + @md.fns \
+            + '.sql',
+            fn: 'dbi sqlite3',
+           }
+        end
+        def sqlite_discrete
+          {
+            cmd: '--sqlite',
+            viewer: 'sqlite3 ',
+            f_pth: @md.file.output_path.sqlite_discrete.dir + '/' \
+            + @md.file.base_filename.sqlite_discrete,
+            p_pth: @env.processing_path.sqlite + '/' \
+            + @md.fns \
+            + '.sql',
+            fn: 'dbi sqlite3',
+           }
+        end
+        self
+      end
+      def po4a
+        def po
+          {
+            cmd: '--po4a/--pot',
+            viewer: @prog.web_browser,
+            f_pth: @prog.text_editor + ' ' \
+            + @md.file.output_path.po.dir \
+            + '/' + y,
+            fn: @fn[:pot],
+           }
+        end
+        def pot
+          {
+            cmd: '--po4a/--pot',
+            viewer: @prog.web_browser,
+            f_pth: @prog.text_editor + ' ' \
+            + @md.file.output_path.pot.dir \
+            + '/' + y,
+            fn: @fn[:pot],
+           }
+        end
+        self
+      end
+      def source
+        {
+          cmd: '--source (sisu markup)',
+          viewer: @prog.text_editor,
+          f_pth: @md.file.output_path.src.dir + '/' \
+          + @opt.fno,
+          p_pth: @md.file.output_path.src.dir + '/' \
+          + @opt.fno,
+          fn: @opt.fno,
+         }
+      end
+      def sisupod
+        {
+          cmd: '--sisupod',
+          viewer: '',
+          f_pth: @md.file.output_path.sisupod.dir + '/' \
+          + @opt.fno \
+          + '.txz',
+          p_pth: @md.file.output_path.sisupod.dir + '/' \
+          + @opt.fno + '/' \
+          + 'sisupod/',
+          fn: @fn[:sisupod],
+         }
+      end
+      def ruby_profile
+        {
+          cmd: '--profile (ruby profiler)',
+          fn: 'profile',
+         }
+      end
+      def qrcode
+        {
+          cmd: '--qrcode',
+          viewer: @prog.web_browser,
+          f_pth: @md.file.output_path.manifest.dir + '/' \
+          + @md.file.base_filename.manifest,
+          fn: @fn[:qrcode],
+         }
+      end
+      def manifest
+        {
+          cmd: '--manifest',
+          viewer: @prog.web_browser,
+          f_pth: @md.file.output_path.manifest.dir + '/' \
+          + @md.file.base_filename.manifest,
+          fn: @fn[:manifest],
+         }
+      end
+      def sitemap
+        {
+          cmd: '--sitemap',
+          viewer: @prog.web_browser,
+          f_pth: @md.file.output_path.sitemaps.dir + '/' \
+          + @md.file.base_filename.sitemap,
+          fn: @fn[:sitemap],
+         }
+      end
+      self
+    end
+    def urls_select
+      unless @opt.act[:quiet][:set]==:on
+        i1='[' + @opt.f_pth[:lng_is] + ']'
+        i2='file://' \
+        + @md.file.output_path.manifest.dir + '/' \
+        + @md.file.base_filename.manifest
+        (@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on) \
+        ? SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'URLs'
+          ).green_title_hi
+        : SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'URL (output manifest)',
+            i1, i2
+          ).grey_title_grey_blue
+        if (@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on)
+          SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            i1, i2,
+          ).flow
+        end
+      end
+      m=/.+\/(?:src\/)?(\S+)/im
+      @pwd_stub="#{@env.url.output_tell}"[m,1]
+      unless @opt.act[:quiet][:set]==:on
+        if @opt.fns =~ @m_regular
+          if (@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on)
+            if @opt.act[:txt][:set]==:on
+              show.report(report_info.text.txt)
+              #show.maintenance(report_info.text.txt)
+            end
+            if @opt.act[:txt_textile][:set]==:on
+              show.report(report_info.text.textile)
+              #show.maintenance(report_info.text.textile)
+            end
+            if @opt.act[:txt_asciidoc][:set]==:on
+              show.report(report_info.text.asciidoc)
+              #show.maintenance(report_info.text.asciidoc)
+            end
+            if @opt.act[:txt_markdown][:set]==:on
+              show.report(report_info.text.markdown)
+              #show.maintenance(report_info.text.markdown)
+            end
+            if @opt.act[:txt_rst][:set]==:on
+              show.report(report_info.text.rst)
+              #show.maintenance(report_info.text.rst)
+            end
+            if @opt.act[:txt_orgmode][:set]==:on
+              show.report(report_info.text.orgmode)
+              #show.maintenance(report_info.text.orgmode)
+            end
+            if (@opt.act[:html][:set]==:on \
+            or @opt.act[:html_scroll][:set]==:on \
+            or @opt.act[:html_seg][:set]==:on)
+              if @opt.act[:html_scroll][:set]==:on
+                show.report(report_info.html.scroll)
+                show.maintenance(report_info.html.scroll)
+              end
+              if @opt.act[:html_seg][:set]==:on
+                show.report(report_info.html.seg)
+                show.maintenance(report_info.html.seg)
+              end
+            end
+            if @opt.act[:concordance][:set]==:on
+              show.report(report_info.html.concordance)
+              #show.maintenance(report_info.html.concordance)
+            end
+            if @opt.act[:xhtml][:set]==:on
+              show.report(report_info.xhtml.xhtml)
+              show.maintenance(report_info.xhtml.xhtml)
+            end
+            if @opt.act[:epub][:set]==:on
+              show.report(report_info.xhtml.epub)
+              show.maintenance(report_info.xhtml.epub)
+            end
+            if @opt.act[:odt][:set]==:on
+              show.report(report_info.xml.odt)
+              show.maintenance(report_info.xml.odt)
+            end
+            if @opt.act[:xml_dom][:set]==:on
+              show.report(report_info.xml.dom)
+              #show.maintenance(report_info.xml.dom)
+            end
+            if @opt.act[:xml_sax][:set]==:on
+              show.report(report_info.xml.sax)
+              #show.maintenance(report_info.xml.sax)
+            end
+            if @opt.act[:xml_docbook_book][:set]==:on
+              show.report(report_info.xml.docbook)
+              #show.maintenance(report_info.xml.docbook)
+            end
+            if @opt.act[:xml_fictionbook][:set]==:on
+              show.report(report_info.xml.fictionbook)
+              #show.maintenance(report_info.xml.fictionbook)
+            end
+            if @opt.act[:xml_scaffold_structure_sisu][:set]==:on
+              show.report(report_info.xml.scaffold_structure_sisu)
+              #show.maintenance(report_info.xml.scaffold_structure_sisu)
+            end
+            if @opt.act[:xml_scaffold_structure_collapse][:set]==:on
+              show.report(report_info.xml.scaffold_collapse)
+              #show.maintenance(report_info.xml.scaffold_collapse)
+            end
+            if @opt.act[:json][:set]==:on
+              show.report(report_info.json)
+              #show.maintenance(report_info.json)
+            end
+            if (@opt.act[:pdf][:set]==:on \
+            or @opt.act[:pdf_p][:set]==:on \
+            or @opt.act[:pdf_l][:set]==:on)
+              if @opt.act[:pdf_p][:set]==:on
+                show.report(report_info.pdf.portrait)
+                show.maintenance(report_info.pdf.portrait)
+              end
+              if @opt.act[:pdf_l][:set]==:on
+                show.report(report_info.pdf.landscape)
+                show.maintenance(report_info.pdf.landscape)
+              end
+            end
+            if @opt.act[:psql][:set]==:on
+              show.report(report_info.db.psql)
+              show.maintenance(report_info.db.psql)
+            end
+            if @opt.act[:sqlite_discrete][:set]==:on
+              show.report(report_info.db.sqlite_discrete)
+              show.maintenance(report_info.db.sqlite_discrete)
+            end
+            if @opt.act[:sqlite][:set]==:on
+              show.report(report_info.db.sqlite)
+              show.maintenance(report_info.db.sqlite)
+            end
+            if @opt.act[:texinfo][:set]==:on
+              show.report(report_info.texinfo)
+              #show.maintenance(report_info.texinfo)
+            end
+            if @opt.act[:manpage][:set]==:on
+              show.report(report_info.manpage)
+              #show.maintenance(report_info.manpage)
+            end
+            if @opt.act[:hash_digests][:set]==:on
+              show.report(report_info.hash_digests)
+              #show.maintenance(report_info.hash_digests)
+            end
+            if @opt.act[:po4a_shelf][:set]==:on
+              #if @opt.fns =~/\S+?~\S{2}(?:_\S{2})?\.ss[mt]/
+              #else
+              #end
+            end
+            if @opt.act[:share_source][:set]==:on
+              show.report(report_info.source)
+              show.maintenance(report_info.source)
+            end
+            if @opt.act[:sisupod][:set]==:on
+              show.report(report_info.sisupod)
+              show.maintenance(report_info.sisupod)
+            end
+            if @opt.act[:qrcode][:set]==:on
+              show.report(report_info.qrcode)
+              #show.maintenance(report_info.qrcode)
+            end
+            if @opt.act[:manifest][:set]==:on
+              show.report(report_info.manifest)
+              show.maintenance(report_info.manifest)
+            end
+          end
+        end
+      end
+    end
+    def urls_all
+      i="(output manifest) [#{@opt.f_pth[:lng_is]}] #{@env.url.output_tell}/#{@fnb}/sisu_manifest.html"
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        'URLs',
+        i
+      ).grey_title_hi
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** webrick.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/webrick.rb"
+# <<sisu_document_header>>
+module SiSU_Webserv
+  class WebrickStart
+    begin
+      require 'time'
+      require 'webrick'
+        include WEBrick
+    rescue LoadError
+      SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+        error('time or webrick NOT FOUND (LoadError)')
+    end
+    require_relative 'se'                                 # se.rb
+      include SiSU_Env
+      include SiSU_Screen
+    def initialize
+      @cX=SiSU_Screen::Ansi.new('yes').cX
+      @env=SiSU_Env::InfoEnv.new
+      port=SiSU_Env::InfoPort.new
+      @host=@env.url.webrick
+      @port=port.webrick
+      @serve=[]
+      Dir.foreach(@env.path.webserv) do |x|
+        if x !~/^\./ \
+        and FileTest.directory?("#{@env.path.webserv}/#{x}")
+          @serve << x
+        end
+      end
+      @mount=[]
+      @serve.each {|x| @mount << ["/#{x}", "#{@env.path.webserv}/#{x}"]}
+      @pwd=Dir.pwd
+      @week=Time.now.strftime(%{%Yw%W})
+      puts "\n"
+      @mount.each { |x,y|
+        puts "  * #{@cX.blue}#{@host}:#{@port}#{x}/#{@cX.off}"
+      }
+      get=Dir.pwd
+      brick(@port,get)
+    end
+    def brick(port,get='')
+      cgidir=if get=~/pwd/ then Dir.pwd
+      else                      '/usr/lib/cgi-bin'
+      end
+      port=SiSU_Env::InfoPort.new.webrick
+      begin
+        s=HTTPServer.new(
+          Port:         port,
+          DocumentRoot: Dir::pwd + '/htdocs',
+          CGIPathEnv:   ENV['PATH']
+        )
+        cgi_dir=File.expand_path(cgidir)
+        @mount.each { |x,y|                                                        # mount subdirectories
+          s.mount(x, HTTPServlet::FileHandler, y, true)
+        }
+        s.mount('/cgi-bin', HTTPServlet::FileHandler, cgi_dir, { FancyIndexing: true })
+        trap("INT"){ s.shutdown }
+        s.start
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,'-W',nil).location do #fix
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    def wb_cgi
+      begin                                                                          #%
+        wb_s2=''
+                                                                 #% writes file wb.cgi to shared directories ...
+                                                                 #% wb_top
+        wb_top=%q(#!/usr/bin/env ruby
+        # * arch-tag: webrick info on environment, mounted directories, and contents of pwd
+        begin
+          require 'time'
+          require 'cgi'
+          require 'fcgi'
+        rescue LoadError
+          puts 'time, cgi or fcgi NOT FOUND (LoadError)'
+        end
+        ls=Dir.entries('./')
+        dir_contents=[]
+        ls.each { |x| dir_contents << "<a href=\"./#{x}/\">#{x}</a><br>" unless x =~/^(\.)+$/ }
+        dir_contents=dir_contents.sort.join(' ')
+        #host=ENV['HOSTNAME']
+        #host=%x{echo $HOSTNAME}
+        )
+        wb_s1=<<-WOK
+
+  page=CGI.new "html3"
+  page.out {
+    page.html {
+      page.head { page.title {"#{@host} Webrick Report"} } +
+      page.body {
+        page.h1 {"Webrick #{@host}"} +
+        page.p {"Webrick is Ruby's built in webserver."} +
+        page.center {"Host name: " + page.b{"#{@host} "} + "(#{@host})  port: " + page.b{"#{@port}"}} +
+        page.center {"#{Time.now}"} +
+        page.center {"#{Time.now.strftime(%{%Yw%W})}"} +
+        page.p {''} +
+        page.p {''} +
+        page.p {page.b{"Webrick Served Directories: "}} +
+        WOK
+                                                               #% wb_s2 (mounts)
+        @mount.each do |x,y| wb_s2 += <<-WOK
+          page.p {%{<a href="#{@host}:#{@port}#{x}/">#{x}</a> } +
+            %{<a href="#{@host}:#{@port}#{x}/">#{@host}:#{@port}#{x}</a> (mounts: #{y}/)   <a href="#{@host}:#{@port}#{x}/wb.cgi">info (wb.cgi)</a>}} +
+          WOK
+        end
+                                                               #% wb_end
+        wb_end=<<-WOK
+        page.p {page.b{"Contents of PWD (see URL): "}} +
+        page.p {"#\{dir_contents}"}
+      }
+    }
+  }
+        WOK
+        @mount.each { |x,y|                                      #% wb puts
+          puts y
+            filename=File.new("#{y}/wb.cgi",'w')
+            filename << wb_top
+            filename << wb_s1
+            filename << wb_s2
+            filename << wb_end
+            filename.close
+            FileUtils::chmod(0755,"#{y}/wb.cgi &") if FileTest.file?("#{y}/wb.cgi &")
+        }
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,'-W',nil).location do #fix
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+  end
+ensure
+end
+__END__
+#+END_SRC
+
+** wikispeak.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/wikispeak.rb"
+# <<sisu_document_header>>
+module SiSU_Wikispeak
+  require_relative 'ao'                                 # ao.rb
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  include SiSU_Param
+  require_relative 'plaintext_format'                   # plaintext_format.rb
+    include Format
+  require_relative 'html_parts'                         # html_parts.rb
+  require_relative 'txt_shared'
+  @@alt_id_count,@@alt_id_count=0,0
+  @@tablefoot=''
+  class Source
+    def initialize(opt)
+      @opt=opt
+      @@dostype='msdos footnotes'
+    end
+    def read
+      begin
+        @md=SiSU_Param::Parameters.new(@opt).get
+        @env=SiSU_Env::InfoEnv.new(@opt.fns)
+        path=@env.path.output_tell
+        tool=(@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on) \
+        ? "#{@env.program.text_editor} #{path}/#{@md.fnb}/#{@md.fn[:wiki]}"
+        : ''
+        SiSU_Screen::Ansi.new(
+          @opt.act[:color_state][:set],
+          'Wikispeak',
+          tool
+        ).green_hi_blue unless @opt.act[:quiet][:set]==:on
+        if (@opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on)
+          SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            @opt.fns,
+            "#{@env.path.output_tell}/#{@md.fnb}/#{@md.fn[:wiki]}"
+          ).flow
+        end
+        @ao_array=SiSU_AO::Source.new(@opt).get # ao file drawn here
+        SiSU_Wikispeak::Source::Scroll.new(@ao_array,@md).songsheet
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    private
+    class SplitTextObject <Source
+      require_relative 'plaintext_format'               # plaintext_format.rb
+        include Format
+      @@alt_id_count=0
+      @@dp=nil
+      attr_reader :format,:lev,:text,:ocn,:lev_para_ocn
+      def initialize(para)
+        @para=para
+        @format,@ocn='ordinary','ordinary'
+        @dp=@@dp ||=SiSU_Env::InfoEnv.new.digest.pattern
+      end
+      def lev_segname_para_ocn
+        @text=nil
+        if @para =~/^(\d~|<:.+?>).+?#{Mx[:id_o]}~(\d+);(?:\w|[0-6]:)\d+;\w\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}$/
+          if /^(([1-6])~(\S+))\s+(\S.+?)#{Mx[:id_o]}~(\d+);(?:\w|[0-6]:)\d+;\w\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}$/m.match(@para)
+            @format,@lev,segname,@text,@ocn=$1,$2,$3,$4,$5
+          elsif  /^(([1-6])~)\s+(\S.+?)#{Mx[:id_o]}~(\d+);(?:\w|[0-6]:)\d+;\w\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}$/m.match(@para)
+            @format,@lev,@text,@ocn=$1,$2,$3,$4
+          elsif /<:(.+?)>\s*(\S.+?)#{Mx[:id_o]}~(\d+);(?:\w|[0-6]:)\d+;\w\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}$/m.match(@para)
+            @format,@text,@ocn=$1,$2,$3
+          elsif /^(([1-6])~(\S+))\s+(\S.+?)#{Mx[:id_o]}~(\d+);(?:\w|[0-6]:)\d+;[um]\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}$/m.match(@para)
+            @@alt_id_count+=1
+            @format,@lev,segname,@text,@ocn=$1,$2,$3,$4,"x#{@@alt_id_count}"
+          elsif  /^(([1-6])~)\s+(\S.+?)#{Mx[:id_o]}~(\d+);[um]\d+;\w\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}$/m.match(@para)
+            @@alt_id_count+=1
+            @format,@lev,@text,@ocn=$1,$2,$3,"x#{@@alt_id_count}"
+          end
+        else
+          if /(.+?)#{Mx[:id_o]}~(\d+);(?:\w|[0-6]:)\d+;\w\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}$/m.match(@para)
+            @text,@ocn=$1,$2
+          end
+          if @para !~/#{Mx[:id_o]}~(\d+);(?:\w|[0-6]:)\d+;\w\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}$|^$/ #added 2002w06
+            @text=/(.+?)/m.match(@para)[1]
+          end
+          if /^((\d)~(?:~\S+)?)\s+(.+)/m.match(@para)
+            @format,@lev,@text=$1,$2,$3
+          end
+        end
+        format=@format.dup
+        @lev_para_ocn=if @para =~/.+#{Mx[:id_o]}~\d+;(?:\w|[0-6]:)\d+;\w\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}$/
+          Format::FormatTextObject.new(format,@text,@ocn)
+        else
+          Format::FormatTextObject.new(format,@text,"#{Mx[:id_o]}~(\d+);[um]\d+;\w\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}")
+        end
+        self
+      end
+    end
+    class Scroll <Source
+      include SiSU_TextUtils
+      include SiSU_Parts_HTML
+      @@endnotes_para=[]
+      @@wiki={ body: [], open: [], close: [], head: [], metadata: [], tail: [], endnotes: [] }
+      @@dp=nil
+      def initialize(data,md)
+        @data,@md=data,md
+        @dp=@@dp ||=SiSU_Env::InfoEnv.new.digest.pattern
+        @regx=/^(?:(?:#{Mx[:br_line]}\s*|#{Mx[:br_nl]}\s*)?#{Mx[:lv_o]}\d:(\S*?)#{Mx[:lv_c]}\s*)?(.+)/ #fix Mx[:lv_o] #m # 2004w18 pb pn removal added
+        @tab="\t"
+        @@dostype='unix footnotes'
+        @br="\n"
+      end
+      def songsheet
+        markup
+        publish
+      end
+      # Used for extraction of endnotes from paragraphs
+      def extract_endnotes(para='') #check
+        para.scan(/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})([\d*+]+\s+.+?)\s*#{Mx[:id_o]}#{@dp}#{Mx[:id_c]}(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/)
+      end
+      def wiki_metadata(meta)
+        util=SiSU_TextUtils::Wrap.new(meta.text,70,15,1)
+        txt=util.line_wrap
+        @@wiki[:metadata] <<= if meta.type=='meta'
+          <<WOK
+
+#{@tab}#{meta.el}: #{txt}
+WOK
+        else ''
+        end
+      end
+      def wiki_tail
+        generator="Generated by: #{@md.project_details.project} #{@md.project_details.version} of #{@md.project_details.date_stamp} (#{@md.project_details.date})"  if @md.project_details.version
+        lastdone="Last Generated on: #{Time.now}"
+        rubyv="Ruby version: #{@md.ruby_version}"
+        sc=if @md.sc_info
+          "Source file:    #{@md.sc_filename}#{@br}Version number: #{@md.sc_number}#{@br}Version date:   #{@md.sc_date}#{@br}"
+        else ''
+        end
+        @@wiki[:tail] <<<<WOK
+#{@br}
+Other versions of this document: #{@br}
+manifest:
+   #{vz.url_root_http}/#{@md.fnb}/#{@md.fn[:manifest]}#{@br}
+html:
+   #{vz.url_root_http}/#{@md.fnb}/#{@md.fn[:toc]}#{@br}
+pdf:
+   #{vz.url_root_http}/#{@md.fnb}/#{@md.fn[:pdf_p]}
+   #{vz.url_root_http}/#{@md.fnb}/#{@md.fn[:pdf_l]}#{@br}
+plaintext (plain text):
+   #{vz.url_root_http}/#{@md.fnb}/#{@md.fn[:plain]}#{@br}
+at:
+   #{vz.url_site}#{@br}
+
+#{sc}
+,* #{generator}
+,* #{rubyv}
+,* #{lastdone}
+,* SiSU #{vz.url_sisu}
+WOK
+      end
+      def wiki_structure(para='',lv='',ocn='',hname='') #% Used to extract the structure of a document
+        lv=lv.to_i
+        lv=nil if lv==0
+        extract_endnotes(para)
+        para.gsub!(/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})(?:[\d*+]+)\s+(.+?)#{Mx[:id_o]}#{@dp}#{Mx[:id_c]}(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/,'<ref>\1</ref>') # endnote marker marked up
+        para.gsub!(/^#{Rx[:lv]}\S*\s+/,'') # endnote marker marked up
+        para.gsub!(/<\S+?>#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}/,'') # endnote marker marked up
+        if lv
+          @@wiki[:body] << case lv
+          when 1    then '='*2 << para.strip << @br*2
+          when 2..3 then '='*2 << para.strip << @br*2
+          when 4    then '='*4 << para.strip << @br*2
+          when 5..6 then '='*4 << para.strip << @br*2
+          end
+        else @@wiki[:body] << para << @br*2 # main text, contents, body KEEP
+        end
+      end
+      def markup                                                               # Used for major markup instructions
+        data=@data
+        SiSU_Env::InfoEnv.new(@md.fns)
+        @data_mod,@endnotes,@level,@cont,@copen,@wiki_contents_close=Array.new(6){[]}
+        (0..6).each { |x| @cont[x]=@level[x]=false }
+        (4..6).each { |x| @wiki_contents_close[x]='' }
+        wiki_tail
+        table_message='[table omitted, see other document formats]'
+        data.each do |para|
+          para.gsub!(/#{Mx[:gr_o]}Th?#{Mx[:tc_p]}.+/um,"#{@br}#{table_message}") #fix
+          para.gsub!(/.+?<-#>/,'')                                           # remove dummy headings (used by html) #check
+          para.gsub!(/_\*\s+/,'* ')                                           # bullet markup, marked down
+          para.gsub!(/&#169;/,'©')                                           # bullet markup, marked down
+          para.gsub!(/&amp;/,'&')                                           # bullet markup, marked down
+          para.gsub!(/<sup>(.+?)<\/sup>/,'^\1^')
+          para.gsub!(/<sub>(.+?)<\/sub>/,'[\1]')
+          para.gsub!(/<i>(.+?)<\/i>/,"''\\1''")
+          para.gsub!(/<b>(.+?)<\/b>/,"'''\\1'''")
+          para.gsub!(/<u>(.+?)<\/u>/,'_\1_')
+          para.gsub!(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,'[\2 \1]')
+          para.gsub!(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,'[\1]')
+          para.gsub!(/<:(?:block|group|verse|alt|code)(?:-end)?>(?:\s+#{Mx[:id_o]}~(\d+);(?:\w|[0-6]:)\d+;\w\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]})?/,'')
+          para.gsub!(/<:p[bn]>/,'')                                         # remove page breaks
+          para.gsub!(/^\s*#{Mx[:id_o]}~\d+;(?:\w|[0-6]:)\d+;\w\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}$/,'') # remove empty lines - check
+          para.gsub!(/<a href=".+?">(.+?)<\/a>/m,'\1')
+          para.gsub!(/<:name#\S+?>/,'')                                       # remove name links
+          para.gsub!(/&nbsp;|#{Mx[:nbsp]}/,' ')                               # decide on
+          para.gsub!(/(?:^|[^_\\])#{Mx[:lnk_o]}(\S+?\.(?:png|jpg|gif)) .+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|image)/,'    [ \1 ]') #"[ #{dir.url.images_local}\/\\1 ]")
+          para.gsub!(/(?:^|[^_\\])#{Mx[:lnk_o]}\s*\S+?\.(?:png|jpg|gif)\s+.+?"(.*?)"\s*#{Mx[:lnk_c]}\S+/,'[image: "\1"]')
+          if para =~/^@(\S+?):\s+(.+?)\Z/m # for headers
+            d_meta=SiSU_TextUtils::HeaderScan.new(@md,para).meta
+            if d_meta; wiki_metadata(d_meta)
+            end
+          end
+          if para !~/(^@\S+?:|#{Mx[:br_endnotes]}|#{Mx[:br_eof]})/
+            if para =~@regx #/.+?<~\d+;\w\d+;\w\d+>.*/ #watch change
+              paranum=para[@regx,3]
+              @p_num=Format::ParagraphNumber.new(paranum)
+            end
+            @sto=SplitTextObject.new(para).lev_segname_para_ocn
+            ### problem in scroll, it appears tables are getting paragraph numbers
+            m=/#{Mx[:id_o]}~(\d+);(?:\w|[0-6]:)\d+;\w\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}$/
+            if para =~m \
+            and para=~/\S+/
+              para=case @sto.format
+              when /^(1)~(?:(\S+))?/
+                wiki_structure(para,$1,@sto.ocn,$2)
+                @sto.lev_para_ocn.heading_body1
+              when /^(2)~(?:(\S+))?/
+                wiki_structure(para,$1,@sto.ocn,$2)
+                @sto.lev_para_ocn.heading_body2
+              when /^(3)~(?:(\S+))?/
+                wiki_structure(para,$1,@sto.ocn,$2)
+                @sto.lev_para_ocn.heading_body3
+              when /^(4)~(\S+)/ # work on see SiSU_text_parts::SplitTextObject
+                wiki_structure(para,$1,@sto.ocn,$2)
+                @sto.lev_para_ocn.heading_body4
+              when /^(5)~(?:(\S+))?/
+                wiki_structure(para,$1,@sto.ocn,$2)
+                @sto.lev_para_ocn.heading_body5
+              when /^(6)~(?:(\S+))?/
+                wiki_structure(para,$1,@sto.ocn,$2)
+                @sto.lev_para_ocn.heading_body6
+              else
+                wiki_structure(para,nil,nil,nil) #watch may be problematic
+                para
+              end
+            elsif para =~/#{table_message}/
+              @@wiki[:body] << para << @br
+            elsif para =~/(Note|Endnotes?)/ \
+            and para !~/#{Mx[:id_o]}~\d+;(?:\w|[0-6]:)\d+;\w\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}$/
+            elsif para =~/(MetaData)/ \
+            and para =~/#{Mx[:id_o]}~(\d+);[um]\d+;\w\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}$/ #debug 2003w46 add rc info ####suspect visit
+            elsif para.include? 'Owner Details' \
+            and para !~/#{Mx[:id_o]}~(\d+);(?:[oh]|[0-6]:)\d+;\w\d+#{Mx[:id_c]}#{Mx[:id_o]}#{@dp}:#{@dp}#{Mx[:id_c]}$/
+            elsif para =~/(#{Mx[:tc_p]}|#{Mx[:gr_o]}Th?)/u #tables ! #fix
+            elsif para =~/(.*)<!#!>(.*)/
+              one,two=$1,$2
+              format_text=FormatTextObject.new(one,two)
+              para=format_text.seg_no_paranum
+            end
+            if (para =~/<a name="n\d+">/ \
+            and para =~/^(-\{{2}~\d+|<!e[:_]\d+!>)/) # -endnote
+              para=''
+            end
+            case para
+            when /<:i1>/
+              if para =~/.*<:#>.*$/
+                format_text=FormatTextObject.new(para,'')
+                para=format_text.scr_indent_one_no_paranum
+              end
+            when /<:i2>/
+              if para =~/.*<:#>.*$/
+                format_text=FormatTextObject.new(para,'')
+                para=format_text.scr_indent_one_no_paranum
+              end
+            end
+            if para !~/#{the_margin.txt_0}|#{the_margin.txt_1}|#{the_margin.txt_2}/
+              # i don't get the condition for no paranum
+            end
+            if para =~/<:center>/
+              one,two=/(.*)<:center>(.*)/.match(para)[1,2]
+              format_text=FormatTextObject.new(one,two)
+              para=format_text.center
+            end
+            para.gsub!(/<!.+!>/,' ') if para ## Clean Prepared Text
+            para.gsub!(/<:\S+>/,' ') if para ## Clean Prepared Text
+          end
+        end
+      end
+      def publish
+        content=[]
+        content << @@wiki[:open]
+        content << @@wiki[:head]
+        content << @@wiki[:body]
+        Output.new(content.join,@md).wiki
+        @@wiki[:head],@@wiki[:body],@@wiki[:tail],@@wiki[:metadata]=[],[],[],[]
+      end
+    end
+    class Output <Source
+      include SiSU_Param
+      include SiSU_Env
+      def initialize(content,md)
+        @content,@md=content,md
+      end
+      def wiki                                                            #%wiki output
+        SiSU_Env::FileOp.new(@md).mkdir
+        filename_wiki=SiSU_Env::FileOp.new(@md,@md.fn[:wiki]).mkfile
+        @sisu=[]
+        @content.each do |para|                                                # this is a hack
+          if para =~/^\S/
+            if para !~/^([*=-]|\.){5}/; filename_wiki.puts para           #unix wiki
+            else                        filename_wiki.puts para           #unix wiki
+            end
+          else filename_wiki.puts para # if para =~/^\s/
+          end
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** zap.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/zap.rb"
+# <<sisu_document_header>>
+module SiSU_Zap
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  class Source
+    def initialize(opt)
+      @opt=opt
+      @env=SiSU_Env::InfoEnv.new(opt.fns)
+    end
+    def read
+      zap_path="#{@env.path.output}/#{@env.fnb}"
+      z=SiSU_Env::CleanOutput.new(@opt)
+      if SiSU_Env::InfoSettings.new.permission?('zap')
+        unless @opt.act[:quiet][:set]==:on
+          tell=SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            "Clean files related to processing #{@opt.selections.str} ->",
+            "#{@opt.fns} -> #{zap_path}"
+          )
+          tell.warn
+        end
+        z.zap.remove_output
+      else
+        unless @opt.act[:quiet][:set]==:on
+          tell=SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'use of -Z (zap) has not enabled in sisurc.yml'
+          )
+          tell.warn
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    misc
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/object_munge.org b/org/object_munge.org
new file mode 100644
index 00000000..7e3f95e5
--- /dev/null
+++ b/org/object_munge.org
@@ -0,0 +1,331 @@
+-*- mode: org -*-
+#+TITLE:       sisu object munge
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:munge:objects:
+#+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
+
+* object_munge.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/object_munge.rb"
+# <<sisu_document_header>>
+module SiSU_Object_Munge
+  def i_src_o_strip_markup(txtobj)
+    txtobj=txtobj.
+      gsub(/#{Mx[:srcrgx_bold_o]}(.+?)#{Mx[:srcrgx_bold_c]}/m,'\1').
+      gsub(/#{Mx[:srcrgx_italics_o]}(.+?)#{Mx[:srcrgx_italics_c]}/m,'\1').
+      gsub(/#{Mx[:srcrgx_underscore_o]}(.+?)#{Mx[:srcrgx_underscore_c]}/m,'\1').
+      gsub(/#{Mx[:srcrgx_cite_o]}(.+?)#{Mx[:srcrgx_cite_c]}/m,'\1').
+      gsub(/#{Mx[:srcrgx_insert_o]}(.+?)#{Mx[:srcrgx_insert_c]}/m,'\1').
+      gsub(/#{Mx[:srcrgx_strike_o]}(.+?)#{Mx[:srcrgx_strike_c]}/m,'\1').
+      gsub(/#{Mx[:srcrgx_superscript_o]}(\d+)#{Mx[:srcrgx_superscript_c]}/m,'[\1]').
+      gsub(/#{Mx[:srcrgx_superscript_o]}(.+?)#{Mx[:srcrgx_superscript_c]}/m,'\1').
+      gsub(/#{Mx[:srcrgx_subscript_o]}(.+?)#{Mx[:srcrgx_subscript_c]}/m,'\1').
+      gsub(/#{Mx[:srcrgx_hilite_o]}(.+?)#{Mx[:srcrgx_hilite_c]}/m,'\1').
+      gsub(/#{Mx[:gl_o]}#(?:126|152)#{Mx[:gl_c]}/i,'~').
+      gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/m,''). # endnote removed
+      gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/m,''). # endnote removed
+      gsub(/(?:#{Mx[:nbsp]})+/,' ').
+      gsub(/(?:#{Mx[:br_nl]})+/,"\n").
+      gsub(/(?:#{Mx[:br_paragraph]})+/,"\n").
+      gsub(/(?:#{Mx[:br_line]})+/,"\n").
+      gsub(/#{Mx[:gl_o]}(?:#lt|#060)#{Mx[:gl_c]}/,'<').
+      gsub(/#{Mx[:gl_o]}(?:#gt|#062)#{Mx[:gl_c]}/,'>').
+      gsub(/#{Mx[:gl_o]}#(?:038|amp)#{Mx[:gl_c]}/,'&').
+      gsub(/#{Mx[:gl_o]}#033#{Mx[:gl_c]}/,'!').
+      gsub(/#{Mx[:gl_o]}#035#{Mx[:gl_c]}/,'#').
+      gsub(/#{Mx[:gl_o]}#042#{Mx[:gl_c]}/,'*').
+      gsub(/#{Mx[:gl_o]}#045#{Mx[:gl_c]}/,'-').
+      gsub(/#{Mx[:gl_o]}#047#{Mx[:gl_c]}/,'/').
+      gsub(/#{Mx[:gl_o]}#095#{Mx[:gl_c]}/,'_').
+      gsub(/#{Mx[:gl_o]}#123#{Mx[:gl_c]}/,'{').
+      gsub(/#{Mx[:gl_o]}#125#{Mx[:gl_c]}/,'}').
+      gsub(/#{Mx[:gl_o]}#126#{Mx[:gl_c]}/,'~').
+      gsub(/#{Mx[:gl_o]}#169#{Mx[:gl_c]}/,'©').
+      gsub(/[ ][ ]s+/,' ').
+      strip
+if txtobj =~/Reading this/
+  puts txtobj
+  if txtobj =~ /#{Mx[:srcrgx_italics_o]}(.+?)#{Mx[:srcrgx_italics_c]}/
+    puts __LINE__
+    puts Mx[:srcrgx_italics_o]
+    puts txtobj
+  end
+end
+; txtobj
+  end
+  def i_ao_o_strip_markup(txtobj)
+    txtobj=txtobj.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'\1').
+      gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'\1').
+      gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'\1').
+      gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'\1').
+      gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'\1').
+      gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'\1').
+      gsub(/#{Mx[:fa_superscript_o]}(\d+)#{Mx[:fa_superscript_c]}/,'[\1]').
+      gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'\1').
+      gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'\1').
+      gsub(/#{Mx[:fa_hilite_o]}(.+?)#{Mx[:fa_hilite_c]}/,'\1').
+      gsub(/#{Mx[:gl_o]}#(?:126|152)#{Mx[:gl_c]}/i,'~').
+      gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,''). # endnote removed
+      gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,''). # endnote removed
+      gsub(/(?:#{Mx[:nbsp]})+/,' ').
+      gsub(/(?:#{Mx[:br_nl]})+/,"\n").
+      gsub(/(?:#{Mx[:br_paragraph]})+/,"\n").
+      gsub(/(?:#{Mx[:br_line]})+/,"\n").
+      gsub(/#{Mx[:gl_o]}(?:#lt|#060)#{Mx[:gl_c]}/,'<').
+      gsub(/#{Mx[:gl_o]}(?:#gt|#062)#{Mx[:gl_c]}/,'>').
+      gsub(/#{Mx[:gl_o]}#(?:038|amp)#{Mx[:gl_c]}/,'&').
+      gsub(/#{Mx[:gl_o]}#033#{Mx[:gl_c]}/,'!').
+      gsub(/#{Mx[:gl_o]}#035#{Mx[:gl_c]}/,'#').
+      gsub(/#{Mx[:gl_o]}#042#{Mx[:gl_c]}/,'*').
+      gsub(/#{Mx[:gl_o]}#045#{Mx[:gl_c]}/,'-').
+      gsub(/#{Mx[:gl_o]}#047#{Mx[:gl_c]}/,'/').
+      gsub(/#{Mx[:gl_o]}#095#{Mx[:gl_c]}/,'_').
+      gsub(/#{Mx[:gl_o]}#123#{Mx[:gl_c]}/,'{').
+      gsub(/#{Mx[:gl_o]}#125#{Mx[:gl_c]}/,'}').
+      gsub(/#{Mx[:gl_o]}#126#{Mx[:gl_c]}/,'~').
+      gsub(/#{Mx[:gl_o]}#169#{Mx[:gl_c]}/,'©').
+      gsub(/[ ][ ]s+/,' ').
+      strip
+  end
+  def i_ao_o_src_markup_restore(txtobj)
+    @txtobj=txtobj
+    def textface_marks
+      @txtobj.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'*{\1}*').
+        gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'/{\1}/').
+        gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'_{\1}_').
+        gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'"{\1}"').
+        gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'+{\1}+').
+        gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'-{\1}-').
+        gsub(/#{Mx[:fa_superscript_o]}(\d+)#{Mx[:fa_superscript_c]}/,'^{[\1]}^').
+        gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'^{\1}^').
+        gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,',{\1},').
+        gsub(/#{Mx[:fa_hilite_o]}(.+?)#{Mx[:fa_hilite_c]}/,'\1').
+        gsub(/#{Mx[:gl_o]}#(?:126|152)#{Mx[:gl_c]}/i,'~').
+        gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'~{\1 \2}~').
+        gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,''). # endnote removed
+        gsub(/(?:#{Mx[:nbsp]})+/,' ').
+        gsub(/(?:#{Mx[:br_nl]})+/,"\n").
+        gsub(/(?:#{Mx[:br_paragraph]})+/,"\n").
+        gsub(/(?:#{Mx[:br_line]})+/,"\n").
+        gsub(/#{Mx[:gl_o]}(?:#lt|#060)#{Mx[:gl_c]}/,'<').
+        gsub(/#{Mx[:gl_o]}(?:#gt|#062)#{Mx[:gl_c]}/,'>').
+        gsub(/#{Mx[:gl_o]}#(?:038|amp)#{Mx[:gl_c]}/,'&').
+        gsub(/#{Mx[:gl_o]}#033#{Mx[:gl_c]}/,'!').
+        gsub(/#{Mx[:gl_o]}#035#{Mx[:gl_c]}/,'#').
+        gsub(/#{Mx[:gl_o]}#042#{Mx[:gl_c]}/,'*').
+        gsub(/#{Mx[:gl_o]}#045#{Mx[:gl_c]}/,'-').
+        gsub(/#{Mx[:gl_o]}#047#{Mx[:gl_c]}/,'/').
+        gsub(/#{Mx[:gl_o]}#095#{Mx[:gl_c]}/,'_').
+        gsub(/#{Mx[:gl_o]}#123#{Mx[:gl_c]}/,'{').
+        gsub(/#{Mx[:gl_o]}#125#{Mx[:gl_c]}/,'}').
+        gsub(/#{Mx[:gl_o]}#126#{Mx[:gl_c]}/,'~').
+        gsub(/#{Mx[:gl_o]}#169#{Mx[:gl_c]}/,'©').
+        gsub(/[ ][ ]s+/,' ').
+        strip
+    end
+    def object_marks
+      @txtobj
+    end
+    self
+  end
+  def clean_text(txtobj,markup=:ao)
+    if txtobj.class==String
+      txtobj=if markup ==:ao
+        i_ao_o_strip_markup(txtobj)
+      elsif markup ==:src
+        i_src_o_strip_markup(txtobj)
+      else p __FILE__; p __LINE__
+      end
+    elsif txtobj.class.inspect=~/^SiSU_AO_DocumentStructure::/
+      txtobj.obj=i_ao_o_strip_markup(txtobj.obj)
+    else p 'error'
+    end
+    txtobj
+  end
+  def footnotes_inline(txtobj)
+  end
+  def footnotes_ref_and_note(txtobj)
+  end
+  def src_markup(txtobj)
+    txtobj
+  end
+  def extract_endnotes(doc_obj_txt,endnotes_)               #% used for extraction of endnotes from paragraphs
+    if endnotes_ ==:separate
+      notes_a=doc_obj_txt.scan(/#{Mx[:en_a_o]}([\d]+\s+.+?)#{Mx[:en_a_c]}/)
+      ##notes_a=doc_obj_txt.scan(/#{Mx[:en_a_o]}([\d*+]+\s+.+?)#{Mx[:en_a_c]}/)
+      #notes_b=doc_obj_txt.scan(/#{Mx[:en_b_o]}([\d*+]+\s+.+?)#{Mx[:en_b_c]}/)
+      n=[]
+      notes_a.flatten.each do |note| #high cost to deal with <br> appropriately within plaintext, consider
+        note=note.dup.to_s
+        note=note.gsub(/^([\d]+)\s+/,'^~\1 ').
+          gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/,
+            ' \\\\\\ ')
+        n << note
+      end
+      notes_a=n.flatten
+      doc_obj_txt=doc_obj_txt.
+        gsub(/#{Mx[:en_a_o]}([\d]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'~^')   # endnote marker marked up
+    else
+      doc_obj_txt=doc_obj_txt.
+        gsub(/#{Mx[:en_b_o]}[\d]+\s+(.+?)#{Mx[:en_b_c]}/,
+          '~[ \1 ]~').     # inline endnote with marker marked up
+        gsub(/#{Mx[:en_a_o]}([*+]+)\s+(.+?)#{Mx[:en_a_c]}/,
+          '~{\1 \2 }~'). # inline endnote with marker marked up
+        gsub(/#{Mx[:en_b_o]}([*+]+)\s+(.+?)#{Mx[:en_b_c]}/,
+          '~[\1 \2 ]~') # inline endnote with marker marked up
+    end
+    [doc_obj_txt,notes_a]
+  end
+  def objects #def i_ao_o_src_markup_restore(txtobj)
+    def code_(dob)
+      if dob.is==:code
+        dob.obj=dob.obj.gsub(/(^|[^}])_([<>])/m,'\1\2'). # _> _<
+          gsub(/(^|[^}])_([<>])/m,'\1\2') # _<_<
+      end
+      dob
+    end
+    def block_(dob)
+      dob.obj=if dob.of==:block                                   # watch
+        dob.obj.gsub(/#{Mx[:gl_o]}●#{Mx[:gl_c]}/,"* ").
+          gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/,"\n")
+      else dob.obj.gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/,"\n\n")
+      end
+      dob
+    end
+    def textface_marks_po4a(dob,endnotes_=:inline)
+      notes=''
+      dob.obj=dob.obj.
+        gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,
+          Mx[:src_bold_o] + '\1' + Mx[:src_bold_c]).
+        gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,
+          Mx[:src_italics_o] + '\1' + Mx[:src_italics_c]).
+        gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,
+          Mx[:src_underscore_o] + '\1' + Mx[:src_underscore_c]).
+        gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,
+          Mx[:src_subscript_o] + '\1' + Mx[:src_subscript_c]).
+        gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,
+          Mx[:src_superscript_o] + '\1' + Mx[:src_superscript_c]).
+        gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,
+          Mx[:src_insert_o] + '\1' + Mx[:src_insert_c]).
+        gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,
+          Mx[:src_cite_o] + '\1' + Mx[:src_cite_c]).
+        gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,
+          Mx[:src_strike_o] + '\1' + Mx[:src_strike_c]).
+        gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,
+          Mx[:src_monospace_o] + '\1' + Mx[:src_monospace_c])
+      unless dob.is==:code
+        dob.obj=dob.obj.
+          gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}/,'\1').
+          gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,'\1').
+          gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,
+            '\1 [link: <\2>]').
+          gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}image/,
+            '\1 [link: local image]').
+          gsub(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,'\1')
+        dob.obj,notes=extract_endnotes(dob.obj,endnotes_)
+        dob.obj=dob.obj.
+          gsub(/#{Mx[:gl_o]}(?:#lt|#060)#{Mx[:gl_c]}/,'<').
+          gsub(/#{Mx[:gl_o]}(?:#gt|#062)#{Mx[:gl_c]}/,'>').
+          gsub(/#{Mx[:gl_o]}#(?:038|amp)#{Mx[:gl_c]}/,'&').
+          gsub(/#{Mx[:gl_o]}#033#{Mx[:gl_c]}/,'!').
+          gsub(/#{Mx[:gl_o]}#035#{Mx[:gl_c]}/,'#').
+          gsub(/#{Mx[:gl_o]}#042#{Mx[:gl_c]}/,'*').
+          gsub(/#{Mx[:gl_o]}#045#{Mx[:gl_c]}/,'-').
+          gsub(/#{Mx[:gl_o]}#047#{Mx[:gl_c]}/,'/').
+          gsub(/#{Mx[:gl_o]}#095#{Mx[:gl_c]}/,'_').
+          gsub(/#{Mx[:gl_o]}#123#{Mx[:gl_c]}/,'{').
+          gsub(/#{Mx[:gl_o]}#125#{Mx[:gl_c]}/,'}').
+          gsub(/#{Mx[:gl_o]}#126#{Mx[:gl_c]}/,'~').
+          gsub(/#{Mx[:gl_o]}#169#{Mx[:gl_c]}/,'©')
+      end
+      dob=block_(dob)
+      dob=code_(dob)
+      dob.obj=dob.obj.gsub(/#{Mx[:br_page]}\s*|#{Mx[:br_page_new]}/,''). # remove page breaks
+        gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,'\1').
+        gsub(/#{Mx[:mk_o]}:name#(\S+?)#{Mx[:mk_c]}/,'').                 # remove name links
+        gsub(/&nbsp;|#{Mx[:nbsp]}/,' ').                                 # decide on
+        gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}(\S+?\.(?:png|jpg|gif)) .+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/,
+          '    [ \1 ]'). #"[ #{dir.url.images_local}\/\\1 ]")
+        gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}(\S+?\.(?:png|jpg|gif)) .+?#{Mx[:lnk_c]}image/,
+          '    [ \1 ]'). #"[ #{dir.url.images_local}\/\\1 ]")
+        gsub(/(?:^|[^_\\])\{\s*\S+?\.(?:png|jpg|gif)\s+.+?"(.*?)"\s*\}\S+/,
+          '[image: "\1"]')
+      [dob,notes]
+    end
+    def object_marks
+      @txtobj
+    end
+    self
+  end
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    object_munge
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/param.org b/org/param.org
new file mode 100644
index 00000000..20dbdf49
--- /dev/null
+++ b/org/param.org
@@ -0,0 +1,2363 @@
+-*- mode: org -*-
+#+TITLE:       sisu param
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:param:
+#+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
+
+* dp.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/dp.rb"
+# <<sisu_document_header>>
+module SiSU_Param
+  begin
+    require 'uri'
+    require 'pstore'
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('uri or pstore NOT FOUND (LoadError)')
+  end
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'dp_make'                            # dp_make.rb
+  require_relative 'dp_identify_markup'                 # dp_identify_markup.rb
+  @@date=SiSU_Env::InfoDate.new
+  @doc={
+    initialise: nil,
+    markup: '',
+    lnks: '',
+    stmp: '',
+    req: {},
+  }
+  @@trigger=nil
+  @@lv,@@flag={},{}
+  @@tex_backslash="\\\\"
+  class Parameters
+    @@publisher='SiSU scribe'
+    @@md=@@fns=@@pth=nil
+    def initialize(opt)
+      @opt=opt
+      @cX||=SiSU_Screen::Ansi.new(@opt.act[:color_state][:set])
+      @fns=if @opt.act[:psql][:set] == [:on] #revisit CHECK
+        opt.fns
+      else opt.fns.gsub(/\.ssm$/,'.ssm.sst')
+      end
+      SiSU_Param::Instantiate.new.param_instantiate
+      @env=SiSU_Env::InfoEnv.new(@fns)
+      @pstorefile="#{@env.processing_path.ao}/#{@fns}.pstore"
+    end
+    def get
+      if @opt.f_pth \
+      and @opt.f_pth[:pth] != Dir.pwd #BUG check
+        # you may need to change Dir.pwd to @opt.f_pth[:pth] where the latter
+        # has a path value that is different, however, f_pth is not always set!
+        Dir.chdir(@opt.f_pth[:pth])
+      end
+      if @@fns !=@fns \
+      or @@pth !=Dir.pwd               #@opt.f_pth[:pth]
+        @@fns,@@pth=@fns,Dir.pwd       #@opt.f_pth[:pth]
+        @@md=nil
+      end
+      if @@md.nil? \
+      or @opt.act[:maintenance][:set]==:on #not particularly helpful, as current cycle is through output types, with files changing, only helpful if deal with a file all output types before going to next file
+        if File.exist?(@pstorefile)
+          param_msg='Parameters from pstore'
+          store=PStore.new(@pstorefile)
+          store.transaction do
+            @md=store['md']
+          end
+          @md
+        else
+          param_msg='Parameters extracted'
+          fns_array=@env.read_source_file(@opt.fns)
+          @md=SiSU_Param::Parameters::Instructions.new(fns_array,@opt).extract
+          @md
+        end
+        if defined? @md.title.main # on removal check problems with -U
+          if (@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on)
+            SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              param_msg,
+              @md.title.main
+            ).txt_grey
+          end
+        end
+        @@md=@md
+      else @@md
+      end
+      begin
+        @@md.opt=@opt
+        @@md
+      rescue
+        SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+          mark('has an existing option been selected?')
+        exit
+      end
+    end
+    class MdDefault
+      def rights(author,date)
+        @author,@date=author,date
+        def assignment(author)
+          'copyright not explicitly stated, ' \
+          + 'program "assigning" copyright to author: ' \
+          + author
+        end
+        def all
+          s=nil
+          if @author
+            #puts assignment(@author)
+            s ||=((@date =~/((?:1[4-9]|2[01])\d{2})/ ) \
+            ? ("Copyright (C) #{$1} #{@author}")
+            : ('Copyright (C)' + @author))                     #matches years 1400 through 21\d\d
+          end
+          s
+        end
+        def copyright_and_license
+          s=nil
+          if @author
+            #puts assignment(@author)
+            s ||=((@date =~/((?:1[4-9]|2[01])\d{2})/ ) \
+            ? ("Copyright (C) #{$1} #{@author}")
+            : ('Copyright (C)' + @author))                     #matches years 1400 through 21\d\d
+          end
+          s
+        end
+        def text
+          all
+        end
+        def copyright
+          def all
+            s=nil
+            if @author
+              s ||=((@date =~/((?:1[4-9]|2[01])\d{2})/ ) \
+              ? ("Copyright (C) #{$1} #{@author}")
+              : ('Copyright (C)' + @author))                     #matches years 1400 through 21\d\d
+            end
+            s
+          end
+          def text
+            all
+          end
+          self
+        end
+        self
+      end
+    end
+    class MdMake < SiSU_Param_Make::MdMake
+    end
+    class Md
+      def initialize(str,opt,env)
+        @s,@opt,@env=str,opt,env
+      end
+      def validate_length(s,l,n)
+        #s=(s.length <= l) ? s : nil
+        s=if s.is_a?(String) \
+        and s.length <= l
+          s
+        elsif s.is_a?(NilClass)
+          nil
+        elsif s.class !=String
+          STDERR.puts "#{n} is #{s.class}: programming error, String expected #{__FILE__}:#{__LINE__}"
+          s
+        else
+          SiSU_Screen::Ansi.new(
+            'v',
+            "*WARN* #{n} length #{s.length} exceeds set db field length #{l}, metadata dropped",
+            @opt.fns
+          ).warn unless @opt.act[:quiet][:set]==:on
+          nil
+        end
+      end
+      def name_format(name)
+        if name
+          name=name.strip
+          @name_a_h=[]
+          authors=name.scan(/[^;]+/)
+          authors.each_with_index do |a,i|
+            b=((a =~/\s*\|\s*/) ? (a.split(/\|/)) : [a])
+            if b[0] =~/"(.+?)"/
+              @name_a_h << { the: $1 }
+            else
+              x=b[0].scan(/[^,]+/)
+              if x.length==1
+                @name_a_h << { the: x[0].strip }
+              elsif x.length==2
+                @name_a_h << { the: x[0].strip, others: x[1].strip }
+              else #p x.length
+              end
+            end
+            b.delete_at(0)
+            b.each do |d|
+              k,c=nil
+              k,c=/^(\S+)\s+(.*)/.match(d)[1,2] if d
+              @name_a_h[i][:hon]=c.strip if k=='hon'
+              @name_a_h[i][:affiliation]=c.strip if k=='affiliation'
+              @name_a_h[i][:nationality]=c.strip if k=='nationality'
+            end
+          end
+          l=@name_a_h.length
+          name_str=''
+          @name_a_h.each_with_index do |a,i|
+            name_str += if a[:others]
+              z=(((l - i) > 1) ? ', ' : '')
+              "#{a[:others].strip} #{a[:the].strip}" + z
+            else
+              z=(((l - i) > 2) ? ', ' : '')
+              "#{a[:the].strip}" + z
+            end
+          end
+          { name_a_h: @name_a_h, name_str: name_str }
+        else nil
+        end
+      end
+      def build_hash(arr)
+        @h={}
+        arr.each_with_index do |x,i|
+          a,b=nil,nil
+          if x =~/^%\s/ #ignore comment
+          elsif x =~/:(\S+?):\s+(.+)/
+            a,b=/:(\S+?):\s+(.+)\Z/m.match(x)[1,2]
+            b=b.gsub(/\s*<br(?: \/)?>\s*/,' \\\\\\ ')
+            b=if b =~/\n/m
+              (b =~/;\n/m) \
+              ? (b.split(/;\s*\n\s*/).join(';'))
+              : (b.split(/\s*\n\s*/).join(' '))
+            else
+              b
+            end
+          elsif i == 0
+            a='main'
+            b=x
+          else
+          end
+          @h[a]=b
+        end
+        @h
+      end
+      def title
+        a=@s.split(/\n%\s.+?$|[ ]*\n[ ]*/m)
+        @h=build_hash(a)
+        def main
+          s=@h['main']
+          l,n=Db[:col_title_part],'title.main'
+          validate_length(s,l,n)
+        end
+        def sub
+          s=@h['subtitle']
+          l,n=Db[:col_title_part],'title.subtitle'
+          validate_length(s,l,n)
+        end
+        def edition
+          s=@h['edition']
+          l,n=Db[:col_title_edition],'title.edition'
+          validate_length(s,l,n)
+        end
+        def note
+          s=@h['note']
+          l,n=Db[:col_info_note],'title.note'
+          validate_length(s,l,n)
+        end
+        def short
+          s=@h['short'] \
+          ? @h['short']
+          : @h['main']
+          l,n=Db[:col_title_part],'title.short'
+          validate_length(s,l,n)
+        end
+        def full
+          s=@h['subtitle'] \
+          ? (@h['main'] + ' - ' + @h['subtitle'])
+          : @h['main']
+          l,n=Db[:col_title],'title.full'
+          validate_length(s,l,n)
+        end
+        def language
+          s=@h['language']
+          l,n=Db[:col_language],'title.language'
+          validate_length(s,l,n)
+        end
+        def language_char # look into, this must be set, from 1 directory stub (.fi), 2 filename (~fi), [3 (not used) document header (@title:\n  :language_char: fi)]
+          s=@h['language_char']
+          l,n=Db[:col_language_char],'title.language_char'
+          validate_length(s,l,n)
+        end
+        self
+      end
+      def creator #there are sub categories that need to be catered for and sometimes more than one author etc.; implement array.to_s.length validation test later, current test on string approximate as string is not used
+        a=@s.split(/\n%\s.+?$|[ ]*\n[ ]*/m)
+        @h=build_hash(a)
+        def author
+          @h['author']=(@h['author'] \
+          ? @h['author']
+          : @h['main'])
+          names=name_format(@h['author'])
+          s=names[:name_str]
+          l,n=Db[:col_name],'creator.author'
+          validate_length(s,l,n)
+        end
+        def author_detail
+          s=@h['author'] \
+          ? @h['author']
+          : @h['main']
+          names=name_format(s)
+          names[:name_a_h]
+        end
+        def email #revisit
+          s=@h['email']
+        end
+        def editor
+          names=@h['editor'] \
+          ? name_format(@h['editor'])
+          : nil
+          s=(names.is_a?(Hash)) \
+          ? names[:name_str]
+          : nil
+          s=if s
+            l,n=Db[:col_name],'creator.editor'
+            validate_length(s,l,n)
+          else nil
+          end
+        end
+        def editor_detail
+          names=@h['editor'] \
+          ? name_format(@h['editor'])
+          : nil
+          (names.is_a?(Hash)) \
+          ? names[:name_a_h]
+          : nil
+        end
+        def contributor
+          names=@h['contributor'] \
+          ? name_format(@h['contributor'])
+          : nil
+          s=(names.is_a?(Hash)) \
+          ? names[:name_str]
+          : nil
+          s=if s
+            l,n=Db[:col_name],'creator.author'
+            validate_length(s,l,n)
+          else nil
+          end
+        end
+        def contributor_detail
+          names=@h['contributor'] \
+          ? name_format(@h['contributor'])
+          : nil
+          (names.is_a?(Hash)) \
+          ? names[:name_a_h]
+          : nil
+        end
+        def illustrator
+          names=@h['illustrator'] \
+          ? name_format(@h['illustrator'])
+          : nil
+          s=(names.is_a?(Hash)) \
+          ? names[:name_str]
+          : nil
+          s=if s
+            l,n=Db[:col_name],'creator.illustrator'
+            validate_length(s,l,n)
+          else nil
+          end
+        end
+        def illustrator_detail
+          names=@h['illustrator'] \
+          ? name_format(@h['illustrator'])
+          : nil
+          (names.is_a?(Hash)) \
+          ? names[:name_a_h]
+          : nil
+        end
+        def photographer
+          names=@h['photographer'] \
+          ? name_format(@h['photographer'])
+          : nil
+          s=(names.is_a?(Hash)) \
+          ? names[:name_str]
+          : nil
+          s=if s
+            l,n=Db[:col_name],'creator.photographer'
+            validate_length(s,l,n)
+          else nil
+          end
+        end
+        def photographer_detail
+          names=@h['photographer'] \
+          ? name_format(@h['photographer'])
+          : nil
+          (names.is_a?(Hash)) \
+          ? names[:name_a_h]
+          : nil
+        end
+        def translator
+          names=@h['translator'] \
+          ? name_format(@h['translator'])
+          : nil
+          s=(names.is_a?(Hash)) \
+          ? names[:name_str]
+          : nil
+          s=if s
+            l,n=Db[:col_name],'creator.translator'
+            validate_length(s,l,n)
+          else nil
+          end
+        end
+        def translator_detail
+          names=@h['translator'] \
+          ? name_format(@h['translator'])
+          : nil
+          (names.is_a?(Hash)) \
+          ? names[:name_a_h]
+          : nil
+        end
+        def audio
+          names=@h['audio'] \
+          ? name_format(@h['audio'])
+          : nil
+          s=(names.is_a?(Hash)) \
+          ? names[:name_str]
+          : nil
+          s=if s
+            l,n=Db[:col_name],'creator.audio'
+            validate_length(s,l,n)
+          else nil
+          end
+        end
+        def audio_detail
+          names=@h['audio'] \
+          ? name_format(@h['audio'])
+          : nil
+          (names.is_a?(Hash)) \
+          ? names[:name_a_h]
+          : nil
+        end
+        def digitized_by
+          names=@h['digitized_by'] \
+          ? name_format(@h['digitized_by'])
+          : nil
+          s=(names.is_a?(Hash)) \
+          ? names[:name_str]
+          : nil
+          s=if s
+            l,n=Db[:col_name],'creator.digitized_by'
+            validate_length(s,l,n)
+          else nil
+          end
+        end
+        def digitized_by_detail
+          names=@h['digitized_by'] \
+          ? name_format(@h['digitized_by'])
+          : nil
+          (names.is_a?(Hash)) \
+          ? names[:name_a_h]
+          : nil
+        end
+        def prepared_by
+          names=@h['prepared_by'] \
+          ? name_format(@h['prepared_by'])
+          : nil
+          s=(names.is_a?(Hash)) \
+          ? names[:name_str]
+          : nil
+          s=if s
+            l,n=Db[:col_name],'creator.prepared_by'
+            validate_length(s,l,n)
+          else nil
+          end
+        end
+        def prepared_by_detail
+          names=@h['prepared_by'] \
+          ? name_format(@h['prepared_by'])
+          : nil
+          names=name_format(@h['prepared_by'])
+          (names.is_a?(Hash)) \
+          ? names[:name_a_h]
+          : nil
+        end
+        self
+      end
+      def rights
+        a=@s.split(/\n%\s.+?$|[ ]*\n[ ]*/m)
+        @h=build_hash(a)
+        def copyright
+          def text #you may wish to expand to take from all
+            s=if @h['copyright'] then @h['copyright']
+            elsif @h['text']     then @h['text']
+            elsif @h['main']     then @h['main']
+            else
+              SiSU_Screen::Ansi.new(
+                @opt.act[:color_state][:set],
+                'WARNING Document Copyright missing; provide @rights: :copyright:'
+              ).warn if (@opt.act[:verbose][:set]==:on \
+                || @opt.act[:verbose_plus][:set]==:on \
+                || @opt.act[:maintenance][:set]==:on)
+              ''
+            end
+            l,n=Db[:col_info_note],'rights.copyright.text'
+            validate_length(s,l,n)
+          end
+          def translation
+            s=@h['translation'] \
+            ? @h['translation']
+            : nil
+            l,n=Db[:col_info_note],'rights.copyright.translation'
+            validate_length(s,l,n)
+          end
+          def illustrations
+            s=@h['illustrations'] \
+            ? @h['illustrations']
+            : nil
+            l,n=Db[:col_info_note],'rights.copyright.illustrations'
+            validate_length(s,l,n)
+          end
+          def photographs
+            s=@h['photographs'] \
+            ? @h['photographs']
+            : nil
+            l,n=Db[:col_info_note],'rights.copyright.photographs'
+            validate_length(s,l,n)
+          end
+          def digitization
+            s=@h['digitization'] \
+            ? @h['digitization']
+            : nil
+            l,n=Db[:col_info_note],'rights.copyright.digitization'
+            validate_length(s,l,n)
+          end
+          def audio
+            s=@h['audio'] \
+            ? @h['audio']
+            : nil
+            l,n=Db[:col_info_note],'rights.copyright.audio'
+            validate_length(s,l,n)
+          end
+          self
+        end
+        def license
+          s=@h['license'] \
+          ? @h['license']
+          : nil
+          l,n=Db[:col_info_note],'rights.license'
+          validate_length(s,l,n)
+        end
+        def sep(str)
+          ' \\\\ '
+        end
+        def copyright_and_license
+          s=if @h['copyright_and_license'] then @h['copyright_and_license']
+          else
+            s=''
+            if defined? copyright.text \
+            and copyright.text \
+            and not copyright.text.empty?
+              v=sep(copyright.text)
+              s +=copyright.text + v
+            end
+            if defined? copyright.license \
+            and copyright.license \
+            and not copyright.license.empty?
+              s +=copyright.license
+            end
+            if s.empty?
+              SiSU_Screen::Ansi.new(
+                @opt.act[:color_state][:set],
+                'WARNING Document Rights information missing; provide @rights: :copyright:'
+              ).warn if (@opt.act[:verbose][:set]==:on \
+                || @opt.act[:verbose_plus][:set]==:on \
+                || @opt.act[:maintenance][:set]==:on)
+            else
+              l,n=Db[:col_info_note],'rights.all'
+              validate_length(s,l,n)
+            end
+            s=s.gsub(/ [\\]+\s+$/,'')
+          end
+          s
+        end
+        def all
+          s=if @h['all'] then @h['all']
+          else
+            s=''
+            if defined? copyright.text \
+            and copyright.text \
+            and not copyright.text.empty?
+              v=sep(copyright.text)
+              s +='Copyright: ' + copyright.text + v
+            end
+            if defined? copyright.translation \
+            and copyright.translation \
+            and not copyright.translation.empty?
+              v=sep(copyright.translation)
+              s +='translation: ' + copyright.translation + v
+            end
+            if defined? copyright.illustrations \
+            and copyright.illustrations \
+            and not copyright.illustrations.empty?
+              v=sep(copyright.illustrations)
+              s +='illustrations: ' + copyright.illustrations + v
+            end
+            if defined? copyright.photographs \
+            and copyright.photographs \
+            and not copyright.photographs.empty?
+              v=sep(copyright.photographs)
+              s +='photographs: ' + copyright.photographs + v
+            end
+            if defined? copyright.digitization \
+            and copyright.digitization \
+            and not copyright.digitization.empty?
+              v=sep(copyright.digitization)
+              s +='digitization: ' + copyright.digitization + v
+            end
+            if defined? copyright.audio \
+            and copyright.audio \
+            and not copyright.audio.empty?
+              v=sep(copyright.audio)
+              s +='audio: ' + copyright.audio + v
+            end
+            if defined? copyright.license \
+            and copyright.license \
+            and not copyright.license.empty?
+              s +='License: ' + copyright.license
+            end
+            if s.empty?
+              SiSU_Screen::Ansi.new(
+                @opt.act[:color_state][:set],
+                'WARNING Document Rights information missing; provide @rights: :copyright:'
+              ).warn if (@opt.act[:verbose][:set]==:on \
+                || @opt.act[:verbose_plus][:set]==:on \
+                || @opt.act[:maintenance][:set]==:on)
+            else
+              l,n=Db[:col_info_note],'rights.all'
+              validate_length(s,l,n)
+            end
+            s=s.gsub(/ [\\]+\s+$/,'')
+          end
+          s
+        end
+        self
+      end
+      def identifier
+        a=@s.split(/\n%\s.+?$|[ ]*\n[ ]*/m)
+        @h=build_hash(a)
+        def oclc
+          s=@h['oclc']
+          l,n=Db[:col_library],'identifier.oclc'
+          validate_length(s,l,n)
+        end
+        def isbn
+          s=@h['isbn']
+          l,n=Db[:col_small],'identifier.isbn'
+          validate_length(s,l,n)
+        end
+        def pg
+          s=@h['pg']
+          l,n=Db[:col_small],'identifier.pg'
+          validate_length(s,l,n)
+        end
+        self
+      end
+      def classify
+        a=@s.split(/(\n%\s.+?$|[ ]*)(?:\n[ ]*(?=:)|\Z)/m)
+        @h=build_hash(a)
+        def topic_register
+          s=@h['topic_register']
+          l,n=Db[:col_info_note],'classify.topic_register'
+          validate_length(s,l,n)
+        end
+        def subject
+          s=@h['subject']
+          l,n=Db[:col_txt_long],'classify.subject'
+          validate_length(s,l,n)
+        end
+        def keywords
+          s=@h['keywords']
+          l,n=Db[:col_txt_long],'classify.keywords'
+          validate_length(s,l,n)
+        end
+        def loc
+          s=@h['loc']
+          l,n=Db[:col_library],'classify.loc'
+          validate_length(s,l,n)
+        end
+        def dewey
+          s=@h['dewey']
+          l,n=Db[:col_library],'classify.dewey'
+          validate_length(s,l,n)
+        end
+        self
+      end
+      def publisher
+        a=@s.split(/\n%\s.+?$|[ ]*\n[ ]*/m)
+        @h=build_hash(a)
+        s=@h['main']
+        l,n=Db[:col_name],'publisher'
+        validate_length(s,l,n)
+      end
+      def date
+        a=@s.split(/\n%\s.+?$|[ ]*\n[ ]*/m)
+        @h=build_hash(a)
+        def added_to_site
+          s=@h['added_to_site']
+          l,n=Db[:col_date_text],'date.added_to_site'
+          validate_length(s,l,n)
+        end
+        def available
+          s=@h['available']
+          l,n=Db[:col_date_text],'date.available'
+          validate_length(s,l,n)
+        end
+        def created
+          s=@h['created']
+          l,n=Db[:col_date_text],'date.created'
+          validate_length(s,l,n)
+        end
+        def issued
+          s=@h['issued']
+          l,n=Db[:col_date_text],'date.issued'
+          validate_length(s,l,n)
+        end
+        def modified
+          s=@h['modified']
+          l,n=Db[:col_date_text],'date.modified'
+          validate_length(s,l,n)
+        end
+        def published
+          s=@h['published']=(@h['published'] ? @h['published'] : @h['main'])
+          l,n=Db[:col_date_text],'date.published'
+          validate_length(s,l,n)
+        end
+        def valid
+          s=@h['valid']
+          l,n=Db[:col_date_text],'date.valid'
+          validate_length(s,l,n)
+        end
+        self
+      end
+      #def language                     # as things stand this should really be populated from title.language and original.language, resolve
+      #  a=@s.split(/\n%\s.+?$|[ ]*\n[ ]*/m)
+      #  @h=build_hash(a)
+      #  def document
+      #    s=@h['document']=(@h['document'] ? @h['document'] : @h['main'])
+      #    l,n=Db[:col_language],'language.document'
+      #    validate_length(s,l,n)
+      #  end
+      #  def document_char
+      #    s=@h['document_char']=(@h['document_char'] ? @h['document_char'] : nil)
+      #    l,n=Db[:col_language_char],'language.document_char'
+      #    validate_length(s,l,n)
+      #  end
+      #  def original
+      #    s=@h['original']
+      #    l,n=Db[:col_language],'language.original'
+      #    validate_length(s,l,n)
+      #  end
+      #  def original_char
+      #    s=@h['original_char']
+      #    l,n=Db[:col_language_char],'language.original_char'
+      #    validate_length(s,l,n)
+      #  end
+      #  self
+      #end
+      def current_publisher
+        @s
+      end
+      def original
+        a=@s.split(/\n%\s.+?$|[ ]*\n[ ]*/m)
+        @h=build_hash(a)
+        def publisher
+          s=@h['publisher']
+          l,n=Db[:col_name],'original.publisher'
+          validate_length(s,l,n)
+        end
+        def language
+          s=@h['language']
+          l,n=Db[:col_language],'original.language'
+          validate_length(s,l,n)
+        end
+        def language_char
+          s=@h['language_char']
+          l,n=Db[:col_language_char],'original.language_char'
+          validate_length(s,l,n)
+        end
+        def source
+          s=@h['source']
+          l,n=Db[:col_name],'original.source'
+          validate_length(s,l,n)
+        end
+        def institution
+          s=@h['institution']
+          l,n=Db[:col_name],'original.institution'
+          validate_length(s,l,n)
+        end
+        def nationality
+          s=@h['nationality']
+          l,n=Db[:col_language],'original.nationality'
+          validate_length(s,l,n)
+        end
+        self
+      end
+      def notes
+        a=@s.split(/\n%\s.+?$|[ ]*\n[ ]*/m)
+        @h=build_hash(a)
+        def description
+          s=@h['description']
+          l,n=Db[:col_info_note],'notes.description'
+          validate_length(s,l,n)
+        end
+        def abstract
+          s=@h['abstract']
+          l,n=Db[:col_info_note],'notes.abstract'
+          validate_length(s,l,n)
+        end
+        def comment
+          s=@h['comment']
+          l,n=Db[:col_info_note],'notes.comment'
+          validate_length(s,l,n)
+        end
+        def coverage
+          s=@h['coverage']
+          l,n=Db[:col_info_note],'notes.coverage'
+          validate_length(s,l,n)
+        end
+        def relation
+          s=@h['relation']
+          l,n=Db[:col_info_note],'notes.relation'
+          validate_length(s,l,n)
+        end
+        def source
+          s=@h['source']
+          l,n=Db[:col_txt_long],'notes.source'
+          validate_length(s,l,n)
+        end
+        def history
+          s=@h['history']
+          l,n=Db[:col_txt_long],'notes.history'
+          validate_length(s,l,n)
+        end
+        def type
+          s=@h['type']
+          l,n=Db[:col_txt_long],'notes.relation'
+          validate_length(s,l,n)
+        end
+        def format
+          s=@h['format']
+          l,n=Db[:col_txt_short],'notes.format'
+          validate_length(s,l,n)
+        end
+        def prefix
+          @h['prefix']
+        end
+        self
+      end
+    end
+    class Instructions
+      @doc={ lv: [] }
+      @doc[:fns],@doc[:fnb],@doc[:scr_suffix]='','',''
+      @@publisher='SiSU scribe'
+      attr_accessor :make,:env,:path,:file,:fn,:fns,:fno,:fnb,:fnn,:fnt,:fnl,:flv,:fnz,:fnstex,:ocn,:sfx_src,:pdf,:file_type,:dir_out,:dir_tex,:dir_lout,:txt_path,:sisu,:project_details,:ruby_version,:title,:subtitle,:full_title,:html_title,:subtitle_tex,:creator,:classify,:author_home,:author,:email,:author_title,:author_nationality,:authors,:authorship,:translator,:illustrator,:prepared_by,:digitized_by,:subject,:description,:publisher,:current_publisher,:contributor,:date,:date_created,:date_issued,:date_available,:date_valid,:date_modified,:date_translated,:date_added_to_site,:date_scheme,:date_created_scheme,:date_issued_scheme,:date_available_scheme,:date_valid_scheme,:date_modified_scheme,:type,:format,:identifier,:source,:language,:language_original,:relation,:coverage,:rights,:keywords,:comments,:abstract,:cls_loc,:cls_dewey,:cls_pg,:cls_isbn,:papersize,:papersize_array,:toc,:lv0,:lv1,:lv2,:lv3,:lv4,:lv5,:lv6,:lvs,:pagenew,:pagebreak,:pageline,:num_top,:bold_match_list,:italics_match_list,:substitution_match_list,:emphasis_set_to,:toc_lev_limit,:flag_biblio,:flag_auto_biblio,:flag_endnotes,:flag_auto_endnotes,:flag_glossary,:flag_separate_endnotes,:flag_separate_endnotes_make,:markup,:markup_instruction,:flag_tables,:vocabulary,:doc_css,:yaml,:lnk,:links,:prefix_a,:prefix_b,:suffix,:information,:contact,:icon,:image,:ad_url,:ad_png,:ad_alt,:ad_began,:flag_promo,:promo,:ad_home,:stmp,:stmpd,:sc_filename,:sc_number,:sc_date,:sc_time,:sc_info,:yamladdr,:locale,:wc_lines,:wc_words,:wc_bytes,:file_encoding,:filesize,:user,:home,:hostname,:pwd,:firstseg,:programs,:author_copymark,:i18n,:lang,:lang_code_insert,:en,:notes,:dgst,:generated,:tags,:tag_array,:concord_make,:seg_names,:seg_autoname_safe,:set_header_title,:set_heading_top,:set_heading_seg,:heading_seg_first,:heading_seg_first_flag,:base_program,:ec,:opt,:sem_tag,:book_idx,:topic_register,:topic_register_array,:original,:writing_focus,:audio,:daisy,:home_button_image,:home_button_links,:footer_links,:cover_image,:man_section
+      def initialize(fns_array,opt)
+        @env=@path,@file=@fn=@fns=@fno=@fnb=@fnn=@fnt=@fnl=@flv=@fnz=@fnstex=@ocn=@sfx_src=@pdf=@file_type=@dir_out=@dir_tex=@dir_lout=@txt_path=@make=@flag_biblio=@flag_auto_biblio=@flag_endnotes=@flag_auto_endnotes=@flag_glossary=@flag_separate_endnotes=@flag_separate_endnotes_make=@sisu=@project_details=@ruby_version=@title=@subtitle=@full_title=@html_title=@subtitle_tex=@creator=@classify=@author_home=@author=@email=@author_title=@author_nationality=@translator=@illustrator=@prepared_by=@digitized_by=@subject=@description=@publisher=@current_publisher=@contributor=@date=@date_created=@date_issued=@date_available=@date_valid=@date_modified=@date_translated=@date_added_to_site=@date_scheme=@date_created_scheme=@date_issued_scheme=@date_available_scheme=@date_valid_scheme=@date_modified_scheme=@type=@format=@identifier=@source=@language=@language_original=@relation=@coverage=@rights=@keywords=@comments=@abstract=@cls_loc=@cls_dewey=@cls_pg=@cls_isbn=@papersize=@toc=@lv0=@lv1=@lv2=@lv3=@lv4=@lv5=@lv6=@pagenew=@pagebreak=@pageline=@num_top=@bold_match_list=@italics_match_list=@substitution_match_list=@emphasis_set_to=@toc_lev_limit=@flag_tables=@vocabulary=@doc_css=@yaml=@lnk=@links=@prefix_a=@prefix_b=@suffix=@information=@contact=@icon=@ad_url=@ad_png=@ad_alt=@ad_began=@promo=@ad_home=@stmp=@stmpd=@sc_filename=@sc_number=@sc_date=@sc_time=@sc_info=@yamladdr=@locale=@wc_lines=@wc_words=@wc_bytes=@file_encoding=@filesize=@firstseg=@programs=@author_copymark=@i18n=@lang=@lang_code_insert=@en=@notes=@dgst=@generated=@heading_seg_first=@base_program=@topic_register=@original=@writing_focus=@audio=@home_button_image=@home_button_links=@cover_image=@man_section=nil
+        @data,      @path,  @fns,   @fno,   @opt=
+          fns_array,opt.pth,opt.fns,opt.fno,opt #@data used as data
+        @flag_tables,@set_header_title,@set_heading_top,@set_heading_seg,@heading_seg_first_flag,@flag_promo,@book_idx=
+          false,     false,            false,           false,           false,                  false,      false
+        @seg_autoname_safe=true
+        @daisy,@sem_tag=false,false
+        @authorship,@markup_instruction,@image='','','','' #check which other values should be set to empty rather than nil
+        @markup=@markup_instruction #use @markup_instruction
+        @doc,@fn,@make_italic,@tag_hash,@ec={},{},{},{},{},{}
+        @flv,@lang,@seg_names,@tags,@tag_array,@tag_a,@ec[:image],@ec[:audio],@ec[:multimedia]=Array.new(9){[]}
+        @authors,@topic_register_array,@papersize_array=[],[],[]
+        @lvs=[nil,0,0,0,0,0,0]
+        @emphasis_set_to='bold'
+        @lang_code_insert=SiSU_Env::FilenameLanguageCodeInsert.new(@opt).language_code_insert
+        @footer_links= { left: { say: '', url: '' }, center: { say: '', url: '' } }
+        @rgx_image=/(?:^|[^_\\])\{(?:\s*|\~\^\s+)(\S+?\.(?:png|jpg|gif)\b)/m
+        @rgx_audio=/\{\s*(\S+?\.(?:mp3|ogg))/
+        @rgx_mm=/\{\s*(\S+?\.(?:ogg|mpeg))/ #expand and distinguish ogg
+        Dir.chdir(@opt.f_pth[:pth])
+        begin
+        rescue
+          SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@fns).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+        ensure
+        end
+        @header_make_links_append=:no
+        common_makes=(defined? @opt.make_instructions_pod) \
+        && @opt.make_instructions_pod !=nil \
+        && @opt.make_instructions_pod[:makeset]==true \
+        ? @opt.make_instructions_pod
+        : @opt.make_instructions
+        if common_makes[:makeset]
+          @pagenew=common_makes[:pagenew]
+          @pagebreak=common_makes[:pagebreak]
+          @pageline=common_makes[:pageline]
+          @toc=common_makes[:toc]
+          @lv0=common_makes[:lv0]
+          @lv1=common_makes[:lv1]
+          @lv2=common_makes[:lv2]
+          @lv3=common_makes[:lv3]
+          @lv4=common_makes[:lv4]
+          @lv5=common_makes[:lv5]
+          @lv6=common_makes[:lv6]
+          @num_top=common_makes[:num_top]
+          @i18n=common_makes[:i18n]
+          @man_section=common_makes[:man_section]
+          @emphasis_set_to=common_makes[:emphasis_set_to]
+          @bold_match_list=common_makes[:bold_match_list]
+          @italics_match_list=common_makes[:italics_match_list]
+          @substitution_match_list=common_makes[:substitution_match_list]
+          @footer_links=common_makes[:footer_links]
+          @home_button_links=common_makes[:home_button_links]
+          @home_button_image=common_makes[:home_button_image]
+          @cover_image=common_makes[:cover_image]
+          @lnk=@links=common_makes[:links]
+          @header_make_links_append=common_makes[:links_append]
+        end
+      end
+      #protected
+      def extract
+        begin
+          @user,@home,@hostname,@pwd=ENV['USER'],ENV['HOME'],ENV['HOSTNAME'],ENV['PWD']
+          @programs,@wc,@language,@language_original={},{},{},{}
+          @en={ sum: 0, mark: 0, note: 0, mismatch: 0 }
+          @prog=SiSU_Env::InfoSettings.new
+          @sys=SiSU_Env::SystemCall.new
+          @env=SiSU_Env::InfoEnv.new(@fns) #watch
+          if (@opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on)
+            puts 'system locale: ' + @sys.locale
+          end
+          if @prog.wc \
+          and @sys.wc
+            wc=%x{wc #{fns}}
+            wca=wc.scan(/\d+/)
+            @wc_lines,@wc_words,@wc_bytes=wca[0].to_i,wca[1].to_i,wca[2].to_i
+          else
+            fns_a=@data.dup
+            tmp=fns_a.join
+            fns_a=tmp.scan(/\S+/)
+            @wc_words=fns_a.length
+            fns_a=tmp=nil
+          end
+          @concord_make=(@wc_words > @env.concord_max) ? false : true
+          @locale=@sys.locale
+          @file_encoding=@sys.file_encoding(fns,@opt.act)
+          # programs set here for things that affect output appearance only
+          @programs[:pdf]=SiSU_Env::SystemCall.new.program_found?('pdflatex')
+          if @opt.act[:psql][:set] == [:ok]
+            m=/((.+?)(?:\~\w\w(?:_\w\w)?)?)\.((?:-|ssm\.)?sst|ssm|ssi)$/ #watch added match for sss
+            @fnn,@fnb,@fnt=@fns[m,1],@fns[m,2],@fns[m,3]
+            @flv=@env.document_language_versions_found[:f]
+          else
+            m=/((.+?)(?:\~\w\w(?:_\w\w)?)?)\.((?:-|ssm\.)?sst|ssm)$/ #watch added match for sss
+            @fnn,@fnb,@fnt=@fns[m,1],@fns[m,2],@fns[m,3]
+            @flv=@env.document_language_versions_found[:f]
+            @fnz=(@fns =~/\.(?:ssm\.sst|ssm)$/) ? (@fnn + '.ssm.txz') : (@fnn + '.sst.txz')
+          end
+          @papersize=@env.papersize #'A4' #default size #get first from SiSU_Env:: # @env is probably no longer most appropriate name! as default info is more general
+          @sfx_src=@fns[m,2]
+          if @fns =~ /(?:-|ssm\.)?sst$/ \
+          and not @opt.act[:psql][:set] == [:ok]
+            @env_out_root=@env.path.output
+            @dir_out="#{@env.path.output}/#{@fnb}"
+            @dir_tex=@env.processing_path.tex
+            @dir_lout=@env.processing_path.lout
+            @@publisher='SiSU http://www.jus.uio.no/sisu'
+          end
+          @txt_path=@txt_path ||= @env.path.output
+          @stmp=%{#{@fns}}[/^(.+?)\..*/m,1]
+          @fnstex=@fns.gsub(/_/,'\_\-').gsub(/\./,'.\-')
+          @flag_endnotes,@flag_auto_endnotes,@flag_separate_endnotes=false,false,false
+          @flag_separate_endnotes_make=true
+          @flag_glossary=false
+          @flag_biblio,@flag_auto_biblio=false,false
+          ver=SiSU_Env::InfoVersion.instance
+          @project_details=ver.get_version
+          @ruby_version=ver.rbversion
+          @generated=Time.now
+          fns_array=@data.dup
+          skip unless fns_array                                                    # consider
+          @code_flag=false
+          flag_code_curly=:not_code_curly
+          flag_code_tics=:not_code_tics
+          fns_array.each do |para|                                               #% scan document
+            if para !~/^%+\s/ \
+            and para =~/<![abcdeghijklmnopqrstuvwxyz]/i # <!f not included
+              raise "Old markup style in file #{@fns}, current version #{@project_details.project} #{@project_details.version} #{@project_details.date_stamp} #{@project_details.date}:\n\t\t#{para}\n\n"
+            end
+            if para =~/^code\{/
+              flag_code_curly=:code_curly
+            elsif para =~/^\}code/
+              flag_code_curly=:not_code_curly
+            elsif para =~/^``` code/
+              flag_code_tics=:code_tics
+            elsif flag_code_tics ==:code_tics \
+            and para =~/^```/
+              flag_code_tics=:not_code_tics
+            end
+            @code_flag=if flag_code_curly==:code_curly \
+            or flag_code_tics==:code_tics
+              true
+            else false
+            end
+            regx_header=/^@\S+?:[+-]?\s/
+            if para =~regx_header \
+            and not @code_flag #or para=~/^(?:1|:?A)~/
+              case para
+              when /^@title:(.+)/m                                               #% * header metadata - title
+                @title=SiSU_Param::Parameters::Md.new($1.strip,@opt,@env).title
+              when /^@creator:(.+)/m                                             #% * header metadata - creator
+                @creator=SiSU_Param::Parameters::Md.new($1.strip,@opt,@env).creator
+                @authorship=@author=@creator.author
+                @authors=@creator.author_detail
+              when /^@date:(.+)/m                                                #% * header metadata - date
+                @date=SiSU_Param::Parameters::Md.new($1.strip,@opt,@env).date
+              when /^@publisher:\s+(.+)/m                                        #% * header metadata - publisher
+                @publisher=SiSU_Param::Parameters::Md.new($1.strip,@opt,@env).current_publisher
+                @current_publisher=@publisher
+              when /^@rights:(.+)/m                                              #% * header metadata - rights
+                @rights=SiSU_Param::Parameters::Md.new($1.strip,@opt,@env).rights
+              when /^@classify:(.+)/m                                            #% * header metadata - classify
+                @classify=SiSU_Param::Parameters::Md.new($1.strip,@opt,@env).classify
+              when /^@identifier:(.+)/m                                          #% * header metadata - identifier
+                @identifier=SiSU_Param::Parameters::Md.new($1.strip,@opt,@env).identifier
+              when /^@original:(.+)/m                                            #% * header metadata - original (document)
+                @original=SiSU_Param::Parameters::Md.new($1.strip,@opt,@env).original
+                @source=@original.source
+              when /^@notes?:\s(.+)\Z/m                                          #% * header metadata - notes
+                @notes=SiSU_Param::Parameters::Md.new($1.strip,@opt,@env).notes
+              when /^@links:\s+(.+?)\Z/m                                         #% * header metadata - links
+                links=SiSU_Param::Parameters::MdMake.new($1.strip,@opt,@env).make_links.links
+                @lnk=@links=if @header_make_links_append == :yes
+                  (links) \
+                    ? (links + @links)
+                    : @links
+                else
+                  (links) \
+                    ? (links)
+                    : @links
+                end
+              when /^@make:(.+)/m                                                #% * header processing - make
+                @make=SiSU_Param::Parameters::MdMake.new($1.strip,@opt,@env).make
+                makes=SiSU_Param_Make::MakeHead.new(@make).make_instruct
+                @pagenew=(makes[:pagenew]) \
+                  ? (makes[:pagenew]) \
+                  : @pagenew
+                @pagebreak=(makes[:pagebreak]) \
+                  ? (makes[:pagebreak]) \
+                  : @pagebreak
+                @pageline=(makes[:pageline]) \
+                  ? (makes[:pageline]) \
+                  : @pageline
+                @toc=(makes[:toc]) ? (makes[:toc]) : @toc
+                @lv0=(makes[:lv0]) ? (makes[:lv0]) : @lv0
+                @lv1=(makes[:lv1]) ? (makes[:lv1]) : @lv1
+                @lv2=(makes[:lv2]) ? (makes[:lv2]) : @lv2
+                @lv3=(makes[:lv3]) ? (makes[:lv3]) : @lv3
+                @lv4=(makes[:lv4]) ? (makes[:lv4]) : @lv4
+                @lv5=(makes[:lv5]) ? (makes[:lv5]) : @lv5
+                @lv6=(makes[:lv6]) ? (makes[:lv6]) : @lv6
+                @num_top=
+                  (makes[:num_top]) \
+                  ? (makes[:num_top]) \
+                  : @num_top
+                @substitution_match_list=
+                  (makes[:substitution_match_list]) \
+                  ? (makes[:substitution_match_list]) \
+                  : @substitution_match_list
+                @bold_match_list=
+                  (makes[:bold_match_list]) \
+                  ? (makes[:bold_match_list]) \
+                  : @bold_match_list
+                @italics_match_list=
+                  (makes[:italics_match_list]) \
+                  ? (makes[:italics_match_list]) \
+                  : @italics_match_list
+                @emphasis_set_to=
+                  (makes[:emphasis_set_to]) \
+                  ? (makes[:emphasis_set_to]) \
+                  : @emphasis_set_to
+                @i18n=
+                  (makes[:i18n]) \
+                  ? (makes[:i18n]) \
+                  : @i18n
+                @man_section=
+                  (makes[:man_section]) \
+                  ? (makes[:man_section]) \
+                  : @man_section
+                @footer_links=
+                  (makes[:footer_links]) \
+                  ? (makes[:footer_links]) \
+                  : @footer_links
+                @home_button_links=
+                  (makes[:home_button_links]) \
+                  ? (makes[:home_button_links]) \
+                  : @home_button_links
+                @home_button_image=
+                  (makes[:home_button_image]) \
+                  ? (makes[:home_button_image]) \
+                  : @home_button_image
+                @cover_image=
+                  (makes[:cover_image]) \
+                  ? (makes[:cover_image]) \
+                  : @cover_image
+              end
+              @lv0 ||=/^0~/
+              @lv1 ||=/^1~/
+              @lv2 ||=/^2~/
+              @lv3 ||=/^3~/
+              @lv4 ||=/^4~/
+              @lv5 ||=/^5~/
+              @lv6 ||=/^6~/
+            else                                                                 #% *
+              l_0=l_1=l_2=l_3=l_4=l_5=''
+              if defined? @make.headings[0]
+                l_0=if defined? @make.headings[0][0] \
+                and @make.headings[0][0] =~/\S+/
+                  "|^#{@make.headings[0][0]}"
+                end
+                l_1=if defined? @make.headings[0][1] \
+                and @make.headings[0][1] =~/\S+/
+                  "|^#{@make.headings[0][1]}"
+                end
+                l_2=if defined? @make.headings[0][2] \
+                and @make.headings[0][2] =~/\S+/
+                  "|^#{@make.headings[0][2]}"
+                end
+                l_3=if defined? @make.headings[0][3] \
+                and @make.headings[0][3] =~/\S+/
+                  "|^#{@make.headings[0][3]}"
+                end
+                l_4=if defined? @make.headings[0][4] \
+                and @make.headings[0][4] =~/\S+/
+                  "|^#{@make.headings[0][4]}"
+                end
+                l_5=if defined? @make.headings[0][5] \
+                and @make.headings[0][5] =~/\S+/
+                  "|^#{@make.headings[0][5]}"
+                end
+              end
+              case para
+              #when /^:?A~/
+              when /^:?B~#{l_0}/
+                @lvs[1]=1
+              when /^:?C~#{l_1}/
+                @lvs[2]=1
+              when /^:?D~#{l_2}/
+                @lvs[3]=1
+              when /^1~#{l_3}/
+                @lvs[4]=1
+              when /^2~#{l_4}/
+                @lvs[5]=1
+              when /^3~#{l_5}/
+                @lvs[6]=1
+              end
+              if para =~ /^:?A~/                                                  #% processing
+                if not defined? @title.full.nil?
+                  tf=para[/^:A~\S*(.+)$/m,1]
+                  tf="@title: #{tf}"
+                  @title=SiSU_Param::Parameters::Md.new(tf.strip,@opt,@env).title
+                end
+                creator=(@creator.is_a?(SiSU_Param::Parameters::Md) \
+                && defined? @creator.author \
+                && @creator.author.is_a?(String)) \
+                ? " #{@creator.author}"
+                : ''
+                title=@title.full.gsub(/\s*(?:<p>|<p \/>|<br>|<br \/>)\s*/,' ').
+                  gsub(/~\{.+?\}~/,'')
+                SiSU_Screen::Ansi.new(
+                  @opt.act[:color_state][:set],
+                  'Document Parameters',
+                  %{#{title}#{creator}}
+                ).txt_grey if @opt.act[:verbose][:set]==:on
+              end
+              unless @code_flag
+                if para =~/^1~!biblio(?:graphy)?/
+                  @flag_auto_biblio,@flag_biblio=false,true
+                  #@flag_biblio=true
+                elsif @flag_biblio ==true \
+                and @flag_auto_biblio ==false \
+                and para =~/^(?:au|author):/m
+                  @flag_auto_biblio =true
+                end
+                if para =~/^1~!glossary/
+                  @flag_glossary=true
+                end
+              end
+              if not @book_idx \
+              and para =~/^=\{(.+?)\}[\s`]*\Z/m
+                @book_idx=true
+              end
+              unless @code_flag
+                case para
+                when /~\{\s+.+?\}~/m                                             #% processing
+                  en=para.scan(/~\{.+?\}~/m)
+                  en.each { |e| @en[:sum] +=1 }
+                when /~\^(?:\s|$)/m                                              #% processing
+                  mk=para.scan(/~\^(?:\s|$)/)
+                  mk.each { |e| @en[:mark] +=1 }
+                when /^\^~\s+\S/ then @en[:note] +=1                             #% processing
+                end
+              end
+              if para =~/~\{|\^~ |~\^|\{.+?\[[1-6]\]\}\S+?\.ss[tm]/m
+                @flag_auto_endnotes,@flag_endnotes=true,true
+              end
+              if para =~/^(?:table\{|\{table)/i
+                @flag_tables=true
+              end
+            end
+            if para =~/^:?A~/
+              @set_heading_top=true
+            end
+            if para =~/^1~/
+              m=nil
+              if para =~/^1~(\S+)\s+(.+)$/
+                m,t=$1,$2
+              elsif para =~/^1~\s+(.+)$/
+                t=$1
+              end
+              unless @heading_seg_first_flag                                     # extract first segment name
+                @heading_seg_first=t
+                @heading_seg_first_flag=true
+              end
+              if m                                                               # list all segment names
+                @seg_names << m
+                @set_heading_seg=true
+                if m=~/^\d{1,3}/ \
+                and m !~/^0/
+                  @seg_autoname_safe=false
+                end
+              end
+            end
+            para=para.gsub(/<:=(\S+?)>/,'{ c_\1.png 14x14 }image')               # embedded symbol (image)
+            if para !~/^%+\s/ \
+            and para =~@rgx_image
+              @ec[:image] << para.scan(@rgx_image).uniq
+            end
+            @ec[:audio] << para.scan(@rgx_audio).uniq if para =~@rgx_audio #embedded content
+            @ec[:multimedia] << para.scan(@rgx_mm).uniq if para =~@rgx_mm #embedded content
+            unless @sem_tag
+              @sem_tag=true if para=~/[:;]\{.+?\}[:;][a-z+]/ #refix later
+            end
+          end                                                                    #% here endeth the document loop
+          unless @make
+            if (@opt.act[:verbose_plus][:set]==:on \
+            || @opt.act[:maintenance][:set]==:on)
+              SiSU_Screen::Ansi.new(
+                @opt.act[:color_state][:set],
+                '@make:',
+                'header absent'
+              ).warn
+            end
+            @make=SiSU_Param::Parameters::MdMake.new('@make: ',@opt,@env).make
+          end
+          if @cover_image \
+          and @cover_image.is_a?(Hash) \
+          and (@cover_image[:cover] =~@rgx_image \
+            or @cover_image[:cover] =~/\S+?.(?:jpg|png|gif)/)
+            @ec[:image] << @cover_image[:cover]
+          end
+          if @home_button_image \
+          and @home_button_image.is_a?(Hash) \
+          and (@home_button_image[:home] =~@rgx_image \
+            or @home_button_image[:home] =~/\S+?\.(?:jpg|png|gif)/)
+            @ec[:image] << @home_button_image
+          end
+          if @ec[:image].length > 0
+            @ec[:image]=@ec[:image].flatten.uniq
+            @ec[:image].delete_if {|x| x =~/https?:\/\// }
+            @ec[:image]=@ec[:image].sort
+          end
+          @ec[:audio]=@ec[:audio].uniq.flatten.sort
+          @ec[:multimedia]=@ec[:multimedia].uniq.flatten.sort
+          unless @rights
+            if defined? @creator.author \
+            and @creator.author.is_a?(String) \
+            and defined? @date.published \
+            and @date.published.is_a?(String)
+              @rights=SiSU_Param::Parameters::MdDefault.new.rights(@creator.author,@date.published)
+            elsif defined? @creator.author \
+            and @creator.author.is_a?(String)
+              @rights=SiSU_Param::Parameters::MdDefault.new.rights("[#{@creator.author}]",'')
+            end
+          end
+          if defined? @classify.topic_register \
+          and @classify.topic_register.is_a?(String) \
+          and @classify.topic_register.length >3
+             topic_register=@classify.topic_register
+             u=topic_register.scan(/[^;]+/m).sort
+             v=[]
+             u.each do |l|
+               v << l.scan(/[^:]+/m)
+             end
+             v.each do |s|
+               s[-1]=s[-1].scan(/[^|]+/m) if s[-1] =~/[|]/m
+               @topic_register_array << s
+             end
+             @topic_register_array
+          end
+          if @i18n
+            @i18n=@i18n.uniq
+            @i18n << 'en' unless @i18n.find_index("en")
+          else
+            @i18n=[ 'en' ]
+          end
+          translated=[]
+          translate_list=[@pagenew,@pagebreak,@pageline,@num_top,@toc_lev_limit]
+          translate_list.each do |t|
+            translate=t.to_s if t
+            translated << if translate
+              translate.gsub!(/3/,'6')
+              translate.gsub!(/2/,'5')
+              translate.gsub!(/1/,'4')
+              translate.gsub!(/:?C/,'3')
+              translate.gsub!(/:?B/,'2')
+              translate.gsub!(/:?A/,'1')
+              # looks like an ok substituion for the above but is not, causes problems, check why
+              #translate=translate.gsub(/3/,'6').
+              #  gsub(/2/,'5').
+              #  gsub(/1/,'4').
+              #  gsub(/:?C/,'3').
+              #  gsub(/:?B/,'2').
+              #  gsub(/:?A/,'1')
+              translate=(translate =~/^\d+$/) \
+              ? translate.to_i
+              : translate
+            else nil
+            end
+          end
+          @pagenew,@pagebreak,@pageline,@num_top,@toc_lev_limit=translated
+          @markup=@markup.gsub(/page_new\s*=\s*([\dA-C])/,"page_new=#{@pagenew}").
+            gsub(/page_break\s*=\s*([\dA-C])/,"page_break=#{@pagebreak}").
+            gsub(/page_line\s*=\s*([\dA-C])/,"page_line=#{@pageline}").
+            gsub(/num_top\s*=\s*([\dA-C])/,"num_top=#{@num_top}").
+            gsub(/toc_lev_limit\s*=\s*([\dA-C])/,"toc_lev_limit=#{@toc_lev_limit}")
+          papersize_array_rc=@papersize.downcase.scan(/(?:a4|letter|legal|book|a5|b5)/)
+          papersize_array_opt=[
+            ((@opt.act[:pdf_a4][:set]==:on)     ? 'a4'     : ''),
+            ((@opt.act[:pdf_a5][:set]==:on)     ? 'a5'     : ''),
+            ((@opt.act[:pdf_b5][:set]==:on)     ? 'b5'     : ''),
+            ((@opt.act[:pdf_letter][:set]==:on) ? 'letter' : ''),
+            ((@opt.act[:pdf_legal][:set]==:on)  ? 'legal'  : ''),
+          ] - [""]
+          @papersize_array=(papersize_array_opt.length > 0) \
+          ? papersize_array_opt
+          : papersize_array_rc
+          fn=@opt.fno #decide what to do a filesize on .ssm tells very little about actual document size
+          @filesize=(File.size(fn)).to_s
+          if @sys.openssl !=false \
+          and FileTest.file?(@env.source_file_with_path)
+            @dgst=[]
+            case @env.digest(@opt).type
+            when :sha512
+              dgst=@sys.sha512(@env.source_file_with_path)
+              @dgst=dgst[1].length==128 ? dgst : nil
+              puts 'check document (sha512) digest' if not @dgst
+            when :sha256
+              dgst=@sys.sha256(@env.source_file_with_path)
+              @dgst=dgst[1].length==64 ? dgst : nil
+              puts 'check document (sha256) digest' if not @dgst
+            when :md5
+              dgst=@sys.md5(@env.source_file_with_path)
+              @dgst=dgst[1].length==32 ? dgst : nil
+              puts 'check document (md5) digest' if not @dgst
+            else
+              dgst=@sys.sha256(@env.source_file_with_path)
+              @dgst=dgst[1].length==64 ? dgst : nil
+              puts 'check document (sha256) digest' if not @dgst
+            end
+          elsif not FileTest.file?(@env.source_file_with_path)
+            #puts SiSU_Utils::CodeMarker.new(__LINE__,__FILE__).set(:fuchsia)
+          end
+          @publisher ||= "#{@@publisher} (this copy)"
+          fn_set_lang=SiSU_Env::StandardiseLanguage.new(@opt.lng).language
+          unless @language[:code] \
+          and @language[:name]
+            lang=@env.i18n.language #default language settings for directory by name, or in sysrc.yml
+            @language[:code] ||= lang.code
+            @language[:name] ||= lang.title
+          end
+          unless fn_set_lang[:d]==true #decide, naming convention overrides other settings, within document, etc.
+            @language[:code]=fn_set_lang[:c]
+            @language[:name]=fn_set_lang[:n]
+          end
+          @fnl=@env.i18n.lang_filename(fn_set_lang[:c])
+          @lang=@lang.uniq
+          @fn=SiSU_Env::EnvCall.new(@fns).lang(fn_set_lang[:c])
+          if @en[:note] > 0 \
+          and @en[:sum] > 0
+            if @en[:sum] > 0
+            else
+              SiSU_Screen::Ansi.new(
+                @opt.act[:color_state][:set],
+                '*WARN* both endnote styles used',
+                "~{ #{@en[:sum]} }~ and ^~ #{@en[:mark]}"
+              ).warn unless @opt.act[:quiet][:set]==:on
+            end
+          end
+          if @en[:mark] != @en[:note] \
+          and @en[:note] > 0
+            @en[:mismatch]=@en[:note] - @en[:mark]
+            SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              '*WARN* endnote number mismatch',
+              "endnotes: #{@en[:note]} != endnote reference marks: #{@en[:mark]} " \
+              + "(difference = #{@en[:mismatch]})"
+            ).warn unless @opt.act[:quiet][:set]==:on
+            footnote_conversion_errors=File.new("#{Dir.pwd}/footnote_conversion_errors.txt",'a')
+            footnote_conversion_errors <<
+              "#{@fns}:\n\tendnotes: #{@en[:note]} != endnote reference marks: #{@en[:mark]} " \
+              + "(difference = #{@en[:mismatch]})\n"
+          end
+          if not @title \
+          or not defined? @title.main \
+          or @title.main !~/[\S]/
+            if @fns =~/\.ssm$/ \
+            and  @opt.inspect =~/P/
+              #@title=Md.new('Text Insert',@opt,@env).title
+            else
+              SiSU_Screen::Ansi.new(
+                @opt.act[:color_state][:set],
+                'WARNING: Document Title missing',
+                'please provide @title:'
+              ).warn if (@opt.act[:verbose][:set]==:on \
+                || @opt.act[:verbose_plus][:set]==:on \
+                || @opt.act[:maintenance][:set]==:on)
+            end
+          end
+          if @author !~/[\S]/
+            if @fns =~/\.ssm$/ \
+            and  @opt.inspect =~/P/
+              #@creator=SiSU_Param::Md.new('Text Insert',@opt,@env).creator
+            else
+              SiSU_Screen::Ansi.new(
+                @opt.act[:color_state][:set],
+                'WARNING: Document Author missing',
+                'please provide @creator: :author:'
+              ).warn if (@opt.act[:verbose][:set]==:on \
+                || @opt.act[:verbose_plus][:set]==:on \
+                || @opt.act[:maintenance][:set]==:on)
+            end
+          end
+          @struct={}
+          doc_struct=Hash.new(0)
+          if @lv1.nil?
+            fns_array.each do |para|
+              if para =~/^(Part|Chapter|Section|Article)\b/i
+                case para
+                when /^(Part|PART)\b/
+                  @struct[:part]=doc_struct[:part]
+                  doc_struct[:part]=doc_struct[:part] + 1
+                when /^(Chapter|CHAPTER)\b/
+                  @struct[:chapter]=doc_struct[:chapter]
+                  doc_struct[:chapter]=doc_struct[:chapter] + 1
+                when /^(Section|SECTION)\b/
+                  @struct[:section]=doc_struct[:section]
+                  doc_struct[:section]=doc_struct[:section] + 1
+                when /^(Article|ARTICLE)\b/
+                  @struct[:article]=doc_struct[:article]
+                  doc_struct[:article]=doc_struct[:article] + 1
+                when /^(Clause|CLAUSE)\b/
+                  @struct[:clause]=doc_struct[:clause]
+                  doc_struct[:clause]=doc_struct[:clause] + 1
+                when /^\d\..*[^\.]$/
+                  @struct[:number]=doc_struct[:number]
+                  doc_struct[:number]=doc_struct[:number] + 1
+                end
+              end
+            end
+            if doc_struct[:article] > 2                                            #%~level 4
+              @lv4=/^(?:Article|ARTICLE)\b/
+            elsif doc_struct[:chapter] > 2 \
+            and doc_struct[:article] \
+            and doc_struct[:article] < 3
+              @lv4=/^(?:Chapter|CHAPTER)\b/
+            elsif doc_struct[:clause] > 2
+              @lv4=/^(?:Clause|CLAUSE)\b/
+            elsif doc_struct[:number] > 2
+              @lv4="^\d\..*[^\.]$"
+            end
+            if doc_struct[:section] > 2                                           #%~level 3
+              @lv3=/^(?:Section|SECTION)\b/
+            end
+            if doc_struct[:chapter] > 2 \
+            and doc_struct[:article] \
+            and doc_struct[:article] > 2
+              @lv2=/^(?:Chapter|CHAPTER)\b/
+            end
+            if doc_struct[:part] > 2 \
+            and @lv[2].nil?
+              @lv2=/^(?:Part|PART)\b/
+            end
+            if doc_struct[:part] > 2 \
+            and @lv[2].inspect !~/Part/ \
+            and @lv[1].nil?
+              @lv1=/^(Part|PART)\b/
+            end
+          end
+          @lnk=@lnk.compact if @lnk
+          @lv0 ||=/^0~/
+          @lv1 ||=/^1~/
+          @lv2 ||=/^2~/
+          @lv3 ||=/^3~/
+          @lv4 ||=/^4~/
+          @lv5 ||=/^5~/
+          @lv6 ||=/^6~/
+          @data=nil #else whole file's contents are stored in md pstore & is not required to be... big waste actually
+          @file=SiSU_Env::FileOp.new(self) #watch
+          Store.new(self,@env).store                                             #% pstore
+          self
+        rescue
+          if @opt.act[:harvest][:set]==:on
+            exit
+          end
+        end
+      end
+      private
+      class Store
+        def initialize(md,env)
+          @md,@env=md,env
+        end
+        def store
+          begin
+            pstorefile="#{@env.processing_path.ao}/#{@md.fns}.pstore"
+            File.unlink(pstorefile) if FileTest.file?(pstorefile)
+            if (@md.opt.act[:verbose_plus][:set]==:on \
+            || @md.opt.act[:maintenance][:set]==:on)
+              SiSU_Screen::Ansi.new(
+                @md.opt.act[:color_state][:set],
+                "PStore -> #{pstorefile}"
+              ).txt_grey
+            end
+            store=PStore.new(pstorefile)
+            store.transaction do
+              store['md']=@md
+              store.commit
+            end
+            @@md=@md=nil
+          rescue
+            SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+              __LINE__.to_s + ':' + __FILE__
+            end
+          ensure
+          end
+        end
+      end
+    end
+  end
+  class Instantiate
+    def param_instantiate
+      @@date=SiSU_Env::InfoDate.new
+      @doc={
+       initialise: nil,
+       markup: '',
+       lnks: '',
+       stmp: '',
+       prefix_a: '',
+       prefix_b: '',
+       req: {}
+      }
+      @@flag={}
+      @@publisher='SiSU scribe'
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* dp_make.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/dp_make.rb"
+# <<sisu_document_header>>
+module SiSU_Param_Make
+  class MdMake
+    def initialize(str,opt,env)
+      @s,@opt,@env=str,opt,env
+    end
+    def validate_length(s,l,n)
+      #s=(s.length <= l) ? s : nil
+      s=if s.is_a?(String) \
+      and s.length <= l
+        s
+      elsif s.is_a?(NilClass)
+        nil
+      elsif s.class !=String
+        STDERR.puts "#{n} is #{s.class}: programming error, String expected #{__FILE__}:#{__LINE__}"
+        s
+      else
+        SiSU_Screen::Ansi.new(
+          'v',
+          "*WARN* #{n} length #{s.length} exceeds set db field length #{l}, metadata dropped",
+          @opt.fns
+        ).warn unless @opt.act[:quiet][:set]==:on
+        nil
+      end
+    end
+    def name_format(name)
+      if name
+        name=name.strip
+        @name_a_h=[]
+        authors=name.scan(/[^;]+/)
+        authors.each_with_index do |a,i|
+          b=((a =~/\s*\|\s*/) ? (a.split(/\|/)) : [a])
+          if b[0] =~/"(.+?)"/
+            @name_a_h << { the: $1 }
+          else
+            x=b[0].scan(/[^,]+/)
+            if x.length==1
+              @name_a_h << { the: x[0].strip }
+            elsif x.length==2
+              @name_a_h << { the: x[0].strip, others: x[1].strip }
+            else #p x.length
+            end
+          end
+          b.delete_at(0)
+          b.each do |d|
+            k,c=nil
+            k,c=/^(\S+)\s+(.*)/.match(d)[1,2] if d
+            @name_a_h[i][:hon]=c.strip if k=='hon'
+            @name_a_h[i][:affiliation]=c.strip if k=='affiliation'
+            @name_a_h[i][:nationality]=c.strip if k=='nationality'
+          end
+        end
+        l=@name_a_h.length
+        name_str=''
+        @name_a_h.each_with_index do |a,i|
+          name_str += if a[:others]
+            z=(((l - i) > 1) ? ', ' : '')
+            "#{a[:others].strip} #{a[:the].strip}" + z
+          else
+            z=(((l - i) > 2) ? ', ' : '')
+            "#{a[:the].strip}" + z
+          end
+        end
+        { name_a_h: @name_a_h, name_str: name_str }
+      else nil
+      end
+    end
+    def build_hash(arr)
+      @h={}
+      arr.each_with_index do |x,i|
+        a,b=nil,nil
+        if x =~/^%[:\s]/ #ignore comment
+        elsif x =~/:(\S+?):\s+(.+)/
+          a,b=/:(\S+?):\s+(.+)\Z/m.match(x)[1,2]
+        elsif i == 0
+          a='main'
+          b=x
+        else
+        end
+        @h[a]=b
+      end
+      @h
+    end
+    def make
+      a=@s.split(/\n%\s.+?$|[ ]*\n[ ]*/m)
+      @h=build_hash(a)
+      def headings
+        lv=[]
+        x=@h['headings']
+        x=((x =~/;/) ? (x.split(/;\s*/)) : [ x ])
+        lv[0]=x
+        lv0 ||='A~ '             #root level, single document apex, document title
+        lv1=x[0] ||='B~ '
+        lv[1]=/^#{lv1}/
+        lv2=x[1] ||='C~ '
+        lv[2]=/^#{lv2}/
+        lv3=x[2] ||='D~ '
+        lv[3]=/^#{lv3}/
+        lv4=x[3] ||='1~ '
+        lv[4]=/^#{lv4}/
+        lv5=x[4] ||='2~ '
+        lv[5]=/^#{lv5}/
+        lv6=x[5] ||='3~ '
+        lv[6]=/^#{lv6}/
+        lv
+      end
+      def num_top
+        @h['num_top']
+      end
+      def breaks
+        pagebreaks=((@h['breaks'] =~/;/) \
+        ? (@h['breaks'].split(/;\s*/))
+        : [ @h['breaks'] ])
+        page_new,page_break,page_line=nil,nil,nil
+        pagebreaks.each do |x|
+          page_new=x[/(:?[\dA-C],?)+/] if x=~/new|clear/
+          page_break=x[/(:?[\dA-C],?)+/] if x =~/break/
+          page_line=x[/(:?[\dA-C],?)+/] if x =~/line/
+        end
+        { page_new: page_new, page_break: page_break, page_line: page_line }
+      end
+      def language
+        if @h['language'] && (@h['language']=~/\S{2,}/)
+          ((@h['language'] =~/,/) \
+          ? (@h['language'].split(/,\s*/))
+          : [ @h['language'] ])
+        else [ 'en' ]
+        end
+      end
+      def bold
+        m=@h['bold']
+        i=(m=~/\/i$/)? 'i' : ''
+        if m
+          x=m.gsub(/^\/(.+?)\/i?/,'\1').
+            gsub(/\((?:\?:)?/,'(?:')                                         # avoid need to escape use of brackets within regex provided
+          rgx='\b(' + x + ')\b'
+          y=((i =~/i/) ? (/#{rgx}/i) : (/#{rgx}/))
+          { str: '\b(?:' + x + ')\b', regx: y, i: i }
+        else nil
+        end
+      end
+      def italics
+        m=@h['italics']
+        i=((m=~/\/i$/) ? 'i' : '')
+        if m
+          x=m.gsub(/^\/(.+?)\/i?/,'\1').
+            gsub(/\((?:\?:)?/,'(?:')                                         # avoid need to escape use of brackets within regex provided
+          rgx='\b(' + x + ')\b'
+          y=((i =~/i/) ? (/#{rgx}/i) : (/#{rgx}/))
+          { str: '\b(?:' + x + ')\b', regx: y, i: i }
+        else nil
+        end
+      end
+      def emphasis
+        if @h['emphasis'] =~/bold/                   then 'bold'
+        elsif @h['emphasis'] =~/italics?/            then 'italics'
+        elsif @h['emphasis'] =~/under(?:line|score)/ then 'underscore'
+        else nil
+        end
+      end
+      def substitute
+        m=@h['substitute']
+        if m
+          w=m.scan(/\/(.+?)\/(i?,)\s*'(.+?)'(?:\s+|\s*;\s*|$)/)
+          arr_hash=[]
+          matches=''
+          w.each do |x|
+            c=(x[1] =~/[i],/) ? :i : :s
+            matches=matches + x[0].gsub(/([${}])/,'\\\\\1') + '|'
+            arr_hash << {
+              match: x[0].gsub(/([${}])/,'\\\\\1'),
+              replace: x[2],
+              case_s: c
+            }
+          end
+          matches.chop!
+          { match_and_replace: arr_hash, matches: matches }
+        else nil
+        end
+      end
+      def plaintext_wrap
+        if @h['plaintext_wrap'].to_s =~/\d\d+/ \
+        and @h['plaintext_wrap'].to_i > 19 \
+        and @h['plaintext_wrap'].to_i < 201
+          @h['plaintext_wrap'].to_i
+        else nil
+        end
+      end
+      def omit
+        m=@h['omit']
+        @m=m ? (m.split(/,\s+/)) : nil
+        def list
+          @m
+        end
+        self
+      end
+      def ocn?
+        (omit.list.inspect =~/"ocn"/) \
+        ? :off
+        : :na
+      end
+      def toc?
+        (omit.list.inspect =~/"toc"/) \
+        ? :off
+        : :na
+      end
+      def manifest?
+        (omit.list.inspect =~/"manifest"/) \
+        ? :off
+        : :na
+      end
+      def links_to_manifest?
+        (omit.list.inspect =~/"manifest_links"|"links_to_manifest"/) \
+        ? :off
+        : :na
+      end
+      def metadata?
+        (omit.list.inspect =~/"metadata"/) \
+        ? :off
+        : :na
+      end
+      def minitoc?
+        (omit.list.inspect =~/"minitoc"/) \
+        ? :off
+        : :na
+      end
+      def html_minitoc?
+        (omit.list.inspect =~/"html_minitoc"/) \
+        ? :off
+        : :na
+      end
+      def html_top_band?
+        (omit.list.inspect =~/"html_top_band"/) \
+        ? :off
+        : :na
+      end
+      def html_navigation?
+        (omit.list.inspect =~/"html_navigation"/) \
+        ? :off
+        : :na
+      end
+      def html_navigation_bar?
+        (omit.list.inspect =~/"html_navigation_bar"/) \
+        ? :off
+        : :na
+      end
+      def segsubtoc?
+        (omit.list.inspect =~/"segsubtoc"/) \
+        ? :off
+        : :na
+      end
+      def search_form?
+        (omit.list.inspect =~/"search_form"/) \
+        ? :off
+        : :na
+      end
+      def html_search_form?
+        (omit.list.inspect =~/"html_search_form"/) \
+        ? :off
+        : :na
+      end
+      def html_right_pane?
+        (omit.list.inspect =~/"html_right_column"|"html_right_pane"/) \
+        ? :off
+        : :na
+      end
+      def manifest_minitoc?
+        (omit.list.inspect =~/"manifest_minitoc"/) \
+        ? :off
+        : :na
+      end
+      def cover_image?
+        (omit.list.inspect =~/"cover_image"/) \
+        ? :off
+        : :na
+      end
+      def home_button_image?
+        (omit.list.inspect =~/"home_button_image"/) \
+        ? :off
+        : :na
+      end
+      def texpdf_font
+        def main
+          @h['texpdf_font'] \
+          && (@h['texpdf_font']=~/\S{3,}/) \
+          ? @h['texpdf_font']
+          : @env.font.texpdf.main
+        end
+        def sans                                                             # not used
+          @h['texpdf_font_sans'] \
+          && (@h['texpdf_font_sans']=~/\S{3,}/) \
+          ? @h['texpdf_font_sans']
+          : @env.font.texpdf.sans
+        end
+        def serif                                                            # not used
+          @h['texpdf_font_serif'] \
+          && (@h['texpdf_font_serif']=~/\S{3,}/) \
+          ? @h['texpdf_font_serif']
+          : @env.font.texpdf.serif
+        end
+        def mono
+          @h['texpdf_font_mono'] \
+          && (@h['texpdf_font_mono']=~/\S{3,}/) \
+          ? @h['texpdf_font_mono']
+          : @env.font.texpdf.mono
+        end
+        def cjk
+          @h['texpdf_font_cjk'] \
+          && (@h['texpdf_font_cjk']=~/\S{3,}/) \
+          ? @h['texpdf_font_cjk']
+          : @env.font.texpdf.cjk
+        end
+        def cjk_zh
+          @h['texpdf_font_cjk_zh'] \
+          && (@h['texpdf_font_cjk_zh']=~/\S{3,}/) \
+          ? @h['texpdf_font_cjk_zh']
+          : @env.font.texpdf.cjk_zh
+        end
+        def cjk_ja
+          @h['texpdf_font_cjk_ja'] \
+          && (@h['texpdf_font_cjk_ja']=~/\S{3,}/) \
+          ? @h['texpdf_font_cjk_ja']
+          : @env.font.texpdf.cjk_ja
+        end
+        def cjk_ko
+          @h['texpdf_font_cjk_ko'] \
+          && (@h['texpdf_font_cjk_ko']=~/\S{3,}/) \
+          ? @h['texpdf_font_cjk_ko']
+          : @env.font.texpdf.cjk_ko
+        end
+        self
+      end
+      def promo
+        @h['promo']
+      end
+      def ad
+        @h['ad']
+      end
+      def manpage
+        manpage={}
+        if @h['manpage']
+          if @h['manpage'] =~/;/m
+            man=@h['manpage'].split(/;/m)
+            man.each do |x|
+              m=(x=~/=/m) ? x.split(/=/m) : nil
+              if m
+                manpage[m[0].strip] = m[1].split(/ \. /)
+              end
+            end
+          end
+        end
+        if manpage['name']
+          manpage['name']=manpage['name'].join("\n.br\n").
+            gsub(/(-)/m,"\\\\\\1").
+            gsub(/\A/,"\n.br\n.SH NAME\n.br\n")
+        else
+          manpage['name']='man page "name/whatis" information not provided, set in header @man: name=[whatis information]'
+        end
+        if manpage['synopsis']
+          manpage['synopsis']=manpage['synopsis'].join("\n\n.br\n").
+            gsub(/(-)/m,"\\\\\\1").
+            gsub(/\A/,"\n.br\n.SH SYNOPSIS\n.br\n")
+        else
+          manpage['synopsis']=''
+        end
+        unless manpage['section']
+          manpage['section']=1
+        end
+        manpage
+      end
+      def get_image_dimensions(img)
+        imgk=SiSU_Env::SystemCall.new.imagemagick
+        gmgk=SiSU_Env::SystemCall.new.graphicsmagick
+        img_pth={
+          sst: @env.path.image_source_include,
+          pod: File.expand_path("../../../sisupod/image" )
+        }
+        path_img=if FileTest.file?("#{img_pth[:pod]}/#{img}")
+          "#{img_pth[:pod]}/#{img}"
+        elsif FileTest.file?("#{img_pth[:sst]}/#{img}")
+          "#{img_pth[:sst]}/#{img}"
+        else nil
+        end
+        if path_img
+          if imgk or gmgk
+            if imgk
+              imgsys=`identify #{path_img}`.strip                           #system call
+            elsif gmgk
+              imgsys=`gm identify #{path_img}`.strip                        #system call
+            end
+            w,h=/(\d+)x(\d+)/m.match(imgsys)[1,2]
+          else
+            w,h='600','800'
+          end
+        else
+          w,h=nil,nil
+        end
+        {w: w, h: h}
+      end
+      def home_button_text
+        if @h['home_button_text']
+          @h['home_button_text'].split(/\s*;\s*/)
+        else nil
+        end
+      end
+      def home_button_image
+        s=nil
+        s=if @h['home_button_image']
+          s=@h['home_button_image'].split(/\s*;\s*/)
+          s0=s[0] #if
+          image={}
+          s=if s0 =~/{(\S+\.(?:jpg|png|gif))(?:\s+(\d+x\d+))?\s*}(?:(http:\/\/\S+)|image)/
+            image[:home_button]=$1
+            if $2
+              image[:dimensions]=$2
+              image[:w],image[:h]=/(\d+)x(\d+)/m.match(image[:dimensions])[1,2]
+            else
+              d=get_image_dimensions(image[:home_button])
+              image[:w],image[:h]=d[:w],d[:h]
+              image[:dimensions]="#{d[:w]}x#{d[:h]}"
+            end
+            image[:link]=$3
+            image
+          end
+        else nil
+        end
+      end
+      def cover_image
+        s=nil
+        if @h['cover_image']
+          s=@h['cover_image'].split(/\s*;\s*/)
+          s=s[0] #if
+          image={}
+          if s =~/{\s*(\S+\.(?:jpg|png|gif))(?:\s+(\d+x\d+))?(?:\s+"(.+?)")?\s*}image/
+            image[:cover]=$1
+            if $2
+              image[:dimensions]=$2
+              image[:w],image[:h]=/(\d+)x(\d+)/m.match(image[:dimensions])[1,2]
+            else
+              d=get_image_dimensions(image[:cover])
+              image[:w],image[:h]=d[:w],d[:h]
+              image[:dimensions]="#{d[:w]}x#{d[:h]}"
+            end
+            image[:note]=$3
+          elsif s =~/(\S+\.(?:jpg|png|gif))/
+            image[:cover]=$1
+            d=get_image_dimensions(image[:cover])
+            image[:w],image[:h]=d[:w],d[:h]
+            image[:dimensions]="#{d[:w]}x#{d[:h]}"
+            image[:note]=nil
+          end
+          image
+        else nil
+        end
+      end
+      def footer
+        if @h['footer']
+          @h['footer'].split(/\s*;\s*/)
+        else nil
+        end
+      end
+      self
+    end
+    def make_links
+      @doc_links=@s.split(/\n%\s.+?$|[ ]*\n[ ]*/m)
+      def links
+        lnks,a_idx=[],0
+        @doc_links.each do |doc_link|
+          if doc_link=~/\{.+?\}(?:(?:https?|file|ftp):\/|\.\.)\/\S+(?:\s|$)/
+            say,url=/\{\s*(.+?)\s*\}((?:(?:https?|file|ftp):\/|\.\.)\/\S+)/im.match(doc_link)[1,2]
+            lnks[a_idx]={ say: say, url: url  }
+            a_idx +=1
+          end
+        end
+        lnks
+      end
+      def append?
+        (@doc_links[0]=='+') \
+          ? :yes
+          : :no
+      end
+      self
+    end
+  end
+  class MakeHead
+    attr_accessor :pagenew,:pagebreak,:pageline,:toc,:lv1,:lv2,:lv3,:lv4,:lv5,:lv6,:num_top,:i18n,:man_section,:substitution_match_list,:bold_match_list,:italics_match_list,:emphasis_set_to,:footer_links,:home_button_links,:home_button_image,:cover_image
+    def initialize(make)
+      @make=make
+    end
+    def clear
+      @pagenew=@pagebreak=@pageline=@toc=@lv1=@lv2=@lv3=@lv4=@lv5=@lv6=@num_top=@i18n=@man_section=@footer_links=@substitution_match_list=@bold_match_list=@italics_match_list=@emphasis_set_to=@home_button_links=@home_button_image=@cover_image=nil
+    end
+    def make_instruct
+      clear
+      if defined? @make.breaks \
+      and @make.breaks[:page_new]                  #clearpage
+        @pagenew=@make.breaks[:page_new]
+      end
+      if defined? @make.breaks \
+      and @make.breaks[:page_break]                #newpage
+        @pagebreak=@make.breaks[:page_break]
+      end
+      if defined? @make.breaks \
+      and @make.breaks[:page_line]                 #page line across
+        @pagebreak=@make.breaks[:page_line]
+      end
+      if defined? @make.headings \
+      and @make.headings
+        @toc=@make.headings[0]
+        @lv1=@make.headings[1]
+        @lv2=@make.headings[2]
+        @lv3=@make.headings[3]
+        @lv4=@make.headings[4]
+        @lv5=@make.headings[5]
+        @lv6=@make.headings[6]
+      end
+      if defined? @make.num_top \
+      and @make.num_top
+        @num_top=@make.num_top # remove @num_top
+      end
+      if defined? @make.language \
+      and @make.language[0]
+        @i18n=@make.language
+      end
+      if defined? @make.manpage \
+      and @make.manpage
+        @man_section=(defined? @make.manpage.section) \
+        ? @make.manpage.section
+        : 1
+      end
+      if defined? @make.substitute \
+      and @make.substitute
+        @substitution_match_list=@make.substitute
+      end
+      if defined? @make.bold \
+      and @make.bold
+        @bold_match_list=@make.bold
+      end
+      if defined? @make.italics \
+      and @make.italics
+        @italics_match_list=@make.italics
+      end
+      if defined? @make.emphasis \
+      and @make.emphasis
+        @emphasis_set_to=@make.emphasis
+      end
+      if defined? @make.footer \
+      and @make.footer.is_a?(Array)
+        @footer_links= { left: { say: '', url: '' }, center: { say: '', url: '' } } #already set
+        @footer_links[:left]=if @make.footer[0]=~/\{.+?\}(?:(?:https?|file|ftp):\/|\.\.)\/\S+(?:\s|$)/
+          say,url=/\{\s*(.+?)\s*\}((?:(?:https?|file|ftp):\/|\.\.)\/\S+)/im.match(@make.footer[0])[1,2]
+          { say: say, url: url }
+        else
+          { say: '', url: '' }
+        end
+        @footer_links[:center]=if @make.footer[1]=~/\{.+?\}(?:(?:https?|file|ftp):\/|\.\.)\/\S+(?:\s|$)/
+          say,url=/\{\s*(.+?)\s*\}((?:(?:https?|file|ftp):\/|\.\.)\/\S+)/im.match(@make.footer[1])[1,2]
+          { say: say, url: url }
+        else
+          { say: '', url: '' }
+        end
+        @footer_links
+      else #already set
+        @footer_links= { left: { say: '', url: '' }, center: { say: '', url: '' } }
+      end
+      if defined? @make.home_button_text \
+      and @make.home_button_text.is_a?(Array)
+        a_idx=0
+        @home_button_links=[]
+        @make.home_button_text.each do |doc_link|
+          if doc_link=~/\{.+?\}(?:(?:https?|file|ftp):\/|\.\.)\/\S+(?:\s|$)/
+            say,url=/\{\s*(.+?)\s*\}((?:(?:https?|file|ftp):\/|\.\.)\/\S+)/im.match(doc_link)[1,2]
+            @home_button_links[a_idx]= { say: say, url: url }
+            a_idx +=1
+          end
+        end
+        @home_button_links
+      end
+      if defined? @make.home_button_image \
+      and @make.home_button_image.is_a?(Hash)
+        @home_button_image=@make.home_button_image
+      end
+      if defined? @make.cover_image \
+      and @make.cover_image.is_a?(Hash)
+        @cover_image=@make.cover_image
+      end
+      { pagenew: @pagenew,
+        pagebreak: @pagebreak,
+        pageline: @pageline,
+        toc: @toc,
+        lv1: @lv1,
+        lv2: @lv2,
+        lv3: @lv3,
+        lv4: @lv4,
+        lv5: @lv5,
+        lv6: @lv6,
+        num_top: @num_top,
+        i18n: @i18n,
+        emphasis_set_to: @emphasis_set_to,
+        bold_match_list: @bold_match_list,
+        italics_match_list: @italics_match_list,
+        substitution_match_list: @substitution_match_list,
+        man_section: @man_section,
+        footer_links: @footer_links,
+        home_button_links: @home_button_links,
+        home_button_image: @home_button_image,
+        cover_image: @cover_image,
+      }
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* dp_identify_markup.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/dp_identify_markup.rb"
+# <<sisu_document_header>>
+module SiSU_MarkupType
+  class MarkupIdentify
+    @@version={}
+    @@fns,@@version[:determined],@@version[:declared],@@declared_doc_type='','','','[text?]'
+    attr_accessor :version,:declared_doc_type
+    def initialize(content,opt)
+      @cont,@opt=content,opt
+    end
+    def identify
+      @version,@declared_doc_type=@@version,@@declared_doc_type
+      if @opt.fns != @@fns
+        if @cont[0] =~ /^(?:%\s+)?SiSU\s+(text|master|insert)\s+([0-9](?:\.[0-9]+){1,2})/ \
+        or @cont[0] =~ /^(?:%\s+)?sisu-([0-9](?:\.[0-9]+){1,2})/
+          @declared_doc_type,@version[:declared]=$1,$2
+        elsif @cont[0] =~ /^(?:%\s+)?SiSU\s+([0-9](?:\.[0-9]+){1,2})/ \
+        or @cont[0] =~ /^(?:%\s+)?sisu-([0-9](?:\.[0-9]+){1,2})/
+          @version[:declared]=$1
+        end
+        @flag_2_0,@flag_66,@flag_57,@flag_38=false,false,false,false
+        @cont.each_with_index do |y,i|
+          if y =~/^@make:|^@classify|^\s\s?:\S+?:\s+\S/
+            version=2.0.to_f
+            @version[:determined]=version
+            @flag_2_0=true
+            break
+          end
+          unless @flag_38
+            if y =~/^:?A~/
+              version=0.38.to_f
+              @version[:determined]=version
+              @flag_38=true
+            end
+          end
+          if @flag_38
+            if @flag_69 \
+            or y =~/^=\{.+?\}\s*$/
+              version=0.69.to_f
+              @flag_69=true
+              @version[:determined]=version
+              break
+            end
+            if @flag_66 \
+            or y =~/[:;]\{.+?\}[:;][a-z+]/
+              version=0.66.to_f
+              @flag_66=true
+              @version[:determined]=version
+              break
+            end
+          end
+        end
+        @flag_57,@flag_38=false,false
+        unless @flag_2_0 \
+        or @flag_66 \
+        or @flag_69
+          @cont.each_with_index do |y,i|
+            if @flag_57 \
+            or y =~/^:?A~\?? @title/
+              @version[:determined]=0.57.to_f
+              @flag_57=true
+              break
+            end
+            if @flag_38 \
+            or y =~/^:?A~/
+              @version[:determined]=0.38.to_f
+              @flag_38=true
+              break if i >= 200
+              if y =~ /(?:~{\*+|~\[\*|~\[\+)\s/
+                @version[:determined]=0.42 #0.38 can safely be treated as 0.42
+                break
+              end
+            end
+            if y =~/^0~/ \
+            and not @flag_38
+              @version[:determined]=0.16.to_f
+              break
+            end
+          end
+        end
+        @@fns=@opt.fns
+        @@version,@@declared_doc_type=@version,@declared_doc_type
+      end
+      self
+    end
+    def markup_version?
+      def determined
+        identify.version[:determined].to_f
+      end
+      def series
+        s=case identify.version[:determined].to_s
+        when /^[01]\./ then '1.0'
+        when /^[2]\./  then '2.0'
+        else '2.0'
+        end
+        "series #{s}"
+      end
+      def declared
+        identify.version[:declared].to_f
+      end
+      self
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    param
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/shared.org b/org/shared.org
new file mode 100644
index 00000000..66df485d
--- /dev/null
+++ b/org/shared.org
@@ -0,0 +1,2297 @@
+-*- mode: org -*-
+#+TITLE:       sisu shared
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:shared:
+#+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
+
+* shared
+** shared_sem.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/shared_sem.rb"
+# <<sisu_document_header>>
+module SiSU_Sem
+  require_relative 'dp'                                 # dp.rb
+  class Tags
+    def initialize(para,md)
+      @para,@md=para,md
+    end
+    def rgx
+      def exclude
+        /^(?:<:code>|%+ )/
+      end
+      def each_csc
+        /(?:;|(?:[a-z]+(?:[_:.][a-z]+)+|[a-z]*):)\{|\}[:;][a-z]+(?:[_:.][a-z]+)*/m
+      end
+      def each_c
+        /(?:[a-z]+(?:[_:.][a-z]+)+|[a-z]*):\{|\}:[a-z]+(?:[_:.][a-z]+)*/m
+      end
+      def each_sc
+        /(?:[a-z]+(?:[_:.][a-z]+)+|[a-z]*);\{|\};[a-z]+(?:[_:.][a-z]+)*/m
+      end
+      def pair_csc
+        /(([a-z]+(?:[_:.][a-z]+)+|[a-z]+)(?::\{(.+?)\}:\2)|([:;])\{(.+?)\}\4[a-z]+(?:[_:.][a-z]+)*)/m
+      end
+      def pair_c
+        /(([a-z]+(?:[_:.][a-z]+)*)(?::\{(.+?)\}:\2)|:\{(.+?)\}:[a-z]+(?:[_:.][a-z]+)*)/m
+      end
+      def pair_sc
+        /(;\{.+?\};[a-z]+(?:[_:.][a-z]+)*)/m
+      end
+      def whole_csc_ae
+        /(([a-z]+(?:[_.][a-z]+)+|[a-z]*)(?::\[(.+?)\]:\2)|;\{(.+?)\};(?:[a-z]+(?:[_:.][a-z]+)+|[a-z]+)\b)/m
+      end
+      def each_csc_ae
+        /(?:;|(?:[a-z]+(?:[_:.][a-z]+)+)*:|[a-z]*:)\[|\][:;](?:[a-z]+(?:[_:.][a-z]+)+|[a-z]+)/m
+      end
+      self
+    end
+    def print
+      def scan_pair_c
+        if @para =~ rgx.pair_c
+          matched=@para.scan(rgx.pair_c).flatten
+          puts matched[0] unless matched[0].nil?
+        end
+      end
+      def scan_pair_sc
+        matched=@para.scan(rgx.pair_sc).flatten
+        puts matched[0] unless matched[0].nil?
+      end
+      def if_pair_c
+        if @para=~/([a-z](?:[a-z_:.]+?[a-z])?)+(?::\{(.+?)\}:\1)/m
+          puts "#{$1}:{ #{$2} }:#{$1}"
+        end
+      end
+      def if_pair_sc
+        if @para=~/;\{\s*(.+?)\s*\};([a-z]+(?:[_:.][a-z]+)*)/
+          puts ";{ #{$1} };#{$2}"
+        end
+      end
+      def match_pair_c
+        matched=[]
+        matched=rgx.pair_c.match(@para)[1] if @para =~ rgx.pair_c
+        puts matched unless matched.nil?
+      end
+      def match_pair_sc
+        matched=[]
+        matched=rgx.pair_sc.match(@para)[1] if @para =~ rgx.pair_sc
+        puts matched unless matched.nil?
+      end
+      def matching
+        scan_pair_c
+      end
+      self
+    end
+    def rm
+      def sem_marker_parts
+        unless @para =~ rgx.exclude
+          @para.gsub!(rgx.each_csc,'')
+        end
+        @para
+      end
+      def sem_marker_added_extra_parts
+        unless @para =~ rgx.exclude
+          @para.gsub!(rgx.whole_csc_ae,'')
+          if @para =~rgx.each_csc_ae
+            STDERR.puts "WARNING semantic tagging error: #{@para}"
+          end
+        end
+        @para
+      end
+      def all
+        if @md.sem_tag
+          sem_marker_parts
+          sem_marker_added_extra_parts
+        end
+        @para
+      end
+      self
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** shared_images.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/shared_images.rb"
+# <<sisu_document_header>>
+module SiSU_Images
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+  class Source
+    def initialize(opt)
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+    end
+    def read
+      SiSU_Images::Source::Place.new(@particulars).songsheet
+    end
+    class Place
+      def initialize(particulars)
+        @particulars=particulars
+        @md=@particulars.md
+        @env=@particulars.env
+        @o_str ||=SiSU_Env::ProcessingSettings.new(@md).output_dir_structure
+      end
+      def songsheet
+        images_set.select_sisu_base
+        images_set.select_with_document
+      end
+      def images_set
+        @pwd=(/(\S+?)(?:\/(?:#{Px[:lng_lst_rgx]}))?$/).match(Dir.pwd)[1]
+        def copy(src_path,dest_path,images=nil)
+          if FileTest.directory?(src_path)
+            FileUtils::cd(src_path)
+            unless images
+              images=Dir.glob("*.{png,jpg,gif,ico}")
+            end
+            unless FileTest.directory?(dest_path) \
+            or FileTest.symlink?(dest_path)
+              FileUtils::mkdir_p(dest_path)
+              FileUtils::chmod(0755,dest_path)
+            end
+            if images.length > 0
+              images.each do |i|
+                if FileTest.file?(i)
+                  FileUtils::cp_r(i,"#{dest_path}/#{i}")
+                  FileUtils::chmod(0644,"#{dest_path}/#{i}")
+                else STDERR.puts %{\t*WARN* did not find image - "#{i}" [#{__FILE__}:#{__LINE__}]}
+                end
+              end
+            end
+            FileUtils::cd(@pwd)
+          else STDERR.puts %{\t*WARN* did not find - "#{src_path}" [#{__FILE__}:#{__LINE__}]}
+          end
+        end
+        def dest_path(image_type)
+          pth=if image_type==:image_sys
+            pth=(@o_str.dump_or_redirect?) \
+            ? "#{@md.file.output_path.html.dir}/image"
+            : "#{@md.file.output_path.base.dir}/_sisu/image_sys"
+          elsif image_type==:image
+            pth=(@o_str.dump_or_redirect?) \
+            ? "#{@md.file.output_path.html.dir}/image"
+            : "#{@md.file.output_path.base.dir}/_sisu/image"
+          end
+          pth
+        end
+        def select_with_document
+          images=@md.ec[:image]
+          src_path=unless @md.opt.f_pth[:pth] =~/\/\S+?\/sisupod\/\S+?\/sisupod\/doc/
+            "#{@pwd}/_sisu/image"
+          else #sisupod
+            pt=/(\/\S+?\/sisupod\/\S+?\/sisupod)\/doc/.match(@md.opt.f_pth[:pth])[1]
+            pt + '/image'
+          end
+          dest=dest_path(:image)
+          copy(src_path,dest,images)
+        end
+        def select_sisu_base
+          images=%w[arrow_next_red.png arrow_prev_red.png arrow_up_red.png dot_clear.png dot_white.png b_doc.png b_epub.png b_odf.png b_pdf.png b_toc.png]
+          src_path="#{SiSU_is.path_base_system_data?}/image"
+          dest=dest_path(:image_sys)
+          copy(src_path,dest,images)
+        end
+        self
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** shared_markup_alt.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/shared_markup_alt.rb"
+# <<sisu_document_header>>
+module SiSU_TextRepresentation
+  class Alter
+    def initialize(x)
+      if x.is_a?(String)
+        @t_o,@s=nil,x
+      else
+        @t_o,@s=x,x.obj.dup
+      end
+    end
+    def strip_clean_of_extra_spaces                                              # dal output tuned
+      @s=@s.dup
+      @s=@s.gsub(/[ ]+([,.;:?](?:$|\s))/,'\1') unless @s =~/#{Mx[:en_a_o]}|#{Mx[:en_b_o]}/
+      @s=@s.gsub(/ [ ]+/,' ').
+        gsub(/^ [ ]+/,'').
+        gsub(/ [ ]+$/,'').
+        gsub(/((?:#{Mx[:fa_bold_c]}|#{Mx[:fa_italics_c]})')[ ]+(s )/,'\1\2').
+        gsub(/((?:#{Mx[:fa_bold_c]}|#{Mx[:fa_italics_c]})')[ ]+(s )/,'\1\2')
+    end
+    def strip_clean_of_markup                                                  # text form used in sql db search, used for digest, define rules, make same as in db clean
+      @s=@s.dup                                                                  #% same as db clean -->
+      @s=@s.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'\1').
+        gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'\1').
+        gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'\1').
+        gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'\1').
+        gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'\1').
+        gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'\1').
+        gsub(/#{Mx[:fa_superscript_o]}(\d+)#{Mx[:fa_superscript_c]}/,'[\1]').
+        gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'\1').
+        gsub(/#{Mx[:fa_hilite_o]}(.+?)#{Mx[:fa_hilite_c]}/,'\1').
+        gsub(/#{Mx[:gl_o]}#(?:126|152)#{Mx[:gl_c]}/i,'~').
+        gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,''). # endnote removed
+        gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,''). # endnote removed
+        gsub(/(?:#{Mx[:nbsp]})+/,' ').
+        gsub(/(?:#{Mx[:br_nl]})+/,"\n").
+        gsub(/(?:#{Mx[:br_paragraph]})+/,"\n").
+        gsub(/(?:#{Mx[:br_line]})+/,"\n").
+        gsub(/#{Mx[:gl_o]}(?:#lt|#060)#{Mx[:gl_c]}/,'<').
+        gsub(/#{Mx[:gl_o]}(?:#gt|#062)#{Mx[:gl_c]}/,'>').
+        gsub(/#{Mx[:gl_o]}#(?:038|amp)#{Mx[:gl_c]}/,'&').
+        gsub(/#{Mx[:gl_o]}#033#{Mx[:gl_c]}/,'!').
+        gsub(/#{Mx[:gl_o]}#035#{Mx[:gl_c]}/,'#').
+        gsub(/#{Mx[:gl_o]}#042#{Mx[:gl_c]}/,'*').
+        gsub(/#{Mx[:gl_o]}#045#{Mx[:gl_c]}/,'-').
+        gsub(/#{Mx[:gl_o]}#047#{Mx[:gl_c]}/,'/').
+        gsub(/#{Mx[:gl_o]}#095#{Mx[:gl_c]}/,'_').
+        gsub(/#{Mx[:gl_o]}#123#{Mx[:gl_c]}/,'{').
+        gsub(/#{Mx[:gl_o]}#125#{Mx[:gl_c]}/,'}').
+        gsub(/#{Mx[:gl_o]}#126#{Mx[:gl_c]}/,'~').
+        gsub(/#{Mx[:gl_o]}#169#{Mx[:gl_c]}/,'©').
+        gsub(/\s\s+/,' ').
+        gsub(/\s\s+/,' ').
+        strip
+    end
+    def semi_revert_markup                                             # used for digest, define rules, make same as in db clean
+      if @t_o
+        @s=@s.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'*{\1}*').
+          gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'/{\1}/').
+          gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'_{\1}_').
+          gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'"{\1}"').
+          gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'+{\1}+').
+          gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strke_c]}/,'-{\1}-').
+          gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'^{\1}^').
+          gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,',{\1},').
+          gsub(/#{Mx[:gl_o]}#(?:126|152)#{Mx[:gl_c]}/i,'~').
+          gsub(/#{Mx[:en_a_o]}([\d*+]+\s+.+?)#{Mx[:en_a_c]}/,'~{\1}~'). # endnote marker marked up
+          gsub(/#{Mx[:en_b_o]}([\d*+]+\s+.+?)#{Mx[:en_b_c]}/,'~[\1]~') # endnote marker marked up
+        if @t_o.is==:heading \
+        || @t_o.is==:para
+          @s=@s.gsub(/ [ ]+/,' ')
+          @s=@s.gsub(/(?:#{Mx[:nbsp]})+/,' ')
+          if @t_o.is==:heading
+            @s=@t_o.lv + '~ ' + @s
+          end
+          if @t_o.is==:para
+            if @t_o.bullet_
+              @s='_* ' + @s
+            end
+            if @t_o.indent.to_i > 0
+              @s="_#{@t_o.indent} " + @s
+              @s=@s.gsub(/^(_[1-9])\s_\*\s/,'\1* ')
+            end
+          end
+        end
+        if @t_o.is==:block \
+        || @t_o.is==:group \
+        || @t_o.is==:code
+          @s=@s.gsub(/#{Mx[:nbsp]}/,' ')
+          @s="#{@t_o.is.to_s}{\n\n#{@s}\n\n}#{@t_o.is.to_s}"
+          @s=@s.gsub(/(?:#{Mx[:br_nl]}|\n)+/m,"\n\n")
+        end
+        #dealing with poem and verse calls for change in dal, where start and end verse of poem are marked as such
+        @s=@s.strip
+      end
+      @s
+    end
+    def html_lite #test whether eventually can be used in db_import replacing shared_html_lite (search for SiSU_FormatShared)
+      if @t_o
+        @s=@s.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'<b>\1</b>').
+          gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'<i>\1</i>').
+          gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'<u>\1</u>').
+          gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'"\1"').
+          gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'+{\1}+').
+          gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strke_c]}/,'-{\1}-').
+          gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'<sup>\1</sup>').
+          gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'<sub>\1</sub>').
+          gsub(/#{Mx[:gl_o]}#(?:126|152)#{Mx[:gl_c]}/i,'~')
+        if @t_o.is !=:code
+          if @s =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|image)/
+            wm=@s.scan(/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|image)|\S+/)
+            words=urls(wm)
+            @s=@s.gsub(/.+/m,words)
+          end
+          @s=@s.gsub(/#{Mx[:gl_o]}(#[0-9]{3})#{Mx[:gl_c]}/u,'&\1;').
+            gsub(/#{Mx[:gl_o]}#([a-z]{2,4})#{Mx[:gl_c]}/u,'&\1;').
+            gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,'<a href="\1" target="_top">\1</a>'). #http ftp matches escaped, no decoration
+            gsub(/(#{Mx[:lnk_c]})#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,'\1<a href="\2" target="_top">\2</a>\3'). #special case \{ e.g. \}http://url
+            gsub(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,%{#{@url_brace.xml_open}<a href="\\1" target="_top">\\1</a>#{@url_brace.xml_close}}) #http ftp matches with decoration
+        else
+          @s=@s.gsub(/</m,'&lt;').gsub(/>/m,'&gt;')
+        end
+        if @t_o.is==:paragraph
+          if @t_o.bullet_
+            @s=@s
+          end
+          if @t_o.indent > 0
+            @s=@s
+          end
+        end
+        if @t_o.is==:heading
+          @s=@s
+        end
+      else
+        p __FILE__ << ':' << __LINE__.to_s
+      end
+      @s
+    end
+  end
+  class ModifiedTextPlusHashDigest
+    def initialize(md,x)
+      @md=md
+      if x.is_a?(String)
+        @t_o,@s=nil,x
+      else
+        @t_o,@s=x,x.obj.dup
+      end
+      @env ||=SiSU_Env::InfoEnv.new(@md.fns)
+      @sha_ = @env.digest(@md.opt).type
+      begin
+        case @sha_
+        when :sha512
+          require 'digest/sha2'
+        when :sha256
+          require 'digest/sha2'
+        when :md5
+          require 'digest/md5'
+        end
+      rescue LoadError
+        SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).error((@sha_ ? 'digest/sha2' : 'digest/md5') + ' NOT FOUND')
+      end
+    end
+    def digest(txt)
+      d=nil
+      case @sha_
+      when :sha512
+        for hash_class in [ Digest::SHA512 ]
+          d=hash_class.hexdigest(txt)
+        end
+      when :sha256
+        for hash_class in [ Digest::SHA256 ]
+          d=hash_class.hexdigest(txt)
+        end
+      when :md5
+        for hash_class in [ Digest::MD5 ]
+          d=hash_class.hexdigest(txt)
+        end
+      end
+      d
+    end
+    def strip_clean_of_markup
+      def txt
+        SiSU_TextRepresentation::Alter.new(@s).strip_clean_of_markup
+      end
+      def dgst
+        txt_dgst=digest(txt)
+        { txt: txt, dgst_txt: txt_dgst }
+      end
+      self
+    end
+    def semi_revert_markup
+      def txt
+        SiSU_TextRepresentation::Alter.new(@s).semi_revert_markup
+      end
+      def dgst
+        txt_dgst=digest(txt)
+        { txt: txt, dgst_txt: txt_dgst }
+      end
+      self
+    end
+    def composite
+      def stripped_clean(txt)
+        SiSU_TextRepresentation::Alter.new(txt).strip_clean_of_markup
+      end
+      def markup_reverted(txt)
+        SiSU_TextRepresentation::Alter.new(txt).semi_revert_markup
+      end
+      def images(imgs)
+        sys=SiSU_Env::SystemCall.new
+        line_image=[]
+        if imgs and imgs.length > 0
+           @image_name,@image_dgst,@img=[],[],[]
+           imgs.each do |i|
+             image_source=if FileTest.file?("#{@env.path.image_source_include_local}/#{i}")
+               @env.path.image_source_include_local
+             elsif FileTest.file?("#{@env.path.image_source_include_remote}/#{i}")
+               @env.path.image_source_include_remote
+             elsif FileTest.file?("#{@env.path.image_source_include}/#{i}")
+               @env.path.image_source_include
+             else
+               SiSU_Screen::Ansi.new(
+                 @md.opt.act[:color_state][:set],
+                 "ERROR - image:",
+                 %{"#{i}" missing},
+                 "search locations: #{@env.path.image_source_include_local}, #{@env.path.image_source_include_remote} and #{@env.path.image_source_include}"
+               ).error2 unless @md.opt.act[:quiet][:set]==:on
+               nil
+             end
+             img_type = /\S+\.(png|jpg|gif)/.match(i)[1]
+             if image_source
+               para_image = image_source + '/' + i
+               image_name = i
+               image_dgst =(@sha_ ? sys.sha256(para_image) : sys.md5(para_image))
+             else
+               image_name = i + ' [image missing]'
+               image_dgst = ''
+             end
+             line_image << { img_dgst: image_dgst[1], img_name: image_name, img_type: img_type }
+           end
+        end
+        line_image
+      end
+      def endnotes(en)
+        en_dgst=[]
+        if en and en.length > 0
+          en.flatten.each do |e|
+             note_no=e.gsub(/^([\d*+]+)\s+.+/,'\1')
+             e=digest(stripped_clean(e))
+             note_dgst=digest(e)
+             en_dgst << { note_number: note_no, note_dgst: note_dgst }
+          end
+        end
+        en_dgst
+      end
+      def dgst
+        if @t_o.of !=:comment \
+        && @t_o.of !=:structure \
+        && @t_o.of !=:layout
+          txt_stripped_dgst=digest(stripped_clean(@t_o))
+          txt_markup_reverted_dgst=digest(markup_reverted(@t_o))
+          endnotes_dgst=[]
+          rgx_notes=/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})([\d*+]+\s+.+?)(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/
+          notes=@t_o.obj.scan(rgx_notes)
+          endnotes_dgst=endnotes(notes)
+          rgx_image=/#{Mx[:lnk_o]}(\S+\.(?:png|jpg|gif))\s.+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|image)/
+          imgs=if (@t_o.is==:para \
+          || @t_o.is==:image) \
+          and @t_o.obj =~rgx_image
+            imgs=@t_o.obj.scan(rgx_image).flatten
+            line_image=images(imgs)
+          end
+          dgst={ is: @t_o.is, ocn: @t_o.ocn, dgst_stripped_txt: txt_stripped_dgst, dgst_markedup_txt: txt_markup_reverted_dgst }
+          dgst[:endnotes]=endnotes_dgst if endnotes_dgst and endnotes_dgst.length > 0
+          dgst[:images]=line_image if line_image and line_image.length > 0
+        end
+        dgst
+      end
+      self
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** shared_metadata.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/shared_metadata.rb"
+# <<sisu_document_header>>
+module SiSU_Metadata
+  require_relative 'xml_parts'                          # xml_parts.rb
+  require_relative 'xml_shared'                         # xml_shared.rb
+  class Summary
+    include SiSU_Parts_XML
+    attr_accessor :tag,:inf,:class,:attrib
+    def initialize(md,display_heading=false)
+      @md,@display_heading=md,display_heading
+      @tag,@inf,@class,@attrib=nil
+    end
+    def metadata_base
+      meta=[]
+      l=SiSU_Env::StandardiseLanguage.new(@md.opt.lng).language
+      language=l[:n]
+      tr=SiSU_Translate::Source.new(@md,language)
+      @attrib='md'
+      def meta_content_clean(content='')
+        content=if not content.nil?
+          content=content.tr('"',"'").
+            gsub(/&/,'&amp;')
+        else content
+        end
+      end
+      if @display_heading
+        @tag,@inf=%{<b><u>Document Metadata</u></b>},''
+        meta << self.meta_para
+      end
+      if defined? @md.title.full \
+      and @md.title.full=~/\S+/
+        @tag,@inf,@class=tr.full_title,@md.title.full,'dc' #1
+        meta << self.meta_para
+      end
+      if defined? @md.creator.author \
+      and @md.creator.author=~/\S+/
+        @tag,@inf,@class=tr.author,@md.creator.author,'dc' #2
+        meta << self.meta_para
+      end
+      if defined? @md.creator.translator \
+      and @md.creator.translator=~/\S+/
+        @tag,@inf,@class=tr.translator,@md.creator.translator,'ext'
+        meta << self.meta_para
+      end
+      if defined? @md.creator.illustrator \
+      and @md.creator.illustrator=~/\S+/
+        @tag,@inf,@class=tr.illustrator,@md.creator.illustrator,'ext'
+        meta << self.meta_para
+      end
+      if defined? @md.creator.prepared_by \
+      and @md.creator.prepared_by=~/\S+/
+        @tag,@inf,@class=tr.prepared_by,@md.creator.prepared_by,'ext'
+        meta << self.meta_para
+      end
+      if defined? @md.creator.digitized_by \
+      and @md.creator.digitized_by=~/\S+/
+        @tag,@inf,@class=tr.digitized_by,@md.creator.digitized_by,'ext'
+        meta << self.meta_para
+      end
+      if defined? @md.creator.contributor \
+      and @md.creator.contributor=~/\S+/
+        @tag,@inf,@class=tr.contributor,@md.creator.contributor,'dc' #6
+        meta << self.meta_para
+      end
+      if defined? @md.rights.all \
+      and @md.rights.all=~/\S+/
+        @tag,@inf,@class=tr.rights,meta_content_clean(@md.rights.all),'dc' #15
+        meta << self.meta_para
+      end
+      if defined? @md.classify.subject \
+      and @md.classify.subject=~/\S+/
+        @tag,@inf,@class=tr.subject,@md.classify.subject,'dc' #3
+        meta << self.meta_para
+      end
+      if defined? @md.classify.keywords \
+      and @md.classify.keywords=~/\S+/
+        @tag,@inf,@class=tr.keywords,@md.classify.keywords,'ext'
+        meta << self.meta_para
+      end
+      if defined? @md.classify.loc \
+      and @md.classify.loc=~/\S+/
+        @tag,@inf,@class=tr.cls_loc,@md.classify.loc,'id'
+        meta << self.meta_para
+      end
+      if defined? @md.classify.dewey \
+      and @md.classify.dewey=~/\S+/
+        @tag,@inf,@class=tr.cls_dewey,@md.classify.dewey,'id'
+        meta << self.meta_para
+      end
+      if defined? @md.publisher \
+      and @md.publisher=~/\S+/
+        @tag,@inf,@class=tr.publisher,@md.publisher,'dc' #5
+        meta << self.meta_para
+      end
+      if defined? @md.date.created \
+      and @md.date.created=~/\S+/
+        @tag,@inf,@class=tr.date_created,@md.date.created,'dc' #7
+        meta << self.meta_para
+      end
+      if defined? @md.date.issued \
+      and @md.date.issued=~/\S+/
+        @tag,@inf,@class=tr.date_issued,@md.date.issued,'dc' #7
+        meta << self.meta_para
+      end
+      if defined? @md.date.available \
+      and @md.date.available=~/\S+/
+        @tag,@inf,@class=tr.date_available,@md.date.available,'dc' #7
+        meta << self.meta_para
+      end
+      if defined? @md.date.modified \
+      and @md.date.modified=~/\S+/
+        @tag,@inf,@class=tr.date_modified,@md.date.modified,'dc' #7
+        meta << self.meta_para
+      end
+      if defined? @md.date.valid \
+      and @md.date.valid=~/\S+/
+        @tag,@inf,@class=tr.date_valid,@md.date.valid,'dc' #7
+        meta << self.meta_para
+      end
+      if defined? @md.date.published \
+      and @md.date.published=~/\S+/
+        @tag,@inf,@class=tr.date,@md.date.published,'dc' #7
+        meta << self.meta_para
+      end
+      if defined? @md.identifier.isbn \
+      and @md.identifier.isbn=~/\S+/
+        @tag,@inf,@class=tr.cls_isbn,@md.identifier.isbn,'id'
+        meta << self.meta_para
+      end
+      if defined? @md.identifier.oclc \
+      and @md.identifier.oclc=~/\S+/
+        @tag,@inf,@class=tr.cls_oclc,@md.identifier.oclc,'id'
+        meta << self.meta_para
+      end
+      if defined? @md.notes.description \
+      and @md.notes.description=~/\S+/
+        @tag,@inf,@class=tr.description,@md.notes.description,'dc' #4
+        meta << self.meta_para
+      end
+      if defined? @md.notes.abstract \
+      and @md.notes.abstract=~/\S+/
+        @tag,@inf,@class=tr.abstract,@md.notes.abstract,'ext'
+        meta << self.meta_para
+      end
+      if defined? @md.notes.comment \
+      and @md.notes.comment=~/\S+/
+        @tag,@inf,@class=tr.comments,@md.notes.comment,'ext'
+        meta << self.meta_para
+      end
+      if defined? @md.notes.coverage \
+      and @md.notes.coverage=~/\S+/
+        @tag,@inf,@class=tr.coverage,@md.notes.coverage,'dc' #14
+        meta << self.meta_para
+      end
+      if defined? @md.notes.relation \
+      and @md.notes.relation=~/\S+/
+        @tag,@inf,@class=tr.relation,@md.notes.relation,'dc' #13
+        meta << self.meta_para
+      end
+      #if defined? @md.notes.source \
+      #and @md.notes.source=~/\S+/
+      #  @tag,@inf,@class=tr.source,@md.notes.source,'dc' #11
+      #  meta << self.meta_para
+      #end
+      if defined? @md.notes.history \
+      and @md.notes.history=~/\S+/
+        @tag,@inf,@class=tr.type,@md.notes.history,'dc' #8
+        meta << self.meta_para
+      end
+      if defined? @md.notes.type \
+      and @md.notes.type=~/\S+/
+        @tag,@inf,@class=tr.type,@md.notes.type,'dc' #8
+        meta << self.meta_para
+      end
+      if defined? @md.notes.format \
+      and @md.notes.format=~/\S+/
+        @tag,@inf,@class=tr.format,@md.notes.format,'dc' #9
+        meta << self.meta_para
+      end
+      if defined? @md.notes.prefix_a \
+      and @md.notes.prefix_a=~/\S+/
+        @tag,@inf,@class=tr.prefix_a,@md.notes.prefix_a,'inf'
+        meta << self.meta_para
+      end
+      if defined? @md.notes.prefix_b \
+      and @md.notes.prefix_b=~/\S+/
+        @tag,@inf,@class=tr.prefix_b,@md.notes.prefix_b,'inf'
+        meta << self.meta_para
+      end
+      if defined? @md.original.source \
+      and @md.original.source=~/\S+/
+        @tag,@inf,@class=tr.source,@md.original.source,'dc' #11
+        meta << self.meta_para
+      end
+      if defined? @md.title.language \
+      and @md.title.language=~/\S+/
+        @tag,@inf,@class=tr.language,@md.title.language,'dc' #12
+        meta << self.meta_para
+      end
+      if defined? @md.original.language \
+      and @md.original.language=~/\S+/
+        @tag,@inf,@class=tr.language_original,@md.original.language,'ext'
+        meta << self.meta_para
+      end
+      if @display_heading
+        @tag,@inf=%{<b><u>Version Information</u></b>},''
+        meta << self.meta_para
+      end
+      if defined? @md.fns \
+      and @md.fns=~/\S+/
+        @tag,@inf,@class=tr.sourcefile,@md.fns,'src'
+        meta << self.meta_para
+      end
+      if defined? @md.file_encoding \
+      and @md.file_encoding=~/\S+/
+        @tag,@inf,@class='Filetype',@md.file_encoding,'src'
+        meta << self.meta_para
+      end
+      if defined? @md.dgst \
+      and @md.dgst.is_a?(Array)
+        @tag,@inf,@class='Source Digest',"#{@md.dgst[0]} #{@md.dgst[1]}",'src'
+        meta << self.meta_para
+      end
+      if @display_heading
+        @tag,@inf=%{<b><u>Generated</u></b>},''
+        meta << self.meta_para
+      end
+      if defined? @md.project_details \
+      and @md.project_details.version=~/\S+/
+        v="#{tr.sisu_version}: " +
+          "#{@md.project_details.project} " +
+          "#{@md.project_details.version} " +
+          "of #{@md.project_details.date_stamp} " +
+          "(#{@md.project_details.date})"
+        @tag,@inf,@class='Generated by',v,'ver'
+        meta << self.meta_para
+      end
+      if defined? @md.ruby_version \
+      and @md.ruby_version=~/\S+/
+        @tag,@inf,@class=tr.ruby_version,@md.ruby_version,'ver'
+        meta << self.meta_para
+      end
+      if defined? @md.generated \
+      and @md.generated.is_a?(Time)
+        @tag,@inf,@class=tr.last_generated,@md.generated,'date'
+        meta << self.meta_para
+      end
+      meta
+    end
+    def metadata_alt
+      meta=[]
+      if @display_heading
+        @tag,@inf=%{<b><u>Document Metadata</u></b>},''
+        meta << self.meta_para
+      end
+      if defined? @md.title.main \
+      and @md.title.main=~/\S+/
+        @tag='title'
+        @inf=@md.title.main
+        meta << self.meta_para
+      end
+      if defined? @md.title.sub \
+      and @md.title.sub=~/\S+/
+        @tag='subtitle'
+        @inf=@md.title.sub
+        meta << self.meta_para
+      end
+      if defined? @md.creator.author \
+      and @md.creator.author=~/\S+/
+        @tag='author'
+        @inf=@md.creator.author
+        meta << self.meta_para
+      end
+      if defined? @md.creator.translator \
+      and @md.creator.translator=~/\S+/
+        @tag='translator'
+        @inf=@md.creator.translator
+        meta << self.meta_para
+      end
+      if defined? @md.creator.illustrator \
+      and @md.creator.illustrator=~/\S+/
+        @tag='illustrator'
+        @inf=@md.creator.illustrator
+        meta << self.meta_para
+      end
+      if defined? @md.rights.copyright.text \
+      and @md.rights.copyright.text=~/\S+/
+        @tag='copyright'
+        @inf=@md.rights.copyright.text # year & holder
+        @inf=@inf.gsub(/(?:Copyright|\(C\))+\s*/,'')
+        meta << self.meta_para
+      end
+      if defined? @md.rights.license \
+      and @md.rights.license=~/\S+/
+        @tag='license'
+        @inf=@md.rights.license
+        meta << self.meta_para
+      end
+      meta
+    end
+    def processing_tags
+      def make
+        def language
+          if defined? @md.make.language \
+          and @md.make.language
+            ' :language: ' + @md.make.language.join(', ')
+          else nil
+          end
+        end
+        def headings
+          if defined? @md.make.headings \
+          and @md.make.headings
+            ' :headings: ' + @md.make.headings[0].join('; ')
+          else nil
+          end
+        end
+        def num_top
+          if defined? @md.make.num_top \
+          and @md.make.num_top
+            ' :num_top: ' + @md.make.num_top
+          else nil
+          end
+        end
+        def breaks
+          x=if defined? @md.make.breaks \
+            and @md.make.breaks
+            x=' :breaks:'
+            if @md.make.breaks[:page_break]
+              x +=' break=' + @md.make.breaks[:page_break] + ';'
+            end
+            if @md.make.breaks[:page_new]
+              x +=' new=' + @md.make.breaks[:page_new] + ';'
+            end
+          else nil
+          end
+        end
+        def emphasis
+          if defined? @md.make.emphasis \
+          and @md.make.emphasis
+            ' :emphasis: ' + @md.make.emphasis[:regx].inspect
+          else nil
+          end
+        end
+        def bold
+          if defined? @md.make.bold \
+          and @md.make.bold
+            ' :bold: ' + @md.make.bold[:regx].inspect
+          else nil
+          end
+        end
+        def italics
+          if defined? @md.make.italics \
+          and  @md.make.italics
+            ' :italics: ' + @md.make.italics[:regx].inspect
+          else nil
+          end
+        end
+        def texpdf_font
+          if defined? @md.make.texpdf_font \
+          and @md.make.texpdf_font
+            ' :texpdf_font: ' + @md.make.texpdf_font.main
+          else nil
+          end
+        end
+        self
+      end
+      self
+    end
+    def metadata_tags
+      def title
+        def main
+          if defined? @md.title.main \
+          and @md.title.main
+            '@title: ' + @md.title.main
+          else '@title:'
+          end
+        end
+        def sub
+          if defined? @md.title.sub \
+          and @md.title.sub
+            ' :subtitle: ' + @md.title.sub
+          else nil
+          end
+        end
+        def edition
+          if defined? @md.title.edition \
+          and @md.title.edition
+            ' :edition: ' + @md.title.edition
+          else nil
+          end
+        end
+        def note
+          if defined? @md.title.note \
+          and @md.title.note
+            ' :note: ' + @md.title.note
+          else nil
+          end
+        end
+        def short
+          if defined? @md.title.short \
+          and @md.title.short
+            ' :short: ' + @md.title.short
+          else nil
+          end
+        end
+        def language
+          if defined? @md.title.language \
+          and @md.title.language
+            ' :language: ' + @md.title.language
+          else nil
+          end
+        end
+        def language_char
+          if defined? @md.title.language_char \
+          and @md.title.language_char
+            ' :language_char: ' + @md.title.language_char
+          else nil
+          end
+        end
+        self
+      end
+      def creator
+        def head
+          '@creator:'
+        end
+        def author
+          x=if defined? @md.creator.author_detail \
+            and @md.creator.author_detail
+            x=''
+            @md.creator.author_detail.each do |n|
+              x += "#{n[:the]}, #{n[:others]}; "
+            end
+            x=x.gsub(/;\s*$/,'')
+            ' :author: ' + x
+          else nil
+          end
+        end
+        def contributor
+          x=if defined? @md.creator.contributor_detail \
+            and @md.creator.contributor_detail
+            x=''
+            @md.creator.contributor_detail.each do |n|
+              x += "#{n[:the]}, #{n[:others]}; "
+            end
+            x=x.gsub(/;\s*$/,'')
+            ' :contributor: ' + x
+          else nil
+          end
+        end
+        def illustrator
+          x=if defined? @md.creator.illustrator_detail \
+            and @md.creator.illustrator_detail
+            x=''
+            @md.creator.illustrator_detail.each do |n|
+              x += "#{n[:the]}, #{n[:others]}; "
+            end
+            x=x.gsub(/;\s*$/,'')
+            ' :illustrator: ' + x
+          else nil
+          end
+        end
+        def photographer
+          x=if defined? @md.creator.photographer_detail \
+            and @md.creator.photographer_detail
+            x=''
+            @md.creator.photographer_detail.each do |n|
+              x += "#{n[:the]}, #{n[:others]}; "
+            end
+            x=x.gsub(/;\s*$/,'')
+            ' :photographer: ' + x
+          else nil
+          end
+        end
+        def translator
+          x=if defined? @md.creator.translator_detail \
+            and @md.creator.translator_detail
+            x=''
+            @md.creator.translator_detail.each do |n|
+              x += "#{n[:the]}, #{n[:others]}; "
+            end
+            x=x.gsub(/;\s*$/,'')
+            ' :translator: ' + x
+          else nil
+          end
+        end
+        def audio
+          x=if defined? @md.creator.audio_detail \
+            and @md.creator.audio_detail
+            x=''
+            @md.creator.audio_detail.each do |n|
+              x += "#{n[:the]}, #{n[:others]}; "
+            end
+            x=x.gsub(/;\s*$/,'')
+            ' :audio: ' + x
+          else nil
+          end
+        end
+        def digitized_by
+          x=if defined? @md.creator.digitized_by_detail \
+            and @md.creator.digitized_by_detail
+            x=''
+            @md.creator.digitized_by_detail.each do |n|
+              x += "#{n[:the]}, #{n[:others]}; "
+            end
+            x=x.gsub(/;\s*$/,'')
+            ' :digitized_by: ' + x
+          else nil
+          end
+        end
+        def prepared_by
+          x=if defined? @md.creator.prepared_by_detail \
+            and @md.creator.prepared_by_detail
+            x=''
+            @md.creator.prepared_by_detail.each do |n|
+              x += "#{n[:the]}, #{n[:others]}; "
+            end
+            x=x.gsub(/;\s*$/,'')
+            ' :prepared_by: ' + x
+          else nil
+          end
+        end
+        self
+      end
+      def rights
+        def head
+          '@rights:'
+        end
+        def copyright
+          def text
+            if defined? @md.rights.copyright.text \
+            and @md.rights.copyright.text
+              ' :copyright: ' + @md.rights.copyright.text
+            else nil
+            end
+          end
+          def translation
+            if defined? @md.rights.copyright.translation \
+            and @md.rights.copyright.translation
+              ' :translation: ' + @md.rights.copyright.translation
+            else nil
+            end
+          end
+          def illustrations
+            if defined? @md.rights.copyright.illustrations \
+            and @md.rights.copyright.illustrations
+              ' :illustrations: ' + @md.rights.copyright.illustrations
+            else nil
+            end
+          end
+          def photographs
+            if defined? @md.rights.copyright.photographs \
+            and @md.rights.copyright.photographs
+              ' :photographs: ' + @md.rights.copyright.photographs
+            else nil
+            end
+          end
+          def digitization
+            if defined? @md.rights.copyright.digitization \
+            and @md.rights.copyright.digitization
+              ' :digitization: ' + @md.rights.copyright.digitization
+            else nil
+            end
+          end
+          def audio
+            if defined? @md.rights.copyright.audio \
+            and @md.rights.copyright.audio
+              ' :audio: ' + @md.rights.copyright.audio
+            else nil
+            end
+          end
+          self
+        end
+        def license
+          if defined? @md.rights.license \
+          and @md.rights.license
+            ' :license: ' + @md.rights.license
+          else nil
+          end
+        end
+        self
+      end
+      def classify
+        def head
+          '@classify:'
+        end
+        def coverage
+          if defined? @md.classify.coverage \
+          and @md.classify.coverage
+            ' :coverage: ' + @md.classify.coverage
+          else nil
+          end
+        end
+        def relation
+          if defined? @md.classify.relation \
+          and @md.classify.relation
+            ' :relation: ' + @md.classify.relation
+          else nil
+          end
+        end
+        def subject
+          if defined? @md.classify.subject \
+          and @md.classify.subject
+            ' :subject: ' + @md.classify.subject
+          else nil
+          end
+        end
+        def topic_register
+          if defined? @md.classify.topic_register \
+          and @md.classify.topic_register
+            ' :topic_register: ' + @md.classify.topic_register
+          else nil
+          end
+        end
+        def type
+#         if defined? @md.classify.type \
+#         and @md.classify.type
+#           ' :type: ' + @md.classify.type
+#         else nil
+#         end
+          nil
+        end
+        #def identifier
+        #  if defined? @md.classify.identifier \
+        #  and @md.classify.identifier
+        #    ' :identifier: ' + @md.classify.identifier
+        #  else nil
+        #  end
+        #end
+        def loc
+          if defined? @md.classify.loc \
+          and @md.classify.loc
+            ' :loc: ' + @md.classify.loc
+          else nil
+          end
+        end
+        def dewey
+          if defined? @md.classify.dewey \
+          and @md.classify.dewey
+            ' :dewey: ' + @md.classify.dewey
+          else nil
+          end
+        end
+        def oclc
+          if defined? @md.classify.oclc \
+          and @md.classify.oclc
+            ' :oclc: ' + @md.classify.oclc
+          else nil
+          end
+        end
+        def pg
+          if defined? @md.classify.pg \
+          and @md.classify.pg
+            ' :pg: ' + @md.classify.pg
+          else nil
+          end
+        end
+        def isbn
+          if defined? @md.classify.isbn \
+          and @md.classify.isbn
+            ' :isbn: ' + @md.classify.isbn
+          else nil
+          end
+        end
+        self
+      end
+      def date
+        def head
+          '@date:'
+        end
+        def added_to_site
+          if defined? @md.date.added_to_site \
+          and @md.date.added_to_site
+            ' :added_to_site: ' + @md.date.added_to_site
+          else nil
+          end
+        end
+        def available
+          if defined? @md.date.available \
+          and @md.date.available
+            ' :available: ' + @md.date.available
+          else nil
+          end
+        end
+        def created
+          if defined? @md.date.created \
+          and @md.date.created
+            ' :created: ' + @md.date.created
+          else nil
+          end
+        end
+        def issued
+          if defined? @md.date.issued \
+          and @md.date.issued
+            ' :issued: ' + @md.date.issued
+          else nil
+          end
+        end
+        def modified
+          if defined? @md.date.modified \
+          and @md.date.modified
+            ' :modified: ' + @md.date.modified
+          else nil
+          end
+        end
+        def published
+          if defined? @md.date.published \
+          and @md.date.published
+            ' :published: ' + @md.date.published
+          else nil
+          end
+        end
+        def valid
+          if defined? @md.date.valid \
+          and @md.date.valid
+            ' :valid: ' + @md.date.valid
+          else nil
+          end
+        end
+        self
+      end
+      #def make
+      #  def headings
+      #    @md.make.headings \
+      #    ? (' :headings: ' + @md.make.headings) \
+      #    : nil
+      #  end
+      #end
+      self
+    end
+    def char_enc(str)
+      @s=str
+      def amp
+        if @s \
+        and @s.is_a?(String)
+          @s=@s.gsub(/&/u,'&amp;')
+        end
+        @s
+      end
+      def br
+        if @s \
+        and @s.is_a?(String)
+          @s=@s.gsub(/(?:#{Mx[:br_line]}|\\\\)+/,'<br />')
+        end
+        @s
+      end
+      def utf8
+        if @s \
+        and @s.is_a?(String)
+          @s=@s.gsub(/<br(?: \/)?>/u,Mx[:br_paragraph]).
+            gsub(/</um,'&lt;').gsub(/>/um,'&gt;').
+            #gsub(/</um,'&#60;').gsub(/>/um,'&#62;').
+            gsub(/ /um,' ').       # space identify
+            gsub(/ /um,' ').       # space identify
+            gsub(/#{Mx[:br_paragraph]}/u,'<br />')
+        end
+        @s
+      end
+      self
+    end
+    def xml_docbook
+      def meta_para
+        inf_xml=char_enc(@inf).amp
+        inf_xml=char_enc(inf_xml).br
+        <<WOK
+#{Ax[:tab]}<#{@tag}>
+#{Ax[:tab]*2}#{inf_xml}
+#{Ax[:tab]}</#{@tag}>
+WOK
+      end
+      def metadata
+        SiSU_Metadata::Summary.new(@md).metadata_alt
+      end
+      self
+    end
+    def html_display
+      def meta_para
+        inf_xml=char_enc(@inf).amp
+        inf_xml=char_enc(inf_xml).br
+        %{<p class="norm">
+  <b>#{@tag}</b>: #{inf_xml}
+</p>}
+      end
+      def metadata
+        SiSU_Metadata::Summary.new(@md,true).metadata_base
+      end
+      self
+    end
+    def xml_sax
+      def meta_para
+        inf_xml=char_enc(inf_xml).br
+        <<WOK
+<metadata>
+#{Ax[:tab]}<meta>#{@tag.capitalize}:</meta>
+#{Ax[:tab]}<data class="#{@attrib}">
+#{Ax[:tab]*2}#{inf_xml}
+#{Ax[:tab]}</data>
+</metadata>
+WOK
+      end
+      def metadata
+        SiSU_Metadata::Summary.new(@md).metadata_base
+      end
+      self
+    end
+    def xml_dom
+      def meta_para
+        inf_xml=char_enc(inf_xml).amp
+        inf_xml=char_enc(inf_xml).br
+        <<WOK
+#{Ax[:tab]}<header>
+#{Ax[:tab]*2}<meta>#{@tag.capitalize}:</meta>
+#{Ax[:tab]*2}<#{@attrib}>
+#{Ax[:tab]*3}#{inf_xml}
+#{Ax[:tab]*2}</#{@attrib}>
+#{Ax[:tab]}</header>
+WOK
+      end
+      def metadata
+        SiSU_Metadata::Summary.new(@md).metadata_base
+      end
+      self
+    end
+    def xhtml_scroll
+      def meta_para
+        inf_xml=char_enc(inf_xml).amp
+        inf_xml=char_enc(inf_xml).br
+        <<WOK
+#{Ax[:tab]}<metadata>
+#{Ax[:tab]}<meta>#{@tag.capitalize}:</meta>
+#{Ax[:tab]}<#{@attrib} class="#{@class}">
+#{Ax[:tab]*2}#{inf_xml}
+#{Ax[:tab]}</#{@attrib}>
+#{Ax[:tab]}</metadata>
+	<br />
+WOK
+      end
+      def metadata
+        SiSU_Metadata::Summary.new(@md).metadata_base
+      end
+      self
+    end
+    def xhtml_display
+      def meta_para
+        inf_xml=char_enc(@inf).amp
+        inf_xml=char_enc(inf_xml).br
+        %{<p class="norm">
+  <b>#{@tag}</b>: #{inf_xml}
+</p>}
+      end
+      def metadata
+        SiSU_Metadata::Summary.new(@md,true).metadata_base
+      end
+      self
+    end
+    def odf
+      def meta_para
+        if @inf.is_a?(String)
+          @inf=@inf.gsub(/</,'&lt;').gsub(/>/,'&gt;').
+            gsub(/&lt;br(?: \/)?&gt;/,'<br />')
+          if @inf =~/&/
+            inf_array=[]
+            word=@inf.scan(/\S+|\n/)
+            word.each do |w| # _ - / # | : ! ^ ~
+              w=w.gsub(/&nbsp;/,'&#160;')
+              if w !~/&\S{2,7}?;/
+                w=w.gsub(/&/,'&amp;')
+              end
+              inf_array << w
+            end
+            @inf=inf_array.join(' ')
+          end
+          @inf=@inf.gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,
+              '<text:a xl:type="simple" xl:href="\1">\1</text:a>'). #http ftp matches escaped, no decoration
+            gsub(/(#{Mx[:lnk_c]})#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,
+              '\1<text:a xl:type="simple" xl:href="\2">\2</text:a>') #special case \{ e.g. \}http://url
+          @inf=if @inf =~/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/
+            @inf.gsub(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,
+              %{#{the_url_decoration.xml_open}<text:a xl:type="simple" xl:href="\\1">\\1</text:a>#{the_url_decoration.xml_close}}) #http ftp matches with decoration
+          else
+            @inf.gsub(/(https?:\/\/[^<>()'"\s]+)/,
+              %{#{the_url_decoration.xml_open}<text:a xl:type="simple" xl:href="\\1">\\1</text:a>#{the_url_decoration.xml_close}}) #http ftp matches with decoration
+          end
+          @inf=@inf.gsub(/([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+)/,
+            %{#{the_url_decoration.xml_open}<text:a xl:type="simple" xl:href="mailto:\\1">\\1</text:a>#{the_url_decoration.xml_close}}) if @inf !~/http:\/\// # improve upon, document crash where url contains '@' symbol
+        end
+        <<WOK
+<text:p text:style-name="P1">#{@tag.capitalize}: #{@inf}</text:p>
+WOK
+      end
+      def metadata
+        SiSU_Metadata::Summary.new(@md).metadata_base
+      end
+      self
+    end
+    def json
+      def meta_para
+        <<WOK
+
+#{@tag.capitalize}: #{@inf}
+WOK
+      end
+      def metadata
+        SiSU_Metadata::Summary.new(@md).metadata_base
+      end
+      self
+    end
+    def plaintext
+      def meta_para
+        <<WOK
+
+#{@tag.capitalize}: #{@inf}
+WOK
+      end
+      def metadata
+        SiSU_Metadata::Summary.new(@md).metadata_base
+      end
+      self
+    end
+    def manpage
+      def meta_para
+        <<WOK
+
+.TP
+#{@tag.capitalize}:
+.I #{@inf}
+WOK
+      end
+      def metadata
+        SiSU_Metadata::Summary.new(@md).metadata_base
+      end
+      self
+    end
+  end
+  class TeX_Metadata
+    def initialize(md)
+      @md=md
+      @br="\\\\\n"
+      @make=SiSU_Env::ProcessingSettings.new(md)
+      @o_str ||=SiSU_Env::ProcessingSettings.new(md).output_dir_structure
+    end
+    def meta_para(tag,inf,sc=true)
+      inf=((inf.is_a?(String) && sc) ? spec_char(inf) : inf)
+      %{\\begin\{bfseries\}#{tag}:\\end\{bfseries\} #{inf}
+}
+    end
+    def spec_char(inf)
+      SiSU_TeX_Pdf::SpecialCharacters.new(@md,inf).special_characters
+    end
+    def word_break_points(inf)
+      SiSU_TeX_Pdf::SpecialCharacters.new(@md,inf).special_word_break_points
+    end
+    def number_break_points(inf)
+      SiSU_TeX_Pdf::SpecialCharacters.new(@md,inf).special_number_break_points
+    end
+    def metadata_tex
+      meta=[]
+      l=SiSU_Env::StandardiseLanguage.new(@md.opt.lng).language
+      language=l[:n]
+      tr=SiSU_Translate::Source.new(@md,language)
+      if @make.build.links_to_manifest? \
+      and not @o_str.dump_or_redirect?
+        tag="Document Manifest @"
+        inf="#{@br}#{@md.file.output_path.manifest.url}/#{@md.file.base_filename.manifest}"
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.title.full \
+      and @md.title.full=~/\S+/
+        tag,inf=tr.full_title,@md.title.full
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.creator.author \
+      and @md.creator.author=~/\S+/
+        tag,inf=tr.author,@md.creator.author
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.creator.translator \
+      and @md.creator.translator=~/\S+/
+        tag,inf=tr.translator,@md.creator.translator
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.creator.illustrator \
+      and @md.creator.illustrator=~/\S+/
+        tag,inf=tr.illustrator,@md.creator.illustrator
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.creator.prepared_by \
+      and @md.creator.prepared_by=~/\S+/
+        tag,inf=tr.prepared_by,@md.creator.prepared_by
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.creator.digitized_by \
+      and @md.creator.digitized_by=~/\S+/
+        tag,inf=tr.digitized_by,@md.creator.digitized_by
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.rights.all \
+      and @md.rights.all=~/\S+/
+        tag,inf=tr.rights,@md.rights.all
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.notes.description \
+      and @md.notes.description=~/\S+/
+        tag,inf=tr.description,@md.notes.description
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.classify.subject \
+      and @md.classify.subject=~/\S+/
+        tag,inf=tr.subject,@md.classify.subject
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.publisher \
+      and @md.publisher=~/\S+/
+        tag,inf=tr.publisher,@md.publisher
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.creator.contributor \
+      and @md.creator.contributor=~/\S+/
+        tag,inf=tr.contributor,@md.creator.contributor
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.notes.abstract \
+      and @md.notes.abstract=~/\S+/
+        tag,inf=tr.abstract,@md.notes.abstract
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.date.created \
+      and @md.date.created=~/\S+/
+        tag,inf=tr.date_created,@md.date.created
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.date.issued \
+      and @md.date.issued=~/\S+/
+        tag,inf=tr.date_issued,@md.date.issued
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.date.available \
+      and @md.date.available=~/\S+/
+        tag,inf=tr.date_available,@md.date.available
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.date.modified \
+      and @md.date.modified=~/\S+/
+        tag,inf=tr.date_modified,@md.date.modified
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.date.valid \
+      and @md.date.valid=~/\S+/
+        tag,inf=tr.date_valid,@md.date.valid
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.date.published \
+      and @md.date.published=~/\S+/
+        tag,inf=tr.date,@md.date.published
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.classify.topic_register \
+      and @md.classify.topic_register=~/\S+/
+        tag,inf=tr.topic_register,@md.classify.topic_register
+        inf=word_break_points(inf)
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.classify.loc \
+      and @md.classify.loc=~/\S+/
+        tag,inf=tr.cls_loc,@md.classify.loc
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.classify.dewey \
+      and @md.classify.dewey=~/\S+/
+        tag,inf=tr.cls_dewey,@md.classify.dewey
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.classify.oclc \
+      and @md.classify.oclc=~/\S+/
+        tag,inf=tr.cls_oclc,@md.classify.oclc
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.classify.pg \
+      and @md.classify.pg=~/\S+/
+        tag,inf=tr.cls_gutenberg,@md.classify.pg
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.classify.isbn \
+      and @md.classify.isbn=~/\S+/
+        tag,inf=tr.cls_isbn,@md.classify.isbn
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.notes.comment \
+      and @md.notes.comment=~/\S+/
+        tag,inf=tr.comments,@md.notes.comment
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.notes.prefix_a \
+      and @md.notes.prefix_a=~/\S+/
+        tag,inf=tr.prefix_a,@md.notes.prefix_a
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.notes.prefix_b \
+      and @md.notes.prefix_b=~/\S+/
+        tag,inf=tr.prefix_b,@md.notes.prefix_b
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.identifier.isbn \
+      and @md.identifier.isbn=~/\S+/
+        tag,inf=tr.cls_isbn,@md.identifier.isbn
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.identifier.oclc \
+      and @md.identifier.oclc=~/\S+/
+        tag,inf=tr.cls_oclc,@md.identifier.oclc
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.original.source \
+      and @md.original.source=~/\S+/
+        tag,inf=tr.source,@md.original.source
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.title.language \
+      and @md.title.language=~/\S+/
+        tag,inf=tr.language,@md.title.language
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.original.language \
+      and @md.original.language=~/\S+/
+        tag,inf=tr.language_original,@md.original.language
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.classify.format \
+      and @md.classify.format=~/\S+/
+        tag,inf=tr.format,@md.classify.format
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.classify.relation \
+      and @md.classify.relation=~/\S+/
+        tag,inf=tr.relation,@md.classify.relation
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.classify.coverage \
+      and @md.classify.coverage=~/\S+/
+        tag,inf=tr.coverage,@md.classify.coverage
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.classify.keywords \
+      and @md.classify.keywords=~/\S+/
+        tag,inf=tr.keywords,@md.classify.keywords
+        meta << meta_para(tag,inf)
+      end
+      meta << %{#{@br}\\begin\{bfseries\}Version Information \\end\{bfseries\}}
+      if defined? @md.fns \
+      and @md.fns=~/\S+/
+        fn=spec_char(@md.fns)
+        fn=word_break_points(fn)
+        fn="\\begin\{footnotesize\}#{fn}\\end\{footnotesize\}"
+        tag,inf=tr.sourcefile,fn
+        meta << meta_para(tag,inf,false)
+      end
+      if defined? @md.file_encoding \
+      and @md.file_encoding=~/\S+/
+        tag,inf='Filetype',@md.file_encoding
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.dgst \
+      and @md.dgst.is_a?(Array)
+        hash_of=spec_char(@md.dgst[0])
+        hash_of=word_break_points(hash_of)
+        dgst=number_break_points(@md.dgst[1])
+        tag,inf='Source Digest',"\\begin\{footnotesize\}#{hash_of}\\end\{footnotesize\}\\-\\begin\{scriptsize\}#{dgst}\\end\{scriptsize\}"
+        meta << meta_para(tag,inf,false)
+      end
+      meta << %{#{@br}\\begin\{bfseries\}Generated \\end\{bfseries\}}
+      if defined? @md.generated \
+      and @md.generated.is_a?(Time)
+        tag,inf=tr.last_generated,@md.generated
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.project_details \
+      and @md.project_details.version=~/\S+/
+        tag=tr.sisu_version
+        inf="#{@md.project_details.project} " +
+          "#{@md.project_details.version} " +
+          "of #{@md.project_details.date_stamp} " +
+          "(#{@md.project_details.date})"
+        meta << meta_para(tag,inf)
+      end
+      if defined? @md.ruby_version \
+      and @md.ruby_version=~/\S+/
+        tag,inf=tr.ruby_version,@md.ruby_version
+        meta << meta_para(tag,inf)
+      end
+      meta
+    end
+  end
+end
+__END__
+if @md.title
+  x=[
+    @md.title.main,
+    @md.title.sub,
+    @md.title.edition,
+    @md.title.note,
+    @md.title.short,
+    @md.title.full,
+    @md.title.language,
+    @md.title.language_char
+  ]
+  x.each {|y| p y if y}
+end
+if @md.creator
+  x=[
+    @md.creator.author,
+    @md.creator.author_detail,
+    @md.creator.contributor,
+    @md.creator.contributor_detail,
+    @md.creator.illustrator,
+    @md.creator.illustrator_detail,
+    @md.creator.photographer,
+    @md.creator.photographer_detail,
+    @md.creator.translator,
+    @md.creator.translator_detail,
+    @md.creator.audio,
+    @md.creator.audio_detail,
+    @md.creator.digitized_by,
+    @md.creator.digitized_by_detail,
+    @md.creator.prepared_by,
+    @md.creator.prepared_by_detail
+  ]
+  x.each {|y| p y if y}
+end
+if @md.rights
+  x=[
+    @md.rights.copyright.text,
+    @md.rights.copyright.translation,
+    @md.rights.copyright.illustrations,
+    @md.rights.copyright.photographs,
+    @md.rights.copyright.digitization,
+    @md.rights.copyright.audio,
+    @md.rights.license,
+    @md.rights.all
+  ]
+  x.each {|y| p y if y}
+end
+if @md.classify
+  x=[
+    @md.classify.coverage,
+    @md.classify.relation,
+    @md.classify.subject,
+    @md.classify.topic_register,
+    @md.classify.type,
+    @md.classify.identifier,
+    @md.classify.loc,
+    @md.classify.dewey,
+    @md.classify.oclc,
+    @md.classify.pg,
+    @md.classify.isbn,
+  ]
+  x.each {|y| p y if y}
+end
+if @md.date
+  x=[
+    @md.date.added_to_site,
+    @md.date.available,
+    @md.date.created,
+    @md.date.issued,
+    @md.date.modified,
+    @md.date.published,
+    @md.date.valid
+  ]
+  x.each {|y| p y if y}
+end
+#if @md.language
+#  p @md.language.document
+#  p @md.language.document_char
+#  p @md.language.original
+#  p @md.language.original_char
+#end
+if @md.make
+  x=[
+    @md.make.headings,
+    @md.make.num_top,
+    @md.make.breaks,
+    @md.make.bold,
+    @md.make.italics,
+    @md.make.emphasis,
+    @md.make.plaintext_wrap,
+    @md.make.texpdf_font,
+    @md.make.promo,
+    @md.make.ad,
+    @md.make.manpage
+  ]
+  x.each {|y| p y if y}
+end
+if @md.current_publisher # @md.publisher
+  x=[
+    @md.current_publisher
+  ]
+  x.each {|y| p y if y}
+end
+if @md.original
+  x=[
+    @md.original.publisher,
+    @md.original.language,
+    @md.original.language_char,
+    @md.original.source,
+    @md.original.institution,
+    @md.original.nationality
+  ]
+  x.each {|y| p y if y}
+end
+if @md.notes
+  x=[
+    @md.notes.abstract,
+    @md.notes.comment,
+    @md.notes.description,
+    @md.notes.history,
+    @md.notes.prefix
+  ]
+  x.each {|y| p y if y}
+end
+__END__
+#+END_SRC
+
+* constants
+** constants.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/constants.rb"
+# <<sisu_document_header>>
+YEAR='2021'
+Sfx={
+  txt:                       '.txt',
+  txt_textile:               '.textile',
+  txt_asciidoc:              '.ad',
+  txt_markdown:              '.md',
+  txt_rst:                   '.rst',
+  txt_orgmode:               '.org',
+  html:                      '.html',
+  xhtml:                     '.xhtml',
+  xml:                       '.xml',
+  xml_sax:                   '.sax.xml',
+  xml_dom:                   '.dom.xml',
+  xml_scaffold:              '.scaffold.xml',
+  xml_scaffold_structure_sisu:     '.scaffold.sisu.xml',
+  xml_scaffold_structure_collapse: '.scaffold.collapse.xml',
+  xml_docbook:               '.docbook.xml',
+  xml_docbook_article:       '.article.docbook.xml',
+  xml_docbook_book:          '.book.docbook.xml',
+  xml_fictionbook:           '.fb2',
+  epub:                      '.epub',
+  epub_xhtml:                '.xhtml',
+  odt:                       '.odt',
+  json:                      '.json',
+  pdf:                       '.pdf',
+  manpage:                   '.1',
+  info:                      '.info',
+  texinfo:                   '.texinfo',
+  sql:                       '.sql.db',
+}
+Ax={
+  tab:                       "\t",
+  comment:                   '%',
+  spaces:                    '  ',
+}
+Xx={
+  protect:                   '☞',
+  split:                     '✠',
+  segment:                   'Ф',
+  relative_path:             '☼',
+  html_relative2:            '※※',
+  html_relative1:            '※',
+}
+Mx={
+  segname_prefix_auto_num_extract: 'c',
+  segname_prefix_auto_num_provide: 's',
+  segname_prefix_auto_num_other:   'x',
+  ocn_id_char:               '',                                              #'o', now as before; remove for html5
+  note:                      'note_',
+  note_ref:                  'noteref_',
+  note_astx:                 'note_astx_',
+  note_ref_astx:             'noteref_astx_',
+  note_plus:                 'note_plus_',
+  note_ref_plus:             'noteref_plus_',
+  meta_o:                    '〔@',   meta_c: '〕',
+  lv_o_0:                    0,
+  lv_o_1:                    1,
+  lv_o_2:                    2,
+  lv_o_3:                    3,
+  lv_o_4:                    4,
+  lv_o_5:                    5,
+  lv_o_6:                    6,
+  lv_o_7:                    7,
+  lv_o_8:                    8,
+  lv_o_9:                    9,
+  lv_o:                      '〔',         lv_c:                '〕',
+  en_a_o:                    '【',         en_a_c:              '】',          #endnote Mx[:en_a_o]='~{'; Mx[:en_a_c]='}~'
+  en_b_o:                    '〖',         en_b_c:              '〗',          #endnote Mx[:en_b_o]='~['; Mx[:en_b_c]=']~'
+  bl_o:                      '〔',         bl_c:                '〕',          #block text mark
+  gr_o:                      '〔',         gr_c:                '〕',          #group text mark #REPLACE & RETIRE
+  id_o:                      '〔',         id_c:                '〕',          #object id mark
+  tc_o:                      '『',         tc_c:                "』",          #table row mark #Mx[:tc_c]="』\n"
+  tc_p:                      '┆',                                              #table col/misc mark
+  pa_o:                      '〔',         pa_c:                '〕',          #affects paragraph mark
+  mk_o:                      '〔',         mk_c:                '〕',          #generic mark
+  gl_o:                      '〔',         gl_c:                '〕',          #glyph
+  fa_o: '〔', fa_o_c: '¤', fa_c_o: '¤', fa_c: '〕',
+  idx_o:                     '▩',         idx_c:               '▩',
+  nbsp:                      '░',                                              #'▭ '
+  br_line:                   '╱',                                              #lB ▌  9612 ┘ ¶
+  br_nl:                     '╲',                                              #lB ▌ 』  ┘
+  br_paragraph:              '█',                                              #FB █  9608 # PP ∥  8741 #▐  #'┘' #'¶' #FB █  9608  lB ▌  9612   RB ▐  9616
+  br_obj:                    'break_obj',
+  br_page_line:              '▭',
+  br_page:                   '┼',
+  br_page_new:               '╋',
+  lnk_o:                     '⌠',          lnk_c:               '⌡',           #'⌈' '⌋' '⌠' '⌡' #Mx[:lnk_o: '◁'; Mx[:lnk_c: '▷' #‹ ›
+  url_o:                     '◘',          url_c:               '◙',
+  rel_o:                     '⌈',          rel_c:               '⌋',
+  tag_o:                     '⌊',          tag_c:               '⌉',
+  sm_set_o:                  '◢',          sm_set_c:            '◣',
+  sm_subset_o:               '◢',          sm_subset_c:         '◣',
+  vline:                     '┆',                                              #  ¦ |
+  src_bold_o:                '!{',    src_bold_c:               '}!',
+  src_italics_o:             '/{',    src_italics_c:            '}/',
+  src_underscore_o:          '_{',    src_underscore_c:         '}_',
+  src_cite_o:                '"{',    src_cite_c:               '}"',
+  src_insert_o:              '+{',    src_insert_c:             '}+',
+  src_strike_o:              '-{',    src_strike_c:             '}-',
+  src_superscript_o:         '^{',    src_superscript_c:        '}^',
+  src_subscript_o:           ',{',    src_subscript_c:          '}',
+  src_hilite_o:              '*{',    src_hilite_c:             '}*',
+  src_monospace_o:           '#{',    src_monospace_c:          '}#',
+  srcrgx_bold_o:             '\!\{',   srcrgx_bold_c:           '\}\!',
+  srcrgx_italics_o:          '\/\{',   srcrgx_italics_c:        '\}\/',
+  srcrgx_underscore_o:       '_\{',    srcrgx_underscore_c:     '\}_',
+  srcrgx_cite_o:             '"\{',    srcrgx_cite_c:           '\}"',
+  srcrgx_insert_o:           '\+\{',   srcrgx_insert_c:         '\}\+',
+  srcrgx_strike_o:           '\-\{',   srcrgx_strike_c:         '\}\-',
+  srcrgx_superscript_o:      '\^\{',   srcrgx_superscript_c:    '\}\^',
+  srcrgx_subscript_o:        ',\{',    srcrgx_subscript_c:      '\},',
+  srcrgx_hilite_o:           '\*\{',   srcrgx_hilite_c:         '\}\*',
+  srcrgx_monospace_o:        '\#\{',   srcrgx_monospace_c:      '\}\#',
+}
+Mx[:fa_bold_o]=              "#{Mx[:fa_o]}b#{Mx[:fa_o_c]}"
+Mx[:fa_bold_c]=              "#{Mx[:fa_c_o]}b#{Mx[:fa_c]}"
+Mx[:fa_italics_o]=           "#{Mx[:fa_o]}i#{Mx[:fa_o_c]}"
+Mx[:fa_italics_c]=           "#{Mx[:fa_c_o]}i#{Mx[:fa_c]}"
+Mx[:fa_underscore_o]=        "#{Mx[:fa_o]}u#{Mx[:fa_o_c]}"
+Mx[:fa_underscore_c]=        "#{Mx[:fa_c_o]}u#{Mx[:fa_c]}"
+Mx[:fa_cite_o]=              "#{Mx[:fa_o]}cite#{Mx[:fa_o_c]}"
+Mx[:fa_cite_c]=              "#{Mx[:fa_c_o]}cite#{Mx[:fa_c]}"
+Mx[:fa_insert_o]=            "#{Mx[:fa_o]}ins#{Mx[:fa_o_c]}"
+Mx[:fa_insert_c]=            "#{Mx[:fa_c_o]}ins#{Mx[:fa_c]}"
+Mx[:fa_strike_o]=            "#{Mx[:fa_o]}del#{Mx[:fa_o_c]}"
+Mx[:fa_strike_c]=            "#{Mx[:fa_c_o]}del#{Mx[:fa_c]}"
+Mx[:fa_superscript_o]=       "#{Mx[:fa_o]}sup#{Mx[:fa_o_c]}"
+Mx[:fa_superscript_c]=       "#{Mx[:fa_c_o]}sup#{Mx[:fa_c]}"
+Mx[:fa_subscript_o]=         "#{Mx[:fa_o]}sub#{Mx[:fa_o_c]}"
+Mx[:fa_subscript_c]=         "#{Mx[:fa_c_o]}sub#{Mx[:fa_c]}"
+Mx[:fa_hilite_o]=            "#{Mx[:fa_o]}hi#{Mx[:fa_o_c]}"
+Mx[:fa_hilite_c]=            "#{Mx[:fa_c_o]}hi#{Mx[:fa_c]}"
+Mx[:fa_monospace_o]=         "#{Mx[:fa_o]}mono#{Mx[:fa_o_c]}"
+Mx[:fa_monospace_c]=         "#{Mx[:fa_c_o]}mono#{Mx[:fa_c]}"
+Mx[:gl_bullet]=              "#{Mx[:gl_o]}●#{Mx[:gl_c]}"
+Mx[:br_endnotes]=            "#{Mx[:mk_o]}ENDNOTES#{Mx[:mk_c]}"
+Mx[:br_eof]=                 "#{Mx[:mk_o]}EOF#{Mx[:mk_c]}"
+Mx[:pa_non_object_dummy_heading]="#{Mx[:pa_o]}-##{Mx[:pa_c]}"                  #unnumbered paragraph, delete when not required [used in dummy headings, eg. for segmented html] (place marker at end of paragraph)
+Mx[:pa_non_object_no_heading]="#{Mx[:pa_o]}~##{Mx[:pa_c]}"                     #unnumbered paragraph (place marker at end of paragraph)
+Hx={
+  br_obj:                    { obj: Mx[:br_obj] },                             # line sep
+  br_page_line:              { obj: Mx[:br_page_line] },                       # line across page
+  br_page:                   { obj: Mx[:br_page] },                            # newpage
+  br_page_new:               { obj: Mx[:br_page_new] },                        # clearpage
+}
+#Mx[:sm_set_o]='∈ '; Mx[:sm_set_c]='∋ '
+#Mx[:sm_subset_o]='∈ '; Mx[:sm_subset_c]='∋ '
+Rx={
+  mx_fa_clean:               /#{Mx[:fa_o]}.+?#{Mx[:fa_c]}|#{Mx[:pa_o]}.+?#{Mx[:pa_c]}|#{Mx[:mk_o]}.+?#{Mx[:mk_c]}/,
+  lv:                        /〔([0-9]):(\S*?)〕/,
+  lv_0:                      /#{Mx[:lv_o_0]}(\S*?)#{Mx[:lv_c]}/,
+  lv_1:                      /#{Mx[:lv_o_1]}(\S*?)#{Mx[:lv_c]}/,
+  lv_2:                      /#{Mx[:lv_o_2]}(\S*?)#{Mx[:lv_c]}/,
+  lv_3:                      /#{Mx[:lv_o_3]}(\S*?)#{Mx[:lv_c]}/,
+  lv_4:                      /#{Mx[:lv_o_4]}(\S*?)#{Mx[:lv_c]}/,
+  lv_5:                      /#{Mx[:lv_o_5]}(\S*?)#{Mx[:lv_c]}/,
+  lv_6:                      /#{Mx[:lv_o_6]}(\S*?)#{Mx[:lv_c]}/,
+  lv_7:                      /#{Mx[:lv_o_7]}(\S*?)#{Mx[:lv_c]}/,
+  lv_8:                      /#{Mx[:lv_o_8]}(\S*?)#{Mx[:lv_c]}/,
+  lv_9:                      /#{Mx[:lv_o_9]}(\S*?)#{Mx[:lv_c]}/,
+  meta:                      /#{Mx[:meta_o]}(\S+?)#{Mx[:meta_c]}/,
+}
+Dx={
+  ocn_o:                     '「',         ocn_c:                   '」',
+  url_o:                     '‹',          url_c:                   '›',
+  url_o_xml:                 '&lt;',       url_c_xml:               '&gt;',
+  rel_o:                     '‹',          rel_c:                   '›',
+  lt_xml:                    '&lt;',       gt_xml:                  '&gt;',
+}
+Tex={
+  backslash:                 "\\\\",
+  backslash:                 "\\\\",
+  tilde:                     '\\\\\\~',
+}
+Px={
+  bold_o:                    '*',          bold_c:                   '*',
+  italics_o:                 '/',          italics_c:                '/',
+  underscore_o:              '_',          underscore_c:             '_',
+ #emphasis_o:                '*',          emphasis_c:               '*',
+ #bold_o:                    '!',          bold_c:                   '!',
+  cite_o:                    '"',          cite_c:                   '"',
+  insert_o:                  '+',          insert_c:                 '+',
+  strike_o:                  '-',          strike_c:                 '-',
+  superscript_o:             '^',          superscript_c:            '^',
+  subscript_o:               '[',          subscript_c:              ']',
+  hilite_o:                  '*',          hilite_c:                 '*',
+  monospace_o:               '',           monospace_c:              '',
+  lng_lst:                   SiSU_is.language_list?,
+  lng_lst_rgx:               SiSU_is.language_list_regex?,
+  lv1:                       '*',
+  lv2:                       '=',
+  lv3:                       '=',
+  lv4:                       '-',
+  lv5:                       '.',
+  lv6:                       '.',
+}
+Px[:lng_lst_rgx]=Px[:lng_lst].join('|')
+Ep={
+  alt:                       :on,
+  d_oebps:                   'OEBPS',
+  d_image:                   'OEBPS/image',
+  d_css:                     'OEBPS/css',
+  f_ncx:                     'toc.ncx',
+  f_opf:                     'content.opf',
+}
+$ep=if Ep[:alt]==:on
+  {
+    o:   'opf:',
+    hsp: ' ',
+  }
+else
+  {
+    o:   '',
+    hsp: '&nbsp;',
+  }
+end
+Db={
+  name_prefix:               "SiSU.#{SiSU_is.version_major?}a.",
+  name_prefix_db:            "sisu_#{SiSU_is.version_major?}a_",
+  col_title:                  800,
+  col_title_part:             400,
+  col_title_edition:           10,
+  col_name:                   600,
+  col_creator_misc_short:     100,
+  col_language:               100,
+  col_language_char:            6,
+  col_date_text:               10,
+  col_txt_long:               600,
+  col_txt_short:              200,
+  col_identify_hash:          256,
+  col_library:                 30,
+  col_small:                   16,
+  col_filename:               256,
+  col_digest:                 128,
+  col_filesize:                10,
+  col_info_note:             2500,
+}
+Gt={
+  grotto:                    'sisu_src',
+  git:                       'sisu:',
+  src:                       'src',
+  pods:                      'pods',
+  sisupod:                   'sisupod',
+  pod:                       'pod',
+  files:                     'files',
+  doc:                       'doc',
+  po:                        'po4a/po',
+  pot:                       'po4a/pot',
+  image:                     'image',
+  audio:                     'audio',
+  video:                     'video',
+  conf:                      'doc/_sisu',
+}
+S_CONF={
+  header_make: 'sisu_document_make',
+  rc_yml: 'sisurc.yml',
+}
+ANSI_C={
+  red:                       "\033[#{31}m",
+  green:                     "\033[#{32}m",
+  yellow:                    "\033[#{33}m",
+  blue:                      "\033[#{34}m",
+  fuchsia:                   "\033[#{35}m",
+  cyan:                      "\033[#{36}m",
+  inv_red:                   "\033[#{41}m",
+  inv_green:                 "\033[#{42}m",
+  inv_yellow:                "\033[#{43}m",
+  inv_blue:                  "\033[#{44}m",
+  inv_fuchsia:               "\033[#{45}m",
+  inv_cyan:                  "\033[#{46}m",
+  b_red:                     "\033[#{91}m",
+  b_green:                   "\033[#{92}m",
+  b_yellow:                  "\033[#{93}m",
+  b_blue:                    "\033[#{94}m",
+  b_fuchsia:                 "\033[#{95}m",
+  b_cyan:                    "\033[#{96}m",
+  off:                       "\033[m"
+}
+DISABLE={
+  epub: {
+    internal_navigation:     true,
+    per_section_title:       true,
+    ncx_navpoint_unique_id:  true,
+  },
+}
+DEVELOPER={
+  maintenance:               :false,
+  under_construction:        '_CONSTRUCTION_ZONE',
+}
+__END__
+utils.rb
+consider:
+  〔comment〕
+  〔links?????〕
+   import document?
+check:
+  bold line
+
+┆┆⋮┇┊┋
+『』
+「」
+〔〕
+【】
+
+·
+¤
+ #˝ " λ Ω  β α π Ѫ Ж Я Ѳ ѳ Ф ✠ ㈣
+ Ѳ  ѳ   Ф
+ ♩ ♭   ✠   ▭  ▬  ▪
+【】〖〗◢ ◣ ◀ ▶ ◘ ◙ « ▲ »
+《》「」
+ ‹ › ∗  ∴ ∷
+'〔lv1〕','〔lv2〕','〔lv3〕','〔lv4〕','〔lv5〕','〔lv6〕','〔lv7〕','〔lv8〕','〔lv9〕'
+'〔 Ѳ1〕','〔 Ѳ2〕','〔 Ѳ3〕','〔 Ѳ4〕','〔 Ѳ5〕','〔Ѳ6〕','〔Ѳ7〕','〔Ѳ8〕','〔Ѳ9〕'
+◁▷
+◀this is text or an image▶ http://
+p __FILE__ +':'+ __LINE__.to_s
+p __FILE__ + ' ' + __LINE__.to_s + ' ' + html
+puts "#{__FILE__} #{__LINE__} #{o.inspect}"
+puts __FILE__ + ' ' + __LINE__.to_s + '-->  ' + o.inspect
+puts %{-\t#{__FILE__}::#{__LINE__}::#{caller}:\n"#{name}"}
+p "\t" + txt.obj + " << #{__FILE__} #{__LINE__} >>"
+p (__FILE__ + ' ' + __LINE__.to_s + '--> ' + dob.inspect) if dob.is==:heading
+data.each {|o| p (__FILE__ + ' ' + __LINE__.to_s + '--> ' + o.inspect) if o.is==:heading}
+puts "#{__FILE__} #{__LINE__} #{para}" if @opt.act[:maintenance][:set]==:on
+puts "#{__FILE__} #{__LINE__} #{t_o}" if @opt.act[:maintenance][:set]==:on
+ dr ┌  9484   dR ┍  9485   Dr ┎  9486   DR ┏  9487   dl ┐  9488   dL ┑  9489   Dl ┒  9490   LD ┓  9491  ur └  9492   uR ┕  9493   Ur ┖  9494   UR ┗  9495   ul ┘  9496   uL ┙  9497   Ul ┚  9498   UL ┛  9499   vr ├
+ dr ┌  9484   dR ┍  9485   Dr ┎  9486   DR ┏  9487   dl ┐  9488   dL ┑  9489   Dl ┒  9490   LD ┓  9491  ur └  9492   uR ┕  9493   Ur ┖  9494   UR ┗  9495   ul ┘  9496   uL ┙  9497   Ul ┚  9498   UL ┛  9499   vr ├
+ └  ┘
+Iu ⌠  8992   Il ⌡ <7 ⌈  8968   >7 ⌉  8969   7< ⌊  8970   7> ⌋  8971
+<" 『 12302  >" 』 12303
+<' 「 12300  >' 」 12301
+#+END_SRC
+
+* generic
+** generic_parts.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/generic_parts.rb"
+# <<sisu_document_header>>
+module SiSU_Parts_Generic
+  def the_url
+    def urify(uri)
+      URI.parse(uri)
+    end
+    def sisu
+      'http://www.sisudoc.org/'
+    end
+    def sisudoc
+      'http://www.sisudoc.org'
+    end
+    def footer_signature
+      'http://www.sisudoc.org/'
+    end
+    def rl_root
+      '/sisu' #watch
+    end
+    def root_http
+      'http://www.sisudoc.org/' #watch
+    end
+    def home
+      'http://www.sisudoc.org/' # used in pdf header
+    end
+    def site #used as stub... where there are subdirectories and is different from home
+      home
+    end
+    def home_txt
+      'www.sisudoc.org'
+    end
+    def sisu_txt
+      'www.sisudoc.org'
+    end
+    self
+  end
+  def the_text
+    def home
+      'SiSU'
+    end
+    def txt_hp
+      '&nbsp;SiSU'
+    end
+    def txt_hp_alias
+      'SiSU'
+    end
+    def txt_home
+      'SiSU'
+    end
+    def txt_signature # used in latex/pdf footer
+      'SiSU'
+    end
+    def url_open
+      '<'
+    end
+    def url_close
+      '>'
+    end
+    self
+  end
+  def the_icon
+    def i_ico
+      'rb7.ico'
+    end
+    def i_home_button
+      'sisu.png'
+    end
+    def i_choice
+      'b_choice.png'
+    end
+    def i_new
+      'b_new.png'
+    end
+    self
+  end
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    shared
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/sisu.org b/org/sisu.org
new file mode 100644
index 00000000..10b7f3e9
--- /dev/null
+++ b/org/sisu.org
@@ -0,0 +1,128 @@
+-*- mode: org -*-
+#+TITLE:       sisu
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:
+#+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
+
+[[./sisu_info.org][sisu_info.org]]  [[./][org/]]
+[[./sisu_build.org][make/build]] VERSION
+
+* version.txt (set version) :version:
+** set program tangle
+
+#+BEGIN_SRC txt  :NO-tangle "../views/version.txt"
+<<sisu_version_current_set>>
+#+END_SRC
+
+* sisu.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu.rb"
+# <<sisu_document_header>>
+module SiSU_libs
+  require_relative 'sisu/hub'                               # sisu/hub.rb
+  require_relative 'sisu/se'                                # sisu/se.rb
+  require_relative 'sisu/utils'                             # sisu/utils.rb
+  class CallHubMaster
+    def initialize(argv,sisu_runtime)
+      begin
+        SiSU::HubMaster.new(argv,sisu_runtime)
+      rescue
+        SiSU_Screen::Ansi.new(argv).rescue do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        Dir.chdir(sisu_runtime[:call_path])
+      end
+    end
+  end
+  class HubClose
+    def initialize(argv,call_path)
+      begin
+        env=SiSU_Env::InfoEnv.new
+      rescue
+      ensure
+        if FileTest.directory?(env.processing_path.processing) \
+        and FileTest.directory?(env.processing_path.processing_base_tmp) \
+        and env.processing_path.processing_base_tmp =~/#{env.processing_path.processing}/ \
+        and env.processing_path.processing_base_tmp =~/^\/tmp\/\S+/ \
+        and not argv.inspect =~/"--maintenance"|"-M"/
+          FileUtils::cd(env.processing_path.processing_base_tmp) do
+            FileUtils::rm_rf('.')
+          end
+        end
+        Dir.chdir(call_path)
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    sisu
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/src.org b/org/src.org
new file mode 100644
index 00000000..cb74f8bb
--- /dev/null
+++ b/org/src.org
@@ -0,0 +1,3437 @@
+-*- mode: org -*-
+#+TITLE:       sisu src
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:src:
+#+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
+
+* src_sisupod_make.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/src_sisupod_make.rb"
+# <<sisu_document_header>>
+module SiSU_Doc
+  require_relative 'src_shared'                         # scr_shared.rb
+    include SiSU_Source
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  class Source < SiSU_Source::SiSUpodSource
+    require_relative 'utils_response'                   # utils_response.rb
+    def initialize(opt,build=nil,place=nil)
+      super(opt,build,place)
+      @zipfile=@opt.fno.gsub(/(?:\~\S{2,3})?(\.ss[tm])$/,'\1')
+      unless @opt.act[:quiet][:set]==:on
+        pthinfo="#{@file.output_path.sisupod.dir}/#{@zipfile}.txz"
+        (@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on) \
+        ? SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'Assemble source for sisu document',
+            "#{@opt.fns} -> file://#{pthinfo}"
+          ).cyan_hi_blue
+        : SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'Assemble source for sisu document',
+            pthinfo
+          ).cyan_title_hi
+      end
+    end
+    def sisupod_tar_xz
+      begin
+        FileUtils::mkdir_p(@file.output_path.sisupod.dir) \
+          unless FileTest.directory?(@file.output_path.sisupod.dir)
+        tree=((@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on) \
+        && SiSU_Env::SystemCall.new.program_found?('tree')) \
+        ? 'tree sisupod'
+        : ''
+        if FileTest.directory?(@path_pod[:fnb])
+          Dir.chdir(@path_pod[:fnb])
+          system(%{
+            #{tree}
+            tar -cJf #{@zipfile}.txz sisupod
+            #echo "#{@file.place_file.sisupod.dir}"
+          })
+          FileUtils::mv("#{@zipfile}.txz",@file.place_file.sisupod.dir)
+          Dir.chdir(@env.path.pwd)
+          if (@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on)
+            SiSU_Screen::Ansi.new('',"#{@opt.fns}.txz").blue_tab
+          end
+        else
+          if (@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on)
+            SiSU_Screen::Ansi.new('',"#{@opt.fns}.txz not built").blue_tab
+          end
+        end
+      rescue
+      ensure
+      end
+    end
+  end
+end
+__END__
+question?:                   should you permit the packing of multiple documents in single .xz ?
+
+  open @opt.fns, parse file
+    extract from file content:
+      images and copy each image from whatever image source to _sisu/sisupod/sisu/_sisu/image
+
+   remove previously existing contents of _/sisu/sisupod &
+   make directory structure:
+
+v3 -->
+   _sisu
+     sisupod
+       doc
+         manifest.txt
+         en/content.sst                [file content]
+         fr/content.sst
+         _sisu
+           conf
+           image (ln -s ../../image)
+           audio (ln -s ../../audio)
+           video (ln -s ../../video)
+       image                           [all images for specific document gathered here]
+       audio
+       video
+
+v2 -->
+   _sisu
+     sisupod
+       content.sst                     [file content]
+       filename.sst                    [link to content.sst]
+       _sisu/
+         image/                        [all images for specific document gathered here]
+
+sisu
+  _sisu
+    sisurc.yml
+    convert/
+    standard_terms/
+    image
+    processing
+      ao/
+      tex/
+      texinfo/
+      tune/
+    sisupod
+
+special case
+
+composite file (master), e.g.
+SiSU.ssm
+#+END_SRC
+
+* src_sisupod_sstm.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/src_sisupod_sstm.rb"
+# <<sisu_document_header>>
+module SiSU_Markup
+  require_relative 'src_shared'                         # src_shared.rb
+    include SiSU_Source
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  class Source_Sisupod < SiSU_Source::SiSUpodSource
+    def initialize(opt,build=nil,place=nil)
+      super(opt,build,place)
+      @opt=opt
+    end
+    def read
+      unless @opt.act[:quiet][:set]==:on
+        (@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on) \
+        ? SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'Share document markup text source',
+            @opt.fns
+          ).cyan_hi_blue
+        : SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'Share document markup text source',
+            @opt.fns
+          ).cyan_title_hi
+      end
+      if FileTest.directory?(@path_pod[:fnb])
+        FileUtils::mkdir_p(@file.output_path.src.dir) \
+          unless FileTest.directory?(@file.output_path.src.dir)
+        v=(@opt.act[:maintenance][:set]==:on) \
+        ? 'v' : ''
+        system(%{
+          rsync -a#{v} #{@path_pod[:fnb]} #{@file.output_path.sisupod.dir}
+          chbk=`pwd`
+          cd #{@file.output_path.sisupod.dir}
+          for I in `find -type d` ; do chmod 755 $I ; done
+          for I in `find -type f` ; do chmod 644 $I ; done
+          cd ${chbk}
+        })
+      else
+        if (@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on)
+          SiSU_Screen::Ansi.new(
+            '',
+            "#{@opt.fno} not available"
+          ).blue_tab
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* src_kdissert_share.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/src_kdissert_share.rb"
+# <<sisu_document_header>>
+module SiSU_KdiSource
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  class Source
+    begin
+      require 'fileutils'
+        include FileUtils
+    rescue LoadError
+      SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+        error('fileutils NOT FOUND (LoadError)')
+    end
+    def initialize(opt)
+      @opt=opt
+      @env=SiSU_Env::InfoEnv.new(@opt.fns)
+      @output_path="#{@env.path.output}/#{@opt.fnb}"
+    end
+    def read
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        'Share Kdissert Source Document!',
+        @opt.fnb
+      ).green_hi_blue unless @opt.act[:quiet][:set]==:on
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        "Copy kdissert file to output directory",
+        "#{@opt.fnb} -> #{@output_path}"
+      ).warn unless @opt.act[:quiet][:set]==:on
+      FileUtils::mkdir_p(@env.path.output) unless FileTest.directory?(@env.path.output)
+      FileUtils::mkdir_p(@output_path) unless FileTest.directory?(@output_path)
+      if FileTest.directory?(@output_path)
+        if @opt.fns =~/\.kdi\._sst$/ \
+        and FileTest.file?(@opt.fnb)
+          FileUtils::cp(@opt.fnb,@output_path)
+        end
+      else
+        SiSU_Screen::Ansi.new(
+          @opt.act[:color_state][:set],
+          "Output directory does not exist",
+          "#{@opt.fnb} -> #{@output_path}"
+        ).warn unless @opt.act[:quiet][:set]==:on
+        exit
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* src_po4a_share.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/src_po4a_share.rb"
+# <<sisu_document_header>>
+module SiSU_Languages_Selected
+  require_relative 'utils_response'                   # utils_response.rb
+  def language
+    def sisu_languages_available
+      Px[:lng_lst]
+    end
+    def source_language_selected_str
+      @opt.act[:po4a_lang][:src] \
+      ? @opt.act[:po4a_lang][:src]
+      : 'en'
+    end
+    def translation_languages_selected
+      @opt.act[:po4a_lang][:trn] \
+      ? @opt.act[:po4a_lang][:trn]
+      : []
+    end
+    def translation_languages_available
+      sisu_languages_available - [source_language_selected_str]
+    end
+    def translation_languages_selected_that_are_available
+      translation_languages_selected & sisu_languages_available
+    end
+    def translation_languages_selected_that_are_available_str
+      translation_languages_selected_that_are_available.join(' ')
+    end
+    def translation_languages_selected_str
+      @opt.act[:po4a_lang][:trn].join(' ')
+    end
+    self
+  end
+end
+module SiSU_Po4a_Project
+  class Po4aCfg
+    include SiSU_Composite_Doc_Utils                    # composite doc, .ssm, extract all related insert files, array of filenames test
+    include SiSU_Response
+    include SiSU_Languages_Selected
+    def initialize(opt,file)
+      @opt,@file=opt,file
+    end
+    def song
+      if @opt.lng==language.source_language_selected_str
+        ans=response?('po4a config file')
+        if ans
+          po4a_cfg
+        end
+      end
+    end
+    def po4a_cfg_filename
+      'po4a.cfg'
+    end
+    def dir
+      def pwd
+        Dir.pwd
+      end
+      def po4a_
+        'po4a/' # ''
+      end
+      def pot
+        #po4a_ + 'pot'
+        'pot'
+      end
+      def po
+        #po4a_ + 'po'
+        'po'
+      end
+      self
+    end
+    def po4a_cfg_file
+      File.open("#{Dir.pwd}/#{po4a_cfg_filename}",'w')
+    end
+    def po4a_cfg
+      lng=language.source_language_selected_str
+      doc_import_list=composite_and_imported_filenames_array(@opt.fno)
+      po4a_cfg_arr=[]
+      po4a_cfg_arr \
+        << "[po4a_langs] #{language.translation_languages_selected_that_are_available_str}"
+      po4a_cfg_arr \
+        << "[po4a_paths] #{dir.pot}/$master.pot $lang:#{dir.po}/$lang/$master.po"
+      doc_import_list.each do |file_src|
+        file_src_fn=
+          file_src.gsub(/#{language.source_language_selected_str}\//,'')
+        po4a_cfg_arr \
+          << "[type: text] #{lng}/#{file_src} $lang:$lang/#{file_src_fn}"
+      end
+      file=@file.write_file.po4a_cfg
+      po4a_cfg_arr.each do |txt|
+      puts txt
+        file << txt << "\n"
+      end
+      file.close
+    end
+  end
+  class Po4aProject
+    include SiSU_Languages_Selected
+    include SiSU_Response
+    def initialize(opt,file)
+      @opt,@file=opt,file
+    end
+    def song
+      make_paths
+      if FileTest.directory?(@file.output_path.po4a.dir)
+        Dir.chdir(@file.output_path.po4a.dir)
+        dirs=Dir['*/']
+        dirs_language=[]
+        dirs.each do |x|
+          dirs_language << x.gsub(/\/$/,'')
+        end
+        dirs_translation = \
+          (language.translation_languages_available & dirs_language)
+      end
+      if (language.translation_languages_available & [@opt.lng]).length == 1
+        puts %{gettext for: #{dirs_translation}
+in #{Dir.pwd}}
+        ans=response?('gettext?')
+        if ans
+          gettext_if_any_build_src_trans_po
+        end
+      end
+      ans=response?('build project?')
+      if ans
+        build_src_master_to_pot_and_po_and_srcs
+      end
+    end
+    def flags
+      def debug
+        '-d -v'
+      end
+      def normal
+        ''
+      end
+      def quiet
+        '-q'
+      end
+      self
+    end
+    def build_src_master_to_pot_and_po_and_srcs
+      if SiSU_Sys_Call::SystemCall.new.po4a
+        pwd=Dir.pwd
+        #cmd='po4a --keep 0 -M UTF-8 --no-backups ' \
+        #+ '--package-name ' \
+        #+ 'sisu-manual' + ' ' \
+        #+ flags.normal + ' ' \
+        #+ filename.po4a_cfg
+        cmd='po4a --keep 0 -M UTF-8' \
+        + flags.normal + ' ' \
+        + @file.base_filename.po4a_cfg
+        Dir.chdir(@file.output_path.po4a.dir)
+        system("
+          cd #{@file.output_path.po4a.dir}
+          #{cmd}
+          cd -
+        "); puts cmd
+        Dir.chdir(pwd)
+      end
+    end
+    def gettext_if_any_build_src_trans_po
+        Dir.chdir(@file.output_path.po4a.dir)
+        dirs=Dir['*/']
+        dirs_language=[]
+        dirs.each do |x|
+          dirs_language << x.gsub(/\/$/,'')
+        end
+        dirs_translation = \
+          (language.translation_languages_available & dirs_language)
+        files_src=Dir.glob("./#{source_language_selected_str}/*.ss[tmi]")
+        dirs_translation.each do |lng|
+          files_src.each do |file|
+            fn=file.gsub(/\.\/#{source_language_selected_str}\//,'')
+            system("
+              po4a-gettextize -f text -M utf-8 \
+              -m ./#{source_language_selected_str}/#{fn} \
+              -l ./#{lng}/#{fn} \
+              -p ./po/#{lng}/#{fn}.po
+            ")
+            puts fn
+          end
+        end
+    end
+    def dir_mk(dir)
+      unless FileTest.directory?(dir)
+        FileUtils::mkdir_p(dir)
+      end
+    end
+    def make_paths
+      dir_mk(@file.output_path.pot.dir)
+      dir_mk(@file.output_path.po.dir)
+    end
+    def clean
+      #rm -f po/*/*.po~
+      #rm -rf ../build
+      FileUtils.rm_f Dir.glob("./#{dir.po}/*/*.po~")
+    end
+    def distclean
+      #rm -f po4a.cfg
+      #rm -rf $(LANGUAGES)
+      FileUtils::rm_f(filename.po4a_cfg)
+      FileUtils::rm_r(language.possible_translations,:force => true)
+      #FileUtils::rm_r(language.translation_languages_selected_that_are_available,:force => true)
+    end
+  end
+  class Po4aDistClean
+    include SiSU_Languages_Selected
+    include SiSU_Response
+    def initialize(opt,file)
+      @opt,@file=opt,file
+    end
+    def song
+      pwd=Dir.pwd
+      if FileTest.directory?(@file.output_path.po4a.dir)
+        Dir.chdir(@file.output_path.po4a.dir)
+        dirs=Dir['*/']
+        dirs_language=[]
+        dirs.each do |x|
+          dirs_language << x.gsub(/\/$/,'')
+        end
+        dirs_translation = \
+          (language.translation_languages_available & dirs_language)
+        if dirs_translation.length > 0
+          puts %{remove language translation directorie(s): #{dirs_translation}
+in #{Dir  .pwd}}
+          ans=response?('disclean?')
+          if ans
+            FileUtils::rm_f(@file.base_filename.po4a_cfg)
+            FileUtils::rm_r(dirs_translation,:force => true)
+            #FileUtils::rm_r(language.translation_languages_available,:force => true)
+          end
+        end
+        Dir.chdir(pwd)
+      end
+    end
+  end
+end
+#end
+__END__
+REMOVE
+&#033;\|&#035;\|&&#042;\|&#045;\|&#047;\|&#095;\|&#123;\|&#125;\|&#126;\|&#
+
+tables are problematic, difficult to reconstitute instruction, check
+
+metadata, move to top? and work on
+
+footnotes, different types, asterisk, also do you want to have separate
+paragraphs, or breaks within one block?
+
+where no ocn appropriately use ~# or -# or indeed 1~name-
+
+comments in document, what to do about them, not sure they are currently
+retained in dal, could be quite valuable to keep
+
+Translate Shell
+http://www.soimort.org/translate-shell/
+translate.google.com
+#+END_SRC
+
+* src_po4a_shelf.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/src_po4a_shelf.rb"
+# <<sisu_document_header>>
+module SiSU_Po4a
+  require_relative 'ao'                                 # ao.rb
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'ao_composite'                       # ao_composite.rb
+  require_relative 'shared_metadata'                    # shared_metadata.rb
+  require_relative 'src_po4a_shelf_set'                 # src_po4a_shelf_set.rb
+  include SiSU_Param
+  require_relative 'object_munge'                       # object_munge.rb
+  require_relative 'utils_composite'                    # utils_composite.rb
+  class Source
+    include SiSU_Object_Munge
+    @@opt_src,@@opt_trn,@@opt_src_,@@opt_trn_,@@md_src,@@md_trn=
+          nil,      nil,       nil,       nil,     nil,     nil
+    @@auto_translation_ = :go
+    def initialize(opt,fn=nil)
+      @opt,@fn=opt,fn
+      #unless @opt.fns =~/(.+?\.(?:-|ssm\.)?sst)$/
+      #  puts "#{@opt.fns} not a processed file type"
+      #end
+      file_arr=SiSU_Info_Env::InfoEnv.new.source_file_processing_array(@opt.fns)
+      SiSU_Param::Parameters::Instructions.new(file_arr,@opt).extract
+      r=Px[:lng_lst_rgx].gsub(/\|en\|/,'|')
+      @lang_regx=%r{(?:#{r})}
+      if opt.fns =~/\S+?~#{@lang_regx}\.ss[mti]/ \
+      and opt.f_pth[:lng]!=@opt.lng_base
+        @@opt_src_=false
+        @@opt_trn=opt
+        @@md_trn=SiSU_Param::Parameters.new(opt).get
+      else
+        @@opt_src_=true
+        @@opt_src=opt
+        @@md_src=SiSU_Param::Parameters.new(opt).get
+      end
+    end
+    def wrap_width_set(md,env)
+      if defined? md.make.plaintext_wrap \
+      and md.make.plaintext_wrap
+        md.make.plaintext_wrap
+      elsif defined? env.plaintext_wrap \
+      and env.plaintext_wrap
+        env.plaintext_wrap
+      else 78
+      end
+    end
+    def process_file(md,env,file,wrap_width,fn)
+      unless @opt.act[:quiet][:set]==:on
+        tool=(@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on) \
+        ? "#{env.program.text_editor} #{file.output_path.pot.dir}/"
+        : @opt.fns
+        (@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on) \
+        ? SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'Pot po4a',
+            tool
+          ).green_hi_blue
+        : SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'Pot po4a',
+            tool
+          ).green_title_hi
+        if (@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on)
+          SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            @opt.fns,
+            file.output_path.pot.dir
+          ).flow
+        end
+      end
+      if @opt.fns =~/\S+?~#{@lang_regx}\.ss[mti]/ \
+      or @opt.f_pth[:lng] !=@opt.lng_base
+        opt_lang_trn_fn=fn
+        @ao_arr_lang_trans=
+          SiSU_AO::Source.new(@opt,opt_lang_trn_fn,:po4a).get # ao file drawn here
+        opt_lang_src_fn=(fn =~/\S+?~\S{2}(?:_\S{2})?\.ss[mti]/) \
+        ? (fn.gsub(/(\S+?)~\S{2}(?:_\S{2})?(\.ss[mti])/,'\1\2')) #check i
+        : fn
+        transdir,srcdir=Dir.pwd,Dir.pwd
+        if Dir.pwd.to_s =~/\/#{@lang_regx}$/
+          transdir=Dir.pwd
+          srcdir=transdir.
+            gsub(/\/#{@lang_regx}$/,
+              "/#{@opt.lng_base}")
+          if FileTest.directory?(srcdir)
+            Dir.chdir(srcdir)
+          end
+        else nil
+        end
+        if FileTest.file?("#{srcdir}/#{opt_lang_src_fn}")
+          @ao_arr_lang_src=
+            SiSU_AO::Source.new(
+              @@opt_src,
+              opt_lang_src_fn,
+              :po4a
+            ).get # ao file drawn here
+        else
+          puts "no identified source document"
+          exit
+        end
+        Dir.chdir(transdir) if transdir
+      else
+        @ao_arr_lang_src=
+          SiSU_AO::Source.new(
+            @opt,
+            fn,
+            :po4a
+          ).get # ao file drawn here
+        @ao_arr_lang_trans=nil
+      end
+      SiSU_Po4a::Source::Scroll.new(
+        fn,
+        @ao_arr_lang_src,
+        @ao_arr_lang_trans,
+        @@md_src,
+        @@md_trn,
+        wrap_width
+      ).songsheet
+    end
+    def read
+      begin
+        src={}
+        src[:pth]=@opt.f_pth[:pth]
+        src[:files]=if @opt.fns =~ /\.(?:(?:-|ssm\.)sst|ssm)$/
+          @opt.fns=@opt.fns.gsub(/\.ssm\.sst$/,'.ssm')
+          SiSU_Assemble::CompositeFileList.new(@opt).read
+        else
+          [@opt.fns]
+        end
+        md=SiSU_Param::Parameters.new(@opt).get
+        env=SiSU_Env::InfoEnv.new(@opt.fns)
+        file=SiSU_Env::FileOp.new(md)
+        Po4aCfg.new(@opt,file).po4a_cfg
+        wrap_width=wrap_width_set(md,env)
+        src[:files].each do |fn|
+          process_file(md,env,file,wrap_width,fn)
+        end
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    private
+    class Scroll <Source
+      include SiSU_Po4aUtils
+      @@endnotes={ para: [], end: [] }
+      def initialize(fn,data_src,data_trn,md_src,md_trn,wrap_width)
+        @fn,@data_src,@data_trn,@md_src,@md_trn,@wrap_width=
+         fn, data_src, data_trn, md_src, md_trn, wrap_width
+        @md=(md_trn.nil?) \
+        ? md_src
+        : md_trn
+        @tab="\t"
+        @@endnotes_=(@md.opt.selections.str =~/--endnote/) \
+        ? true
+        : false    # --footnote
+        @pot={
+          body: [],
+          open: [],
+          close: [],
+          head: [],
+          metadata: [],
+          tail: []
+        }
+      end
+      def br
+        (@md.opt.selections.str =~/--dos/) ? "\r\n" : "\n"  # --unix
+      end
+      def songsheet
+        fn=@fn
+        pot=pot_markup(@data_src,@data_trn)
+        publish(fn,pot)
+      end
+      def pot_structure_wrap(desc,orig,trans,indent=0,hang=0)
+        SiSU_Po4aUtils::Wrap.new(
+          @md,
+          orig,
+          trans,
+          desc,
+          @wrap_width,
+          indent,
+          hang
+        )
+      end
+      def wrap_endnotes(orig_notes='',trn_notes='')
+        nt=@@endnotes_ ? 'endnote' : 'footnote'
+        @fn=0
+        a_l=orig_notes.length
+        0.upto(a_l-1) do |i|
+          @fn=if orig_notes[i].to_s =~/^\^~([\d*+]+)/ # provides endnote number within paragraph
+            @fn += 1
+          else @fn
+          end
+          d="#{nt} #{@fn}"
+          mark="^~ "
+          instruct=s_mark=''
+          if @md.opt.act[:maintenance][:set]==:on
+            instruct=%{\n# footnotes, the preferred sisu markup for a footnote is~{this is a footnote}~ } \
+            + %{however, for translation a footnote reference marker in the text~^ } \
+            + %{with a set of notes following the paragraph starting on a newline with "^~ this is a footnote", } \
+            + %{is easier to deal with, if possible these should be converted back to~{inline notes}~}
+            s_mark="\n# " + %{"\\n\\n#{mark}...\\n\\n"}
+          end
+          desc="#{d}#{s_mark}#{instruct}"
+          orig=(orig_notes[i].to_s =~/^\^~[\d*+]+/) \
+          ? (orig_notes[i].to_s.gsub(/^\^~[\d*+]+/,'^~'))
+          : orig_notes[i].to_s
+          trans=if trn_notes.is_a?(Array) \
+          and trn_notes.length==orig_notes.length
+            (trn_notes[i].to_s =~/^\^~[\d*+]+/) \
+            ? (trn_notes[i].to_s.gsub(/^\^~[\d*+]+/,'^~'))
+            : trn_notes[i].to_s
+          else ''
+          end
+          util=pot_structure_wrap(desc,orig,trans)
+          wrap=util.line_wrap
+          wrap=if wrap =~ /^\s*\^~[\d*+]+\s+.+?\s*\Z/m
+            wrap.gsub(/^\s*(\^~[\d*+]+)\s+(.+?)\s*\Z/m, <<GSUB
+\\1 \\2
+GSUB
+                      )
+          else
+            wrap.gsub(/^(.+)\Z/m, <<GSUB
+\\1
+GSUB
+                      )
+          end
+          @@endnotes[:para] << wrap
+          @@endnotes[:end] << '' << wrap
+        end
+        @@endnotes[:para].each {|e| @pot[:body] << e << br}
+        @@endnotes[:para]=[]
+        @@endnotes
+      end
+      def pot_metadata_src
+        @po4a_identify_type='type: SiSU doc' #'type: Plain text'
+        meta_src=SiSU_Metadata::Summary.new(@md_src)
+        w=[]
+        w << [
+          "#. #{@po4a_identify_type} - metadata: title",
+          "#: en/#{@md.fns}:#{SiSU_Po4aUtils::PotNumber.new.num}",
+          'msgid ""',
+          meta_src.metadata_tags.title.main,
+          meta_src.metadata_tags.title.sub,
+          meta_src.metadata_tags.title.edition,
+          meta_src.metadata_tags.title.note,
+          meta_src.metadata_tags.title.short,
+          meta_src.metadata_tags.title.language,
+          meta_src.metadata_tags.title.language_char,
+          'msgstr ""',
+        ]
+        w << [
+          "#. #{@po4a_identify_type} - metadata: creator",
+          "#: en/#{@md.fns}:#{SiSU_Po4aUtils::PotNumber.new.num}",
+          'msgid ""',
+          meta_src.metadata_tags.creator.head,
+          meta_src.metadata_tags.creator.author,
+          meta_src.metadata_tags.creator.contributor,
+          meta_src.metadata_tags.creator.illustrator,
+          meta_src.metadata_tags.creator.photographer,
+          meta_src.metadata_tags.creator.translator,
+          meta_src.metadata_tags.creator.audio,
+          meta_src.metadata_tags.creator.digitized_by,
+          meta_src.metadata_tags.creator.prepared_by,
+          'msgstr ""',
+        ]
+        w << [
+          "#. #{@po4a_identify_type} - metadata: rights",
+          "#: en/#{@md.fns}:#{SiSU_Po4aUtils::PotNumber.new.num}",
+          'msgid ""',
+          meta_src.metadata_tags.rights.head,
+          meta_src.metadata_tags.rights.copyright.text,
+          meta_src.metadata_tags.rights.copyright.translation,
+          meta_src.metadata_tags.rights.copyright.illustrations,
+          meta_src.metadata_tags.rights.copyright.photographs,
+          meta_src.metadata_tags.rights.copyright.digitization,
+          meta_src.metadata_tags.rights.copyright.audio,
+          meta_src.metadata_tags.rights.license,
+          'msgstr ""',
+        ]
+        w << [
+          "#. #{@po4a_identify_type} - metadata: classify",
+          "#: en/#{@md.fns}:#{SiSU_Po4aUtils::PotNumber.new.num}",
+          'msgid ""',
+          meta_src.metadata_tags.classify.head,
+          meta_src.metadata_tags.classify.subject,
+          meta_src.metadata_tags.classify.topic_register,
+          meta_src.metadata_tags.classify.loc,
+          meta_src.metadata_tags.classify.dewey,
+          #meta_src.metadata_tags.notes.relation,
+          #meta_src.metadata_tags.notes.type,
+          #meta_src.metadata_tags.identifier.oclc,
+          #meta_src.metadata_tags.identifier.isbn,
+          'msgstr ""',
+        ]
+        w << [
+          "#. #{@po4a_identify_type} - metadata: date",
+          "#: en/#{@md.fns}:#{SiSU_Po4aUtils::PotNumber.new.num}",
+          'msgid ""',
+          meta_src.metadata_tags.date.head,
+          meta_src.metadata_tags.date.added_to_site,
+          meta_src.metadata_tags.date.available,
+          meta_src.metadata_tags.date.created,
+          meta_src.metadata_tags.date.issued,
+          meta_src.metadata_tags.date.modified,
+          meta_src.metadata_tags.date.published,
+          meta_src.metadata_tags.date.valid,
+          'msgstr ""',
+        ]
+        w << [
+          "#. #{@po4a_identify_type} - processing, make instruction",
+          "#: en/#{@md.fns}:#{SiSU_Po4aUtils::PotNumber.new.num}",
+          'msgid ""',
+          meta_src.processing_tags.make.language,
+          meta_src.processing_tags.make.headings,
+          meta_src.processing_tags.make.num_top,
+          meta_src.processing_tags.make.breaks,
+          meta_src.processing_tags.make.emphasis,
+          meta_src.processing_tags.make.bold,
+          meta_src.processing_tags.make.italics,
+          meta_src.processing_tags.make.texpdf_font,
+          'msgstr ""',
+        ]
+        w.each do |y|
+          z=''
+          y.each do |x|
+            if x
+              z += x + "\n" if x =~/^#|^msg(?:id|str)/
+              z += %{"#{x}"\n} if x =~/^@\S+?:(?: |$)/
+              z += %{"#{x}"\n} if x =~/^\s+:\S+?: /
+            end
+          end
+          @pot[:metadata] << z << br
+          #puts z unless z.empty?
+        end
+      end
+      def pot_metadata_src_trn
+        @po4a_identify_type='type: SiSU doc'
+        #@po4a_identify_type='type: Plain text'
+        meta_src=SiSU_Metadata::Summary.new(@md_src)
+        meta_trn=SiSU_Metadata::Summary.new(@md_trn)
+        w=[]
+        w << [
+          "#. #{@po4a_identify_type} - metadata: title",
+          "#: en/#{@md.fns}:#{SiSU_Po4aUtils::PotNumber.new.num}",
+          'msgid ""',
+          meta_src.metadata_tags.title.main,
+          meta_src.metadata_tags.title.sub,
+          meta_src.metadata_tags.title.edition,
+          meta_src.metadata_tags.title.note,
+          meta_src.metadata_tags.title.short,
+          meta_src.metadata_tags.title.language,
+          meta_src.metadata_tags.title.language_char,
+          'msgstr ""',
+          meta_trn.metadata_tags.title.main,
+          meta_trn.metadata_tags.title.sub,
+          meta_trn.metadata_tags.title.edition,
+          meta_trn.metadata_tags.title.note,
+          meta_trn.metadata_tags.title.short,
+          meta_trn.metadata_tags.title.language,
+          meta_trn.metadata_tags.title.language_char,
+        ]
+        w << [
+          "#. #{@po4a_identify_type} - metadata: creator",
+          "#: en/#{@md.fns}:#{SiSU_Po4aUtils::PotNumber.new.num}",
+          'msgid ""',
+          meta_src.metadata_tags.creator.head,
+          meta_src.metadata_tags.creator.author,
+          meta_src.metadata_tags.creator.contributor,
+          meta_src.metadata_tags.creator.illustrator,
+          meta_src.metadata_tags.creator.photographer,
+          meta_src.metadata_tags.creator.translator,
+          meta_src.metadata_tags.creator.audio,
+          meta_src.metadata_tags.creator.digitized_by,
+          meta_src.metadata_tags.creator.prepared_by,
+          'msgstr ""',
+          meta_trn.metadata_tags.creator.head,
+          meta_trn.metadata_tags.creator.author,
+          meta_trn.metadata_tags.creator.contributor,
+          meta_trn.metadata_tags.creator.illustrator,
+          meta_trn.metadata_tags.creator.photographer,
+          meta_trn.metadata_tags.creator.translator,
+          meta_trn.metadata_tags.creator.audio,
+          meta_trn.metadata_tags.creator.digitized_by,
+          meta_trn.metadata_tags.creator.prepared_by,
+        ]
+        w << [
+          "#. #{@po4a_identify_type} - metadata: rights",
+          "#: en/#{@md.fns}:#{SiSU_Po4aUtils::PotNumber.new.num}",
+          'msgid ""',
+          meta_src.metadata_tags.rights.head,
+          meta_src.metadata_tags.rights.copyright.text,
+          meta_src.metadata_tags.rights.copyright.translation,
+          meta_src.metadata_tags.rights.copyright.illustrations,
+          meta_src.metadata_tags.rights.copyright.photographs,
+          meta_src.metadata_tags.rights.copyright.digitization,
+          meta_src.metadata_tags.rights.copyright.audio,
+          meta_src.metadata_tags.rights.license,
+          'msgstr ""',
+          meta_trn.metadata_tags.rights.head,
+          meta_trn.metadata_tags.rights.copyright.text,
+          meta_trn.metadata_tags.rights.copyright.translation,
+          meta_trn.metadata_tags.rights.copyright.illustrations,
+          meta_trn.metadata_tags.rights.copyright.photographs,
+          meta_trn.metadata_tags.rights.copyright.digitization,
+          meta_trn.metadata_tags.rights.copyright.audio,
+          meta_trn.metadata_tags.rights.license,
+        ]
+        w << [
+          "#. #{@po4a_identify_type} - metadata: classify",
+          "#: en/#{@md.fns}:#{SiSU_Po4aUtils::PotNumber.new.num}",
+          'msgid ""',
+          meta_src.metadata_tags.classify.head,
+          meta_src.metadata_tags.classify.subject,
+          meta_src.metadata_tags.classify.topic_register,
+          meta_src.metadata_tags.classify.loc,
+          meta_src.metadata_tags.classify.dewey,
+          #meta_src.metadata_tags.notes.relation,
+          #meta_src.metadata_tags.notes.type,
+          #meta_src.metadata_tags.identifier.oclc,
+          #meta_src.metadata_tags.identifier.isbn,
+          'msgstr ""',
+          meta_trn.metadata_tags.classify.head,
+          meta_trn.metadata_tags.classify.subject,
+          meta_trn.metadata_tags.classify.topic_register,
+          meta_trn.metadata_tags.classify.loc,
+          meta_trn.metadata_tags.classify.dewey,
+          #meta_trn.metadata_tags.notes.relation,
+          #meta_trn.metadata_tags.notes.type,
+          #meta_trn.metadata_tags.identifier.oclc,
+          #meta_trn.metadata_tags.identifier.isbn,
+        ]
+        w << [
+          "#. #{@po4a_identify_type} - metadata: date",
+          "#: en/#{@md.fns}:#{SiSU_Po4aUtils::PotNumber.new.num}",
+          'msgid ""',
+          meta_src.metadata_tags.date.head,
+          meta_src.metadata_tags.date.added_to_site,
+          meta_src.metadata_tags.date.available,
+          meta_src.metadata_tags.date.created,
+          meta_src.metadata_tags.date.issued,
+          meta_src.metadata_tags.date.modified,
+          meta_src.metadata_tags.date.published,
+          meta_src.metadata_tags.date.valid,
+          'msgstr ""',
+          meta_trn.metadata_tags.date.head,
+          meta_trn.metadata_tags.date.added_to_site,
+          meta_trn.metadata_tags.date.available,
+          meta_trn.metadata_tags.date.created,
+          meta_trn.metadata_tags.date.issued,
+          meta_trn.metadata_tags.date.modified,
+          meta_trn.metadata_tags.date.published,
+          meta_trn.metadata_tags.date.valid,
+        ]
+        w << [
+          "#. #{@po4a_identify_type} - processing, make instruction",
+          "#: en/#{@md.fns}:#{SiSU_Po4aUtils::PotNumber.new.num}",
+          'msgid ""',
+          meta_src.processing_tags.make.language,
+          meta_src.processing_tags.make.headings,
+          meta_src.processing_tags.make.num_top,
+          meta_src.processing_tags.make.breaks,
+          meta_src.processing_tags.make.emphasis,
+          meta_src.processing_tags.make.bold,
+          meta_src.processing_tags.make.italics,
+          meta_src.processing_tags.make.texpdf_font,
+          'msgstr ""',
+          meta_trn.processing_tags.make.language,
+          meta_trn.processing_tags.make.headings,
+          meta_trn.processing_tags.make.num_top,
+          meta_trn.processing_tags.make.breaks,
+          meta_trn.processing_tags.make.emphasis,
+          meta_trn.processing_tags.make.bold,
+          meta_trn.processing_tags.make.italics,
+          meta_trn.processing_tags.make.texpdf_font,
+        ]
+        w.each do |y|
+          z=''
+          y.each do |x|
+            if x
+              z += x + "\n" if x =~/^#|^msg(?:id|str)/
+              z += %{"#{x}"\n} if x =~/^@\S+?:(?: |$)/
+              z += %{"#{x}"\n} if x =~/^\s+:\S+?: /
+            end
+          end
+          @pot[:metadata] << z << br
+          #puts z unless z.empty?
+        end
+      end
+      def auto_translate?(set_to=nil)
+        @@auto_translation_=
+        if @md.opt.act[:po4a_lang_trans][:set]==:on
+          set_to \
+          ? set_to
+          : @@auto_translation_
+        else :skip
+        end
+      end
+      def auto_translation(src_txt,markup=:src) # check for an appropriate request flag
+        auto_translate?(:skip)
+        begin
+          src_txt_clean=clean_text(src_txt,markup)
+          src_txt_clean=src_txt_clean.
+            gsub(/\n/,' ').
+            gsub(/"/,'\"').
+            gsub(/([()])/,'\\\\\1')
+          trans=''
+          unless auto_translate? == :skip
+            require 'timeout'
+            Timeout::timeout(60) {
+              trans=`trans -b -no-ansi en:#{@md.opt.f_pth[:lng_is]} #{src_txt_clean}`.strip
+              unless trans.empty?
+                trans + ' {[G.Tr]}http://translate.google.com'
+              end
+            }
+          end
+          trans
+        rescue
+          auto_translate?(:skip)
+          p 'timeout issues with translation, skip remaining'
+        end
+      end
+      def pot_structure
+        def heading(dob_src='',notes_s='',dob_trn='',notes_t='')   #% used to extract the structure of a document
+          lv=n=n3=nil
+          lv=dob_src.ln
+          n=lv - 1
+          n3=lv + 2
+          util=nil
+          fn=(dob_src.name=~/[a-z\d]/i) ? dob_src.name : ''
+          mark="#{dob_src.lv}~#{fn} "
+          d="#{dob_src.is.to_s} (level #{dob_src.lv})"
+          instruct=s_mark=''
+          if @md.opt.act[:maintenance][:set]==:on
+            instruct=%{\n# markup for headings is marker at the start of the line/object, } \
+            + %{indicating the heading level, and if provided an associated name tag, } \
+            + %{this heading is "#{mark}"}
+            s_mark="\n# " + %{"\\n\\n#{mark}...\\n\\n"}
+          end
+          desc="#{d}#{s_mark}#{instruct}"
+          orig="#{s_mark}#{dob_src.obj}"
+          trans=((dob_trn=='') \
+          || (dob_src.obj == dob_trn.obj)) \
+          ? ''
+          : "#{s_mark}#{dob_trn.obj}"
+          if @md.opt.f_pth[:lng_is] !=@md.opt.lng_base \
+          and trans.empty? \
+          and auto_translate?
+            trans=auto_translation(dob_src.obj,:src)
+          end
+          util=pot_structure_wrap(desc,orig,trans)
+          wrapped=util.line_wrap
+          @pot[:body] << wrapped << br # main text, contents, body KEEP
+          if @@endnotes[:para] \
+          and notes_s.length > 0 \
+          and not @@endnotes_
+            @pot[:body] << br
+            wrap_endnotes(notes_s,notes_t)
+          elsif @@endnotes[:para] \
+          and @@endnotes_
+            @pot[:body] << br*2
+          end
+        end
+        def para(dob_src='',notes_s='',dob_trn='',notes_t='')      #% used to extract the structure of a document
+          util=nil
+          wrapped=if dob_src.indent =~/[1-9]/ \
+          and dob_src.indent == dob_src.hang
+            s_mark=desc=orig=trans=''
+            if dob_src.bullet_
+              mark="_#{dob_src.indent}* "
+              d="#{dob_src.is.to_s}: indent #{dob_src.indent}, bullet"
+              instruct=s_mark=''
+              if @md.opt.act[:maintenance][:set]==:on
+                instruct=%{\n# markup for indented bullet text is at the start of the line/object, } \
+                + %{an underscore followed by the indent level and an asterisk "#{mark}"}
+                s_mark="\n# " + %{"\\n\\n#{mark}...\\n\\n"}
+              end
+              desc="#{d}#{s_mark}#{instruct}"
+            else
+              mark="_#{dob_src.indent} "
+              d="#{dob_src.is.to_s}: indent #{dob_src.indent}"
+              instruct=s_mark=''
+              if @md.opt.act[:maintenance][:set]==:on
+                instruct=%{\n# markup for indented text is at the start of the line/object, } \
+                + %{an underscore followed by the indent level "#{mark}"}
+                s_mark="\n# " + %{"\\n\\n#{mark}...\\n\\n"}
+              end
+              desc="#{d}#{s_mark}#{instruct}"
+            end
+            orig="#{s_mark}#{dob_src.obj}"
+            trans=((dob_trn=='') \
+            || (dob_src.obj == dob_trn.obj)) \
+            ? ''
+            : "#{s_mark}#{dob_trn.obj}"
+            if @md.opt.f_pth[:lng_is] !=@md.opt.lng_base \
+            and trans.empty? \
+            and auto_translate?
+              trans=auto_translation(dob_src.obj,:src)
+            end
+            util=pot_structure_wrap(desc,orig,trans)
+          elsif dob_src.hang =~/[0-9]/ \
+          and dob_src.indent != dob_src.hang
+            s_mark=desc=orig=trans=''
+            mark="_#{dob_src.hang}_#{dob_src.indent} "
+            d="#{dob_src.is.to_s}: hang #{dob_src.hang} indent #{dob_src.indent}"
+            instruct=s_mark=''
+            if @md.opt.act[:maintenance][:set]==:on
+              instruct=%{\n# markup for indented text with a first line indented } \
+              + %{to a different level from the rest of the paragraph, } \
+              + %{is at the start of the line/object, } \
+              + %{an underscore and the first indent level } \
+              + %{a second underscore and the indent level for the rest of the paragraph, "#{mark1}"}
+              s_mark="\n# " + %{"\\n\\n#{mark}...\\n\\n"}
+            end
+            desc="#{d}#{s_mark}#{instruct}"
+            orig="#{s_mark}#{dob_src.obj}"
+            trans=((dob_trn=='') \
+            || (dob_src.obj == dob_trn.obj)) \
+            ? ''
+            : "#{s_mark}#{dob_trn.obj}"
+            if @md.opt.f_pth[:lng_is] !=@md.opt.lng_base \
+            and trans.empty? \
+            and auto_translate?
+              trans=auto_translation(dob_src.obj,:src)
+            end
+            util=pot_structure_wrap(desc,orig,trans)
+          else
+            s_mark=desc=orig=trans=''
+            if dob_src.bullet_
+              mark='_* '
+              d="#{dob_src.is.to_s}: bullet"
+              instruct=s_mark=''
+              if @md.opt.act[:maintenance][:set]==:on
+                instruct=%{\n# markup for indented text is at the start of the line/object, } \
+                + %{an underscore followed by an asterisk "#{mark}"}
+                s_mark="\n# " + %{"\\n\\n#{mark}...\\n\\n"}
+              end
+              desc="#{d}#{s_mark}#{instruct}"
+              orig="#{s_mark}#{dob_src.obj}"
+              trans=((dob_trn=='') \
+              || (dob_src.obj == dob_trn.obj)) \
+              ? ''
+              : "#{s_mark}#{dob_trn.obj}"
+              if @md.opt.f_pth[:lng_is] !=@md.opt.lng_base \
+              and trans.empty? \
+              and auto_translate?
+                trans=auto_translation(dob_src.obj,:src)
+              end
+            else
+              mark=''
+              d=dob_src.is.to_s
+              instruct=%{\n# regular paragraph, no special markup}
+              if @md.opt.act[:maintenance][:set]==:on
+                instruct="\n# "
+                s_mark="\n# " + %{"\\n\\n#{mark}...\\n\\n"}
+              end
+              desc="#{d}#{s_mark}#{instruct}"
+              orig=dob_src.obj
+              trans=((dob_trn=='') \
+              || (dob_src.obj == dob_trn.obj)) \
+              ? ''
+              : "#{s_mark}#{dob_trn.obj}"
+              if @md.opt.f_pth[:lng_is] !=@md.opt.lng_base \
+              and trans.empty? \
+              and auto_translate?
+                trans=auto_translation(dob_src.obj,:src)
+              end
+            end
+            util=pot_structure_wrap(desc,orig,trans)
+          end
+          wrapped=util.line_wrap
+          @pot[:body] << wrapped << br # main text, contents, body KEEP
+          if @@endnotes[:para] \
+          and notes_s.length > 0 \
+          and not @@endnotes_
+            @pot[:body] << br
+            wrap_endnotes(notes_s,notes_t)
+          elsif @@endnotes[:para] \
+          and @@endnotes_
+            @pot[:body] << br*2
+          end
+        end
+        def block(dob_src='',notes_s='',dob_trn='',notes_t='')     #% used to extract the structure of a document
+          mark="block{\\n\\n...\\n\\n}block"
+          d=dob_src.is.to_s
+          instruct=s_mark=''
+          if @md.opt.act[:maintenance][:set]==:on
+            instruct=%{\n# block text is a text block with an opening and closing marker, } \
+            + %{the content of which may be wrapped}
+            s_mark="\n# " + %{"\\n\\n#{mark}\\n\\n"}
+          end
+          desc="#{d}#{s_mark}#{instruct}"
+          orig=dob_src.obj
+          trans=((dob_trn=='') \
+          || (dob_src.obj == dob_trn.obj)) \
+          ? ''
+          : "#{s_mark}#{dob_trn.obj}"
+          if @md.opt.f_pth[:lng_is] !=@md.opt.lng_base \
+          and trans.empty? \
+          and auto_translate?
+            trans=auto_translation(dob_src.obj,:src)
+          end
+          util=pot_structure_wrap(desc,orig,trans)
+          unwrapped=util.no_line_wrap_block
+          @pot[:body] << unwrapped << br
+        end
+        def group(dob_src='',notes_s='',dob_trn='',notes_t='')     #% used to extract the structure of a document
+          mark="group{\\n\\n...\\n\\n}group"
+          d=dob_src.is.to_s
+          instruct=s_mark=''
+          if @md.opt.act[:maintenance][:set]==:on
+            instruct=%{\n# group text is a text block with an opening and closing marker, } \
+            + %{the content of which may be wrapped}
+            s_mark="\n# " + %{"\\n\\n#{mark}\\n\\n"}
+          end
+          desc="#{d}#{s_mark}#{instruct}"
+          orig=dob_src.obj
+          trans=((dob_trn=='') \
+          || (dob_src.obj == dob_trn.obj)) \
+          ? ''
+          : "#{s_mark}#{dob_trn.obj}"
+          if @md.opt.f_pth[:lng_is] !=@md.opt.lng_base \
+          and trans.empty? \
+          and auto_translate?
+            trans=auto_translation(dob_src.obj,:src)
+          end
+          util=pot_structure_wrap(desc,orig,trans)
+          unwrapped=util.no_line_wrap_block
+          @pot[:body] << unwrapped << br
+        end
+        def verse(dob_src='',notes_s='',dob_trn='',notes_t='')     #% used to extract the structure of a document
+          mark="poem{\n\nverse\n\nverse\n\n...\n\n}poem"
+          d=dob_src.is.to_s
+          instruct=s_mark=''
+          if @md.opt.act[:maintenance][:set]==:on
+            instruct=%{\n# verse are part of the text block described as a poem, } \
+            + %{the first verse is preceeded by an opening marker, } \
+            + %{and the last verse by a closing marker, } \
+            + %{the content of which should remain unwrapped}
+            s_mark="\n# " + %{"\\n\\n#{mark}\\n\\n"}
+          end
+          desc="#{d}#{s_mark}#{instruct}"
+          orig=dob_src.obj
+          trans=(dob_trn=='') ? '' : dob_trn.obj
+          util=pot_structure_wrap(desc,orig,trans)
+          unwrapped=util.no_line_wrap_block
+          @pot[:body] << unwrapped << br
+        end
+        def code(dob_src='',notes_s='',dob_trn='',notes_t='')      #% used to extract the structure of a document
+          mark="code{\\n\\n...\\n\\n}code"
+          d=dob_src.is.to_s
+          instruct=s_mark=''
+          if @md.opt.act[:maintenance][:set]==:on
+            instruct=%{\n# codeblocks are a text block with an opening and closing marker, } \
+            + %{the content of which should remain unwrapped}
+            s_mark="\n# " + %{"\\n\\n#{mark}\\n\\n"}
+          end
+          desc="#{d}#{s_mark}#{instruct}"
+          orig=dob_src.obj
+          trans=(dob_trn=='') ? '' : dob_trn.obj
+          util=pot_structure_wrap(desc,orig,trans)
+          unwrapped=util.no_line_wrap_block
+          @pot[:body] << unwrapped << br
+        end
+        def table(dob_src='',notes_s='',dob_trn='',notes_t='')     #% used to extract the structure of a document
+          mark="table{\\n\\n...\\n\\n}table"
+          d=dob_src.is.to_s
+          instruct=s_mark=''
+          if @md.opt.act[:maintenance][:set]==:on
+            instruct=%{\n# tables are a text block with an opening and closing marker, } \
+            + %{the content of which should remain unwrapped}
+            s_mark="\n# " + %{"\\n\\n#{mark}\\n\\n"}
+          end
+          desc="#{d}#{s_mark}#{instruct}"
+          orig=dob_src.obj
+          orig=orig.gsub(/#{Mx[:tc_c]}/,"\n")
+          trans=(dob_trn=='') ? '' : dob_trn.obj
+          trans=trans.gsub(/#{Mx[:tc_c]}/,"\n")
+          util=pot_structure_wrap(desc,orig,trans)
+          unwrapped=util.no_line_wrap_block
+          @pot[:body] << unwrapped << br
+        end
+        def idx_markup(idx)
+          struct=['={']
+          idx.sort.each do |x|
+            x.each_with_index do |y,i0|
+              case y
+              when String
+                struct << ';' unless struct[-1] =~/=\{/
+                struct << y
+                if x[i0+1].class == Hash \
+                and x[i0+1][:sub].length > 0
+                  struct << ':'
+                end
+              when Hash
+                if y[:plus].to_i > 0
+                  struct << '+' + y[:plus].to_s
+                end
+                if y[:sub].length > 0
+                  y[:sub].each_with_index do |z,i1|
+                    z.each_with_index do |a,i2|
+                      #p a
+                      if z.length > 0
+                        struct << a[0]
+                        if a[1][:plus].to_i > 0
+                          struct << '+' + a[1][:plus].to_s
+                        end
+                        if (i1 + 1) < y[:sub].length
+                          struct << '|'
+                        end
+                      end
+                    end
+                  end
+                end
+              end
+            end
+          end
+          struct << '}'
+          #puts struct.join
+          struct.join
+        end
+        def idx(dob_src='',dob_trn='')                             #% used for book index but broken as original markup lost, already abstracted, fix
+          mark="={ ... }"
+          instruct=s_mark=''
+          if @md.opt.act[:maintenance][:set]==:on
+            instruct=%{\n# the book index should be attached unwrapped to the preceding text block } \
+            + %{(there should be a new line, but no empty line)}
+            s_mark="\n# " + %{"\\n#{mark}\\n\\n"}
+          end
+          d='book-idx'
+          desc="#{d}#{s_mark}#{instruct}"
+          orig=pot_structure.idx_markup(dob_src.idx) #'={' + dob_src.idx + '}'
+          trans=if defined? dob_trn.idx \
+          and not dob_trn.idx.nil? \
+          and not dob_trn.idx.empty?
+            pot_structure.idx_markup(dob_trn.idx) #'={' + dob_trn.idx + '}'
+          else ''
+          end
+          util=pot_structure_wrap(desc,orig,trans)
+          unwrapped=util.no_line_wrap_block
+          @pot[:body] << unwrapped << br
+        end
+        self
+      end
+      def pot_markup(data_src,data_trn)
+        #@endnotes,@copen,@pot_contents_close=Array.new(3){[]}
+        a_l=if data_trn
+        a_l=(data_src.length >= data_trn.length) \
+        ? data_src.length
+        : data_trn.length
+        else
+          data_src.length
+        end
+        s,t=0,0
+        if @md.fns =~ /\.(?:(?:-|ssm\.)?sst|ssm)$/
+          (data_trn.nil?) \
+          ? pot_metadata_src
+          : pot_metadata_src_trn
+        end
+        0.upto(a_l-1) do |i|
+          if data_trn
+            unless data_src[s] \
+            and data_trn[t]
+              break
+            end
+            if data_src[s].of == :comment \
+            and data_trn[t].of == :comment \
+            and (data_src[s].is == data_trn[t].is)
+              s+=1;t+=1
+              next
+            end
+            if ((data_src[s].is == :comment) \
+            || (data_trn[t].is == :comment)) \
+            and (data_src[s].is != data_trn[t].is)
+              if data_src[s].is == :comment
+                if @md.opt.act[:maintenance][:set]==:on
+                  puts "src (comment):\n\t" \
+                  + data_src[s].obj
+                end
+                s+=1
+                #next if data_src[s].is == :comment
+              elsif data_trn[t].is == :comment
+                if @md.opt.act[:maintenance][:set]==:on
+                  puts "trans (comment):\n\t" \
+                  + data_trn[t].obj
+                end
+                t+=1
+                #next if data_trn[t].is == :comment
+              end
+            end
+            if ((defined? data_src[s].ocn) \
+            && (data_src[s].ocn.is_a?(Fixnum))) \
+            and ((defined? data_trn[t].ocn) \
+            && (data_trn[t].ocn.is_a?(Fixnum))) \
+            and (data_src[s].ocn == data_trn[t].ocn)
+              @m_s,@m_t=s,t
+            elsif ((defined? data_src[s].ocn) \
+            && (data_src[s].ocn.is_a?(Fixnum))) \
+            and ((defined? data_trn[t].ocn) \
+            && (data_trn[t].ocn.is_a?(Fixnum))) \
+            and (data_src[s].ocn != data_trn[t].ocn)
+              p '--- OCN ---'
+              p 'mis-match'
+              p data_src[s].ocn
+              p data_src[s].obj
+              p data_trn[t].ocn
+              p data_trn[t].obj
+              p '---'
+              p 'previous match'
+              p data_src[@m_s].ocn
+              p data_src[@m_s].obj
+              p data_trn[@m_t].ocn
+              p data_trn[@m_t].obj
+              exit
+            elsif (((defined? data_src[s].ocn) \
+            && (defined? data_trn[t].ocn)) \
+            and data_src[s].ocn.class != data_trn[t].ocn.class)
+              p '--- OCN class ---'
+              p 'mis-match'
+              p data_src[s].ocn if defined? data_src[s].ocn
+              p data_src[s].obj
+              p data_trn[t].ocn if defined? data_trn[t].ocn
+              p data_trn[t].obj
+              #p '---'
+              #p 'previous match'
+              #p data_src[@m_s].ocn
+              #p data_src[@m_s].obj
+              #p data_trn[@m_t].ocn
+              #p data_trn[@m_t].obj
+            #elsif (defined? data_src[s].ocn != defined? data_trn[t].ocn) \
+            #and (data_src[s].ocn.nil? != data_trn[t].ocn.nil?)
+            #  p '--- missing OCN? ---'
+            #  p 'mis-match'
+            #  p data_src[s].ocn if defined? data_src[s].ocn
+            #  p data_src[s].obj
+            #  p data_trn[t].ocn if defined? data_trn[t].ocn
+            #  p data_trn[t].obj
+            else
+            end
+          end
+          notes_s,notes_t='',''
+          data_src[s],notes_s=markup(data_src[s])
+          if data_trn
+            data_trn[t],notes_t=markup(data_trn[t])
+            #data_src[s],data_trn[t]=pot_data(data_src[s],notes_s,data_trn[t],notes_t)
+            pot_data(data_src[s],notes_s,data_trn[t],notes_t)
+          else
+            #data_src[s],nul=pot_data(data_src[s],notes_s)
+            pot_data(data_src[s],notes_s)
+          end
+          s+=1;t+=1
+        end
+        @pot #watch
+      end
+      def pot_data(dob_src='',notes_s='',dob_trn='',notes_t='')
+        if dob_src.obj !~/(^#{Rx[:meta]}|#{Mx[:br_eof]}|#{Mx[:br_endnotes]})/
+          if defined? dob_src.ocn \
+          and dob_src.ocn.to_s =~/\d+/
+            paranum=dob_src.ocn.to_s
+            @p_num=SiSU_Po4aUtils::ParagraphNumber.new(paranum)
+          end
+          case dob_src.is
+          when :heading
+            pot_structure.heading(dob_src,notes_s,dob_trn,notes_t)
+          when :para
+            pot_structure.para(dob_src,notes_s,dob_trn,notes_t)
+          when :group
+            pot_structure.group(dob_src,notes_s,dob_trn,notes_t)
+          when :block
+            pot_structure.block(dob_src,notes_s,dob_trn,notes_t)
+          when :verse
+            pot_structure.verse(dob_src,notes_s,dob_trn,notes_t)
+          when :code
+            pot_structure.code(dob_src,notes_s,dob_trn,notes_t)
+          when :table
+            pot_structure.table(dob_src,notes_s,dob_trn,notes_t)
+          end
+          if defined? dob_src.idx \
+          and not dob_src.idx.nil? \
+          and not dob_src.idx.empty?
+            pot_structure.idx(dob_src,dob_trn)
+          end
+          dob_src='' if (dob_src.obj =~/<a name="n\d+">/ \
+          and dob_src.obj =~/^(-\{{2}~\d+|<!e[:_]\d+!>)/) # -endnote
+          if dob_src ## Clean Prepared Text
+            dob_src.obj=dob_src.obj.gsub(/<!.+!>/,' ').
+              gsub(/<:\S+>/,' ') if dob_src ## Clean Prepared Text
+          end
+        end
+        #[dob_src,dob_trn]
+      end
+      def markup(dob)
+        dob,notes=objects.textface_marks_po4a(dob,:separate)
+        [dob,notes]
+      end
+      def publish(fn,pot)
+        content=[]
+        content << pot[:open]
+        content << pot[:head]
+        content << pot[:metadata]
+        content << pot[:body]
+        content << @@endnotes[:end] if @@endnotes_
+        Output.new(fn,content,@md,@process).po4a
+        @@endnotes={ para: [], end: [] }
+      end
+    end
+    class Po4aCfg
+      include SiSU_Composite_Doc_Utils                    # composite doc, .ssm, extract all related insert files, array of filenames test
+      def initialize(opt,file)
+        @opt,@file=opt,file
+      end
+      def po4a_cfg_filename
+        'po4a.cfg'
+      end
+      def dir
+        def pwd
+          Dir.pwd
+        end
+        def po4a_
+          'po4a/' # ''
+        end
+        def pot
+          po4a_ + 'pot'
+        end
+        def po
+          po4a_ + 'po'
+        end
+        self
+      end
+      def po4a_cfg_file
+        File.open("#{Dir.pwd}/#{po4a_cfg_filename}",'w')
+      end
+      def language
+        def sisu_languages_available
+          Px[:lng_lst]
+        end
+        def translation_languages_selected
+          @opt.act[:po4a_lang_trans][:trn] \
+          ? @opt.act[:po4a_lang_trans][:trn]
+          : []
+        end
+        def translation_languages_selected_that_are_available
+          translation_languages_selected & sisu_languages_available
+        end
+        def source_language_selected_str
+          @opt.act[:po4a_lang_trans][:src] \
+          ? @opt.act[:po4a_lang_trans][:src]
+          : 'en'
+        end
+        def translation_languages_selected_that_are_available_str
+          translation_languages_selected_that_are_available.join(' ')
+        end
+        def translation_languages_selected_str
+          @opt.act[:po4a_lang_trans][:trn].join(' ')
+        end
+        self
+      end
+      def po4a_cfg
+        doc_import_list=composite_and_imported_filenames_array(@opt.fno)
+        po4a_cfg_arr=[]
+        po4a_cfg_arr \
+          << "[po4a_langs] #{language.translation_languages_selected_that_are_available_str}"
+        po4a_cfg_arr \
+          << "[po4a_paths] #{dir.pot}/$master.pot $lang:#{dir.po}/$lang/$master.po"
+        doc_import_list.each do |file_src|
+          file_src_fn=
+            file_src.gsub(/#{language.source_language_selected_str}\//,'')
+          po4a_cfg_arr \
+            << "[type: text] #{file_src} $lang:$lang/#{file_src_fn}"
+        end
+        file=@file.write_file.po4a_cfg
+        po4a_cfg_arr.each do |txt|
+        puts txt
+          file << txt << "\n"
+        end
+        file.close
+      end
+    end
+    class Output <Source
+      include SiSU_Param
+      include SiSU_Env
+      def initialize(fn,content,md,process=:complete)
+        @fn,@content,@md,@process=fn,content,md,process
+        @file=SiSU_Env::FileOp.new(md,fn)
+      end
+      def po4a                                                                 #%pot output
+        file_pot=(@md.opt.f_pth[:lng] == @md.opt.lng_base) \
+        ? @file.write_file.pot
+        : @file.write_file.po
+        @sisu=[]
+        emptyline=0
+        @content.each do |para|                                                # this is a hack
+          if para.is_a?(Array) \
+          and para.length > 0
+            para.each do |line|
+              if line
+                line=line.gsub(/\s+$/m,'').
+                  gsub(/^\A[ ]*\Z/m,'')
+                if line=~/^\A[ ]*\Z/m
+                  emptyline+=1
+                else emptyline=0
+                end
+                file_pot.puts line if emptyline < 2                     #remove extra line spaces (fix upstream)
+              end
+            end
+          else file_pot.puts para          #unix plaintext # /^([*=-]|\.){5}/
+          end
+        end
+        file_pot.close
+        SiSU_Po4aUtils::PotNumber.new.reset
+        po4a_git
+      end
+      def po4a_git
+        unless @md.opt.act[:maintenance][:set]==:on
+          require_relative 'git'                           # git.rb
+          git=SiSU_Git::Source.new(@md.opt,@process)
+          unless FileTest.directory?(@file.output_path.pot_git.dir)
+            git.create_file_structure_git
+          end
+          if @md.opt.f_pth[:lng] == @md.opt.lng_base
+            FileUtils::cp(
+              @file.place_file.pot.dir,
+              @file.output_path.pot_git.dir
+            )
+          else # naive, work on -->
+            FileUtils::cp(
+              @file.place_file.po.dir,
+              @file.output_path.po_git.dir
+            ) #unless FileTest.file?(@file.place_file.po_git.dir)
+          end
+          git.read
+        end
+      end
+    end
+  end
+end
+__END__
+&#033;\|&#035;\|&&#042;\|&#045;\|&#047;\|&#095;\|&#123;\|&#125;\|&#126;\|&#
+
+tables are problematic, difficult to reconstitute instruction, check
+
+metadata, move to top? and work on
+
+footnotes, different types, asterisk, also do you want to have separate
+paragraphs, or breaks within one block?
+
+where no ocn appropriately use ~# or -# or indeed 1~name-
+
+comments in document, what to do about them, not sure they are currently
+retained in dal, could be quite valuable to keep
+
+Translate Shell
+http://www.soimort.org/translate-shell/
+translate.google.com
+#+END_SRC
+
+* src_po4a_shelf_set.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/src_po4a_shelf_set.rb"
+# <<sisu_document_header>>
+module SiSU_Po4aUtils
+  class Wrap
+    def initialize(md,orig='',trans='',is_desc='',n_char_max=76,n_indent=0,n_hang=nil)
+      @md,@orig,@trans,@is_desc,@n_char_max,@n_indent=
+       md, orig, trans, is_desc, n_char_max, n_indent
+      @n_char_max_extend = n_char_max
+      @br="\n"
+      @n_hang=n_hang ? n_hang : @n_indent
+      @po4a_identify_type='type: SiSU doc'
+      #@po4a_identify_type='type: Plain text'
+    end
+    def line_wrap
+      space=' '
+      spaces_indent,spaces_hang=
+        "#{@br}#{space*@n_indent}",space*@n_hang
+      pot,i=[],0
+      pot_array=(@trans.empty?) ? [@orig] : [@orig,@trans]
+      pot_array.each do |pa|
+        line=0
+        out=[]
+        out[line]=''
+        @oldword='' #REMOVE @oldword
+        pa=pa.gsub(/<br>/,' <br> ').
+          gsub(/#{Mx[:br_nl]}/,"\n\n")
+        words=pa.scan(/\n\n|\\\\\\|<br>|\S+/m)
+        while words != ''
+          word=words.shift
+          if not word
+            out[line] unless out[line].empty? #check
+            break
+          elsif word =~/\n\n/
+            word="\n"
+            @n_char_max_extend = @n_char_max + out[line].length
+            line=line
+          elsif (out[line].length + word.length) > (@n_char_max_extend - @n_indent) \
+          and out[line] =~/\S+/
+            @n_char_max_extend = @n_char_max
+            out[line].squeeze!(' ')
+            line += 1
+          end
+          if word
+            out[line]=if out[line] \
+            and out[line] !~/\S+$/m
+              "#{out[line]}#{word}"
+            elsif out[line] \
+            and out[line] =~/\S+/
+              "#{out[line]} #{word}"
+            else "#{word.strip}"
+            end
+          end
+          @oldword=word if word =~/\S+/
+        end
+        x=out.join(spaces_indent).gsub(/\A\n+/m,'').insert(0,spaces_hang)
+        z=[]
+        x.split(/\n/).each do |y|
+          y=y.gsub(/"/,'\"')
+          y=%{"#{y}"}
+          z << y
+        end
+        pot[i]=z.join("\n")
+        i +=1
+        pot
+      end
+      trans=(pot.length == 2) ? pot[1] : ''
+      po_str=<<WOK
+#. #{@po4a_identify_type} - #{@is_desc}
+#: en/#{@md.fns}:#{PotNumber.new.num}
+msgid ""
+#{pot[0]}
+msgstr ""
+#{trans}
+WOK
+      po_str
+    end
+    def no_line_wrap_block
+      pot,i=[],0
+      pot_array=(@trans.empty?) ? [@orig] : [@orig,@trans]
+      pot_array.each do |pa|
+        z=[]
+        pa.split(/\n\n/).each do |y|
+          y=y.gsub(/"/,'\"')
+          y=%{"#{y}"}
+          z << y if not y.empty?
+        end
+        pot[i]=z.join("\n")
+        i +=1
+        pot
+      end
+      trans=(pot.length == 2) ? pot[1] : ''
+      po_str=<<WOK
+#. #{@po4a_identify_type} - #{@is_desc}
+#: en/#{@md.fns}:#{PotNumber.new.num}
+#, no-wrap
+msgid ""
+#{pot[0]}
+msgstr ""
+#{trans}
+WOK
+      po_str
+    end
+    def line_wrap_indent1
+      @n_indent,@n_hang=2,2
+      line_wrap
+    end
+    def line_wrap_endnote
+      @n_indent,@n_hang=4,2
+      line_wrap
+    end
+    def array_wrap
+      if @orig.is_a?(Array)
+        @arr=[]
+        @orig.each do |line|
+          @arr << SiSU_TextUtils::Wrap.new(line,@n_char_max,@n_indent,@n_hang).line_wrap
+        end
+      end
+      @arr
+    end
+  end
+  class HeaderScan
+    def initialize(md,para)
+      @md,@p=md,para
+    end
+    def extract(tag,tag_content,type,attrib)
+      if dc_tag \
+      and dc_content
+        [dc_tag,dc_content,{dc_tag=>dc_content}]
+      else nil
+      end
+    end
+    def header(tag,tag_content,type='',attrib='') #this will break stuff and must be tested thoroughly 20060825
+      @tag,@tag_content,@type,@attrib=tag,tag_content,type,attrib
+      def label #element
+        @tag
+      end
+      def type
+        @type
+      end
+      def text
+        @tag_content
+      end
+      def info  #element text
+        @tag_content
+      end
+      def attribute
+        @attrib
+      end
+      def element
+        @tag
+      end
+      def attrib
+        @attrib
+      end
+      def el
+        @tag
+      end
+      self
+    end
+    def start_is_match
+      case @p
+      when /^#{Mx[:meta_o]}(title)#{Mx[:meta_c]}\s*(.+?)$/                      then header($1,@md.title.full,'meta','dc') #dc 1
+      when /^#{Mx[:meta_o]}(creator|author)#{Mx[:meta_c]}\s*(.+?)$/             then header('creator',$2,'meta','dc')    #dc 2
+      when /^#{Mx[:meta_o]}(subject)#{Mx[:meta_c]}\s*(.+?)$/                    then header($1,$2,'meta','dc')           #dc 3
+      when /^#{Mx[:meta_o]}(description)#{Mx[:meta_c]}\s*(.+?)$/                then header($1,$2,'meta','dc')           #dc 4
+      when /^#{Mx[:meta_o]}(publisher)#{Mx[:meta_c]}\s*(.+?)$/                  then header($1,$2,'meta','dc')           #dc 5
+      when /^#{Mx[:meta_o]}(contributor)#{Mx[:meta_c]}\s*(.+?)$/                then header($1,$2,'meta','dc')           #dc 6
+      when /^#{Mx[:meta_o]}(date)#{Mx[:meta_c]}\s*(.+?)$/                       then header($1,$2,'meta','dc')           #dc 7
+      when /^#{Mx[:meta_o]}(date\.created)#{Mx[:meta_c]}\s*(.+?)$/              then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(date\.issued)#{Mx[:meta_c]}\s*(.+?)$/               then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(date\.available)#{Mx[:meta_c]}\s*(.+?)$/            then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(date\.valid)#{Mx[:meta_c]}\s*(.+?)$/                then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(date\.modified)#{Mx[:meta_c]}\s*(.+?)$/             then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(type)#{Mx[:meta_c]}\s*(.+?)$/                       then header($1,$2,'meta','dc')           #dc 8
+      when /^#{Mx[:meta_o]}(format)#{Mx[:meta_c]}\s*(.+?)$/                     then header($1,$2,'meta','dc')           #dc 9
+      when /^#{Mx[:meta_o]}(identifier)#{Mx[:meta_c]}\s*(.+?)$/                 then header($1,$2,'meta','dc')           #dc 10
+      when /^#{Mx[:meta_o]}(source)#{Mx[:meta_c]}\s*(.+?)$/                     then header($1,$2,'meta','dc')           #dc 11
+      when /^#{Mx[:meta_o]}(language)#{Mx[:meta_c]}\s*(.+?)$/                   then header($1,$2,'meta','dc')           #dc 12
+      when /^#{Mx[:meta_o]}(relation)#{Mx[:meta_c]}\s*(.+?)$/                   then header($1,$2,'meta','dc')           #dc 13
+      when /^#{Mx[:meta_o]}(coverage)#{Mx[:meta_c]}\s*(.+?)$/                   then header($1,$2,'meta','dc')           #dc 14
+      when /^#{Mx[:meta_o]}(rights)#{Mx[:meta_c]}\s*(.+?)$/                     then header($1,$2,'meta','dc')           #dc 15
+      when /^#{Mx[:meta_o]}(keywords)#{Mx[:meta_c]}\s*(.+?)$/                   then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(copyright)#{Mx[:meta_c]}\s*(.+?)$/                  then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(translator|translated_by)#{Mx[:meta_c]}\s*(.+?)$/   then header('translator',$2)
+      when /^#{Mx[:meta_o]}(illustrator|illustrated_by)#{Mx[:meta_c]}\s*(.+?)$/ then header('illustrator',$2)
+      when /^#{Mx[:meta_o]}(prepared_by)#{Mx[:meta_c]}\s*(.+?)$/                then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(digitized_by)#{Mx[:meta_c]}\s*(.+?)$/               then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(comments?)#{Mx[:meta_c]}\s*(.+?)$/                  then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(abstract)#{Mx[:meta_c]}\s*(.+?)$/                   then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(tags?)#{Mx[:meta_c]}\s*(.+?)$/                      then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(catalogue)#{Mx[:meta_c]}\s*(.+?)$/                  then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(class(?:ify)?_loc)#{Mx[:meta_c]}\s*(.+?)$/          then header('classify_loc',$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(class(?:ify)?_dewey)#{Mx[:meta_c]}\s*(.+?)$/        then header('classify_dewey',$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(class(?:ify)?_pg)#{Mx[:meta_c]}\s*(.+?)$/           then header('classify_pg',$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(class(?:ify)?_isbn)#{Mx[:meta_c]}\s*(.+?)$/         then header('classify_isbn',$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(toc|structure)#{Mx[:meta_c]}\s*(.+?)$/              then header('structure',$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(level|page|markup)#{Mx[:meta_c]}\s*(.+?)$/          then header('markup',$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(bold)#{Mx[:meta_c]}\s*(.+?)$/                       then header($1,$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(italics|itali[sz]e)#{Mx[:meta_c]}\s*(.+?)$/         then header('italicize',$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(vocabulary|wordlist)#{Mx[:meta_c]}\s*(.+?)$/        then header('vocabulary',$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(css|stylesheet)#{Mx[:meta_c]}\s*(.+?)$/             then header('css',$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(links)#{Mx[:meta_c]}\s*(.+?)$/                      then header($1,$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(prefix)#{Mx[:meta_c]}\s*(.+?)$/                     then header($1,$2,'process','instruct') #add a & b
+      when /^#{Mx[:meta_o]}(suffix)#{Mx[:meta_c]}\s*(.+?)$/                     then header($1,$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(information)#{Mx[:meta_c]}\s*(.+?)$/                then header($1,$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(contact)#{Mx[:meta_c]}\s*(.+?)$/                    then header($1,$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(rcs|cvs)#{Mx[:meta_c]}\s*(.+?)$/                    then header('version',$2,'process','instruct')
+      else nil
+      end
+    end
+    def dublin
+      (@p =~/^#{Mx[:meta_o]}\S+?#{Mx[:meta_c]}/) \
+      ? start_is_match
+      : nil
+    end
+    def meta
+      (@p =~/^#{Mx[:meta_o]}\S+?#{Mx[:meta_c]}/) \
+      ? start_is_match
+      : nil
+    end
+  end
+  class ParagraphNumber
+    def initialize(paranum)
+      @paranum=/(\d+)/m.match(paranum)[1]
+    end
+    def display
+      @paranum.gsub(/(\d+)/,'#\1')
+    end
+  end
+  class PotNumber
+    @@n=0
+    def initialize
+      @@n +=2
+    end
+    def num
+      @@n
+    end
+    def reset
+      @@n=0
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* src_po4a_sst_ao_sst.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/src_po4a_sst_ao_sst.rb"
+# <<sisu_document_header>>
+module SiSU_SStm_AO_SStm
+  require_relative 'ao'                                 # ao.rb
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'ao_composite'                       # ao_composite.rb
+  require_relative 'shared_metadata'                    # shared_metadata.rb
+  require_relative 'src_po4a_share'                     # src_po4a_share.rb
+  require_relative 'src_po4a_sst_ao_sst_set'            # src_po4a_sst_ao_sst_set.rb
+  include SiSU_Param
+  require_relative 'object_munge'                       # object_munge.rb
+  require_relative 'utils_composite'                    # utils_composite.rb
+  require_relative 'utils_response'                     # utils_response.rb
+  class Source
+    include SiSU_Object_Munge
+    include SiSU_Languages_Selected
+    include SiSU_Response
+    @@md_src,@@md_master=
+          nil,      nil
+    @@auto_translation_ = :go
+    def initialize(opt,fn=nil)
+      @opt,@fn=opt,fn
+      #unless @opt.fns =~/(.+?\.(?:-|ssm\.)?sst)$/
+      #  puts "#{@opt.fns} not a processed file type"
+      #end
+      file_arr=SiSU_Info_Env::InfoEnv.new.
+        source_file_processing_array(@opt.fno)
+      SiSU_Param::Parameters::Instructions.new(file_arr,@opt).extract
+      r=Px[:lng_lst_rgx].gsub(/\|#{language.source_language_selected_str}\|/,'|')
+      @lang_regx=%r{(?:#{r})}
+      @@todo=if source_language_selected_str == opt.f_pth[:lng]
+        :same_file
+      else :compare
+      end
+      if opt.f_pth[:lng]==@opt.lng_base \
+      and opt.f_pth[:lng]==source_language_selected_str
+        @@md_master=SiSU_Param::Parameters.new(opt).get
+      end
+    end
+    def wrap_width_set(md,env)
+      if defined? md.make.plaintext_wrap \
+      and md.make.plaintext_wrap
+        md.make.plaintext_wrap
+      elsif defined? env.plaintext_wrap \
+      and env.plaintext_wrap
+        #env.plaintext_wrap # 78 use 75
+        75
+      else 75 #78
+      end
+    end
+    def process_file(md,env,file,wrap_width,fn)
+      if source_language_selected_str == @opt.f_pth[:lng]
+        @@ao_arr_lang_trans=
+          SiSU_AO::Source.new(
+            @opt,
+            fn,
+            :po4a
+          ).get # ao file drawn here
+      end
+      @ao_arr_lang_src=
+        SiSU_AO::Source.new(
+          @opt,
+          fn,
+          :po4a
+        ).get # ao file drawn here
+      SiSU_SStm_AO_SStm::Source::Scroll.new(
+        fn,
+        @ao_arr_lang_src,
+        @@ao_arr_lang_trans,
+        @@md_src,
+        @@md_master,
+        wrap_width
+      ).songsheet
+    end
+    def read_process_src_files
+      begin
+        src={}
+        src[:pth]=@opt.f_pth[:pth]
+        src[:files]=if @opt.fns =~ /\.(?:(?:-|ssm\.)sst|ssm)$/
+          @opt.fns=@opt.fns.gsub(/\.ssm\.sst$/,'.ssm')
+          SiSU_Assemble::CompositeFileList.new(@opt).read
+        else
+          [@opt.fns]
+        end
+        md=SiSU_Param::Parameters.new(@opt).get
+        env=SiSU_Env::InfoEnv.new(@opt.fns)
+        file=SiSU_Env::FileOp.new(md)
+        lng=/\/([^\/]+)$/.match(src[:pth])[1]
+        if language.source_language_selected_str == lng
+          SiSU_Po4a_Project::Po4aDistClean.new(@opt,file).song
+        end
+        wrap_width=wrap_width_set(md,env)
+        lng = /\/([^\/]+)$/.match(src[:pth])[1]
+        ans=response?('process files?')
+        if ans
+          src[:files].each do |fn|
+            puts "[#{lng}] #{fn}"
+            process_file(md,env,file,wrap_width,fn)
+          end
+        end
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    def read_setup
+      begin
+        md=SiSU_Param::Parameters.new(@opt).get
+        file=SiSU_Env::FileOp.new(md)
+        SiSU_Po4a_Project::Po4aCfg.new(@opt,file).song
+        SiSU_Po4a_Project::Po4aProject.new(@opt,file).song
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    private
+    class Scroll <Source
+      include SiSU_Po4aUtils
+      @@endnotes={ para: [], end: [] }
+      def initialize(fn,data_src,data_master,md_src,md_master,wrap_width)
+        @fn,@data_src,@data_master,@md_src,@md_master,@wrap_width=
+         fn, data_src, data_master, md_src, md_master, wrap_width
+        @md=md_src
+        @tab="\t"
+        @@endnotes_=(@md.opt.selections.str =~/--endnote/) \
+        ? true
+        : false    # --footnote
+        @pot={
+          body: [],
+          open: [],
+          close: [],
+          head: [],
+          metadata: [],
+          tail: []
+        }
+      end
+      def br
+        (@md.opt.selections.str =~/--dos/) ? "\r\n" : "\n"  # --unix
+      end
+      def songsheet
+        fn=@fn
+        pot=compare_structure_src_trn(@data_src,@data_master,@@todo)
+        publish(fn,pot)
+      end
+      def pot_structure_wrap(orig,trans,indent=0,hang=0)
+        SiSU_Po4aUtils::Wrap.new(
+          @md,
+          orig,
+          trans,
+          @wrap_width,
+          indent,
+          hang
+        )
+      end
+      def wrap_endnotes(orig_notes='',trn_notes='')
+        #nt=@@endnotes_ ? 'endnote' : 'footnote'
+        @fn=0
+        a_l=orig_notes.length
+        0.upto(a_l-1) do |i|
+          @fn=if orig_notes[i].to_s =~/^\^~([\d*+]+)/ # provides endnote number within paragraph
+            @fn += 1
+          else @fn
+          end
+          #mark="^~ "
+          orig=(orig_notes[i].to_s =~/^\^~[\d*+]+/) \
+          ? (orig_notes[i].to_s.gsub(/^\^~[\d*+]+/,'^~'))
+          : orig_notes[i].to_s
+          trans=if trn_notes.is_a?(Array) \
+          and trn_notes.length==orig_notes.length
+            (trn_notes[i].to_s =~/^\^~[\d*+]+/) \
+            ? (trn_notes[i].to_s.gsub(/^\^~[\d*+]+/,'^~'))
+            : trn_notes[i].to_s
+          else ''
+          end
+          util=pot_structure_wrap(orig,trans)
+          wrap=util.line_wrap
+          wrap=if wrap =~ /^\s*\^~[\d*+]+\s+.+?\s*\Z/m
+            wrap.gsub(/^\s*(\^~[\d*+]+)\s+(.+?)\s*\Z/m, <<GSUB
+\\1 \\2
+GSUB
+                      )
+          else
+            wrap.gsub(/^(.+)\Z/m, <<GSUB
+\\1
+GSUB
+                      )
+          end
+          @@endnotes[:para] << wrap
+          @@endnotes[:end] << '' << wrap
+        end
+        @@endnotes[:para].each {|e| @pot[:body] << e << br}
+        @@endnotes[:para]=[]
+        @@endnotes
+      end
+      def pot_metadata_src
+        @po4a_identify_type='type: SiSU doc' #'type: Plain text'
+        meta_src=SiSU_Metadata::Summary.new(@md_src)
+        w=[]
+        w << [
+          meta_src.metadata_tags.title.main,
+          meta_src.metadata_tags.title.sub,
+          meta_src.metadata_tags.title.edition,
+          meta_src.metadata_tags.title.note,
+          meta_src.metadata_tags.title.short,
+          meta_src.metadata_tags.title.language,
+          meta_src.metadata_tags.title.language_char,
+        ]
+        w << [
+          meta_src.metadata_tags.creator.head,
+          meta_src.metadata_tags.creator.author,
+          meta_src.metadata_tags.creator.contributor,
+          meta_src.metadata_tags.creator.illustrator,
+          meta_src.metadata_tags.creator.photographer,
+          meta_src.metadata_tags.creator.translator,
+          meta_src.metadata_tags.creator.audio,
+          meta_src.metadata_tags.creator.digitized_by,
+          meta_src.metadata_tags.creator.prepared_by,
+        ]
+        w << [
+          meta_src.metadata_tags.rights.head,
+          meta_src.metadata_tags.rights.copyright.text,
+          meta_src.metadata_tags.rights.copyright.translation,
+          meta_src.metadata_tags.rights.copyright.illustrations,
+          meta_src.metadata_tags.rights.copyright.photographs,
+          meta_src.metadata_tags.rights.copyright.digitization,
+          meta_src.metadata_tags.rights.copyright.audio,
+          meta_src.metadata_tags.rights.license,
+        ]
+        w << [
+          meta_src.metadata_tags.classify.head,
+          meta_src.metadata_tags.classify.subject,
+          meta_src.metadata_tags.classify.topic_register,
+          meta_src.metadata_tags.classify.loc,
+          meta_src.metadata_tags.classify.dewey,
+        ]
+        w << [
+          meta_src.metadata_tags.date.head,
+          meta_src.metadata_tags.date.added_to_site,
+          meta_src.metadata_tags.date.available,
+          meta_src.metadata_tags.date.created,
+          meta_src.metadata_tags.date.issued,
+          meta_src.metadata_tags.date.modified,
+          meta_src.metadata_tags.date.published,
+          meta_src.metadata_tags.date.valid,
+        ]
+        w << [
+          meta_src.processing_tags.make.language,
+          meta_src.processing_tags.make.headings,
+          meta_src.processing_tags.make.num_top,
+          meta_src.processing_tags.make.breaks,
+          meta_src.processing_tags.make.emphasis,
+          meta_src.processing_tags.make.bold,
+          meta_src.processing_tags.make.italics,
+          meta_src.processing_tags.make.texpdf_font,
+        ]
+        w.each do |y|
+          z=''
+          y.each do |x|
+            if x
+              z += x + "\n" if x =~/^#|^msg(?:id|str)/
+              z += %{#{x}\n} if x =~/^@\S+?:(?: |$)/
+              z += %{#{x}\n} if x =~/^\s+:\S+?: /
+            end
+          end
+          @pot[:metadata] << z << br
+          #puts z unless z.empty?
+        end
+      end
+      def pot_metadata_src_trn
+        #@po4a_identify_type='type: Plain text'
+        meta_src=SiSU_Metadata::Summary.new(@md_src)
+        w=[]
+        w << [
+          meta_src.metadata_tags.title.main,
+          meta_src.metadata_tags.title.sub,
+          meta_src.metadata_tags.title.edition,
+          meta_src.metadata_tags.title.note,
+          meta_src.metadata_tags.title.short,
+          meta_src.metadata_tags.title.language,
+          meta_src.metadata_tags.title.language_char,
+        ]
+        w << [
+          meta_src.metadata_tags.creator.head,
+          meta_src.metadata_tags.creator.author,
+          meta_src.metadata_tags.creator.contributor,
+          meta_src.metadata_tags.creator.illustrator,
+          meta_src.metadata_tags.creator.photographer,
+          meta_src.metadata_tags.creator.translator,
+          meta_src.metadata_tags.creator.audio,
+          meta_src.metadata_tags.creator.digitized_by,
+          meta_src.metadata_tags.creator.prepared_by,
+        ]
+        w << [
+          meta_src.metadata_tags.rights.head,
+          meta_src.metadata_tags.rights.copyright.text,
+          meta_src.metadata_tags.rights.copyright.translation,
+          meta_src.metadata_tags.rights.copyright.illustrations,
+          meta_src.metadata_tags.rights.copyright.photographs,
+          meta_src.metadata_tags.rights.copyright.digitization,
+          meta_src.metadata_tags.rights.copyright.audio,
+          meta_src.metadata_tags.rights.license,
+        ]
+        w << [
+          meta_src.metadata_tags.classify.head,
+          meta_src.metadata_tags.classify.subject,
+          meta_src.metadata_tags.classify.topic_register,
+          meta_src.metadata_tags.classify.loc,
+          meta_src.metadata_tags.classify.dewey,
+        ]
+        w << [
+          meta_src.metadata_tags.date.head,
+          meta_src.metadata_tags.date.added_to_site,
+          meta_src.metadata_tags.date.available,
+          meta_src.metadata_tags.date.created,
+          meta_src.metadata_tags.date.issued,
+          meta_src.metadata_tags.date.modified,
+          meta_src.metadata_tags.date.published,
+          meta_src.metadata_tags.date.valid,
+        ]
+        w << [
+          meta_src.processing_tags.make.language,
+          meta_src.processing_tags.make.headings,
+          meta_src.processing_tags.make.num_top,
+          meta_src.processing_tags.make.breaks,
+          meta_src.processing_tags.make.emphasis,
+          meta_src.processing_tags.make.bold,
+          meta_src.processing_tags.make.italics,
+          meta_src.processing_tags.make.texpdf_font,
+        ]
+        w.each do |y|
+          z=''
+          y.each do |x|
+            if x
+              z += x + "\n" if x =~/^#|^msg(?:id|str)/
+              z += %{#{x}\n} if x =~/^@\S+?:(?: |$)/
+              z += %{#{x}\n} if x =~/^\s+:\S+?: /
+            end
+          end
+          @pot[:metadata] << z << br
+          #puts z unless z.empty?
+        end
+      end
+      def auto_translate?(set_to=nil)
+        @@auto_translation_=
+        if @md.opt.act[:po4a_lang_trans][:set]==:on
+          set_to \
+          ? set_to
+          : @@auto_translation_
+        else :skip
+        end
+      end
+      def auto_translation(src_txt,markup=:src) # check for an appropriate request flag
+        auto_translate?(:skip)
+        begin
+          src_txt_clean=clean_text(src_txt,markup)
+          src_txt_clean=src_txt_clean.
+            gsub(/\n/,' ').
+            gsub(/"/,'\"').
+            gsub(/([()])/,'\\\\\1')
+          trans=''
+          unless auto_translate? == :skip
+            require 'timeout'
+            Timeout::timeout(60) {
+              trans=`trans -b -no-ansi en:#{@md.opt.f_pth[:lng_is]} #{src_txt_clean}`.strip
+              unless trans.empty?
+                trans + ' {[G.Tr]}http://translate.google.com'
+              end
+            }
+          end
+          trans
+        rescue
+          auto_translate?(:skip)
+          p 'timeout issues with translation, skip remaining'
+        end
+      end
+      def pot_structure
+        def heading(dob_src='',notes_s='',dob_trn='',notes_t='')   #% used to extract the structure of a document
+          lv=n=n3=nil
+          lv=dob_src.ln
+          n=lv - 1
+          n3=lv + 2
+          util=nil
+          fn=(dob_src.name=~/[a-z\d]/i) ? dob_src.name : ''
+          mark="#{dob_src.lv}~#{fn} "
+          orig="#{mark}#{dob_src.obj}"
+          trans=((dob_trn=='') \
+          || (dob_src.obj == dob_trn.obj)) \
+          ? ''
+          : "#{mark}#{dob_trn.obj}"
+          if @md.opt.f_pth[:lng_is] !=@md.opt.lng_base \
+          and trans.empty? \
+          and auto_translate?
+            trans=auto_translation(dob_src.obj,:src)
+          end
+          util=pot_structure_wrap(orig,trans)
+          wrapped=util.line_wrap
+          @pot[:body] << wrapped << br # main text, contents, body KEEP
+          if @@endnotes[:para] \
+          and notes_s.length > 0 \
+          and not @@endnotes_
+            @pot[:body] << br
+            wrap_endnotes(notes_s,notes_t)
+          elsif @@endnotes[:para] \
+          and @@endnotes_
+            @pot[:body] << br*2
+          end
+        end
+        def para(dob_src='',notes_s='',dob_trn='',notes_t='')      #% used to extract the structure of a document
+          util=nil
+          wrapped=if dob_src.indent =~/[1-9]/ \
+          and dob_src.indent == dob_src.hang
+            s_mark=desc=orig=trans=''
+            mark=if dob_src.bullet_
+              "_#{dob_src.indent}* "
+            else
+              "_#{dob_src.indent} "
+            end
+            orig="#{mark}#{dob_src.obj}"
+            trans=((dob_trn=='') \
+            || (dob_src.obj == dob_trn.obj)) \
+            ? ''
+            : "#{mark}#{dob_trn.obj}"
+            if @md.opt.f_pth[:lng_is] !=@md.opt.lng_base \
+            and trans.empty? \
+            and auto_translate?
+              trans=auto_translation(dob_src.obj,:src)
+            end
+            util=pot_structure_wrap(orig,trans)
+          elsif dob_src.hang =~/[0-9]/ \
+          and dob_src.indent != dob_src.hang
+            s_mark=desc=orig=trans=''
+            mark="_#{dob_src.hang}_#{dob_src.indent} "
+            orig="#{mark}#{dob_src.obj}"
+            trans=((dob_trn=='') \
+            || (dob_src.obj == dob_trn.obj)) \
+            ? ''
+            : "#{mark}#{dob_trn.obj}"
+            if @md.opt.f_pth[:lng_is] !=@md.opt.lng_base \
+            and trans.empty? \
+            and auto_translate?
+              trans=auto_translation(dob_src.obj,:src)
+            end
+            util=pot_structure_wrap(orig,trans)
+          else
+            s_mark=desc=orig=trans=''
+            if dob_src.bullet_
+              mark='_* '
+              orig="#{mark}#{dob_src.obj}"
+              trans=((dob_trn=='') \
+              || (dob_src.obj == dob_trn.obj)) \
+              ? ''
+              : "#{mark}#{dob_trn.obj}"
+              if @md.opt.f_pth[:lng_is] !=@md.opt.lng_base \
+              and trans.empty? \
+              and auto_translate?
+                trans=auto_translation(dob_src.obj,:src)
+              end
+            else
+              mark=''
+              orig=dob_src.obj
+              trans=((dob_trn=='') \
+              || (dob_src.obj == dob_trn.obj)) \
+              ? ''
+              : "#{mark}#{dob_trn.obj}"
+              if @md.opt.f_pth[:lng_is] !=@md.opt.lng_base \
+              and trans.empty? \
+              and auto_translate?
+                trans=auto_translation(dob_src.obj,:src)
+              end
+            end
+            util=pot_structure_wrap(orig,trans)
+          end
+          wrapped=util.line_wrap
+          @pot[:body] << wrapped << br # main text, contents, body KEEP
+          if @@endnotes[:para] \
+          and notes_s.length > 0 \
+          and not @@endnotes_
+            @pot[:body] << br
+            wrap_endnotes(notes_s,notes_t)
+          elsif @@endnotes[:para] \
+          and @@endnotes_
+            @pot[:body] << br*2
+          end
+        end
+        def block(dob_src='',notes_s='',dob_trn='',notes_t='')     #% used to extract the structure of a document
+          mark_o ="block{\n\n"
+          mark_c ="\n\n}block"
+          orig="#{mark_o}#{dob_src.obj}#{mark_c}"
+          trans=((dob_trn=='') \
+          || (dob_src.obj == dob_trn.obj)) \
+          ? ''
+          : "#{mark_o}#{dob_trn.obj}#{mark_c}"
+          if @md.opt.f_pth[:lng_is] !=@md.opt.lng_base \
+          and trans.empty? \
+          and auto_translate?
+            trans=auto_translation(dob_src.obj,:src)
+          end
+          util=pot_structure_wrap(orig,trans)
+          unwrapped=util.no_line_wrap_block
+          @pot[:body] << unwrapped << br
+        end
+        def group(dob_src='',notes_s='',dob_trn='',notes_t='')     #% used to extract the structure of a document
+          mark_o ="group{\n\n"
+          mark_c ="\n\n}group"
+          orig="#{mark_o}#{dob_src.obj}#{mark_c}"
+          trans=((dob_trn=='') \
+          || (dob_src.obj == dob_trn.obj)) \
+          ? ''
+          : "#{mark_o}#{dob_trn.obj}#{mark_c}"
+          if @md.opt.f_pth[:lng_is] !=@md.opt.lng_base \
+          and trans.empty? \
+          and auto_translate?
+            trans=auto_translation(dob_src.obj,:src)
+          end
+          util=pot_structure_wrap(orig,trans)
+          unwrapped=util.no_line_wrap_block
+          @pot[:body] << unwrapped << br
+        end
+        def verse(dob_src='',notes_s='',dob_trn='',notes_t='')     #% used to extract the structure of a document
+          mark="poem{\n\nverse\n\nverse\n\n...\n\n}poem"
+          instruct=s_mark=''
+          if @md.opt.act[:maintenance][:set]==:on
+            instruct=%{\n# verse are part of the text block described as a poem, } \
+            + %{the first verse is preceeded by an opening marker, } \
+            + %{and the last verse by a closing marker, } \
+            + %{the content of which should remain unwrapped}
+            s_mark="\n# " + %{"\\n\\n#{mark}\\n\\n"}
+          end
+          orig=dob_src.obj
+          trans=(dob_trn=='') \
+          ? ''
+          : dob_trn.obj
+          util=pot_structure_wrap(orig,trans)
+          unwrapped=util.no_line_wrap_block
+          @pot[:body] << unwrapped << br
+        end
+        def code(dob_src='',notes_s='',dob_trn='',notes_t='')      #% used to extract the structure of a document
+          mark_o ="code{\n\n"
+          mark_c ="\n\n}code"
+          orig="#{mark_o}#{dob_src.obj}#{mark_c}"
+          trans=(dob_trn=='') \
+          ? ''
+          : "#{mark_o}#{dob_trn.obj}#{mark_c}"
+          util=pot_structure_wrap(orig,trans)
+          unwrapped=util.no_line_wrap_block
+          @pot[:body] << unwrapped << br
+        end
+        def table(dob_src='',notes_s='',dob_trn='',notes_t='')     #% used to extract the structure of a document
+          mark_o ="table{\n\n"
+          mark_c ="\n\n}table"
+          orig="#{mark_o}#{dob_src.obj}#{mark_c}"
+          orig=orig.gsub(/#{Mx[:tc_c]}/m,"\n")
+          trans=(dob_trn=='') \
+          ? ''
+          : "#{mark_o}#{dob_trn.obj}#{mark_c}"
+          trans=trans.gsub(/#{Mx[:tc_c]}/m,"\n")
+          util=pot_structure_wrap(orig,trans)
+          unwrapped=util.no_line_wrap_block
+          @pot[:body] << unwrapped << br
+        end
+        def idx_markup(idx)
+          struct=['={' + "\n  "]
+          idx.sort.each do |x|
+            x.each_with_index do |y,i0|
+              case y
+              when String
+                unless struct[-1] =~/=\{/
+                  struct << ' ;' + "\n  "
+                end
+                struct << y
+                if x[i0+1].class == Hash \
+                and x[i0+1][:sub].length > 0
+                  struct << ' :' + "\n    "
+                end
+              when Hash
+                if y[:plus].to_i > 0
+                  struct << '+' + y[:plus].to_s
+                end
+                if y[:sub].length > 0
+                  y[:sub].each_with_index do |z,i1|
+                    z.each_with_index do |a,i2|
+                      if z.length > 0
+                        struct << a[0]
+                        if a[1][:plus].to_i > 0
+                          struct << '+' + a[1][:plus].to_s
+                        end
+                        if (i1 + 1) < y[:sub].length
+                          struct << '|'
+                        end
+                      end
+                    end
+                  end
+                end
+              end
+            end
+          end
+          struct << "\n" + '}'
+          #puts struct.join
+          struct.join
+        end
+        def idx(dob_src='') #% used for book index but broken as original markup lost, already abstracted, fix
+          orig=pot_structure.idx_markup(dob_src.idx) #'={' + dob_src.idx + '}'
+          util=pot_structure_wrap(orig,'')
+          unwrapped=util.no_line_wrap_block
+          if @pot[:body][-1] == "\n"
+            @pot[:body][-1] = unwrapped #<< br
+            @pot[:body] << br
+          else # expect to catch all above, problem if wraps, must =~/^=\{/
+            @pot[:body] << unwrapped << br # places idx in separate object
+          end
+        end
+        self
+      end
+      def compare_structure_src_trn(data_src,data_trn,todo)
+        #@endnotes,@copen,@pot_contents_close=Array.new(3){[]}
+        a_l= data_src.length
+        s,t=0,0
+        0.upto(a_l-1) do |i|
+          if todo==:compare
+            unless data_src[s] \
+            and data_trn[t]
+              break
+            end
+            if data_src[s].of == :comment \
+            and data_trn[t].of == :comment \
+            and (data_src[s].is == data_trn[t].is)
+              s+=1;t+=1
+              next
+            end
+            if ((data_src[s].is == :comment) \
+            || (data_trn[t].is == :comment)) \
+            and (data_src[s].is != data_trn[t].is)
+              if data_src[s].is == :comment
+                if @md.opt.act[:maintenance][:set]==:on
+                  puts "src (comment):\n\t" \
+                  + data_src[s].obj
+                end
+                s+=1
+                #next if data_src[s].is == :comment
+              elsif data_trn[t].is == :comment
+                if @md.opt.act[:maintenance][:set]==:on
+                  puts "trans (comment):\n\t" \
+                  + data_trn[t].obj
+                end
+                t+=1
+                #next if data_trn[t].is == :comment
+              end
+            end
+            if ((defined? data_src[s].ocn) \
+            && (data_src[s].ocn.is_a?(Fixnum))) \
+            and ((defined? data_trn[t].ocn) \
+            && (data_trn[t].ocn.is_a?(Fixnum))) \
+            and (data_src[s].ocn == data_trn[t].ocn)
+              @m_s,@m_t=s,t
+            elsif ((defined? data_src[s].ocn) \
+            && (data_src[s].ocn.is_a?(Fixnum))) \
+            and ((defined? data_trn[t].ocn) \
+            && (data_trn[t].ocn.is_a?(Fixnum))) \
+            and (data_src[s].ocn != data_trn[t].ocn)
+              p '--- OCN ---'
+              p 'mis-match'
+              p data_src[s].ocn if defined? data_src[s].ocn
+              p data_src[s].obj if defined? data_src[s].obj
+              p data_trn[t].ocn if defined? data_trn[t].ocn
+              p data_trn[t].obj if defined? data_trn[t].obj
+              p '---'
+              p 'previous match'
+              p data_src[@m_s].ocn if defined? data_src[@m_s].ocn
+              p data_src[@m_s].obj if defined? data_src[@m_s].obj
+              p data_trn[@m_t].ocn if defined? data_trn[@m_t].ocn
+              p data_trn[@m_t].obj if defined? data_trn[@m_s].obj
+              exit
+            elsif (((defined? data_src[s].ocn) \
+            && (defined? data_trn[t].ocn)) \
+            and data_src[s].ocn.class != data_trn[t].ocn.class)
+              p '--- OCN class ---'
+              p 'mis-match'
+              p data_src[s].ocn if defined? data_src[s].ocn
+              p data_src[s].obj if defined? data_src[s].obj
+              p data_trn[t].ocn if defined? data_trn[t].ocn
+              p data_trn[t].obj if defined? data_trn[t].obj
+              #p '---'
+              #p 'previous match'
+              #p data_src[@m_s].ocn
+              #p data_src[@m_s].obj
+              #p data_trn[@m_t].ocn
+              #p data_trn[@m_t].obj
+            #elsif (defined? data_src[s].ocn != defined? data_trn[t].ocn) \
+            #and (data_src[s].ocn.nil? != data_trn[t].ocn.nil?)
+            #  p '--- missing OCN? ---'
+            #  p 'mis-match'
+            #  p data_src[s].ocn if defined? data_src[s].ocn
+            #  p data_src[s].obj
+            #  p data_trn[t].ocn if defined? data_trn[t].ocn
+            #  p data_trn[t].obj
+            else
+            end
+          end
+          notes_s=''
+          data_src[s],notes_s=markup(data_src[s])
+          data_src[s],nul=pot_data(data_src[s],notes_s)
+          s+=1;t+=1
+        end
+        @pot #watch
+      end
+      def pot_data(dob_src='',notes_s)
+        if dob_src.obj !~/(^#{Rx[:meta]}|#{Mx[:br_eof]}|#{Mx[:br_endnotes]})/
+          if defined? dob_src.ocn \
+          and dob_src.ocn.to_s =~/\d+/
+            paranum=dob_src.ocn.to_s
+            @p_num=SiSU_Po4aUtils::ParagraphNumber.new(paranum)
+          end
+          case dob_src.is
+          when :heading
+            pot_structure.heading(dob_src,notes_s)
+          when :para
+            pot_structure.para(dob_src,notes_s)
+          when :group
+            pot_structure.group(dob_src,notes_s)
+          when :block
+            pot_structure.block(dob_src,notes_s)
+          when :verse
+            pot_structure.verse(dob_src,notes_s)
+          when :code
+            pot_structure.code(dob_src,notes_s)
+          when :table
+            pot_structure.table(dob_src,notes_s)
+          end
+          if defined? dob_src.idx \
+          and not dob_src.idx.nil? \
+          and not dob_src.idx.empty?
+            pot_structure.idx(dob_src)
+          end
+          #if dob_src ## Clean Prepared Text
+          #  dob_src.obj=dob_src.obj.gsub(/<!.+!>/,' ').
+          #    gsub(/<:\S+>/,' ') if dob_src ## Clean Prepared Text
+          #end
+        end
+        #[dob_src,dob_trn]
+      end
+      def markup(dob)
+        dob,notes=objects.textface_marks_po4a(dob,:separate)
+        [dob,notes]
+      end
+      def publish(fn,pot)
+        content=[]
+        content << pot[:open]
+        content << pot[:head]
+        content << pot[:metadata]
+        content << pot[:body]
+        content << @@endnotes[:end] if @@endnotes_
+        Output.new(fn,content,@md,@process).po4a
+        @@endnotes={ para: [], end: [] }
+      end
+    end
+    class Output <Source
+      include SiSU_Param
+      include SiSU_Env
+      def initialize(fn,content,md,process=:complete)
+        @fn,@content,@md,@process=fn,content,md,process
+        @file=SiSU_Env::FileOp.new(md,fn)
+      end
+      def po4a                                                                 #%pot output
+        file_pot=@file.write_file.po4a_sst
+        #file_pot=(@md.opt.f_pth[:lng] == @md.opt.lng_base) \
+        #? @file.write_file.pot
+        #: @file.write_file.po
+        @sisu=[]
+        emptyline=0
+        @content.each do |para|                                                # this is a hack
+          if para.is_a?(Array) \
+          and para.length > 0
+            para.each do |line|
+              if line
+                line=line.gsub(/\s+$/m,'').
+                  gsub(/^\A[ ]*\Z/m,'')
+                if line=~/^\A[ ]*\Z/m
+                  emptyline+=1
+                else emptyline=0
+                end
+                file_pot.puts line if emptyline < 2                     #remove extra line spaces (fix upstream)
+              end
+            end
+          else file_pot.puts para          #unix plaintext # /^([*=-]|\.){5}/
+          end
+        end
+        file_pot.close
+        SiSU_Po4aUtils::PotNumber.new.reset
+        #po4a_git
+      end
+      def po4a_git
+        unless @md.opt.act[:maintenance][:set]==:on
+          require_relative 'git'                           # git.rb
+          git=SiSU_Git::Source.new(@md.opt,@process)
+          unless FileTest.directory?(@file.output_path.pot_git.dir)
+            git.create_file_structure_git
+          end
+          if @md.opt.f_pth[:lng] == @md.opt.lng_base
+            FileUtils::cp(
+              @file.place_file.pot.dir,
+              @file.output_path.pot_git.dir
+            )
+          else # naive, work on -->
+            FileUtils::cp(
+              @file.place_file.po.dir,
+              @file.output_path.po_git.dir
+            ) #unless FileTest.file?(@file.place_file.po_git.dir)
+          end
+          git.read
+        end
+      end
+    end
+  end
+end
+__END__
+REMOVE
+&#033;\|&#035;\|&&#042;\|&#045;\|&#047;\|&#095;\|&#123;\|&#125;\|&#126;\|&#
+
+tables are problematic, difficult to reconstitute instruction, check
+
+metadata, move to top? and work on
+
+footnotes, different types, asterisk, also do you want to have separate
+paragraphs, or breaks within one block?
+
+where no ocn appropriately use ~# or -# or indeed 1~name-
+
+comments in document, what to do about them, not sure they are currently
+retained in dal, could be quite valuable to keep
+
+Translate Shell
+http://www.soimort.org/translate-shell/
+translate.google.com
+#+END_SRC
+
+* src_po4a_sst_ao_sst_set.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/src_po4a_sst_ao_sst_set.rb"
+# <<sisu_document_header>>
+module SiSU_Po4aUtils
+  class Wrap
+    def initialize(md,orig='',trans='',n_char_max=76,n_indent=0,n_hang=nil)
+      @md,@orig,@trans,@n_char_max,@n_indent=
+       md, orig, trans, n_char_max, n_indent
+      @n_char_max_extend = n_char_max
+      @br="\n"
+      @n_hang=n_hang ? n_hang : @n_indent
+      @po4a_identify_type='type: SiSU doc'
+      #@po4a_identify_type='type: Plain text'
+    end
+    def line_wrap
+      space=' '
+      spaces_indent,spaces_hang=
+        "#{@br}#{space*@n_indent}",space*@n_hang
+      pot,i=[],0
+      pot_array=(@trans.empty?) ? [@orig] : [@orig,@trans]
+      pot_array.each do |pa|
+        line=0
+        out=[]
+        out[line]=''
+        @oldword='' #REMOVE @oldword
+        pa=pa.gsub(/<br>/,' <br> ').
+          gsub(/#{Mx[:br_nl]}/,"\n\n")
+        words=pa.scan(/\n\n|\\\\\\|<br>|\S+/m)
+        while words != ''
+          word=words.shift
+          if not word
+            out[line] unless out[line].empty? #check
+            break
+          elsif word =~/\n\n/
+            word="\n"
+            @n_char_max_extend = @n_char_max + out[line].length
+            line=line
+          elsif (out[line].length + word.length) > (@n_char_max_extend - @n_indent) \
+          and out[line] =~/\S+/
+            @n_char_max_extend = @n_char_max
+            out[line].squeeze!(' ')
+            line += 1
+          end
+          if word
+            out[line]=if out[line] \
+            and out[line] !~/\S+$/m
+              "#{out[line]}#{word}"
+            elsif out[line] \
+            and out[line] =~/\S+/
+              "#{out[line]} #{word}"
+            else "#{word.strip}"
+            end
+          end
+          @oldword=word if word =~/\S+/
+        end
+        x=out.join(spaces_indent).gsub(/\A\n+/m,'').insert(0,spaces_hang)
+        z=[]
+        x.split(/\n/).each do |y|
+          z << y
+        end
+        pot[i]=z.join("\n")
+        i +=1
+        pot
+      end
+      trans=(pot.length == 2) ? pot[1] : ''
+      po_str=<<WOK
+#{pot[0]}
+WOK
+#{trans}
+      po_str
+    end
+    def no_line_wrap_block
+      pot,i=[],0
+      pot_array=(@trans.empty?) ? [@orig] : [@orig,@trans]
+      pot_array.each do |pa|
+        z=[]
+        pa.split(/\n\n/).each do |y|
+          z << y if not y.empty?
+        end
+        pot[i]=z.join("\n")
+        i +=1
+        pot
+      end
+      trans=(pot.length == 2) ? pot[1] : ''
+      po_str=<<WOK
+#{pot[0]}
+WOK
+#{trans}
+      po_str
+    end
+    def line_wrap_indent1
+      @n_indent,@n_hang=2,2
+      line_wrap
+    end
+    def line_wrap_endnote
+      @n_indent,@n_hang=4,2
+      line_wrap
+    end
+    def array_wrap
+      if @orig.is_a?(Array)
+        @arr=[]
+        @orig.each do |line|
+          @arr << SiSU_TextUtils::Wrap.new(line,@n_char_max,@n_indent,@n_hang).line_wrap
+        end
+      end
+      @arr
+    end
+  end
+  class HeaderScan
+    def initialize(md,para)
+      @md,@p=md,para
+    end
+    def extract(tag,tag_content,type,attrib)
+      if dc_tag \
+      and dc_content
+        [dc_tag,dc_content,{dc_tag=>dc_content}]
+      else nil
+      end
+    end
+    def header(tag,tag_content,type='',attrib='') #this will break stuff and must be tested thoroughly 20060825
+      @tag,@tag_content,@type,@attrib=tag,tag_content,type,attrib
+      def label #element
+        @tag
+      end
+      def type
+        @type
+      end
+      def text
+        @tag_content
+      end
+      def info  #element text
+        @tag_content
+      end
+      def attribute
+        @attrib
+      end
+      def element
+        @tag
+      end
+      def attrib
+        @attrib
+      end
+      def el
+        @tag
+      end
+      self
+    end
+    def start_is_match
+      case @p
+      when /^#{Mx[:meta_o]}(title)#{Mx[:meta_c]}\s*(.+?)$/                      then header($1,@md.title.full,'meta','dc') #dc 1
+      when /^#{Mx[:meta_o]}(creator|author)#{Mx[:meta_c]}\s*(.+?)$/             then header('creator',$2,'meta','dc')    #dc 2
+      when /^#{Mx[:meta_o]}(subject)#{Mx[:meta_c]}\s*(.+?)$/                    then header($1,$2,'meta','dc')           #dc 3
+      when /^#{Mx[:meta_o]}(description)#{Mx[:meta_c]}\s*(.+?)$/                then header($1,$2,'meta','dc')           #dc 4
+      when /^#{Mx[:meta_o]}(publisher)#{Mx[:meta_c]}\s*(.+?)$/                  then header($1,$2,'meta','dc')           #dc 5
+      when /^#{Mx[:meta_o]}(contributor)#{Mx[:meta_c]}\s*(.+?)$/                then header($1,$2,'meta','dc')           #dc 6
+      when /^#{Mx[:meta_o]}(date)#{Mx[:meta_c]}\s*(.+?)$/                       then header($1,$2,'meta','dc')           #dc 7
+      when /^#{Mx[:meta_o]}(date\.created)#{Mx[:meta_c]}\s*(.+?)$/              then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(date\.issued)#{Mx[:meta_c]}\s*(.+?)$/               then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(date\.available)#{Mx[:meta_c]}\s*(.+?)$/            then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(date\.valid)#{Mx[:meta_c]}\s*(.+?)$/                then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(date\.modified)#{Mx[:meta_c]}\s*(.+?)$/             then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(type)#{Mx[:meta_c]}\s*(.+?)$/                       then header($1,$2,'meta','dc')           #dc 8
+      when /^#{Mx[:meta_o]}(format)#{Mx[:meta_c]}\s*(.+?)$/                     then header($1,$2,'meta','dc')           #dc 9
+      when /^#{Mx[:meta_o]}(identifier)#{Mx[:meta_c]}\s*(.+?)$/                 then header($1,$2,'meta','dc')           #dc 10
+      when /^#{Mx[:meta_o]}(source)#{Mx[:meta_c]}\s*(.+?)$/                     then header($1,$2,'meta','dc')           #dc 11
+      when /^#{Mx[:meta_o]}(language)#{Mx[:meta_c]}\s*(.+?)$/                   then header($1,$2,'meta','dc')           #dc 12
+      when /^#{Mx[:meta_o]}(relation)#{Mx[:meta_c]}\s*(.+?)$/                   then header($1,$2,'meta','dc')           #dc 13
+      when /^#{Mx[:meta_o]}(coverage)#{Mx[:meta_c]}\s*(.+?)$/                   then header($1,$2,'meta','dc')           #dc 14
+      when /^#{Mx[:meta_o]}(rights)#{Mx[:meta_c]}\s*(.+?)$/                     then header($1,$2,'meta','dc')           #dc 15
+      when /^#{Mx[:meta_o]}(keywords)#{Mx[:meta_c]}\s*(.+?)$/                   then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(copyright)#{Mx[:meta_c]}\s*(.+?)$/                  then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(translator|translated_by)#{Mx[:meta_c]}\s*(.+?)$/   then header('translator',$2)
+      when /^#{Mx[:meta_o]}(illustrator|illustrated_by)#{Mx[:meta_c]}\s*(.+?)$/ then header('illustrator',$2)
+      when /^#{Mx[:meta_o]}(prepared_by)#{Mx[:meta_c]}\s*(.+?)$/                then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(digitized_by)#{Mx[:meta_c]}\s*(.+?)$/               then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(comments?)#{Mx[:meta_c]}\s*(.+?)$/                  then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(abstract)#{Mx[:meta_c]}\s*(.+?)$/                   then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(tags?)#{Mx[:meta_c]}\s*(.+?)$/                      then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(catalogue)#{Mx[:meta_c]}\s*(.+?)$/                  then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(class(?:ify)?_loc)#{Mx[:meta_c]}\s*(.+?)$/          then header('classify_loc',$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(class(?:ify)?_dewey)#{Mx[:meta_c]}\s*(.+?)$/        then header('classify_dewey',$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(class(?:ify)?_pg)#{Mx[:meta_c]}\s*(.+?)$/           then header('classify_pg',$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(class(?:ify)?_isbn)#{Mx[:meta_c]}\s*(.+?)$/         then header('classify_isbn',$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(toc|structure)#{Mx[:meta_c]}\s*(.+?)$/              then header('structure',$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(level|page|markup)#{Mx[:meta_c]}\s*(.+?)$/          then header('markup',$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(bold)#{Mx[:meta_c]}\s*(.+?)$/                       then header($1,$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(italics|itali[sz]e)#{Mx[:meta_c]}\s*(.+?)$/         then header('italicize',$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(vocabulary|wordlist)#{Mx[:meta_c]}\s*(.+?)$/        then header('vocabulary',$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(css|stylesheet)#{Mx[:meta_c]}\s*(.+?)$/             then header('css',$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(links)#{Mx[:meta_c]}\s*(.+?)$/                      then header($1,$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(prefix)#{Mx[:meta_c]}\s*(.+?)$/                     then header($1,$2,'process','instruct') #add a & b
+      when /^#{Mx[:meta_o]}(suffix)#{Mx[:meta_c]}\s*(.+?)$/                     then header($1,$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(information)#{Mx[:meta_c]}\s*(.+?)$/                then header($1,$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(contact)#{Mx[:meta_c]}\s*(.+?)$/                    then header($1,$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(rcs|cvs)#{Mx[:meta_c]}\s*(.+?)$/                    then header('version',$2,'process','instruct')
+      else nil
+      end
+    end
+    def dublin
+      (@p =~/^#{Mx[:meta_o]}\S+?#{Mx[:meta_c]}/) \
+      ? start_is_match
+      : nil
+    end
+    def meta
+      (@p =~/^#{Mx[:meta_o]}\S+?#{Mx[:meta_c]}/) \
+      ? start_is_match
+      : nil
+    end
+  end
+  class ParagraphNumber
+    def initialize(paranum)
+      @paranum=/(\d+)/m.match(paranum)[1]
+    end
+    def display
+      @paranum.gsub(/(\d+)/,'#\1')
+    end
+  end
+  class PotNumber
+    @@n=0
+    def initialize
+      @@n +=2
+    end
+    def num
+      @@n
+    end
+    def reset
+      @@n=0
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* src_po4a_sstm.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/src_po4a_sstm.rb"
+# <<sisu_document_header>>
+module SiSU_Markup
+  require_relative 'src_shared'                         # src_shared.rb
+    include SiSU_Source
+  require_relative 'src_po4a_share'                     # src_po4a_share.rb
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  class Source_Po4a < SiSU_Source::SiSUpodSource
+    def initialize(opt,build=nil,place=nil)
+      super(opt,build,place)
+      @opt=opt
+      md=SiSU_Param::Parameters.new(opt).get
+      @file=SiSU_Env::FileOp.new(md,opt.fno)
+    end
+    def dir_mk(dir)
+      unless FileTest.directory?(dir)
+        FileUtils::mkdir_p(dir)
+      end
+    end
+    def make_paths
+      dir_mk(@file.output_path.pot.dir)
+      dir_mk(@file.output_path.po.dir)
+    end
+    def language
+      def source_language_selected_str
+        @opt.act[:po4a_lang][:src] \
+        ? @opt.act[:po4a_lang][:src]
+        : 'en'
+      end
+      self
+    end
+    def read
+      unless @opt.act[:quiet][:set]==:on
+        (@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on) \
+        ? SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'Share document markup text source',
+            @opt.fns
+          ).cyan_hi_blue
+        : SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'Share document markup text source',
+            @opt.fns
+          ).cyan_title_hi
+      end
+      make_paths
+      if FileTest.directory?(@path_pod[:fnb])
+        FileUtils::mkdir_p(@file.output_path.src.dir) \
+          unless FileTest.directory?(@file.output_path.src.dir)
+        v=(@opt.act[:maintenance][:set]==:on) \
+        ? 'v' : ''
+        system(%{
+          #rsync -a#{v} #{@path_pod[:fnb]}/sisupod/doc/* #{@file.output_path.po4a.dir}
+          rsync -a#{v} #{@path_pod[:fnb]}/sisupod/doc/#{language.source_language_selected_str}* #{@file.output_path.po4a.dir}
+          chbk=`pwd`
+          cd #{@file.output_path.sisupod.dir}
+          for I in `find -type d` ; do chmod 755 $I ; done
+          for I in `find -type f` ; do chmod 644 $I ; done
+          cd ${chbk}
+        })
+        md=SiSU_Param::Parameters.new(@opt).get
+        file=SiSU_Env::FileOp.new(md)
+        SiSU_Po4a_Project::Po4aCfg.new(@opt,file).song
+        SiSU_Po4a_Project::Po4aProject.new(@opt,file).song
+      else
+        if (@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on)
+          SiSU_Screen::Ansi.new(
+            '',
+            "#{@opt.fno} not available"
+          ).blue_tab
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* src_shared.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/src_shared.rb"
+# <<sisu_document_header>>
+module SiSU_Source
+  include SiSU_Env
+  class SiSUpodSource
+    require_relative 'se'                               # se.rb
+    require_relative 'se_hub_particulars'               # se_hub_particulars.rb
+    require_relative 'utils_composite'                  # utils_composite.rb
+    include SiSU_Composite_Doc_Utils                    # composite doc, .ssm, extract all related insert files, array of filenames test
+    def initialize(opt,build=nil,place=nil)
+      @opt=opt
+      @date=SiSU_Env::InfoDate.new.dt
+      @env=SiSU_Env::InfoEnv.new(opt.fns)
+      #@ver=SiSU_Env::InfoVersion.instance.get_version
+      @v=(@opt.act[:verbose_plus][:set]==:on \
+      || @opt.act[:maintenance][:set]==:on) \
+      ? 'v' : ''
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+      @file=@particulars.file
+      @local_path="#{@file.output_path.sisupod.dir}"
+      processing_sisupod=@env.processing_path.processing_sisupod(opt)
+      processing_sisupod.make
+      path_pod=processing_sisupod.paths[:sisupod]
+      path_pod_fnb=processing_sisupod.paths[:fnb]
+      FileUtils::mkdir_p(path_pod) unless FileTest.directory?(path_pod)
+      @path_pod={
+        fnb:       path_pod_fnb,
+        pod:       path_pod,
+        doc:       path_pod + '/' + Gt[:doc] + '/' + opt.lng,
+        po:        path_pod + '/' + Gt[:po]  + '/' + opt.lng,
+        pot:       path_pod + '/' + Gt[:pot],
+        conf:      path_pod + '/' + Gt[:conf],
+        image:     path_pod + '/' + Gt[:image],
+        audio:     path_pod + '/' + Gt[:audio],
+        video:     path_pod + '/' + Gt[:video],
+      }
+    end
+    def read
+      unless @opt.act[:quiet][:set]==:on
+        (@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on) \
+        ? SiSU_Screen::Ansi.new(
+          @opt.act[:color_state][:set],
+          'Assemble SiSU source',
+          "[#{@opt.f_pth[:lng_is]}] #{@opt.fno}").
+          green_hi_blue
+        : ''
+      end
+      unless @opt.fns.empty?
+        directories
+        doc_import_list=composite_and_imported_filenames_array(@opt.fno)
+        doc_import_list=[@opt.fno, doc_import_list].flatten
+        image_extraction(doc_import_list)
+        language_versions
+      end
+    end
+    def images_extract(f,images)                                                # consider using param info
+      rgx_image=/(?:^|[^_\\])\{(?:\s*|\~\^\s+)(\S+?\.(?:png|jpg|gif)\b)/m
+      if f !~/^%+\s/ \
+      and f =~rgx_image
+        images << f.scan(rgx_image).uniq
+      end
+      images.flatten
+    end
+    def image_extraction(doc_import_list)
+      @rgx_rb_image=/["']\S*?([a-zA-Z0-9_-]+?\.(?:png|jpg|gif))["']/
+      @rgx_image=/(?:^|[^_\\])\{\s*(\S+?\.(?:png|jpg|gif))/
+      doc_import_dir=@opt.sub_location
+      images=[]
+      if doc_import_list.length > 0
+        doc_import_list=doc_import_list.uniq.flatten
+        doc_import_list.each do |fn|
+          file_array=IO.readlines(fn,'')
+          file_array.each do |f|                                               #% work area
+            f=f.gsub(/<:=(\S+?)>/,'{ c_\1.png 14x14 }image')                   # embedded symbol (image)
+            if f !~/^%+\s/ \
+            and f =~@rgx_image
+              images=images_extract(f,images)
+            end
+          end
+        end
+      end
+      gi=SiSU_Env::GetInit.new
+      unless FileTest.file?("#{@path_pod[:conf]}/#{gi.makefile_name}")
+        if gi.makefile \
+        && FileTest.file?(gi.makefile)
+          FileUtils::mkdir_p(@path_pod[:conf]) \
+            unless FileTest.directory?(@path_pod[:conf])
+          FileUtils::cp(gi.makefile,"#{@path_pod[:conf]}/#{gi.makefile_name}")
+        end
+        #get images from makefile, consider placing in param
+      end
+      if images \
+      and images.length > 1
+        images=images.flatten.uniq
+        images.delete_if {|x| x =~/https?:\/\// }
+        #images=images.sort
+        FileUtils::mkdir_p(@path_pod[:image])
+        images_pwd=@opt.image_src_path
+        ##sequence copies base images, defaults used in all html outputs
+          #image_source_base='/usr/share/sisu/image'
+          #dir_pwd=Dir.pwd
+          #Dir.chdir(image_source_base)
+          #base_images=Dir.glob('*')
+          #base_images.each do |i|
+          #  FileUtils::cp_r(i,"#{images_path_pod}/#{i}")
+          #end
+          #Dir.chdir(dir_pwd)
+        if FileTest.directory?(images_pwd)
+          images=images.uniq
+          images.each do |i|
+            if FileTest.file?("#{images_pwd}/#{i}")
+              FileUtils::cp(
+                "#{images_pwd}/#{i}",
+                "#{@path_pod[:image]}/#{i}"
+              )
+            else
+              STDERR.puts \
+                %{\t*WARN* did not find image - } \
+                + %{"#{images_pwd}/#{i}" } \
+                + %{[#{__FILE__}:#{__LINE__}]}
+            end
+          end
+        else
+          STDERR.puts \
+            %{\t*WARN* did not find - } \
+            + %{#{images_pwd} #{@path_pod[:image]} } \
+            + %{[#{__FILE__}:#{__LINE__}]}
+        end
+      end
+      if doc_import_list.length > 0 \
+      and @opt.fno =~/\.ssm$/
+        doc_import_list.each do |f|
+          if FileTest.file?("#{@opt.base_path}#{doc_import_dir}/#{f}")
+            FileUtils::cp(
+              "#{@opt.base_path}#{doc_import_dir}/#{f}",
+              "#{@path_pod[:doc]}/#{f}"
+            )
+          else
+            STDERR.puts \
+              %{\t*WARN* did not find image - } \
+              + %{"#{@opt.base_path}#{doc_import_dir}/#{f}" } \
+              + %{[#{__FILE__}:#{__LINE__}]}
+          end
+        end
+      end
+    end
+    def language_versions
+      x=@env.document_language_versions_found                                  #check multiple document language versions (param not used)
+      doc_import_dir=@opt.sub_location
+      if x[:f] \
+      and x[:f].length > 0                                                     #store multiple document language versions, sisupod
+        x[:f].each do |f|
+          FileUtils::mkdir_p(@path_pod[:doc]) \
+            unless FileTest.directory?(@path_pod[:doc])
+          if f[:f] =~/\~(\S{2,3})\.ss[tm]$/
+            lng_f=$1
+            if @opt.lng == lng_f
+              if @opt.fno =~/\.ssm$/
+                if FileTest.file?("#{@opt.base_path}#{doc_import_dir}/#{f[:f]}")
+                  FileUtils::cp(
+                    "#{@opt.base_path}#{doc_import_dir}/#{f[:f]}",
+                    "#{@path_pod[:doc]}/#{f[:n]}"
+                  )
+                else
+                  STDERR.puts \
+                    %{\t*WARN* did not find - } \
+                    + %{"#{@opt.base_path}#{doc_import_dir}/#{f[:f]}" } \
+                    + %{[#{__FILE__}:#{__LINE__}]}
+                end
+              else
+                if FileTest.file?("#{@opt.base_path}/#{f[:f]}")
+                  cpy= :no
+                  cpy=if f[:f] =~ /^#{@opt.f_pth[:lng_is]}\// \
+                  or f[:f] =~ /~#{@opt.f_pth[:lng_is]}\.sst/
+                    :yes
+                  elsif f[:f] !~ /^(?:#{Px[:lng_lst_rgx]})\/|~(?:#{Px[:lng_lst_rgx]})\.sst/ \
+                  and @opt.f_pth[:lng_is] == 'en'
+                    :yes
+                  else :no
+                  end
+                  if cpy == :yes
+                    FileUtils::cp(
+                      "#{@opt.base_path}/#{f[:f]}",
+                      "#{@path_pod[:doc]}/#{f[:n]}"
+                    )
+                  end
+                else
+                  STDERR.puts \
+                    %{\t*WARN* did not find - } \
+                    + %{"#{@opt.base_path}/#{f[:f]}" } \
+                    + %{[#{__FILE__}:#{__LINE__}]}
+                end
+              end
+            end
+          else
+            if @opt.fno =~/\.ssm$/
+              if FileTest.file?("#{@opt.base_path}#{doc_import_dir}/#{f[:f]}")
+                FileUtils::cp_r(
+                  "#{@opt.base_path}#{doc_import_dir}/#{f[:f]}",
+                  "#{@path_pod[:doc]}/#{f[:n]}"
+                )
+              else
+                STDERR.puts \
+                  %{\t*WARN* did not find - } \
+                  + %{"#{@opt.base_path}#{doc_import_dir}/#{f[:f]}" } \
+                  + %{[#{__FILE__}:#{__LINE__}]}
+              end
+            else
+              if FileTest.file?("#{@opt.base_path}#{doc_import_dir}/#{f[:f]}")
+                cpy= :no
+                cpy=if f[:f] =~ /^#{@opt.f_pth[:lng_is]}\// \
+                or f[:f] =~ /~#{@opt.f_pth[:lng_is]}\.sst/
+                  :yes
+                elsif f[:f] !~ /^(?:#{Px[:lng_lst_rgx]})\/|~(?:#{Px[:lng_lst_rgx]})\.sst/ \
+                and @opt.f_pth[:lng_is] == 'en'
+                  :yes
+                else :no
+                end
+                if cpy == :yes
+                  FileUtils::cp(
+                    "#{@opt.base_path}#{doc_import_dir}/#{f[:f]}",
+                    "#{@path_pod[:doc]}/#{f[:n]}"
+                  )
+                end
+              else
+                STDERR.puts \
+                  %{\t*WARN* did not find - } \
+                  + %{"#{@opt.base_path}#{doc_import_dir}/#{f[:f]}" } \
+                  + %{[#{__FILE__}:#{__LINE__}]}
+              end
+            end
+          end
+        end
+      end #NB not all possibilies met, revisit, also in case of composite file may wish to add README
+    end
+    def directories
+      SiSU_Env::InfoEnv.new.sisupod_v4(@opt)
+    end
+  end
+end
+__END__
+question?:                   should you permit the packing of multiple documents in single .xz ?
+
+  open @opt.fns, parse file
+    extract from file content:
+      images and copy each image from whatever image source to _sisu/sisupod/sisu/_sisu/image
+
+   remove previously existing contents of _/sisu/sisupod &
+   make directory structure:
+
+v3 -->
+   _sisu
+     sisupod
+       doc
+         manifest.txt
+         en/content.sst                [file content]
+         fr/content.sst
+         _sisu
+           conf
+           image (ln -s ../../image)
+           audio (ln -s ../../audio)
+           video (ln -s ../../video)
+       image                           [all images for specific document gathered here]
+       audio
+       video
+
+v2 -->
+   _sisu
+     sisupod
+       content.sst                     [file content]
+       filename.sst                    [link to content.sst]
+       _sisu/
+         image/                        [all images for specific document gathered here]
+
+sisu
+  _sisu
+    sisurc.yml
+    convert/
+    standard_terms/
+    image
+    processing
+      ao/
+      tex/
+      texinfo/
+      tune/
+    sisupod
+
+special case
+
+composite file (master), e.g.
+SiSU.ssm
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    src
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/sst.org b/org/sst.org
new file mode 100644
index 00000000..5cfe98d6
--- /dev/null
+++ b/org/sst.org
@@ -0,0 +1,1713 @@
+-*- mode: org -*-
+#+TITLE:       sisu sst
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:sst:
+#+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
+
+* sst_from_xml.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/sst_from_xml.rb"
+# <<sisu_document_header>>
+module SiSU_sstFromXML
+  require_relative 'se'                                 # se.rb
+  class Convert
+    begin
+      require 'rexml/document'
+        include REXML
+    rescue LoadError
+      SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+        error('rexml/document NOT FOUND (LoadError)')
+    end
+    def initialize(opt)
+      @opt=opt
+      @sisu,@sisu_base=[],[]
+      @ver=SiSU_Env::InfoVersion.instance.get_version
+    end
+    def tell(filename,type)
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        "XML #{type} to SiSU sst",
+        "#{filename} --> #{filename}.sst"
+      ).green_hi_blue
+    end
+    def read
+      xml_to_sisu
+    end
+    def markup_head(text)
+      text.strip!
+      text.gsub!(/(?:\s*\n|\s\s+)/,' ')
+      text.gsub!(/<header class=['"]\S+?['"]>(.+?)<\/header>/,'\1')
+      text.gsub!(/<(\w+)>(.+?)<\/\w+>/,'@\1: \2')
+      text.gsub!(/<header class=['"]\S+?['"]><(\w+)>(.+?)<\/\w+><\/header>/,'@\1: \2')
+      text.gsub!(/\s +/,' ')
+      text.strip!
+      text + "\n\n"
+    end
+    def markup(text)
+      text.strip!
+      text.gsub!(/(?:\s*\n|\s\s+)/,' ')
+      text.gsub!(/<text class='h1'>(.+?)<\/text>/,':A~ \1')
+      text.gsub!(/<text class='h2'>(.+?)<\/text>/,':B~ \1')
+      text.gsub!(/<text class='h3'>(.+?)<\/text>/,':C~ \1')
+      text.gsub!(/<text class='h4'>(.+?)<\/text>/,'1~ \1')
+      text.gsub!(/<text class='h5'>(.+?)<\/text>/,'2~ \1')
+      text.gsub!(/<text class='h6'>(.+?)<\/text>/,'3~ \1')
+      text.gsub!(/<text class='norm'>(.+?)<\/text>/,'\1')
+      text.gsub!(/<endnote symbol='norm'>(.+?)<\/endnote>/,'~{ \1 }~')
+      text.gsub!(/<br ?\/>/,'<br>')
+      text.gsub!(/<i>(.+?)<\/i>/,'/{\1}/')
+      text.gsub!(/<b>(.+?)<\/b>/,'*{\1}*')
+      text.gsub!(/<u>(.+?)<\/u>/,'_{\1}_')
+      text.gsub!(/<sem:([a-z_]+)\s+depth=['"]zero['"]>(\s*.+?\s*)<\/sem:\1>/,';{ \2 };\1')
+      text.gsub!(/<sem:([a-z_]+)\s+depth=['"]one['"]>(\s*.+?\s*)<\/sem:\1>/,':{ \2 }:\1')
+      text.gsub!(/<sem:([a-z_]+)\s+depth=['"]many['"]>(\s*.+?\s*)<\/sem:\1>/,'\1:{ \2 }:\1')
+      text.gsub!(/<sem:([a-z_]+)>(\s*.+?\s*)<\/sem:\1>/,'\1:{ \2 }:\1')
+      text.gsub!(/\s +/,' ')
+      text.strip!
+      text + "\n\n"
+    end
+    def sax
+      out_file=File.new(@output_file_name,'w')
+      head=@doc.root.get_elements('//head/header')
+      body=@doc.root.get_elements('//object/text')
+      out_file.puts "% SiSU text #{@ver.version} (generated from a SiSU XML markup representation)\n\n"
+      head.each do |x|
+        if x.name=='header'
+          head=markup_head(x.to_s)
+          out_file.puts head
+        end
+      end
+      body.each do |x|
+        if x.name=='text'
+          body=markup(x.to_s)
+          out_file.puts body
+        end
+      end
+    end
+    def node
+      sax
+    end
+    def dom
+      raise "#{__FILE__}::#{__LINE__} xml dom representation to sst not yet implemented (experimental simple xml representations sax and node to sst are in place)."
+    end
+    def xml_to_sisu
+      unless @opt.files.empty?
+        @opt.files.each do |xml|
+          @sisu_base=[]
+          if xml =~/\.sx[sdn]\.xml$/
+            begin
+              @doc_str=IO.readlines(xml,'').join("\n")
+              @output=File.new("#{xml}.sst",'w')
+              @doc=REXML::Document.new(@doc_str)
+              @output_file_name="#{Dir.pwd}/#{xml}.sst"
+              @el=[]
+            rescue REXML::ParseException
+            end
+          end
+          if xml =~/\.sxs\.xml$/
+            unless @opt.act[:quiet][:set]==:on
+              tell(xml,'sax')
+            end
+            sax
+          elsif xml =~/\.sxd\.xml$/
+            unless @opt.act[:quiet][:set]==:on
+              tell(xml,'dom')
+            end
+            dom
+          elsif xml =~/\.sxn\.xml$/
+            unless @opt.act[:quiet][:set]==:on
+              tell(xml,'node')
+            end
+            node
+          else puts "filename not recognised: << #{xml} >>"
+          end
+          @output << @sisu_base
+        end
+      else puts '.xml file for conversion to sisu expected'
+      end
+      puts @opt.files.inspect
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* sst_to_s_xml_sax.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/sst_to_s_xml_sax.rb"
+# <<sisu_document_header>>
+module SiSU_SimpleXML_ModelSax
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+    include SiSU_Particulars
+  require_relative 'dp'                                 # dp.rb
+    include SiSU_Param
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'ao_doc_str'                         # ao_doc_str.rb
+  require_relative 'xml_shared'                         # xml_shared.rb
+    include SiSU_XML_Munge
+  require_relative 'shared_sem'                         # shared_sem.rb
+  require_relative 'xml_format'                         # xml_format.rb
+    include SiSU_XML_Format
+  require_relative 'rexml'                              # rexml.rb
+    include SiSU_Rexml
+  @@alt_id_count=0
+  @@tablefoot=''
+  class Convert
+    @@fns=nil
+    def initialize(opt)
+      @opt=opt
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_env_md(opt)
+    end
+    def read
+      begin
+        @md=@particulars.md #bug, relies on info persistence, assumes -m has previously been run
+        @env=@particulars.env
+        SiSU_Screen::Ansi.new(
+          @opt.act[:color_state][:set],
+          'invert',
+          'XML SAX',
+          "#{@md.fns} -> #{@md.fn[:sxs]}"
+        ).colorize unless @opt.act[:quiet][:set]==:on
+        if (@opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on)
+          SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            @opt.fns,
+            "#{Dir.pwd}/#{@md.fn[:sxs]}"
+          ).flow
+        end
+        unless @@fns==@opt.fns
+          @@fns=@opt.fns
+          @@fns_array=[]
+        end
+        @fns_array=if @@fns_array.empty?; read_fnm
+        else @@fns_array.dup #check
+        end
+        SiSU_SimpleXML_ModelSax::Convert::Songsheet.new(@fns_array,@particulars).songsheet
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.cmd,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure #file closed in songsheet
+      end
+    end
+    def read_fnm
+      ao=[]
+      if FileTest.file?("#{Dir.pwd}/#{@opt.fns}")
+        ao=IO.readlines("#{Dir.pwd}/#{@opt.fns}","\n\n")
+      else STDERR.puts 'Error'
+      end
+    end
+    private
+    class Songsheet
+      def initialize(data,particulars)
+        @data,@particulars,@env,@md=data,particulars,particulars.env,particulars.md
+      end
+      def songsheet
+        begin
+          SiSU_SimpleXML_ModelSax::Convert::Scroll.new(@data,@particulars).songsheet
+          if (@md.opt.act[:verbose][:set]==:on \
+          || @md.opt.act[:verbose_plus][:set]==:on \
+          || @md.opt.act[:maintenance][:set]==:on)
+            SiSU_SimpleXML_ModelSax::Convert::Tidy.new(@md,@env).xml # test wellformedness, comment out when not in use
+          end
+          SiSU_Rexml::Rexml.new(@md,@md.fn[:sxs]).xml if @md.opt.act[:maintenance][:set]==:on # test rexml parsing, comment out when not in use #debug
+        rescue
+          SiSU_Errors::Rescued.new($!,$@,@md.opt.cmd,@md.fns).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+        ensure
+        end
+      end
+    end
+    class Scroll
+      require_relative 'txt_shared'                     # txt_shared.rb
+      require_relative 'css'                            # css.rb
+        include SiSU_TextUtils
+      @@xml={ body: [], open: [], close: [], head: [] }
+      def initialize(data='',particulars='')
+        @data,@env,@md=data,particulars.env,particulars.md
+        @regx=/^(?:#{Mx[:mk_o]}:p[bn]#{Mx[:mk_c]}\s*)?(?:#{Mx[:lv_o]}[1-9]:(\S*)#{Mx[:lv_c]})?(.+)/
+        @tab="\t"
+        if @md
+          @trans=SiSU_XML_Munge::Trans.new(@md)
+        end
+        @sys=SiSU_Env::SystemCall.new
+      end
+      def songsheet
+        pre
+        markup
+        post
+        publish
+      end
+    protected
+      def embedded_endnotes(para='')
+        para.gsub!(/~\{(.+?)\}~/,'<endnote symbol="norm">\1</endnote> ')
+        para.gsub!(/~\[([*+])\s+(.+?)\]~/,'<endnote symbol="\1">\2</endnote> ')
+      end
+      def xml_head(meta)
+        txt=meta.text
+        txt.gsub!(/\/{(.+?)}\//,'<i>\1</i>')
+        txt.gsub!(/[*!]{(.+?)}[*!]/,'<b>\1</b>')
+        txt.gsub!(/_{(.+?)}_/,'<u>\1</u>')
+        txt.gsub!(/-{(.+?)}-/,'<del>\1</del>')
+        txt.gsub!(/<br(?: \/)?>/,'<br />')
+        txt.gsub!(/ & /,' and ')
+        @@xml[:head] <<<<WOK
+#{@tab}<header class="#{meta.attrib}">
+#{@tab*2}<#{meta.el}>
+#{@tab*3}#{txt}
+#{@tab*2}</#{meta.el}>
+#{@tab}</header>
+WOK
+      end
+      def xml_sc(md='')
+        sc=if @md.sc_info
+          <<WOK
+    <source_control>
+      <sc class="sourcefile">
+        #{@md.sc_filename}
+      </sc>
+      <sc class="number">
+        #{@md.sc_number}
+      </sc>
+      <sc class="date">
+        #{@md.sc_date}
+      </sc>
+    </source_control>
+WOK
+        else ''
+        end
+        @@xml[:sc]=sc
+      end
+      def xml_structure(para='',lv='',hname='') #extracted endnotes
+        lv=lv.to_i
+        lv=nil if lv==0
+        embedded_endnotes(para)
+        if para[@regx]
+          paragraph="#{para[@regx,2]}"
+          util=SiSU_TextUtils::Wrap.new(paragraph,70)
+          wrapped=util.line_wrap
+        end
+        @@xml[:body] << "#{@tab*0}<object>" if para[@regx]
+        @@xml[:body] << "#{@tab*1}" << "\n" if para[@regx]
+        @@xml[:body] << if lv; %{#{@tab*1}<text class="h#{lv}">\n#{@tab*2}#{wrapped}\n#{@tab*1}</text>\n} << "\n"
+        elsif wrapped =~/\A%%?\s+/; %{<!--\n#{@tab*1}<text class="comment">\n#{@tab*2}#{wrapped}\n#{@tab*1}</text>\n-->\n} # comments
+        else                        %{#{@tab*1}<text class="norm">\n#{@tab*2}#{wrapped}\n#{@tab*1}</text>\n} # main text, contents, body KEEP
+        end
+        @@xml[:body] << "#{@endnotes}" if @endnotes # main text, endnotes KEEP
+        @@xml[:body] << "#{@tab*0}</object>" << "\n" if para[@regx]
+        @endnotes=[]
+      end
+      def block_structure(para='')
+        para.gsub!(/<:block(?:-end)?>/,'')
+        para.strip!
+        @@xml[:body] << %{#{@tab*0}<object>}
+        @@xml[:body] << %{#{@tab*1}<text class="block">#{@tab*1}\n}
+        @@xml[:body] << %{#{@tab*2}#{para}#{@tab*1}\n}
+        @@xml[:body] << %{#{@tab*1}</text>\n}
+        @@xml[:body] << "#{@tab*0}</object>"
+      end
+      def group_structure(para='')
+        para.gsub!(/<:group(?:-end)?>/,'')
+        para.strip!
+        @@xml[:body] << %{#{@tab*0}<object>}
+        @@xml[:body] << %{#{@tab*1}<text class="group">#{@tab*1}\n}
+        @@xml[:body] << %{#{@tab*2}#{para}#{@tab*1}\n}
+        @@xml[:body] << %{#{@tab*1}</text>\n}
+        @@xml[:body] << "#{@tab*0}</object>"
+      end
+      def poem_structure(para='')
+        para.gsub!(/<:verse(?:-end)?>/,'')
+        para.strip!
+        @@xml[:body] << %{#{@tab*0}<object>}
+        @@xml[:body] << %{#{@tab*1}<text class="verse">#{@tab*1}\n}
+        @@xml[:body] << %{#{@tab*2}#{para}#{@tab*1}\n}
+        @@xml[:body] << %{#{@tab*1}</text>\n}
+        @@xml[:body] << "#{@tab*0}</object>" << "\n"
+      end
+      def code_structure(para='')
+        para.gsub!(/<:code(?:-end)?>/,'')
+        para.strip!
+        @@xml[:body] << %{#{@tab*0}<object>}
+        @@xml[:body] << %{#{@tab*1}<text class="code">#{@tab*1}\n}
+        @@xml[:body] << %{#{@tab*2}#{para}#{@tab*1}\n}
+        @@xml[:body] << %{#{@tab*1}</text>\n}
+        @@xml[:body] << "#{@tab*0}</object>" << "\n"
+      end
+      def table_structure(table='') #tables
+        @@xml[:body] << %{#{@tab*0}<object>}
+        @@xml[:body] << %{#{@tab*1}#{table}\n#{@tab*1}\n} # unless lv  # main text, contents, body KEEP
+        @@xml[:body] << "#{@tab*0}</object>" << "\n" #if para[@regx]
+        @endnotes=[]
+      end
+      def tidywords(wordlist)
+        wordlist.each do |x|
+          x.gsub!(/&/,'&amp;') unless x =~/&\S+;/
+        end
+      end
+      def xml_clean(para)
+        para.gsub!(/#{Mx[:gl_o]}[1-9]:\S*?#{Mx[:gl_c]}/,'') #Danger, watch
+        para
+      end
+      def markup
+        data=[]
+        xml_sc(@md)
+        @endnotes,@level,@cont,@copen,@xml_contents_close=[],[],[],[],[]
+        @rcdc=false
+        (0..6).each { |x| @cont[x]=@level[x]=false }
+        (4..6).each { |x| @xml_contents_close[x]='' }
+        @data.each do |para|
+          data << SiSU_AO_DocumentStructureExtract::Structure.new(@md,para).structure #takes on Mx marks
+        end
+        data.each do |para|
+          if para !~/^\s*(?:%+ |<:code>)/
+            if @md.sem_tag and para =~/[:;]\{|\}[:;]/
+              para=@trans.xml_semantic_tags(para)
+            end
+            if para =~/[:;]\{|\}[:;]/
+              para=SiSU_Sem::Tags.new(para,@md).rm.all
+            end
+          end
+          para=@trans.markup_light(para)
+          @trans.char_enc.utf8(para) if @sys.locale =~/utf-?8/i #% utf8
+          para.gsub!(/^@(\S+?):/,"#{Mx[:lv_o]}@\\1#{Mx[:lv_c]}")
+          if para =~/\A#{Mx[:lv_o]}@(\S+?)#{Mx[:lv_c]}\s*(.+?)\Z/m # for headers
+            d_meta=SiSU_TextUtils::HeaderScan.new(@md,para).meta
+            if d_meta; xml_head(d_meta)
+            end
+          end
+          para='' if para=~/#{Mx[:lv_o]}@\S+?#{Mx[:lv_c]}/
+          if @rcdc==false \
+          and (para =~/~metadata/ or para =~/^1~meta\s+Document Information/)
+            @rcdc=true
+          end
+          if para !~/(^@\S+?:|^\s*$|<ENDNOTES>|<EOF>)/
+            @sto=SiSU_text_parts::SplitTextObject.new(@md,para).lev_segname_para
+            unless @rcdc
+              SiSU_XML_Format::FormatScroll.new(@md,@sto.text) if @sto.format =~/i[1-9]|ordinary/
+              case @sto.format
+              when /^(1):(\S*)/
+                xml_clean(para)
+                xml_structure(para,$1,$2)
+                para=@sto.lev_para_ocn.heading_body1
+              when /^(2):(\S*)/
+                xml_clean(para)
+                xml_structure(para,$1,$2)
+                para=@sto.lev_para_ocn.heading_body2
+              when /^(3):(\S*)/
+                xml_clean(para)
+                xml_structure(para,$1,$2)
+                para=@sto.lev_para_ocn.heading_body3
+              when /^(4):(\S*)/ # work on see SplitTextObject
+                xml_clean(para)
+                xml_structure(para,$1,$2)
+                para=@sto.lev_para_ocn.heading_body4
+              when /^(5):(\S*)/
+                xml_clean(para)
+                xml_structure(para,$1,$2)
+                para=@sto.lev_para_ocn.heading_body5
+              when /^(6):(\S*)/
+                xml_clean(para)
+                xml_structure(para,$1,$2)
+                para=@sto.lev_para_ocn.heading_body6
+              else
+                if para =~ /<:verse>/
+                  para=poem_structure(para)
+                elsif para =~ /<:group>/
+                  para=group_structure(para)
+                elsif para =~ /<:code>/
+                  para.gsub!(/</,'&lt;')
+                  para.gsub!(/>/,'&gt;')
+                  para=code_structure(para)
+                elsif para =~/<!Th?.+/ # tables come as single block #work area 2005w13
+                  table=SiSU_Tables::TableXML.new(para)
+                  para=table.table_split
+                  para=table_structure(para)
+                else xml_structure(para,nil,nil)
+                end
+              end
+              if para =~/<a name="n\d+">/ \
+              and para =~/^(-\{{2}~\d+|<!e[:_]\d+!>)/ # -endnote
+                para=''
+              end
+              if para =~/.*<:#>.*$/
+                para=case para
+                when /<:i1>/
+                  format_text=FormatTextObject.new(para,'')
+                  format_text.scr_inden_ocn_e_no_paranum
+                when /<:i2>/
+                  format_text=FormatTextObject.new(para,'')
+                  format_text.scr_inden_ocn_e_no_paranum
+                end
+              end
+              if para =~/<:center>/
+                one,two=/(.*)<:center>(.*)/.match(para)[1,2]
+                format_text=FormatTextObject.new(one,two)
+                para=format_text.center
+              end
+            end
+            para.gsub!(/<:\S+?>/,'')
+            para.gsub!(/<!.+!>/,'') ## Clean Prepared Text #bugwatch reinstate
+            para
+          end
+          para
+        end
+        6.downto(4) do |x|
+          y=x - 1; v=x - 3
+          @@xml[:body] << "#{@tab*5}</content>\n#{@tab*y}</contents#{v}>\n" if @level[x]==true
+        end
+        3.downto(1) do |x|
+          y=x - 1
+          @@xml[:body] << "#{@tab*y}</heading#{x}>\n" if @level[x]==true
+        end
+      end
+      def pre
+        rdf=SiSU_XML_Tags::RDF.new(@md)
+        dir=SiSU_Env::InfoEnv.new
+        @@xml[:head],@@xml[:body]=[],[]
+        css=SiSU_Env::CSS_Select.new(@md).xml_sax
+        encoding=if @sys.locale =~/utf-?8/i then '<?xml version="1.0" encoding="UTF-8" standalone="no"?>'
+        else                                     '<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>'
+        end
+        @@xml[:open] =<<WOK
+#{encoding}
+<?xml-stylesheet type="text/css" href="../#{dir.path.style}/#{css}"?>
+#{rdf.comment_xml_sax}
+<document>
+WOK
+        @@xml[:head] << "<head>\n"
+        @@xml[:body] << "<body>\n"
+      end
+      def post
+        @@xml[:head] << @@xml[:sc]
+        @@xml[:head] << "</head>\n"
+        @@xml[:body] << "</body>\n"
+        @@xml[:close] = "</document>\n"
+      end
+      def publish
+        content=[]
+        content << @@xml[:open] << @@xml[:head] << @@xml[:body] << @@xml[:metadata]
+        content << @@xml[:owner_details] if @md.stmp =~/\w\w/
+        content << @@xml[:tail] << @@xml[:close]
+        Output.new(content.join,@md).xml
+        @@xml={}
+      end
+    end
+    class Output
+      def initialize(data,md)
+        @data,@md=data,md
+      end
+      def xml
+        @sisu=[]
+        @data.each do |para|
+          para.gsub!(/<:\S+?>/,'')
+          para.gsub!(/<!.+?!>/,'')
+          para="#{para}\n" unless para.empty?
+          @sisu << para
+        end
+        new_file_data=@sisu.join
+        @sisu=new_file_data.scan(/.+/)
+        SiSU_Env::FileOp.new(@md).mkdir
+        filename_sxm=SiSU_Env::FileOp.new(@md,@md.fn[:sxs]).mkfile_pwd
+        if filename_sxm.is_a?(File)
+          @sisu.each {|para| filename_sxm.puts para}
+          filename_sxm.close
+        else puts 'file not created, is directory writable?'
+        end
+      end
+    end
+    class Tidy
+      def initialize(md,dir)
+        @md,@env=md,dir
+        @prog=SiSU_Env::InfoProgram.new
+      end
+      def xml
+        if @prog.tidy !=false #note values can be other than true
+          if (@md.opt.act[:verbose_plus][:set]==:on \
+          || @md.opt.act[:maintenance][:set]==:on)
+            SiSU_Screen::Ansi.new(
+              @md.opt.act[:color_state][:set],
+              'invert',
+              'Using XML Tidy',
+              'check document structure'
+            ).colorize unless @md.opt.act[:quiet][:set]==:on
+            SiSU_Screen::Ansi.new(
+              @md.opt.act[:color_state][:set],
+              '',
+              '',
+              'check document structure'
+            )
+            tell.grey_open unless @md.opt.act[:quiet][:set]==:on
+            tidyfile='/dev/null' #don't want one or screen output, check for alternative flags
+            tidy =SiSU_Env::SystemCall.new("#{Dir.pwd}/#{@md.fn[:sxs]}",tidyfile)
+            tidy.well_formed?
+            tell.p_off unless @md.opt.act[:quiet][:set]==:on
+          end
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* sst_identify_markup.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/sst_identify_markup.rb"
+# <<sisu_document_header>>
+module SiSU_Markup
+  class MarkupInform
+    attr_accessor :version
+    def initialize(version,message,declared_markup='',declared_type='')
+      @version,@message,@declared_markup,@declared_type=version,message,declared_markup,declared_type
+    end
+    def version
+      @version
+    end
+    def message
+      @message
+    end
+    def declared_version
+      @declared_markup
+    end
+    def declared_type
+      @declared_type
+    end
+    def history
+      MarkupHistory.new(@version).query
+    end
+  end
+  class MarkupIdentify
+    def initialize(opt)
+      @opt=opt
+      @description='This is a script attempts to identify the version of markup used in SiSU (and provides information on changes in markup)'
+    end
+    def help
+    print <<WOK
+
+#{@description}
+
+WOK
+      exit
+    end
+    def identify
+      f=@opt.fns
+      if f =~/(?:\.sst|\.ssm|\.ssi|\.s[123])$/ \
+      and File.exist?(f)
+        file=File.open(f,'r')
+        cont=file.readlines
+        file.close
+        links,oldlinks='',''
+        markup=nil
+        @declared_type,@declared_markup='[text?]',''
+        if cont[0] =~ /^(?:%\s+)?SiSU\s+(text|master|insert)\s+([0-9](?:\.[0-9]+){1,2})/ \
+        or cont[0] =~ /^(?:%\s+)?sisu-([0-9](?:\.[0-9]+){1,2})/
+          @declared_type,@declared_markup=$1,$2
+        elsif cont[0] =~ /^(?:%\s+)?SiSU\s+([0-9](?:\.[0-9]+){1,2})/ \
+        or cont[0] =~ /^(?:%\s+)?sisu-([0-9](?:\.[0-9]+){1,2})/
+          @declared_markup=$1
+        end
+        @flag_2_0,@flag_1_0,@flag_69,@flag_66,@flag_57,@flag_38=false,false,false,false,false,false
+        cont.each_with_index do |y,i|
+          if y =~/^(?:0\{?~links?|@links?:)\s/ \
+          and f =~/(?:\.sst|\.ssm|\.ssi|\.s[123])/
+            links=unless y =~/\{.+?\}\S+/; oldlinks=' (pre 0.20.4 header links)'
+            else ' (post 0.20.4 header links)'
+            end
+          end
+          if @flag_2_0 \
+          or y =~/^@make:|^@classify|^\s\s?:[a-z_-]+?:\s+\S/
+            version=2.0.to_f
+            markup=MarkupInform.new(version,'2.0' + oldlinks,@declared_markup,@declared_type)
+            @flag_2_0=true
+            break
+          end
+          unless @flag_38
+            if (y =~/^:?A~/ and f =~/(?:\.sst|\.ssm|\.ssi)/)
+              version='0.38'
+              markup=MarkupInform.new(version,'0.38' + oldlinks,@declared_markup,@declared_type)
+              @flag_38=true
+            end
+          end
+          if @flag_38
+            if @flag_1_0 \
+            or y =~/^=\{.+?\}\s*$/
+              version='0.69'
+              markup=MarkupInform.new(version,'0.69' + oldlinks,@declared_markup,@declared_type)
+              @flag_1_0=true
+              break
+            end
+            if @flag_66 \
+            or y =~/[a-z+][:;]\{.+?\}[:;][a-z+]/
+              version='0.66'
+              markup=MarkupInform.new(version,'0.66' + oldlinks,@declared_markup,@declared_type)
+              @flag_66=true
+              break
+            end
+          end
+        end
+        unless @flag_2_0 \
+        or @flag_1_0 \
+        or @flag_66
+          cont.each_with_index do |y,i|
+            if y =~/^(?:0\{?~links?|@links?:)\s/ \
+            and f =~/(?:\.sst|\.ssm|\.ssi|\.s[123])/
+              links=unless y =~/\{.+?\}\S+/; oldlinks=' (pre 0.20.4 header links)'
+              else ' (post 0.20.4 header links)'
+              end
+            end
+            if @flag_57 \
+            or (y =~/^:?A~\?? @title/ and f =~/(?:\.sst|\.ssm|\.ssi)/)
+              version='0.57'
+              markup=MarkupInform.new(version,'0.57' + oldlinks,@declared_markup,@declared_type)
+              @flag_57=true
+              break
+            end
+            if @flag_38 \
+            or (y =~/^:?A~/ and f =~/(?:\.sst|\.ssm|\.ssi)/)
+              version='0.38'
+              markup=MarkupInform.new(version,'0.38' + oldlinks,@declared_markup,@declared_type)
+              @flag_38=true
+              break if i >= 200
+              if y =~ /(?:~{\*+|~\[\*|~\[\+)\s/
+                version='0.42'
+                markup=MarkupInform.new(version,'0.42' + oldlinks,@declared_markup,@declared_type)
+                break
+              end
+            end
+            if (y =~/^1~/ and f =~/(?:\.sst|\.ssm|\.ssi)/) \
+            and not @flag_38
+              version='0.37'
+              markup=MarkupInform.new(version,'0.37 is substantially 0.16 - 0.36 markup with new file-extension' + oldlinks,@declared_markup,@declared_type)
+              break
+            end
+            if y =~/^1~/ \
+            and f =~/\.([rs])([123])/ \
+            and not @flag_38
+              t,n=$1,$2
+              version='0.16'
+              instruct=if t =~/r/
+                " (change file extension from .#{t}#{n} to .ssm)"
+              else " (change file extension from .#{t}#{n} to .sst)"
+              end
+              markup=MarkupInform.new(version,'0.16 - 0.36' + instruct + links,@declared_markup,@declared_type)
+              break
+            end
+            if y =~/^0\{~/ \
+            and not @flag_38
+              version='0.1'
+              markup=MarkupInform.new(version,'0.1 - 0.15',@declared_markup,@declared_type)
+              break
+            end
+            if y =~/^0\{{3}/ \
+            and not @flag_38
+              markup=MarkupInform.new('circa. 1997','old, check date',@declared_markup,@declared_type)
+              break
+            end
+            markup='Not a recognised file type '
+          end
+        end
+        markup
+      else MarkupHistory.new(@opt).help_query
+      end
+    end
+    def determine_markup_version
+      if @opt.fns.nil? \
+      or @opt.fns.empty?
+        MarkupHistory.new(@opt).help_identify
+      end
+      if File.exist?(@opt.fns)
+        if @opt.fns =~/\.(?:sst|ssm|ssi|s[123i]|r[123])/
+          markup=identify #(@opt.fns)
+          if defined? markup.version
+            unless @opt.act[:quiet][:set]==:on
+              message=unless markup.declared_version.empty?
+                "#{@opt.fns}\n  markup Type Declared as SiSU #{markup.declared_version} #{markup.declared_type}\n  appears to be SiSU #{markup.version}"
+              else
+                "Markup Type Appears to be SiSU #{markup.version}\n  in file #{@opt.fns}"
+              end
+              puts message
+              puts %{"sisu --query-#{markup.version}" for a brief description of markup type}
+            end
+          end
+        else puts 'file-type not recognised: ' + @opt.fns
+        end
+      else puts 'file not found: ' + @opt.fns
+      end
+      (defined? markup.version) \
+      ? markup.version
+      : 'markup type/version not determined'
+    end
+    def markup_version?
+      if @opt.fns.empty?
+        @opt.files.each do |fns|
+          @opt.fns=fns
+          determine_markup_version
+        end
+      else determine_markup_version
+      end
+    end
+  end
+  class MarkupHistory
+    def initialize(opt)
+      @opt=opt
+    end
+    def sisu_3_0
+      <<WOK
+  SiSU 3.0 same as 2.0, apart from change to headers
+
+    see document markup samples, and sisu --help headers
+
+WOK
+    end
+    def sisu_2_0
+      <<WOK
+  SiSU 2.0 same as 1.0, apart from the changing of headers and the addition of a monospace tag
+    related headers now grouped, e.g.
+
+    @title:
+     :subtitle:
+
+    @creator:
+     :author:
+     :translator:
+     :illustrator:
+
+    see document markup samples, and sisu --help headers
+
+    the monospace tag takes the form of a has '#' \#{ this enclosed text would be monospaced }#
+
+WOK
+    end
+    def sisu_1_0
+      <<WOK
+  SiSU 1.0 same as 0.69
+
+WOK
+    end
+    def sisu_0_69
+      <<WOK
+  SiSU 0.69 (same as 1.0) as previous (0.57) with the addition of book index tags
+    /^=\{.+?\}$/
+    e.g. appended to a paragraph, on a new-line (without a blank line in between)
+    logical structure produced assuming this is the first text "object"
+    ={GNU/Linux community distribution:Debian+2|Fedora|Gentoo;Free Software Foundation+5}
+
+   Free Software Foundation, 1-6
+   GNU/Linux community distribution, 1
+       Debian, 1-3
+       Fedora, 1
+       Gentoo,
+
+WOK
+    end
+    def sisu_0_66
+      <<WOK
+  SiSU 0.66 same as previous, adds semantic tags
+    /[:;]\{.+?\}[:;][a-z+]/
+    e.g. :{ Ralph last;{Amissah};last }:author
+
+WOK
+    end
+    def sisu_0_65
+      <<WOK
+  SiSU 0.65 same as previous, adds semantic tags
+    /[a-z+][:;]\{.+?\}[:;][a-z+]/
+    e.g. author:{ Ralph last;{Amissah};last }:author
+
+WOK
+    end
+    def sisu_0_57
+      <<WOK
+
+  SiSU 0.57 (a subset of 1.0) is the same as 0.42 with the introduction of some
+  a shortcut to use the headers @title and @creator in the first heading
+  [expanded using the contents of the headers @title: and @author:]
+
+  :A~ @title by @author
+
+WOK
+    end
+    def sisu_0_42
+      <<WOK
+  SiSU 0.42 (a subset of 1.0) is the same as 0.38 with the introduction of some additional endnote types,
+
+  Introduces some varations on endnotes, in particular the use of the asterisk
+  ~{* for example for describing an author }~ and ~{** for describing a second author }~
+
+  * for example for describing an author
+
+  ** for describing a second author
+
+  and ~[* my note ]~ or ~[+ another note ]~ which numerically increments an
+  asterisk and plus respectively
+
+  *1 my note
+  +1 another note
+
+WOK
+    end
+    def sisu_0_38
+      <<WOK
+
+  SiSU 0.38 (a subset of 1.0) introduced alternative experimental header and heading/structure markers,
+
+  @headername: and headers :A~ :B~ :C~ 1~ 2~ 3~
+
+  as the equivalent of (the superceded)
+
+  0~headername and headers 1~ 2~ 3~ 4~ 5~ 6~
+
+  The internal document markup of SiSU 0.16 remains valid and standard
+  Though note that SiSU 0.37 introduced a new file naming convention
+
+  SiSU has in effect two sets of levels to be considered, using 0.38 notation
+  A-C headings/levels, pre-ordinary paragraphs /pre-substantive text, and
+  1-3 headings/levels, levels which are followed by ordinary text.
+    This may be conceptualised as levels A,B,C, 1,2,3, and using such letter
+    number notation, in effect:
+      A must exist, optional B and C may follow in sequence (not strict)
+      1 must exist, optional 2 and 3 may follow in sequence
+    i.e. there are two independent heading level sequences A,B,C and 1,2,3
+      (using the 0.16 standard notation 1,2,3 and 4,5,6)
+    on the positive side:
+      * the 0.38 A,B,C,1,2,3 alternative makes explicit an aspect of structuring
+        documents in SiSU that is not otherwise obvious to the newcomer (though
+        it appears more complicated, is more in your face and likely to be
+        understood fairly quickly)
+      * the substantive text follows levels 1,2,3 and it is 'nice' to do
+        most work in those levels
+WOK
+    end
+    def sisu_0_37
+      <<WOK
+
+  SiSU 0.37 introduced the file naming convention, that remains in use in SiSU
+  v1 and v2, using the file extensions .sst .ssm and .ssi
+  to replace .s1 .s2 .s3 .r1 .r2 .r3  and .si
+
+  this is captured by the following file 'rename' instruction:
+
+  rename 's/\.s[123]$/\.sst/' *.s{1,2,3}
+  rename 's/\.r[123]$/\.ssm/' *.r{1,2,3}
+  rename 's/\.si$/\.ssi/' *.si
+
+  The internal document markup remains unchanged, from SiSU 0.16
+WOK
+    end
+    def sisu_0_16
+      <<WOK
+
+  SiSU 0.16 (0.15 development branch) introduced the use of
+
+  the header 0~ and headings/structure 1~ 2~ 3~ 4~ 5~ 6~
+
+  in place of the 0.1 header, heading/structure notation
+WOK
+    end
+    def sisu_0_1
+      <<WOK
+
+  SiSU 0.1 headers and headings structure represented by
+  header 0{~ and headings/structure  1{ 2{ 3{ 4{~ 5{ 6{
+WOK
+    end
+    def help_query
+      <<WOK
+
+  sisu --query=[sisu version [0.38] or 'history]
+  provides a short history of changes to SiSU markup
+
+WOK
+    end
+    def help_identify
+      <<WOK
+
+  sisu --identify [filename]
+  attempts to identify the SiSU markup used in a file
+
+WOK
+    end
+    def query
+      tell=if @opt.selections.str =~/--query/
+        tell=case @opt.selections.str
+        when /history/
+          "#{sisu_3_0}#{sisu_2_0}#{sisu_1_0}#{sisu_0_69}#{sisu_0_66}#{sisu_0_57}#{sisu_0_42}#{sisu_0_38}\n#{sisu_0_37}\n#{sisu_0_16}\n#{sisu_0_1}"
+        when /3.0/
+          "#{sisu_3_0}#{sisu_2_0}#{sisu_1_0}#{sisu_0_69}#{sisu_0_66}#{sisu_0_57}#{sisu_0_42}#{sisu_0_38}#{sisu_0_16}"
+        when /2.0/
+          "#{sisu_2_0}#{sisu_1_0}#{sisu_0_69}#{sisu_0_66}#{sisu_0_57}#{sisu_0_42}#{sisu_0_38}#{sisu_0_16}"
+        when /1.0/
+          "#{sisu_1_0}#{sisu_0_69}#{sisu_0_66}#{sisu_0_57}#{sisu_0_42}#{sisu_0_38}#{sisu_0_16}"
+        when /0.69/
+          "#{sisu_0_69}#{sisu_0_66}#{sisu_0_57}#{sisu_0_42}#{sisu_0_38}#{sisu_0_16}"
+        when /0.66/
+          "#{sisu_0_66}#{sisu_0_57}#{sisu_0_42}#{sisu_0_38}#{sisu_0_16}"
+        when /0.65/
+          "#{sisu_0_65}#{sisu_0_57}#{sisu_0_42}#{sisu_0_38}#{sisu_0_16}"
+        when /0.57/
+          "#{sisu_0_57}#{sisu_0_42}#{sisu_0_38}#{sisu_0_16}"
+        when /0.42/
+          "#{sisu_0_42}#{sisu_0_38}#{sisu_0_16}"
+        when /0.38/
+          "#{sisu_0_38}#{sisu_0_16}"
+        when /0.37/
+          "#{sisu_0_37}\n#{sisu_0_16}"
+        when /0.1[6-9]|0.2[0-9]|0.3[0-6]/
+          "#{sisu_0_16}\n#{sisu_0_1}"
+        when /0.[1-9]|0.1[1-4]/
+          sisu_0_1
+        else puts "NOT RECOGNISED: #{@opt.selections.str}"
+          help_query
+        end
+        tell
+      else help_query
+      end
+    end
+  end
+end
+__END__
+#%% to use as independent program ------------------------->
+f=$*
+cf=f[0].to_s
+f.shift
+match_and_replace=[]
+unless f.length > 0; f=Dir.glob("[a-z]*.ss?")  #restricted to sisu type files, it need not be
+end
+puts "SiSU files:"
+puts f
+f.each do |x|
+  SiSU_Markup::MarkupIdentify.new(x).markup_version?
+end
+#+END_SRC
+
+* sst_do_inline_footnotes.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/sst_do_inline_footnotes.rb"
+# <<sisu_document_header>>
+module SiSU_ConvertFootnotes
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'dp'                                 # dp.rb
+    include SiSU_Param
+  require_relative 'ao_syntax'                          # ao_syntax.rb
+    include SiSU_AO_Syntax
+  require_relative 'i18n'                               # i18n.rb
+  class Instantiate < SiSU_Param::Parameters::Instructions
+     @@flag={} #Beware!!
+    def initialize
+      @@flag['table_to']=false
+      @@counter=@@column=@@columns=@@flag_vocab=0
+      @@endnote={}
+      @@endnote_array=@@word_mode=[]
+      @@endnote_call_counter=1
+      @@line_mode=''
+    end
+  end
+  class Source <Instantiate
+    @@ao_array=[]
+    @@fns=nil
+    def initialize(opt)
+      @opt=opt
+      @@fns||@opt.fns
+      @my_make=SiSU_Env::CreateFile.new(@opt.fns)
+      @fnm=SiSU_Env::InfoFile.new(@opt.fns).marshal.ao_content
+    end
+    def read                                                                     #creates ao
+      begin
+        @@ao_array=[]
+        @@fns=@opt.fns
+        create_ao
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.cmd,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        Instantiate.new
+      end
+    end
+    def get                                                                      #reads ao, unless does not exist then creates first
+      begin
+        ao=[]
+        unless @@fns==@opt.fns
+          @@fns=@opt.fns
+          @@ao_array=[]
+        end
+        ao=(@@ao_array.empty?) \
+        ? read_fnm
+        : @@ao_array.dup #check
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.cmd,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        Instantiate.new
+      end
+    end
+  protected
+    def create_ao
+      ao_array=[]
+      SiSU_Screen::Ansi.new(
+        @opt.act[:color_state][:set],
+        'convert footnotes'
+      ).green_title_hi unless @opt.act[:quiet][:set]==:on
+      file_array=IO.readlines(@opt.fns,'')
+      file_array.each do |l|
+        if l =~/\r\n/ then l.gsub!(/\r\n/,"\n")
+        end
+      end
+      meta=file_array.dup
+      meta=meta.join.split("\n\n") #check whether can be eliminated, some of these are large objects to have twice
+      @md=SiSU_Param::Parameters::Instructions.new(meta,@opt).extract
+      if @md.en[:mismatch]==0 \
+      or @md.opt.selections.str =~/=footnotes-force/
+        meta=nil
+        ao=SiSU_ConvertFootnotes::Make.new(@md,file_array).song
+        SiSU_Screen::Ansi.new(
+          @opt.act[:color_state][:set],
+          @opt.fns,
+          "#{@md.fns}.fn"
+        ).output if @md.opt.act[:verbose][:set]==:on
+        SiSU_Screen::Ansi.new(
+          @opt.act[:color_state][:set],
+          "#{@md.fns}.fn -> #{@md.fns}.fn"
+        ).txt_red unless @md.opt.act[:quiet][:set]==:on
+        ao.each {|s| ao_array << "#{s.strip}\n\n" unless s.strip.empty?}
+        ao_array
+      else
+        SiSU_Screen::Ansi.new(
+          @md.opt.act[:color_state][:set],
+          '*WARN* no footnote conversion done, problem with source file',
+          'to override use --convert=footnote-force (this is not advised)'
+        ).warn unless @md.opt.act[:quiet][:set]==:on
+        ''
+      end
+    end
+    def read_fnm
+      ao=[]
+      ao=(FileTest.file?(@fnm)) \
+      ? (File.open(@fnm){ |f| ao=Marshal.load(f)})
+      : (SiSU_ConvertFootnotes::Source.new(@opt).create_ao) #watch
+    end
+  end
+  class Output
+    def initialize(md,data)
+      @md,@data=md,data
+      @my_make=SiSU_Env::CreateFile.new(@md.fns)
+      SiSU_Env::InfoEnv.new(@md.fns)
+      @hard="#{Dir.pwd}/#{@md.fns}.fn"
+    end
+    def hard_output
+      filename_note=@my_make.file_note
+      @data.each {|s| filename_note.puts s.strip + "\n\n" unless s.strip.empty?}
+    end
+  end
+  class Make
+    @@endnote={}
+    @@endnote_array=@@word_mode=[]
+    @@endnote_call_counter=1
+    @@comment='%'
+    @@flag={ ['table_to']=>false }
+    def initialize(md,data)
+      @md,@data=md,data
+      @@word_mode=[]
+      @env=SiSU_Env::InfoEnv.new(@md.fns)
+      l=SiSU_Env::StandardiseLanguage.new(@md.opt.lng).language
+      @language=l[:n]
+      @translate=SiSU_Translate::Source.new(@md,@language)
+    end
+    def reset
+      @@counter=@@column=@@columns=@@flag_vocab=0
+      @@endnote={}
+      @@endnote_array=@@word_mode=[]
+      @@endnote_call_counter=1
+      @@line_mode=''
+    end
+    def song
+      reset
+      data=@data
+      @metafile="#{@env.processing_path.ao}/#{@md.fns}.meta"
+      SiSU_Env::CreateFile.new(@md.fns)
+      data=data.join.split("\n\n")
+      data_new=[]
+      data.each do |x|
+        data_new << (x =~ /\n\n/m) \
+        ? (x.split(/\n\n+/))
+        : x
+      end
+      data=data_new.flatten
+      data=SiSU_ConvertFootnotes::Make.new(@md,data).character_check
+      data=SiSU_ConvertFootnotes::Make.new(@md,data).endnotes
+      SiSU_ConvertFootnotes::Output.new(@md,data).hard_output
+      reset
+      data
+    end
+  protected
+    def vocabulary
+      data=@data
+      tuned_file,vocab_insert=[],[]
+      data.each do |para|
+        if para =~/^1~/ \
+        and @@flag_vocab==0
+          vocab_insert << '@vocabulary: lex' << "\n\n" << para
+          tuned_file << vocab_insert unless para.nil?
+          @@flag_vocab=1
+        else tuned_file << para unless para.nil?
+        end
+      end
+      tuned_file
+    end
+    def character_check
+      reset
+      data=@data
+      @tuned_file=[]
+      endnote_no=1
+      data.each do |para|
+        para.strip!
+        para.gsub!(/^[{~}]\s*$/,'')
+        para.gsub!(/^#{@@comment}.*/,'')                                       #remove comment and divider #%
+        para.gsub!(/<~#>|~#\s*/,'~#')
+        para.gsub!(/-#\s*/,'-#')
+        para.gsub!(/(~\{ )\s+/,'\1')
+        para.gsub!(/ \/\//,'<br />')                                           #added 2004w29
+        para.gsub!(/<br>/,'<br />')                                            #needed by xml, xhtml etc.
+        para.gsub!(/`/,"'")
+        para.gsub!(/\342\200\231/,"'") #if para =~/’/  #Avoid #&lsquo; &rsquo; #&ldquo; &rdquo;
+        para.gsub!(/\t/,' ')
+        para.gsub!(/�/,' ') #watch, replace with char code
+        para.gsub!(/[“”]/,'""')
+        para.gsub!(/[­–—]/,'-')   #— – chk
+        para.gsub!(/·/,'*')
+        para.gsub!(/\\copy(?:right)?\b/,'&#169;')
+        para.gsub!(/\\trademark\b|\\tm\b/,'&#174;')
+        para.gsub!(/\44/,'&#36;') #$ watch
+        para=para + "\n"
+        case para
+        when /\^~/                                                             # endnotes
+                                                                               #% Note must do this first (earlier loop) and then enter gathered data into ~^\d+
+          sub_para=para.dup
+          @@endnote_array << sub_para.gsub!(/\n/,'').gsub!(/\^~\s+(.+)\s*/,'~{ \1 }~').strip
+           endnote_no+=1
+          para=nil if para =~/\^~ .+/ #removes 'binary' endnote now in endnote array for later insertion
+        end
+        @tuned_file << para unless para.nil?
+      end
+      @tuned_file
+    end
+    def name_endnote_seg
+      data=@data
+      @tuned_file=[]
+      data.each do |para|
+        para.gsub!(/<:3>\s*<:ee>/,
+          "#{@@endnote['special_align']} <p /><br />\r " +
+          "#{@@endnote['seg_name_3']} <p /> " +
+          "#{@@endnote['special_align_close']}")
+        para.gsub!(/<:2>\s*<:ee>/,
+          "#{@@endnote['special_align']} <p /><br />\r " +
+          "#{@@endnote['seg_name_2']} <p />" +
+          "#{@@endnote['special_align_close']}")
+        para.gsub!(/<:1>\s*<:ee>/,
+          "#{@@endnote['special_align']} <p /><br />\r " +
+          "#{@@endnote['seg_name_1']} <p /> " +
+          "#{@@endnote['special_align_close']}")
+        @tuned_file << para
+      end
+      if @md.flag_auto_endnotes \
+      and @md.flag_separate_endnotes_make
+        @tuned_file << "\n1~endnotes Endnotes" #prob numbering, revisit
+      end
+      @tuned_file << "\n<ENDNOTES>"
+      @tuned_file
+    end
+    def owner_details_seg
+      data << '1~owner.details Owner Details'
+    end
+    def number_sub_heading(para,num,title_no)
+      case para
+      when /#{num}~- /    then para.gsub!(/#{num}~- /,"#{title_no} ")
+      when /^#{num}~#\s*/ then para.gsub!(/^#{num}~#\s*/,"#{title_no} ")
+      when /^#{num}~[a-z_\.]+ /
+        para.gsub!(/^#{num}~([a-z_\.]+)\s+(.+)/i,%{#{num}~\\1 #{title_no} \\2  <:name##{title_no}>})
+      else para.gsub!(/^#{num}~ /,"#{num}~#{title_no} #{title_no} ") #main
+      end
+      if @md.toc_lev_limit \
+      and @md.toc_lev_limit < num
+        para.gsub!(/^[2-6]~(?:~\S+)?\s*/,'!_ ')
+      end
+      para
+    end
+    def set_heading_top                                                        #% make sure no false positives
+      unless @md.set_heading_top
+        if (@md.opt.act[:verbose_plus][:set]==:on \
+        || @md.opt.act[:maintenance][:set]==:on)
+          puts "\tdocument contains no top level heading, (will have to manufacture one)"
+        end
+        data=@data
+        @tuned_file=[]
+        data.each do |para|
+          unless @md.set_heading_top
+            if para !~/^(?:@\S+:|0~\S+)\s/m \
+            and para !~/\A\s*\Z/m
+              @md.set_heading_top=true
+              head=(@md.title.full) \
+              ? (":A~ #{@md.title.full}")
+              : (':A~ [no title provided]')
+              @tuned_file << head
+            end
+          end
+          @tuned_file << para
+        end
+        @tuned_file
+      end
+    end
+    def set_heading_seg                                                        #% make sure no false positives
+      unless @md.set_heading_seg
+        if (@md.opt.act[:verbose_plus][:set]==:on \
+        || @md.opt.act[:maintenance][:set]==:on)
+          puts "\tdocument contains no segment level, (will have to manufacture one)"
+        end
+        data=@data
+        @tuned_file=[]
+        data.each do |para|
+          unless @md.set_heading_seg
+            if para !~/^(?:@\S+:|0~\S+|:[ABC]~)/m \
+            and para !~/\A\s*\Z/m \
+            and para !~/<:p[bn]>/
+              @md.set_heading_seg=true
+              head=(@md.title.full) \
+              ? ("1~seg [#{@md.title.full}]")
+              : ('1~seg [segment]')
+              @tuned_file << head
+            end
+          end
+          @tuned_file << para
+        end
+        @tuned_file
+      end
+    end
+    def set_header_title                                                       #% make sure no false positives
+      unless @md.set_header_title
+        if (@md.opt.act[:verbose_plus][:set]==:on \
+        || @md.opt.act[:maintenance][:set]==:on)
+          puts "\t no document title provided, (will have to manufacture one)"
+        end
+        data=@data
+        @tuned_file=[]
+        data.each do |para|
+          unless @md.set_header_title
+            if para !~/^%{1,2}\s/m \
+            and para !~/\A\s*\Z/m
+              @tuned_file << "0~title #{@md.heading_seg_first}"
+              @md.title.full=@md.heading_seg_first
+              @md.set_header_title=true
+            end
+          end
+          @tuned_file << para
+        end
+        @tuned_file
+      end
+    end
+    def endnotes                                                                         #% endnote work zone
+      data=@data
+      @tuned_file=[]
+      endnote_ref=1
+      data.each do |para|
+        case para                                                                               # manually numbered endnotes <!e(\d)!> <!e_(\d)!> -->
+        when /~\{\s+.+?\}~/                                                                               # auto-numbered endnotes <!e!> <!e_!> -->
+          para.gsub!(/\s*\}~/,' }~')                                           # required 2003w31
+          @word_mode=para.scan(/\S+/)
+          word_mode=SiSU_ConvertFootnotes::Make.new(@md,@word_mode).endnote_call_number
+          para=word_mode.join(' ')
+          endnote_ref+=1
+        when /~\^(?:\s|$)|<:e>/                                                #%Note inserts endnotes previously gathered from /^(<!e[:_]!>|[-~]\{{3})/ (in earlier loop)
+          word_mode=para.scan(/\S+/)
+          word_mode=SiSU_ConvertFootnotes::Make.new(@md,word_mode).endnote_call_number
+          para=word_mode.join(' ')
+          endnote_ref+=1
+        end
+        @tuned_file << para
+      end
+      @tuned_file
+    end
+    def endnote_call_number
+      data=@data
+      data.each do |word|
+        case word
+        when /~\{/
+          unless word =~/~\{\*+/
+            @@endnote_call_counter+=1
+          end
+        when /~\^|<:e>/
+          word.gsub!(/~\^|<:e>/,"#{@@endnote_array[@@endnote_call_counter-1]}")
+          @@endnote_call_counter+=1
+        end
+      end
+    end
+    def strip_clean_extra_spaces(s)                                            # ao output tuned
+      s=s.dup
+      s=s.gsub(/[ ]+([,.;:?](?:$|\s))/,'\1')
+      s=s.gsub(/ [ ]+/,' ')
+      s=s.gsub(/^ [ ]+/,'')
+      s=s.gsub(/ [ ]+$/,'')
+      s=s.gsub(/(<\/[bi]>')[ ]+(s )/,'\1\2')
+    end
+    def strip_clean_of_markup(s)                                               # used for digest, define rules, make same as in db clean
+      s=s.dup
+      s=s.gsub(/(?:<\/?[ib]>|^:[A-C]~\S+|^[1-6]~\S+|~\{\d+\s.+?\}~)/,'') # markup and endnotes removed
+                                                                               #% same as db clean -->
+      s=s.gsub(/<del>(.+?)<\/del>/,'DELETED(\1)')                           # deletions
+      s=s.gsub(/<sup>(\d+)<\/sup>/,'[\1]')
+      s=s.gsub(/(?:&nbsp\\;|#{Mx[:nbsp]})+/,' ')  #checking source Mx not necessary
+      s=s.gsub(/\{.+?\.(?:png|jpg|gif).+?\}(?:https?|file|ftp)\\\:\S+ /,' [image] ')             # else image names found in search
+      s=s.gsub(/#{Mx[:lnk_o]}.+?\.(?:png|jpg|gif).+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/,' [image] ')             # else image names found in search, re-check
+      s=s.gsub(/\s\s+/,' ')
+      s=s.strip
+    end
+  end
+end
+__END__
+@particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+ao_array=@particulars.ao_array # ao file drawn here
+#+END_SRC
+
+* sst_convert_markup.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/sst_convert_markup.rb"
+# <<sisu_document_header>>
+module SiSU_Modify
+  require_relative 'sst_identify_markup'                # sst_identify_markup.rb
+  require_relative 'sst_from_xml'                       # sst_from_xml.rb
+  require_relative 'utils_response'                     # utils_response.rb
+  class ConvertMarkup
+    include SiSU_Response
+    def initialize(opt)
+      @opt=opt
+      @description='This is a script that contains canned text conversions for reuse'
+      @warn='WARNING, PROCEED AT YOUR OWN RISK, will make file changes.'
+    end
+    def current_match_and_replace
+      convert_37_to_38
+    end
+    def message(text)
+      response=''
+      unless @opt.cmd=~/QQ/ \
+      or @opt.act[:quiet][:set]==:on
+        response=response?(%{#{  text}\nProceed? })
+      end
+    end
+    def help
+    print <<WOK
+
+#{@description}
+
+sisu --convert --to38 [filename/wildcard]
+  converts pre 0.37 sisu markup to 0.38 experimental
+  [--37to38]
+
+sisu --convert --to37 [filename/wildcard]
+  converts pre 0.37 sisu markup to 0.38 experimental
+  [--38to37]
+
+sisu --convert --36to37 [filename/wildcard]
+  converts pre 0.36 file-name, to 0.37 file-name
+  [--36to37]
+
+sisu --identify [filename]
+  attempts to identify markup version used in file
+
+sisu --query [version number]
+  gives short summary of distinguishing characteristic
+  of that version of markup
+
+WOK
+      exit
+    end
+    #%% substitutions to be made
+    def convert_37_to_38
+      message("#{@warn}\nConvert sisu markup from 0.37 to 0.38")
+      [
+        [/^0~(\S+?)([+-])\s+/,    '@\1:\2 ',               //],
+        [/^0~(\S+)\s+/,           '@\1: ',                 //],
+        [/^@toc:\s+/,             '@structure: ',          //],
+        [/^1~/,                   ':A~',                   //],
+        [/^2~/,                   ':B~',                   //],
+        [/^3~/,                   ':C~',                   //],
+        [/^4~/,                   '1~',                    //],
+        [/^5~/,                   '2~',                    //],
+        [/^6~/,                   '3~',                    //],
+        [/^7~/,                   '4~',                    //],
+        [/^8~/,                   '5~',                    //],
+        [/^9~/,                   '6~',                    //],
+        [/1/,                     ':A',                    /^@(?:level|markup):\s/],
+        [/2/,                     ':B',                    /^@(?:level|markup):\s/],
+        [/3/,                     ':C',                    /^@(?:level|markup):\s/],
+        [/4/,                     '1',                     /^@(?:level|markup):\s/],
+        [/5/,                     '2',                     /^@(?:level|markup):\s/],
+        [/6/,                     '3',                     /^@(?:level|markup):\s/]
+      ]
+    end
+    def convert_38_to_37
+      message("#{@warn}\nConvert sisu markup from 0.38 to 0.37")
+      [
+        [/^@(\S+?):([+-])\s+/,    '0~\1\2 ',               //],
+        [/^@(\S+?):\s+/,          '0~\1 ',                 //],
+        [/^0~structure\s+/,       '0~toc ',                //],
+        [/^1~/,                   '4~',                    //],
+        [/^2~/,                   '5~',                    //],
+        [/^3~/,                   '6~',                    //],
+        [/^4~/,                   '7~',                    //],
+        [/^5~/,                   '8~',                    //],
+        [/^6~/,                   '9~',                    //],
+        [/^:?A~/,                 '1~',                    //],
+        [/^:?B~/,                 '2~',                    //],
+        [/^:?C~/,                 '3~',                    //],
+        [/1/,                     '4',                     /^0~(?:level|markup)\s/],
+        [/2/,                     '5',                     /^0~(?:level|markup)\s/],
+        [/3/,                     '6',                     /^0~(?:level|markup)\s/],
+        [/:?A/,                   '1',                     /^0~(?:level|markup)\s/],
+        [/:?B/,                   '2',                     /^0~(?:level|markup)\s/],
+        [/:?C/,                   '3',                     /^0~(?:level|markup)\s/]
+      ]
+    end
+    def convert_filename_36_to_37
+      @opt.files.each do |f|
+        s=case f
+        when /(\.s[1-3])$/ then f.sub($1,'.sst')
+        when /(\.r[1-3])$/ then f.sub($1,'.ssm')
+        when /(\.ri)$/     then f.sub($1,'.ssi')
+        else f
+        end
+        pwd=Dir.pwd
+        unless f==s
+          unless File.exist?("#{pwd}/#{s}")
+            puts "./#{f} -> ./#{s}"
+            FileUtils::cp("#{pwd}/#{f}","#{pwd}/#{s}")
+          else "File already exists, < #{s} >  will not overwrite"
+          end
+        end
+      end
+    end
+    def convert_to_simple_xml_model_sax
+      SiSU_SimpleXML_ModelSax::Convert.new(@opt).read
+    end
+    def convert_to_simple_xml_model_dom
+      SiSU_simple_xml_model_dom::Convert.new(@opt).read
+    end
+    def convert_to_simple_xml_model_node
+      SiSU_simple_xml_model_node::Convert.new(@opt).read
+    end
+    def convert_kdi_to_sst
+      SiSU_Kdissert::Convert.new(@opt).read
+    end
+    def convert_s_xml_to_sst
+      SiSU_sstFromXML::Convert.new(@opt).read
+    end
+    def convert_footnotes
+      require_relative 'sst_do_inline_footnotes'
+      SiSU_ConvertFootnotes::Source.new(@opt).read
+    end
+    def conversion
+      #%% do it                                   -------------------------->
+      if @opt.files \
+      and @opt.files.length > 0
+        mr=nil
+        #%% changes to make m match, r replace      -------------------------->
+        if @opt.selections.str =~/--help/ then help
+        elsif @opt.selections.str =~/(?:convert|to)[=-](?:xml |sxs|sax|sxd|dom|sxn|node)/
+          ext=case @opt.selections.str
+          when /(?:convert|to)[=-](?:xml|sxs|sax)/ then '.sxs.xml'
+          when /(?:convert|to)[=-](?:sxd|dom)/     then '.sxd.xml'
+          when /(?:convert|to)[=-](?:sxn|node)/    then '.sxn.xml'
+          end
+          message("#{@opt.files.inspect}\n\nWARNING, PROCEED AT YOUR OWN RISK,\noverwriting any equivalent file with the extension #{ext}")
+          mr=case @opt.selections.str
+          when /(?:convert|to)[=-](?:sxs|sax|xml )/ then convert_to_simple_xml_model_sax
+          when /(?:convert|to)[=-](?:sxd|dom)/      then convert_to_simple_xml_model_dom
+          when /(?:convert|to)[=-](?:sxn|node)/     then convert_to_simple_xml_model_node
+          else help
+          end
+        else
+          mr=case @opt.selections.str
+          when /(?:(?:37)?to-?38|--(?:convert|to)[=-](?:current|0.38))/           then convert_37_to_38
+          when /(?:(?:38)?to-?37|--(?:convert|to)[=-](?:0.37))/                   then convert_38_to_37
+          when /(?:36to37)/                                                       then convert_filename_36_to_37
+          when /(?:convert|from)[=-]kdi/                                          then convert_kdi_to_sst
+          when /(?:(?:convert|from)[=-])?(?:xml_to_sst|xml2sst|sxml|sxs|sxd|sxd)/ then convert_s_xml_to_sst
+          when /(?:convert|to)[=-]footnotes/                                      then convert_footnotes
+          when /convert|default/                                                  then current_match_and_replace
+          else help
+          end
+        end
+        unless @opt.selections.str =~/kdi/
+          match_and_replace=mr
+          #start_processing =/not used in this example/i
+          end_processing =/END\s+OF\s+FILE/
+          i=@opt.fns
+          if i =~/(?:\.sst|\.ssm|\.ssi)$/
+            @new,@matched,@flag_start,@flag_end,@empty1,@empty2=true,false,false,false,false,false
+            o="#{i}.bk" #o is for old
+            markup_version=SiSU_Markup::MarkupIdentify.new(@opt).markup_version?
+            if (@opt.selections.str=~/37/ and markup_version=~/0.38/) \
+            or (@opt.selections.str=~/current|38/ and markup_version=~/0.37/)
+              puts "#{i} #{markup_version}"
+              file=File.open(i,'r')
+              cont=file.readlines
+              file.close
+              cont.each do |y|
+                match_and_replace.each do |m,r,w|
+                  if y =~m \
+                  and y =~w
+                    if @new
+                      @new=false
+                      File.unlink(o) if File.exist?(o)
+                      File.rename(i,o)
+                      File.unlink(i) if File.exist?(i)
+                      @file=File.new(i,'w')
+                      @matched=true
+                      break
+                    end
+                  end
+                end
+              end
+              if @matched
+                puts "conversion match in #{i}" unless @opt.act[:quiet][:set]==:on
+                @flag_start=true
+                cont.each do |y|
+                  if y =~end_processing
+                    @flag_end=true
+                  end
+                  if @flag_start \
+                  and not @flag_end
+                    match_and_replace.each do |m,r,w|
+                      if y =~m \
+                      and y =~w
+                        puts m.inspect + ' -> ' + r unless @opt.act[:quiet][:set]==:on
+                        if (@opt.act[:verbose][:set]==:on \
+                        || @opt.act[:verbose_plus][:set]==:on \
+                        || @opt.act[:maintenance][:set]==:on)
+                          puts "in:  #{y}"
+                        end
+                        y.gsub!(m,r) if m and r
+                        if (@opt.act[:verbose][:set]==:on \
+                        || @opt.act[:verbose_plus][:set]==:on \
+                        || @opt.act[:maintenance][:set]==:on)
+                          puts "out: #{y}"
+                        end
+                      end
+                    end
+                  end
+                  @empty1=(y=~/^\s*$/) \
+                  ? true
+                  : false
+                  @file.puts y unless (@empty1==true and @empty2==true)
+                  @empty2=(y=~/^\s*$/) \
+                  ? true
+                  : false
+                end
+                @file.close
+              else puts "NO conversion match in #{i}" unless @opt.act[:quiet][:set]==:on
+              end
+            else
+              if (@opt.act[:verbose][:set]==:on \
+              || @opt.act[:verbose_plus][:set]==:on \
+              || @opt.act[:maintenance][:set]==:on)
+                puts "Requested conversion #{@opt.selections.str} markup #{markup_version} identified in #{i}"
+              end
+            end
+          end
+        end
+      else puts 'this routine makes permanent changes to the contents of the files matched, as instructed within [no matches]'
+      end
+    end
+  end
+end
+#%% files to match for this conversion set  ------------------------->
+require_relative 'hub_options'                          # hub_options.rb
+argv=$*
+base_path=Dir.pwd
+@opt=SiSU_Commandline::Options.new(argv,base_path)
+case @opt.selections.str
+when /=kdi/
+  SiSU_Modify::ConvertMarkup.new(@opt).conversion
+when /(?:36|37|38)?to-?(?:37|38)|--convert|--to|--from|default/
+@opt.files.each do |fns|
+  @opt.fns=fns
+  SiSU_Modify::ConvertMarkup.new(@opt).conversion
+end
+else
+  @opt.selections.str='--help'
+ SiSU_Modify::ConvertMarkup.new(@opt).help
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    sst
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/texinfo.org b/org/texinfo.org
new file mode 100644
index 00000000..3046df51
--- /dev/null
+++ b/org/texinfo.org
@@ -0,0 +1,946 @@
+-*- mode: org -*-
+#+TITLE:       sisu texinfo
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:texinfo:
+:wqa
+#+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
+
+* texinfo.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/texinfo.rb"
+# <<sisu_document_header>>
+module SiSU_TexInfo
+  require_relative 'html'                               # html.rb
+  require_relative 'dp'                                 # dp.rb
+    include SiSU_Param
+  #include Stamp ... needed removed arbitrarily 2005w05/1 (warnings about undefined flags)
+  require_relative 'texinfo_format'                     # texinfo_format.rb
+  include SiSU_TexInfoFormat
+  @tex_file=[]
+  @@tabular="{tabular}"
+  @@table_pagebreak_counter,@@tex_endnote_call_counter,@@tex_table_flag,@@tex_counter,@@tex_column,@@tex_columns,@@counting=0,0,0,0,0,0,0
+  @@column_instruct,@@tex_line_mode,@@tex_word_mode,@@start_table,@@line_mode='','','','',''
+  @@n,@@copyright,@@tableheader=nil,nil,nil
+  @@tex_col_w=[]
+  @@tex_pattern_margin_number="\\\\marginpar.+?\s+"
+  class Source
+    include SiSU_Param
+    include SiSU_TexInfo
+    def initialize(opt)
+      @opt=opt
+      @md=SiSU_Param::Parameters.new(@opt).get
+      @env=SiSU_Env::InfoEnv.new(@opt.fns)
+    end
+    def directories
+      begin
+        case @opt.fns
+        when /\.(?:-|ssm\.)?sst$/
+          Dir.mkdir(@env.path.output) unless FileTest.directory?("#{@env.path.output}")
+          Dir.mkdir(@env.processing_path.texi) unless FileTest.directory?(@env.processing_path.texi)
+        end
+      rescue
+        SiSU_Screen::Ansi.new(opt,$!,$@).rescue do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    def read
+      begin
+        song
+      ensure
+        Dir.chdir(@opt.f_pth[:pth])
+      end
+    end
+    def song
+      begin
+        tool=(@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on) \
+        ? "cd #{@md.file.output_path.texinfo.dir} && #{@env.program.texinfo} #{@md.file.base_filename.info}; cd -"
+        : "[#{@opt.f_pth[:lng_is]}] #{@opt.fno}"
+        (@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on) \
+        && ! @opt.act[:quiet][:set]==:on \
+        ? SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'TexInfo',
+            tool
+          ).green_hi_blue
+        : SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'TexInfo',
+            tool
+          ).green_title_hi
+        @md=SiSU_Param::Parameters.new(@opt).get
+        directories
+        @marshalfile=SiSU_Env::InfoFile.new(@opt.fns).marshal.ao_content
+        if FileTest.file?(@marshalfile)==true
+          File.open(@marshalfile) { |f| @@tuned_file=Marshal.load(f)}
+          #tell.meta_verse_skipped if @opt.selections.str =~/[vVM]/
+        else
+          tex_array=IO.readlines(@opt.fns,'')
+          SiSU_Metaverse.songsheet(tex_array)
+        end
+        tex_array=@@tuned_file
+        TeXinfoMake.new(@md,tex_array).songsheet
+        tex_array=''
+      rescue; STDERR.puts SiSU_Screen::Ansi.new(@opt.act[:color_state][:set],$!,$@).rescue
+      ensure
+      end
+    end
+  end
+  class TeXinfoMake
+    include SiSU_Param
+    include SiSU_TexInfoFormat
+    @@tex_1='(?:.+?)+~' #?? debug
+    @@tabular="{tabular}"
+    @@tex_pattern_margin_number="\\\\marginpar.+?\s+"
+    def initialize(md,data)
+      @md,@data=md,data
+      @env=SiSU_Env::InfoEnv.new(@md.fns)
+      @f=SiSU_Env::FileOp.new(@md)
+    end
+    def songsheet
+      begin
+        data=@data
+        data=pre(data)
+        data=endnote(data)
+        data,head=markup(data)
+        objs_txt=tail(data)
+        doc_txt=[head,objs_txt]
+        output(doc_txt)
+        makeinfo #KEEP reinstate when fixed #%
+        place_info
+      rescue; STDERR.puts SiSU_Screen::Ansi.new(@md.opt.act[:color_state][:set],$!,$@).rescue
+      ensure
+      end
+    end
+    def pre(data)
+      data_new=[]
+      data.each do |dob|
+        # DEBUG 2003w16 this is a kludge, because i could not get parameters
+        # from param, Sort out ... revert to more elegant solution
+        if dob.is =='table'
+          @@flag['tables']='y' # KLUDGE get from param
+        end
+        dob.obj=dob.obj.gsub(/<:p[bn]>/,'').
+          gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,'\1(\2 [linked to:] \3)').
+          gsub(/(^|#{Mx[:gl_c]}|\s)\{(.+?)\}((?:https?|file):\/\/\S+)/,'\1(\2 [linked to:] \3)')
+        do_mono=SiSU_TexInfoFormat::Texinfo.new(@md,dob)
+        dob.obj=do_mono.spec_char(dob.obj)
+        data_new << dob
+      end
+      data_new
+    end
+    def endnote(data)
+      data_new=[]
+      data.each do |dob|
+        if dob.of==:para \
+        || dob.of==:block
+          dob.obj=dob.obj.gsub(/\s*#{Mx[:en_a_o]}(?:\d+)\s+(.+?)#{Mx[:en_a_c]}/m,' @footnote{ \1} ').
+            gsub(/\s*#{Mx[:en_a_o]}(\*+)\s+(.+?)#{Mx[:en_a_c]}/m,' @footnote{ \1} ')
+        end
+        data_new << dob
+      end
+      data_new
+    end
+    def poem
+      data,data_new=@data,[]
+      @tex_file=[]
+      @@counting=0
+      data.each do |dob|
+        if dob.is ==:code
+          @@flag['code']=true
+          @@counting=1
+        end
+        if dob.is ==:verse
+          @@flag['poem']=1
+        end
+        if @@flag['code']
+          if @@flag['code'] \
+          && (dob.obj =~ /#{Mx[:gr_o]}code[-_](?:end|close)#{Mx[:gr_c]}/) #watch change not tested 200501 #fix
+            @@flag['code']=false
+          end
+          if @@flag['code'] \
+          && (dob.obj =~ /\S/)
+            sub_array=dob.obj.dup
+            @@line_mode=sub_array.scan(/.+/)
+            Tune.code_lines(@@line_mode)
+            dob.obj=@@line_mode.join
+          end
+        elsif @@flag['poem']==1
+          if @@flag['poem']==1 \
+          && (dob.obj =~ /#{Mx[:gr_o]}verse[-_](?:end|close)#{Mx[:gr_c]}/) #watch change not tested 200501 #fix
+            @@flag['poem']=0
+          end
+          if @@flag['poem']==1 \
+          && (dob.obj =~ /\S/)
+            sub_array=dob.obj.dup
+            @@line_mode=sub_array.scan(/.+/)
+            Tune.code_lines(@@line_mode)
+            dob.obj=@@line_mode.join
+          end
+        end
+        @tex_file << dob.obj
+        data_new << dob
+      end
+      data_new
+    end
+    def code_lines
+      data,data_new=@data,[]
+      data.each do |line|
+        if (line =~ /\S/) \
+        && (line !~ /#{Mx[:gr_o]}(code|verse).+/) #fix
+          line=if @@flag['code']
+            line.gsub(/^\s*(.+)/m,"\\noindent \\marginpar\[left-text\]{\\begin{tiny}#{@@counting}\\end{tiny}}\\1\\")
+            @@counting+=1 if @@flag['code']
+          else line.gsub(/(.+)/m,'\noindent\1')
+          end
+        end
+        data_new << line
+      end
+    end
+    def tables
+      data,data_new=@data,[]
+      @tex_file=[]
+      @@tableheader=0
+      data.each do |dob|
+        if dob.obj =~ /#{Mx[:tc_p]}|#{Mx[:gr_o]}T/ui #fix
+          do_mono=SiSU_TexInfoFormat::Texinfo.new(@md,dob)
+          dob.obj=do_mono.longtable # using longtable latex package
+        end
+        @tex_file << dob.obj
+        data_new << dob
+      end
+      data_new
+    end
+    def markup(data)
+      data_new=[]
+      @tex_file=[]
+      @row_break='\\\\\\'
+      @break_page="#{@row_break}\n#{@row_break} \n"
+      @tex_file << SiSU_TexInfoFormat::Texinfo.new(@md).head
+      mono=SiSU_TexInfoFormat::Texinfo.new(@md)
+      @tex_file << mono.topnode(@md.title.full)
+      texinfo_menu=[]
+      n_menu,n_submenu=0,0
+      @submenu,@subsubmenu={},{}
+      data.each do |dob|
+        if dob.is ==:heading \
+        && (dob.ln.to_s =~ /^[0-3]$/)
+          toc=SiSU_TexInfoFormat::Texinfo.new(@md,dob)
+          texinfo_menu << toc.menu
+        elsif dob.is ==:heading \
+        && (dob.ln.to_s =~ /^[4-6]$/)
+          toc=SiSU_TexInfoFormat::Texinfo.new(@md,dob)
+          texinfo_menu << toc.menu
+          case dob.ln
+          when 4
+            n_menu+=1
+            @submenu[n_menu]=[]
+          when 5
+            n_submenu+=1
+            @subsubmenu[n_menu]=[]
+            @submenu[n_menu] << toc.menu
+          when 6
+            n_submenu+=1
+            @subsubmenu[n_submenu]=[]
+            @subsubmenu[n_submenu] << toc.menu
+          end
+        else
+          dob.obj=dob.obj.gsub(/\s*(?:<:?br>|<br \/>)\s*/,"\n\n")
+        end
+        data_new << dob
+      end
+      data=data_new
+      texinfo_menu=texinfo_menu.compact
+      texinfo_menu << "* Dublin Core::"
+      @tex_file << texinfo_menu
+      @tex_file << "* Index::\n" +
+        "@end menu\n\n" +
+        "@c %% 5\n\n"
+      n_menu,n_submenu=0,0
+      @@do_submenu,@@do_subsubmenu=1,1
+      data_new=[]
+      data.each do |dob|
+        unless defined? dob.ln and dob.ln == (5..6)
+          mono=SiSU_TexInfoFormat::Texinfo.new(@md,dob)
+        end
+        if dob.is==:heading
+          case dob.ln
+          when 0 then dob=mono.level0
+          when 1 then dob=mono.level1
+          when 2 then dob=mono.level2
+          when 3 then dob=mono.level3
+          when 4;
+            @@n4_txt=dob.obj
+            dob=mono.level4
+            n_menu+=1
+            @@do_submenu,@@do_subsubmenu=1,1
+          when 5;
+            n_submenu+=1
+            @@do_subsubmenu=1
+            @@n5_txt=dob.obj
+            if @@do_submenu==1
+              menu=SiSU_TexInfoFormat::TeXinfoTxt.new(@md,dob,@submenu[n_menu])
+              dob.obj="#{menu.submenu}#{SiSU_TexInfoFormat::Texinfo.new(@md,dob,@@n4_txt).level5.obj}"
+              @@do_submenu=0
+            else dob.obj="#{SiSU_TexInfoFormat::Texinfo.new(@md,dob,@@n4_txt).level5.obj}"
+            end
+          when 6;
+            if @@do_submenu==1
+              menu=SiSU_TexInfoFormat::TeXinfoTxt.new(@md,dob,@submenu[n_menu])
+              dob.obj="#{menu.submenu}#{SiSU_TexInfoFormat::Texinfo.new(@md,dob,@@n5_txt).level6.obj}"
+              dob.obj="#{menu.subsubmenu}#{mono.level6.obj}"
+              @@do_subsubmenu=0
+            else dob.obj="#{SiSU_TexInfoFormat::Texinfo.new(@md,dob,@@n5_txt).level6.obj}"
+            end
+          end
+        else
+          if dob.obj !~/\S/
+            dob.obj=nil
+          else
+            if dob.is==:para \
+            && (dob.obj !~/#{Dx[:ocn_o]}#{dob.ocn}#{Dx[:ocn_c]}/)
+              dob.obj=dob.ocn.is_a?(Fixnum) \
+              ? "#{dob.obj} #{Dx[:ocn_o]}#{dob.ocn}#{Dx[:ocn_c]}\n\n" : "#{dob.obj}\n\n"
+            end
+          end
+        end
+        #%case with endnotes
+        dob.obj=dob.obj.gsub(/\s*[0-8]\\+(\S+)?\s+/,' ') if dob.obj
+        data_new << dob
+      end
+      [data_new, @tex_file]
+    end
+    def number_titles
+      data,data_new=@data,[]
+      @tex_file=[]
+      data.each do |dob|
+        if (@md.markup =~ /num_top/i) \
+        && (dob.obj !~ /#{Rx[:meta]}/)
+          if (dob.obj =~ /^[1-6]\\+(?:~\S+)?\s*<!h-.+?-!>/) \
+          && (dob.obj !~ /<:\d-endnotes>/)
+            header=dob.obj[/<!h-(.+?)-!>/m, 1].gsub(/-/m,'.')
+            dob.obj=dob.obj.gsub(/^(?:[1-6]\\+(?:~\S+)|<:([12356]|4-.+?-)>)\s*<!h-.+?-!>/,
+              "\\1 #{header} ")
+          end
+        elsif dob.obj=~ /<!h!>|<!h\d!>|<!h.+?!>|<!!h.+?!>/
+          if dob.obj=~ /<!h-.+?-!>/
+            dob.obj=dob.obj.gsub(/<!h-(.+?)-!>/,'\1 ')
+          end
+        end
+        @tex_file << dob.obj
+      end
+      data_new << dob
+    end
+    def tail(data)
+      tex=SiSU_TexInfoFormat::Texinfo.new(@md)
+      objs_txt=[]
+      data.each do |dob|
+        if dob.obj \
+        && (dob.is !=:structure \
+        && dob.is !=:comment)
+           objs_txt << dob.obj if dob.obj
+        end
+      end
+      objs_txt << tex.dublincore << tex.tail
+      objs_txt
+    end
+    def output(data)
+      filename_texinfo=%{#{@env.processing_path.texi}/#{@md.fnb}.texinfo}
+      file_texinfo=File.new(filename_texinfo,'w+')
+      puts filename_texinfo if @md.opt.act[:maintenance][:set]==:on
+      data.each {|s| (file_texinfo.puts s,"\n") if s}
+      file_texinfo.close
+    end
+    def makeinfo
+      if @md.fns =~/\.(?:-|ssm\.)?sst$/
+        m=/(.+?)\.((?:-|ssm\.)?sst)$/.match(@md.fns)
+        fnb,sfx=m[1],m[2]
+        pwd=Dir.pwd
+        case sfx
+        when /(?:-|ssm\.)?sst$/
+          @env=SiSU_Env::InfoEnv.new(@md.fns,@md.opt.selections.str)
+          Dir.chdir(@env.processing_path.texi)
+          texinfo=SiSU_Env::SystemCall.new("#{fnb}.texinfo")
+          texinfo.makeinfo
+        end
+        Dir.chdir(pwd)
+      end
+      def place_info
+        unless FileTest.directory?(@f.output_path.texinfo.dir)
+          FileUtils::mkdir_p(@f.output_path.texinfo.dir)
+        end
+        info_src=%{#{@env.processing_path.texi}/#{@md.fnb}.info}
+        Dir.glob("#{info_src}*").sort.each do |f|
+          FileUtils::cp(f, File.dirname(@f.place_file.info.dir)) # bug should provide dir without need to extract it!
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* texinfo_format.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/texinfo_format.rb"
+# <<sisu_document_header>>
+module SiSU_TexInfoFormat
+  @@table_pg_break_counter=1
+  require_relative 'dp'                                 # dp.rb
+    include SiSU_Param
+  class Texinfo
+    @@tex_1='\\\\~' #?? debug
+    @@tabular="{tabular}"
+    @@tex_pattern_margin_number="\\\\marginpar.+?\s+"
+    def initialize(md,dob=nil,up='')
+      @md,@dob,@up=md,dob,up
+      if dob.is_a?(Hash)
+        p dob.class
+        p caller
+      elsif dob.is_a?(String)
+        p dob.class
+        p caller
+      end
+    end
+    def head
+      t=Time.now
+      year=t.year
+      title=spec_char(@md.title.full)
+      title=title.gsub(/<(br|p|i)>|<\/\s*(br|p|i)>|<(br|p)\s*\/>/," #{Tex[:backslash]*2} ").
+        gsub(/\$/,"\\$").
+        gsub(/[,]\s*/,' - ')
+      if @md.title.sub
+        subtitle=spec_char(@md.title.sub)
+        subtitle=subtitle.gsub(/<(br|p|i)>|<\/\s*(br|p|i)>|<(br|p)\s*\/>/," #{Tex[:backslash]*2} ").
+          gsub(/\$/,"\\$").
+          gsub(/[,]\s*/,' - ')
+        subtitle="\n@subtitle #{subtitle}\n"
+      end
+      subtitle ||=''
+      author=@md.author if @md.author
+      author ||=''
+      author=author.gsub(/[\*]/,'') #if author
+      #SiSU_Env::InfoVersion.instance.get_version
+      head =<<WOK
+\\input texinfo   @c -*-texinfo-*-
+@comment %**start of header
+@setfilename #{@md.fnb}.info
+@settitle #{title}
+@syncodeindex pg cp
+@comment %**end of header
+@c %% 2
+@copying
+SiSU texinfo of #{title}
+
+Copyright @copyright{} #{year} #{author}.
+
+@quotation
+Copyright #{author}, generated by ``SiSU''
+@end quotation
+@end copying
+
+@dircategory SiSU Texinfo
+@direntry
+,* sisu: SiSU texinfo file.
+@end direntry
+WOK
+      if @md.title.sub
+        titlepage=<<WOK
+@c %% 3
+@titlepage
+@title #{title} #{subtitle}
+@author #{author}
+@page
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+@contents
+WOK
+      else
+        titlepage=<<WOK
+@c %% 3
+@titlepage
+@title #{title}
+@author #{author}
+@page
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+
+@contents
+WOK
+      end
+      "#{head}#{titlepage}"
+    end
+    def topnode(txt)
+      txt=spec_char(txt)
+      txt=txt.gsub(/<(br|p|i)>|<\/\s*(br|p|i)>|<(br|p)\s*\/>/," #{Tex[:backslash]*2} ").
+        gsub(/\$/,"\\$").
+        gsub(/[,]\s*/,' - ')
+      "@c %% 4\n" +
+        "@ifnottex\n" +
+        "@node Top\n" +
+        "@top #{txt}\n\n" +
+        "@insertcopying\n" +
+        "@end ifnottex\n\n" +
+        "@menu\n"
+    end
+    def dublincore
+      if defined? @md.title.full \
+      and @md.title.full=~/\S+/
+        full_title=spec_char(@md.title.full)
+      end
+      if defined? @md.creator.author \
+      and @md.creator.author=~/\S+/
+        author=spec_char(@md.creator.author)
+      end
+      if defined? @md.publisher \
+      and @md.publisher=~/\S+/
+        publisher=spec_char(@md.publisher)
+      end
+      if defined? @md.creator.contributor \
+      and @md.creator.contributor=~/\S+/
+        contributor=spec_char(@md.contributor)
+      end
+      if defined? @md.date.published \
+      and @md.date.published=~/\S+/
+        date=spec_char(@md.date.published)
+      end
+      if defined? @md.date.created \
+      and @md.date.created=~/\S+/
+        date_created=spec_char(@md.date.created)
+      end
+      if defined? @md.date.issued \
+      and @md.date.issued=~/\S+/
+        date_issued=spec_char(@md.date.issued)
+      end
+      if defined? @md.date.available \
+      and @md.date.available=~/\S+/
+        date_available=spec_char(@md.date.available)
+      end
+      if defined? @md.date.valid \
+      and @md.date.valid=~/\S+/
+        date_valid=spec_char(@md.date.valid)
+      end
+      if defined? @md.date.modified \
+      and @md.date.modified=~/\S+/
+        date_modified=spec_char(@md.date.modified)
+      end
+      if defined? @md.classify.subject \
+      and @md.classify.subject=~/\S+/
+        subject=spec_char(@md.classify.subject)
+      end
+      if defined? @md.notes.description \
+      and @md.notes.description=~/\S+/
+        description=spec_char(@md.description)
+      end
+      if defined? @md.notes.coverage \
+      and @md.notes.coverage=~/\S+/
+        coverage=spec_char(@md.notes.coverage)
+      end
+      if defined? @md.notes.relation \
+      and @md.notes.relation=~/\S+/
+        relation=spec_char(@md.notes.relation)
+      end
+      #type=spec_char(@md.type) if @md.type                                   #dc
+      if defined? @md.notes.format \
+      and @md.notes.format=~/\S+/
+        format=spec_char(@md.notes.format)
+      end
+      #if defined? @md.identifier.sisupod \
+      #and @md.identifier.sisupod=~/\S+/
+      #  identifier=spec_char(@md.identifier.sisupod)
+      #end
+      if defined? @md.original.source \
+      and @md.original.source=~/\S+/
+        source=spec_char(@md.original.source)
+      end
+      if defined? @md.title.language \
+      and @md.title.language=~/\S+/
+        language=spec_char(@md.title.language)
+      end
+      if defined? @md.rights.all \
+      and @md.rights.all=~/\S+/
+        rights=spec_char(@md.rights.all)
+      end
+      rights=spec_char(@md.rights.all)
+      full_title="Title: #{full_title}\n\n" if full_title                           #dc
+      author="Author: #{author}\n\n" if author                                      #dc
+      subject="Subject: #{subject}\n\n" if subject                                  #dc
+      description="Description: #{description}\n\n" if description                  #dc
+      publisher="Publisher: #{publisher}\n\n" if publisher                          #dc
+      contributor="Contributor: #{contributor}\n\n" if contributor                  #dc
+      date="Date: #{date}\n\n" if date                                              #dc
+      date_created="Date Created: #{date_created}\n\n" if date_created              #dc
+      date_issued="Date Issued: #{date_issued}\n\n" if date_issued                  #dc
+      date_available="Date Available: #{date_available}\n\n" if date_available      #dc
+      date_valid="Date Valid: #{date_valid}\n\n" if date_valid                      #dc
+      date_modified="Date Modified: #{date_modified}\n\n" if date_modified          #dc
+      format="Format: #{format}\n\n" if format                                      #dc
+      identifier="Identifier: #{identifier}\n\n" if identifier #watch               #dc
+      source="Source: #{source}\n\n" if source                                      #dc
+      language="Language: #{language}\n\n" if language                              #dc
+      relation="Relation: #{relation}\n\n" if relation                              #dc
+      coverage="Coverage: #{coverage}\n\n" if coverage                              #dc
+      rights="Rights: #{rights}\n\n" if rights                                      #dc
+      <<WOK
+@node Dublin Core
+@unnumbered Dublin Core
+@cindex chapter, Dublin Core
+
+#{full_title}#{author}#{subject}#{description}#{publisher}#{contributor}#{date}#{date_created}#{date_issued}#{date_available}#{date_valid}#{date_modified}#{format}#{identifier}#{source}#{language}#{relation}#{coverage}#{rights}
+
+WOK
+    end
+    def tail
+      <<WOK
+@c %% 6
+@node Index
+@unnumbered Index
+@printindex cp
+
+@bye
+WOK
+    end
+    def clean(dob)
+      if dob.is==:heading \
+      and dob.obj !~/#{Dx[:ocn_o]}#{dob.ocn}#{Dx[:ocn_c]}/
+        dob.obj=dob.ocn.is_a?(Fixnum) \
+        ? "#{dob.obj} #{Dx[:ocn_o]}#{dob.ocn}#{Dx[:ocn_c]}" : dob.obj
+      end
+      dob.obj=dob.obj.gsub(/\n/m,' ').
+        gsub(/,\s+/,' - ').
+        strip
+      dob
+    end
+    def menu
+      dob=clean(@dob)
+      m=dob.obj.gsub(/[:,]\s*/,' - ').
+        gsub(/@footnote\{.+?\}\s+/,'')
+      m="* #{m}::"
+    end
+    def level_common
+      dob=clean(@dob)
+      nd=dob.obj.gsub(/@footnote\{.+?\}\s+/,'').
+        gsub(/: \s*/,' - ')
+      dob.obj="@node #{nd}\n@unnumbered #{nd}\n@cindex chapter, #{nd}\n\n"
+      dob
+    end
+    def level_sub(up)
+      dob=clean(@dob)
+      nd=dob.obj.gsub(/@footnote\{.+?\}\s+/,'').
+        gsub(/: \s*/,' - ')
+      dob.obj="@node #{nd}, #{up}\n@comment node-name, up\n@unnumbered #{nd}\n@cindex chapter, #{nd}\n\n"
+      dob
+    end
+    def level0
+      level_common
+    end
+    def level1
+      level_common
+    end
+    def level2
+      level_common
+    end
+    def level3
+      level_common
+    end
+    def level4
+      level_common
+    end
+    def level5
+      level_sub(@up)
+    end
+    def level6
+      level_sub(@up)
+    end
+    def spec_char(txt) # special characters
+      txt=txt.gsub(/#{Mx[:br_eof]}/i,'').
+        gsub(/#{Mx[:gl_o]}#169#{Mx[:gl_c]}/,'(c)').
+        gsub(/#{Mx[:gl_o]}#(?:lt|060)#{Mx[:gl_c]}/,'<').gsub(/#{Mx[:gl_o]}(gt|#062)#{Mx[:gl_c]}/,'>').
+        gsub(/#{Mx[:gl_o]}#123#{Mx[:gl_c]}/,'{').gsub(/#{Mx[:gl_o]}#125#{Mx[:gl_c]}/,'}').
+        gsub(/#{Mx[:gl_o]}#(?:126|152)#{Mx[:gl_c]}/i,'~').
+        gsub(/#{Mx[:gl_o]}#033#{Mx[:gl_c]}/,'!').
+        gsub(/#{Mx[:gl_o]}#035#{Mx[:gl_c]}/,'#').
+        gsub(/#{Mx[:gl_o]}#042#{Mx[:gl_c]}/,'*').
+        gsub(/#{Mx[:gl_o]}#047#{Mx[:gl_c]}/,'/').
+        gsub(/#{Mx[:gl_o]}#095#{Mx[:gl_c]}/,'_').
+        gsub(/#{Mx[:gl_o]}#092#{Mx[:gl_c]}/,'\\').
+        gsub(/(?:#{Mx[:br_line]}|#{Mx[:br_nl]})\s*/,"\n\n").                                   # watch
+        gsub(/<sup><font face=symbol>&atild;<\/font><\/sup>/,' ').
+        #gsub(/\\/,'\\backslash ').
+        gsub(/<:pb>/,'\\newpage').
+        gsub(/\\backslash copyright/,'\\copyright ').
+        gsub(/\^/,'\\wedge ').
+        gsub(/(\$)/,"\\$").
+        gsub(/\~/,'\\~').
+        gsub(/#{Mx[:url_o]}(https?:\S+?)#{Mx[:url_c]}/,'<\1>').
+        gsub(/#{Mx[:url_o]}_(https?:\S+?)#{Mx[:url_c]}/,'\1').
+        gsub(/§/i,'\S').
+        gsub(/£/i,'\pounds').
+        gsub(/å/,'\aa').gsub(/Å/,'\AA').
+        gsub(/æ/,'\ae').gsub(/Æ/,'\AE').
+        gsub(/ø/,'\o').gsub(/Ø/,'\O').
+        gsub(/<a href=".+?">/i,' ').
+        gsub(/<\/a>/i,' ').
+        gsub(/<!>/i,' ').
+        gsub(/#{Mx[:br_paragrph]}/i,''). #watch
+        gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'*\1*').
+        gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'/\1/').
+        gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'_\1_').
+        gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'[\1]').
+        gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'^\1^').
+        gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'+\1+').
+        gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'"\1"').
+        gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'-\1-').
+        gsub(/@/i,'@@').
+        gsub(/\{/,'@{').gsub(/\}/,'@}').
+        gsub(/(?:&nbsp;|#{Mx[:nbsp]})+/,' ').        # ~ character for hardspace
+        gsub(/&(\S+?);/,' ').
+        gsub(/&/,'<=and>').
+        gsub(/(\s+&\s+)/,' and ').
+        gsub(/(\&)/,"\\&").
+        gsub(/"(.+?)"/,"`\\1'").                                        # open & close "
+        gsub(/\s+"/," `").                                              # open "
+        gsub(/^([1-6-]\\+(?:~\S+)?|<.+?>)?\s*"/,'\1`').       # open "
+        gsub(/"(\s|\.|,|:|;)/,"'\\1").                                  # close "
+        gsub(/"([1-6-]\\+(?:~\S+)?|<.+?>)?\s*$/,"'\\1").       # close "
+        gsub(/"(\.|,)/,"'").                                            # close "
+        gsub(/\s+'/," `").                                              # open '
+        gsub(/^([1-6-]\\+(?:~\S+)?|<.+?>)?\s*'/,'\1`').       # open '
+        gsub(/(<font.*?>|<\/font>)/,'')
+    end
+    def longtable
+      @end_table="\\end{longtable}"
+      @row_break='\\\\\\'
+      if @dob[/#{Mx[:gr_o]}Th?#{Mx[:tc_p]}\s+c(\d+);(.+?)#{Mx[:gr_c]}/ui] #CHECK !> closure #fix
+        no_of_cols,cols_width=$1,$2
+        @@tableheader=1 if @dob =~ /#{Mx[:gr_o]}Th/i #fix
+        @w=cols_width.split(/;\s+/)
+        @@number_of_cols=no_of_cols
+        @colW=[]
+        @colW << '{'
+        @w.each  do |x|
+          col_w=x.gsub(/.+/,'l\|') #unless x.nil?
+          @colW << "#{col_w}" if col_w
+        end
+        @colW << '}'
+        @colW=@colW.join
+        @@start_table="\\setlength{\\LTleft}{0pt}\n\\setlength{\\LTright}{\\fill}\n" +
+          "\\begin{longtable}[hb]#{@colW}\n"
+        @dob.obj=@dob.obj.gsub(/#{Mx[:gr_o]}Th?#{Mx[:tc_p]}\s+c\d+?;.+#{Mx[:gr_c]}/u,"#{@@start_table}") #fix
+      end
+      if @dob =~/#{Mx[:gr_o]}TZ#{Mx[:gr_c]}/ #fix
+        @dob.obj=@dob.obj.gsub(/#{Mx[:gr_o]}TZ#{Mx[:gr_c]}/," #{@end_table}") #fix
+      end
+      @dob.obj=@dob.obj.gsub(/#{Mx[:tc_o]}#{Mx[:tc_p]}/u,'')
+      if @@tableheader==1
+        if @dob =~/#{Mx[:tc_p]}\d+?#{Mx[:tc_p]}(.+?)(?:#{Mx[:tc_p]}|!)/u
+          tablefoot=para[/\<!f(.+?)!\>/,1]
+          @dob.obj=@dob.obj.gsub(/\<!f(.+?)!\>/,'').
+            gsub(/#{Mx[:tc_p]}\d+?#{Mx[:tc_p]}(.+?)(?:#{Mx[:tc_p]}|!)/u,
+              "{\\begin{tiny} {\\bfseries \\1}\\end{tiny}}&").
+            gsub(/&>\s*$/,
+              " #{@row_break} \\hline\\endhead #{@row_break}")
+          @dob="#{@dob} \\multicolumn{#{@@number_of_cols}}{l}{\\tiny #{tablefoot}} \\\\ \\hline\n\\endfoot\n\\hline\n" if tablefoot
+          @@tableheader=0
+          @@number_of_cols=0
+        end
+      else
+        if @dob =~/#{Mx[:tc_p]}\d+?#{Mx[:tc_p]}(.+?)(?:#{Mx[:tc_p]}|!)/u
+          @dob.obj=@dob.obj.gsub(/#{Mx[:tc_p]}\d+?#{Mx[:tc_p]}(.+?)(?:#{Mx[:tc_p]}|!)/u,"\\begin{tiny}\\1\\end{tiny}&").
+            gsub(/&>\s*$/," #{@row_break}")
+        end
+      end
+      @dob
+    end
+    def scopedtable
+      # some features related to headers have been incorporated in longtable
+      # that are not included yet here, so until synced is broken on some
+      # input files, work needs to be done if is to work as before
+      @end_table="\\end{tabular}"
+      @row_break='\\\\\\\\'
+      @break_page="#{@row_break}\n#{@row_break} \n"
+      if @dob[/#{Mx[:gr_o]}Th?#{Mx[:tc_p]}\s+c(\d+);(.+?)#{Mx[:gr_c]}/ui] #fix
+        cols_width=$2
+        @w=cols_width.split(/;\s+/)
+        @colW=[]
+        @w.each  do |x|
+          col_w=((x.to_i*12)/100.00).to_s #unless x.nil?
+          @colW << "p{#{col_w}cm}" if col_w
+        end
+        @@start_table="\\begin{tabular}{#{@colW}}\n"
+        @dob.obj=@dob.obj.gsub(/#{Mx[:gr_o]}Th?#{Mx[:tc_p]}\s+c\d+?;.+#{Mx[:gr_c]}/u,"#{@@start_table}") #fix
+      end
+      if @dob =~/#{Mx[:gr_o]}TZ#{Mx[:gr_c]}/ #fix
+        @dob.obj=@dob.obj.gsub(/#{Mx[:gr_o]}TZ#{Mx[:gr_c]}/,"#{@end_table}") #fix
+        @@table_pg_break_counter=1
+      end
+      if @dob =~/#{Mx[:tc_o]}#{Mx[:tc_p]}/u
+        if @@table_pg_break_counter==28 # taken from 34 ideal for portrait to 28 which suits landscape
+          @dob =
+            "\n\n#{@end_table} \n" +
+            "#{@break_page}" +
+            "#{@@start_table}\n"
+          @@table_pg_break_counter=1
+        else
+          @dob.obj=@dob.obj.gsub(/#{Mx[:tc_o]}#{Mx[:tc_p]}/u,'')
+          @@table_pg_break_counter+=1
+          @dob.obj=@dob.obj.gsub(/\<!f(.+?)!\>/,'')
+        end
+      end
+      if @dob =~/#{Mx[:tc_p]}\d+?#{Mx[:tc_p]}(.+?)(?:#{Mx[:tc_p]}|!)/u
+        @dob.obj=@dob.obj.gsub(/#{Mx[:tc_p]}\d+?#{Mx[:tc_p]}(.+?)(?:#{Mx[:tc_p]}|!)/u,"\\begin{tiny}\\1\\end{tiny}&").
+          gsub(/&>\s*$/,"#{@row_break}")
+      end
+      @dob
+    end
+    def graphics
+      dir=SiSU_Env::InfoEnv.new(@md.fns)
+      @dob.obj=@dob.obj.gsub(/<::\s+(\S+?)\s+>/i, #watch
+        "\\includegraphics*[width=11pt]{#{dir.path.image_source_include}/c_\\1.png}")
+    end
+    def image
+      dir=SiSU_Env::InfoEnv.new(@md.fns)
+      width="100"
+      width=@dob[/<:image.+?width=``(\d+)''.+?>/im,1]
+      width=width.to_i*0.4
+      @dob.obj=@dob.obj.gsub(/<:image\s+((?:https?|file|ftp)\S+)\s+(\S+)\s+.+\s+?>/i,
+          "\\href{\\1}{\\includegraphics*[width=#{width}pt]{#{dir.path.image_source_include}/\\2}}").
+        gsub(/<:image\s+(\S+)\s+.+\s+?>/i,
+          "\\includegraphics*[width=#{width}pt]{#{dir.path.image_source_include}/\\1}")
+    end
+    def png
+      # very messy clean up ! - work area, testing
+      z=@dob[/\\\{(.+?)\}(?:image|png)/,1] # match operator for z \\ fragile !
+      image=z.scan(/\S+/)[0] #image,w,x,y=z.scan(/\S+/)
+      image=image.gsub(/\\/,'')
+      @dob.obj=@dob.obj.gsub(/\\\{\S+\.(png|jpg|gif).+?\}(image|png)/,"<image #{image} not available>")  # fragile match operator\\ fragile !
+    end
+    def http
+      # very messy clean up ! - work area, testing
+      z=@dob[/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/,1] # match operator for z \\ fragile !
+      url=@dob[/((?:https?|file|ftp):\S+)/im,1]
+      if @dob =~/\.(png|jpg|gif)/
+        image=z.scan(/\S+/)[0] #image,w,x,y=z.scan(/\S+/)
+        image=image.gsub(/\\/,'')
+        width=200
+        width=z[/w=(\d+)/im,1] if z =~/w=(\d+)/
+        width=width.to_i*0.8
+        width=400 if width > 400
+        c=z[/``(.+?)''/im,1]
+        caption="{\\\\\\\ \n\\begin{scriptsize}#{c}\\end{scriptsize}&}" if c
+      end
+      if image
+        dir=SiSU_Env::InfoEnv.new(@md.fns)
+        @dob.obj=@dob.obj.gsub(/#{Mx[:lnk_o]}\S+\.(png|jpg|gif).+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/, # fragile match operator\\ fragile !
+          "\n\\href{#{url}}{\\includegraphics*[width=#{width}pt]{#{dir.path.image_source_include}/#{image}}}#{caption}")
+      else
+        link=z[/(.+?)\\/im,1]
+        @dob.obj=@dob.obj.gsub(/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+#{Mx[:url_c]}/,"\n\\noindent\\href{#{url}}{#{link}}")  # fragile match operator\\ fragile !
+      end
+    end
+  end
+  class TeXinfoTxt
+    def initialize(md,dob,txt)
+      @md,@dob,@txt=md,dob,txt
+    end
+    def clean(dob,txt)
+      if dob.is==:heading \
+      and txt !~/#{Dx[:ocn_o]}#{dob.ocn}#{Dx[:ocn_c]}/
+        txt=dob.ocn.is_a?(Fixnum) \
+        ? "#{dob.obj} #{Dx[:ocn_o]}#{dob.ocn}#{Dx[:ocn_c]}" : dob.obj
+      end
+      txt.strip
+    end
+    def submenu
+      txt=@txt.join("\n")
+      txt=clean(@dob,txt)
+      txt="@menu\n#{txt}\n@end menu\n\n"
+      txt=txt.gsub(/.+/m,"#{txt}")
+    end
+    def subsubmenu
+      txt=@txt.join("\n")
+      txt=clean(@dob,txt)
+      txt="@menu\n#{txt}\n@end menu\n\n"
+      txt=txt.gsub(/.+/m,"#{txt}")
+    end
+  end
+end
+__END__
+watch title, might need full_title
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    texinfo
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/texpdf.org b/org/texpdf.org
new file mode 100644
index 00000000..3aa25fcd
--- /dev/null
+++ b/org/texpdf.org
@@ -0,0 +1,2969 @@
+-*- mode: org -*-
+#+TITLE:       sisu tex pdf
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:texpdf:
+#+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
+
+* texpdf
+** texpdf.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/texpdf.rb"
+# <<sisu_document_header>>
+module SiSU_TeX
+  begin
+    require 'pstore'
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('pstore NOT FOUND (LoadError)')
+  end
+  require_relative 'texpdf_parts'                        # texpdf_parts.rb
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+    include SiSU_Particulars
+  require_relative 'texpdf_format'                      # texpdf_format.rb
+    include SiSU_TeX_Pdf
+  require_relative 'shared_metadata'                    # shared_metadata.rb
+  require_relative 'prog_text_translation'              # prog_text_translation.rb
+  @tex_file=@@tex_footnote_array=@@tex_col_w=[]
+  @@tabular="{tabular}"
+  @@column_instruct=@@squigle_close=@@tex_line_mode=@@tex_word_mode=@@line_mode=''
+  @@tex_debug_counter=@@table_pagebreak_counter=@@tex_footnote_call_counter=@@tex_table_flag=@@tex_counter=@@tex_column=@@tex_columns=@@tex_columns=@@counting=0
+  @@tex_pattern_margin_number=/\\\\begin\\\{tiny\\\}\\\\hspace\\\{0mm\\\}\\\\end\\\{tiny\\\}\\\{\\\\marginpar.+?\s+/
+  @@n=@@tableheader=@@rights=nil
+  @@date ||=SiSU_Env::InfoDate.new
+  class Source
+    begin
+      require 'pstore'
+    rescue LoadError
+      SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+        error('pstore NOT FOUND (LoadError)')
+    end
+    require_relative 'se'                               # se.rb
+      include SiSU_Env
+    require_relative 'ao'                               # ao.rb
+      include SiSU_AO
+    include SiSU_TeX
+    def initialize(opt)
+      @opt=opt
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+      @md=@particulars.md
+      @env=SiSU_Env::InfoEnv.new(@md.fns) #@env=@particulars.env
+    end
+    def directories
+      begin
+        case @opt.fns
+        when /\.(?:-|ssm\.)?sst$/
+          SiSU_Env::FileOp.new(@md).mkdir
+          Dir.mkdir(@env.processing_path.tex) unless FileTest.directory?(@env.processing_path.tex)
+        end
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    def read
+      begin
+        song
+      ensure
+        Dir.chdir(@opt.f_pth[:pth])
+      end
+    end
+    def song
+      begin
+        @md=@particulars.md
+        SiSU_Screen::Ansi.new(
+          @opt.act[:color_state][:set],
+          'LaTeX/PDF',
+          "[#{@opt.f_pth[:lng_is]}] #{@opt.fno}"
+        ).green_title_hi unless @opt.act[:quiet][:set]==:on
+        if (@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on)
+          @env.url.output_tell
+          if @md.opt.act[:pdf_l][:set]==:on
+            SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              @opt.fns,
+              "#{@env.program.pdf_viewer} #{@md.file.output_path.pdf.dir}/#{@md.file.base_filename.pdf_l}#{@md.papersize_array[0]}.pdf"
+            ).flow
+          end
+          if @md.opt.act[:pdf_p][:set]==:on
+            SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              @opt.fns,
+              "#{@opt.fns} #{@env.program.pdf_viewer} #{@md.file.output_path.pdf.dir}/#{@md.file.base_filename.pdf_p}#{@md.papersize_array[0]}.pdf"
+            ).flow
+          end
+        end
+        @md=@particulars.md
+        $flag=@md.opt.selections.str                                                          #introduced to pass 0 for no object citation numbers... to texpdf_format
+        directories
+                                                                               #% needed needs to be reprogrammed !!!
+        ao_array=SiSU_AO::Source.new(@opt).get # ao file drawn here
+        SiSU_TeX::Source::LaTeXcreate.new(@particulars).songsheet
+        ao_array=''
+        pwd=Dir.pwd
+        SiSU_TeX::Source::LaTeXtoPdf.new(@md,@particulars.env).latexrun_selective
+        Dir.chdir(pwd)
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        unless (@opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on)
+          texfiles=Dir["#{@env.processing_path.tex}/#{@opt.fns}*"]
+          texfiles.each do |f|
+            if FileTest.file?(f)
+              File.unlink(f)
+            end
+          end
+        end
+        @tex_file=@@tex_footnote_array=[]
+        @@column_instruct=''
+        @@squigle_close=@@tex_line_mode=@@tex_word_mode=@@line_mode=''
+        @@tex_debug_counter=@@table_pagebreak_counter=@@tex_footnote_call_counter=@@tex_table_flag=@@tex_counter=@@tex_column=@@tex_columns=@@tex_columns=@@counting=0
+        @@tex_col_w=[]
+        @@n=@@tableheader=@@rights=nil
+        @@date=SiSU_Env::InfoDate.new
+        @@flag={}
+        $flag=1 #remove at some stage
+        SiSU_Env::Clear.new(@opt.selections.str,@opt.fns).param_instantiate
+      end
+    end
+    private
+    class LaTeXtoPdf
+      @@n_lpdf||=0 #change
+      def initialize(md,env)
+        @md,@env=md,env
+        @f=SiSU_Env::FileOp.new(@md).base_filename
+      end
+      def latex_do(texfilename,papersize)
+        @texfilename=texfilename
+        @@n_lpdf=@@n_lpdf+1
+        tex_fn_base=@texfilename.gsub(/\.tex$/,'')
+        tell=SiSU_Screen::Ansi.new(@md.opt.selections.str)
+        if @md.opt.act[:pdf_p][:set]==:on
+          if (@md.opt.act[:verbose][:set]==:on \
+          || @md.opt.act[:verbose_plus][:set]==:on \
+          || @md.opt.act[:maintenance][:set]==:on)
+            SiSU_Screen::Ansi.new(
+              @md.opt.act[:color_state][:set],
+              "#{papersize} portrait ->"
+            ).dark_grey_title_hi
+          end
+          cmd=SiSU_Env::SystemCall.new("#{tex_fn_base}.tex",'',@md.opt.selections.str)
+          if @md.opt.act[:verbose][:set]==:on \
+          || @md.opt.act[:verbose_plus][:set]==:on \
+          || @md.opt.act[:maintenance][:set]==:on
+            tell.grey_open
+          end
+          if "#{tex_fn_base}" =~/\w+/ \
+          and "#{papersize}" =~/\w+/
+            2.times { |i| cmd.latex2pdf(@md,papersize) } #comment out to skip processing of latex portrait
+          end
+          if @md.opt.act[:verbose][:set]==:on \
+          || @md.opt.act[:verbose_plus][:set]==:on \
+          || @md.opt.act[:maintenance][:set]==:on
+            tell.p_off
+          end
+        end
+        if @md.opt.act[:pdf_l][:set]==:on
+          if (@md.opt.act[:verbose][:set]==:on \
+          || @md.opt.act[:verbose_plus][:set]==:on \
+          || @md.opt.act[:maintenance][:set]==:on)
+            SiSU_Screen::Ansi.new(
+              @md.opt.act[:color_state][:set],
+              "#{papersize} landscape ->"
+            ).dark_grey_title_hi
+          end
+          cmd=SiSU_Env::SystemCall.new("#{tex_fn_base}.landscape.tex",'',@md.opt.selections.str)
+          if (@md.opt.act[:verbose][:set]==:on \
+          || @md.opt.act[:verbose_plus][:set]==:on \
+          || @md.opt.act[:maintenance][:set]==:on)
+            tell.grey_open
+          end
+          if "#{tex_fn_base}" =~/\w+/ \
+          and "#{papersize}" =~/\w+/
+            2.times { |i| cmd.latex2pdf(@md,papersize) } #comment out to skip processing of latex landscape
+          end
+          if (@md.opt.act[:verbose][:set]==:on \
+          || @md.opt.act[:verbose_plus][:set]==:on \
+          || @md.opt.act[:maintenance][:set]==:on)
+            tell.p_off
+          end
+        end
+        pwd=Dir.pwd
+        if @md.opt.act[:pdf_p][:set]==:on
+          portrait_pdf="#{pwd}/#{tex_fn_base}.pdf"
+        end
+        if @md.opt.act[:pdf_l][:set]==:on
+          landscape_pdf="#{pwd}/#{tex_fn_base}.landscape.pdf"
+        end
+        case papersize
+        when /a4/     then pdf_p=@f.pdf_p_a4;     pdf_l=@f.pdf_l_a4
+        when /a5/     then pdf_p=@f.pdf_p_a5;     pdf_l=@f.pdf_l_a5
+        when /b5/     then pdf_p=@f.pdf_p_b5;     pdf_l=@f.pdf_l_b5
+        when /letter/ then pdf_p=@f.pdf_p_letter; pdf_l=@f.pdf_l_letter
+        when /legal/  then pdf_p=@f.pdf_p_legal;  pdf_l=@f.pdf_l_legal
+        else               pdf_p=@f.pdf_p_a4;     pdf_l=@f.pdf_l_a4
+        end
+        FileUtils::mkdir_p(@md.file.output_path.pdf.dir) unless FileTest.directory?(@md.file.output_path.pdf.dir)
+        cX=SiSU_Screen::Ansi.new(@md.opt.act[:color_state][:set]).cX
+        if @md.opt.act[:pdf_p][:set]==:on
+          if FileTest.file?(portrait_pdf)
+            FileUtils::cp(portrait_pdf,"#{@md.file.output_path.pdf.dir}/#{pdf_p}")
+            FileUtils::rm(portrait_pdf)
+          else
+            STDERR.puts "#{__FILE__}:#{__LINE__} NOT FOUND: #{portrait_pdf}" if @md.opt.act[:maintenance][:set]==:on
+            errmsg="pdf file not generated #{portrait_pdf.gsub(/.+?([^\/]+?\.pdf)$/,'\1')} (check texlive dependencies)"
+            if @md.opt.act[:no_stop][:set]==:on
+              SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+                error("#{errmsg}, proceeding without pdf output (as requested)")
+            else
+              SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+                error("#{errmsg}, STOPPING")
+              exit
+            end
+          end
+        end
+        if @md.opt.act[:pdf_l][:set]==:on
+          if FileTest.file?(landscape_pdf)
+            FileUtils::cp(landscape_pdf,"#{@md.file.output_path.pdf.dir}/#{pdf_l}")
+            FileUtils::rm(landscape_pdf)
+          else
+            STDERR.puts "#{__FILE__}:#{__LINE__} NOT FOUND: #{landscape_pdf}" if @md.opt.act[:maintenance][:set]==:on
+            errmsg="pdf file not generated #{landscape_pdf.gsub(/.+?([^\/]+?\.pdf)$/,'\1')} (check texlive dependencies)"
+            if @md.opt.act[:no_stop][:set]==:on
+              SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+                error("#{errmsg}, proceeding without pdf output (as requested)")
+            else
+              SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+                error("#{errmsg}, STOPPING")
+              exit
+            end
+          end
+        end
+        if (@md.opt.act[:verbose][:set]==:on \
+        || @md.opt.act[:verbose_plus][:set]==:on \
+        || @md.opt.act[:maintenance][:set]==:on)
+          SiSU_Screen::Ansi.new(
+            @md.opt.act[:color_state][:set],
+            @@n_lpdf,
+            'processed (SiSU LaTeX to pdf - using pdfetex aka. pdftex or pdflatex)'
+          ).generic_number
+        end
+      end
+      def latexrun_selective
+        begin
+          pwd=Dir.pwd
+          Dir.chdir(pwd) #watch
+          @tex_f_no=0
+          if FileTest.file?(@env.source_file_with_path)
+            @md.papersize_array.each do |ps|
+              if @md.fns =~/\.(?:-|ssm\.)?sst$/
+                case @md.fns
+                when /\.(?:-|ssm\.)?sst$/
+                  if FileTest.directory?(@env.processing_path.tex)==true
+                    Dir.chdir(@env.processing_path.tex)
+                    texfile=@md.fns.gsub(/$/,".#{ps}.tex").
+                      gsub(/~/,'-')
+                    if @md.opt.act[:pdf_p][:set]==:on \
+                    or @md.opt.act[:pdf_l][:set]==:on
+                      latex_do(texfile,ps)
+                      if @md.opt.act[:pdf_p][:set]==:on
+                        if File.exist?(texfile) \
+                        and File.size(texfile) > 0
+                          #@tex_f_no+=1
+                        else
+                          errmsg="zero file size #{@env.processing_path.tex}/#{texfile}"
+                          if @md.opt.act[:no_stop][:set]==:on
+                            SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+                              error("#{errmsg}, proceeding without pdf output (as requested)")
+                          else
+                            SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+                              error("#{errmsg}, STOPPING")
+                            exit
+                          end
+                        end
+                      end
+                    end
+                  end
+                end
+              end
+            end
+            case @md.papersize_array[0] #default pdf
+            when /a4/     then pdf_p=@f.pdf_p_a4;     pdf_l=@f.pdf_l_a4
+            when /a5/     then pdf_p=@f.pdf_p_a5;     pdf_l=@f.pdf_l_a5
+            when /b5/     then pdf_p=@f.pdf_p_b5;     pdf_l=@f.pdf_l_b5
+            when /letter/ then pdf_p=@f.pdf_p_letter; pdf_l=@f.pdf_l_letter
+            when /legal/  then pdf_p=@f.pdf_p_legal;  pdf_l=@f.pdf_l_legal
+            else               pdf_p=@f.pdf_p_a4;     pdf_l=@f.pdf_l_a4
+            end
+            if @md.opt.act[:pdf_p][:set]==:on
+              if FileTest.file?("#{@md.file.output_path.pdf.dir}/#{pdf_p}")
+                mklnk=((@md.file.output_dir_structure.by_language_code?) \
+                || (@md.file.output_dir_structure.by_filetype?)) \
+                ? "#{@md.fnb}.portrait.pdf"
+                : 'portrait.pdf'
+                if FileTest.directory?(@md.file.output_path.pdf.dir)
+                  pwd=Dir.pwd
+                  Dir.chdir(@md.file.output_path.pdf.dir)
+                  FileUtils::rm_f(mklnk)
+                  FileUtils::ln_s(pdf_p, mklnk)
+                  Dir.chdir(pwd)
+                end
+              end
+            end
+            if @md.opt.act[:pdf_l][:set]==:on
+              if FileTest.file?("#{@md.file.output_path.pdf.dir}/#{pdf_l}")
+                mklnk=((@md.file.output_dir_structure.by_language_code?) \
+                || (@md.file.output_dir_structure.by_filetype?)) \
+                ? "#{@md.fnb}.landscape.pdf"
+                : 'landscape.pdf'
+                pwd_set=Dir.pwd
+                Dir.chdir(@md.file.output_path.pdf.dir)
+                FileUtils::rm_f(mklnk)
+                FileUtils::ln_s(pdf_l, mklnk)
+                Dir.chdir(pwd_set)
+              end
+            end
+          else
+            SiSU_Screen::Ansi.new(
+              @md.opt.act[:color_state][:set],
+              "*WARN* FILE NOT FOUND: << #{@md.fns} >> - requested latex system processing skipped"
+            ).warn
+          end
+          lst=Dir["*.{aux,log,out}"]
+          lst.each {|file| File.unlink(file)} if lst
+        rescue
+          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+        end
+      end
+    end
+    class LaTeXcreate
+      include SiSU_Parts_TeXpdf
+      @@tex_head={
+        'a4'=>    { p: nil, l: nil },
+        'a5'=>    { p: nil, l: nil },
+        'b5'=>    { p: nil, l: nil },
+        'letter'=>{ p: nil, l: nil },
+        'legal'=> { p: nil, l: nil },
+        'book'=>  { p: nil, l: nil }
+      }
+      @@prefix_b=nil
+      def initialize(particulars)
+        @particulars=particulars
+        @md=@particulars.md
+        @env=SiSU_Env::InfoEnv.new(@md.fns) #@env=@particulars.env
+        @data=@particulars.ao_array # ao file drawn here
+        @st={ tex: {} }
+        @tex_ml=SiSU_TeX_Pdf::UseTeX.new(@md)
+        @dp=@@dp ||=SiSU_Env::InfoEnv.new.digest.pattern
+        l=SiSU_Env::StandardiseLanguage.new(@md.opt.lng).language
+        @language=l[:n]
+        @translate=SiSU_Translate::Source.new(@md,@language)
+        @codeblock_box='listings' #alternative 'boites'
+        @make ||=SiSU_Env::ProcessingSettings.new(@md)
+      end
+      def songsheet
+        begin
+          data=@data
+          @@tex_footnote_array=[]
+          @@rights=nil
+          txt_gen=if @md.opt.act[:pdf_l][:set]==:on \
+          and @md.opt.act[:pdf_p][:set]==:on
+            'pdfTex portrait & landscape'
+          elsif @md.opt.act[:pdf_l][:set]==:on
+            'pdfTex landscape'
+          elsif @md.opt.act[:pdf_p][:set]==:on
+            'pdfTex portrait'
+          else
+            SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).error('error: neither landscape nor portrait')
+          end
+          if (@md.opt.act[:verbose][:set]==:on \
+          || @md.opt.act[:verbose_plus][:set]==:on \
+          || @md.opt.act[:maintenance][:set]==:on)
+            SiSU_Screen::Ansi.new(
+              @md.opt.act[:color_state][:set],
+              txt_gen
+            ).txt_grey
+          end
+          if defined? @md.rights.all \
+          and not @md.rights.all.empty?
+            sp_char=SiSU_TeX_Pdf::SpecialCharacters.new(@md,@md.rights.copyright.copyright_and_license.dup)
+            copymark='Copyright {\begin{small}{\copyright\end{small}} '
+           #copymark='Copyright {\begin{small}^{\copyright\end{small}} '
+            copyright=sp_char.special_characters_safe.gsub(/\s*Copyright \(C\)/, copymark)
+            @@rights||="\n #{Tex[:backslash]*2}[3]\\ \\linebreak #{copyright}"
+          end
+          if defined? @md.notes.prefix_b \
+          and not @md.notes.prefix_b.empty?
+            sp_char=SiSU_TeX_Pdf::SpecialCharacters.new(@md,@md.notes.prefix_b)
+            prefix_b=sp_char.special_characters_safe
+            @@prefix_b="\n #{Tex[:backslash]*2}[3]\\ \\linebreak \\ #{prefix_b}\n" unless @@prefix_b
+          end
+          data=pre(data)
+          data=footnote(data)
+          if @md.flag_tables #WORK ON 2009
+            data=tables(data) #uncomment to start experimenting with tables
+          end
+          data=number_paras(data)
+          data=markup(data)
+          output(data)
+        rescue
+          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+        ensure
+        end
+      end
+    protected
+      def pre(data)
+        @tex_file=[]
+        data.each do |dob|
+          # DEBUG 2003w16 this is a kludge, because i could not get parameters
+          # from param, Sort out ... revert to more elegant solution
+          # even more of a kludge as had to insert newlines where code is used not satisfactory, think about
+          dob.tmp=dob.obj #.dup
+          if dob.is==:para \
+          || dob.is==:heading
+            dob.tmp=dob.tmp.gsub(/#{Mx[:mk_o]}:name#\S+?#{Mx[:mk_c]}/,'')
+            dob.tmp=SiSU_TeX_Pdf::SpecialCharacters.new(@md,dob.tmp).special_characters
+            if dob.tmp =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}/
+              dob.tmp=SiSU_TeX_Pdf::FormatTextObject.new(@md,dob.tmp).url_str_internal(dob.tmp)
+            end
+          elsif dob.is ==:code
+            dob.tmp=if @codeblock_box=='listings'
+              dob.tmp
+            else
+              SiSU_TeX_Pdf::SpecialCharacters.new(@md,dob.tmp).special_characters_code
+            end
+          elsif dob.is ==:break
+            if dob.obj==Mx[:br_page]; dob.tmp='\newpage'
+            elsif dob.obj==Mx[:br_page_new]; dob.tmp='\clearpage'
+            elsif dob.obj==Mx[:br_page_line]; dob.tmp=' \\ \hline \\ '
+            elsif dob.obj==Mx[:br_obj]; dob.tmp='\parasep'
+            end
+          elsif dob.is==:comment \
+          || dob.is==:meta
+            dob.tmp='' #dob.tmp=nil
+          end
+        end
+        data
+      end
+      def footnote(data)
+        data.each do |dob|
+          # EMBEDDED FOOTNOTES / ENDNOTES should be straightforward but not quite a synch.
+          if dob.tmp =~/#{Mx[:en_a_o]}[\d*+]+\s|#{Mx[:en_b_o]}([*+]\d+)\s/
+            dob.tmp=dob.tmp.gsub(/#{Mx[:en_a_o]}(\d+)\s+(.+?)#{Mx[:en_a_c]}/m,"\\footnote[\\1]{%\n \\2} ").
+              gsub(/#{Mx[:en_b_o]}([*+]\d+)\s+(.+?)#{Mx[:en_b_c]}/m,"\\FootnoteA{\\1}{%\n \\2} ").
+              gsub(/#{Mx[:en_a_o]}([*+]+)\s+(.+?)#{Mx[:en_a_c]}/m,"\\FootnoteA{\\1}{%\n \\2} ")
+          end
+        end
+        data
+      end
+      def tables_hash(md,dob)
+        @block={}
+        @dob=dob
+        @md.papersize_array.each do |ps|
+          @@tableheader={ ps => { p: 0, l: 0 } }
+          dob.tmp={ tmp: dob.tmp, paper_size: ps }
+          format_l=SiSU_TeX_Pdf::FormatTextObject.new(md,dob)
+          dob.tmp={ tmp: dob.tmp, paper_size: ps }
+          format_p=SiSU_TeX_Pdf::FormatTextObject.new(md,dob)
+          @block[ps]={
+            l: format_l.longtable_landscape,
+            p: format_p.longtable_portrait
+          }
+        end
+        @dob.tmp=@block
+        @dob
+      end
+      def tables(data)
+        @tex_file=[]
+        data.each do |dob|
+          @tex_file << if dob.is_a?(String) \
+          or dob.is_a?(Hash)
+            dob
+          elsif dob.is==:table
+            tables_hash(@md,dob) #Hash result
+          else dob
+          end
+        end
+        @tex_file
+      end
+      def enclose(dob)
+        dob
+      end
+      def box_boites(dob,ocn)
+        sp_char=SiSU_TeX_Pdf::SpecialCharacters.new(@md,dob.tmp,dob.is)
+        dob.tmp=sp_char.special_characters_safe
+        dob.tmp=dob.tmp.gsub(/(#{Mx[:nbsp]})/m,'{\color{mywhite}\1}').
+        #dob.tmp.gsub(/#{Mx[:nbsp]}/m,'{~}') # dob.tmp.gsub(/#{Mx[:nbsp]}\s*/m,'{~}')
+          gsub(/#{Mx[:vline]}/m,'\vline').
+          gsub(/ \\( |#{Mx[:br_nl]})/,' {\textbackslash}\1').
+          gsub(/#{Mx[:br_nl]}\s*\Z/m,'').
+          gsub(/#{Mx[:br_nl]}{2}/,'\newline \\\\\\ ').
+          gsub(/#{Mx[:br_nl]}/,' \\\\\\ ').
+          gsub(/\n\n\n/m," \\newline\n\n")
+        ocn=SiSU_TeX_Pdf::FormatTextObject.new(@md).ocn_display(dob)
+        dob.tmp = ocn \
+        + @tex_ml.paraskip_small \
+        + '\begin{Codeblock}' \
+        + '\begin{codeblockboitebox} \hardspace \newline ' \
+        + dob.tmp \
+        + '\end{codeblockboitebox}' \
+        + '\end{Codeblock}' \
+        + "\n" \
+        + @tex_ml.paraskip_normal
+        dob
+      end
+      def box_listings(dob,ocn)
+        sp_char=SiSU_TeX_Pdf::SpecialCharacters.new(@md,dob.tmp,dob.is)
+        dob.tmp=sp_char.characters_code_listings
+        dob.tmp=dob.tmp.gsub(/^\s+/m,''). #bug, fix earlier, should be made unecessary
+          gsub(/#{Mx[:nbsp]}/m,' ').
+          gsub(/#{Mx[:vline]}/m,'|').
+          gsub(/#{Mx[:br_nl]}(?:\s?\n)?/m,"\n").
+          gsub(/\n\n\n/m," \n\n")
+        ocn=SiSU_TeX_Pdf::FormatTextObject.new(@md).ocn_display(dob)
+        dob.tmp = ocn \
+        + @tex_ml.paraskip_small \
+        + '\begin{Codeblock}' \
+        + "\n" \
+        + '\begin{lstlisting} ' \
+        + "\n" \
+        + dob.tmp \
+        + "\n" \
+        + '\end{lstlisting} ' \
+        + "\n" \
+        + '\end{Codeblock}' \
+        + "\n" \
+        + @tex_ml.paraskip_normal
+        dob
+      end
+      def markup_common(dob)
+        if dob.of==:block
+          @lineone=if dob.is==:block \
+          || dob.is==:group \
+          || dob.is==:alt \
+          || dob.is==:verse
+            dob.tmp=dob.tmp.gsub(/#{Mx[:nbsp]}/m,' \hardspace ').
+              gsub(/#{Mx[:gl_bullet]}/m,'\txtbullet \hardspace '). #Bullet environment not used for grouped text, no hanging indent here
+              gsub(/#{Mx[:br_nl]}+/m,"\n\n") #match not ideal, but currently not inserting extra newlines anyway
+            ocn=SiSU_TeX_Pdf::FormatTextObject.new(@md).ocn_display(dob)
+            dob.tmp=if dob.is==:group \
+            || dob.is==:block \
+            || dob.is==:alt
+              dob.tmp=SiSU_TeX_Pdf::SpecialCharacters.new(@md,dob.tmp).special_characters_safe
+              ocn \
+              + @tex_ml.paraskip_small \
+              + "\n" \
+              + ' \\begin{footnotesize}' \
+              + "\n\n" \
+              + dob.tmp \
+              + '\\end{footnotesize}' \
+              + "\n" \
+              + @tex_ml.paraskip_normal
+            elsif dob.is==:verse
+              dob.tmp=dob.tmp.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/m,'\begin{bfseries}\1 \end{bfseries}').
+                gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/m,'\emph{\1}').
+                gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/m,'\uline{\1}')
+              ocn \
+              + @tex_ml.paraskip_tiny \
+              + "\n" \
+              + ' \\begin{footnotesize}' \
+              + "\n\n" \
+              + dob.tmp \
+              + '\\end{footnotesize}' \
+              + "\n" \
+              + @tex_ml.paraskip_normal \
+              + "\n\\linebreak\n"
+            end
+            dob
+          elsif dob.is ==:code
+            dob=if @codeblock_box == 'listings'
+              box_listings(dob,ocn)
+            elsif @codeblock_box == 'boites'
+              box_boites(dob,ocn)
+            else
+              box_boites(dob,ocn)
+            end
+            dob
+          else 'error' #should never occur
+          end
+          dob=enclose(dob) unless (dob.tmp.is_a?(String) && dob.tmp =~/^$/)
+          dob
+        else
+          tst=SiSU_TeX_Pdf::FormatTextObject.new(@md,dob)
+          case dob.is
+          when :heading
+            case dob.ln
+            when 0
+              tst.title_level_A
+            when 1
+              tst.section_heading_level_B
+            when 2
+              tst.section_heading_level_C
+            when 3
+              tst.section_heading_level_D
+            when 4
+              tst.heading_level_1
+            when 5
+              tst.heading_level_2
+            when 6
+              tst.heading_level_3
+            when 7
+              tst.heading_level_4
+            else dob
+            end
+          when :heading_insert
+            br="\n\\\\\n"
+            if dob.name=='book_index'
+              h=tst.section_heading_level_B
+              heading="\\clearpage\n" + h.tmp
+              idx_arr=[]
+              idx=SiSU_Particulars::CombinedSingleton.instance.get_idx_raw(@md.opt).raw_idx
+              idx.each do |x|
+                x=if x.is_a?(String)
+                  x=SiSU_TeX_Pdf::SpecialCharacters.new(@md,x).special_characters
+                  x=SiSU_TeX_Pdf::FormatTextObject.new(@md,x).url_str_internal(x,true)
+                else x=nil
+                end
+                idx_arr << x.sub(/,$/,'') if x.is_a?(String)
+              end
+              idx_str=idx_arr.join(br)
+              l=heading + br + idx_str
+              p=heading + br +
+                '\begin{multicols}{2}' + br +
+                idx_str + br +
+                '\end{multicols}'
+              dob.tmp={ l: l, p: p }
+            elsif dob.ln==2 \
+            and dob.obj=~/Metadata\b/
+              tst.section_heading_level_B
+            elsif dob.ln==4 \
+            and dob.obj=~/Metadata\b/
+              h=tst.heading_level_1
+              metadata=SiSU_Metadata::TeX_Metadata.new(@md).metadata_tex
+              dob.tmp=h.tmp + ' ' + '\begin{scriptsize}' + metadata.join(br) + '\end{scriptsize}'
+            else dob.tmp='' # dob.tmp={ l: '', p: '' }
+            end
+          when :para
+            if dob.bullet_
+              dob.tmp=tst.bullet
+            elsif dob.indent \
+            and dob.hang \
+            and dob.indent =~/[1-9]/ \
+            and dob.indent == dob.hang
+              dob.tmp=tst.indent
+            elsif dob.hang \
+            and dob.hang =~/[0-9]/ \
+            and (dob.indent != dob.hang or dob.indent =~/[1-9]/)
+              dob.tmp=tst.hang
+            else
+              dob.tmp=dob.tmp.strip
+              dob=enclose(dob) unless (dob.tmp.is_a?(String) && dob.tmp =~/^$/)
+            end
+          else
+            dob.tmp=dob.tmp.strip unless dob.is==:code
+            dob=enclose(dob) unless (dob.tmp.is_a?(String) && dob.tmp =~/^$/)
+          end
+          if dob.is_a?(String)
+            dob.tmp=dob.tmp.gsub(/\s*(?:#{Mx[:br_line]}|#{Mx[:br_nl]})\s*/,' \newline ').   #% tread with care
+              gsub(/(\.#{Tex[:tilde]}\S*\s*|<:\S+>|#{Mx[:fa_o]}.*?#{Mx[:fa_c]}|#{Mx[:gr_o]}.*?#{Mx[:gr_c]}|<!.*?!>|<!>)/,' ')   #% tread with care
+          end
+          dob
+        end
+        if (dob.tmp.is_a?(String) and dob.tmp =~/(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|image\b)/m) \
+        && dob.is !=:code
+          dob=SiSU_TeX_Pdf::BareUrls.new(@md,dob).bare_urls
+          tst=SiSU_TeX_Pdf::FormatTextObject.new(@md,dob)
+          dob=tst.urls_txt_and_images
+          dob
+        elsif (dob.tmp.is_a?(String) and dob.tmp  =~/https?:\/\/\S+\b/m) \
+        && dob.is ==:code \
+        && @codeblock_box !='listings'
+          dob=SiSU_TeX_Pdf::BareUrls.new(@md,dob).bare_urls_in_code
+          dob
+        end
+        if dob.class !=Hash \
+        && (dob.tmp.is_a?(String) and dob.tmp =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}image\b/) \
+        && dob.is !=:code
+          tst=SiSU_TeX_Pdf::FormatTextObject.new(@md,dob)
+        end
+        dob
+      end
+      def tex_box_listings
+        <<-WOK
+\\definecolor{listinggray}{gray}{0.9}
+\\definecolor{lbcolor}{rgb}{0.9,0.9,0.9}
+\\lstset{
+	backgroundcolor=\\color{lbcolor},
+	tabsize=4,
+	rulecolor=,
+	language=,
+  basicstyle=\\scriptsize,
+  upquote=true,
+  aboveskip={1.5\\baselineskip},
+  columns=fixed,
+  showstringspaces=false,
+  extendedchars=true,
+  breaklines=true,
+  prebreak = \\raisebox{0ex}[0ex][0ex]{\\ensuremath{\\hookleftarrow}},
+  frame=single,
+  showtabs=false,
+  showspaces=false,
+  showstringspaces=false,
+  identifierstyle=\\ttfamily,
+  keywordstyle=\\color[rgb]{0,0,1},
+  commentstyle=\\color[rgb]{0.133,0.545,0.133},
+  stringstyle=\\color[rgb]{0.627,0.126,0.941},
+}
+        WOK
+      end
+      def tex_box_boites
+        <<-WOK
+\\def\\codeblockboitebox{%
+  \\def\\bkvz@before@breakbox{\\ifhmode\\par\\fi\\vskip\\breakboxskip\\relax}%
+  \\def\\bkvz@set@linewidth{\\advance\\linewidth -2\\fboxrule
+    \\advance\\linewidth -2\\fboxsep} %
+  \\def\\bk@line{\\hbox to \\linewidth{%
+      \\ifbkcount\\smash{\\llap{\\the\\bk@lcnt\\ }}\\fi
+      \\psframebox*[framesep=0pt,linewidth=0pt]{%
+        \\vrule\\@width\\fboxrule \\hskip\\fboxsep
+        \\box\\bk@bxa
+        \\hskip\\fboxsep \\vrule\\@width\\fboxrule
+        }%
+      }}%
+  %\\def\\bkvz@top{\\hrule\\@height\\fboxrule}
+  \\def\\bkvz@top{\\hrule height .6pt}%
+  \\def\\bkvz@bottom{\\hrule\\@height\\fboxrule}%
+  \\breakbox}
+\\def\\endcodeblockboitebox{\\endbreakbox}
+        WOK
+      end
+      def tex_codeblock
+        codeblock_box=if @codeblock_box=='listings'
+          tex_box_listings
+        elsif @codeblock_box=='boites'
+          tex_box_boites
+        else
+          tex_box_boites
+        end
+        codeblock_box
+      end
+      def markup(data)
+        @tex_file=[]
+        home=the_text.txt_home.gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}|#{Mx[:br_paragraph]}|\\\\/,' - ') #no line splitting in heading neither html nor latex
+        title=@md.title.full.gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}|#{Mx[:br_paragraph]}|\\\\/,' - ') #no line splitting in heading neither html nor latex
+        @md.papersize_array.each do |ps|
+          if @md.opt.act[:pdf_p][:set]==:on
+            txt_obj={ txt: "#{home}: - #{title}", paper_size: ps, orientation: :portrait }
+            orient_portrait=SiSU_TeX_Pdf::FormatHead.new(@md,txt_obj)
+            @@tex_head[ps][:p]=orient_portrait.document_head_with_orientation(@codeblock_box)
+          end
+          if @md.opt.act[:pdf_l][:set]==:on
+            txt_obj={ txt: "#{home}: - #{title}", paper_size: ps, orientation: :landscape }
+            orient_landscape=SiSU_TeX_Pdf::FormatHead.new(@md,txt_obj)
+            @@tex_head[ps][:l]=orient_landscape.document_head_with_orientation(@codeblock_box)
+          end
+        end
+        @tex_file << <<-WOK
+#{@tex_ml.header}#{@tex_ml.footer}
+\\tolerance=300
+\\clubpenalty=300
+\\widowpenalty=300
+\\makeatother
+\\makeatother
+\\chardef\\txtbullet="2022
+\\chardef\\tilde="7E
+%\\chardef\\asterisk="2A
+\\def\\asterisk{{\\rm \\char42} }
+\\definecolor{Light}{gray}{.92}
+\\newcommand{\\Codeblock}[1]{\\normaltext\\raggedright\\small\\ttfamily\\texbackslash#1}
+\\newcommand{\\monosp}[1]{\\normaltext\\ttfamily\\texbackslash#1}
+\\newcommand{\\parasep}{\\\\ \\begin{center}*\\hspace{2em}*\\hspace{2em}*\\end{center} \\\\}
+\\newcommand{\\hardspace}{{~}}
+%\\newcommand{\\hardspace}{\\hspace{.5em}}
+\\newcommand{\\caret}{{\\^{~}}}
+\\newcommand{\\pipe}{{\\textbar}}
+\\newcommand{\\curlyopen}{\{}
+\\newcommand{\\curlyclose}{\}}
+\\newcommand{\\lt}{{\UseTextSymbol{OML}{<}}}
+\\newcommand{\\gt}{{\UseTextSymbol{OML}{>}}}
+\\newcommand{\\slash}{{/}}
+\\newcommand{\\underscore}{\\_}
+\\newcommand{\\exclaim}{\\Verbatim{!}}
+#{tex_codeblock}
+% (tilde hash amp affected by http)
+% \\sloppy
+\\begin{document}
+        WOK
+        @copymark='' #check and remove as now is superflous
+        x={}
+        txt_obj={ title: @md.title.full }
+        if @md.opt.act[:pdf_l][:set]==:on
+          x[:l]=SiSU_TeX_Pdf::FormatTextObject.new(@md,txt_obj).title_landscape
+        end
+        if @md.opt.act[:pdf_p][:set]==:on
+          x[:p]=SiSU_TeX_Pdf::FormatTextObject.new(@md,txt_obj).title_portrait
+        end
+        @tex_file << x
+        x=nil
+        if defined? @md.creator.author \
+        and @md.creator.author
+          sp_char=SiSU_TeX_Pdf::SpecialCharacters.new(@md,@md.creator.author)
+          author=sp_char.special_characters
+          @tex_file << if @md.author_home
+            <<-WOK
+
+\\author{\\href{#{@md.author_home}}{#{@copymark} \\textnormal{#{author}}}}
+            WOK
+          else "\n\\author{#{@copymark} \\textnormal{#{author}}}"
+          end
+        end
+        if defined? @md.make.cover_image \
+        and not @md.make.cover_image.nil? \
+        and @md.make.cover_image[:cover] =~/\S+/
+          x={}
+          dir=SiSU_Env::InfoEnv.new(@md.fns)
+          x[:l] =<<-WOK
+\\titlepic{\\includegraphics[width=0.3\\textwidth]{#{dir.path.image_source_include}/#{@md.make.cover_image[:cover]}}}
+          WOK
+          x[:p] =<<-WOK
+\\titlepic{\\includegraphics[width=0.6\\textwidth]{#{dir.path.image_source_include}/#{@md.make.cover_image[:cover]}}}
+          WOK
+          @tex_file << x
+          x=nil
+        end
+        @tex_file << unless @md.fnb =~/^mail\s*$/ then @tex_ml.site
+        else                                           '\date'
+        end
+        @tex_file << <<-WOK
+\\pagenumbering{roman}\\maketitle
+\\pagestyle{fancy}
+        WOK
+        if defined? @md.rights.all \
+        and @md.rights.all
+          @tex_file << "\\newpage\n"
+          @tex_file << @@rights
+          @tex_file << @@prefix_b if defined? @md.creator.prefix_b and @md.creator.prefix_b
+        end
+        x={}
+        if (@make.build.toc?)
+          toc=<<-WOK
+\\renewcommand{\\contentsname}{#{@translate.contents}}
+\\tableofcontents
+          WOK
+          toc_pb={ l: @tex_ml.newpage(:landscape), p: @tex_ml.newpage(:portrait) }
+        else
+          toc=''
+          toc_pb={ l: '', p: '' }
+        end
+        if @md.opt.act[:pdf_l][:set]==:on
+          x[:l] =<<-WOK
+#{@tex_ml.newpage(:landscape)}
+\\pagestyle{fancy}
+#{toc}#{toc_pb[:l]}
+\\pagenumbering{arabic}
+#{@tex_ml.paraskip_normal}
+#{@tex_ml.newpage(:landscape)}
+          WOK
+        end
+        if @md.opt.act[:pdf_p][:set]==:on
+          x[:p] =<<-WOK
+#{@tex_ml.newpage(:portrait)}
+\\pagestyle{fancy}
+#{toc}#{toc_pb[:p]}
+#{@tex_ml.newpage(:portrait)}
+\\pagenumbering{arabic}
+#{@tex_ml.paraskip_normal}
+#{@tex_ml.newpage(:portrait)}
+          WOK
+        end
+        @tex_file << x
+        x=nil
+        data.each do |dob|                                                      #% case follows with levels 1-6 indents & graphics
+          if dob.is_a?(Hash)
+          elsif dob.of==:para \
+          || dob.of==:block #GATEWAY FIX FIX stuff
+            dob=markup_common(dob)
+          elsif dob.is==:table
+            if ( dob.tmp['a4'] \
+            or dob.tmp['a5'] \
+            or dob.tmp['b5'] \
+            or dob.tmp['letter'] \
+            or dob.tmp['legal'])
+              @md.papersize_array.each do |ps|
+                if dob.tmp[ps]
+                  if (dob.tmp[ps][:p] and dob.tmp[ps][:l])
+                    dob.tmp[ps]={
+                      p: markup_common(dob.tmp[ps][:p]),
+                      l: markup_common(dob.tmp[ps][:l])
+                    }
+                  else p "#{__FILE__}:#{__LINE__}" if @md.opt.act[:maintenance][:set]==:on
+                  end
+                end
+              end
+            elsif dob.tmp.is_a?(Hash) \
+            and (dob.tmp[:p] and dob.tmp[:l])
+              dob = {
+                p: markup_common(dob.tmp[:p]),
+                l: markup_common(dob.tmp[:l])
+              }
+            else p "#{__FILE__}:#{__LINE__}" if @md.opt.act[:maintenance][:set]==:on
+            end
+          end
+          @tex_file << dob
+        end
+        @st[:tex][:stmp]||=@md.stmpd
+        stamp=@st[:tex][:stmp] if @st[:tex][:stmp]
+        if stamp
+          use=stamp.gsub(/\n/,"#{Tex[:backslash]*2}\n")
+          @tex_file << "\n\\newpage\n"
+          @tex_file << "\\section*" +
+            "{#{@tex_ml.owner_chapter}}\n" +
+            "\\addcontentsline{toc}" +
+            "{section}{#{@tex_ml.owner_chapter}}\n"
+          @tex_file << "#{use}\n"
+          @tex_file << @@rights if @@rights
+        end
+        @tex_file << "\n\\end{document}"
+      end
+      def number_paras_numbering(dob) # need tables and other types of object
+        if dob.of ==:para
+          paranum=dob.ocn ? dob.ocn : ''
+          paranum = '' if paranum.to_i==0
+          paranumber_display=if @make.build.ocn?
+            tags=''
+            #[keep] code that follows inserts "name tags" as hypertargets, currently using ocn (converting nametags to ocn) for internal linking, related code: |texpdf_format.rb|@|uses nametags directly|
+            #if dob.tags.length > 0 # insert tags "hypertargets"
+            #  dob.tags.each do |t|
+            #    tags=tags +"\\hspace{0mm}\\hypertarget{#{t}}{\\hspace{0mm}}"
+            #  end
+            #end
+            "\\begin{tiny}\\hspace{0mm}\\end{tiny}{\\marginpar{\\begin{tiny}\\hspace{0mm}\\hypertarget{#{dob.ocn}}{#{dob.ocn}}#{tags}\\end{tiny}}}" #ocn object citation numbering
+          else ''
+          end
+          dob.tmp = paranumber_display + dob.tmp
+        end
+        dob
+      end
+      def number_paras(data)
+        data.each do |dob|
+          dob=if dob.is_a?(Hash)
+            if ( dob['a4'] \
+            or dob['a5'] \
+            or dob['b5'] \
+            or dob['letter'] \
+            or dob['legal'])
+              para_hash={}
+              @md.papersize_array.each do |ps|
+                if defined? dob.tmp and dob.tmp[ps]
+                  if (dob.tmp[ps][:p] and dob.tmp[ps][:l])
+                    para_hash[ps]={
+                      p: number_paras_numbering(dob.tmp[ps][:p]),
+                      l: number_paras_numbering(dob.tmp[ps][:l])
+                    }
+                    dob.tmp=para_hash
+                  else p "#{__FILE__}:#{__LINE__}" if @md.opt.act[:maintenance][:set]==:on
+                  end
+                end
+              end
+            elsif (dob.tmp[:p] and dob.tmp[:l])
+              dob.tmp = {
+                p: number_paras_numbering(dob.tmp[:p]),
+                l: number_paras_numbering(dob.tmp[:l])
+              }
+            else p "#{__FILE__}:#{__LINE__}" if @md.opt.act[:maintenance][:set]==:on
+            end
+          else
+            dob=if dob.of !=:comment \
+            || dob.of !=:meta \
+            || dob.of !=:layout
+              number_paras_numbering(dob)
+            else dob
+            end
+          end
+        end
+        data
+      end
+      def output_morph_hash(o)
+        ps,h,fn=o[:ps],o[:h],o[:filename]
+        if h[ps] \
+        and (h[ps][:p] or h[ps][:l])
+          if @md.opt.act[:pdf_p][:set]==:on
+            if h[ps][:p]
+              h[ps][:p]=h[ps][:p].gsub(/[ ]+$/m,'').
+                gsub(/\n\n\n+/m,"\n\n")
+            end
+            if h[ps][:p] !~/\A\s*\Z/
+              fn[:portrait].puts h[ps][:p],"\n"
+            end
+          end
+          if @md.opt.act[:pdf_l][:set]==:on
+            if h[ps][:l]
+              h[ps][:l]=h[ps][:l].gsub(/[ ]+$/m,'').
+                gsub(/\n\n\n+/m,"\n\n")
+            end
+            if h[ps][:l] !~/\A\s*\Z/
+              fn[:landscape].puts h[ps][:l],"\n"
+            end
+          end
+        elsif (h[:p] or h[:l])
+          if @md.opt.act[:pdf_p][:set]==:on
+            if h[:p]
+              h[:p]=h[:p].gsub(/[ ]+$/m,'').
+                gsub(/\n\n\n+/m,"\n\n")
+            end
+            if h[:p] !~/\A\s*\Z/
+              fn[:portrait].puts h[:p],"\n"
+            end
+          end
+          if @md.opt.act[:pdf_l][:set]==:on
+            if h[:l]
+              h[:l]=h[:l].gsub(/[ ]+$/m,'').
+                gsub(/\n\n\n+/m,"\n\n")
+            end
+            if h[:l] !~/\A\s*\Z/
+              fn[:landscape].puts h[:l],"\n"
+            end
+          end
+        else p "#{__FILE__}:#{__LINE__}" if @md.opt.act[:maintenance][:set]==:on
+        end
+      end
+      def output(array)
+        @array=array=array.flatten.compact
+        fns=@md.fns.gsub(/~/,'-') #this is a sorry fix, but necessary as it appears latex programs like not ~
+        @md.papersize_array.each do |ps|
+          texfile_landscape=(@md.opt.act[:pdf_l][:set]==:on) \
+          ? (File.new("#{@env.processing_path.tex}/#{fns}.#{ps}.landscape.tex",'w+'))
+          : nil
+          texfile_portrait=(@md.opt.act[:pdf_p][:set]==:on) \
+          ? (File.new("#{@env.processing_path.tex}/#{fns}.#{ps}.tex",'w+'))
+          : nil
+          file={
+            landscape: texfile_landscape,
+            portrait:  texfile_portrait
+          }
+          if @md.opt.act[:pdf_p][:set]==:on
+            file[:portrait] << @@tex_head[ps][:p]
+          end
+          if @md.opt.act[:pdf_l][:set]==:on
+            file[:landscape] << @@tex_head[ps][:l]
+          end
+          array.each do |morph|
+            if morph.is_a?(String)
+              #morph.gsub!(/^\s+/,'')
+              if morph !~/\A\s*\Z/
+                if @md.opt.act[:pdf_p][:set]==:on
+                  file[:portrait].puts morph,"\n"
+                end
+                if @md.opt.act[:pdf_l][:set]==:on
+                  file[:landscape].puts morph,"\n"
+                end
+              end
+            elsif morph.class.inspect =~ /SiSU_AO_DocumentStructure/ \
+            and morph.tmp \
+            and morph.tmp.is_a?(String)
+              if morph.is !=:code \
+              && morph.of !=:block
+                morph.tmp=morph.tmp.gsub(/^\s+/,'')
+              else morph.tmp
+              end
+              if (morph.tmp !~/\A\s*\Z/) \
+              || morph.is==:code
+                if @md.opt.act[:pdf_p][:set]==:on
+                  file[:portrait].puts morph.tmp,"\n"
+                end
+                if @md.opt.act[:pdf_l][:set]==:on
+                  file[:landscape].puts morph.tmp,"\n"
+                end
+              end
+            elsif morph.is_a?(Hash)            #inserted headers and the like, only
+              h={ ps: ps, h: morph, filename: file }
+              output_morph_hash(h)
+            elsif morph.tmp.is_a?(Hash)       #tables & images?
+              h={ ps: ps, h: morph.tmp, filename: file }
+              output_morph_hash(h)
+            end
+          end
+          array=@array
+          if @md.opt.act[:pdf_p][:set]==:on
+            file[:portrait].close
+          end
+          if @md.opt.act[:pdf_l][:set]==:on
+            file[:landscape].close
+          end
+        end
+        @@tex_head={
+          'a4'=>    { p: nil, l: nil },
+          'a5'=>    { p: nil, l: nil },
+          'b5'=>    { p: nil, l: nil },
+          'letter'=>{ p: nil, l: nil },
+          'legal'=> { p: nil, l: nil },
+          'book'=>  { p: nil, l: nil }
+        }
+        array=[]
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** texpdf_parts.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/texpdf_parts.rb"
+# <<sisu_document_header>>
+module SiSU_Parts_TeXpdf
+  require_relative 'generic_parts'                       # generic_parts.rb
+  include SiSU_Parts_Generic
+  def the_line_break
+    ' \\ '
+  end
+  def url_decoration
+    def tex_open                     #'{\UseTextSymbol{OML}{<}}'
+      Dx[:url_o]
+    end
+    def tex_close                    #'{\UseTextSymbol{OML}{>}}'
+      Dx[:url_c]
+    end
+    def txt_open
+      '<'
+    end
+    def txt_close
+      '>'
+    end
+    self
+  end
+  def the_font
+    def set_fonts
+      'verdana, arial, georgia, tahoma, sans-serif, helvetica, times, roman'
+    end
+    self
+  end
+  class TeX
+    def initialize(papersize='')
+      @papersize=papersize
+    end
+    def a4
+      def portrait
+        def w
+          160
+        end
+        def h
+          228
+        end
+        def img_px
+          450
+        end
+        self
+      end
+      def landscape
+        def w
+          238
+        end
+        def h
+          160
+        end
+        def img_px
+          300
+        end
+        self
+      end
+      self
+    end
+    def letter
+      def portrait
+        def w
+          166
+        end
+        def h
+          212
+        end
+        def img_px
+          468
+        end
+        self
+      end
+      def landscape
+        def w
+          226
+        end
+        def h
+          166
+        end
+        def img_px
+          290
+        end
+        self
+      end
+      self
+    end
+    def legal
+      def portrait
+        def w
+          168
+        end
+        def h
+          286
+        end
+        def img_px
+          474
+        end
+        self
+      end
+      def landscape
+        def w
+          296
+        end
+        def h
+          166
+        end
+        def img_px
+          420
+        end
+        self
+      end
+      self
+    end
+    def b5
+      def portrait
+        def w
+          140
+        end
+        def h
+          204
+        end
+        def img_px
+          356
+        end
+        self
+      end
+      def landscape
+        def w
+          200
+        end
+        def h
+          130
+        end
+        def img_px
+          260
+        end
+        self
+      end
+      self
+    end
+    def a5
+      def portrait
+        def w
+          112
+        end
+        def h
+          162
+        end
+        def img_px
+          280
+        end
+        self
+      end
+      def landscape
+        def w
+          152
+        end
+        def h
+          100
+        end
+        def img_px
+          190
+        end
+        self
+      end
+      self
+    end
+    def dimensions
+      case @papersize
+      when /a4/     then a4
+      when /letter/ then letter
+      when /legal/  then legal
+      when /b5/     then b5
+      when /a5/     then a5
+      else               a4
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** texpdf_format.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/texpdf_format.rb"
+# <<sisu_document_header>>
+module SiSU_TeX_Pdf
+  require_relative 'texpdf_parts'                        # texpdf_parts.rb
+  @@table_pg_break_counter=1
+  class BareUrls
+    include SiSU_Parts_TeXpdf
+    def initialize(md,dob=nil)
+      @md,@dob=md,dob
+    end
+    def bare_urls
+      @dob.obj=@dob.obj.gsub(/#{Mx[:url_o]}([a-zA-Z0-9._-]+\@[a-zA-Z0-9_-]+?\.[a-zA-Z0-9._-]+)#{Mx[:url_c]}/,
+         "#{url_decoration.tex_open}\\begin{scriptsize}\\email{\\1}#{url_decoration.tex_close}")
+      @dob.tmp=@dob.tmp.gsub(/(^|[^\\])_/m,'\1\_'). #watch may not work
+        gsub(/(^|[^#{Mx[:lnk_c]}])#{Mx[:url_o]}_?(?:\\?_)?(\S+?)#{Mx[:url_c]}/m,
+          "\\1#{url_decoration.tex_open}\\begin{scriptsize}\\url{\\2}\\end{scriptsize}#{url_decoration.tex_close}")
+      @dob
+    end
+    def bare_urls_in_code
+      @dob.tmp=@dob.tmp.gsub(/(^|[^\\])_/m,'\1\_'). #watch may not work
+        gsub(/(https?:\/\/\S+?)([{]|[.,;)\]]?(?: |$))/m,
+          '\begin{scriptsize}\url{\1}\end{scriptsize}\2')
+      @dob
+    end
+  end
+  class FormatTextObject
+    include SiSU_Parts_TeXpdf
+    attr_accessor :string,:string1,:orientation,:url,:dir,:tex
+    @@sys=SiSU_Env::SystemCall.new
+    @@tex_pattern_margin_number=/\\begin\{tiny\}\\hspace\{0mm\}\\end\{tiny\}\{\\marginpar.+?\}\}\}/
+    @@tableheader={
+      'a4' => { p: 0, l: 0 },
+      'a5' => { p: 0, l: 0 },
+      'b5' => { p: 0, l: 0 },
+      'letter' => { p: 0, l: 0 },
+      'legal' => { p: 0, l: 0 }
+    }
+    @@sys=SiSU_Env::SystemCall.new
+    def initialize(md,dob=nil)
+      @md,@dob=md,dob
+      if defined? @md.image \
+      and @md.image =~/center/
+        @center_begin,@center_end='\begin{center}','\end{center}'
+      else @center_begin,@center_end='',''
+      end
+      @start_table=''
+      @tx=SiSU_Env::GetInit.new.tex
+      @env ||=SiSU_Env::InfoEnv.new(@md.fns)
+      @tex2pdf=@@tex3pdf ||=SiSU_Env::SystemCall.new.tex2pdf_engine
+      @make ||=SiSU_Env::ProcessingSettings.new(@md)
+    end
+    def ocn_display(dob)
+      show_ocn=(@make.build.ocn?) \
+      ? dob.ocn
+      : ''
+      "\\begin{tiny}\\hspace{0mm}\\end{tiny}{\\marginpar{\\begin{tiny}\\hspace{0mm}\\hypertarget{#{dob.ocn}}{#{show_ocn}}\\end{tiny}}}" #ocn object citation numbering
+    end
+    def table_special_characters(r)
+      r=r.gsub(/#{Mx[:tc_p]}/mu,'&').
+        gsub(/#{Mx[:tc_c]}/m,'\\\\\\').
+        gsub(/%/,'\%').
+        gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'\begin{bfseries}\1 \end{bfseries}').
+        gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'\emph{\1}').
+        gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'\uline{\1}'). # ulem
+        gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,"``\\1''"). # quote #CHECK
+        gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'\uline{\1}'). # ulem
+        gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'\sout{\1}'). # ulem
+        gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,"\$^{\\textrm{\\1}}\$").
+        gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,"\$_{\\textrm{\\1}}\$")
+    end
+    def longtable_landscape
+      end_table='\end{longtable}'
+      row_break='\\\\\\'
+      if @dob.is==:table
+        tw=case @dob.tmp[:paper_size]
+        when /a4/i      then @tx.a4.landscape.w     #European default, SiSU default
+        when /letter/i  then @tx.letter.landscape.w #U.S. default
+        when /legal/i   then @tx.legal.landscape.w  #U.S. alternative
+        when /book|b5/i then @tx.b5.landscape.w     #book default - larger
+        when /a5/i      then @tx.a5.landscape.w
+        else             @tx.a4.landscape.w     #default currently A4
+        end
+        textwidth=(tw.to_i/2) - 24
+        colW=[]
+        colW << '{'
+        @dob.widths.each  do |x|
+          x=(x.to_i * textwidth)/100
+          col_w=x.to_s # x.gsub(/.+/,'l\|') #unless x.nil?
+          colW << "p{#{col_w}mm}" if col_w
+        end
+        colW << '}'
+        colW=colW.join
+        start_table="\n\\setlength{\\LTleft}{0pt}\n\\setlength{\\LTright}{\\fill}\n" +
+          "\\begin{tiny}\n\\begin{longtable}#{colW}\n"
+        rows=@dob.obj.split(/#{Mx[:br_nl]}/)
+        if @dob.head_ #result imperfect, check on
+          rows[0]=rows[0].gsub(/(^|.+?)(?:#{Mx[:tc_p]}|$)/u,'\bfseries \1&').
+            gsub(/&\s*$/," #{row_break} \\hline\\endhead #{row_break}")
+        end
+        rows_new=[]
+        rows.each do |r|
+          r=table_special_characters(r)
+          r=r.gsub(/$/," #{row_break}\n") unless r =~/#{row_break*2}$/
+          if r=~/\<!f(.+?)!\>/ # not tested table footer if any
+            tablefoot=$1
+            r=r.gsub(/\<!f(.+?)!\>/,'')
+            r="#{r} \\multicolumn{#{@dob.cols}}{l}{\\tiny #{tablefoot}} \\\\ \\hline\n\\endfoot\n\\hline\n"
+          end
+          rows_new << r
+        end
+        table=rows_new.join #@dob[:ao].obj=rows.join
+        ocn_display(@dob) + start_table + table + " #{end_table}\n\\end{tiny}"
+      else ''
+      end
+    end
+    def longtable_portrait
+      end_table='\end{longtable}'
+      row_break='\\\\\\'
+      if @dob.is==:table
+        tw=case @dob.tmp[:paper_size]
+        when /a4/i      then @tx.a4.portrait.w     #European default, SiSU default
+        when /letter/i  then @tx.letter.portrait.w #U.S. default
+        when /legal/i   then @tx.legal.portrait.w  #U.S. alternative
+        when /book|b5/i then @tx.b5.portrait.w     #book default - larger
+        when /a5/i      then @tx.a5.portrait.w
+        else             @tx.a4.portrait.w         #default currently A4
+        end
+        textwidth=tw.to_i - 20
+        colW=[]
+        colW << '{'
+        @dob.widths.each do |x|
+          x=(x.to_i * textwidth)/100 #x=(x.to_i/100.0 * 160)
+          col_w=x.to_s # x.gsub(/.+/,'l\|') #unless x.nil?
+          colW << "p{#{col_w}mm}" if col_w
+        end
+        colW << '}'
+        colW=colW.join
+        start_table="\n\\setlength{\\LTleft}{0pt}\n\\setlength{\\LTright}{\\fill}\n" +
+          "\\begin{tiny}\n\\begin{longtable}#{colW}\n"
+        rows=@dob.obj.split(/#{Mx[:br_nl]}/)
+        if @dob.head_
+          rows[0]=rows[0].gsub(/(^|.+?)(?:#{Mx[:tc_p]}|$)/u,'\bfseries \1&').
+            gsub(/&\s*$/," #{row_break} \\hline\\endhead #{row_break}")
+        end
+        rows_new=[]
+        rows.each do |r|
+          r=table_special_characters(r)
+          r=r.gsub(/$/," #{row_break}\n") unless r =~/#{row_break*2}$/
+          if r=~/\<!f(.+?)!\>/ # not tested table footer if any
+            tablefoot=$1
+            r=r.gsub(/\<!f(.+?)!\>/,'')
+            r="#{r} \\multicolumn{#{@dob.cols}}{l}{\\tiny #{tablefoot}} \\\\ \\hline\n\\endfoot\n\\hline\n"
+          end
+          rows_new << r
+        end
+        table=rows_new.join #@dob[:ao].obj=rows.join
+        ocn_display(@dob) + start_table + table + " #{end_table}\n\\end{tiny}"
+      else ''
+      end
+    end
+    def remove_footnotes(cont_ln)
+      cont_ln=if cont_ln =~/\\[Ff]ootnote/m
+        cont_ln.gsub(/\s*\\[Ff]ootnote\[\d+\]\{%\s+.+?\}\s*/m,' ').
+          gsub(/\s*\\[Ff]ootnote[A]\{[*+]+\d*\}\{%\S+.+?\}\s*/m,' ')
+      else cont_ln
+      end
+    end
+    def title_level_A
+      dob=@dob
+      dob.tmp=dob.tmp.strip if dob.tmp
+      dob.tmp=dob.tmp.gsub(/\\begin\{(bfseries|itshape)\}(.+?)\\end\{\1\}/m,'\2').
+        gsub(/#{Mx[:url_o]}|#{Mx[:url_c]}/,'')
+      cont_ln=dob.tmp.dup
+      cont_ln=cont_ln.gsub(/\\begin\{(monosp)\}(.+?)\\end\{\1\}/m,'\2').
+        gsub(@@tex_pattern_margin_number,'')
+      cont_ln=remove_footnotes(cont_ln)
+      cont_ln=cont_ln.gsub(/\{[\\]+(&)\}/,'\\1')
+      titleset=''
+      dob.tmp=dob.tmp.gsub(/^(.*)\n?$/m,
+        "#{titleset}\\part*{\\1}
+\\markboth{#{@md.title.full}}\n")
+      dob
+    end
+    def section_heading_level(dob)
+      dob.tmp=dob.tmp.strip if dob.tmp
+      dob.tmp=dob.tmp.gsub(/\\begin\{(bfseries|itshape)\}(.+?)\\end\{\1\}/m,'\2').
+        gsub(/#{Mx[:url_o]}|#{Mx[:url_c]}/,'')
+      cont_ln=dob.tmp.dup
+      cont_ln=cont_ln.gsub(/\\begin\{(monosp)\}(.+?)\\end\{\1\}/m,'\2').
+        gsub(@@tex_pattern_margin_number,'')
+      cont_ln=remove_footnotes(cont_ln)
+      cont_ln=cont_ln.gsub(/\{[\\]+(&)\}/,'\\1')
+      dob.tmp=dob.tmp.gsub(/^(.*)\n?$/m,
+        "\\clearpage
+\\part*{\\1}
+\\addcontentsline{toc}{part}{#{cont_ln}}
+\\markboth{#{@md.title.full}}\n")
+      dob
+    end
+    def heading_dev_null(dob)
+      dob.tmp,dob.obj='',''
+      dob
+    end
+    def heading_sublevels(dob)
+      if dob.lv=='1'
+        sect='section'
+        tocadd=%{\\addcontentsline{toc}{section}}
+        pre=''
+        post=''
+        headadd=%{\n\\markright{#{@md.title.full}}}
+      elsif dob.lv=='2'
+        sect='subsection'
+        tocadd=%{\\addcontentsline{toc}{subsection}}
+        pre=''
+        post=" \\\\\n"
+        headadd=''
+      elsif dob.lv=='3'
+        sect='subsubsection'
+        tocadd=%{\\addcontentsline{toc}{subsubsection}}
+        pre='' #pre='~~~~'
+        post=" \\\\\n"
+        headadd=''
+      end
+      dob.tmp=dob.tmp.strip if dob.tmp
+      dob.tmp=dob.tmp.gsub(/\\begin\{(bfseries|itshape)\}(.+?)\\end\{\1\}/m,'\2').
+        gsub(/#{Mx[:url_o]}|#{Mx[:url_c]}/,'')
+      cont_ln=dob.tmp.dup
+      cont_ln=cont_ln.gsub(/\\begin\{(monosp)\}(.+?)\\end\{\1\}/m,'\2').
+        gsub(@@tex_pattern_margin_number,'').
+        gsub(/#{Tex[:backslash]*2}/,"#{Tex[:backslash]*4}"). # added w42
+        gsub(/\\footnote\[\d+\]\{%.+?\\end\{scriptsize\}\s*\}/m,''). #arbitrary bugfix, revisit should not be necessary, eg. wta.1994 2004w22
+        gsub(/\\Footnote[A]\{[*+]+\d*\}\{%.+?\\end\{scriptsize\}\s*\}/m,'') #arbitrary bugfix, revisit should not be necessary, eg. wta.1994 2004w22
+      if dob.name =~/endnotes/
+        dob.tmp=dob.tmp.gsub(/.+/m,'')
+      end
+      cont_ln=remove_footnotes(cont_ln)
+      cont_ln=cont_ln.gsub(/\{[\\]+(&)\}/,'\\1')
+      dob.tmp=dob.tmp.gsub(/^(.*)?\n?$/m,
+        "\\#{sect}*{\\1}
+#{tocadd}{#{pre}#{cont_ln}#{post}}#{headadd}")
+      dob
+    end
+    def section_heading_level_B
+      section_heading_level(@dob)
+    end
+    def section_heading_level_C
+      section_heading_level(@dob)
+    end
+    def section_heading_level_D
+      section_heading_level(@dob)
+    end
+    def heading_level_1
+      if not @dob.use_ == :dummy
+        heading_sublevels(@dob)
+      else
+        heading_dev_null(@dob)
+      end
+    end
+    def heading_level_2
+      heading_sublevels(@dob)
+    end
+    def heading_level_3
+      heading_sublevels(@dob)
+    end
+    def heading_level_4
+      heading_sublevels(@dob)
+    end
+    def hang
+      _idt=10
+      indent = "#{_idt*(@dob.indent.to_i-1)}mm"
+      hang =  "#{_idt*(@dob.hang.to_i - @dob.indent.to_i)}mm"
+      "\\begin{ParagraphHang}{#{indent}}{#{hang}}#{@dob.tmp} \\end{ParagraphHang}}"
+    end
+    def indent
+      indent=case @dob.indent
+      when /1/ then '0mm'
+      when /2/ then '10mm'
+      when /3/ then '20mm'
+      when /4/ then '30mm'
+      when /5/ then '40mm'
+      when /6/ then '50mm'
+      when /7/ then '60mm'
+      when /8/ then '70mm'
+      when /9/ then '80mm'
+      end
+      "\\begin{ParagraphIndent}{#{indent}}#{@dob.tmp} \\end{ParagraphIndent}}"
+    end
+    def bullet
+      blt=if @dob.indent
+        indent=case @dob.indent
+        when /1/ then '0em'
+        when /2/ then '1.0em'
+        when /3/ then '2.0em'
+        when /4/ then '3.0em'
+        when /5/ then '4.0em'
+        when /6/ then '5.0em'
+        when /7/ then '6.0em'
+        when /8/ then '7.0em'
+        when /9/ then '8.0em'
+        else      '-1.0em'
+        end
+        "\\begin{Bullet}{#{indent}}$\\txtbullet$\\hspace{\\enspace}#{@dob.tmp}\\end{Bullet}"
+      else
+        "\\begin{Bullet}{-5mm}$\\txtbullet$\\hspace{\\enspace}#{@dob.tmp}\\end{Bullet}"
+      end
+      blt
+    end
+    def symbol_graphic
+      dir=SiSU_Env::InfoEnv.new(@md.fns)
+      image='c_' + /<:=\s*(\S+?)\s*>/m.match(@txt).captures.join + '.png' #watch
+      if FileTest.file?("#{dir.path.image_source_include}/#{image}")
+        @txt.gsub!(/<:=\s*(\S+?)\s*>/,
+          "\\includegraphics*[width=11pt]{#{dir.path.image_source_include}/c_\\1.png}")
+      else
+        SiSU_Screen::Ansi.new(
+          @md.opt.act[:color_state][:set],
+          "ERROR - image:",
+          %{"#{image}" missing},
+          "search path: #{dir.path.image_source_include}"
+        ).error2 unless @md.opt.act[:quiet][:set]==:on
+        @txt.gsub!(/#{Mx[:lnk_o]}\S+\.(png|jpg|gif).+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/,'') # fragile match operator\\ fragile !
+      end
+    end
+    def url_str_internal(str,idx=nil)
+      map_nametags=SiSU_Particulars::CombinedSingleton.instance.get_map_nametags(@md).nametags_map #p map_nametags
+      rgx_url_internal=/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:rel_o]}#?\S+?#{Mx[:rel_c]}/m
+      while str =~/#{Mx[:lnk_o]}([^#{Mx[:lnk_o]}#{Mx[:lnk_c]}]+)#{Mx[:lnk_c]}#{Mx[:rel_o]}:(\S+?)#{Mx[:rel_c]}/m
+        link,url=$1,$2
+        link,url=link.strip,url.strip
+        link.gsub!(/&/,"#{Xx[:protect]}&")
+        url="#{@env.url.root}/" + url
+        str.sub!(/#{Mx[:lnk_o]}[^#{Mx[:lnk_o]}#{Mx[:lnk_c]}]+#{Mx[:lnk_c]}#{Mx[:rel_o]}:\S+?#{Mx[:rel_c]}/m,
+          "#{url_decoration.tex_open}\\href{#{url}}{#{link}}#{url_decoration.tex_close}")
+      end
+      while str =~/#{Mx[:lnk_o]}([^#{Mx[:lnk_o]}#{Mx[:lnk_c]}]+)#{Mx[:lnk_c]}#{Mx[:rel_o]}#?(\S+?)#{Mx[:rel_c]}/m
+        link,url=$1,$2
+        link,url=link.strip,url.strip
+        link.gsub!(/&/,"#{Xx[:protect]}&")
+        url.gsub!(/\\_/,'_')
+        ocn_lnk=if map_nametags[url] \
+        and map_nametags[url][:ocn]
+          map_nametags[url][:ocn]
+        else nil
+        end
+        ocn_lnk=(url=~/^\d+$/ ? url : ocn_lnk)
+        if ocn_lnk and not ocn_lnk.empty?
+          idx \
+          ? (str.sub!(rgx_url_internal,"\\hyperlink{#{ocn_lnk}}{#{link}}"))
+          : (str.sub!(rgx_url_internal,"#{url_decoration.tex_open}\\hyperlink{#{ocn_lnk}}{#{link}}#{url_decoration.tex_close}"))
+        else
+          puts %{name tag: "#{url}" not found}
+          str.sub!(rgx_url_internal,"#{link}")
+        end
+        #[keep] code that follows uses nametags directly, currently nametags converted to their ocn, related code: |texpdf.rb|@|hypertargets|
+        #idx \
+        #? (str.sub!(rgx_url_internal,"\\hyperlink{#{url}}{#{link}}")) \
+        #: (str.sub!(rgx_url_internal,"#{url_decoration.tex_open}\\hyperlink{#{url}}{#{link}}#{url_decoration.tex_close}"))
+      end
+      str=str.gsub(/#{Xx[:protect]}/,'')
+    end
+    def url_str(str)
+      rgx_url_generic=/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/m
+      while str =~rgx_url_generic
+        if str=~rgx_url_generic
+          regx_url=%r/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/m
+          z,url=regx_url.match(str).captures if str =~regx_url
+          url=url.strip
+          link=z.strip
+          link.gsub!(/&/,"#{Xx[:protect]}&")
+          str.sub!(rgx_url_generic,"#{url_decoration.tex_open}\\href{#{url}}{#{link}}#{url_decoration.tex_close}")
+          str=str.gsub(/#{Xx[:protect]}/,'')
+          str
+        else str
+        end
+        str
+      end
+      str
+    end
+    def url_with_txt(dob)
+      rgx_url_generic=/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/m
+      while dob.tmp =~rgx_url_generic
+        if dob.tmp=~rgx_url_generic
+          if dob.tmp =~/#{Mx[:lnk_o]}(?:.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/m
+            regx_url=%r/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/m
+            punctuate=/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/m.match(dob.tmp).captures.join
+          else
+            regx_url=%r/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/m
+            punctuate=''
+          end
+          z,url=regx_url.match(dob.tmp).captures if dob.tmp =~regx_url
+          url=url.strip
+          link=z.strip
+          link.gsub!(/&/,"#{Xx[:protect]}&")
+          dob.tmp.sub!(rgx_url_generic,"#{url_decoration.tex_open}\\href{#{url}}{#{link}}#{url_decoration.tex_close}#{punctuate}")
+          dob.tmp.gsub!(/#{Xx[:protect]}/,'')
+          #dob.tmp=dob.tmp.sub(rgx_url_generic,"#{url_decoration.tex_open}\\href{#{url}}{#{link}}#{url_decoration.tex_close}#{punctuate}").
+          #  gsub(/#{Xx[:protect]}/,'')
+          dob
+        else dob
+        end
+        dob
+      end
+      dob
+    end
+    def urls_txt_and_images
+      dob=@dob
+      dir=SiSU_Env::InfoEnv.new(@md.fns)
+      @dm={
+        'a4'=>     @tx.a4.landscape.img_px,
+        'letter'=> @tx.letter.landscape.img_px,
+        'legal'=>  @tx.legal.landscape.img_px,
+        'b5'=>     @tx.b5.landscape.img_px,
+        'a5'=>     @tx.a5.landscape.img_px
+      }
+      images_hash={ }
+      generic_rgx=/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|image\b)/m
+      rgx_url_generic=/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/m
+      #url_bare_rgx=/#{Mx[:url_o]}\S+?#{Mx[:url_c]}/m
+      url_image_rgx=/#{Mx[:lnk_o]}[a-zA-Z0-9_\\-]+\.(?:png|jpg|gif).+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/m
+      image_rgx=/#{Mx[:lnk_o]}[a-zA-Z0-9_\\-]+\.(?:png|jpg|gif).+?#{Mx[:lnk_c]}image/m
+      @md.papersize_array.each do |ps|
+        images_hash[ps] = dob.tmp
+        while images_hash[ps] =~generic_rgx
+          if dob.tmp =~rgx_url_generic \
+          and dob.tmp !~/\.(?:png|jpg|gif)|#{Mx[:lnk_c]}image\b/m
+            dob=url_with_txt(dob)
+          elsif images_hash[ps]=~generic_rgx
+            if dob.tmp=~rgx_url_generic
+              if images_hash[ps] =~/#{Mx[:lnk_o]}(?:.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/m
+                regx_url=%r/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/m
+                punctuate=/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/m.match(images_hash[ps]).captures.join
+              else
+                regx_url=%r/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/m
+                punctuate=''
+              end
+              z,url=regx_url.match(images_hash[ps]).captures if images_hash[ps] =~regx_url
+              url=url.strip
+            else
+              if images_hash[ps] =~/#{Mx[:lnk_o]}(?:.+?)#{Mx[:lnk_c]}image\.[^'"\s]+?(?:[;.,]?(?:\s|$)|(?:\s|$))/m
+                regx_url=%r/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}image\.[^'"\s]+?(?:[;.,]?(?:\s|$)|(?:\s|$))/m
+                punctuate=/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}image\.[^'"\s]+?([;.,]?(?:\s|$))/m.match(images_hash[ps]).captures.join
+              else
+                regx_url=%r/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}image/m
+                punctuate=''
+              end
+              z=regx_url.match(images_hash[ps])[1] if images_hash[ps] =~regx_url
+              url=''
+            end
+            if images_hash[ps] =~/#{Mx[:lnk_o]}\s*\S+\.?(?:png|jpg|gif)/m \
+            and images_hash[ps]=~/\s+\d+x\d+(\s+|\s*#{Mx[:lnk_c]})/m
+              image=z.scan(/\S+/)[0] #image,x,y=z.scan(/\S+/)
+              image.gsub!(/\\/,'')
+              w=((z =~/\s(\d+)x\d*/) ? z[/\s(\d+)x\d*/,1] : 200)
+              width={}
+              width['a4'] =     ((w.to_i > @dm['a4'])     ? @dm['a4'] :     w)
+              width['letter'] = ((w.to_i > @dm['letter']) ? @dm['letter'] : w)
+              width['legal'] =  ((w.to_i > @dm['legal'])  ? @dm['legal'] :  w)
+              width['a5'] =     ((w.to_i > @dm['a5'])     ? @dm['a5'] :     w)
+              width['b5'] =     ((w.to_i > @dm['b5'])     ? @dm['b5'] :     w)
+              c=z[/``(.+?)''/m,1]
+              hsp="\n{\\color{mywhite} .}&~\n" # ~ character for hardspace
+              caption=(c ?  "{\\\\\ \n\\begin{scriptsize}#{hsp*3}#{c}\\end{scriptsize}&}" : '')
+            elsif images_hash[ps] =~/#{Mx[:lnk_o]}\s*(\S+\.?\.(?:png|jpg|gif))/m
+              SiSU_Screen::Ansi.new(
+                @md.opt.act[:color_state][:set],
+                %{document built without image: "#{$1}" as image dimensions not provided (either image not found or neither imagemagick nor graphicsmagick is installed)?\n}
+              ).print_grey #unless @md.opt.act[:quiet][:set]==:on
+              images_hash[ps].gsub!(/#{Mx[:lnk_o]}\s*(\S+\.?\.(?:png|jpg|gif))/,'[image]')
+            end
+            if image #most images fc etc. #% clean up !
+              if FileTest.file?("#{dir.path.image_source_include}/#{image}")
+                case images_hash[ps]
+                when url_image_rgx
+                  images_hash[ps].sub!(url_image_rgx,
+                    "#{@center_begin}\\\n\\href{#{url}}\n{\\includegraphics*[width=#{width[ps]}pt]{#{dir.path.image_source_include}/#{image}}}#{caption}#{@center_end}")
+                when image_rgx
+                  images_hash[ps].sub!(image_rgx,
+                    "#{@center_begin}\\\n\\includegraphics*[width=#{width[ps]}pt]{#{dir.path.image_source_include}/#{image}}#{caption}#{@center_end}")
+                end
+                images_hash[ps]
+              elsif @md.opt.f_pth[:pth] =~/\/\S+?\/sisupod\/\S+?\/sisupod\/doc/
+                pt=/(\/\S+?\/sisupod\/\S+?\/sisupod)\/doc/.match(@md.opt.f_pth[:pth])[1]
+                img_src=pt + '/image'
+                if FileTest.file?("#{img_src}/#{image}")
+                  case images_hash[ps]
+                  when url_image_rgx
+                    images_hash[ps].sub!(url_image_rgx,
+                      "#{@center_begin}\\\n\\href{#{url}}{\\includegraphics*[width=#{width[ps]}pt]{#{img_src}/#{image}}}#{caption} #{@center_end}")
+                  when image_rgx
+                    images_hash[ps].sub!(image_rgx,
+                      "#{@center_begin}\\\n\\includegraphics*[width=#{width[ps]}pt]{#{img_src}/#{image}}#{caption} #{@center_end}")
+                  end
+                  images_hash[ps]
+                end
+
+              elsif @md.fns =~/\.(?:ssm\.)?sst$/ \
+              and FileTest.file?("#{dir.path.image_source_include_local}/#{image}")
+                case images_hash[ps]
+                when url_image_rgx
+                  images_hash[ps].sub!(url_image_rgx,
+                    "#{@center_begin}\\\n\\href{#{url}}{\\includegraphics*[width=#{width[ps]}pt]{#{dir.path.image_source_include_local}/#{image}}}#{caption} #{@center_end}")
+                when image_rgx
+                  images_hash[ps].sub!(image_rgx,
+                    "#{@center_begin}\\\n\\includegraphics*[width=#{width[ps]}pt]{#{dir.path.image_source_include_local}/#{image}}#{caption} #{@center_end}")
+                end
+                images_hash[ps]
+              elsif @md.fns =~/\.-ss[tm]$/ \
+              and FileTest.file?("#{dir.path.image_source_include_remote}/#{image}")
+                case images_hash[ps]
+                when url_image_rgx
+                  images_hash[ps].sub!(url_image_rgx,
+                    "#{@center_begin}\\\n\\href{#{url}}{\\includegraphics*[width=#{width[ps]}pt]{#{dir.path.image_source_include_remote}/#{image}}}#{caption}#{@center_end}")
+                when image_rgx
+                  images_hash[ps].sub!(image_rgx,
+                    "#{@center_begin}\\\n\\includegraphics*[width=#{width[ps]}pt]{#{dir.path.image_source_include_remote}/#{image}}#{caption}#{@center_end}")
+                end
+                images_hash[ps]
+              else
+                SiSU_Screen::Ansi.new(
+                  @md.opt.act[:color_state][:set],
+                  "ERROR - image:",
+                  %{"#{image}" missing},
+                  "search locations: #{dir.path.image_source_include_local}, #{dir.path.image_source_include_remote} and #{dir.path.image_source_include}"
+                ).error2 unless @md.opt.act[:quiet][:set]==:on
+                if images_hash[ps] =~url_image_rgx \
+                or images_hash[ps] =~image_rgx
+                  images_hash[ps]=''
+                end
+                images_hash[ps]
+              end
+            else
+              link=z.strip #[/(.+?)\\/m,1]
+              images_hash[ps]="\\href{#{url}}{#{link}}#{punctuate}" if images_hash[ps] =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/
+              images_hash[ps]
+            end
+          else images_hash[ps]
+          end
+          images_hash[ps] #=ocn_display(dob) + images_hash[ps]
+        end #while loop
+        images_hash
+      end
+      use_images_hash={}
+      images_hash.each do |k,t|
+        use_images_hash[k]={ l: t, p: t}
+      end
+      dob.tmp=use_images_hash
+      dob
+    end
+    def title
+      title=SiSU_TeX_Pdf::SpecialCharacters.new(@md,@md.title.full).special_characters_safe
+      "\n\\title{#{title}}"
+    end
+    def title_landscape
+      title
+    end
+    def title_portrait
+      title
+    end
+  end
+  class FormatHead
+    require_relative 'prog_text_translation'        # prog_text_translation.rb
+    def initialize(md,t_o)
+      @md,@t_o=md,t_o
+      @env=SiSU_Env::InfoEnv.new(@md.fns)
+      if t_o.is_a?(Hash)
+        @txt =t_o[:txt]            || nil
+        @subtitle=t_o[:subtitle]   || nil
+        @ps=t_o[:paper_size]       || nil
+        @ocn=t_o[:ocn]             || nil
+        @layout=t_o[:orientation]  || nil
+      else
+        p t_o.class
+        p caller
+      end
+      @tx=SiSU_Env::GetInit.new.tex
+      @tex2pdf=@@tex3pdf ||=SiSU_Env::SystemCall.new.tex2pdf_engine
+      @ps=@txt if @txt=~/(?:a4|letter|legal|book|a5|b5)/i
+      @lang ||=SiSU_i18n::Languages.new #.list[@md.opt.lng][:xlp]
+      @author=if defined? @md.creator.author \
+      and @md.creator.author=~/\S+/
+        SiSU_TeX_Pdf::SpecialCharacters.new(@md,@md.creator.author).special_characters_safe
+      else ''
+      end
+      @subject=if defined? @md.classify.subject \
+      and @md.classify.subject=~/\S+/
+        SiSU_TeX_Pdf::SpecialCharacters.new(@md,@md.classify.subject).special_characters_safe
+      else ''
+      end
+      @keywords=if defined? @md.classify.keywords \
+      and @md.classify.keywords=~/\S+/
+        SiSU_TeX_Pdf::SpecialCharacters.new(@md,@md.classify.keywords).special_characters_safe
+      else ''
+      end
+    end
+    def tex_head_lang #babel 18n
+      lang_char_arr=@md.i18n
+      mainlang_char=if @md.i18n == Array \
+      and @md.i18n.length > 0
+        lang_char_arr.slice(0)
+      else @md.opt.lng
+      end
+      mainlang=@lang.list[mainlang_char][:xlp]
+      otherlang=if mainlang != 'english'
+        [ @lang.list['en'][:xlp] ]
+      else []
+      end
+      if lang_char_arr.length > 0
+        lang_char_arr.slice(1..9).each { |ch| otherlang << @lang.list[ch][:xlp] }
+        otherlang=otherlang.uniq
+      end
+      otherlang=otherlang.join(',')
+      { mainlang: mainlang, otherlang: otherlang }
+    end
+    def tex_head_encode
+      texpdf_fontface=if defined? @md.make.texpdf_fontface.main \
+      and not @md.make.texpdf_fontface.main.nil? \
+      and @md.make.texpdf_fontface.main=~/\S{3,}/
+        @md.make.texpdf_fontface.main
+      else @env.font.texpdf.main
+      end
+      texpdf_fontface_sans=if defined? @md.make.texpdf_fontface.sans \
+      and not @md.make.texpdf_fontface.sans.nil? \
+      and @md.make.texpdf_fontface.sans=~/\S{3,}/                                  # not used
+        @md.make.texpdf_fontface.sans
+      else @env.font.texpdf.sans
+      end
+      texpdf_fontface_serif=if defined? @md.make.texpdf_fontface.serif \
+      and not @md.make.texpdf_fontface.serif.nil? \
+      and @md.make.texpdf_fontface.serif=~/\S{3,}/                                 # not used
+        @md.make.texpdf_fontface.serif
+      else @env.font.texpdf.serif
+      end
+      texpdf_fontface_mono=if defined? @md.make.texpdf_fontface.mono \
+      and not @md.make.texpdf_fontface.mono.nil? \
+      and @md.make.texpdf_fontface.mono=~/\S{3,}/
+        @md.make.texpdf_fontface.mono
+      else @env.font.texpdf.mono
+      end
+      texpdf_fontface_cjk=if @md.opt.lng =~/zh/ \
+      and defined? @md.make.texpdf_fontface.cjk_zh \
+      and not @md.make.texpdf_fontface.cjk_zh.nil? \
+      and @md.make.texpdf_fontface.cjk_zh=~/\S{3,}/
+        @md.make.texpdf_fontface.cjk_zh
+      elsif @md.opt.lng =~/ja/ \
+      and defined? @md.make.texpdf_fontface.cjk_ja \
+      and not @md.make.texpdf_fontface.cjk_ja.nil? \
+      and @md.make.texpdf_fontface.cjk_ja=~/\S{3,}/
+        @md.make.texpdf_fontface.cjk_ja
+      elsif @md.opt.lng =~/ko/ \
+      and defined? @md.make.texpdf_fontface.cjk_ko \
+      and not @md.make.texpdf_fontface.cjk_ko.nil? \
+      and @md.make.texpdf_fontface.cjk_ko=~/\S{3,}/
+        @md.make.texpdf_fontface.cjk_ko
+      elsif @md.opt.lng =~/(?:zh|ja|ko)/ \
+      and defined? @md.make.texpdf_fontface.cjk \
+      and not @md.make.texpdf_fontface.cjk.nil? \
+      and @md.make.texpdf_fontface.cjk=~/\S{3,}/
+        @md.make.texpdf_fontface.cjk
+      else
+        case @md.opt.lng
+        when /zh/ then @env.font.texpdf.cjk_zh
+        when /ja/ then @env.font.texpdf.cjk_ja
+        when /ko/ then @env.font.texpdf.cjk_ko
+        else @env.font.texpdf.cjk
+        end
+      end
+      # you may wish to check selected font against available fonts:
+      # fc-list :outline -f "%{family}\n"
+      # fc-list :lang=ja
+      case @tex2pdf
+      when /xe/
+        if @md.opt.lng =~/(?:zh|ja|ko)/
+          <<-WOK
+\\usepackage{ucs, fontspec, xltxtra, xunicode, xeCJK}
+\\setmainCJKlanguage{#{tex_head_lang[:mainlang]}}
+\\setCJKmainfont{#{texpdf_fontface_cjk}}
+\\XeTeXlinebreaklocale "#{tex_head_lang[:mainlang]}"
+\\XeTeXlinebreakskip = 0pt plus 1pt
+\\setotherlanguage{#{tex_head_lang[:otherlang]}}
+\\setmainfont{#{texpdf_fontface}}
+\\setmonofont[Scale=0.85]{#{texpdf_fontface_mono}}
+          WOK
+        elsif (tex_head_lang[:mainlang] == "english" \
+        && (tex_head_lang[:otherlang] == "english" \
+          || tex_head_lang[:otherlang] == "" \
+          || tex_head_lang[:otherlang].length == 0))
+          <<-WOK
+\\usepackage{polyglossia, ucs, fontspec, xltxtra, xunicode}
+\\setmainlanguage{#{tex_head_lang[:mainlang]}}
+\\setmainfont{#{texpdf_fontface}}
+\\setmonofont[Scale=0.85]{#{texpdf_fontface_mono}}
+% \\setsansfont{#{texpdf_fontface_sans}}
+% \\setromanfont{#{texpdf_fontface_serif}}
+          WOK
+        else
+          <<-WOK
+\\usepackage{polyglossia, ucs, fontspec, xltxtra, xunicode}
+\\setmainlanguage{#{tex_head_lang[:mainlang]}}
+\\setotherlanguage{english}
+\\setmainfont{#{texpdf_fontface}}
+\\setmonofont[Scale=0.85]{#{texpdf_fontface_mono}}
+% \\setsansfont{#{texpdf_fontface_sans}}
+% \\setromanfont{#{texpdf_fontface_serif}}
+          WOK
+        end
+      when /pdf/
+        if @md.file_encoding =~ /iso-?8859/i                                   #% iso8859
+          <<-WOK
+% \\usepackage[latin1]{inputenc}
+\\usepackage{fontspec}
+          WOK
+        else                                                                   #% utf-8 assumed
+        <<-WOK
+\\usepackage{babel}
+\\usepackage{ucs}
+\\usepackage[utf8x]{inputenc}
+          WOK
+        end
+      end
+    end
+    def tex_head_info
+      generator="Generated by: #{@md.project_details.project} #{@md.project_details.version} of #{@md.project_details.date_stamp} (#{@md.project_details.date})" if @md.project_details.version
+      lastdone="Last Generated on: #{Time.now}"
+      rubyv="Ruby version: #{@md.ruby_version}"
+      <<-WOK
+%% SiSU (Linux & Ruby - \"better ways\") LaTeX output
+%% #{generator}
+%% #{rubyv}
+%% LaTeX output
+%% #{lastdone}
+%% SiSU http://www.jus.uio.no/sisu
+      WOK
+    end
+    def tex_head_paper_portrait(d)
+      multicol=(@md.book_idx ? '\usepackage{multicol}' : '')
+      <<-WOK
+#{tex_head_info}
+\\usepackage{geometry}
+\\documentclass[#{d[:fontsize]},#{d[:papertype]},titlepage]{scrartcl}        %with titlepage
+\\setlength{\\textheight}{#{d[:textheight]}mm} \\setlength{\\textwidth}{#{d[:textwidth]}mm}
+\\setlength{\\oddsidemargin}{#{d[:oddsidemargin]}} \\setlength{\\evensidemargin}{#{d[:evensidemargin]}}
+\\setlength{\\topmargin}{#{d[:topmargin]}} \\setlength{\\headheight}{#{d[:headheight]}}
+\\setlength{\\headsep}{#{d[:headsep]}}
+\\setlength{\\marginparsep}{#{d[:marginparsep]}}
+\\setlength{\\marginparwidth}{#{d[:marginparwidth]}}
+#{multicol}
+      WOK
+    end
+    def tex_head_paper_landscape(d)
+      <<-WOK
+#{tex_head_info}
+\\usepackage{geometry}
+\\documentclass[#{d[:fontsize]},#{d[:papertype]},landscape,titlepage,twocolumn]{scrartcl}        %with titlepage
+\\setlength{\\textheight}{#{d[:textheight]}mm} \\setlength{\\textwidth}{#{d[:textwidth]}mm}
+\\setlength{\\oddsidemargin}{#{d[:oddsidemargin]}} \\setlength{\\evensidemargin}{#{d[:evensidemargin]}}
+\\setlength{\\topmargin}{#{d[:topmargin]}} \\setlength{\\headheight}{#{d[:headheight]}}
+\\setlength{\\headsep}{#{d[:headsep]}}
+\\setlength{\\columnsep}{#{d[:columnsep]}}
+\\setlength{\\marginparsep}{#{d[:marginparsep]}}
+\\setlength{\\marginparwidth}{#{d[:marginparwidth]}}
+      WOK
+    end
+    def tex_head_paper_portrait_dvi(d)
+      <<-WOK
+#{tex_head_info}
+\\documentclass[#{d[:fontsize]},#{d[:papertype]},titlepage]{scrartcl}      %with titlepage
+\\setlength{\\textheight}{#{d[:textheight]}mm} \\setlength{\\textwidth}{#{d[:textwidth]}mm}
+\\setlength{\\oddsidemargin}{#{d[:oddsidemargin]}} \\setlength{\\evensidemargin}{#{d[:evensidemargin]}}
+\\setlength{\\topmargin}{#{d[:topmargin]}} \\setlength{\\headheight}{#{d[:headheight]}}
+\\setlength{\\headsep}{#{d[:headsep]}}
+\\setlength{\\marginparsep}{#{d[:marginparsep]}}
+\\setlength{\\marginparwidth}{#{d[:marginparwidth]}}
+      WOK
+    end
+    def tex_head_paper_dimensions
+      d={}
+      fontsize_set=if defined? @env.font.texpdf.size(@md.opt.act[:pdf_font_size]) \
+      and not @env.font.texpdf.size(@md.opt.act[:pdf_font_size]).nil?
+        @env.font.texpdf.size(@md.opt.act[:pdf_font_size])
+      else :na
+      end
+      case @layout
+      when :portrait
+        fontsize=(fontsize_set==:na) ? '11pt' : (fontsize_set + 'pt')
+        d[:papertype],d[:fontsize]='a4paper',fontsize
+        d[:oddsidemargin],d[:evensidemargin],d[:topmargin]='0mm','0mm','-12pt'
+        d[:headheight],d[:headsep],d[:columnsep]='12pt','35pt',''
+        d[:marginparsep],d[:marginparwidth]='4mm','8mm'
+        case @ps #@md.papersize
+        when /a4/i           #European default, SiSU default
+          fontsize=(fontsize_set==:na) ? '12pt' : (fontsize_set + 'pt')
+          d[:papertype],d[:fontsize]='a4paper',fontsize
+          d[:textheight],d[:textwidth]=@tx.a4.portrait.h,@tx.a4.portrait.w
+        when /letter/i   #U.S. default
+          fontsize=(fontsize_set==:na) ? '12pt' : (fontsize_set + 'pt')
+          d[:papertype],d[:fontsize]='letterpaper',fontsize
+          d[:textheight],d[:textwidth]=@tx.letter.portrait.h,@tx.letter.portrait.w
+        when /legal/i     #U.S. alternative
+          fontsize=(fontsize_set==:na) ? '12pt' : (fontsize_set + 'pt')
+          d[:papertype],d[:fontsize]='legalpaper',fontsize
+          d[:textheight],d[:textwidth]=@tx.legal.portrait.h,@tx.legal.portrait.w
+        when /book|b5/i   #book default - larger
+          fontsize=(fontsize_set==:na) ? '11pt' : (fontsize_set + 'pt')
+          d[:papertype],d[:fontsize]='b5paper',fontsize
+          d[:oddsidemargin],d[:evensidemargin],d[:topmargin]='-4mm','-4mm','-36pt'
+          d[:headheight],d[:headsep],d[:columnsep]='12pt','20pt',''
+          d[:textheight],d[:textwidth]=@tx.b5.portrait.h,@tx.b5.portrait.w
+        when /a5/i
+          fontsize=(fontsize_set==:na) ? '11pt' : (fontsize_set + 'pt')
+          d[:papertype],d[:fontsize]='a5paper',fontsize
+          d[:oddsidemargin],d[:evensidemargin],d[:topmargin]='-4mm','-4mm','-36pt'
+          d[:headheight],d[:headsep],d[:columnsep]='11pt','12pt',''
+          d[:marginparsep],d[:marginparwidth]='4mm','6mm'
+          d[:textheight],d[:textwidth]=@tx.a5.portrait.h,@tx.a5.portrait.w
+        else           #default currently A4
+          fontsize=(fontsize_set==:na) ? '12pt' : (fontsize_set + 'pt')
+          d[:papertype],d[:fontsize]='a4paper',fontsize
+          d[:textheight],d[:textwidth]=@tx.a4.portrait.h,@tx.a4.portrait.w
+        end
+      when :landscape
+        fontsize=(fontsize_set==:na) ? '11pt' : (fontsize_set + 'pt')
+        d[:papertype],d[:fontsize]='a4paper',fontsize
+        d[:oddsidemargin],d[:evensidemargin],d[:topmargin]='6mm','6mm','-12mm'
+        d[:headheight],d[:headsep],d[:columnsep]='12pt','20pt','40pt'
+        d[:marginparsep],d[:marginparwidth]='4mm','8mm'
+        case @ps #@md.papersize
+        when /a4/i                            #European default, SiSU default
+          fontsize=(fontsize_set==:na) ? '11pt' : (fontsize_set + 'pt')
+          d[:papertype],d[:fontsize]='a4paper',fontsize
+          d[:textheight],d[:textwidth]=@tx.a4.landscape.h,@tx.a4.landscape.w
+        when /letter/i                    #U.S. default
+          fontsize=(fontsize_set==:na) ? '11pt' : (fontsize_set + 'pt')
+          d[:papertype],d[:fontsize]='letterpaper',fontsize
+          d[:textheight],d[:textwidth]=@tx.letter.landscape.h,@tx.letter.landscape.w
+        when /legal/i #U.S. alternative
+          fontsize=(fontsize_set==:na) ? '11pt' : (fontsize_set + 'pt')
+          d[:papertype],d[:fontsize],d[:columnsep]='legalpaper',fontsize,'48pt'
+          d[:textheight],d[:textwidth]=@tx.legal.landscape.h,@tx.legal.landscape.w
+        when /book|b5/i       #book default - larger
+          fontsize=(fontsize_set==:na) ? '11pt' : (fontsize_set + 'pt')
+          d[:papertype],d[:fontsize],d[:columnsep]='b5paper',fontsize,'35pt'
+          d[:textheight],d[:textwidth]=@tx.b5.landscape.h,@tx.b5.landscape.w
+        when /a5/i
+          fontsize=(fontsize_set==:na) ? '10pt' : (fontsize_set + 'pt')
+          d[:papertype],d[:fontsize],d[:columnsep]='a5paper',fontsize,'32pt'
+          d[:textheight],d[:textwidth]=@tx.a5.landscape.h,@tx.a5.landscape.w
+        else                            #default currently A4
+          fontsize=(fontsize_set==:na) ? '12pt' : (fontsize_set + 'pt')
+          d[:papertype],d[:fontsize]='a4paper',fontsize
+          d[:textheight],d[:textwidth]=@tx.a4.landscape.h,@tx.a4.landscape.w
+        end
+      end
+      d
+    end
+    def tex_head_paper
+      case @layout
+      when :portrait
+        tex_head_paper_portrait(tex_head_paper_dimensions)
+      when :landscape
+        tex_head_paper_landscape(tex_head_paper_dimensions)
+      end
+    end
+    def hyperlinks_monochrome
+      <<-WOK
+  colorlinks=true,
+  urlcolor=myblack,
+  filecolor=myblack,
+  linkcolor=myblack,
+      WOK
+    end
+    def hyperlinks_colored
+      <<-WOK
+  colorlinks=true,
+  urlcolor=myblue,    % \\href{...}{...}   external url
+  filecolor=mygreen,  % \\href{...}        local file
+  linkcolor=myred,    % \\href{...} and \\pageref{...}
+      WOK
+    end
+    def hyperlinks_color?
+      case @layout
+      when :portrait  then hyperlinks_monochrome
+        if @env.texpdf_hyperlinks(@md.opt.act[:pdf_hyperlink_colors]).portrait != :na
+          case @env.texpdf_hyperlinks(@md.opt.act[:pdf_hyperlink_colors]).portrait
+          when :color then hyperlinks_colored
+          when :mono  then hyperlinks_monochrome
+          else p __LINE__.to_s + ':error'
+          end
+        else               hyperlinks_monochrome
+        end
+      when :landscape
+        if @env.texpdf_hyperlinks(@md.opt.act[:pdf_hyperlink_colors]).landscape != :na
+          case @env.texpdf_hyperlinks(@md.opt.act[:pdf_hyperlink_colors]).landscape
+          when :color then hyperlinks_colored
+          when :mono  then hyperlinks_monochrome
+          else p __LINE__.to_s + ':error'
+          end
+        else               hyperlinks_colored
+        end
+      end
+    end
+    def tex_head_pdftex
+      author=if defined? @md.creator.author \
+      and @md.creator.author=~/\S+/
+        SiSU_TeX_Pdf::SpecialCharacters.new(@md,@md.creator.author).special_characters_safe_no_urls
+      else ''
+      end
+      <<-WOK
+\\usepackage{alltt}
+\\usepackage{thumbpdf}
+\\usepackage[#{@tex2pdf},
+  #{hyperlinks_color?.strip}
+  pdftitle={#{@txt}},
+  pdfauthor={#{author}},
+  pdfsubject={#{@subject}},
+  pdfkeywords={#{@keywords}},
+  pageanchor=true,
+  plainpages=true,
+  pdfpagelabels=true,
+  pagebackref,
+  bookmarks=true,
+  bookmarksopen=true,
+  pdfmenubar=true,
+  pdfpagemode=UseOutline,
+  pdffitwindow=true,
+  pdfwindowui=true,
+  plainpages=false,
+%  pdfusetitle=true,
+%  pdfpagelayout=SinglePage,
+%  pdfpagelayout=TwoColumnRight,
+%  pdfpagelayout=TwoColumnLeft,
+%  pdfstartpage=3,
+  pdfstartview=FitH
+]
+{hyperref}
+%% trace lost characters
+% \\tracinglostchars = 1
+% \\tracingonline = 1
+\\usepackage[usenames]{color}
+\\definecolor{myblack}{rgb}{0,0,0}
+\\definecolor{myred}{rgb}{0.75,0,0}
+\\definecolor{mygreen}{rgb}{0,0.5,0}
+\\definecolor{myblue}{rgb}{0,0,0.5}
+\\definecolor{mywhite}{rgb}{1,1,1}
+\\usepackage{url}
+\\urlstyle{sf}
+%\\usepackage{breakurl}
+        WOK
+    end
+    def tex_head_codeblock(codeblock_box_type)
+      codeblock_box=if codeblock_box_type=='listings'
+        <<-WOK
+\\usepackage{listings}
+\\usepackage{color}
+\\usepackage{textcomp}
+        WOK
+      elsif codeblock_box_type=='boites'
+        "\\usepackage{boites}"
+      else
+        "\\usepackage{boites}"
+      end
+      codeblock_box
+    end
+    def tex_head_misc
+      <<-WOK
+\\usepackage{textcomp}
+\\usepackage[parfill]{parskip}
+\\usepackage[normalem]{ulem}
+\\usepackage{soul}
+\\usepackage{longtable}
+\\usepackage[tc]{titlepic}
+\\usepackage{graphicx}
+\\makeatletter
+\\parindent0pt
+%\\usepackage{mathptmx}
+\\usepackage{amssymb}
+% amssymb used for backslash
+      WOK
+    end
+    def document_head_with_orientation(codeblock_box_type)
+      endnotes=("\\usepackage{endnotes}" if @txt =~/endnotes?/) || '' #not implemented see also def endnotes
+      @lang.list[@md.i18n[0]][:xlp]
+      <<-WOK
+#{tex_head_paper}
+#{tex_head_encode}
+#{tex_head_pdftex}
+#{tex_head_misc}
+#{tex_head_codeblock(codeblock_box_type)}
+\\setcounter{secnumdepth}{2}
+\\setcounter{tocdepth}{4}
+\\makeatletter
+#{endnotes}
+\\usepackage[multiple,ragged]{footmisc}
+\\setlength\\footnotemargin{12pt}
+\\usepackage[para]{manyfoot}
+\\DeclareNewFootnote{A}
+%\\DeclareNewFootnote[para]{A}
+\\newenvironment{ParagraphIndent}[1]%
+{
+\\begin{list}{}{%
+\\setlength\\topsep{0pt}%
+\\addtolength{\\leftmargin}{#1}
+\\setlength\\parsep{0pt plus 1pt}%
+}
+\\item[]
+}
+{\\end{list}}
+
+\\newenvironment{ParagraphHang}[2]%
+{
+\\begin{list}{}{%
+\\setlength\\topsep{0pt}%
+\\addtolength{\\leftmargin}{#1}
+\\itemindent=#2
+\\setlength\\parsep{0pt plus 1pt}%
+}
+\\item[]
+}
+{\\end{list}}
+
+\\newenvironment{Bullet}[1]%
+{
+\\begin{list}{}{%
+\\setlength\\topsep{0pt}%
+\\addtolength{\\leftmargin}{#1}
+\\itemindent=-1em
+\\setlength\\parsep{0pt plus 1pt}%
+}
+\\item[]
+}
+{\\end{list}}
+\\usepackage{fancyhdr}
+\\lhead{}
+\\renewcommand{\\part}{\\\@startsection
+  {part}{1}{-2mm}%
+  {-\\baselineskip}{0.5\\baselineskip}%
+  {\\bfseries\\large\\upshape\\raggedright}}
+\\renewcommand{\\section}{\\\@startsection
+  {section}{2}{-2mm}%
+  {-\\baselineskip}{0.5\\baselineskip}%
+  {\\bfseries\\large\\upshape\\raggedright}}
+\\renewcommand{\\subsection}{\\\@startsection
+  {subsection}{3}{-2mm}%
+  {-\\baselineskip}{0.5\\baselineskip}%
+  {\\bfseries\\large\\upshape\\raggedright}}
+\\renewcommand{\\subsubsection}{\\\@startsection
+  {subsubsection}{4}{-2mm}%
+  {-\\baselineskip}{0.5\\baselineskip}%
+  {\\normalfont\\normalsize\\bfseries\\raggedright}}
+\\renewcommand{\\paragraph}{\\\@startsection
+  {paragraph}{5}{-2mm}%
+  {-\\baselineskip}{0.5\\baselineskip}%
+  {\\normalfont\\normalsize\\itshape\\raggedright}}
+\\renewcommand{\\subparagraph}{\\\@startsection
+  {subparagraph}%{6}%{-2mm}%
+  {-\\baselineskip}{0.5\\baselineskip}%
+  {\\normalfont\\normalsize\\itshape\\raggedright}}
+% \\makeatother
+\\selectlanguage{#{@lang.list[@md.i18n[0]][:xlp]}}
+      WOK
+    end
+    def a4generic
+    end
+  end
+  class SpecialCharacters
+    include SiSU_Parts_TeXpdf
+    def initialize(md,str,is=:default)
+      @md,@txt,@is=md,str,is
+      @tex2pdf=@@tex3pdf ||=SiSU_Env::SystemCall.new.tex2pdf_engine
+    end
+    def xetex_code_listings(str,is=:default)                                 # ~ ^ $ & % _ { }  #LaTeX special characters - KEEP list
+      word=str.scan(/\S+|\n/) #unless line =~/^(?:@\S|%+\s)/
+      para_array=[]
+      str=if word
+        word.each do |w| # _ - / # | : ! ^ ~
+          w=w.gsub(/#{Mx[:gl_o]}#lt#{Mx[:gl_c]}/,'<').gsub(/#{Mx[:gl_o]}#gt#{Mx[:gl_c]}/,'>').
+            gsub(/[\\]?~/,'~').
+            gsub(/[#{Mx[:br_line]}#{Mx[:br_paragraph]}]/,"\n").              #watch
+            gsub(/#{Mx[:gl_o]}#(?:126|152)#{Mx[:gl_c]}/,'~').                #126 usual
+            gsub(/\\?\||#{Mx[:gl_o]}#124#{Mx[:gl_c]}/,'|')                   #unless is=='code' #unless w=~/<~\d+;(?:[ohmu]|[0-6]:)\d+;\w\d+>/ # | SiSU not really special sisu character but done, also LaTeX
+          para_array << w
+        end
+        str=para_array.join(' ')
+        str=str.strip unless is==:code
+        str
+      else ''
+      end
+      str=str.gsub(/\s*#{Mx[:mk_o]}:name#\S+?#{Mx[:mk_c]}\s*/,' ').
+        gsub(/.+?<-#>/,'').
+        gsub(/#{Mx[:br_eof]}/,'').
+        gsub(/#{Mx[:br_endnotes]}/,'').
+      #problem sequence ->
+        gsub(/&(?:lt|#060);/,'<').                                           # < SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#(?:gt|062)#{Mx[:gl_c]}/,'>').                     # > SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#123#{Mx[:gl_c]}/,'{').                            # { SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#125#{Mx[:gl_c]}/,'}').                            # } SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#(?:126|152)#{Mx[:gl_c]}/,'~').                    # ~ SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#035#{Mx[:gl_c]}/,'#').                            # SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#033#{Mx[:gl_c]}/,'!').                            # ! SiSU not really special sisu character but done, also LaTeX
+       #gsub(/(^|\s)\*\s/,'\1\asterisk ').                                   # * should you wish to escape astrisk e.g. describing \*{bold}*
+        gsub(/#{Mx[:gl_o]}#042#{Mx[:gl_c]}/,'*').                            # * should you wish to escape astrisk e.g. describing \*{bold}*
+        gsub(/#{Mx[:gl_o]}#045#{Mx[:gl_c]}/,'-').                            # - SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#043#{Mx[:gl_c]}/,'+').                            # + SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#044#{Mx[:gl_c]}/,',').                            # + SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#038#{Mx[:gl_c]}/,'&').                            #unless @txt=~/<:code>/  # / SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#047#{Mx[:gl_c]}/,'/').                            # / SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#092#{Mx[:gl_c]}/,'\\').                           # \ SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#095#{Mx[:gl_c]}/,'_').                            # _ SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#124#{Mx[:gl_c]}/,'|').                            # | SiSU not really special sisu character but done, also LaTeX
+        gsub(/#{Mx[:gl_o]}#058#{Mx[:gl_c]}/,':').                            # : SiSU not really special sisu character but done, also LaTeX
+        gsub(/#{Mx[:gl_o]}#094#{Mx[:gl_c]}|\^/,'^').                         # ^ SiSU not really special sisu character but done, also LaTeX
+      ##watch placement, problem sequence ^
+        gsub(/<sup><font face=symbol>&atild;<\/font><\/sup>/,' ').
+        gsub(/\\copy(right|mark)?/,'<=copymark>')                            # ok problem with superscript
+    end
+    def xetex_special_characters_1(str,is=:default)                          # ~ ^ $ & % _ { }  #LaTeX special characters - KEEP list
+      word=str.scan(/\S+|\n/) #unless line =~/^(?:@\S|%+\s)/
+      para_array=[]
+      str=if word
+        word.each do |w| # _ - / # | : ! ^ ~
+          if w !~/https?:/ \
+          and w=~/\/\S+?\// \
+          and w.length > 6
+            w=w.gsub(/([_.\/])/,'\1\-')
+          end
+          w=w.gsub(/#{Mx[:gl_o]}#lt#{Mx[:gl_c]}/,'<').gsub(/#{Mx[:gl_o]}#gt#{Mx[:gl_c]}/,'>').
+            gsub(/[\\]?~/,'<=tilde>').
+            gsub(/[#{Mx[:br_line]}#{Mx[:br_paragraph]}]/,' \newline ').      #watch
+            gsub(/#{Mx[:gl_o]}#(?:126|152)#{Mx[:gl_c]}/,'<=tilde>').         #126 usual
+            gsub(/\\?\||#{Mx[:gl_o]}#124#{Mx[:gl_c]}/,'\pipe')               #unless is=='code' #unless w=~/<~\d+;(?:[ohmu]|[0-6]:)\d+;\w\d+>/ # | SiSU not really special sisu character but done, also LaTeX
+          if w !~/#{Mx[:rel_o]}/ \
+          and w !~/#{Mx[:gl_o]}#/
+            w=w.gsub(/\#/,'<=hash>')
+          end
+          para_array << w
+        end
+        str=para_array.join(' ')
+        str=str.strip unless is==:code
+        str
+      else ''
+      end
+      str=str.gsub(/\s*#{Mx[:mk_o]}:name#\S+?#{Mx[:mk_c]}\s*/,' ').
+        gsub(/.+?<-#>/,'').
+        gsub(/#{Mx[:br_eof]}/,'').
+        gsub(/#{Mx[:br_endnotes]}/,'')
+      #problem sequence ->
+      str=str.gsub(/&(?:nbsp);|#{Mx[:nbsp]}/,'\hardspace') unless is==:code  # < SiSU special character also LaTeX
+      str=str.gsub(/&(?:lt|#060);/,'\lt').                                   # < SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#(?:gt|062)#{Mx[:gl_c]}/,'\gt').                   # > SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#123#{Mx[:gl_c]}/,'\curlyopen').                   # { SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#125#{Mx[:gl_c]}/,'\curlyclose').                  # } SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#(?:126|152)#{Mx[:gl_c]}/,'<=tilde>').             # ~ SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#035#{Mx[:gl_c]}/,'\#').                           # # SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#033#{Mx[:gl_c]}/,'!').                            # ! SiSU not really special sisu character but done, also LaTeX
+        gsub(/(^|\s)\*\s/,'\1\asterisk ').                                   # * should you wish to escape astrisk e.g. describing \*{bold}*
+        gsub(/#{Mx[:gl_o]}#042#{Mx[:gl_c]}/,'\*').                           # * should you wish to escape astrisk e.g. describing \*{bold}*
+        gsub(/#{Mx[:gl_o]}#045#{Mx[:gl_c]}/,'-').                            # - SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#043#{Mx[:gl_c]}/,'+').                            # + SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#044#{Mx[:gl_c]}/,',').                            # + SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#038#{Mx[:gl_c]}/,'<=amp>'). #unless @txt=~/<:code>/  # / SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#047#{Mx[:gl_c]}/,'\slash').                       # / SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#092#{Mx[:gl_c]}/,'\textbackslash').               # \ SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#095#{Mx[:gl_c]}/,'<=underscore>').                # _ SiSU special character also LaTeX
+        gsub(/#{Mx[:gl_o]}#124#{Mx[:gl_c]}/,'|').                            # | SiSU not really special sisu character but done, also LaTeX
+        gsub(/#{Mx[:gl_o]}#058#{Mx[:gl_c]}/,':').                            # : SiSU not really special sisu character but done, also LaTeX
+        gsub(/#{Mx[:gl_o]}#094#{Mx[:gl_c]}|\^/,'\caret').                    # ^ SiSU not really special sisu character but done, also LaTeX
+      ##watch placement, problem sequence ^
+        gsub(/<sup><font face=symbol>&atild;<\/font><\/sup>/,' ').
+        gsub(/\\copy(right|mark)?/,'<=copymark>') # ok problem with superscript
+    end
+    def xetex_special_characters_2(str,is=:default)
+      str=str.gsub(/#{Mx[:gl_o]}#156#{Mx[:gl_c]}/,'\oe ').
+        gsub(/\$/,'\$').
+        gsub(/\#/,'\#').
+        gsub(/\%/,'\%').
+        gsub(/\~/,'\~') #revist, should not be necessary to mark remaining tildes
+      if str !~/^\s*#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}image\s/
+        str=str.gsub(/_/,'\_')
+      end
+      str=str.gsub(/\{/,'\{').
+        gsub(/\}/,'\}')
+      str=if is==:code
+        str.gsub(/&/,'{\\\&}').
+          gsub(/\\~(\\\{)/,'{$\tilde$}\1').
+          gsub(/(\\\})\\~/,'\1{$\tilde$}').
+          gsub(/\\~(\[)/,'{$\tilde$}\1').
+          gsub(/(\])\\~/,'\1{$\tilde$}').
+          gsub(/<=tilde>/,'{$\tilde$}').
+          gsub(/<=hash>/,'{\#}')
+      else
+        str.gsub(/&nbsp;|#{Mx[:nbsp]}/,'~'). # ~ character for hardspace
+          gsub(/&/,'<=amp>')
+      end
+      str=str.gsub(/&\S+?;/,' ').
+        gsub(/§/u,'\S'). #latex: space between next character not preserved? #str.gsub(/§ /,'\S ')
+        gsub(/£/u,'\pounds').
+        gsub(/<a href=".+?">/,' ').
+        gsub(/<\/a>/,' ')
+      unless is==:no_urls
+        str=str.gsub(/((?:^|\s)#{Mx[:lnk_c]})#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,
+            '\1\begin{scriptsize}\url{\2}\end{scriptsize}\3'). #special case \{ e.g. \}http://url
+          gsub(/#{Mx[:url_o]}\\_(\S+?)#{Mx[:url_c]}/,
+            '\begin{scriptsize}\url{\1}\end{scriptsize}'). #special case \{ e.g. \}http://url
+          gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,
+            '\begin{scriptsize}\\url{\1}\end{scriptsize}') #specially escaped url no decoration
+      end
+      if is !=:code \
+      and is !=:no_urls
+        str=str.gsub(/(^|#{Mx[:gl_c]}|\s)((?:https?|file|ftp):\/\/\S+?\.[^'"\s]+?)([;.,]?(?=\s|$))/,
+          "\\1#{url_decoration.tex_open}\\begin{scriptsize}\\url{\\2}\\end{scriptsize}#{url_decoration.tex_close}\\3") #url matching with decoration <url> positive lookahead, sequence issue with { linked }http://url cannot use \b at start
+      end
+      str=str.gsub(/<:ee>/,'').
+        gsub(/<!>/,' ').  #proposed change, insert, but may be redundant
+        gsub(/<(br|p)>|<\/\s*(br|p)>|<(br|p)\s*\/>/," #{Tex[:backslash]*2} "). # Work Area
+        gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'\begin{bfseries}\1 \end{bfseries}').
+        gsub(/<h\d+>(.+?)<\/h\d+>/,'\begin{bfseries}\1 \end{bfseries}').
+        gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'\emph{\1}').
+        gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'\uline{\1}'). # ulem
+        gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,"``\\1''"). # quote #CHECK
+        gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'\uline{\1}'). # ulem
+        gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'\sout{\1}'). # ulem
+        gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,"\$^{\\textrm{\\1}}\$").
+        gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,"\$_{\\textrm{\\1}}\$").
+        gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,'\begin{monosp}\1\end{monosp}')
+      unless is==:code
+        str=str.gsub(/"(.+?)"/,'“\1”').  # quote marks / quotations open & close " need condition exclude for code
+          gsub(/\s+"/,' “').                                # open "
+          gsub(/^(#{Mx[:lv_o]}[1-6-]:\S*?#{Mx[:lv_c]}|<.+?>)?\s*"/,'\1“'). #fix Mx[:lv_o] # open "
+          gsub(/"(\s|\.|,|:|;)/,'”\1').                     # close "
+          gsub(/"(#{Mx[:lv_o]}[1-6-]:\S*?#{Mx[:lv_c]}|<.+?>)?\s*$/,'”\1'). #fix Mx[:lv_o] # close "
+          gsub(/"(\.|,)/,'”').                              # close "
+          gsub(/\s+'/,' `').                                # open '
+          gsub(/^(#{Mx[:lv_o]}[1-6-]:\S*?#{Mx[:lv_c]}|<.+?>)?\s*'/,'\1`') #fix Mx[:lv_o] # open '
+      end
+      str=str.gsub(/(<font.*?>|<\/font>)/,'').
+        gsub(/\s*#{Mx[:fa_superscript_o]}(\S+?)#{Mx[:fa_superscript_c]}/,'^\1')
+      str
+    end
+    def xetex_special_characters_3(str)
+      str=str.gsub(/<br(\s*[^\/][^>])/,'\1'). # clean up, incredibly messy :-( footnote indents, problems if match exists in ordinary paragraphs? check! Work Area 200501 a bit tricky as must be able to match multiple times, and to clean remainder
+        gsub(/([^<][^b][^r]\s+)\/>/,'\1') # clean up, incredibly messy :-( footnote indents, problems if match exists in ordinary paragraphs? check! Work Area 200501 a bit tricky as must be able to match multiple times, and to clean remainder
+      while str =~/(https?:\/\/\S+?)(?:<=tilde>\S+)+/ #tilde in urls \href treated differently from text #FIX
+        str=str.gsub(/(https?:\/\/\S+?)(?:<=tilde>(\S+))+/,'\1~\2')
+      end
+      str=str.gsub(/<=tilde>/,'{$\tilde$}').
+        gsub(/(https?:\/\/\S+?)(?:(?:<=hash>)(\S+))+/,'\1#\2'). #hash in urls \href treated differently from text #FIX
+        gsub(/<=hash>/,'{\#}')
+      while str =~/(https?:\/\/\S+?)(?:<=amp>\S+)+/ #amp in urls \href treated differently from text #FIX
+        str=str.gsub(/(https?:\/\/\S+?)(?:<=amp>(\S+))+/,'\1&\2')
+      end
+      str=str.gsub(/<=amp>/,'{\\\&}'). #changed ... 2005
+        gsub(/<=copymark>\s*(.+)/,
+          '^\copyright \textnormal{\1} \2') # watch likely to be problematic
+      str
+    end
+    def special_characters_safe_close(str)
+      str=str.gsub(/<=tilde>/,'{$\tilde$}').
+        gsub(/<=hash>/,'{\#}').
+        gsub(/<=amp>/,'{\\\&}'). #changed ... 2005
+        gsub(/<=copymark>\s*(.+)/,
+          '^\copyright \textnormal{\1} \2') # watch likely to be problematic
+    end
+    def special_characters_code_fix(str)
+      str=str.gsub(/<=tilde>/,'{$\tilde$}')
+      str
+    end
+    def special_characters_unsafe_1(str) #depreciated, make obsolete
+      # some substitutions are sequence sensitive, rearrange with care.
+      str=str.gsub(/\\textbackslash (copyright|clearpage|newpage)/,"\\\\\\1")  #kludge bad solution, find out where tail is sent through specChar !
+      str
+    end
+    def special_characters                                                   # special characters - some substitutions are sequence sensitive, rearrange with care
+      str,is=@txt,@is
+      str=xetex_special_characters_1(str,is) unless str.nil?
+      str=special_characters_unsafe_1(str) unless str.nil? #xetex_special_characters_unsafe_1(@txt)
+      str=xetex_special_characters_2(str,is) unless str.nil? #issues with xetex
+      str=xetex_special_characters_3(str) unless str.nil?
+      @txt=str
+    end
+    def special_word_break_points
+      str=@txt
+      str=str.gsub(/([_,.;:\/|=])/,'\1\-').
+        gsub(/(--)(\S{4,})/,'\1\-\2')
+      @txt=str
+    end
+    def special_number_break_points
+      str=@txt
+      str=str.gsub(/([0-9a-f]{8})/i,'\1\-')
+      @txt=str
+    end
+    def special_characters_safe                                              # special characters - some substitutions are sequence sensitive, rearrange with care
+      str,is=@txt,@is
+      str=xetex_special_characters_1(str,is) unless str.nil?
+      str=xetex_special_characters_2(str,is) unless str.nil?                 # remove this to start with, causes issues
+      str=special_characters_safe_close(str) unless str.nil?
+      @txt=str
+    end
+    def special_characters_safe_no_urls
+      str,is=@txt,:no_urls
+      str=xetex_special_characters_1(str,is) unless str.nil?
+      str=xetex_special_characters_2(str,is) unless str.nil? # remove this to start with, causes issues
+      str=special_characters_safe_close(str) unless str.nil?
+      @txt=str
+    end
+    def characters_code_listings                                             # special characters - some substitutions are sequence sensitive, rearrange with care
+      str,is=@txt,@is
+      str=xetex_code_listings(str,is) unless str.nil?
+      @txt=str
+    end
+    def special_characters_code
+      str=@txt
+      str=str.gsub(/ \\\\([ #{Mx[:br_nl]}]+|$)/,' \textbackslash\textbackslash\hardspace\1')
+      str
+    end
+  end
+  class UseTeX
+    include SiSU_Parts_TeXpdf
+    attr_accessor :url,:txt,:date
+    def initialize(md)
+      @md=md
+      @date=SiSU_Env::InfoDate.new # #{@date.year}
+      @copymark='{\\begin{footnotesize}\\raisebox{1ex}{\\copyright}\\end{footnotesize}}'
+    end
+    def skip
+      "\n\\vspace*{\\smallskipamount} \n"
+    end
+    def paraskip_normal
+      '\setlength{\parskip}{1ex plus0.5ex minus0.2ex}'
+    end
+    def paraskip_small
+      '\setlength{\parskip}{0.5ex plus0.2ex minus0.1ex}'
+    end
+    def paraskip_tiny
+      '\setlength{\parskip}{0.1ex plus0.1ex minus0.1ex}'
+    end
+    def skip_small
+      "\\smallskip{}"
+    end
+    def skip_small_vspace
+      "\n\\vspace*{\\smallskipamount} \n"
+    end
+    def skip_small_footnote
+    end
+    def skip_medium
+      "\n\\medskip{}\n\n"
+    end
+    def skip_dummy
+      "\n"
+    end
+    def header
+      "\\lhead[ ]{ }\n" +
+      "\\chead[ \\fancyplain{} \\bfseries \\footnotesize \\leftmark ]{ \\fancyplain{} \\bfseries \\footnotesize \\rightmark }\n" +
+      "\\rhead[ ]{ }\n"
+    end
+    def footer
+      "\\lfoot[\\textrm{\\thepage}]{\\tiny \\href{#{@md.footer_links[:left][:url]}}{#{@md.footer_links[:left][:say]}}}\n" +
+      "\\cfoot{\\href{#{@md.footer_links[:center][:url]}}{#{@md.footer_links[:center][:say]}}}\n" +
+      "\\rfoot[\\tiny \\href{}{}]{\\textrm{\\thepage}}\n"
+    end
+    def site
+      if not the_url.home.empty? \
+      and not the_url.home_txt.empty?
+        "\n\\date{\\begin{tiny} \\end{tiny}}"
+      else ''
+      end
+    end
+    def owner_chapter
+      "Contact Details for Original Promulgating Authority"
+    end
+    #BOOK standard dimensions - 229x156
+    def newpage(orientation)
+      case orientation
+      when :landscape # using longtable latex package
+        <<-WOK
+\\clearpage
+        WOK
+      when :portrait
+        <<-WOK
+\\newpage
+        WOK
+      end
+    end
+    def sisu_rights
+      v=SiSU_Env::InfoVersion.instance.get_version
+      base_prog_txt=if @md.base_program
+        case @md.base_program
+        when /kdissert/i then "\n\\\\ This document prepared using \\href{http://freehackers.org/~tnagy/kdissert/}{Kdissert \\ http://freehackers.org/~tnagy/kdissert/ } \\\\ Kdissert is Document Mapping software by Thomas Nagy"
+        else ''
+        end
+      else ''
+      end
+      <<-WOK
+\\\\ ~
+{\\begin{footnotesize}#{base_prog_txt}
+\\\\ Generated by \\href{http://www.jus.uio.no/sisu}{SiSU} \\begin{tiny}[ #{v.project} #{v.version} of #{v.date_stamp} ]\\end{tiny} \\href{http://www.jus.uio.no/sisu}{www.jus.uio.no/sisu}
+\\\\ Copyright #{@copymark} 1997, current #{@date.year_static} Ralph Amissah, All Rights Reserved.
+\\\\ SiSU is software for document structuring, publishing and search (with object citation numbering), \\href{http://www.sisudoc.org}{www.sisudoc.org}
+\\\\ SiSU is released under \\href{http://www.fsf.org/licenses/gpl.html}{GPL 3 } or later, #{url_brace.tex_open}\\href{http://www.fsf.org/licenses/gpl.html}{http://www.fsf.org/licenses/gpl.html}#{url_brace.tex_close}.
+{\\end{footnotesize}
+\\\\
+      WOK
+    end
+    def doc_sc_info_footnote_full
+      <<-WOK
+\\footnote{%\nGenerated by \\href{http://www.jus.uio.no/sisu}{SiSU \\ www.jus.uio.no/sisu }\\ \\newline \\scriptsize{Document version information: \\emph{sourcefile} \\uline{#{@md.fnstex}}; \\emph{version} \\uline{#{@md.sc_number}}; \\emph{date} \\uline{#{@md.sc_date}}; \\emph{time} \\uline{#{@md.sc_time}}}}
+      WOK
+    end
+    def doc_sc_info_footnote_brief
+      " \\footnote{%\nGenerated by \\href{http://www.jus.uio.no/sisu}{SiSU} \\ \\href{http://www.jus.uio.no/sisu}{www.jus.uio.no/sisu} \\newline \\href{http://www.sisudoc.org}{www.sisudoc.org} \\\n}"
+    end
+    def doc_sc_info
+      v=SiSU_Env::InfoVersion.instance.get_version
+      <<-WOK
+\\\\
+{\\begin{footnotesize}
+Document version information: \\\\
+\\emph{sourcefile} \\uline{#{@md.fnstex}}; \\emph{version} \\uline{#{@md.sc_number}}; \\emph{date} \\uline{#{@md.sc_date}}; \\emph{time} \\uline{#{@md.sc_time}} \\\\
+Generated by \\href{http://www.jus.uio.no/sisu}{SiSU www.jus.uio.no/sisu }\\- version information: \\\\
+\\uline{ #{v.project} #{v.version} of #{v.date_stamp}}
+\\end{footnotesize}}&
+      WOK
+    end
+    def doc_no_sc_info
+      v=SiSU_Env::InfoVersion.instance.get_version
+      <<-WOK
+\\\\
+{\\begin{small}
+Document information: \\\\
+\\emph{sourcefile} \\uline{#{@md.fnstex}} \\\\
+Generated by \\href{http://www.jus.uio.no/sisu}{SiSU www.jus.uio.no/sisu } \\\\ version information: \\
+\\uline{ #{v.project} #{v.version} of #{v.date_stamp}}
+
+\\end{small}}&
+      WOK
+    end
+    def endnotes #not used should be inserted before MetaData section which preceeds doc_tail, but is "part of document"
+      <<-WOK
+\\subsection*{Endnotes}
+\\addcontentsline{toc}{section}{Endnotes}
+\\
+\\listofendnotes
+      WOK
+    end
+  end
+end
+__END__
+ag usepackage texpdf*
+ag usepackage texpdf* | ag '\{.+?\}'
+# texpdf_format.rb
+ag usepackage texpdf* | ag --only-matching '\{.+?\}'
+
+,* sort & make unique
+@tex2pdf
+alltt.sty
+amssymb.sty
+babel.sty
+boites.sty
+breakurl.sty
+color.sty
+endnotes.sty
+fancyhdr.sty
+fontspec.sty
+footmisc.sty
+graphicx.sty
+inputenc.sty
+listings.sty
+longtable.sty
+manyfoot.sty
+mathptmx.sty
+multicol.sty
+parskip.sty
+polyglossia.sty
+soul.sty
+textcomp.sty
+thumbpdf.sty
+titlepic.sty
+ucs.sty
+ulem.sty
+url.sty
+xeCJK.sty
+xltxtra.sty
+xunicode.sty
+
+,* debian related
+,** found in
+
+alltt.sty
+  texlive-latex-base: /usr/share/texlive/texmf-dist/tex/latex/base/alltt.sty
+amssymb.sty
+  texlive-base: /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amssymb.sty
+babel.sty
+  texlive-latex-base: /usr/share/texlive/texmf-dist/tex/generic/babel/babel.sty
+boites.sty
+  texlive-latex-extra: /usr/share/texlive/texmf-dist/tex/latex/boites/boites.sty
+breakurl.sty
+  texlive-latex-extra: /usr/share/texlive/texmf-dist/tex/latex/breakurl/breakurl.sty
+color.sty
+  texlive-latex-base: /usr/share/texlive/texmf-dist/tex/latex/graphics/color.sty
+endnotes.sty
+  texlive-latex-extra: /usr/share/texlive/texmf-dist/tex/latex/endnotes/endnotes.sty
+fancyhdr.sty
+  texlive-latex-base: /usr/share/texlive/texmf-dist/tex/latex/fancyhdr/fancyhdr.sty
+fontspec.sty
+  texlive-latex-recommended: /usr/share/texlive/texmf-dist/tex/latex/fontspec/fontspec.sty
+footmisc.sty
+  texlive-latex-extra: /usr/share/texlive/texmf-dist/tex/latex/footmisc/footmisc.sty
+graphicx.sty
+  texlive-latex-base: /usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty
+inputenc.sty
+  texlive-latex-base: /usr/share/texlive/texmf-dist/tex/latex/base/inputenc.sty
+listings.sty
+  texlive-latex-recommended: /usr/share/texlive/texmf-dist/tex/latex/listings/listings.sty
+longtable.sty
+  texlive-latex-base: /usr/share/texlive/texmf-dist/tex/latex/tools/longtable.sty
+manyfoot.sty
+  texlive-latex-extra: /usr/share/texlive/texmf-dist/tex/latex/ncctools/manyfoot.sty
+mathptmx.sty
+  texlive-font-utils: /usr/share/doc/texlive-doc/fonts/fontinst/examples/mathptmx/mathptmx.sty
+  texlive-latex-base: /usr/share/texlive/texmf-dist/tex/latex/psnfss/mathptmx.sty
+multicol.sty
+  ptex-jtex: /usr/share/texmf/ajtex/multicol.sty
+  texlive-latex-base: /usr/share/texlive/texmf-dist/tex/latex/tools/multicol.sty
+parskip.sty
+  texlive-latex-recommended: /usr/share/texlive/texmf-dist/tex/latex/parskip/parskip.sty
+polyglossia.sty
+  texlive-latex-recommended: /usr/share/texlive/texmf-dist/tex/latex/polyglossia/polyglossia.sty
+soul.sty
+  texlive-latex-extra: /usr/share/texlive/texmf-dist/tex/latex/soul/soul.sty
+textcomp.sty
+  texlive-latex-base: /usr/share/texlive/texmf-dist/tex/latex/base/textcomp.sty
+thumbpdf.sty
+  texlive-latex-recommended: /usr/share/texlive/texmf-dist/tex/generic/thumbpdf/thumbpdf.sty
+titlepic.sty
+  texlive-latex-extra: /usr/share/texlive/texmf-dist/tex/latex/titlepic/titlepic.sty
+ucs.sty
+  texlive-latex-extra: /usr/share/texlive/texmf-dist/tex/latex/ucs/ucs.sty
+ulem.sty
+  texlive-plain-generic: /usr/share/texlive/texmf-dist/tex/generic/ulem/ulem.sty
+url.sty
+  texlive-latex-base: /usr/share/texlive/texmf-dist/tex/latex/url/url.sty
+xeCJK.sty
+  texlive-xetex: /usr/share/texlive/texmf-dist/tex/xelatex/xecjk/xeCJK.sty
+xltxtra.sty
+  texlive-latex-recommended: /usr/share/texlive/texmf-dist/tex/latex/xltxtra/xltxtra.sty
+xunicode.sty
+  texlive-latex-recommended: /usr/share/texlive/texmf-dist/tex/xelatex/xunicode/xunicode.sty
+
+,** belongs to
+
+texlive-base:
+  amssymb.sty
+texlive-latex-base:
+  alltt.sty
+  babel.sty
+  color.sty
+  fancyhdr.sty
+  graphicx.sty
+  inputenc.sty
+  longtable.sty
+  mathptmx.sty
+  multicol.sty
+  textcomp.sty
+  url.sty
+texlive-latex-extra:
+  boites.sty
+  breakurl.sty
+  endnotes.sty
+  footmisc.sty
+  manyfoot.sty
+  soul.sty
+  titlepic.sty
+  ucs.sty
+texlive-latex-recommended:
+  fontspec.sty
+  listings.sty
+  parskip.sty
+  polyglossia.sty
+  thumbpdf.sty
+  xltxtra.sty
+  xunicode.sty
+texlive-plain-generic:
+  ulem.sty
+texlive-xetex:
+  xeCJK.sty
+
+,** all texlive packages used
+
+texlive-base
+texlive-latex-base
+texlive-latex-extra
+texlive-latex-recommended
+texlive-plain-generic
+texlive-xetex
+
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    texpdf
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/txt.org b/org/txt.org
new file mode 100644
index 00000000..e7fb6a7c
--- /dev/null
+++ b/org/txt.org
@@ -0,0 +1,3205 @@
+-*- mode: org -*-
+#+TITLE:       sisu txt
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:txt:
+#+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
+
+* types
+** asciidoc
+*** txt_asciidoc.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/txt_asciidoc.rb"
+# <<sisu_document_header>>
+module SiSU_Txt_AsciiDoc
+  require_relative 'ao'                                 # ao.rb
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'shared_metadata'                    # shared_metadata.rb
+  require_relative 'generic_parts'                      # generic_parts.rb
+  require_relative 'txt_read'                           # txt_read.rb
+  require_relative 'txt_shared'                         # txt_shared.rb
+  require_relative 'txt_asciidoc_decorate'              # txt_decorate.rb
+  require_relative 'txt_output'                         # txt_output.rb
+  include SiSU_Param
+  @@alt_id_count,@@alt_id_count=0,0
+  @@tablefoot=''
+  class Source
+    include SiSU_Txt_Read
+    def initialize(opt)
+      @opt=opt
+      unless @opt.fns =~/(.+?)\.(?:-|ssm\.)?sst$/
+        puts "#{sf} not a processed file type"
+      end
+    end
+    def read
+      begin
+        md=SiSU_Param::Parameters.new(@opt).get
+        specific={
+          description:     'AsciiDoc (plaintext utf-8)',
+          output_path:     md.file.output_path.asciidoc.dir,
+          output_file:     md.file.base_filename.asciidoc,
+        }
+        read_generic(@opt,specific)
+        SiSU_Txt_AsciiDoc::Source::Scroll.new(md,@ao_array,@wrap_width).songsheet
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    private
+    class Scroll <Source
+      include SiSU_Parts_Generic
+      include SiSU_TextUtils
+      include SiSU_Decorate_Txt_AsciiDoc
+      @@endnotes={ para: [], end: [] }
+      def initialize(md,data,wrap_width)
+        @md,@data,@wrap_width=md,data,wrap_width
+        @env=SiSU_Env::InfoEnv.new(@md.fns)
+        @tab="\t"
+        @@endnotes_=case md.opt.selections.str
+        when /--footnote/ then false
+        when /--endnote/  then true
+        else                   true
+        end
+        @plaintext={ body: [], open: [], close: [], head: [], metadata: [], tail: [] }
+      end
+      def songsheet
+        plaintext=markup(@data)
+        publish(plaintext)
+      end
+      def break_line
+        "\n"
+      end
+      # Used for extraction of endnotes from paragraphs
+      def plaintext_metadata
+        array=SiSU_Metadata::Summary.new(@md).plaintext.metadata
+        array.each do |meta|
+          tag,inf=meta.scan(/^.+?:\s|.+/)
+          if tag and inf
+            util=SiSU_TextUtils::Wrap.new(inf,@wrap_width,15,1)
+            txt=util.line_wrap
+            @plaintext[:metadata] <<<<WOK
+
+#{@tab}#{tag}#{txt}
+WOK
+          end
+        end
+      end
+      def plaintext_tail
+#       env=SiSU_Env::InfoEnv.new(@md.fns)
+        generator="Generated by: #{@md.project_details.project} #{@md.project_details.version} of #{@md.project_details.date_stamp} (#{@md.project_details.date})"  if @md.project_details.version
+        lastdone="Last Generated on: #{Time.now}"
+        rubyv="Ruby version: #{@md.ruby_version}"
+        sc=if @md.sc_info
+          "Source file:    #{@md.sc_filename}#{break_line}Version number: #{@md.sc_number}#{break_line}Version date:   #{@md.sc_date}#{break_line}"
+        else ''
+        end
+        @plaintext[:tail] <<<<WOK
+#{break_line}
+plaintext (plain text):
+   #{@md.file.output_path.asciidoc.url}/#{@md.file.base_filename.asciidoc}#{break_line}
+Other versions of this document: #{break_line}
+manifest:
+   #{@md.file.output_path.manifest.url}/#{@md.file.base_filename.manifest}#{break_line}
+at:
+   #{@md.file.output_path.base.url}#{break_line}
+
+#{sc}
+,* #{generator}
+,* #{rubyv}
+,* #{lastdone}
+,* SiSU #{the_url.sisu_txt}
+WOK
+      end
+      def heading_decorated_inline(dob)
+        if dob.is==:heading
+          heading_inline = case dob.lc
+          when 0 then decorate.heading.inline.l0
+          when 1 then decorate.heading.inline.l1
+          when 2 then decorate.heading.inline.l2
+          when 3 then decorate.heading.inline.l3
+          when 4 then decorate.heading.inline.l4
+          when 5 then decorate.heading.inline.l5
+          when 6 then decorate.heading.inline.l6
+          end
+          heading_inline + ' ' +  dob.obj + ' ' + heading_inline
+        end
+      end
+      def heading_decorated_underscore(dob,times,p_num)
+        if dob.is==:heading
+          #times=@wrap_width if times > @wrap_width
+          case dob.lc
+          when 0 then decorate.heading.underscore.l0*times + p_num << break_line*2
+          when 1 then decorate.heading.underscore.l1*times + p_num << break_line*2
+          when 2 then decorate.heading.underscore.l2*times + p_num << break_line*2
+          when 3 then decorate.heading.underscore.l3*times + p_num << break_line*2
+          when 4 then decorate.heading.underscore.l4*times + p_num << break_line*2
+          when 5 then decorate.heading.underscore.l5*times + p_num << break_line*2
+          when 6 then decorate.heading.underscore.l6*times + p_num << break_line*2
+          end
+        end
+      end
+      def plaintext_structure(dob='',p_num='') #% Used to extract the structure of a document
+        heading_decoration=:inline #(:inline|:underscore) #switch heading decoration between inline & underscore options
+        util=nil
+        wrapped=if dob.is==:para \
+        || dob.is==:heading
+          if dob.is==:heading
+            util=(heading_decoration== :inline) \
+            ? (SiSU_TextUtils::Wrap.new(heading_decorated_inline(dob),@wrap_width,0))
+            : (SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,0))
+          elsif dob.is==:para
+            if dob.hang \
+            and dob.hang =~/[0-9]/ \
+            and dob.indent != dob.hang
+              util=SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,dob.indent.to_i*2,dob.hang.to_i*2)
+              #util=SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,dob.hang.to_i*2,0)
+            elsif dob.indent =~/[1-9]/
+              util=if dob.bullet_
+                SiSU_TextUtils::Wrap.new("* #{dob.obj}",@wrap_width,dob.indent.to_i*2)
+              else SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,dob.indent.to_i*2)
+              end
+            else
+              util=if dob.bullet_
+                SiSU_TextUtils::Wrap.new("* #{dob.obj}",@wrap_width,0)
+              else SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,0)
+              end
+            end
+          else util=SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,0)
+          end
+          dob.is==:heading ? util.no_wrap_no_breaks : util.line_wrap
+        end
+        if heading_decoration== :underscore \
+        and dob.is==:heading
+          @plaintext[:body] << wrapped + p_num # main text, contents, body KEEP
+          @plaintext[:body] << heading_decorated_underscore(dob,wrapped.length,p_num)
+        else
+          @plaintext[:body] << wrapped + p_num << break_line # main text, contents, body KEEP
+        end
+        if @@endnotes[:para] \
+        and not @@endnotes_
+          @@endnotes[:para].each {|e| @plaintext[:body] << e << break_line}
+        elsif @@endnotes[:para] \
+        and @@endnotes_
+        end
+        @@endnotes[:para]=[]
+      end
+      def markup(data)                                                       # Used for major markup instructions
+        SiSU_Env::InfoEnv.new(@md.fns)
+        @data_mod,@endnotes,@level,@cont,@copen,@plaintext_contents_close=Array.new(6){[]}
+        (0..6).each { |x| @cont[x]=@level[x]=false }
+        (4..6).each { |x| @plaintext_contents_close[x]='' }
+        plaintext_tail #($1,$2)
+        plaintext_metadata
+        table_message='[table conversion awaited, see other document formats]'
+        data.each do |dob|
+          dob.obj=dob.obj.gsub(/#{Mx[:gr_o]}Th?#{Mx[:tc_p]}.+/um,"#{break_line}#{table_message}"). #fix
+            gsub(/.+?#{Mx[:gl_o]}-##{Mx[:gl_c]}/,'').                              # remove dummy headings (used by html) #check also [~-]#
+            gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,
+              "#{decorate.bold.open}\\1#{decorate.bold.close}").
+            gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,
+              "#{decorate.italics.open}\\1#{decorate.italics.close}").
+            gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,
+              "#{decorate.underscore.open}\\1#{decorate.underscore.close}").
+            gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,
+              "#{decorate.subscript.open}\\1#{decorate.subscript.close}").
+            gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,
+              "#{decorate.superscript.open}\\1#{decorate.superscript.close}").
+            gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,
+              "#{decorate.insert.open}\\1#{decorate.insert.close}").
+            gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,
+              "#{decorate.cite.open}\\1#{decorate.cite.close}").
+            gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,
+              "#{decorate.strike.open}\\1#{decorate.strike.close}").
+            gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,
+              "#{decorate.monospace.open}\\1#{decorate.monospace.close}")
+          unless dob.is==:code
+            dob.obj=dob.obj.gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}/,'\1').
+              gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,'\1').
+              gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,'\1 [link: <\2>]').
+              gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}image/,'\1 [link: local image]').
+              gsub(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,"#{the_text.url_open}\\1#{the_text.url_close}")
+            dob.obj=dob.obj.gsub(/\s*#{Mx[:en_a_o]}([\d*+]+)\s+(.+?)#{Mx[:en_a_c]}/,' footnote:[note\1,\2]').
+              gsub(/\s*#{Mx[:en_b_o]}([\d*+]+\s+.+?)#{Mx[:en_b_c]}/,' footnote:[\1]')
+            dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'[^\1]'). # endnote marker marked up
+              gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'[^\1]'). # endnote marker marked up
+              gsub(/#{Mx[:gl_o]}(?:#lt|#060)#{Mx[:gl_c]}/,'<').
+              gsub(/#{Mx[:gl_o]}(?:#gt|#062)#{Mx[:gl_c]}/,'>').
+              gsub(/#{Mx[:gl_o]}#(?:038|amp)#{Mx[:gl_c]}/,'&').
+              gsub(/#{Mx[:gl_o]}#033#{Mx[:gl_c]}/,'!').
+              gsub(/#{Mx[:gl_o]}#035#{Mx[:gl_c]}/,'#').
+              gsub(/#{Mx[:gl_o]}#042#{Mx[:gl_c]}/,'*').
+              gsub(/#{Mx[:gl_o]}#045#{Mx[:gl_c]}/,'-').
+              gsub(/#{Mx[:gl_o]}#047#{Mx[:gl_c]}/,'/').
+              gsub(/#{Mx[:gl_o]}#095#{Mx[:gl_c]}/,'_').
+              gsub(/#{Mx[:gl_o]}#123#{Mx[:gl_c]}/,'{').
+              gsub(/#{Mx[:gl_o]}#125#{Mx[:gl_c]}/,'}').
+              gsub(/#{Mx[:gl_o]}#126#{Mx[:gl_c]}/,'~').
+              gsub(/#{Mx[:gl_o]}#169#{Mx[:gl_c]}/,'©').
+              gsub(/#{Mx[:gl_o]}#092#{Mx[:gl_c]}/,'\\')
+          end
+          dob.obj=if dob.of==:block                                   # watch
+            dob.obj.gsub(/#{Mx[:gl_o]}●#{Mx[:gl_c]}/m,"* ").
+              gsub(/\n?#{Mx[:br_line]}\n?|\n?#{Mx[:br_nl]}\n?/m,break_line)
+          else dob.obj.gsub(/\n?#{Mx[:br_line]}\n?|\n?#{Mx[:br_nl]}\n?/m,break_line*2)
+          end
+          if dob.is==:code
+            dob.obj=dob.obj.gsub(/(^|[^}])_([<>])/m,'\1\2'). # _> _<
+              gsub(/(^|[^}])_([<>])/m,'\1\2') # _<_<
+          end
+          dob.obj=dob.obj.gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,'\1').
+            gsub(/<a href=".+?">(.+?)<\/a>/m,'\1').
+            gsub(/#{Mx[:mk_o]}:name#(\S+?)#{Mx[:mk_c]}/,'').                       # remove name links
+            gsub(/&nbsp;|#{Mx[:nbsp]}/,' ').                                       # decide on
+            gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}(\S+?\.(?:png|jpg|gif)) .+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/,'    [ \1 ]'). #"[ #{dir.url.images_local}\/\\1 ]")
+            gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}(\S+?\.(?:png|jpg|gif)) .+?#{Mx[:lnk_c]}image/,'    [ \1 ]').
+            gsub(/(?:^|[^_\\])\{\s*\S+?\.(?:png|jpg|gif)\s+.+?"(.*?)"\s*\}\S+/,'[image: "\1"]')
+          if dob.obj !~/(^#{Rx[:meta]}|#{Mx[:br_eof]}|#{Mx[:br_endnotes]})/
+            p_num=''
+            #ocn
+            if dob.is==:heading \
+            or dob.is==:para
+              plaintext_structure(dob,p_num)
+            elsif dob.is==:group \
+            or dob.is==:block \
+            or dob.is==:verse \
+            or dob.is==:code \
+            or dob.is==:table
+              @plaintext[:body] << dob.obj + p_num << break_line
+            elsif dob.is==:break
+              sp=' '
+              ln='<' #ln='-'
+              @plaintext[:body] <<=if dob.obj==Mx[:br_page] \
+              or dob.obj==Mx[:br_page_new] \
+              or dob.obj==Mx[:br_page_line]
+                "#{break_line}#{ln*40}#{break_line*2}"
+              elsif dob.obj ==Mx[:br_obj]
+                "#{break_line}#{sp*20}*  *  *#{break_line*2}"
+              end # following empty line (break_line) missing, fix
+            end
+            dob='' if (dob.obj =~/<a name="n\d+">/ \
+              and dob.obj =~/^(-\{{2}~\d+|<!e[:_]\d+!>)/) # -endnote
+            if dob ## Clean Prepared Text
+              dob.obj=dob.obj.gsub(/<!.+!>/,' ').
+                gsub(/<:\S+>/,' ')
+            end
+          end
+        end
+        @plaintext
+      end
+      def publish(plaintext)
+        divider='='
+        content=[]
+        content << plaintext[:open]
+        content << plaintext[:head]
+        content << plaintext[:body]
+        content << @@endnotes[:end] if @@endnotes_
+        content << "#{break_line}#{divider*@wrap_width}#{break_line}"
+        content << plaintext[:metadata]
+        content << "#{break_line}#{divider*@wrap_width}#{break_line}" if @md.stmp =~/\w+/ #not used?
+        content << plaintext[:tail]
+        outputfile=SiSU_Env::FileOp.new(@md).write_file.asciidoc
+        Txt_Output::Output.new.document(content,outputfile)
+        @@endnotes={ para: [], end: [] }
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+*** txt_asciidoc_decorate.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/txt_asciidoc_decorate.rb"
+# <<sisu_document_header>>
+module SiSU_Decorate_Txt_AsciiDoc
+  def decorate
+    def heading
+      def inline
+        def l0
+          '='
+        end
+        def l1
+          '=='
+        end
+        def l2
+          '==='
+        end
+        def l3
+          '===='
+        end
+        def l4
+          '====='
+        end
+        def l5
+          '' #'======' #logical
+        end
+        self
+      end
+      def underscore
+        def l0
+          '='
+        end
+        def l1
+          '-'
+        end
+        def l2
+          '~'
+        end
+        def l3
+          '^'
+        end
+        def l4
+          '+'
+        end
+        def l5
+          '.' #'.' #proposed
+        end
+        self
+      end
+      self
+    end
+    def bold
+      def open
+        '*'
+      end
+      def close
+        '*'
+      end
+      self
+    end
+    def italics
+      def open
+        '_'
+      end
+      def close
+        '_'
+      end
+      self
+    end
+    def underscore
+      def open
+        ''
+      end
+      def close
+        ''
+      end
+      self
+    end
+   #def emphasis
+   #  def open
+   #    ''
+   #  end
+   #  def close
+   #    ''
+   #  end
+   #  self
+   #end
+    def cite
+      def open
+        '"'
+      end
+      def close
+        '"'
+      end
+      self
+    end
+    def insert
+      def open
+        ''
+      end
+      def close
+        ''
+      end
+      self
+    end
+    def strike
+      def open
+        '-'
+      end
+      def close
+        '-'
+      end
+      self
+    end
+    def superscript
+      def open
+        '^'
+      end
+      def close
+        '^'
+      end
+      self
+    end
+    def subscript
+      def open
+        '~'
+      end
+      def close
+        '~'
+      end
+      self
+    end
+    def hilite #bold
+      def open
+        '*'
+      end
+      def close
+        '*'
+      end
+      self
+    end
+    def monospace
+      def open
+        '+'
+      end
+      def close
+        '+'
+      end
+      self
+    end
+    self
+  end
+end
+__END__
+#+END_SRC
+
+** markdown
+*** txt_markdown.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/txt_markdown.rb"
+# <<sisu_document_header>>
+module SiSU_Txt_Markdown
+  require_relative 'ao'                                 # ao.rb
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'shared_metadata'                    # shared_metadata.rb
+  require_relative 'generic_parts'                      # generic_parts.rb
+  require_relative 'txt_read'                           # txt_read.rb
+  require_relative 'txt_shared'                         # txt_shared.rb
+  require_relative 'txt_markdown_decorate'              # txt_markdown_decorate.rb
+  require_relative 'txt_output'                         # txt_output.rb
+  include SiSU_Param
+  @@alt_id_count,@@alt_id_count=0,0
+  @@tablefoot=''
+  class Source
+    include SiSU_Txt_Read
+    def initialize(opt)
+      @opt=opt
+      unless @opt.fns =~/(.+?)\.(?:-|ssm\.)?sst$/
+        puts "#{sf} not a processed file type"
+      end
+    end
+    def read
+      begin
+        md=SiSU_Param::Parameters.new(@opt).get
+        specific={
+          description:     'Markdown (plaintext utf-8)',
+          output_path:     md.file.output_path.markdown.dir,
+          output_file:     md.file.base_filename.markdown,
+        }
+        read_generic(@opt,specific)
+        SiSU_Txt_Markdown::Source::Scroll.new(md,@ao_array,@wrap_width).songsheet
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    private
+    class Scroll <Source
+      include SiSU_Parts_Generic
+      include SiSU_TextUtils
+      include SiSU_Decorate_Txt_Markdown
+      @@endnotes={ para: [], end: [] }
+      def initialize(md,data,wrap_width)
+        @md,@data,@wrap_width=md,data,wrap_width
+        @env=SiSU_Env::InfoEnv.new(@md.fns)
+        @tab="\t"
+        @@endnotes_=case md.opt.selections.str
+        when /--footnote/ then false
+        when /--endnote/  then true
+        else                   true
+        end
+        @plaintext={ body: [], open: [], close: [], head: [], metadata: [], tail: [] }
+      end
+      def songsheet
+        plaintext=markup(@data)
+        publish(plaintext)
+      end
+      def break_line
+        "\n"
+      end
+      # Used for extraction of endnotes from paragraphs
+      def extract_endnotes(dob='')
+        notes=dob.obj.scan(/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})([\d*+]+\s+.+?)(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/)
+        @n=[]
+        notes.flatten.each do |n| #high cost to deal with <br> appropriately within plaintext, consider
+          n=n.dup.to_s
+          if n =~/#{Mx[:br_line]}|#{Mx[:br_nl]}/
+            fix = n.split(/#{Mx[:br_line]}|#{Mx[:br_nl]}/) #watch #added
+            fix.each do |x|
+              unless x.empty? then @n << x
+              end
+            end
+          else                     @n << n
+          end
+        end
+        notes=@n.flatten
+        notes.each do |e|
+          util=(e.to_s =~/^\[[\d*+]+\]:/) \
+          ? (SiSU_TextUtils::Wrap.new(e.to_s,@wrap_width,4,1))
+          : (SiSU_TextUtils::Wrap.new(e.to_s,@wrap_width,1,1))
+          wrap=util.line_wrap
+          wrap=if wrap =~ /^\s*[\d*+]+\s+.+?\s*\Z/m
+            wrap.gsub(/^(\s*)([\d*+]+)\s+(.+?)\s*\Z/m, <<-GSUB
+\\1[\\2]: \\3
+              GSUB
+            )
+          else
+            wrap.gsub(/^(.+)\Z/m, <<-GSUB
+\\1
+              GSUB
+            )
+          end
+          @@endnotes[:para] << "-#{wrap}"
+          @@endnotes[:end] << '' << wrap
+        end
+        @@endnotes
+      end
+      def plaintext_metadata
+        array=SiSU_Metadata::Summary.new(@md).plaintext.metadata
+        array.each do |meta|
+          tag,inf=meta.scan(/^.+?:\s|.+/)
+          if tag and inf
+            util=SiSU_TextUtils::Wrap.new(inf,@wrap_width,15,1)
+            txt=util.line_wrap
+            @plaintext[:metadata] <<<<WOK
+
+#{@tab}#{tag}#{txt}
+WOK
+          end
+        end
+      end
+      def plaintext_tail
+#       env=SiSU_Env::InfoEnv.new(@md.fns)
+        generator="Generated by: #{@md.project_details.project} #{@md.project_details.version} of #{@md.project_details.date_stamp} (#{@md.project_details.date})"  if @md.project_details.version
+        lastdone="Last Generated on: #{Time.now}"
+        rubyv="Ruby version: #{@md.ruby_version}"
+        sc=if @md.sc_info
+          "Source file:    #{@md.sc_filename}#{break_line}Version number: #{@md.sc_number}#{break_line}Version date:   #{@md.sc_date}#{break_line}"
+        else ''
+        end
+        @plaintext[:tail] <<<<WOK
+#{break_line}
+plaintext (plain text):
+   #{@md.file.output_path.markdown.url}/#{@md.file.base_filename.markdown}#{break_line}
+Other versions of this document: #{break_line}
+manifest:
+   #{@md.file.output_path.manifest.url}/#{@md.file.base_filename.manifest}#{break_line}
+at:
+   #{@md.file.output_path.base.url}#{break_line}
+
+#{sc}
+,* #{generator}
+,* #{rubyv}
+,* #{lastdone}
+,* SiSU #{the_url.sisu_txt}
+WOK
+      end
+      def heading_decorated_inline(dob)
+        if dob.is==:heading
+          heading_inline = case dob.lc
+          when 0 then decorate.heading.inline.l0
+          when 1 then decorate.heading.inline.l1
+          when 2 then decorate.heading.inline.l2
+          when 3 then decorate.heading.inline.l3
+          when 4 then decorate.heading.inline.l4
+          when 5 then decorate.heading.inline.l5
+          when 6 then decorate.heading.inline.l6
+          end
+          heading_inline + ' ' +  dob.obj + ' ' + heading_inline
+        end
+      end
+      def heading_decorated_underscore(dob,times,p_num)
+        if dob.is==:heading
+          #times=@wrap_width if times > @wrap_width
+          case dob.lc
+          when 0 then decorate.heading.underscore.l0*times + p_num << break_line*2
+          when 1 then decorate.heading.underscore.l1*times + p_num << break_line*2
+          when 2 then decorate.heading.underscore.l2*times + p_num << break_line*2
+          when 3 then decorate.heading.underscore.l3*times + p_num << break_line*2
+          when 4 then decorate.heading.underscore.l4*times + p_num << break_line*2
+          when 5 then decorate.heading.underscore.l5*times + p_num << break_line*2
+          when 6 then decorate.heading.underscore.l6*times + p_num << break_line*2
+          end
+        end
+      end
+      def plaintext_structure(dob='',p_num='') #% Used to extract the structure of a document
+        heading_decoration=:inline #(:inline|:underscore) #switch heading decoration between inline & underscore options
+        util=nil
+        wrapped=if dob.is==:para \
+        || dob.is==:heading
+          if dob.is==:heading
+            util=(heading_decoration== :inline) \
+            ? (SiSU_TextUtils::Wrap.new(heading_decorated_inline(dob),@wrap_width,0))
+            : (SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,0))
+          elsif dob.is==:para
+            if dob.hang \
+            and dob.hang =~/[0-9]/ \
+            and dob.indent != dob.hang
+              util=SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,dob.indent.to_i*2,dob.hang.to_i*2)
+              #util=SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,dob.hang.to_i*2,0)
+            elsif dob.indent =~/[1-9]/
+              util=if dob.bullet_
+                SiSU_TextUtils::Wrap.new("* #{dob.obj}",@wrap_width,dob.indent.to_i*2)
+              else SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,dob.indent.to_i*2)
+              end
+            else
+              util=if dob.bullet_
+                SiSU_TextUtils::Wrap.new("* #{dob.obj}",@wrap_width,0)
+              else SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,0)
+              end
+            end
+          else util=SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,0)
+          end
+          dob.is==:heading ? util.no_wrap_no_breaks : util.line_wrap
+        end
+        if heading_decoration== :underscore \
+        and dob.is==:heading
+          @plaintext[:body] << wrapped + p_num # main text, contents, body KEEP
+          @plaintext[:body] << heading_decorated_underscore(dob,wrapped.length,p_num)
+        else
+          @plaintext[:body] << wrapped + p_num << break_line # main text, contents, body KEEP
+        end
+        if @@endnotes[:para] \
+        and not @@endnotes_
+          @@endnotes[:para].each {|e| @plaintext[:body] << e << break_line}
+        elsif @@endnotes[:para] \
+        and @@endnotes_
+        end
+        @@endnotes[:para]=[]
+      end
+      def markup(data)                                                       # Used for major markup instructions
+        SiSU_Env::InfoEnv.new(@md.fns)
+        @data_mod,@endnotes,@level,@cont,@copen,@plaintext_contents_close=Array.new(6){[]}
+        (0..6).each { |x| @cont[x]=@level[x]=false }
+        (4..6).each { |x| @plaintext_contents_close[x]='' }
+        plaintext_tail #($1,$2)
+        plaintext_metadata
+        table_message='[table conversion awaited, see other document formats]'
+        data.each do |dob|
+          dob.obj=dob.obj.gsub(/#{Mx[:gr_o]}Th?#{Mx[:tc_p]}.+/um,"#{break_line}#{table_message}"). #fix
+            gsub(/.+?#{Mx[:gl_o]}-##{Mx[:gl_c]}/,'').                              # remove dummy headings (used by html) #check also [~-]#
+            gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,
+              "#{decorate.bold.open}\\1#{decorate.bold.close}").
+            gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,
+              "#{decorate.italics.open}\\1#{decorate.italics.close}").
+            gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,
+              "#{decorate.underscore.open}\\1#{decorate.underscore.close}").
+            gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,
+              "#{decorate.subscript.open}\\1#{decorate.subscript.close}").
+            gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,
+              "#{decorate.superscript.open}\\1#{decorate.superscript.close}").
+            gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,
+              "#{decorate.insert.open}\\1#{decorate.insert.close}").
+            gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,
+              "#{decorate.cite.open}\\1#{decorate.cite.close}").
+            gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,
+              "#{decorate.strike.open}\\1#{decorate.strike.close}").
+            gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,
+              "#{decorate.monospace.open}\\1#{decorate.monospace.close}")
+          unless dob.is==:code
+            dob.obj=dob.obj.gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}/,'\1').
+              gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,'\1').
+              gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,'\1 [link: <\2>]').
+              gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}image/,'\1 [link: local image]').
+              gsub(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,"#{the_text.url_open}\\1#{the_text.url_close}")
+            extract_endnotes(dob)
+            dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'[^\1]'). # endnote marker marked up
+              gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'[^\1]'). # endnote marker marked up
+              gsub(/#{Mx[:gl_o]}(?:#lt|#060)#{Mx[:gl_c]}/,'<').
+              gsub(/#{Mx[:gl_o]}(?:#gt|#062)#{Mx[:gl_c]}/,'>').
+              gsub(/#{Mx[:gl_o]}#(?:038|amp)#{Mx[:gl_c]}/,'&').
+              gsub(/#{Mx[:gl_o]}#033#{Mx[:gl_c]}/,'!').
+              gsub(/#{Mx[:gl_o]}#035#{Mx[:gl_c]}/,'#').
+              gsub(/#{Mx[:gl_o]}#042#{Mx[:gl_c]}/,'*').
+              gsub(/#{Mx[:gl_o]}#045#{Mx[:gl_c]}/,'-').
+              gsub(/#{Mx[:gl_o]}#047#{Mx[:gl_c]}/,'/').
+              gsub(/#{Mx[:gl_o]}#095#{Mx[:gl_c]}/,'_').
+              gsub(/#{Mx[:gl_o]}#123#{Mx[:gl_c]}/,'{').
+              gsub(/#{Mx[:gl_o]}#125#{Mx[:gl_c]}/,'}').
+              gsub(/#{Mx[:gl_o]}#126#{Mx[:gl_c]}/,'~').
+              gsub(/#{Mx[:gl_o]}#169#{Mx[:gl_c]}/,'©').
+              gsub(/#{Mx[:gl_o]}#092#{Mx[:gl_c]}/,'\\')
+          end
+          dob.obj=if dob.of==:block                                   # watch
+            dob.obj.gsub(/#{Mx[:gl_o]}●#{Mx[:gl_c]}/m,"* ").
+              gsub(/\n?#{Mx[:br_line]}\n?|\n?#{Mx[:br_nl]}\n?/m,break_line)
+          else dob.obj.gsub(/\n?#{Mx[:br_line]}\n?|\n?#{Mx[:br_nl]}\n?/m,break_line*2)
+          end
+          if dob.is==:code
+            dob.obj=dob.obj.gsub(/(^|[^}])_([<>])/m,'\1\2'). # _> _<
+              gsub(/(^|[^}])_([<>])/m,'\1\2') # _<_<
+          end
+          dob.obj=dob.obj.gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,'\1').
+            gsub(/<a href=".+?">(.+?)<\/a>/m,'\1').
+            gsub(/#{Mx[:mk_o]}:name#(\S+?)#{Mx[:mk_c]}/,'').                       # remove name links
+            gsub(/&nbsp;|#{Mx[:nbsp]}/,' ').                                       # decide on
+            gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}(\S+?\.(?:png|jpg|gif)) .+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/,'    [ \1 ]'). #"[ #{dir.url.images_local}\/\\1 ]")
+            gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}(\S+?\.(?:png|jpg|gif)) .+?#{Mx[:lnk_c]}image/,'    [ \1 ]').
+            gsub(/(?:^|[^_\\])\{\s*\S+?\.(?:png|jpg|gif)\s+.+?"(.*?)"\s*\}\S+/,'[image: "\1"]')
+          if dob.obj !~/(^#{Rx[:meta]}|#{Mx[:br_eof]}|#{Mx[:br_endnotes]})/
+            p_num=''
+            #ocn
+            if dob.is==:heading \
+            or dob.is==:para
+              plaintext_structure(dob,p_num)
+            elsif dob.is==:group \
+            or dob.is==:block \
+            or dob.is==:verse \
+            or dob.is==:code \
+            or dob.is==:table
+              @plaintext[:body] << dob.obj + p_num << break_line
+            elsif dob.is==:break
+              sp=' '
+              ln='-'
+              @plaintext[:body] <<=if dob.obj==Mx[:br_page] \
+              or dob.obj==Mx[:br_page_new] \
+              or dob.obj==Mx[:br_page_line]
+                "#{break_line}#{ln*40}#{break_line*2}"
+              elsif dob.obj ==Mx[:br_obj]
+                "#{break_line}#{sp*20}*  *  *#{break_line*2}"
+              end # following empty line (break_line) missing, fix
+            end
+            dob='' if (dob.obj =~/<a name="n\d+">/ \
+              and dob.obj =~/^(-\{{2}~\d+|<!e[:_]\d+!>)/) # -endnote
+            if dob ## Clean Prepared Text
+              dob.obj=dob.obj.gsub(/<!.+!>/,' ').
+                gsub(/<:\S+>/,' ')
+            end
+          end
+        end
+        @plaintext
+      end
+      def publish(plaintext)
+        divider='='
+        content=[]
+        content << plaintext[:open]
+        content << plaintext[:head]
+        content << plaintext[:body]
+        content << @@endnotes[:end] if @@endnotes_
+        content << "#{break_line}#{divider*@wrap_width}#{break_line}"
+        content << plaintext[:metadata]
+        content << "#{break_line}#{divider*@wrap_width}#{break_line}" if @md.stmp =~/\w+/ #not used?
+        content << plaintext[:tail]
+        outputfile=SiSU_Env::FileOp.new(@md).write_file.markdown
+        Txt_Output::Output.new.document(content,outputfile)
+        @@endnotes={ para: [], end: [] }
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+*** txt_markdown_decorate.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/txt_markdown_decorate.rb"
+# <<sisu_document_header>>
+module SiSU_Decorate_Txt_Markdown
+  def decorate
+    def heading
+      def inline                   #atx
+        def l0
+          '#'
+        end
+        def l1
+          '##'
+        end
+        def l2
+          '###'
+        end
+        def l3
+          '####'
+        end
+        def l4
+          '#####'
+        end
+        def l5
+          '######'
+        end
+        self
+      end
+      def underscore               #Setext
+        def l1
+          '='
+        end
+        def l2
+          '-'
+        end
+        def l3
+          ''
+        end
+        def l4
+          ''
+        end
+        def l5
+          ''
+        end
+        def l6
+          ''
+        end
+        self
+      end
+      self
+    end
+    def bold
+      def open
+        '**'
+      end
+      def close
+        '**'
+      end
+      self
+    end
+    def italics
+      def open
+        '*'
+      end
+      def close
+        '*'
+      end
+      self
+    end
+    def underscore
+      def open
+        '_'
+      end
+      def close
+        '_'
+      end
+      self
+    end
+   #def emphasis
+   #  def open
+   #    ''
+   #  end
+   #  def close
+   #    ''
+   #  end
+   #  self
+   #end
+    def cite
+      def open
+        '"'
+      end
+      def close
+        '"'
+      end
+      self
+    end
+    def insert
+      def open
+        '+'
+      end
+      def close
+        '+'
+      end
+      self
+    end
+    def strike
+      def open
+        '-'
+      end
+      def close
+        '-'
+      end
+      self
+    end
+    def superscript
+      def open
+        '^'
+      end
+      def close
+        '^'
+      end
+      self
+    end
+    def subscript
+      def open
+        '['
+      end
+      def close
+        ']'
+      end
+      self
+    end
+    def hilite
+      def open
+        '**'
+      end
+      def close
+        '**'
+      end
+      self
+    end
+    def monospace
+      def open
+        '`'
+      end
+      def close
+        '`'
+      end
+      self
+    end
+    self
+  end
+end
+__END__
+#+END_SRC
+
+** orgmode
+*** txt_orgmode.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/txt_orgmode.rb"
+# <<sisu_document_header>>
+module SiSU_Txt_OrgMode
+  require_relative 'ao'                                 # ao.rb
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'shared_metadata'                    # shared_metadata.rb
+  require_relative 'generic_parts'                      # generic_parts.rb
+  require_relative 'txt_read'                           # txt_read.rb
+  require_relative 'txt_shared'                         # txt_shared.rb
+  require_relative 'txt_orgmode_decorate'               # txt_orgmode_decorate.rb
+  require_relative 'txt_output'                         # txt_output.rb
+  include SiSU_Param
+  @@alt_id_count,@@alt_id_count=0,0
+  @@tablefoot=''
+  class Source
+    include SiSU_Txt_Read
+    def initialize(opt)
+      @opt=opt
+      unless @opt.fns =~/(.+?)\.(?:-|ssm\.)?sst$/
+        puts "#{sf} not a processed file type"
+      end
+    end
+    def read
+      begin
+        md=SiSU_Param::Parameters.new(@opt).get
+        specific={
+          description:     'OrgMode (plaintext utf-8)',
+          output_path:     md.file.output_path.orgmode.dir,
+          output_file:     md.file.base_filename.orgmode,
+        }
+        read_generic(@opt,specific)
+        SiSU_Txt_OrgMode::Source::Scroll.new(md,@ao_array,@wrap_width).songsheet
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    private
+    class Scroll <Source
+      include SiSU_Parts_Generic
+      include SiSU_TextUtils
+      include SiSU_Decorate_Txt_OrgMode
+      @@endnotes={ para: [], end: [] }
+      def initialize(md,data,wrap_width)
+        @md,@data,@wrap_width=md,data,wrap_width
+        @env=SiSU_Env::InfoEnv.new(@md.fns)
+        @tab="\t"
+        @@endnotes_=case md.opt.selections.str
+        when /--footnote/ then false
+        when /--endnote/  then true
+        else                   true
+        end
+        @plaintext={ body: [], open: [], close: [], head: [], endnotes: [], metadata: [], tail: [] }
+        @plaintext[:head]= <<-WOK
+#+TITLE: #{@md.title.short}
+#+AUTHOR: #{@md.creator.author}
+#+EMAIL: #{@md.creator.email}
+#+STARTUP: indent content
+#+LANGUAGE: #{@md.opt.lng}
+#+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
+#+EXPORT_SELECT_TAGS: export
+#+EXPORT_EXCLUDE_TAGS: noexport
+
+        WOK
+      end
+      def songsheet
+        plaintext=markup(@data)
+        publish(plaintext)
+      end
+      def break_line
+        "\n"
+      end
+      def extract_endnotes(dob='')
+        notes=dob.obj.
+          scan(/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})([\d*+]+\s+.+?)(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/)
+        @n=[]
+        notes.flatten.each do |n| #high cost to deal with <br> appropriately within plaintext, consider
+          n=n.dup.to_s
+          if n =~/#{Mx[:br_line]}|#{Mx[:br_nl]}/
+            fix = n.split(/#{Mx[:br_line]}|#{Mx[:br_nl]}/) #watch #added
+            fix.each do |x|
+              unless x.empty? then @n << x
+              end
+            end
+          else                     @n << n
+          end
+        end
+        notes=@n.flatten
+        notes.each do |e|
+          util=(e.to_s =~/^\[[\d*+]+\]:/) \
+          ? (SiSU_TextUtils::Wrap.new(e.to_s,@wrap_width,4,1))
+          : (SiSU_TextUtils::Wrap.new(e.to_s,@wrap_width,1,1))
+          wrap=util.line_wrap
+          wrap=if wrap =~ /^\s*[\d*+]+\s+.+?\s*\Z/m
+            wrap.gsub(/^(\s*)([\d*+]+)\s+(.+?)\s*\Z/m, <<-GSUB
+\\1[fn:\\2] \\3
+              GSUB
+            )
+          else
+            wrap.gsub(/^(.+)\Z/m, <<-GSUB
+\\1
+              GSUB
+            )
+          end
+          @@endnotes[:para] << "-#{wrap}"
+          @@endnotes[:end] << '' << wrap.strip
+        end
+        @@endnotes
+      end
+      # Used for extraction of endnotes from paragraphs
+      def plaintext_metadata
+        array=SiSU_Metadata::Summary.new(@md).plaintext.metadata
+        array.each do |meta|
+          tag,inf=meta.scan(/^.+?:\s|.+/)
+          if tag and inf
+            util=SiSU_TextUtils::Wrap.new(inf,@wrap_width,15,1)
+            txt=util.line_wrap
+            @plaintext[:metadata] <<<<WOK
+
+#{@tab}#{tag}#{txt}
+WOK
+          end
+        end
+      end
+      def plaintext_tail
+#       env=SiSU_Env::InfoEnv.new(@md.fns)
+        generator="Generated by: #{@md.project_details.project} #{@md.project_details.version} of #{@md.project_details.date_stamp} (#{@md.project_details.date})"  if @md.project_details.version
+        lastdone="Last Generated on: #{Time.now}"
+        rubyv="Ruby version: #{@md.ruby_version}"
+        sc=if @md.sc_info
+          "Source file:    #{@md.sc_filename}#{break_line}Version number: #{@md.sc_number}#{break_line}Version date:   #{@md.sc_date}#{break_line}"
+        else ''
+        end
+        @plaintext[:tail] <<<<WOK
+,** Metadata
+#{break_line}
+plaintext (plain text):
+   #{@md.file.output_path.orgmode.url}/#{@md.file.base_filename.orgmode}#{break_line}
+Other versions of this document: #{break_line}
+manifest:
+   #{@md.file.output_path.manifest.url}/#{@md.file.base_filename.manifest}#{break_line}
+at:
+   #{@md.file.output_path.base.url}#{break_line}
+
+  #{sc}
+  * #{generator}
+  * #{rubyv}
+  * #{lastdone}
+  * SiSU #{the_url.sisu_txt}
+WOK
+      end
+      def heading_decorated_inline(dob)
+        if dob.is==:heading
+          heading_inline = case dob.lc
+          when 0 then decorate.heading.inline.l0
+          when 1 then decorate.heading.inline.l1
+          when 2 then decorate.heading.inline.l2
+          when 3 then decorate.heading.inline.l3
+          when 4 then decorate.heading.inline.l4
+          when 5 then decorate.heading.inline.l5
+          when 6 then decorate.heading.inline.l6
+          end
+          heading_inline + ' ' +  dob.obj
+        end
+      end
+      def plaintext_structure(dob='',p_num='') #% Used to extract the structure of a document
+        heading_decoration=:inline #(:inline|:underscore) #switch heading decoration between inline & underscore options
+        util=nil
+        wrapped=if dob.is==:para \
+        || dob.is==:heading
+          if dob.is==:heading
+            util=(heading_decoration== :inline) \
+            ? (SiSU_TextUtils::Wrap.new(heading_decorated_inline(dob),@wrap_width,0))
+            : (SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,0))
+          elsif dob.is==:para
+            if dob.hang \
+            and dob.hang =~/[0-9]/ \
+            and dob.indent != dob.hang
+              util=SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,dob.indent.to_i*2,dob.hang.to_i*2)
+              #util=SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,dob.hang.to_i*2,0)
+            elsif dob.indent =~/[1-9]/
+              util=if dob.bullet_
+                SiSU_TextUtils::Wrap.new("* #{dob.obj}",@wrap_width,dob.indent.to_i*2)
+              else SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,dob.indent.to_i*2)
+              end
+            else
+              util=if dob.bullet_
+                SiSU_TextUtils::Wrap.new("* #{dob.obj}",@wrap_width,0)
+              else SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,0)
+              end
+            end
+          else util=SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,0)
+          end
+          dob.is==:heading ? util.no_wrap_no_breaks : util.line_wrap
+        end
+        if dob.is==:para \
+        || dob.is==:heading
+          @plaintext[:body] << wrapped + p_num << break_line # main text, contents, body KEEP
+        end
+# remove ...
+        if @@endnotes[:para] \
+        and not @@endnotes_
+          @@endnotes[:para].each {|e| @plaintext[:body] << e << break_line}
+        elsif @@endnotes[:para] \
+        and @@endnotes_
+          @@endnotes[:para].each {|e| @plaintext[:endnotes] << e << break_line}
+        end
+        @@endnotes[:para]=[]
+      end
+      def markup(data)                                                       # Used for major markup instructions
+        SiSU_Env::InfoEnv.new(@md.fns)
+        @data_mod,@endnotes,@level,@cont,@copen,@plaintext_contents_close=Array.new(6){[]}
+        (0..6).each { |x| @cont[x]=@level[x]=false }
+        (4..6).each { |x| @plaintext_contents_close[x]='' }
+        plaintext_tail #($1,$2)
+        plaintext_metadata
+        table_message='[table conversion awaited, see other document formats]'
+        data.each do |dob|
+          dob.obj=dob.obj.gsub(/#{Mx[:gr_o]}Th?#{Mx[:tc_p]}.+/um,"#{break_line}#{table_message}"). #fix
+            gsub(/.+?#{Mx[:gl_o]}-##{Mx[:gl_c]}/,'').                              # remove dummy headings (used by html) #check also [~-]#
+            gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,
+              "#{decorate.bold.open}\\1#{decorate.bold.close}").
+            gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,
+              "#{decorate.italics.open}\\1#{decorate.italics.close}").
+            gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,
+              "#{decorate.underscore.open}\\1#{decorate.underscore.close}").
+            gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,
+              "#{decorate.subscript.open}\\1#{decorate.subscript.close}").
+            gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,
+              "#{decorate.superscript.open}\\1#{decorate.superscript.close}").
+            gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,
+              "#{decorate.insert.open}\\1#{decorate.insert.close}").
+            gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,
+              "#{decorate.cite.open}\\1#{decorate.cite.close}").
+            gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,
+              "#{decorate.strike.open}\\1#{decorate.strike.close}").
+            gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,
+              "#{decorate.monospace.open}\\1#{decorate.monospace.close}")
+          unless dob.is==:code
+            dob.obj=dob.obj.gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}/,'\1').
+              gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,'[[\1]]').
+              gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,'[[\2][\1]]').
+              gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}image/,'[[\1]] [link: local image]').
+              gsub(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,'[[\1]]') #urls
+            extract_endnotes(dob)
+            dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'[fn:\1]'). # endnote marker marked up
+              gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'[fn:\1]'). # endnote marker marked up
+              gsub(/#{Mx[:gl_o]}(?:#lt|#060)#{Mx[:gl_c]}/,'<').
+              gsub(/#{Mx[:gl_o]}(?:#gt|#062)#{Mx[:gl_c]}/,'>').
+              gsub(/#{Mx[:gl_o]}#(?:038|amp)#{Mx[:gl_c]}/,'&').
+              gsub(/#{Mx[:gl_o]}#033#{Mx[:gl_c]}/,'!').
+              gsub(/#{Mx[:gl_o]}#035#{Mx[:gl_c]}/,'#').
+              gsub(/#{Mx[:gl_o]}#042#{Mx[:gl_c]}/,'*').
+              gsub(/#{Mx[:gl_o]}#045#{Mx[:gl_c]}/,'-').
+              gsub(/#{Mx[:gl_o]}#047#{Mx[:gl_c]}/,'/').
+              gsub(/#{Mx[:gl_o]}#095#{Mx[:gl_c]}/,'_').
+              gsub(/#{Mx[:gl_o]}#123#{Mx[:gl_c]}/,'{').
+              gsub(/#{Mx[:gl_o]}#125#{Mx[:gl_c]}/,'}').
+              gsub(/#{Mx[:gl_o]}#126#{Mx[:gl_c]}/,'~').
+              gsub(/#{Mx[:gl_o]}#169#{Mx[:gl_c]}/,'©').
+              gsub(/#{Mx[:gl_o]}#092#{Mx[:gl_c]}/,'\\')
+          end
+          dob.obj=if dob.of==:block                                   # watch
+            dob.obj.gsub(/#{Mx[:gl_o]}●#{Mx[:gl_c]}/m,"* ").
+              gsub(/\n?#{Mx[:br_line]}\n?|\n?#{Mx[:br_nl]}\n?/m,break_line)
+          else dob.obj.gsub(/\n?#{Mx[:br_line]}\n?|\n?#{Mx[:br_nl]}\n?/m,break_line*2)
+          end
+          if dob.is==:code
+            dob.obj=dob.obj.gsub(/(^|[^}])_([<>])/m,'\1\2'). # _> _<
+              gsub(/(^|[^}])_([<>])/m,'\1\2'). # _<_<
+              gsub(/^\*/m,',*')
+            dob.obj = '#+BEGIN_SRC sh :tangle no :padline no :exports none   :noweb yes' + "\n" + dob.obj + '#+END_SRC'
+          end
+          dob.obj=dob.obj.gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,'\1').
+            gsub(/<a href=".+?">(.+?)<\/a>/m,'\1').
+            gsub(/#{Mx[:mk_o]}:name#(\S+?)#{Mx[:mk_c]}/,'').                       # remove name links
+            gsub(/&nbsp;|#{Mx[:nbsp]}/,' ').                                       # decide on
+            gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}(\S+?\.(?:png|jpg|gif)) .+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/,'    [ \1 ]'). #"[ #{dir.url.images_local}\/\\1 ]")
+            gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}(\S+?\.(?:png|jpg|gif)) .+?#{Mx[:lnk_c]}image/,'    [ \1 ]').
+            gsub(/(?:^|[^_\\])\{\s*\S+?\.(?:png|jpg|gif)\s+.+?"(.*?)"\s*\}\S+/,'[image: "\1"]')
+          if dob.obj !~/(^#{Rx[:meta]}|#{Mx[:br_eof]}|#{Mx[:br_endnotes]})/
+            p_num=''
+            #ocn
+            if dob.is==:heading \
+            or dob.is==:para
+              plaintext_structure(dob,p_num)
+            elsif dob.is==:group \
+            or dob.is==:block \
+            or dob.is==:verse \
+            or dob.is==:code \
+            or dob.is==:table
+              @plaintext[:body] << dob.obj + p_num << break_line
+            elsif dob.is==:break
+              sp=' '
+              ln='<' #ln='-'
+              @plaintext[:body] <<=if dob.obj==Mx[:br_page] \
+              or dob.obj==Mx[:br_page_new] \
+              or dob.obj==Mx[:br_page_line]
+                "#{break_line}#{ln*40}#{break_line*2}"
+              elsif dob.obj ==Mx[:br_obj]
+                "#{break_line}#{sp*20}*  *  *#{break_line*2}"
+              end # following empty line (break_line) missing, fix
+            end
+            dob='' if (dob.obj =~/<a name="n\d+">/ \
+              and dob.obj =~/^(-\{{2}~\d+|<!e[:_]\d+!>)/) # -endnote
+            if dob ## Clean Prepared Text
+              dob.obj=dob.obj.gsub(/<!.+!>/,' ').
+                gsub(/<:\S+>/,' ')
+            end
+          end
+        end
+        @plaintext
+      end
+      def publish(plaintext)
+        divider='='
+        content=[]
+        content << plaintext[:open]
+        content << plaintext[:head]
+        content << plaintext[:body]
+        if @@endnotes_
+          content << '** Endnotes' <<  @@endnotes[:end]
+        end
+        content << plaintext[:metadata]
+        content << "#{break_line}#{divider*@wrap_width}#{break_line}" if @md.stmp =~/\w+/ #not used?
+        content << plaintext[:tail]
+        outputfile=SiSU_Env::FileOp.new(@md).write_file.orgmode
+        Txt_Output::Output.new.document(content,outputfile)
+        @@endnotes={ para: [], end: [] }
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+*** txt_orgmode_decorate.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/txt_orgmode_decorate.rb"
+# <<sisu_document_header>>
+module SiSU_Decorate_Txt_OrgMode
+  def decorate
+    def heading
+      def inline
+        def l0
+          '*'
+        end
+        def l1
+          '**'
+        end
+        def l2
+          '***'
+        end
+        def l3
+          '****'
+        end
+        def l4
+          '*****'
+        end
+        def l5
+          '******'
+        end
+        self
+      end
+      self
+    end
+    def bold
+      def open
+        '*'
+      end
+      def close
+        '*'
+      end
+      self
+    end
+    def italics
+      def open
+        '/'
+      end
+      def close
+        '/'
+      end
+      self
+    end
+    def underscore
+      def open
+        ''
+      end
+      def close
+        ''
+      end
+      self
+    end
+   #def emphasis
+   #  def open
+   #    ''
+   #  end
+   #  def close
+   #    ''
+   #  end
+   #  self
+   #end
+    def cite
+      def open
+        '"'
+      end
+      def close
+        '"'
+      end
+      self
+    end
+    def insert
+      def open
+        ''
+      end
+      def close
+        ''
+      end
+      self
+    end
+    def strike
+      def open
+        '+'
+      end
+      def close
+        '+'
+      end
+      self
+    end
+    def superscript
+      def open
+        '^'
+      end
+      def close
+        '^'
+      end
+      self
+    end
+    def subscript
+      def open
+        '~'
+      end
+      def close
+        '~'
+      end
+      self
+    end
+    def hilite #bold
+      def open
+        '*'
+      end
+      def close
+        '*'
+      end
+      self
+    end
+    def monospace
+      def open
+        '~'
+      end
+      def close
+        '~'
+      end
+      self
+    end
+    self
+  end
+end
+__END__
+#+END_SRC
+
+** plain
+*** txt_plain.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/txt_plain.rb"
+# <<sisu_document_header>>
+module SiSU_Txt_Plain
+  require_relative 'ao'                                 # ao.rb
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'shared_metadata'                    # shared_metadata.rb
+  require_relative 'generic_parts'                      # generic_parts.rb
+  require_relative 'txt_read'                           # txt_read.rb
+  require_relative 'txt_shared'                         # txt_shared.rb
+  require_relative 'txt_plain_decorate'                 # txt_plain_decorate.rb
+  require_relative 'txt_output'                         # txt_output.rb
+  include SiSU_Param
+  @@alt_id_count,@@alt_id_count=0,0
+  @@tablefoot=''
+  class Source
+    include SiSU_Txt_Read
+    def initialize(opt)
+      @opt=opt
+      unless @opt.fns =~/(.+?)\.(?:-|ssm\.)?sst$/
+        puts "#{sf} not a processed file type"
+      end
+    end
+    def read
+      begin
+        md=SiSU_Param::Parameters.new(@opt).get
+        specific={
+          description:     'Plaintext (utf-8)',
+          output_path:     md.file.output_path.txt.dir,
+          output_file:     md.file.base_filename.txt,
+        }
+        read_generic(@opt,specific)
+        SiSU_Txt_Plain::Source::Scroll.new(md,@ao_array,@wrap_width).songsheet
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    private
+    class Scroll <Source
+      include SiSU_Parts_Generic
+      include SiSU_TextUtils
+      include SiSU_Decorate_Txt_Plain
+      @@endnotes={ para: [], end: [] }
+      def initialize(md,data,wrap_width)
+        @md,@data,@wrap_width=md,data,wrap_width
+        @env=SiSU_Env::InfoEnv.new(@md.fns)
+        @tab="\t"
+        @@endnotes_=case md.opt.selections.str
+        when /--footnote/ then false
+        when /--endnote/  then true
+        else                   true
+        end
+        @plaintext={ body: [], open: [], close: [], head: [], metadata: [], tail: [] }
+      end
+      def songsheet
+        plaintext=markup(@data)
+        publish(plaintext)
+      end
+      def break_line
+        "\n"
+      end
+      # Used for extraction of endnotes from paragraphs
+      def extract_endnotes(dob='')
+        notes=dob.obj.scan(/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})([\d*+]+\s+.+?)(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/)
+        @n=[]
+        notes.flatten.each do |n| #high cost to deal with <br> appropriately within plaintext, consider
+          n=n.dup.to_s
+          if n =~/#{Mx[:br_line]}|#{Mx[:br_nl]}/
+            fix = n.split(/#{Mx[:br_line]}|#{Mx[:br_nl]}/) #watch #added
+            fix.each do |x|
+              unless x.empty?; @n << x
+              end
+            end
+          else                 @n << n
+          end
+        end
+        notes=@n.flatten
+        notes.each do |e|
+          util=(e.to_s =~/^\[[\d*+]+\]:/) \
+          ? (SiSU_TextUtils::Wrap.new(e.to_s,@wrap_width,4,1))
+          : (SiSU_TextUtils::Wrap.new(e.to_s,@wrap_width,1,1))
+          wrap=util.line_wrap
+          wrap=if wrap =~ /^\s*[\d*+]+\s+.+?\s*\Z/m
+            wrap.gsub(/^(\s*)([\d*+]+)\s+(.+?)\s*\Z/m, <<-GSUB
+\\1[\\2]: \\3
+              GSUB
+            )
+          else
+            wrap.gsub(/^(.+)\Z/m, <<-GSUB
+\\1
+              GSUB
+            )
+          end
+          @@endnotes[:para] << "-#{wrap}"
+          @@endnotes[:end] << '' << wrap
+        end
+        @@endnotes
+      end
+      def plaintext_metadata
+        array=SiSU_Metadata::Summary.new(@md).plaintext.metadata
+        array.each do |meta|
+          tag,inf=meta.scan(/^.+?:\s|.+/)
+          if tag and inf
+            util=SiSU_TextUtils::Wrap.new(inf,@wrap_width,15,1)
+            txt=util.line_wrap
+            @plaintext[:metadata] <<<<WOK
+
+#{@tab}#{tag}#{txt}
+WOK
+          end
+        end
+      end
+      def plaintext_tail
+#       env=SiSU_Env::InfoEnv.new(@md.fns)
+        generator="Generated by: #{@md.project_details.project} #{@md.project_details.version} of #{@md.project_details.date_stamp} (#{@md.project_details.date})"  if @md.project_details.version
+        lastdone="Last Generated on: #{Time.now}"
+        rubyv="Ruby version: #{@md.ruby_version}"
+        sc=if @md.sc_info
+          "Source file:    #{@md.sc_filename}#{break_line}Version number: #{@md.sc_number}#{break_line}Version date:   #{@md.sc_date}#{break_line}"
+        else ''
+        end
+        @plaintext[:tail] <<<<WOK
+#{break_line}
+plaintext (plain text):
+   #{@md.file.output_path.txt.url}/#{@md.file.base_filename.txt}#{break_line}
+Other versions of this document: #{break_line}
+manifest:
+   #{@md.file.output_path.manifest.url}/#{@md.file.base_filename.manifest}#{break_line}
+at:
+   #{@md.file.output_path.base.url}#{break_line}
+
+#{sc}
+,* #{generator}
+,* #{rubyv}
+,* #{lastdone}
+,* SiSU #{the_url.sisu_txt}
+WOK
+      end
+      def plaintext_structure(dob='',p_num='') #% Used to extract the structure of a document
+        lv=n=n3=nil
+        if dob.is==:heading
+          lv=dob.ln
+          n=lv - 1
+          n3=lv + 2
+        end
+        util=nil
+        wrapped=if dob.is==:para \
+        || dob.is==:heading
+          if dob.is==:para
+            if dob.hang \
+            and dob.hang =~/[0-9]/ \
+            and dob.indent != dob.hang
+              util=SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,dob.indent.to_i*2,dob.hang.to_i*2)
+              #util=SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,dob.hang.to_i*2,0)
+            elsif dob.indent =~/[1-9]/
+              util=if dob.bullet_
+                SiSU_TextUtils::Wrap.new("* #{dob.obj}",@wrap_width,dob.indent.to_i*2)
+              else SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,dob.indent.to_i*2)
+              end
+            else
+              util=if dob.bullet_
+                SiSU_TextUtils::Wrap.new("* #{dob.obj}",@wrap_width,0)
+              else SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,0)
+              end
+            end
+          else util=SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,0)
+          end
+          util.line_wrap
+        end
+        if lv
+          times=wrapped.length
+          times=@wrap_width if times > @wrap_width
+          @plaintext[:body] << case lv
+          when 0 then wrapped.upcase << break_line << decorate.heading_underscore.l0*times + p_num << break_line*2
+          when 1 then wrapped.upcase << break_line << decorate.heading_underscore.l1*times + p_num << break_line*2
+          when 2 then wrapped.upcase << break_line << decorate.heading_underscore.l2*times + p_num << break_line*2
+          when 3 then wrapped.upcase << break_line << decorate.heading_underscore.l3*times + p_num << break_line*2
+          when 4
+            unless dob.use_ == :dummy
+              wrapped.upcase << break_line << decorate.heading_underscore.l4*times + p_num << break_line*2
+            end
+          when 5 then wrapped.upcase << break_line << decorate.heading_underscore.l5*times + p_num << break_line*2
+          when 6 then wrapped.upcase << break_line << decorate.heading_underscore.l6*times + p_num << break_line*2
+          when 7
+            wrapped.upcase << break_line << decorate.heading_underscore.l7*times + p_num << break_line*2
+          #when 7 then wrapped.upcase << break_line << decorate.heading_underscore.l7*times + p_num << break_line*2
+          end
+        else
+          @plaintext[:body] << wrapped + p_num << break_line # main text, contents, body KEEP
+        end
+        if @@endnotes[:para] \
+        and not @@endnotes_
+          @@endnotes[:para].each {|e| @plaintext[:body] << e << break_line}
+        elsif @@endnotes[:para] \
+        and @@endnotes_
+        end
+        @@endnotes[:para]=[]
+      end
+      def ocn_display(dob)
+        make=SiSU_Env::ProcessingSettings.new(@md)
+        if make.build.plaintext_ocn?
+          if defined? dob.ocn \
+          and dob.ocn.is_a?(Fixnum)
+            (defined? dob.ocn) \
+            ? "\n#{Dx[:ocn_o]}#{dob.ocn}#{Dx[:ocn_c]}" \
+            : ''
+          else ''
+          end
+        else ''
+        end
+      end
+      def markup(data)                                                       # Used for major markup instructions
+        SiSU_Env::InfoEnv.new(@md.fns)
+        @data_mod,@endnotes,@level,@cont,@copen,@plaintext_contents_close=Array.new(6){[]}
+        (0..7).each { |x| @cont[x]=@level[x]=false }
+        (4..7).each { |x| @plaintext_contents_close[x]='' }
+        plaintext_tail #($1,$2)
+        plaintext_metadata
+        table_message='[table omitted, see other document formats]'
+        data.each do |dob|
+          dob.obj=dob.obj.gsub(/#{Mx[:gr_o]}Th?#{Mx[:tc_p]}.+/um,"#{break_line}#{table_message}"). #fix
+            gsub(/.+?#{Mx[:gl_o]}-##{Mx[:gl_c]}/,'').                              # remove dummy headings (used by html) #check also [~-]#
+            gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,
+              "#{decorate.bold.open}\\1#{decorate.bold.close}").
+            gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,
+              "#{decorate.italics.open}\\1#{decorate.italics.close}").
+            gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,
+              "#{decorate.underscore.open}\\1#{decorate.underscore.close}").
+            gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,
+              "#{decorate.subscript.open}\\1#{decorate.subscript.close}").
+            gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,
+              "#{decorate.superscript.open}\\1#{decorate.superscript.close}").
+            gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,
+              "#{decorate.insert.open}\\1#{decorate.insert.close}").
+            gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,
+              "#{decorate.cite.open}\\1#{decorate.cite.close}").
+            gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,
+              "#{decorate.strike.open}\\1#{decorate.strike.close}").
+            gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,
+              "#{decorate.monospace.open}\\1#{decorate.monospace.close}")
+          unless dob.is==:code
+            dob.obj=dob.obj.gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}/,'\1').
+              gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,'\1').
+              gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,'\1 [link: <\2>]').
+              gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}image/,'\1 [link: local image]').
+              gsub(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,"#{the_text.url_open}\\1#{the_text.url_close}")
+            extract_endnotes(dob)
+            dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'[^\1]'). # endnote marker marked up
+              gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'[^\1]'). # endnote marker marked up
+              gsub(/#{Mx[:gl_o]}(?:#lt|#060)#{Mx[:gl_c]}/,'<').
+              gsub(/#{Mx[:gl_o]}(?:#gt|#062)#{Mx[:gl_c]}/,'>').
+              gsub(/#{Mx[:gl_o]}#(?:038|amp)#{Mx[:gl_c]}/,'&').
+              gsub(/#{Mx[:gl_o]}#033#{Mx[:gl_c]}/,'!').
+              gsub(/#{Mx[:gl_o]}#035#{Mx[:gl_c]}/,'#').
+              gsub(/#{Mx[:gl_o]}#042#{Mx[:gl_c]}/,'*').
+              gsub(/#{Mx[:gl_o]}#045#{Mx[:gl_c]}/,'-').
+              gsub(/#{Mx[:gl_o]}#047#{Mx[:gl_c]}/,'/').
+              gsub(/#{Mx[:gl_o]}#095#{Mx[:gl_c]}/,'_').
+              gsub(/#{Mx[:gl_o]}#123#{Mx[:gl_c]}/,'{').
+              gsub(/#{Mx[:gl_o]}#125#{Mx[:gl_c]}/,'}').
+              gsub(/#{Mx[:gl_o]}#126#{Mx[:gl_c]}/,'~').
+              gsub(/#{Mx[:gl_o]}#169#{Mx[:gl_c]}/,'©').
+              gsub(/#{Mx[:gl_o]}#092#{Mx[:gl_c]}/,'\\')
+          end
+          dob.obj=if dob.of==:block                                   # watch
+            dob.obj.gsub(/#{Mx[:gl_o]}●#{Mx[:gl_c]}/m,"* ").
+              gsub(/\n?#{Mx[:br_line]}\n?|\n?#{Mx[:br_nl]}\n?/m,break_line)
+          else dob.obj.gsub(/\n?#{Mx[:br_line]}\n?|\n?#{Mx[:br_nl]}\n?/m,break_line*2)
+          end
+          if dob.is==:code
+            dob.obj=dob.obj.gsub(/(^|[^}])_([<>])/m,'\1\2'). # _> _<
+              gsub(/(^|[^}])_([<>])/m,'\1\2') # _<_<
+          end
+          dob.obj=dob.obj.gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,'\1').
+            gsub(/<a href=".+?">(.+?)<\/a>/m,'\1').
+            gsub(/#{Mx[:mk_o]}:name#(\S+?)#{Mx[:mk_c]}/,'').                       # remove name links
+            gsub(/&nbsp;|#{Mx[:nbsp]}/,' ').                                       # decide on
+            gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}(\S+?\.(?:png|jpg|gif)) .+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/,'    [ \1 ]'). #"[ #{dir.url.images_local}\/\\1 ]")
+            gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}(\S+?\.(?:png|jpg|gif)) .+?#{Mx[:lnk_c]}image/,'    [ \1 ]').
+            gsub(/(?:^|[^_\\])\{\s*\S+?\.(?:png|jpg|gif)\s+.+?"(.*?)"\s*\}\S+/,'[image: "\1"]')
+          if dob.obj !~/(^#{Rx[:meta]}|#{Mx[:br_eof]}|#{Mx[:br_endnotes]})/
+            p_num=ocn_display(dob)
+            if dob.is==:heading \
+            or dob.is==:para
+              plaintext_structure(dob,p_num)
+            elsif dob.is==:group \
+            or dob.is==:block \
+            or dob.is==:verse \
+            or dob.is==:code \
+            or dob.is==:table
+              @plaintext[:body] << dob.obj + p_num << break_line
+            elsif dob.is==:break
+              sp=' '
+              ln='-'
+              @plaintext[:body] <<=if dob.obj==Mx[:br_page] \
+              or dob.obj==Mx[:br_page_new] \
+              or dob.obj==Mx[:br_page_line]
+                "#{break_line}#{ln*40}#{break_line*2}"
+              elsif dob.obj ==Mx[:br_obj]
+                "#{break_line}#{sp*20}*  *  *#{break_line*2}"
+              end # following empty line (break_line) missing, fix
+            end
+            dob='' if (dob.obj =~/<a name="n\d+">/ \
+              and dob.obj =~/^(-\{{2}~\d+|<!e[:_]\d+!>)/) # -endnote
+            if dob ## Clean Prepared Text
+              dob.obj=dob.obj.gsub(/<!.+!>/,' ').
+                gsub(/<:\S+>/,' ')
+            end
+          end
+        end
+        @plaintext
+      end
+      def publish(plaintext)
+        divider='='
+        content=[]
+        content << plaintext[:open]
+        content << plaintext[:head]
+        content << plaintext[:body]
+        content << @@endnotes[:end] if @@endnotes_
+        content << "#{break_line}#{divider*@wrap_width}#{break_line}"
+        content << plaintext[:metadata]
+        content << "#{break_line}#{divider*@wrap_width}#{break_line}" if @md.stmp =~/\w+/ #not used?
+        content << plaintext[:tail]
+        outputfile=SiSU_Env::FileOp.new(@md).write_file.txt
+        Txt_Output::Output.new.document(content,outputfile)
+        @@endnotes={ para: [], end: [] }
+      end
+    end
+  end
+end
+__END__
+  bold_o:                    '*',          bold_c:                   '*',
+ #bold_o:                    '!',          bold_c:                   '!',
+ #emphasis_o:                '*',          emphasis_c:               '*',
+  italics_o:                 '/',          italics_c:                '/',
+  underscore_o:              '_',          underscore_c:             '_',
+  cite_o:                    '"',          cite_c:                   '"',
+  insert_o:                  '+',          insert_c:                 '+',
+  strike_o:                  '-',          strike_c:                 '-',
+  superscript_o:             '^',          superscript_c:            '^',
+  subscript_o:               '[',          subscript_c:              ']',
+  hilite_o:                  '*',          hilite_c:                 '*',
+  monospace_o:               '',           monospace_c:              '',
+  p_bold_o:                  '!{',         p_bold_c:                 '}!',
+  p_italics_o:               '/{',         p_italics_c:              '}/',
+  p_underscore_o:            '_{',         p_underscore_c:           '}_',
+  p_cite_o:                  '"{',         p_cite_c:                 '}"',
+  p_insert_o:                '+{',         p_insert_c:               '}+',
+  p_strike_o:                '-{',         p_strike_c:               '}-',
+  p_superscript_o:           '^{',         p_superscript_c:          '}^',
+  p_subscript_o:             ',{',         p_subscript_c:            '},',
+  p_hilite_o:                '*{',         p_hilite_c:               '}*',
+  p_monospace_o:             '#{',         p_monospace_c:            '}#',
+#+END_SRC
+
+*** txt_plain_decorate.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/txt_plain_decorate.rb"
+# <<sisu_document_header>>
+module SiSU_Decorate_Txt_Plain
+  def decorate
+    def heading_underscore
+      def l0
+        '='
+      end
+      def l1
+        '*'
+      end
+      def l2
+        '+'
+      end
+      def l3
+        '~'
+      end
+      def l4
+        '-'
+      end
+      def l5
+        '.'
+      end
+      def l6
+        '.'
+      end
+      def l7
+        '.'
+      end
+      self
+    end
+    def bold
+      def open
+        '*'
+      end
+      def close
+        '*'
+      end
+      self
+    end
+    def italics
+      def open
+        '/'
+      end
+      def close
+        '/'
+      end
+      self
+    end
+    def underscore
+      def open
+        '_'
+      end
+      def close
+        '_'
+      end
+      self
+    end
+   #def emphasis
+   #  def open
+   #    ''
+   #  end
+   #  def close
+   #    ''
+   #  end
+   #  self
+   #end
+    def cite
+      def open
+        '"'
+      end
+      def close
+        '"'
+      end
+      self
+    end
+    def insert
+      def open
+        '+'
+      end
+      def close
+        '+'
+      end
+      self
+    end
+    def strike
+      def open
+        '-'
+      end
+      def close
+        '-'
+      end
+      self
+    end
+    def superscript
+      def open
+        '^'
+      end
+      def close
+        '^'
+      end
+      self
+    end
+    def subscript
+      def open
+        '['
+      end
+      def close
+        ']'
+      end
+      self
+    end
+    def hilite
+      def open
+        '*'
+      end
+      def close
+        '*'
+      end
+      self
+    end
+    def monospace
+      def open
+        '#'
+      end
+      def close
+        '#'
+      end
+      self
+    end
+    self
+  end
+end
+__END__
+#+END_SRC
+
+** rst
+*** txt_rst.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/txt_rst.rb"
+# <<sisu_document_header>>
+module SiSU_Txt_rST
+  require_relative 'ao'                                 # ao.rb
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'shared_metadata'                    # shared_metadata.rb
+  require_relative 'generic_parts'                      # generic_parts.rb
+  require_relative 'txt_read'                           # txt_read.rb
+  require_relative 'txt_shared'                         # txt_shared.rb
+  require_relative 'txt_rst_decorate'                   # txt_rst_decorate.rb
+  require_relative 'txt_output'                         # txt_output.rb
+  include SiSU_Param
+  @@alt_id_count,@@alt_id_count=0,0
+  @@tablefoot=''
+  class Source
+    include SiSU_Txt_Read
+    def initialize(opt)
+      @opt=opt
+      unless @opt.fns =~/(.+?)\.(?:-|ssm\.)?sst$/
+        puts "#{sf} not a processed file type"
+      end
+    end
+    def read
+      begin
+        md=SiSU_Param::Parameters.new(@opt).get
+        specific={
+          description:     'rST (plaintext utf-8)',
+          output_path:     md.file.output_path.rst.dir,
+          output_file:     md.file.base_filename.rst,
+        }
+        read_generic(@opt,specific)
+        SiSU_Txt_rST::Source::Scroll.new(md,@ao_array,@wrap_width).songsheet
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    private
+    class Scroll <Source
+      include SiSU_Parts_Generic
+      include SiSU_TextUtils
+      include SiSU_Decorate_Txt_rST
+      @@endnotes={ para: [], end: [] }
+      def initialize(md,data,wrap_width)
+        @md,@data,@wrap_width=md,data,wrap_width
+        @env=SiSU_Env::InfoEnv.new(@md.fns)
+        @tab="\t"
+        @@endnotes_=case md.opt.selections.str
+        when /--footnote/ then false
+        when /--endnote/  then true
+        else                   true
+        end
+        @plaintext={ body: [], open: [], close: [], head: [], metadata: [], tail: [] }
+      end
+      def songsheet
+        plaintext=markup(@data)
+        publish(plaintext)
+      end
+      def break_line
+        "\n"
+      end
+      # Used for extraction of endnotes from paragraphs
+      def extract_endnotes(dob='')
+        notes=dob.obj.scan(/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})([\d*+]+\s+.+?)(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/)
+        @n=[]
+        notes.flatten.each do |n| #high cost to deal with <br> appropriately within plaintext, consider
+          n=n.dup.to_s
+          if n =~/#{Mx[:br_line]}|#{Mx[:br_nl]}/
+            fix = n.split(/#{Mx[:br_line]}|#{Mx[:br_nl]}/) #watch #added
+            fix.each do |x|
+              unless x.empty?; @n << x
+              end
+            end
+          else                 @n << n
+          end
+        end
+        notes=@n.flatten
+        notes.each do |e|
+          util=(e.to_s =~/^\[[\d*+]+\]:/) \
+          ? (SiSU_TextUtils::Wrap.new(e.to_s,@wrap_width,4,1))
+          : (SiSU_TextUtils::Wrap.new(e.to_s,@wrap_width,1,1))
+          wrap=util.line_wrap
+          wrap=if wrap =~ /^\s*[\d*+]+\s+.+?\s*\Z/m
+            wrap.gsub(/^(\s*)([\d*+]+)\s+(.+?)\s*\Z/m, <<-GSUB
+\\1[\\2]: \\3
+              GSUB
+            )
+          else
+            wrap.gsub(/^(.+)\Z/m, <<-GSUB
+\\1
+              GSUB
+            )
+          end
+          @@endnotes[:para] << "-#{wrap}"
+          @@endnotes[:end] << '' << wrap
+        end
+        @@endnotes
+      end
+      def plaintext_metadata
+        array=SiSU_Metadata::Summary.new(@md).plaintext.metadata
+        array.each do |meta|
+          tag,inf=meta.scan(/^.+?:\s|.+/)
+          if tag and inf
+            util=SiSU_TextUtils::Wrap.new(inf,@wrap_width,15,1)
+            txt=util.line_wrap
+            @plaintext[:metadata] <<<<WOK
+
+#{@tab}#{tag}#{txt}
+WOK
+          end
+        end
+      end
+      def plaintext_tail
+#       env=SiSU_Env::InfoEnv.new(@md.fns)
+        generator="Generated by: #{@md.project_details.project} #{@md.project_details.version} of #{@md.project_details.date_stamp} (#{@md.project_details.date})"  if @md.project_details.version
+        lastdone="Last Generated on: #{Time.now}"
+        rubyv="Ruby version: #{@md.ruby_version}"
+        sc=if @md.sc_info
+          "Source file:    #{@md.sc_filename}#{break_line}Version number: #{@md.sc_number}#{break_line}Version date:   #{@md.sc_date}#{break_line}"
+        else ''
+        end
+        @plaintext[:tail] <<<<WOK
+#{break_line}
+plaintext (plain text):
+   #{@md.file.output_path.rst.url}/#{@md.file.base_filename.rst}#{break_line}
+Other versions of this document: #{break_line}
+manifest:
+   #{@md.file.output_path.manifest.url}/#{@md.file.base_filename.manifest}#{break_line}
+at:
+   #{@md.file.output_path.base.url}#{break_line}
+
+#{sc}
+,* #{generator}
+,* #{rubyv}
+,* #{lastdone}
+,* SiSU #{the_url.sisu_txt}
+WOK
+      end
+      def heading_decorated_underscore(dob,times,p_num)
+        if dob.is==:heading
+          #times=@wrap_width if times > @wrap_width
+          case dob.lc
+          when 0 then decorate.heading.underscore.l0*times + p_num << break_line*2
+          when 1 then decorate.heading.underscore.l1*times + p_num << break_line*2
+          when 2 then decorate.heading.underscore.l2*times + p_num << break_line*2
+          when 3 then decorate.heading.underscore.l3*times + p_num << break_line*2
+          when 4 then decorate.heading.underscore.l4*times + p_num << break_line*2
+          when 5 then decorate.heading.underscore.l5*times + p_num << break_line*2
+          when 6 then decorate.heading.underscore.l6*times + p_num << break_line*2
+          end
+        end
+      end
+      def plaintext_structure(dob='',p_num='') #% Used to extract the structure of a document
+        util=nil
+        wrapped=if dob.is==:para \
+        || dob.is==:heading
+          if dob.is==:heading
+            util=SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,0)
+          elsif dob.is==:para
+            if dob.hang \
+            and dob.hang =~/[0-9]/ \
+            and dob.indent != dob.hang
+              util=SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,dob.indent.to_i*2,dob.hang.to_i*2)
+              #util=SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,dob.hang.to_i*2,0)
+            elsif dob.indent =~/[1-9]/
+              util=if dob.bullet_
+                SiSU_TextUtils::Wrap.new("* #{dob.obj}",@wrap_width,dob.indent.to_i*2)
+              else SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,dob.indent.to_i*2)
+              end
+            else
+              util=if dob.bullet_
+                SiSU_TextUtils::Wrap.new("* #{dob.obj}",@wrap_width,0)
+              else SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,0)
+              end
+            end
+          else util=SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,0)
+          end
+          dob.is==:heading ? util.no_wrap_no_breaks : util.line_wrap
+        end
+        if dob.is==:heading
+          @plaintext[:body] << wrapped + p_num # main text, contents, body KEEP
+          @plaintext[:body] << heading_decorated_underscore(dob,wrapped.length,p_num)
+        else
+          @plaintext[:body] << wrapped + p_num << break_line # main text, contents, body KEEP
+        end
+        if @@endnotes[:para] \
+        and not @@endnotes_
+          @@endnotes[:para].each {|e| @plaintext[:body] << e << break_line}
+        elsif @@endnotes[:para] \
+        and @@endnotes_
+        end
+        @@endnotes[:para]=[]
+      end
+      def markup(data)                                                       # Used for major markup instructions
+        SiSU_Env::InfoEnv.new(@md.fns)
+        @data_mod,@endnotes,@level,@cont,@copen,@plaintext_contents_close=Array.new(6){[]}
+        (0..6).each { |x| @cont[x]=@level[x]=false }
+        (4..6).each { |x| @plaintext_contents_close[x]='' }
+        plaintext_tail #($1,$2)
+        plaintext_metadata
+        table_message='[table conversion awaited, see other document formats]'
+        data.each do |dob|
+          dob.obj=dob.obj.gsub(/#{Mx[:gr_o]}Th?#{Mx[:tc_p]}.+/um,"#{break_line}#{table_message}"). #fix
+            gsub(/.+?#{Mx[:gl_o]}-##{Mx[:gl_c]}/,'').                              # remove dummy headings (used by html) #check also [~-]#
+            gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,
+              "#{decorate.bold.open}\\1#{decorate.bold.close}").
+            gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,
+              "#{decorate.italics.open}\\1#{decorate.italics.close}").
+            gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,
+              "#{decorate.underscore.open}\\1#{decorate.underscore.close}").
+            gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,
+              "#{decorate.subscript.open}\\1#{decorate.subscript.close}").
+            gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,
+              "#{decorate.superscript.open}\\1#{decorate.superscript.close}").
+            gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,
+              "#{decorate.insert.open}\\1#{decorate.insert.close}").
+            gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,
+              "#{decorate.cite.open}\\1#{decorate.cite.close}").
+            gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,
+              "#{decorate.strike.open}\\1#{decorate.strike.close}").
+            gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,
+              "#{decorate.monospace.open}\\1#{decorate.monospace.close}")
+          unless dob.is==:code
+            dob.obj=dob.obj.gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}/,'\1').
+              gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,'\1').
+              gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,'\1 [link: <\2>]').
+              gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}image/,'\1 [link: local image]').
+              gsub(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,"#{the_text.url_open}\\1#{the_text.url_close}")
+            extract_endnotes(dob)
+            dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'[^\1]'). # endnote marker marked up
+              gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'[^\1]'). # endnote marker marked up
+              gsub(/#{Mx[:gl_o]}(?:#lt|#060)#{Mx[:gl_c]}/,'<').
+              gsub(/#{Mx[:gl_o]}(?:#gt|#062)#{Mx[:gl_c]}/,'>').
+              gsub(/#{Mx[:gl_o]}#(?:038|amp)#{Mx[:gl_c]}/,'&').
+              gsub(/#{Mx[:gl_o]}#033#{Mx[:gl_c]}/,'!').
+              gsub(/#{Mx[:gl_o]}#035#{Mx[:gl_c]}/,'#').
+              gsub(/#{Mx[:gl_o]}#042#{Mx[:gl_c]}/,'*').
+              gsub(/#{Mx[:gl_o]}#045#{Mx[:gl_c]}/,'-').
+              gsub(/#{Mx[:gl_o]}#047#{Mx[:gl_c]}/,'/').
+              gsub(/#{Mx[:gl_o]}#095#{Mx[:gl_c]}/,'_').
+              gsub(/#{Mx[:gl_o]}#123#{Mx[:gl_c]}/,'{').
+              gsub(/#{Mx[:gl_o]}#125#{Mx[:gl_c]}/,'}').
+              gsub(/#{Mx[:gl_o]}#126#{Mx[:gl_c]}/,'~').
+              gsub(/#{Mx[:gl_o]}#169#{Mx[:gl_c]}/,'©').
+              gsub(/#{Mx[:gl_o]}#092#{Mx[:gl_c]}/,'\\')
+          end
+          dob.obj=if dob.of==:block                                   # watch
+            dob.obj.gsub(/#{Mx[:gl_o]}●#{Mx[:gl_c]}/m,"* ").
+              gsub(/\n?#{Mx[:br_line]}\n?|\n?#{Mx[:br_nl]}\n?/m,break_line)
+          else dob.obj.gsub(/\n?#{Mx[:br_line]}\n?|\n?#{Mx[:br_nl]}\n?/m,break_line*2)
+          end
+          if dob.is==:code
+            dob.obj=dob.obj.gsub(/(^|[^}])_([<>])/m,'\1\2'). # _> _<
+              gsub(/(^|[^}])_([<>])/m,'\1\2') # _<_<
+          end
+          dob.obj=dob.obj.gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,'\1').
+            gsub(/<a href=".+?">(.+?)<\/a>/m,'\1').
+            gsub(/#{Mx[:mk_o]}:name#(\S+?)#{Mx[:mk_c]}/,'').                       # remove name links
+            gsub(/&nbsp;|#{Mx[:nbsp]}/,' ').                                       # decide on
+            gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}(\S+?\.(?:png|jpg|gif)) .+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/,'    [ \1 ]'). #"[ #{dir.url.images_local}\/\\1 ]")
+            gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}(\S+?\.(?:png|jpg|gif)) .+?#{Mx[:lnk_c]}image/,'    [ \1 ]').
+            gsub(/(?:^|[^_\\])\{\s*\S+?\.(?:png|jpg|gif)\s+.+?"(.*?)"\s*\}\S+/,'[image: "\1"]')
+          if dob.obj !~/(^#{Rx[:meta]}|#{Mx[:br_eof]}|#{Mx[:br_endnotes]})/
+            p_num=''
+            #ocn
+            if dob.is==:heading \
+            or dob.is==:para
+              plaintext_structure(dob,p_num)
+            elsif dob.is==:group \
+            or dob.is==:block \
+            or dob.is==:verse \
+            or dob.is==:code \
+            or dob.is==:table
+              @plaintext[:body] << dob.obj + p_num << break_line
+            elsif dob.is==:break
+              sp=' '
+              ln='-'
+              @plaintext[:body] <<=if dob.obj==Mx[:br_page] \
+              or dob.obj==Mx[:br_page_new] \
+              or dob.obj==Mx[:br_page_line]
+                "#{break_line}#{ln*40}#{break_line*2}"
+              elsif dob.obj ==Mx[:br_obj]
+                "#{break_line}#{sp*20}*  *  *#{break_line*2}"
+              end # following empty line (break_line) missing, fix
+            end
+            dob='' if (dob.obj =~/<a name="n\d+">/ \
+              and dob.obj =~/^(-\{{2}~\d+|<!e[:_]\d+!>)/) # -endnote
+            if dob ## Clean Prepared Text
+              dob.obj=dob.obj.gsub(/<!.+!>/,' ').
+                gsub(/<:\S+>/,' ')
+            end
+          end
+        end
+        @plaintext
+      end
+      def publish(plaintext)
+        divider='='
+        content=[]
+        content << plaintext[:open]
+        content << plaintext[:head]
+        content << plaintext[:body]
+        content << @@endnotes[:end] if @@endnotes_
+        content << "#{break_line}#{divider*@wrap_width}#{break_line}"
+        content << plaintext[:metadata]
+        content << "#{break_line}#{divider*@wrap_width}#{break_line}" if @md.stmp =~/\w+/ #not used?
+        content << plaintext[:tail]
+        outputfile=SiSU_Env::FileOp.new(@md).write_file.rst
+        Txt_Output::Output.new.document(content,outputfile)
+        @@endnotes={ para: [], end: [] }
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+*** txt_rst_decorate.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/txt_rst_decorate.rb"
+# <<sisu_document_header>>
+module SiSU_Decorate_Txt_rST
+  def decorate
+    def heading
+      def underscore
+        def l0
+          '='
+        end
+        def l1
+          '-'
+        end
+        def l2
+          '`'
+        end
+        def l3
+          ':'
+        end
+        def l4
+          "'"
+        end
+        def l5
+          '"'
+        end
+        self
+      end
+      self
+    end
+    def bold
+      def open
+        '*'
+      end
+      def close
+        '*'
+      end
+      self
+    end
+    def italics
+      def open
+        '/'
+      end
+      def close
+        '/'
+      end
+      self
+    end
+    def underscore
+      def open
+        '_'
+      end
+      def close
+        '_'
+      end
+      self
+    end
+   #def emphasis
+   #  def open
+   #    ''
+   #  end
+   #  def close
+   #    ''
+   #  end
+   #  self
+   #end
+    def cite
+      def open
+        '"'
+      end
+      def close
+        '"'
+      end
+      self
+    end
+    def insert
+      def open
+        '+'
+      end
+      def close
+        '+'
+      end
+      self
+    end
+    def strike
+      def open
+        '-'
+      end
+      def close
+        '-'
+      end
+      self
+    end
+    def superscript
+      def open
+        '^'
+      end
+      def close
+        '^'
+      end
+      self
+    end
+    def subscript
+      def open
+        '['
+      end
+      def close
+        ']'
+      end
+      self
+    end
+    def hilite
+      def open
+        '*'
+      end
+      def close
+        '*'
+      end
+      self
+    end
+    def monospace
+      def open
+        '#'
+      end
+      def close
+        '#'
+      end
+      self
+    end
+    self
+  end
+end
+__END__
+#+END_SRC
+
+** textile
+*** txt_textile.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/txt_textile.rb"
+# <<sisu_document_header>>
+module SiSU_Txt_Textile
+  require_relative 'ao'                                 # ao.rb
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'shared_metadata'                    # shared_metadata.rb
+  require_relative 'generic_parts'                      # generic_parts.rb
+  require_relative 'txt_read'                           # txt_read.rb
+  require_relative 'txt_shared'                         # txt_shared.rb
+  require_relative 'txt_textile_decorate'               # txt_textile_decorate.rb
+  require_relative 'txt_output'                         # txt_output.rb
+  include SiSU_Param
+  @@alt_id_count,@@alt_id_count=0,0
+  @@tablefoot=''
+  class Source
+    include SiSU_Txt_Read
+    #include SiSU_Parts_Generic
+    def initialize(opt)
+      @opt=opt
+      unless @opt.fns =~/(.+?)\.(?:-|ssm\.)?sst$/
+        puts "#{sf} not a processed file type"
+      end
+    end
+    def read
+      begin
+        md=SiSU_Param::Parameters.new(@opt).get
+        specific={
+          description:     'Textile (plaintext utf-8)',
+          output_path:     md.file.output_path.textile.dir,
+          output_file:     md.file.base_filename.textile,
+        }
+        read_generic(@opt,specific)
+        SiSU_Txt_Textile::Source::Scroll.new(md,@ao_array,@wrap_width).songsheet
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    private
+    class Scroll <Source
+      include SiSU_Parts_Generic
+      include SiSU_TextUtils
+      include SiSU_Decorate_Txt_Textile
+      @@endnotes={ para: [], end: [] }
+      def initialize(md,data,wrap_width)
+        @md,@data,@wrap_width=md,data,wrap_width
+        @env=SiSU_Env::InfoEnv.new(@md.fns)
+        @tab="\t"
+        @@endnotes_=case md.opt.selections.str
+        when /--footnote/ then false
+        when /--endnote/  then true
+        else                   true
+        end
+        @plaintext={ body: [], open: [], close: [], head: [], metadata: [], tail: [] }
+      end
+      def songsheet
+        plaintext=markup(@data)
+        publish(plaintext)
+      end
+      def break_line
+        "\n"
+      end
+      # Used for extraction of endnotes from paragraphs
+      def extract_endnotes(dob='')
+        notes=dob.obj.scan(/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})([\d*+]+\s+.+?)(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/)
+        @n=[]
+        notes.flatten.each do |n| #high cost to deal with <br> appropriately within plaintext, consider
+          n=n.dup.to_s
+          if n =~/#{Mx[:br_line]}|#{Mx[:br_nl]}/
+            fix = n.split(/#{Mx[:br_line]}|#{Mx[:br_nl]}/) #watch #added
+            fix.each do |x|
+              unless x.empty?; @n << x
+              end
+            end
+          else                 @n << n
+          end
+        end
+        notes=@n.flatten
+        notes.each do |e|
+          util=(e.to_s =~/^\[[\d*+]+\]:/) \
+          ? (SiSU_TextUtils::Wrap.new(e.to_s,@wrap_width,4,1))
+          : (SiSU_TextUtils::Wrap.new(e.to_s,@wrap_width,1,1))
+          wrap=util.line_wrap
+          wrap=if wrap =~ /^\s*[\d*+]+\s+.+?\s*\Z/m
+            wrap.gsub(/^(\s*)([\d*+]+)\s+(.+?)\s*\Z/m, <<-GSUB
+\\1[\\2]: \\3
+              GSUB
+            )
+          else
+            wrap.gsub(/^(.+)\Z/m, <<-GSUB
+\\1
+              GSUB
+            )
+          end
+          @@endnotes[:para] << "-#{wrap}"
+          @@endnotes[:end] << '' << wrap
+        end
+        @@endnotes
+      end
+      def plaintext_metadata
+        array=SiSU_Metadata::Summary.new(@md).plaintext.metadata
+        array.each do |meta|
+          tag,inf=meta.scan(/^.+?:\s|.+/)
+          if tag and inf
+            util=SiSU_TextUtils::Wrap.new(inf,@wrap_width,15,1)
+            txt=util.line_wrap
+            @plaintext[:metadata] <<<<WOK
+
+#{@tab}#{tag}#{txt}
+WOK
+          end
+        end
+      end
+      def plaintext_tail
+#       env=SiSU_Env::InfoEnv.new(@md.fns)
+        generator="Generated by: #{@md.project_details.project} #{@md.project_details.version} of #{@md.project_details.date_stamp} (#{@md.project_details.date})"  if @md.project_details.version
+        lastdone="Last Generated on: #{Time.now}"
+        rubyv="Ruby version: #{@md.ruby_version}"
+        sc=if @md.sc_info
+          "Source file:    #{@md.sc_filename}#{break_line}Version number: #{@md.sc_number}#{break_line}Version date:   #{@md.sc_date}#{break_line}"
+        else ''
+        end
+        @plaintext[:tail] <<<<WOK
+#{break_line}
+plaintext (plain text):
+   #{@md.file.output_path.textile.url}/#{@md.file.base_filename.textile}#{break_line}
+Other versions of this document: #{break_line}
+manifest:
+   #{@md.file.output_path.manifest.url}/#{@md.file.base_filename.manifest}#{break_line}
+at:
+   #{@md.file.output_path.base.url}#{break_line}
+
+#{sc}
+,* #{generator}
+,* #{rubyv}
+,* #{lastdone}
+,* SiSU #{the_url.sisu_txt}
+WOK
+      end
+      def heading_decorated_inline(dob)
+        if dob.is==:heading
+          heading_inline = case dob.lc
+          when 0 then decorate.heading.inline.l0
+          when 1 then decorate.heading.inline.l1
+          when 2 then decorate.heading.inline.l2
+          when 3 then decorate.heading.inline.l3
+          when 4 then decorate.heading.inline.l4
+          when 5 then decorate.heading.inline.l5
+          when 6 then decorate.heading.inline.l6
+          end
+          heading_inline + ' ' +  dob.obj
+        end
+      end
+      def plaintext_structure(dob='',p_num='') #% Used to extract the structure of a document
+        util=nil
+        wrapped=if dob.is==:para \
+        || dob.is==:heading
+          if dob.is==:heading
+            util=SiSU_TextUtils::Wrap.new(heading_decorated_inline(dob),@wrap_width,0,0)
+          elsif dob.is==:para
+            if dob.hang \
+            and dob.hang =~/[0-9]/ \
+            and dob.indent != dob.hang
+              util=SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,dob.indent.to_i*2,dob.hang.to_i*2)
+              #util=SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,dob.hang.to_i*2,0)
+            elsif dob.indent =~/[1-9]/
+              util=if dob.bullet_
+                SiSU_TextUtils::Wrap.new("* #{dob.obj}",@wrap_width,dob.indent.to_i*2)
+              else SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,dob.indent.to_i*2)
+              end
+            else
+              util=if dob.bullet_
+                SiSU_TextUtils::Wrap.new("* #{dob.obj}",@wrap_width,0)
+              else SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,0)
+              end
+            end
+          else util=SiSU_TextUtils::Wrap.new(dob.obj,@wrap_width,0)
+          end
+          dob.is==:heading ? util.no_wrap_no_breaks : util.line_wrap
+        end
+        @plaintext[:body] << wrapped + p_num << break_line # main text, contents, body KEEP
+        if @@endnotes[:para] \
+        and not @@endnotes_
+          @@endnotes[:para].each {|e| @plaintext[:body] << e << break_line}
+        elsif @@endnotes[:para] \
+        and @@endnotes_
+        end
+        @@endnotes[:para]=[]
+      end
+      def markup(data)                                                       # Used for major markup instructions
+        SiSU_Env::InfoEnv.new(@md.fns)
+        @data_mod,@endnotes,@level,@cont,@copen,@plaintext_contents_close=Array.new(6){[]}
+        (0..6).each { |x| @cont[x]=@level[x]=false }
+        (4..6).each { |x| @plaintext_contents_close[x]='' }
+        plaintext_tail #($1,$2)
+        plaintext_metadata
+        table_message='[table conversion awaited, see other document formats]'
+        data.each do |dob|
+          dob.obj=dob.obj.gsub(/#{Mx[:gr_o]}Th?#{Mx[:tc_p]}.+/um,"#{break_line}#{table_message}"). #fix
+            gsub(/.+?#{Mx[:gl_o]}-##{Mx[:gl_c]}/,'').                              # remove dummy headings (used by html) #check also [~-]#
+            gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,
+              "#{decorate.bold.open}\\1#{decorate.bold.close}").
+            gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,
+              "#{decorate.italics.open}\\1#{decorate.italics.close}").
+            gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,
+              "#{decorate.underscore.open}\\1#{decorate.underscore.close}").
+            gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,
+              "#{decorate.subscript.open}\\1#{decorate.subscript.close}").
+            gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,
+              "#{decorate.superscript.open}\\1#{decorate.superscript.close}").
+            gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,
+              "#{decorate.insert.open}\\1#{decorate.insert.close}").
+            gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,
+              "#{decorate.cite.open}\\1#{decorate.cite.close}").
+            gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,
+              "#{decorate.strike.open}\\1#{decorate.strike.close}").
+            gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,
+              "#{decorate.monospace.open}\\1#{decorate.monospace.close}")
+          unless dob.is==:code
+            dob.obj=dob.obj.gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}/,'\1').
+              gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,'\1').
+              gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,'\1 [link: <\2>]').
+              gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}image/,'\1 [link: local image]').
+              gsub(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,"#{the_text.url_open}\\1#{the_text.url_close}")
+            extract_endnotes(dob)
+            dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'[^\1]'). # endnote marker marked up
+              gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'[^\1]'). # endnote marker marked up
+              gsub(/#{Mx[:gl_o]}(?:#lt|#060)#{Mx[:gl_c]}/,'<').
+              gsub(/#{Mx[:gl_o]}(?:#gt|#062)#{Mx[:gl_c]}/,'>').
+              gsub(/#{Mx[:gl_o]}#(?:038|amp)#{Mx[:gl_c]}/,'&').
+              gsub(/#{Mx[:gl_o]}#033#{Mx[:gl_c]}/,'!').
+              gsub(/#{Mx[:gl_o]}#035#{Mx[:gl_c]}/,'#').
+              gsub(/#{Mx[:gl_o]}#042#{Mx[:gl_c]}/,'*').
+              gsub(/#{Mx[:gl_o]}#045#{Mx[:gl_c]}/,'-').
+              gsub(/#{Mx[:gl_o]}#047#{Mx[:gl_c]}/,'/').
+              gsub(/#{Mx[:gl_o]}#095#{Mx[:gl_c]}/,'_').
+              gsub(/#{Mx[:gl_o]}#123#{Mx[:gl_c]}/,'{').
+              gsub(/#{Mx[:gl_o]}#125#{Mx[:gl_c]}/,'}').
+              gsub(/#{Mx[:gl_o]}#126#{Mx[:gl_c]}/,'~').
+              gsub(/#{Mx[:gl_o]}#169#{Mx[:gl_c]}/,'©').
+              gsub(/#{Mx[:gl_o]}#092#{Mx[:gl_c]}/,'\\')
+          end
+          dob.obj=if dob.of==:block                                   # watch
+            dob.obj.gsub(/#{Mx[:gl_o]}●#{Mx[:gl_c]}/m,"* ").
+              gsub(/\n?#{Mx[:br_line]}\n?|\n?#{Mx[:br_nl]}\n?/m,break_line)
+          else dob.obj.gsub(/\n?#{Mx[:br_line]}\n?|\n?#{Mx[:br_nl]}\n?/m,break_line*2)
+          end
+          if dob.is==:code
+            dob.obj=dob.obj.gsub(/(^|[^}])_([<>])/m,'\1\2'). # _> _<
+              gsub(/(^|[^}])_([<>])/m,'\1\2') # _<_<
+          end
+          dob.obj=dob.obj.gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,'\1').
+            gsub(/<a href=".+?">(.+?)<\/a>/m,'\1').
+            gsub(/#{Mx[:mk_o]}:name#(\S+?)#{Mx[:mk_c]}/,'').                       # remove name links
+            gsub(/&nbsp;|#{Mx[:nbsp]}/,' ').                                       # decide on
+            gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}(\S+?\.(?:png|jpg|gif)) .+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/,'    [ \1 ]'). #"[ #{dir.url.images_local}\/\\1 ]")
+            gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}(\S+?\.(?:png|jpg|gif)) .+?#{Mx[:lnk_c]}image/,'    [ \1 ]').
+            gsub(/(?:^|[^_\\])\{\s*\S+?\.(?:png|jpg|gif)\s+.+?"(.*?)"\s*\}\S+/,'[image: "\1"]')
+          if dob.obj !~/(^#{Rx[:meta]}|#{Mx[:br_eof]}|#{Mx[:br_endnotes]})/
+            p_num=''
+            #ocn
+            if dob.is==:heading \
+            or dob.is==:para
+              plaintext_structure(dob,p_num)
+            elsif dob.is==:group \
+            or dob.is==:block \
+            or dob.is==:verse \
+            or dob.is==:code \
+            or dob.is==:table
+              @plaintext[:body] << dob.obj + p_num << break_line
+            elsif dob.is==:break
+              sp=' '
+              ln='-'
+              @plaintext[:body] <<=if dob.obj==Mx[:br_page] \
+              or dob.obj==Mx[:br_page_new] \
+              or dob.obj==Mx[:br_page_line]
+                "#{break_line}#{ln*40}#{break_line*2}"
+              elsif dob.obj ==Mx[:br_obj]
+                "#{break_line}#{sp*20}*  *  *#{break_line*2}"
+              end # following empty line (break_line) missing, fix
+            end
+            dob='' if (dob.obj =~/<a name="n\d+">/ \
+              and dob.obj =~/^(-\{{2}~\d+|<!e[:_]\d+!>)/) # -endnote
+            if dob ## Clean Prepared Text
+              dob.obj=dob.obj.gsub(/<!.+!>/,' ').
+                gsub(/<:\S+>/,' ')
+            end
+          end
+        end
+        @plaintext
+      end
+      def publish(plaintext)
+        divider='='
+        content=[]
+        content << plaintext[:open]
+        content << plaintext[:head]
+        content << plaintext[:body]
+        content << @@endnotes[:end] if @@endnotes_
+        content << "#{break_line}#{divider*@wrap_width}#{break_line}"
+        content << plaintext[:metadata]
+        content << "#{break_line}#{divider*@wrap_width}#{break_line}" if @md.stmp =~/\w+/ #not used?
+        content << plaintext[:tail]
+        outputfile=SiSU_Env::FileOp.new(@md).write_file.textile
+        Txt_Output::Output.new.document(content,outputfile)
+        @@endnotes={ para: [], end: [] }
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+*** txt_textile_decorate.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/txt_textile_decorate.rb"
+# <<sisu_document_header>>
+module SiSU_Decorate_Txt_Textile
+  def decorate
+    def heading
+      def inline
+        def l0
+          'h1. '
+        end
+        def l1
+          'h2. '
+        end
+        def l2
+          'h3. '
+        end
+        def l3
+          'h4. '
+        end
+        def l4
+          'h5. '
+        end
+        def l5
+          'h6. '
+        end
+        self
+      end
+      self
+    end
+    def bold
+      def open
+        '*'
+      end
+      def close
+        '*'
+      end
+      self
+    end
+    def italics
+      def open
+        '_'
+      end
+      def close
+        '_'
+      end
+      self
+    end
+    def underscore
+      def open
+        '+'
+      end
+      def close
+        '+'
+      end
+      self
+    end
+   #def emphasis
+   #  def open
+   #    ''
+   #  end
+   #  def close
+   #    ''
+   #  end
+   #  self
+   #end
+    def cite
+      def open
+        '"'
+      end
+      def close
+        '"'
+      end
+      self
+    end
+    def insert
+      def open
+        ''
+      end
+      def close
+        ''
+      end
+      self
+    end
+    def strike
+      def open
+        '-'
+      end
+      def close
+        '-'
+      end
+      self
+    end
+    def superscript
+      def open
+        '^'
+      end
+      def close
+        '^'
+      end
+      self
+    end
+    def subscript
+      def open
+        '~'
+      end
+      def close
+        '~'
+      end
+      self
+    end
+    def hilite
+      def open
+        '*'
+      end
+      def close
+        '*'
+      end
+      self
+    end
+    def monospace
+      def open
+        ''
+      end
+      def close
+        ''
+      end
+      self
+    end
+    self
+  end
+end
+__END__
+#+END_SRC
+
+* txt_output.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/txt_output.rb"
+# <<sisu_document_header>>
+module Txt_Output
+  class Output
+    include SiSU_Param
+    include SiSU_Env
+    def document(content,outputfile)
+      emptyline=0
+      content.each do |para|           # this is a hack
+        if para.is_a?(Array) \
+        and para.length > 0
+          para.each do |line|
+            if line
+              line=line.gsub(/[ \t]+$/m,'').
+                gsub(/^\A[ ]*\Z/m,'')
+              (line=~/^\A\Z/) \
+              ? (emptyline+=1)
+              : emptyline=0
+              if emptyline < 2         #remove additional empty lines
+                outputfile.puts line
+              end
+            end
+          end
+        else outputfile.puts para      #unix plaintext # /^([*=-]|\.){5}/
+        end
+      end
+      outputfile.close
+    end
+  end
+end
+__END__
+
+#+END_SRC
+
+* txt_read.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/txt_read.rb"
+# <<sisu_document_header>>
+module SiSU_Txt_Read
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  def read_generic(opt,specific)
+    begin
+      env=SiSU_Env::InfoEnv.new(opt.fns)
+      unless opt.act[:quiet][:set]==:on
+        tool=(opt.act[:verbose][:set]==:on \
+        || opt.act[:verbose_plus][:set]==:on \
+        || opt.act[:maintenance][:set]==:on) \
+        ? "#{env.program.text_editor} #{specific[:output_path]}/#{specific[:output_file]}"
+        : "[#{opt.f_pth[:lng_is]}] #{opt.fno}"
+        (opt.act[:verbose][:set]==:on \
+        || opt.act[:verbose_plus][:set]==:on \
+        || opt.act[:maintenance][:set]==:on) \
+        ? SiSU_Screen::Ansi.new(
+            opt.act[:color_state][:set],
+            specific[:description],
+            tool
+          ).green_hi_blue
+        : SiSU_Screen::Ansi.new(
+            opt.act[:color_state][:set],
+            specific[:description],
+            tool
+          ).green_title_hi
+        if (opt.act[:verbose_plus][:set]==:on \
+        || opt.act[:maintenance][:set]==:on)
+          SiSU_Screen::Ansi.new(
+            opt.act[:color_state][:set],
+            opt.fns,
+            "#{specific[:output_path]}/#{specific[:output_file]}"
+          ).flow
+        end
+      end
+      @ao_array=SiSU_AO::Source.new(opt).get # ao file drawn here
+      @wrap_width=if defined? md.make.plaintext_wrap \
+      and md.make.plaintext_wrap
+        md.make.plaintext_wrap
+      elsif defined? env.plaintext_wrap \
+      and env.plaintext_wrap
+        env.plaintext_wrap
+      else 78
+      end
+      #wrap_width=(defined? md.make.plaintext_wrap) ? md.make.plaintext_wrap : 78
+    rescue
+      SiSU_Errors::Rescued.new($!,$@,opt.selections.str,opt.fns).location do
+        __LINE__.to_s + ':' + __FILE__
+      end
+    ensure
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* txt_shared.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/txt_shared.rb"
+# <<sisu_document_header>>
+module SiSU_TextUtils
+  require_relative 'generic_parts'                      # generic_parts.rb
+  class Wrap
+    def initialize(para='',n_char_max=76,n_indent=0,n_hang=nil,post='')
+      @para,@n_char_max,@n_indent,@post,=para,n_char_max,n_indent,post
+      @n_char_max_extend = n_char_max
+      @n_hang=n_hang ? n_hang : @n_indent
+    end
+    def break_line
+      "\n"
+    end
+    def line_wrap
+      space=' '
+      spaces_indent,spaces_hang="#{break_line}#{space*@n_indent}",space*@n_hang
+      line=0
+      out=[]
+      out[line]=''
+      @para=@para.gsub(/<br>/,' \\ ').
+        gsub(/#{Mx[:br_nl]}/,"\n\n")
+      words=@para.scan(/\n\n|\s+\\\s+|<br>|\S+/m)
+      while words != ''
+        word=words.shift
+        if not word
+          out[line] unless out[line].empty? #check
+          break
+        elsif word =~/<br>/
+          word=nil
+          out[line]=out[line].gsub(/<br>/,'')
+          line=line
+        elsif word =~/\n\n/
+          word="\n"
+          @n_char_max_extend = @n_char_max
+          line += 1
+        elsif (out[line].length + word.length) > (@n_char_max_extend - @n_indent) \
+        and out[line] =~/\S+/
+          @n_char_max_extend = @n_char_max
+          out[line].squeeze!(' ')
+          line += 1
+        end
+        if word
+          out[line]=if out[line] \
+          and out[line] !~/\S+$/m
+            "#{out[line]}#{word}"
+          elsif out[line] \
+          and out[line] =~/\S+/
+            "#{out[line]} #{word}"
+          else "#{word.strip}"
+          end
+        end
+        @oldword=word if word =~/\S+/
+      end
+      post=(@post.empty?) \
+      ? ''
+      : "\n" + (' '*@n_indent) +@post
+      spaces_hang + out.join(spaces_indent) + post
+    end
+    def line_wrap_indent1
+      @n_indent,@n_hang=2,2
+      line_wrap
+    end
+    def line_wrap_endnote
+      @n_indent,@n_hang=4,2
+      line_wrap
+    end
+    def array_wrap
+      if @para.is_a?(Array)
+        @arr=[]
+        @para.each do |line|
+          @arr << SiSU_TextUtils::Wrap.new(line,@n_char_max,@n_indent,@n_hang).line_wrap
+        end
+      end
+      @arr
+    end
+    def no_wrap
+      @para
+    end
+    def no_wrap_no_breaks
+      @para.gsub(/\n/m,' ').gsub(/\s\s+/,' ')
+    end
+  end
+  class HeaderScan
+    def initialize(md,para)
+      @md,@p=md,para
+    end
+    def extract(tag,tag_content,type,attrib)
+      if dc_tag \
+      and dc_content
+        [dc_tag,dc_content,{dc_tag=>dc_content}]
+      else nil
+      end
+    end
+    def header(tag,tag_content,type='',attrib='') #this will break stuff and must be tested thoroughly 20060825
+      @tag,@tag_content,@type,@attrib=tag,tag_content,type,attrib
+      def label #element
+        @tag
+      end
+      def type
+        @type
+      end
+      def text
+        @tag_content
+      end
+      def info  #element text
+        @tag_content
+      end
+      def attribute
+        @attrib
+      end
+      def element
+        @tag
+      end
+      def attrib
+        @attrib
+      end
+      def el
+        @tag
+      end
+      self
+    end
+    def start_is_match
+      case @p
+      when /^#{Mx[:meta_o]}(title)#{Mx[:meta_c]}\s*(.+?)$/               then header($1,@md.title.full,'meta','dc') #dc 1
+      when /^#{Mx[:meta_o]}(creator|author)#{Mx[:meta_c]}\s*(.+?)$/      then header('creator',$2,'meta','dc')    #dc 2
+      when /^#{Mx[:meta_o]}(subject)#{Mx[:meta_c]}\s*(.+?)$/             then header($1,$2,'meta','dc')           #dc 3
+      when /^#{Mx[:meta_o]}(description)#{Mx[:meta_c]}\s*(.+?)$/         then header($1,$2,'meta','dc')           #dc 4
+      when /^#{Mx[:meta_o]}(publisher)#{Mx[:meta_c]}\s*(.+?)$/           then header($1,$2,'meta','dc')           #dc 5
+      when /^#{Mx[:meta_o]}(contributor)#{Mx[:meta_c]}\s*(.+?)$/         then header($1,$2,'meta','dc')           #dc 6
+      when /^#{Mx[:meta_o]}(date)#{Mx[:meta_c]}\s*(.+?)$/                then header($1,$2,'meta','dc')           #dc 7
+      when /^#{Mx[:meta_o]}(date\.created)#{Mx[:meta_c]}\s*(.+?)$/       then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(date\.issued)#{Mx[:meta_c]}\s*(.+?)$/        then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(date\.available)#{Mx[:meta_c]}\s*(.+?)$/     then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(date\.valid)#{Mx[:meta_c]}\s*(.+?)$/         then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(date\.modified)#{Mx[:meta_c]}\s*(.+?)$/      then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(type)#{Mx[:meta_c]}\s*(.+?)$/                then header($1,$2,'meta','dc')           #dc 8
+      when /^#{Mx[:meta_o]}(format)#{Mx[:meta_c]}\s*(.+?)$/              then header($1,$2,'meta','dc')           #dc 9
+      when /^#{Mx[:meta_o]}(identifier)#{Mx[:meta_c]}\s*(.+?)$/          then header($1,$2,'meta','dc')           #dc 10
+      when /^#{Mx[:meta_o]}(source)#{Mx[:meta_c]}\s*(.+?)$/              then header($1,$2,'meta','dc')           #dc 11
+      when /^#{Mx[:meta_o]}(language)#{Mx[:meta_c]}\s*(.+?)$/            then header($1,$2,'meta','dc')           #dc 12
+      when /^#{Mx[:meta_o]}(relation)#{Mx[:meta_c]}\s*(.+?)$/            then header($1,$2,'meta','dc')           #dc 13
+      when /^#{Mx[:meta_o]}(coverage)#{Mx[:meta_c]}\s*(.+?)$/            then header($1,$2,'meta','dc')           #dc 14
+      when /^#{Mx[:meta_o]}(rights)#{Mx[:meta_c]}\s*(.+?)$/              then header($1,$2,'meta','dc')           #dc 15
+      when /^#{Mx[:meta_o]}(keywords)#{Mx[:meta_c]}\s*(.+?)$/            then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(copyright)#{Mx[:meta_c]}\s*(.+?)$/           then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(translator|translated_by)#{Mx[:meta_c]}\s*(.+?)$/   then header('translator',$2)
+      when /^#{Mx[:meta_o]}(illustrator|illustrated_by)#{Mx[:meta_c]}\s*(.+?)$/ then header('illustrator',$2)
+      when /^#{Mx[:meta_o]}(prepared_by)#{Mx[:meta_c]}\s*(.+?)$/         then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(digitized_by)#{Mx[:meta_c]}\s*(.+?)$/        then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(comments?)#{Mx[:meta_c]}\s*(.+?)$/           then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(abstract)#{Mx[:meta_c]}\s*(.+?)$/            then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(tags?)#{Mx[:meta_c]}\s*(.+?)$/               then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(catalogue)#{Mx[:meta_c]}\s*(.+?)$/           then header($1,$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(class(?:ify)?_loc)#{Mx[:meta_c]}\s*(.+?)$/   then header('classify_loc',$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(class(?:ify)?_dewey)#{Mx[:meta_c]}\s*(.+?)$/ then header('classify_dewey',$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(class(?:ify)?_pg)#{Mx[:meta_c]}\s*(.+?)$/    then header('classify_pg',$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(class(?:ify)?_isbn)#{Mx[:meta_c]}\s*(.+?)$/  then header('classify_isbn',$2,'meta','extra')
+      when /^#{Mx[:meta_o]}(toc|structure)#{Mx[:meta_c]}\s*(.+?)$/       then header('structure',$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(level|page|markup)#{Mx[:meta_c]}\s*(.+?)$/   then header('markup',$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(bold)#{Mx[:meta_c]}\s*(.+?)$/                then header($1,$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(italics|itali[sz]e)#{Mx[:meta_c]}\s*(.+?)$/  then header('italicize',$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(vocabulary|wordlist)#{Mx[:meta_c]}\s*(.+?)$/ then header('vocabulary',$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(css|stylesheet)#{Mx[:meta_c]}\s*(.+?)$/      then header('css',$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(links)#{Mx[:meta_c]}\s*(.+?)$/               then header($1,$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(prefix)#{Mx[:meta_c]}\s*(.+?)$/              then header($1,$2,'process','instruct') #add a & b
+      when /^#{Mx[:meta_o]}(suffix)#{Mx[:meta_c]}\s*(.+?)$/              then header($1,$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(information)#{Mx[:meta_c]}\s*(.+?)$/         then header($1,$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(contact)#{Mx[:meta_c]}\s*(.+?)$/             then header($1,$2,'process','instruct')
+      when /^#{Mx[:meta_o]}(rcs|cvs)#{Mx[:meta_c]}\s*(.+?)$/             then header('version',$2,'process','instruct')
+      else nil
+      end
+    end
+    def dublin
+      if @p =~/^#{Mx[:meta_o]}\S+?#{Mx[:meta_c]}/
+        start_is_match
+      else nil
+      end
+    end
+    def meta
+      if @p =~/^#{Mx[:meta_o]}\S+?#{Mx[:meta_c]}/
+        start_is_match
+      else nil
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    txt
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/utils.org b/org/utils.org
new file mode 100644
index 00000000..e709bcfe
--- /dev/null
+++ b/org/utils.org
@@ -0,0 +1,857 @@
+-*- mode: org -*-
+#+TITLE:       sisu utils
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:utils:
+#+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
+
+* utils
+** utils.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/utils.rb"
+# <<sisu_document_header>>
+module SiSU_Utils
+  class CodeMarker
+    def initialize(line,file,color=:red)
+      @line,@file,@color=line.to_s,file,color
+    end
+    def ansi(color=nil)
+      @color=color ? color : @color
+      c={}
+      c[:on]=case @color
+      when :red         then ANSI_C[:red]
+      when :green       then ANSI_C[:green]
+      when :yellow      then ANSI_C[:yellow]
+      when :blue        then ANSI_C[:blue]
+      when :fuchsia     then ANSI_C[:fuchsia]
+      when :cyan        then ANSI_C[:cyan]
+      when :inv_red     then ANSI_C[:inv_red]
+      when :inv_green   then ANSI_C[:inv_green]
+      when :inv_yellow  then ANSI_C[:inv_yellow]
+      when :inv_blue    then ANSI_C[:inv_blue]
+      when :inv_fuchsia then ANSI_C[:inv_fuchsia]
+      when :inv_cyan    then ANSI_C[:inv_cyan]
+      when :b_red       then ANSI_C[:b_red]
+      when :b_green     then ANSI_C[:b_green]
+      when :b_yellow    then ANSI_C[:b_yellow]
+      when :b_blue      then ANSI_C[:b_blue]
+      when :b_fuchsia   then ANSI_C[:b_fuchsia]
+      when :b_cyan      then ANSI_C[:b_cyan]
+      else                   ANSI_C[:red]
+      end
+      c[:off]= ANSI_C[:off]
+      #ansi_color + @line.to_s + ansi_color_off + ' ' + @file.gsub(/([^\/]+$)/,"#{ansi_color}\\1#{ansi_color_off}")
+      c
+    end
+    def var(v,x)
+      h={ c: nil, m: '' }
+      if v.is_a?(Hash)
+        h[:c] = (defined? v[:c]) ? v[:c] : ''
+        h[:m] = (defined? v[:m]) ? v[:m] : ''
+      elsif (v.is_a?(Symbol) \
+      and x.is_a?(String))
+        if v.is_a?(Symbol)
+          h[:c]=v
+        elsif v.is_a?(String)
+          h[:m]=v
+        end
+        if x.is_a?(String)
+          h[:m]=x
+        end
+      elsif (v.is_a?(Symbol) \
+      or v.is_a?(String))
+        if v.is_a?(Symbol)
+          h[:c]=v
+        elsif v.is_a?(String)
+          h[:m]=v
+        end
+      end
+      h[:c] = (defined? h[:c]) ? h[:c] : ''
+      h[:m] = (defined? h[:m]) ? h[:m] : ''
+      h[:c]=ansi(h[:c])
+      h[:m]=message(h[:m])
+      h
+    end
+    def message(msg='')
+      @message=(msg.nil? || msg.empty?) \
+      ? ''
+      : ' ' + msg
+    end
+    def set(v=nil,x=nil)
+      v=var(v,x)
+      file,path=File.basename(@file),File.dirname(@file)
+      v[:c][:on] + @line + v[:c][:off] + ' ' \
+      + path + '/' \
+      + "#{v[:c][:on]}#{file}#{v[:c][:off]}" \
+      + v[:m]
+    end
+    def mark(v=nil,x=nil)
+      puts set(v,x)
+    end
+    def tell(v=nil,x=nil)
+      puts set(v,x)
+    end
+    def report(v=nil,x=nil)
+      puts set(v,x)
+    end
+    def ok(v=nil,x=nil)
+      if (v.is_a?(Symbol) \
+      and x.is_a?(String))
+        x= '*OK* ' + x
+      elsif v.is_a?(String)
+        v='*OK* ' + v
+        x=nil
+      else
+        v,x='*OK*',nil
+      end
+      puts set(v,x)
+    end
+    def warn(v=nil,x=nil)
+      if (v.is_a?(Symbol) \
+      and x.is_a?(String))
+        x="\n  " + '*WARN* ' + x
+      elsif v.is_a?(String)
+        v="\n  " + '*WARN* ' + v
+        x=nil
+      else
+        v,x='*WARN*',nil
+      end
+      puts set(v,x)
+    end
+    def error(v=nil,x=nil)
+      if (v.is_a?(Symbol) \
+      and x.is_a?(String))
+        x="\n  " + '*ERROR* ' + x
+      elsif v.is_a?(String)
+        v="\n  " + '*ERROR* ' + v
+        x=nil
+      else
+        v,x='*ERROR*',nil
+      end
+      STDERR.puts set(v,x)
+    end
+  end
+  class Path
+    def initialize(dir=Dir.pwd)
+      @dir=dir
+    end
+    def base_markup(call_path=nil)
+      call_path = call_path \
+      ? call_path \
+      : Dir.pwd
+      (/(\S+?)(?:\/(?:#{Px[:lng_lst_rgx]}))?$/).match(call_path)[1]
+    end
+    def base_markup_stub
+      m=/.+\/(?:src\/)?(\S+)/im
+      base_markup[m,1]
+    end
+    def image_src
+      if base_markup =~/sisupod\/doc[\/]?$/
+        base_markup.gsub(/\/doc[\/]?$/,'/image')
+      elsif FileTest.directory?("#{base_markup}/_sisu/image")
+        "#{base_markup}/_sisu/image"
+      end
+    end
+    def bmd
+      base_markup
+    end
+  end
+end
+__END__
+SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:green).mark({ m: %{
+  code: #{@@flag[:code]}, <-- close "#{t_o}"
+}})
+SiSU_Utils::CodeMarker.new(__LINE__,__FILE__).mark({ m: %{
+  code: #{@@flag['code']}, <-- close "#{t_o}"
+}, c: :green})
+SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:green).mark({ m: %{
+  code: #{@@flag['code']}, open --> "#{t_o}"
+}}) if t_o=~/^```/m
+SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:green).mark(%{ code: #{@@flag['code']}, open --> "#{t_o}" }) \
+if t_o=~/^```/m
+SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:green).mark("open -->")
+SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).mark("open -->")
+SiSU_Utils::CodeMarker.new(__LINE__,__FILE__).mark("open -->",:green)
+SiSU_Utils::CodeMarker.new(__LINE__,__FILE__).mark(:green,"open -->")
+SiSU_Utils::CodeMarker.new(__LINE__,__FILE__).mark("open -->")
+SiSU_Utils::CodeMarker.new(__LINE__,__FILE__).mark(:green)
+SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:green).mark
+SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:green).mark("open -->")
+SiSU_Utils::CodeMarker.new(__LINE__,__FILE__).mark('open -->',:green)
+SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:red).mark
+puts SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:red).set
+puts SiSU_Utils::CodeMarker.new(__LINE__,__FILE__).set('',:green)
+puts SiSU_Utils::CodeMarker.new(__LINE__,__FILE__).set('',:fuchsia)
+puts ANSI_C[:red] + __LINE__.to_s + ANSI_C[:off] + ' ' + __FILE__
+puts "#{ANSI_C[:red]} #{__LINE__.to_s} #{ANSI_C[:off]} #{__FILE__}"
+puts ANSI_C[:fuchsia] + __LINE__.to_s + ANSI_C[:off] + ' ' + __FILE__.gsub(/([^\/]+$)/,"#{ANSI_C[:fuchsia]}\\1#{ANSI_C[:off]}")
+puts ANSI_C[:red] + __LINE__.to_s + ANSI_C[:off] + ' ' + __FILE__.gsub(/([^\/]+$)/,"#{ANSI_C[:red]}\\1#{ANSI_C[:off]}")
+#+END_SRC
+
+** utils_spell.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/utils_spell.rb"
+# <<sisu_document_header>>
+module SiSU_SpellUtility
+  class Spell
+    def initialize(input,filesrc,flg)
+      @flg=flg
+      @filename, @filetype = /(.+?)(\.\w\w\w0$)/.match(filesrc)[1,2] #.gsub(/\.\w\w\w0$/, "")
+      @input=input
+      @allwords=[]
+      puts @filename
+      @speller='aspell' # 'ispell'
+      @dictionary='british'
+      @lang='en_GB'
+    end
+    def check
+      @input.each do |data|
+        data=data.gsub(/(https?|www|ftp|gopher|png|jpg|gif|html|htm)\S+/i,' ').
+          gsub(/(&nbsp;|#{Mx[:nbsp]})/i,' ').
+          gsub(/<\/?(table|tr|td|b|p|href).*?>/i,' ').
+          gsub(/(<==.+|<:\S+>|<!.+?!>|^@\S+?:.+|\{\{\{|~)/,' ').
+          gsub(/(["|<>)(\n'`.;&_-]|\=)/,' ').
+          gsub(/\b(altExternal|
+            target|externalimg|
+            srcimagebext|
+            img|src|toc|pdf|
+            cd|org|
+            helvetica|roman
+            )\b/i,' ').
+          gsub(/EOF/,'')
+        @words=data.scan(/\S+/)
+        @words.each { |y| @allwords << y }
+      end
+      @allwords=@allwords.uniq
+      if @flg =~ /S/
+        File.open('/home/ralph/spell_error','a+') do |file| #fix
+          file.puts %{\n\n[ #{@filename} ]}
+        end
+        @allwords.each { |y| puts y.inspect; system(%{cat #{y} | /usr/bin/#{@speller} -l -d #{@dictionary} >> ~/spell_error })}
+      else
+        @allwords.each { |y| sp=%x{echo #{y}|#{@speller} -l }; puts sp unless sp.empty?}
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** utils_response.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/utils_response.rb"
+# <<sisu_document_header>>
+module SiSU_Response
+  def available_selections_
+    %{'yes', 'no', 'quit' or 'exit'; [ynqx]}
+  end
+  def response?(ask)
+    response='redo'
+    print ask + %{ [#{available_selections_}]: }
+    response=File.new('/dev/tty').gets.strip
+    case response
+    when /^(?:y|yes)$/          then true
+    when /^(?:n|no)$/           then false
+    when /^(?:[qx]|quit|exit)$/ then exit
+    else puts %{[please type: #{available_selections_}]}
+      response?(ask)
+    end
+  end
+  def query
+    def selections_available_(selections=:strict)
+      short_options=(selections == :strict) ? '' : '; [ynqx]'
+      %{'yes', 'no', 'quit' or 'exit'#{short_options}}
+    end
+    def selection_options
+      def response_strict(resp)
+        case resp
+        when /^(?:yes)$/          then true
+        when /^(?:no)$/           then false
+        when /^(?:quit|exit)$/    then exit
+        else
+          puts %{response was: #{resp}}
+          puts %{[please type to select: #{selections_available_(:strict)}]}
+          answer?('',:strict)
+        end
+      end
+      def response_short(resp)
+        case resp
+        when /^(?:y|yes)$/          then true
+        when /^(?:n|no)$/           then false
+        when /^(?:[qx]|quit|exit)$/ then exit
+        else
+          puts %{response was: #{resp}}
+          puts %{[please type to select: #{selections_available_(:short)}]}
+          answer?('',:short)
+        end
+      end
+      self
+    end
+    def answer?(ask,selections=:strict)
+      resp='redo'
+      print ask + %{PROCEED? [#{selections_available_(selections)}]: }
+      resp=File.new('/dev/tty').gets.strip
+      (selections==:strict) \
+      ? selection_options.response_strict(resp)
+      : selection_options.response_short(resp)
+    end
+    self
+  end
+end
+__END__
+#+END_SRC
+
+** utils_composite.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/utils_composite.rb"
+# <<sisu_document_header>>
+module SiSU_Composite_Doc_Utils
+  def inserts_array(loadfilename)
+    IO.readlines(loadfilename,'')
+  end
+  def insert_filename?(para)
+    if para =~ /^<<\s+((?:https?|file):\/\/\S+?\.ss[it])$/ # and NetTest
+      url($1.strip)
+    elsif para =~/^<<\s*(\S+?\.ss[it])$/
+      $1.strip
+    end
+  end
+  def extract_filenames(loadfilename,file_names_arr)
+    file_names_arr << loadfilename
+    ssi_files=[]
+    if loadfilename =~/\S+?\.ss[im]$/
+      inserts_array(loadfilename).each do |para|
+        filen=insert_filename?(para)
+        file_names_arr << filen
+        if filen =~/\S+?\.ssi$/
+          ssi_files << filen
+        end
+      end
+    end
+    ssi_files.each do |fn|
+      extract_filenames(fn,file_names_arr)
+    end
+    file_names_arr.flatten.compact.uniq.sort
+  end
+  def composite_and_imported_filenames_array(loadfilename)
+    file_names_arr=[]
+    begin
+      if FileTest.file?(loadfilename)
+        if loadfilename =~/\S+?\.ss[itm]$/
+          if (@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on)
+            SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'loading:',
+              loadfilename,
+            ).txt_grey
+          end
+          file_names_arr=extract_filenames(loadfilename,file_names_arr)
+        end
+      end
+      if (@opt.act[:verbose_plus][:set]==:on \
+      || @opt.act[:maintenance][:set]==:on)
+        p file_names_arr ;p file_names_arr.length
+      end
+      file_names_arr
+    rescue
+      SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+        __LINE__.to_s + ':' + __FILE__
+      end
+    ensure
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** utils_screen_text_color.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/utils_screen_text_color.rb"
+# <<sisu_document_header>>
+module SiSU_Screen
+  class Color
+    attr_accessor :off,:marker,:bold,:underline,:invert,:darkgrey_hi,:grey_hi,:pink_hi,:fuchsia_hi,:red_hi,:orange_hi,:yellow_hi,:brown_hi,:lightgreen_hi,:green_hi,:cyan_hi,:blue_hi,:navy_hi,:white,:white_bold,:grey,:pink,:fuchsia,:ruby,:red,:orange,:yellow,:brown,:green,:darkgreen,:cyan,:blue,:navy,:black
+    def initialize(&block)
+      instance_eval &block
+    end
+  end
+  class Ansi < Color
+    attr_reader :cX
+    def initialize(color_state,*txt)
+      @color_state,@txt=color_state,txt
+      @color_instruct=txt[0]
+      @cX=@@cX=if color_state==:on
+        Color.new do
+          self.off=self.white=self.white_bold=self.marker=self.bold=self.underline=self.invert=self.darkgrey_hi=self.grey_hi=self.pink_hi=self.fuchsia_hi=self.red_hi=self.orange_hi=self.yellow_hi=self.brown_hi=self.lightgreen_hi=self.green_hi=self.cyan_hi=self.blue_hi=self.navy_hi=self.grey=self.pink=self.fuchsia=self.ruby=self.red=self.orange=self.yellow=self.brown=self.green=self.darkgreen=self.cyan=self.blue=self.navy=self.black=''
+        end
+      else                                                                       #default set to colors on
+        Color.new do
+          self.off           = "\033[0m"
+          self.white         = "\033[37m"
+          self.white_bold    = "\033[1m"
+          self.marker        = "\033[42m"
+          self.bold          = "\033[1m"
+          self.underline     = "\033[4m"
+          self.invert        = "\033[7m"
+          self.darkgrey_hi   = "\033[100m"
+          self.grey_hi       = "\033[47m"
+          self.pink_hi       = "\033[105m"
+          self.fuchsia_hi    = "\033[45m"
+          self.red_hi        = "\033[41m"
+          self.orange_hi     = "\033[101m"
+          self.yellow_hi     = "\033[103m"
+          self.brown_hi      = "\033[43m"
+          self.lightgreen_hi = "\033[102m"
+          self.green_hi      = "\033[42m"
+          self.cyan_hi       = "\033[106m"
+          self.blue_hi       = "\033[104m"
+          self.navy_hi       = "\033[44m"
+          self.grey          = "\033[90m"
+          self.pink          = "\033[95m"
+          self.fuchsia       = "\033[35m"
+          self.ruby          = "\033[31m"
+          self.red           = "\033[91m" #check
+          self.orange        = "\033[91m"
+          self.yellow        = "\033[93m"
+          self.brown         = "\033[33m"
+          self.green         = "\033[92m"
+          self.darkgreen     = "\033[32m"
+          self.cyan          = "\033[36m"
+          self.blue          = "\033[94m"
+          self.navy          = "\033[34m"
+          self.black         = "\033[30m"
+        end
+      end
+    end
+    def colors
+      0.upto(109) {|i| print "\033[#{i}m 33[#{i}m \033[m"}
+      puts ''
+    end
+    def color
+      case @color_instruct
+      when /invert/        then @cX.invert
+      when /darkgrey_hi/   then @cX.darkgrey_hi
+      when /grey_hi/       then @cX.grey_hi
+      when /pink_hi/       then @cX.pink_hi
+      when /fuchsia_hi/    then @cX.fuchsia_hi
+      when /red_hi/        then @cX.red_hi
+      when /orange_hi/     then @cX.orange_hi
+      when /yellow_hi/     then @cX.yellow_hi
+      when /brown_hi/      then @cX.brown_hi
+      when /lightgreen_hi/ then @cX.lightgreen_hi
+      when /green_hi/      then @cX.green_hi
+      when /cyan_hi/       then @cX.cyan_hi
+      when /blue_hi/       then @cX.blue_hi
+      when /navy_hi/       then @cX.navy_hi
+      when /white/         then @cX.white
+      when /grey/          then @cX.grey
+      when /pink/          then @cX.pink
+      when /fuchsia/       then @cX.fuchsia
+      when /ruby/          then @cX.ruby
+      when /red/           then @cX.red
+      when /orange/        then @cX.orange
+      when /yellow/        then @cX.yellow
+      when /brown/         then @cX.brown
+      when /green/         then @cX.green
+      when /darkgreen/     then @cX.darkgreen
+      when /cyan/          then @cX.cyan
+      when /blue/          then @cX.blue
+      when /navy/          then @cX.navy
+      when /close/         then @cX.off
+      when /off/           then @cX.off
+      end
+    end
+    def colorize
+      case @color_instruct
+      when /invert/        then puts "#{@cX.invert}#{@txt[1]}#{@cX.off} #{@cX.blue}#{@txt[2]}#{@cX.off} #{@cX.grey}#{@txt[3]}#{@cX.off}"
+      when /darkgrey_hi/   then puts "#{@cX.darkgrey_hi}#{@txt[1]}#{@cX.off} #{@cX.blue}#{@txt[2]}#{@cX.off} #{@cX.grey}#{@txt[3]}#{@cX.off}"
+      when /grey_hi/       then puts "#{@cX.grey_hi}#{@txt[1]}#{@cX.off} #{@cX.blue}#{@txt[2]}#{@cX.off} #{@cX.grey}#{@txt[3]}#{@cX.off}"
+      when /pink_hi/       then puts "#{@cX.pink_hi}#{@txt[1]}#{@cX.off} #{@cX.blue}#{@txt[2]}#{@cX.off} #{@cX.grey}#{@txt[3]}#{@cX.off}"
+      when /fuchsia_hi/    then puts "#{@cX.fuchsia_hi}#{@txt[1]}#{@cX.off} #{@cX.blue}#{@txt[2]}#{@cX.off} #{@cX.grey}#{@txt[3]}#{@cX.off}"
+      when /red_hi/        then puts "#{@cX.red_hi}#{@txt[1]}#{@cX.off} #{@cX.blue}#{@txt[2]}#{@cX.off} #{@cX.grey}#{@txt[3]}#{@cX.off}"
+      when /orange_hi/     then puts "#{@cX.orange_hi}#{@txt[1]}#{@cX.off} #{@cX.blue}#{@txt[2]}#{@cX.off} #{@cX.grey}#{@txt[3]}#{@cX.off}"
+      when /yellow_hi/     then puts "#{@cX.yellow_hi}#{@txt[1]}#{@cX.off} #{@cX.blue}#{@txt[2]}#{@cX.off} #{@cX.grey}#{@txt[3]}#{@cX.off}"
+      when /brown_hi/      then puts "#{@cX.brown_hi}#{@txt[1]}#{@cX.off} #{@cX.blue}#{@txt[2]}#{@cX.off} #{@cX.grey}#{@txt[3]}#{@cX.off}"
+      when /lightgreen_hi/ then puts "#{@cX.lightgreen_hi}#{@txt[1]}#{@cX.off} #{@cX.blue}#{@txt[2]}#{@cX.off} #{@cX.grey}#{@txt[3]}#{@cX.off}"
+      when /green_hi/      then puts "#{@cX.green_hi}#{@txt[1]}#{@cX.off} #{@cX.blue}#{@txt[2]}#{@cX.off} #{@cX.grey}#{@txt[3]}#{@cX.off}"
+      when /cyan_hi/       then puts "#{@cX.cyan_hi}#{@txt[1]}#{@cX.off} #{@cX.blue}#{@txt[2]}#{@cX.off} #{@cX.grey}#{@txt[3]}#{@cX.off}"
+      when /blue_hi/       then puts "#{@cX.blue_hi}#{@txt[1]}#{@cX.off} #{@cX.blue}#{@txt[2]}#{@cX.off} #{@cX.grey}#{@txt[3]}#{@cX.off}"
+      when /navy_hi/       then puts "#{@cX.navy_hi}#{@txt[1]}#{@cX.off} #{@cX.blue}#{@txt[2]}#{@cX.off} #{@cX.grey}#{@txt[3]}#{@cX.off}"
+      when /bold/          then puts "#{@cX.bold}#{@txt[1]}#{@cX.off} #{@cX.grey}#{@txt[2]}#{@cX.off}"
+      when /white/         then puts "#{@cX.off}#{@txt[1]} #{@txt[2]}"
+      when /grey/          then puts "#{@cX.grey}#{@txt[1]}#{@cX.off} #{@cX.grey}#{@txt[2]}#{@cX.off}"
+      when /pink/          then puts "#{@cX.pink}#{@txt[1]}#{@cX.off} #{@cX.grey}#{@txt[2]}#{@cX.off}"
+      when /fuchsia/       then puts "#{@cX.fuchsia}#{@txt[1]}#{@cX.off} #{@cX.grey}#{@txt[2]}#{@cX.off}"
+      when /ruby/          then puts "#{@cX.ruby}#{@txt[1]}#{@cX.off} #{@cX.grey}#{@txt[2]}#{@cX.off}"
+      when /red/           then puts "#{@cX.red}#{@txt[1]}#{@cX.off} #{@cX.grey}#{@txt[2]}#{@cX.off}"
+      when /orange/        then puts "#{@cX.orange}#{@txt[1]}#{@cX.off} #{@cX.grey}#{@txt[2]}#{@cX.off}"
+      when /yellow/        then puts "#{@cX.yellow}#{@txt[1]}#{@cX.off} #{@cX.grey}#{@txt[2]}#{@cX.off}"
+      when /brown/         then puts "#{@cX.brown}#{@txt[1]}#{@cX.off} #{@cX.grey}#{@txt[2]}#{@cX.off}"
+      when /green/         then puts "#{@cX.green}#{@txt[1]}#{@cX.off} #{@cX.grey}#{@txt[2]}#{@cX.off}"
+      when /darkgreen/     then puts "#{@cX.darkgreen}#{@txt[1]}#{@cX.off} #{@cX.grey}#{@txt[2]}#{@cX.off}"
+      when /cyan/          then puts "#{@cX.cyan}#{@txt[1]}#{@cX.off} #{@cX.grey}#{@txt[2]}#{@cX.off}"
+      when /blue/          then puts "#{@cX.blue}#{@txt[1]}#{@cX.off} #{@cX.grey}#{@txt[2]}#{@cX.off}"
+      when /navy/          then puts "#{@cX.navy}#{@txt[1]}#{@cX.off} #{@cX.grey}#{@txt[2]}#{@cX.off}"
+      end
+    end
+    def sourcename(sourcefilename)
+      @sourcefilename=sourcefilename
+    end
+    def basename(sourcefilename)
+      @basename=sourcefilename.sub(/\.(?:(?:-|ssm\.)?sst|ssm)$/,'')
+    end
+    def sisu
+    end
+    def rescue
+      STDERR.puts %{\t   #{@cX.orange}Rescued#{@cX.off} #{@cX.grey}#{yield if block_given?}\n\t   An#{@cX.off} #{@cX.fuchsia}ERROR#{@cX.off} #{@cX.grey}occurred, message:#{@cX.off} #{@cX.fuchsia}#{@txt[0]}#{@cX.off} #{@cX.grey}#{@txt[1]}#{@cX.off} #{@cX.brown}#{@txt[2]}#{@cX.off}}
+    end
+    def warn
+      STDERR.puts "\t  #{@cX.brown}#{@txt[0]}#{@cX.off} #{@cX.grey}#{@txt[1]}#{@cX.off}"
+    end
+    def error
+      STDERR.puts "\t  #{@cX.fuchsia}#{@txt[0]}#{@cX.off} #{@cX.brown}#{@txt[1]}#{@cX.off}"
+    end
+    def error2
+      STDERR.puts "\t  #{@cX.grey}#{@txt[0]}#{@cX.off} #{@cX.fuchsia}#{@txt[1]}#{@cX.off} #{@cX.grey}#{@txt[2]}#{@cX.off}"
+    end
+    def version
+      puts "#{@cX.blue_hi}#{@txt[0]} #{@txt[1]}#{@cX.off} #{@cX.grey} (#{@txt[3]} [#{@txt[2]}])#{@txt[4]} &#{@cX.off} #{@cX.ruby}Ruby#{@cX.off} #{@cX.grey}(#{@txt[5]})#{@cX.off}\n"
+    end
+    def html3numbers
+      puts %{\t#{@cX.green}#{@txt[0]}#{@cX.off} #{@cX.cyan}files processed#{@cX.off}. } +
+        %{#{@cX.grey}} +
+        %{scroll only: #{@txt[1]}, seg only: #{@txt[2]},} +
+        %{#{@cX.off} } +
+        %{#{@cX.cyan}joint scroll & seg: #{@txt[3]},#{@cX.off}} +
+        %{#{@cX.grey} } +
+        %{nav only: #{@txt[4]}} +
+        %{#{@cX.off}}
+    end
+    def html2numbers
+      puts %{\t#{@cX.green}#{@txt[0]}#{@cX.off} #{@cX.cyan}files processed#{@cX.off}. } +
+        %{#{@cX.grey}} +
+        %{scroll only: #{@txt[1]},} +
+        %{#{@cX.off} } +
+        %{#{@cX.cyan}seg only: #{@txt[2]},#{@cX.off}} +
+        %{#{@cX.grey} } +
+        %{joint scroll & seg: #{@txt[3]}, nav only: #{@n_files_nav}} +
+        %{#{@cX.off}}
+    end
+    def html1numbers
+      puts %{\t#{@cX.green}#{@txt[0]}#{@cX.off} #{@cX.cyan}files processed#{@cX.off}. } +
+        %{#{@cX.cyan}scroll only: #{@txt[1]},#{@cX.off}} +
+        %{#{@cX.grey} } +
+        %{seg only: #{@txt[2]}, } +
+        %{joint scroll & seg: #{@txt[3]}, nav only: #{@n_files_nav}} +
+        %{#{@cX.off}}
+    end
+    def html0_numbers
+      puts %{\t#{@cX.ruby}#{@txt[0]} files processed#{@cX.off}. } +
+        %{#{@cX.grey}} +
+        %{scroll only: #{@txt[1]}, seg only: #{@txt[2]}, joint scroll & seg: #{@txt[3]},} +
+        %{#{@cX.off} } +
+        %{#{@cX.cyan}nav only: #{@txt[4]}#{@cX.off}.}
+    end
+    def grey
+      puts "#{@cX.grey}#{@txt[0]}#{@cX.off} #{@cX.cyan}#{@txt[1]}#{@cX.off}"
+    end
+    def txt_white
+      puts "\t#{@cX.white}#{@txt[0]}#{@cX.off} #{@cX.white}#{@txt[1]}#{@cX.off}"
+    end
+    def txt_grey
+      puts "\t#{@cX.grey}#{@txt[0]}#{@cX.off} #{@cX.cyan}#{@txt[1]}#{@cX.off}"
+    end
+    def txt_cyan
+      puts "\t#{@cX.cyan}#{@txt[0]}#{@cX.off} #{@cX.grey}#{@txt[1]}#{@cX.off}"
+    end
+    def txt_blue
+      puts "\t#{@cX.blue}#{@txt[0]}#{@cX.off} #{@cX.grey}#{@txt[1]}#{@cX.off}"
+    end
+    def txt_red
+      puts "\t#{@cX.red}#{@txt[0]}#{@cX.off} #{@cX.cyan}#{@txt[1]}#{@cX.off}"
+    end
+    def txt_green
+      puts "\t#{@cX.green}#{@txt[0]}#{@cX.off} #{@cX.grey}#{@txt[1]}#{@cX.off}"
+    end
+    def url #clean
+      blue
+    end
+    def result
+      puts "\t#{@cX.grey}#{@txt[0]}#{@cX.off} #{@cX.green}#{@txt[1]}#{@cX.off} #{@cX.blue}#{@txt[2]}#{@cX.off}"
+    end
+    def maintenance
+      puts "\t#{@cX.grey}#{@txt[0]}#{@cX.off} #{@cX.brown}#{@txt[1]}#{@cX.off} #{@cX.grey}#{@txt[2]}#{@cX.off}"
+    end
+    def instruct
+      puts %{\t  #{@cX.grey}#{@txt[0]}#{@cX.off} #{@cX.cyan}#{@txt[1]}#{@cX.off} #{@cX.grey}#{@txt[2]}#{@cX.off} #{@cX.cyan}#{@txt[3]}#{@cX.off} #{@cX.grey}#{@txt[4]}#{@cX.off} "#{@cX.brown}#{@f}#{@cX.off}"}
+    end
+    def grey_open
+      print @cX.grey
+    end
+    def p_off
+      print @cX.off
+    end
+    def p_close
+      print @cX.off
+    end
+    def flow
+      puts %{\t#{@cX.grey}#{@txt[0]}#{@cX.off} #{@cX.ruby}->#{@cX.off}\n\t  #{@cX.blue}#{@txt[1]}#{@cX.off}}
+    end
+    def output
+      puts %{\t#{@cX.grey}#{@txt[0]}#{@cX.off} #{@cX.ruby}->#{@cX.off}\n\t  #{@cX.blue}#{@txt[1]}#{@cX.off}}
+    end
+    def generic
+      puts %{\t#{@cX.navy}#{@txt[0]} #{@txt[1]}#{@cX.off}. }
+    end
+    def files_processed
+      puts %{\t#{@cX.green}#{@txt[0]}#{@cX.off} #{@cX.grey}#{@txt[1]}#{@cX.off}}
+    end
+    def print_blue
+      print "#{@cX.blue}#{@txt[0]} #{@txt[1]}#{@cX.off}"
+    end
+    def puts_blue
+      puts "#{@cX.blue}#{@txt[0]} #{@txt[1]}#{@cX.off}"
+    end
+    def print_brown
+      print "#{@cX.brown}#{@txt[0]}#{@cX.off}"
+    end
+    def blue_tab
+      print  "\t#{@cX.blue}#{@txt[0]}#{@cX.off}\n"
+    end
+    def print_grey
+      print "#{@cX.grey}#{@txt[0]} #{@txt[1]}#{@cX.off}"
+    end
+    def puts_grey
+      puts "#{@cX.grey}#{@txt[0]} #{@txt[1]}#{@cX.off}"
+    end
+    def puts_brown
+      puts "#{@cX.brown}#{@txt[0]} #{@txt[1]}#{@cX.off}"
+    end
+    def grey_tab
+      print "\t#{@cX.grey}#{@txt[0]}#{@cX.off}\n"
+    end
+    def green_title
+      puts %{#{@cX.green}#{@txt[0]}#{@cX.off} #{@cX.grey}#{@txt[1]}#{@cX.off}}
+    end
+    def green_title_hi
+      puts %{#{@cX.green_hi}#{@cX.black}#{@txt[0]}#{@cX.off*2} #{@cX.grey}#{@txt[1]}#{@cX.off}}
+    end
+    def green_hi_blue
+      puts %{#{@cX.green_hi}#{@cX.black}#{@txt[0]}#{@cX.off*2} #{@cX.blue}#{@txt[1]}#{@cX.off}}
+    end
+    def blue_title_hi
+      puts %{#{@cX.blue_hi}#{@txt[0]}#{@cX.off*2} #{@cX.blue}#{@txt[1]}#{@cX.off}}
+    end
+    def grey_title_hi
+      puts %{#{@cX.grey_hi}#{@cX.black}#{@txt[0]}#{@cX.off*2} #{@cX.blue}#{@txt[1]}#{@cX.off}}
+    end
+    def grey_title_grey_blue
+      puts %{#{@cX.grey_hi}#{@cX.black}#{@txt[0]}#{@cX.off*2} #{@cX.grey}#{@txt[1]}#{@cX.off} #{@cX.blue}#{@txt[2]}#{@cX.off}}
+    end
+    def dark_grey_title_hi
+      puts %{#{@cX.darkgrey_hi}#{@cX.black}#{@txt[0]}#{@cX.off*2} #{@cX.blue}#{@txt[1]}#{@cX.off}}
+    end
+    def cyan_title_hi
+      puts %{#{@cX.cyan_hi}#{@cX.black}#{@txt[0]}#{@cX.off*2} #{@cX.blue}#{@txt[1]}#{@cX.off}}
+    end
+    def cyan_hi_blue
+      puts %{#{@cX.cyan_hi}#{@cX.black}#{@txt[0]}#{@cX.off*2} #{@cX.blue}#{@txt[1]}#{@cX.off}}
+    end
+    def dbi_title
+      puts %{#{@cX.blue_hi}#{@cX.black}#{@txt[0]}#{@cX.off*2} #{@cX.cyan}#{@cX.grey}#{@txt[1]}#{@cX.off*2} #{@cX.green}#{@txt[2]}#{@cX.off}}
+    end
+    def yellow_title_hi
+      puts %{#{@cX.yellow_hi}#{@cX.black}#{@txt[0]}#{@cX.off*2} #{@cX.blue}#{@txt[1]}#{@cX.off}}
+    end
+    def term_sheet_title
+      puts %{\t#{@cX.green}#{@txt[0]}#{@cX.off} #{@cX.red_hi}#{@cX.black}#{@txt[1]}.#{@cX.off*2} }
+    end
+    def generic_number
+      puts "#{@cX.green}#{@txt[0]}#{@cX.off} #{@cX.grey}#{@txt[1]}#{@cX.off}"
+    end
+    def tex_numbers
+      puts %{  #{@cX.green}#{@txt[0]}#{@cX.off} #{@cX.cyan}tex/pdf files processed#{@cX.off}.}
+    end
+    def tex_info_numbers
+      puts %{  #{@cX.green}#{@txt[0]}#{@cX.off} #{@cX.cyan}texinfo files processed#{@cX.off}.}
+    end
+    def lout_numbers
+      puts %{  #{@cX.green}#{@n_lout}#{@cX.off} #{@cX.cyan}lout/pdf files processed#{@cX.off}.}
+    end
+    def parameters
+    end
+    def reserved
+      puts %{ #{@cX.grey_hi}#{@cX.black}reserved#{@cX.off*2}}
+    end
+    def meta_verse_title
+      puts %{#{@cX.green_hi}#{@cX.black}MetaVerse#{@cX.off*2} }
+    end
+    def meta_verse_title_v
+      b=sourcename(@txt[0])
+      puts %{#{@cX.green_hi}#{@cX.black}MetaVerse#{@cX.off*2} } +
+        %{#{@cX.grey}#{@txt[0]}#{@cX.off} #{@cX.ruby}->#{@cX.off}\n\t  #{@cX.blue}~meta/#{b}.meta#{@cX.off}}
+    end
+    def meta_verse
+      puts "\t#{@cX.grey}MetaVerse#{@cX.off}"
+    end
+    def meta_verse_skipped
+      puts %{\t#{@cX.grey}MetaVerse: MarshalLoad (creation of metaVerse skipped)#{@cX.off}}
+    end
+    def meta_verse_load
+      puts %{\t[ MetaVerse: MarshalLoad ]}
+    end
+    def html_title
+      puts %{#{@cX.green_hi}#{@cX.black}HTML#{@cX.off*2}}
+    end
+    def html_output
+      puts %{\t#{@cX.grey}#{@txt[0]}#{@cX.off} #{@cX.ruby}->#{@cX.off}\n\t  #{@cX.blue}#{@txt[1]}#{@cX.off}}
+    end
+    def segmented
+      puts "\t#{@cX.grey}Seg#{@cX.off} #{@cX.green}#{@txt[0]}#{@cX.off} #{@cX.grey}segments#{@cX.off}"
+    end
+  end
+end
+__END__
+        Color.new do
+          self.off           = "\033[0m"
+          self.white         = "\033[37m"
+          self.white_bold    = "\033[1m"
+          self.marker        = "\033[42m"
+          self.bold          = "\033[1m"
+          self.underline     = "\033[4m"
+          self.invert        = "\033[7m"
+          self.darkgrey_hi   = "\033[100m"
+          self.grey_hi       = "\033[47m"
+          self.pink_hi       = "\033[105m"
+          self.fuchsia_hi    = "\033[45m"
+          self.red_hi        = "\033[41m"
+          self.orange_hi     = "\033[101m"
+          self.yellow_hi     = "\033[103m"
+          self.brown_hi      = "\033[43m"
+          self.lightgreen_hi = "\033[102m"
+          self.green_hi      = "\033[42m"
+          self.cyan_hi       = "\033[106m"
+          self.blue_hi       = "\033[104m"
+          self.navy_hi       = "\033[44m"
+          self.grey          = "\033[90m"
+          self.pink          = "\033[95m"
+          self.fuchsia       = "\033[35m"
+          self.ruby          = "\033[31m"
+          self.red           = "\033[91m" #check
+          self.orange        = "\033[91m"
+          self.yellow        = "\033[93m"
+          self.brown         = "\033[33m"
+          self.green         = "\033[92m"
+          self.darkgreen     = "\033[32m"
+          self.cyan          = "\033[36m"
+          self.blue          = "\033[94m"
+          self.navy          = "\033[34m"
+          self.black         = "\033[30m"
+        end
+# fewer colors
+        Color.new do
+          self.off           = "\033[0m"
+          self.white         = "\033[0m"
+          self.marker        = "\033[42m"
+          self.bold          = "\033[1m"
+          self.underline     = "\033[4m"
+          self.invert        = "\033[7m"
+          self.darkgrey_hi   = "\033[100m"
+          self.grey_hi       = "\033[47m"
+          self.pink_hi       = "\033[105m"
+          self.fuchsia_hi    = "\033[45m"
+          self.red_hi        = "\033[41m"
+          self.orange_hi     = "\033[101m"
+          self.yellow_hi     = "\033[103m"
+          self.brown_hi      = "\033[43m"
+          self.lightgreen_hi = "\033[102m"
+          self.green_hi      = "\033[42m"
+          self.cyan_hi       = "\033[106m"
+          self.blue_hi       = "\033[104m"
+          self.navy_hi       = "\033[44m"
+          self.grey          = "\033[90m"
+          self.pink          = "\033[95m"
+          self.fuchsia       = "\033[35m"
+          self.ruby          = "\033[31m"
+          self.red           = "\033[31m" #check
+          self.orange        = "\033[91m"
+          self.yellow        = "\033[33m"
+          self.brown         = "\033[33m"
+          self.green         = "\033[32m"
+          self.darkgreen     = "\033[32m"
+          self.cyan          = "\033[36m"
+          self.blue          = "\033[34m"
+          self.navy          = "\033[34m"
+          self.black         = "\033[30m"
+        end
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    utils
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/xhtml.org b/org/xhtml.org
new file mode 100644
index 00000000..3fc576e9
--- /dev/null
+++ b/org/xhtml.org
@@ -0,0 +1,5080 @@
+-*- mode: org -*-
+#+TITLE:       sisu xhtml including epub
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:xhtml:
+#+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
+
+* xhtml.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xhtml.rb"
+# <<sisu_document_header>>
+module SiSU_XHTML
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+    include SiSU_Particulars
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'xml_shared'                         # xml_shared.rb
+    include SiSU_XML_Munge
+  require_relative 'xml_format'                         # xml_format.rb
+    include SiSU_XML_Format
+  require_relative 'xml_persist'                        # xml_persist.rb
+  require_relative 'rexml'                              # rexml.rb
+    include SiSU_Rexml
+  require_relative 'shared_metadata'                    # shared_metadata.rb
+  @@alt_id_count=0
+  @@tablefoot=''
+  class Source
+    def initialize(opt)
+      @opt=opt
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+    end
+    def read
+      begin
+        @env,@md,@ao_array=@particulars.env,@particulars.md,@particulars.ao_array
+        unless @opt.act[:quiet][:set]==:on
+          tool=if (@opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on)
+            "#{@env.program.web_browser} file://#{@md.file.output_path.xhtml.dir}/#{@md.file.base_filename.xhtml}"
+          elsif @opt.act[:verbose][:set]==:on
+            "#{@env.program.web_browser} file://#{@md.file.output_path.xhtml.dir}/#{@md.file.base_filename.xhtml}"
+          else "[#{@opt.f_pth[:lng_is]}] #{@opt.fno}"
+          end
+          (@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on) \
+          ? SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'XHTML',
+              tool
+            ).green_hi_blue
+          : SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'XHTML',
+              tool
+            ).green_title_hi
+          if (@opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on)
+            SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              @opt.fns,
+              "/#{@md.file.output_path.xhtml.dir}/#{@md.file.base_filename.xhtml}"
+            ).flow
+          end
+        end
+        SiSU_XHTML::Source::Songsheet.new(@particulars).song
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        SiSU_Env::CreateSite.new(@opt).cp_css
+        Dir.chdir(@opt.f_pth[:pth])
+      end
+    end
+    private
+    class Songsheet
+      def initialize(particulars)
+        @env,@md,@ao_array,@particulars=particulars.env,particulars.md,particulars.ao_array,particulars
+        @file=SiSU_Env::FileOp.new(@md)
+      end
+      def song
+        begin
+          SiSU_XHTML::Source::Scroll.new(@particulars).songsheet
+          if (@md.opt.act[:verbose][:set]==:on \
+          || @md.opt.act[:verbose_plus][:set]==:on \
+          || @md.opt.act[:maintenance][:set]==:on)
+            SiSU_XHTML::Source::Tidy.new(@md,@file.place_file.xhtml.dir).xml # test wellformedness, comment out when not in use
+          end
+          SiSU_Rexml::Rexml.new(@md,@file.place_file.xhtml.dir).xml if @md.opt.act[:maintenance][:set]==:on # test rexml parsing, comment out when not in use #debug
+        rescue
+          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+        ensure
+        end
+      end
+    end
+    class Scroll
+      require_relative 'xhtml_shared'                   # xhtml_shared.rb #check already called
+      require_relative 'txt_shared'                     # txt_shared.rb
+        include SiSU_TextUtils
+      require_relative 'css'                            # css.rb
+      def initialize(particulars)
+        @env,@md,@ao_array=particulars.env,particulars.md,particulars.ao_array
+        @tab="\t"
+        @trans=SiSU_XML_Munge::Trans.new(@md)
+        @sys=SiSU_Env::SystemCall.new
+        @per=SiSU_XML_Persist::Persist.new
+      end
+      def songsheet
+        begin
+          pre
+          @data=markup(@ao_array)
+          post
+          publish
+        ensure
+          SiSU_XML_Persist::Persist.new.persist_init
+        end
+      end
+    protected
+      def embedded_endnotes(dob='')
+        dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}(\d+)\s+(.+?)#{Mx[:en_a_c]}/,
+            '<endnote><number>\1</number><note>\2</note></endnote> ').
+          gsub(/#{Mx[:en_b_o]}([*+]\d+)\s+(.+?)#{Mx[:en_b_c]}/,
+            '<endnote><symbol>\1</symbol><note>\2</note></endnote> ').
+          gsub(/#{Mx[:en_a_o]}([*+]+)\s+(.+?)#{Mx[:en_a_c]}/,
+            '<endnote><symbol>\1</symbol><note>\2</note></endnote> ')
+      end
+      def extract_endnotes(dob='')
+        notes=dob.obj.scan(/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})([\d*+]+\s+.+?)(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/)
+        notes.flatten.each do |e|
+          s=e.to_s
+          util=SiSU_TextUtils::Wrap.new(s,70)
+          wrap=util.line_wrap
+          wrap=wrap.gsub(/^(\d+)\s+(.+?)\s*\Z/m, <<WOK
+#{Ax[:tab]*1}<endnote notenumber="\\1">
+#{Ax[:tab]*2}\\1. \\2
+#{Ax[:tab]*1}</endnote>
+WOK
+).
+            gsub(/^([*+]\d+)\s+(.+?)\s*\Z/m, <<WOK
+#{Ax[:tab]*1}<endnote symbol="\\1">
+#{Ax[:tab]*2}\\1 \\2
+#{Ax[:tab]*1}</endnote>
+WOK
+).
+            gsub(/^([*+]+)\s+(.+?)\s*\Z/m, <<WOK
+#{Ax[:tab]*1}<endnote symbol="\\1.length">
+#{Ax[:tab]*2}\\1 \\2
+#{Ax[:tab]*1}</endnote>
+WOK
+)
+#KEEP alternative presentation of endnotes
+#        wrap=wrap.gsub(/^(\d+)\s+(.+?)\s*\Z/m, <<WOK
+##{Ax[:tab]*1}<p class="endnote" notenumber="\\1">
+##{Ax[:tab]*2}\\1. \\2
+##{Ax[:tab]*1}</p>
+#WOK
+#)
+          @endnotes << wrap
+        end
+      end
+      def xml_head
+        metadata=SiSU_Metadata::Summary.new(@md).xhtml_scroll.metadata
+        @per.head << metadata
+      end
+      def name_tags(dob)
+        tags=''
+        if defined? dob.tags \
+        and dob.tags.length > 0 # insert tags "hypertargets"
+          dob.tags.each do |t|
+            tags=tags << %{<named id="#{t}" />}
+          end
+        end
+        tags
+      end
+      def xml_structure(dob,type='norm')
+        if dob.is ==:para \
+        || dob.is ==:heading
+          named=name_tags(dob)
+          if dob.is==:heading
+            lv=dob.ln
+            dob.ln + 2
+          else lv=nil
+          end
+          extract_endnotes(dob)
+          dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'<en>\1</en>'). #footnote/endnote clean
+            gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'<en>\1</en>')
+          util=SiSU_TextUtils::Wrap.new(dob.obj,70)
+          wrapped=util.line_wrap
+          @per.body << if defined? dob.ocn
+            %{#{Ax[:tab]*0}<object id="#{dob.ocn}">}
+          else                        "#{Ax[:tab]*0}<object>"
+          end
+          @per.body << %{#{Ax[:tab]*1}<text class="#{type}">#{named}\n#{Ax[:tab]*2}#{wrapped}\n#{Ax[:tab]*1}</text>} unless lv  # main text, contents, body KEEP
+          @per.body << %{#{Ax[:tab]*1}<text class="h#{lv}">#{named}\n#{Ax[:tab]*2}#{wrapped}\n#{Ax[:tab]*1}</text>} if lv # main text, contents, body KEEP
+          @per.body << @endnotes.compact.join if @endnotes.length > 0 # main text, endnotes KEEP
+          @per.body << "#{Ax[:tab]*1}<ocn>#{dob.ocn}</ocn>" if defined? dob.ocn
+          @per.body << "#{Ax[:tab]*0}</object>"
+          @endnotes=[]
+        end
+      end
+      def block_structure(dob)
+        named=name_tags(dob)
+        dob=@trans.markup_block(dob)
+        dob.obj=dob.obj.strip.
+          gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'<en>\1</en>'). #footnote/endnote clean
+          gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'<en>\1</en>') #footnote/endnote clean
+        @per.body << %{#{Ax[:tab]*0}<object id="#{dob.ocn}">}
+        @per.body << %{#{Ax[:tab]*1}<ocn>#{dob.ocn}</ocn>}
+        @per.body << %{#{Ax[:tab]*1}<text class="block">#{named}#{Ax[:tab]*1}}
+        @per.body << %{#{Ax[:tab]*2}#{dob.obj}#{Ax[:tab]*1}}
+        @per.body << %{#{Ax[:tab]*1}</text>}
+        @per.body << "#{Ax[:tab]*0}</object>"
+      end
+      def group_structure(dob)
+        named=name_tags(dob)
+        dob=@trans.markup_group(dob)
+        dob.obj=dob.obj.strip.
+          gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'<en>\1</en>'). #footnote/endnote clean
+          gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'<en>\1</en>') #footnote/endnote clean
+        @per.body << %{#{Ax[:tab]*0}<object id="#{dob.ocn}">}
+        @per.body << %{#{Ax[:tab]*1}<ocn>#{dob.ocn}</ocn>}
+        @per.body << %{#{Ax[:tab]*1}<text class="group">#{named}#{Ax[:tab]*1}}
+        @per.body << %{#{Ax[:tab]*2}#{dob.obj}#{Ax[:tab]*1}}
+        @per.body << %{#{Ax[:tab]*1}</text>}
+        @per.body << "#{Ax[:tab]*0}</object>"
+      end
+      def poem_structure(dob)
+        named=name_tags(dob)
+        dob=@trans.markup_group(dob)
+        dob.obj=dob.obj.strip
+        @per.body << %{#{Ax[:tab]*0}<object id="#{dob.ocn}">}
+        @per.body << %{#{Ax[:tab]*1}<ocn>#{dob.ocn}</ocn>}
+        @per.body << %{#{Ax[:tab]*1}<text class="verse">#{named}#{Ax[:tab]*1}}
+        @per.body << %{#{Ax[:tab]*2}#{dob.obj}#{Ax[:tab]*1}}
+        @per.body << %{#{Ax[:tab]*1}</text>}
+        @per.body << "#{Ax[:tab]*0}</object>"
+      end
+      def code_structure(dob)
+        named=name_tags(dob)
+        dob=@trans.markup_group(dob)
+        dob.obj=dob.obj.gsub(/\s\s/,'&#160;&#160;').strip
+        @per.body << %{#{Ax[:tab]*0}<object id="#{dob.ocn}">}
+        @per.body << %{#{Ax[:tab]*1}<ocn>#{dob.ocn}</ocn>}
+        @per.body << %{#{Ax[:tab]*1}<text class="code">#{named}#{Ax[:tab]*1}}
+        @per.body << %{#{Ax[:tab]*2}#{dob.obj}#{Ax[:tab]*1}}
+        @per.body << %{#{Ax[:tab]*1}</text>}
+        @per.body << "#{Ax[:tab]*0}</object>"
+      end
+      def table_structure(dob)
+        named=name_tags(dob)
+        table=SiSU_XHTML_Shared::TableXHTML.new(dob)
+        @per.body << %{#{Ax[:tab]*0}<object id="#{dob.ocn}">}
+        @per.body << %{#{Ax[:tab]*1}<ocn>#{dob.ocn}</ocn>}
+        @per.body << %{#{Ax[:tab]*2}#{named}#{table.table.obj}}
+        @per.body << "#{Ax[:tab]*0}</object>"
+      end
+      def markup(data)
+        @endnotes=[]
+        @rcdc=false
+        @level,@cont,@copen,@xml_contents_close=[],[],[],[]
+        xml_head
+        (0..7).each { |x| @cont[x]=@level[x]=false }
+        (4..7).each { |x| @xml_contents_close[x]='' }
+        data.each do |dob|
+          dob=@trans.markup(dob)
+          if @rcdc==false \
+          and (dob.obj =~/~meta/ \
+          and dob.obj =~/Document Information/)
+            @rcdc=true
+          end
+          if dob.obj !~/(^#{Rx[:meta]}|#{Mx[:br_eof]}|#{Mx[:br_endnotes]})/
+            if defined? dob.ocn #look to move to format section
+              ocn=(dob.ocn.to_s =~/\d+/) ? dob.ocn : nil
+              @p_num=SiSU_XML_Format::ParagraphNumber.new(@md,ocn)
+            end
+            if not @rcdc
+              x=SiSU_XML_Format::FormatSeg.new(@md,dob)
+              if dob.is==:heading
+                xml_structure(dob)
+                dob.obj=case dob.ln
+                when 0 then x.heading_body0
+                when 1 then x.heading_body1
+                when 2 then x.heading_body2
+                when 3 then x.heading_body3
+                when 4 then x.heading_body4
+                when 5 then x.heading_body5
+                when 6 then x.heading_body6
+                when 7 then x.heading_body7
+                end
+              else
+                if dob.is ==:verse
+                  poem_structure(dob)
+                elsif dob.is ==:group
+                  group_structure(dob)
+                elsif dob.is ==:block
+                  block_structure(dob)
+                elsif dob.is ==:code
+                  code_structure(dob)
+                elsif dob.is ==:table
+                  table_structure(dob)
+                elsif dob.is ==:para \
+                and dob.indent.to_s =~/[1-9]/ \
+                and dob.bullet_==true
+                  xml_structure(dob,"indent_bullet#{dob.indent}")
+                elsif dob.is ==:para \
+                and dob.indent.to_s =~/[1-9]/ \
+                and dob.indent == dob.hang
+                  xml_structure(dob,"indent#{dob.indent}")
+                elsif dob.is==:para \
+                and dob.hang.to_s =~/[0-9]/ \
+                and dob.indent != dob.hang
+                  xml_structure(dob,"hang#{dob.hang.to_s}_indent#{dob.indent.to_s}")
+                else xml_structure(dob)
+                end
+              end
+              if dob.obj =~/.*<:#>.*$/ #investigate removal
+                dob.obj=if dob.obj =~ /#{Mx[:pa_o]}:i[1-9]#{Mx[:pa_c]}/
+                  txt_obj={ txt: dob }
+                  format_text=FormatTextObject.new(@md,txt_obj)
+                  format_text.scr_inden_ocn_e_no_paranum
+                end
+              end
+            else #
+            end
+            dob.obj=dob.obj.gsub(/#{Mx[:pa_o]}:\S+#{Mx[:pa_c]}/,'') if dob.obj
+          end
+        end
+        6.downto(4) do |x|
+          y=x - 1; v=x - 3
+          @per.body << "#{Ax[:tab]*5}</content>\n#{Ax[:tab]*y}</contents#{v}>" if @level[x]==true
+        end
+        3.downto(1) do |x|
+          y=x - 1
+          @per.body << "#{Ax[:tab]*y}</heading#{x}>" if @level[x]==true
+        end
+      end
+      def pre
+        rdf=SiSU_XML_Tags::RDF.new(@md)
+        @per.head,@per.body=[],[]
+        stylesheet=SiSU_Style::CSS_HeadInfo.new(@md,'xhtml').stylesheet
+        encoding=(@sys.locale =~/utf-?8/i) \
+        ? '<?xml version="1.0" encoding="UTF-8" standalone="no"?>'
+        : '<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>'
+        @per.open =<<WOK
+#{encoding}
+#{stylesheet.css_head_xml}
+#{rdf.comment_xml}
+<document>
+WOK
+        @per.head << %{<head>\n\t<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />}
+        @per.body << '<body>'
+      end
+      def post
+        @per.head << '</head>'
+        @per.body << '</body>'
+        @per.close = '</document>'
+      end
+      def publish
+        content=[]
+        content << @per.open << @per.head << @per.body << @per.metadata
+        content << @per.tail << @per.close
+        content=content.flatten.compact
+        Output.new(content,@md).xhtml
+        @@xml={}
+      end
+    end
+    class Output
+      def initialize(data,md)
+        @data,@md=data,md
+        @file=SiSU_Env::FileOp.new(@md)
+      end
+      def xhtml
+        SiSU_Env::FileOp.new(@md).mkdir
+        filename_xml=@file.write_file.xhtml
+        @data.each do |str|
+          str=str.gsub(/\A\s+\Z/m,'') #str.gsub(/^\s+$/,'')
+          filename_xml.puts str unless str.empty?
+        end
+        filename_xml.close
+      end
+    end
+    class Tidy
+      def initialize(md,file)
+        @md,@file=md,file
+        @prog=SiSU_Env::InfoProgram.new
+      end
+      def xml
+        if @prog.tidy !=false
+          if (@md.opt.act[:verbose_plus][:set]==:on \
+          || @md.opt.act[:maintenance][:set]==:on)
+            unless @md.opt.act[:quiet][:set]==:on
+              SiSU_Screen::Ansi.new(
+                @md.opt.act[:color_state][:set],
+                'invert',
+                'Using XML Tidy',
+                'check document structure'
+              ).colorize
+              tell=SiSU_Screen::Ansi.new(
+                @md.opt.act[:color_state][:set],
+                'invert',
+                '',
+                ''
+              )
+              tell.grey_open
+            end
+            tidyfile='/dev/null' #don't want one or screen output, check for alternative flags
+            tidy=SiSU_Env::SystemCall.new(@file,tidyfile)
+            tidy.well_formed?
+            tell.p_off unless @md.opt.act[:quiet][:set]==:on
+          end
+        end
+      end
+    end
+  end
+end
+__END__
+,** Notes:
+tidy -xml scroll.xhtml >> index.tidy
+<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
+<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?xml version="1.0" encoding="UTF-16" standalone="no"?>
+#+END_SRC
+
+* epub2.rb
+** xhtml_epub2.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xhtml_epub2.rb"
+# <<sisu_document_header>>
+module SiSU_XHTML_EPUB2
+  begin
+    require 'pstore'
+  rescue LoadError
+    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+      error('pstore NOT FOUND (LoadError)')
+  end
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+    include SiSU_Particulars
+  require_relative 'xml_shared'                         # xml_shared.rb
+    include SiSU_XML_Munge
+  require_relative 'xhtml_table'                        # xhtml_table.rb
+  require_relative 'xhtml_epub2_format'                 # xhtml_epub2_format.rb
+    include SiSU_XHTML_EPUB2_Format
+  require_relative 'xhtml_epub2_segments'               # xhtml_epub2_segments.rb
+    include SiSU_XHTML_EPUB2_Seg
+  require_relative 'xhtml_epub2_tune'                   # xhtml_epub2_tune.rb
+    include SiSU_XHTML_EPUB2_Tune
+  require_relative 'xhtml_epub2_concordance'            # xhtml_epub2_concordance.rb
+  require_relative 'xhtml_epub2_persist'                # xhtml_epub2_persist.rb
+  class Source
+    def initialize(opt)
+      @opt=opt
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+    end
+    def read
+      begin
+        songsheet
+      ensure
+        Dir.chdir(@opt.f_pth[:pth])
+      end
+    end
+    def songsheet
+      begin
+        @md=@particulars.md
+        @fnb=@md.fnb
+        @env=@particulars.env
+        unless @opt.act[:quiet][:set]==:on
+          tool=(@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on) \
+          ? "#{@env.program.epub_viewer} #{@md.file.output_path.epub.dir}/#{@md.file.base_filename.epub}"
+          : "[#{@opt.f_pth[:lng_is]}] #{@opt.fno}"
+          (@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on) \
+          ? SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'EPUB',
+              tool
+            ).green_hi_blue
+          : SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'EPUB',
+              tool
+            ).green_title_hi
+          if (@opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on)
+            SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              @opt.fns,
+              "#{@md.file.output_path.epub.dir}/#{@md.file.base_filename.epub}"
+            ).flow
+          end
+        end
+        @env.processing_path.epub_bld #(@md)
+        @env.processing_path.epub_cp_images(@md)
+        data=nil
+        SiSU_Env::FileOp.new(@md).mkdir.output.epub
+        @tuned_file_array=SiSU_XHTML_EPUB2::Source::XHTML_Environment.new(@particulars).tuned_file_instructions
+        data=@tuned_file_array
+        per=SiSU_XHTML_EPUB2::Source::Toc.new(@md,data).songsheet
+        data=@tuned_file_array
+        SiSU_XHTML_EPUB2::Source::ScrollHeadAndSegToc.new(@md,per).in_common #watch
+        SiSU_XHTML_EPUB2::Source::Seg.new(@md,data).songsheet
+        SiSU_XHTML_EPUB2::Source::Output.new(@md).songsheet
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        unless (@opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on)
+          texfiles=Dir["#{@env.processing_path.tune}/#{@opt.fns}*"]
+          texfiles.each do |f|
+            if FileTest.file?(f)
+              File.unlink(f)
+            end
+          end
+        end
+        SiSU_Env::Clear.new(@opt.selections.str,@opt.fns).param_instantiate
+        @@flag,@@scr,@@seg,@@seg_endnotes,@@seg_subtoc={},{},{},{},{}
+        @@tracker=0
+        @@seg_name,@@seg_name_html,@@seg_subtoc_array,@@seg_endnotes_array,@@tablefoot=Array.new(5){[]}
+        @@filename_seg,@@seg_url,@@to_lev4,@@get_hash_to,@@get_hash_fn='','','','',''
+      end
+    end
+    private
+    class XHTML_Environment
+      def initialize(particulars)
+        @particulars=particulars
+        @md,@env=particulars.md,particulars.env
+        @env,@css=particulars.env,SiSU_Style::CSS.new
+      end
+      def directories
+        SiSU_Env::FileOp.new(@md).mkdir.output.epub
+      end
+      def tuned_file_instructions
+        @tell=SiSU_Screen::Ansi.new(@md.opt.act[:color_state][:set])
+        directories
+        ao_array=@particulars.ao_array # ao file drawn here
+        @tuned_file_array=SiSU_XHTML_EPUB2_Tune::Tune.new(ao_array,@md).songsheet
+        @tuned_file_array
+      end
+    end
+    class Endnotes
+      include SiSU_XHTML_EPUB2_Format
+      def initialize(md,data)
+        @md,@data=md,data
+      end
+      def scroll
+        @scr_endnotes=[]
+        @data.each do |dob|
+          pg=dob.dup
+          unless pg.is ==:code
+            if pg.obj =~/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})[\d*+]+ /
+              endnote_array=[]
+              if pg.obj=~/#{Mx[:en_a_o]}[\d*+].+?#{Mx[:en_a_c]}/m
+                endnote_array = pg.obj.scan(/#{Mx[:en_a_o]}[\d*+]+(.+?)#{Mx[:en_a_c]}/m)
+              end
+              if pg.obj=~/#{Mx[:en_b_o]}[\d*]+\s.+?#{Mx[:en_b_c]}/m
+                endnote_array = pg.obj.scan(/#{Mx[:en_b_o]}[\d*]+(.+?)#{Mx[:en_b_c]}/m)
+              end
+              if pg.obj=~/#{Mx[:en_b_o]}[\d+]+\s.+?#{Mx[:en_b_c]}/m
+                endnote_array = pg.obj.scan(/#{Mx[:en_b_o]}[\d+]+(.+?)#{Mx[:en_b_c]}/m)
+              end
+              endnote_array.flatten.each do |note|
+                txt_obj={ txt: note }
+                format_scroll=SiSU_XHTML_EPUB2_Format::FormatScroll.new(@md,txt_obj)
+                @scr_endnotes << format_scroll.endnote_body
+              end
+            end
+          end
+        end
+        @scr_endnotes
+      end
+    end
+    class Toc
+      @@seg_url=''
+      @@firstseg=nil
+      def initialize(md=nil,data='')
+        @md,@data=md,data
+        @epub=SiSU_XHTML_EPUB2_Format::HeadInformation.new(@md)
+        @tell=SiSU_Screen::Ansi.new(@md.opt.act[:color_state][:set]) if @md
+        @make=SiSU_Env::ProcessingSettings.new(@md)
+        @per=SiSU_XHTML_EPUB2_Persist::PersistTOC.new
+      end
+      def songsheet #extracts toc for scroll & seg
+        begin
+          if (@md.opt.act[:verbose][:set]==:on \
+          || @md.opt.act[:verbose_plus][:set]==:on \
+          || @md.opt.act[:maintenance][:set]==:on)
+            SiSU_Screen::Ansi.new(
+              @md.opt.act[:color_state][:set],
+              'Toc'
+            ).txt_grey
+          end
+          toc=nil
+          @@firstseg=nil
+          SiSU_XHTML_EPUB2_Persist::PersistTOC.new.persist_init
+          md_opf_a_content,md_opf_a_spine,md_opf_a_guide=[],[],[]
+          @nav_no=0
+          @s_a_no,@s_b_no,@s_c_no,@s_d_no,@lv5_no,@lv6_no=0,0,0,0,0,0
+          @per.ncx << @epub.toc_ncx.open #epub ncx navmap
+          @per.ncx << @epub.toc_ncx.head_open << @epub.toc_ncx.head << @epub.toc_ncx.head_close
+          @per.ncx << @epub.toc_ncx.doc_title << @epub.toc_ncx.doc_author
+          @per.ncx << @epub.toc_ncx.navmap_open
+          @per.opf << @epub.metadata_opf.package_open
+          @per.opf << @epub.metadata_opf.metadata
+          @per.opf << @epub.metadata_opf.manifest_open
+          @per.seg << %{<div class="content">\n<div class="substance">}
+          @per.scr << %{<div class="content">\n<div class="substance">}
+          if defined? @md.make.cover_image \
+          and @md.make.cover_image.is_a?(Hash) \
+          and @md.make.cover_image[:cover] =~/\S+/
+            md_opf_a_content << @epub.metadata_opf.manifest_cover_image_information(@md)
+            md_opf_a_spine << @epub.metadata_opf.spine_cover_image
+            md_opf_a_guide << @epub.metadata_opf.guide_cover_image
+          end
+          md_opf_a_content << @epub.metadata_opf.manifest_content_sisu_toc
+          if @make.build.toc?
+            md_opf_a_spine << @epub.metadata_opf.spine_sisu_toc
+            md_opf_a_guide << @epub.metadata_opf.guide_sisu_toc
+          end
+          @ncxo=[false,false,false,false,false,false,false]
+          @dob_toc2,@dob_toc3=nil,nil
+          @ncx_cls=[]
+          @level_a_first_occurrence=true
+          @data.each do |dob|
+            if dob.is==:heading \
+            || dob.is==:heading_insert
+              dob_toc=dob.dup
+              toc=case dob_toc.ln
+              when 0
+                @s_a_no +=1
+                lv_name='section_a' + @s_a_no.to_s
+                @nav_no+=1
+                @nav_no2=@nav_no
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[7]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[6]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[5]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[4]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[3]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[2]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[1]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[0]
+                @ncxo[0],@ncxo[1],@ncxo[2],@ncxo[3],@ncxo[4],@ncxo[5],@ncxo[6],@ncxo[7]=
+                  true,  false,   false,   false,   false,   false,   false,   false
+                @epub.sections(dob_toc,lv_name)
+                if @level_a_first_occurrence \
+                && @make.build.toc?
+                  @per.ncx << @epub.toc_ncx.navmap_sisu_toc(@nav_no) #epub ncx navmap, toc
+                  @nav_no+=1
+                  @level_a_first_occurrence=false
+                end
+                @per.ncx << @epub.toc_ncx.navpoint(dob_toc,@nav_no,lv_name) if dob_toc
+                md_opf_a_content << @epub.metadata_opf.manifest_content(dob_toc,lv_name)
+                md_opf_a_spine << @epub.metadata_opf.spine(dob_toc,lv_name)
+                md_opf_a_guide << @epub.metadata_opf.guide(dob_toc,lv_name)
+                SiSU_XHTML_EPUB2::Source::Toc.new(@md,dob_toc).level_0
+              when 1
+                @s_b_no +=1
+                lv_name='section_b' + @s_b_no.to_s
+                @nav_no+=1
+                @nav_no2=@nav_no
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[7]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[6]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[5]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[4]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[3]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[2]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[1]
+                @ncxo[1],@ncxo[2],@ncxo[3],@ncxo[4],@ncxo[5],@ncxo[6],@ncxo[7]=
+                  true,  false,   false,   false,   false,   false,   false
+                @epub.sections(dob_toc,lv_name)
+                @per.ncx << @epub.toc_ncx.navpoint(dob_toc,@nav_no,lv_name) if dob_toc
+                md_opf_a_content << @epub.metadata_opf.manifest_content(dob_toc,lv_name)
+                md_opf_a_spine << @epub.metadata_opf.spine(dob_toc,lv_name)
+                md_opf_a_guide << @epub.metadata_opf.guide(dob_toc,lv_name)
+                SiSU_XHTML_EPUB2::Source::Toc.new(@md,dob_toc).level_1
+              when 2
+                @s_c_no +=1
+                lv_name='section_c' + @s_c_no.to_s
+                @nav_no+=1
+                @nav_no2=@nav_no
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[7]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[6]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[5]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[4]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[3]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[2]
+                @ncxo[2],@ncxo[3],@ncxo[4],@ncxo[5],@ncxo[6],@ncxo[7]=
+                  true,  false,   false,   false,   false,   false
+                @epub.sections(dob_toc,lv_name)
+                @per.ncx << @epub.toc_ncx.navpoint(dob_toc,@nav_no,lv_name) if dob_toc
+                md_opf_a_content << @epub.metadata_opf.manifest_content(dob_toc,lv_name)
+                md_opf_a_spine << @epub.metadata_opf.spine(dob_toc,lv_name)
+                md_opf_a_guide << @epub.metadata_opf.guide(dob_toc,lv_name)
+                SiSU_XHTML_EPUB2::Source::Toc.new(@md,dob_toc).level_2
+              when 3
+                @s_d_no +=1
+                lv_name='section_d' + @s_d_no.to_s
+                @nav_no+=1
+                @nav_no3=@nav_no
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[7]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[6]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[5]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[4]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[3]
+                @ncxo[3],@ncxo[4],@ncxo[5],@ncxo[6],@ncxo[7]=
+                  true,  false,   false,   false,   false
+                @epub.sections(dob_toc,lv_name)
+                @per.ncx << @epub.toc_ncx.navpoint(dob_toc,@nav_no,lv_name) if dob_toc
+                md_opf_a_content << @epub.metadata_opf.manifest_content(dob_toc,lv_name)
+                md_opf_a_spine << @epub.metadata_opf.spine(dob_toc,lv_name)
+                md_opf_a_guide << @epub.metadata_opf.guide(dob_toc,lv_name)
+                SiSU_XHTML_EPUB2::Source::Toc.new(@md,dob_toc).level_3
+              when 4
+                @ncx_cls=[]
+                lv_name=dob_toc.name
+                @nav_no+=1
+                @dob_name=dob.name
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[7]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[6]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[5]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[4]
+                @ncxo[4],@ncxo[5],@ncxo[6],@ncxo[7]=
+                  true,  false,   false,   false
+                @per.ncx << @epub.toc_ncx.navpoint(dob_toc,@nav_no,lv_name) if dob_toc
+                md_opf_a_content << @epub.metadata_opf.manifest_content(dob_toc,lv_name)
+                md_opf_a_spine << @epub.metadata_opf.spine(dob_toc,lv_name)
+                md_opf_a_guide << @epub.metadata_opf.guide(dob_toc,lv_name)
+                SiSU_XHTML_EPUB2::Source::Toc.new(@md,dob_toc).level_4
+              when 5
+                @ncx_cls=[]
+                hashtag='#o' + dob_toc.ocn.to_s
+                lv_name=@dob_name
+                @nav_no+=1
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[7]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[6]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[5]
+                @ncxo[5],@ncxo[6],@ncxo[7]=
+                  true,  false, false
+                @per.ncx << @epub.toc_ncx.navpoint(dob_toc,@nav_no,lv_name,hashtag) if dob_toc
+                md_opf_a_content << @epub.metadata_opf.manifest_content(dob_toc,lv_name,hashtag)
+                md_opf_a_spine << @epub.metadata_opf.spine(dob_toc,lv_name,hashtag)
+                md_opf_a_guide << @epub.metadata_opf.guide(dob_toc,lv_name,hashtag)
+                SiSU_XHTML_EPUB2::Source::Toc.new(@md,dob_toc).level_5
+              when 6
+                @ncx_cls=[]
+                hashtag='#o' + dob_toc.ocn.to_s
+                lv_name=@dob_name
+                @nav_no+=1
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[7]
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[6]
+                @ncxo[6],@ncxo[7]=
+                  true,  false
+                @per.ncx << @epub.toc_ncx.navpoint(dob_toc,@nav_no,lv_name,hashtag) if dob_toc
+                md_opf_a_content << @epub.metadata_opf.manifest_content(dob_toc,lv_name,hashtag)
+                md_opf_a_spine << @epub.metadata_opf.spine(dob_toc,lv_name,hashtag)
+                md_opf_a_guide << @epub.metadata_opf.guide(dob_toc,lv_name,hashtag)
+                SiSU_XHTML_EPUB2::Source::Toc.new(@md,dob_toc).level_6
+              when 7
+                @ncx_cls=[]
+                hashtag='#o' + dob_toc.ocn.to_s
+                lv_name=@dob_name
+                @nav_no+=1
+                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[7]
+                @ncxo[7]=true
+                @per.ncx << @epub.toc_ncx.navpoint(dob_toc,@nav_no,lv_name,hashtag) if dob_toc
+                md_opf_a_content << @epub.metadata_opf.manifest_content(dob_toc,lv_name,hashtag)
+                md_opf_a_spine << @epub.metadata_opf.spine(dob_toc,lv_name,hashtag)
+                md_opf_a_guide << @epub.metadata_opf.guide(dob_toc,lv_name,hashtag)
+                SiSU_XHTML_EPUB2::Source::Toc.new(@md,dob_toc).level_7
+              else nil
+              end
+              toc.each do |k,d|
+                d.gsub!(/(?:#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})\s*/m,' ')
+              end if toc
+              if @@firstseg.nil? \
+              and dob.ln==4 \
+              and dob.name =~/\S+/
+                @@firstseg=dob.name
+              end
+              if toc
+                begin
+                  @per.seg << toc[:seg]
+                  @per.scr << toc[:seg]
+                rescue
+                  SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+                    __LINE__.to_s + ':' + __FILE__
+                  end
+                end
+              end
+            end
+          end
+          @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[6]
+          @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[5]
+          @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[4]
+          @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[3]
+          @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[2]
+          @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[1]
+          @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[0]
+          @ncxo[0],@ncxo[1],@ncxo[2],@ncxo[3],@ncxo[4],@ncxo[5],@ncxo[6]=false,false,false,false,false,false,false
+          md_opf_a_content << @epub.metadata_opf.manifest_images(@md.ec[:image])
+          @per.seg << "</div>\n</div>"
+          @per.scr << "</div>\n</div>"
+          @per.ncx << @epub.toc_ncx.navmap_close
+          @per.ncx << @epub.toc_ncx.close
+          @per.opf << md_opf_a_content << @epub.metadata_opf.manifest_close
+          @per.opf << @epub.metadata_opf.spine_open << md_opf_a_spine << @epub.metadata_opf.spine_close
+          @per.opf << @epub.metadata_opf.guide_open << md_opf_a_guide << @epub.metadata_opf.guide_close
+          @per.opf << @epub.metadata_opf.package_close
+          @per.opf=@per.opf.flatten
+          SiSU_XHTML_EPUB2::Source::Output.new(@md,@per.opf).epub_metadata_opf
+          SiSU_XHTML_EPUB2::Source::Output.new(@md,@per.ncx).epub_toc_ncx
+          @md.firstseg=@@firstseg
+          @per
+        ensure
+          SiSU_XHTML_EPUB2_Persist::Persist.new.persist_init
+        end
+      end
+    protected
+      def level_0
+        dob=@data
+        linkname=dob.obj.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'').strip
+        link=dob.ocn
+        title=linkname
+        toc={}
+        txt_obj={ txt: title }
+        format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
+        toc[:seg]=format_toc.lev1
+        title=if dob.ocn ==0 then linkname
+        else
+          @per.scr <<  '<br />'
+          link=(dob.ln) \
+          ? dob.ln
+          : ''
+          %{<b><a href="##{link}">#{linkname}</a></b>}
+        end
+        txt_obj={ txt: title }
+        format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
+        toc[:scr]=format_toc.lev1
+        toc
+      end
+      def level_1
+        dob=@data
+        linkname=dob.obj.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'').strip
+        link=dob.ocn
+        title=if dob.obj !~/Document Information/
+          linkname
+        else
+          link='metadata'
+          %{<b><a href="#{link}#{Sfx[:epub_xhtml]}">#{linkname}</a></b>}
+        end
+        toc={}
+        txt_obj={ txt: title }
+        format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
+        toc[:seg]=if dob.name =~/^meta/ \
+        and dob.obj =~/Document Information/ #check
+          format_toc.lev0
+        else format_toc.lev1
+        end
+        title=if dob.ocn ==0
+          if dob.name =~/^meta/ \
+          and dob.obj =~/Document Information/
+            %{<a href="#docinfo">#{linkname}</a>}
+          else linkname
+          end
+        else
+          @per.scr <<  '<br />'
+          link=(dob.ln) \
+          ? dob.ln
+          : ''
+          %{<b><a href="##{link}">#{linkname}</a></b>}
+        end
+        txt_obj={ txt: title }
+        format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
+        toc[:scr]=if dob.name =~/^meta/ \
+        and dob.obj =~/Document Information/
+          format_toc.lev0
+        else format_toc.lev1
+        end
+        toc
+      end
+      def level_2
+        dob=@data
+        linkname=dob.obj.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'').strip
+        ocn=dob.ocn
+        if ocn \
+        and ocn !~/#/
+          p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,ocn)
+        end
+        txt_obj={ txt: linkname }
+        format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
+        toc={}
+        toc[:seg]=format_toc.lev2
+        if p_num
+          title=%{#{p_num.goto}#{linkname}</a>}
+          txt_obj={ txt: title }
+          format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
+          toc[:scr]=format_toc.lev2
+        end
+        toc
+      end
+      def level_3
+        dob=@data
+        linkname=dob.obj.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'').strip
+        ocn=dob.ocn
+        if ocn \
+        and ocn !~/#/
+          p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,ocn)
+        end
+        txt_obj={ txt: linkname }
+        format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
+        toc={}
+        toc[:seg]=format_toc.lev3
+        if p_num
+          title=%{#{p_num.goto}#{linkname}</a>}
+          txt_obj={ txt: title }
+          format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
+          toc[:scr]=format_toc.lev3
+        end
+        toc
+      end
+      def level_4
+        dob=@data
+        linkname=dob.obj.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'').strip
+        ocn=dob.ocn
+        p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,ocn) if ocn
+        if dob.ln==4
+          seg_link=%{  <a href="#{dob.name}#{Sfx[:epub_xhtml]}">
+    #{dob.obj}
+  </a> }
+          @@seg_url=dob.name
+        elsif dob.obj =~/\d+.\d+.\d+.\d+|\d+.\d+.\d+|\d+.\d+|\d+/
+          seg_link=dob.obj.gsub(/^(\d+.\d+.\d+.\d+|\d+.\d+.\d+|\d+.\d+|\d+)(.*)/,
+            %{<a href="\\1#{Sfx[:epub_xhtml]}">} +
+            %{\\1 \\2</a> })
+        end
+        p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,ocn) if ocn
+        txt_obj={ txt: seg_link }
+        format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
+        toc={}
+        toc[:seg]=format_toc.lev4
+        title=%{#{p_num.goto}#{linkname}</a>} if p_num
+        txt_obj={ txt: title }
+        format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
+        toc[:scr]=format_toc.lev4
+        toc
+      end
+      def level_5
+        dob=@data
+        linkname=dob.obj.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'').strip
+        ocn=dob.ocn
+        toc={}
+        if ocn \
+        and ocn.to_s !~/#/
+          p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,ocn)
+          lnk_n_txt=%{  <a href="#{@@seg_url}#{Sfx[:epub_xhtml]}#o#{ocn}">
+    #{linkname}
+  </a>}
+          txt_obj={ txt: lnk_n_txt }
+          format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
+          toc[:seg]=format_toc.lev5
+          title=%{#{p_num.goto}#{linkname}</a>}
+          txt_obj={ txt: title }
+          format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
+          toc[:scr]=format_toc.lev5
+        end
+        toc
+      end
+      def level_6
+        dob=@data
+        linkname=dob.obj.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'').strip
+        ocn=dob.ocn
+        toc={}
+        if ocn \
+        and ocn.to_s !~/#/
+          p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,ocn)
+          lnk_n_txt=%{  <a href="#{@@seg_url}#{Sfx[:epub_xhtml]}#o#{ocn}">
+  #{linkname}
+</a>}
+          txt_obj={ txt: lnk_n_txt }
+          format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
+          toc[:seg]=format_toc.lev6
+          title=%{#{p_num.goto}#{linkname}</a>}
+          txt_obj={ txt: title }
+          format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
+          toc[:scr]=format_toc.lev6
+        end
+        toc
+      end
+      def level_7
+        dob=@data
+        linkname=dob.obj.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'').strip
+        ocn=dob.ocn
+        toc={}
+        if ocn \
+        and ocn.to_s !~/#/
+          p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,ocn)
+          lnk_n_txt=%{  <a href="#{@@seg_url}#{Sfx[:epub_xhtml]}#o#{ocn}">
+  #{linkname}
+</a>}
+          txt_obj={ txt: lnk_n_txt }
+          format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
+          toc[:seg]=format_toc.lev7
+          title=%{#{p_num.goto}#{linkname}</a>}
+          txt_obj={ txt: title }
+          format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
+          toc[:scr]=format_toc.lev7
+        end
+        toc
+      end
+    end
+    class ScrollHeadAndSegToc < Toc
+      def initialize(md='',per='',links_guide_toc='')
+        @md,@per,@links_guide_toc=md,per,links_guide_toc
+      end
+      def in_common
+        toc_shared=[]
+        segtoc=[]
+        if (@md.opt.act[:verbose][:set]==:on \
+        || @md.opt.act[:verbose_plus][:set]==:on \
+        || @md.opt.act[:maintenance][:set]==:on)
+          SiSU_Screen::Ansi.new(
+            @md.opt.act[:color_state][:set],
+            'Scroll & Segtoc'
+          ).txt_grey
+        end
+        format_head_toc=SiSU_XHTML_EPUB2_Format::HeadToc.new(@md)
+        dochead=format_head_toc.head
+        dochead=dochead.gsub(/toc\.(html)/,'doc.\1') #kludge
+        toc_shared << dochead #<< ads.div.major
+        segtoc << format_head_toc.head #<< ads.div.major
+        if defined? @md.rights.all \
+        and @md.rights.all
+          rights=format_head_toc.rights.all
+          rights=SiSU_XHTML_EPUB2_Tune::CleanXHTML.new(rights).clean
+        end
+        if defined? @md.notes.prefix_b \
+        and @md.notes.prefix_b
+          prefix_b=format_head_toc.prefix_b
+          prefix_b=SiSU_XHTML_EPUB2_Tune::CleanXHTML.new(prefix_b).clean
+        end
+        tmp_head=nil
+        doc_title_endnote=@md.title.full.gsub(/(\*+)/,'<sup><a href="#endnotes">\1</a></sup>')
+        tmp_head=doc_title_endnote + "\n"
+        txt_obj={ txt: tmp_head }
+        format_txt_obj=SiSU_XHTML_EPUB2_Format::FormatTextObject.new(@md,txt_obj)
+        toc_shared << format_txt_obj.center_bold
+        segtoc << format_txt_obj.center_bold
+        if defined? @md.creator.author \
+        and @md.creator.author
+          creator_endnote=@md.creator.author.gsub(/(\*+)/,%{#{$ep[:hsp]}<sup><a href="#notes">\\1</a></sup>})
+          tmp_head=creator_endnote + "\n"
+          txt_obj={ txt: tmp_head }
+          format_txt_obj=SiSU_XHTML_EPUB2_Format::FormatTextObject.new(@md,txt_obj)
+          toc_shared << format_txt_obj.center_bold
+          segtoc << format_txt_obj.center_bold
+        end
+        tmp_head=nil
+        if defined? @md.prefix_a \
+        and @md.prefix_a
+          tmp_head ||= %{#{@md.prefix_a}\n}
+          toc_shared << tmp_head.dup
+          segtoc << tmp_head.dup
+        end
+        tmp_head=nil
+        toc_shared << @links_guide_toc
+        if defined? @md.rights.all \
+        and @md.rights.all
+          toc_shared << rights
+        end
+        if defined? @md.prefix_b \
+        and @md.prefix_b
+          toc_shared << prefix_b
+        end
+        #Table of Contents added/appended here
+        toc_shared << @per.scr
+        segtoc << @links_guide_toc
+        segtoc << @per.seg
+        if defined? @md.rights.all \
+        and @md.rights.all
+          segtoc << rights
+        end
+        if defined? @md.prefix_b \
+        and @md.prefix_b
+          segtoc << prefix_b
+        end
+        #Segtoc tail added here
+        segtoc << format_head_toc.xhtml_close
+        segtoc=segtoc.flatten.compact #watch
+        SiSU_XHTML_EPUB2::Source::Output.new(@md).make_cover_image
+        SiSU_XHTML_EPUB2::Source::Output.new(@md,segtoc).make_segtoc
+        segtoc=[]
+        @per.scr,@per.seg=[],[]
+        toc_shared
+      end
+    end
+    class Table < SiSU_XHTML_Table::TableXHTML
+    end
+    class Seg < SiSU_XHTML_EPUB2_Seg::Seg
+    end
+    class Output
+      def initialize(md,output='')
+        @md,@output=md,output
+        @epub_doc="#{@md.fnb}.epub"
+        @epub_header=SiSU_XHTML_EPUB2_Format::HeadInformation.new(@md)
+        @make=SiSU_Env::ProcessingSettings.new(@md)
+        @make_file=SiSU_Env::CreateFile.new(@md.fns)
+      end
+      def songsheet
+        mimetype
+        metainf_container
+        css
+        images if @md.ec[:image]
+       #concordance #uncomment to enable inclusion of concordance file
+        output_zip
+      end
+      def mimetype
+        out=@make_file.epub.mimetype
+        out<<@epub_header.mimetype
+        out.close
+      end
+      def metainf_container #container.xml file in META-INF directory
+        out=@make_file.epub.metainf_cont
+        out<<@epub_header.metainf_container
+        out.close
+      end
+      def css
+        out=@make_file.epub.xhtml_css
+        out << SiSU_XHTML_EPUB2_Format::CSS.new.css_epub_xhtml
+        out.close
+      end
+      def epub_toc_ncx
+        begin
+          out=@make_file.epub.toc_ncx
+          @output.each do |para|
+            unless para =~/\A\s*\Z/
+              out.puts para
+            end
+          end
+          out.close
+        rescue
+          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+        end
+      end
+      def epub_metadata_opf
+        begin
+          out=@make_file.epub.metadata
+          @output.each do |para|
+            unless para =~/\A\s*\Z/
+              out.puts para
+            end
+          end
+          out.close
+        rescue
+          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+        end
+      end
+      def images
+        img_pth=@md.env.path.image_source_include
+        img_src_pth=unless @md.opt.f_pth[:pth] =~/\/\S+?\/sisupod\/\S+?\/sisupod\/doc/
+          @md.file.output_path.epub.rel_image
+        else
+          pt=/(\/\S+?\/sisupod\/\S+?\/sisupod)\/doc/.match(@md.opt.f_pth[:pth])[1]
+          pt + '/image'
+        end
+        @md.ec[:image].each do |x|
+          if FileTest.directory?("#{@md.env.processing_path.epub}/#{Ep[:d_oebps]}/image") \
+          && FileTest.file?("#{img_src_pth}/#{x}")
+            FileUtils::cp("#{img_src_pth}/#{x}","#{@md.env.processing_path.epub}/#{Ep[:d_oebps]}/image")
+          elsif FileTest.directory?("#{@md.env.processing_path.epub}/#{Ep[:d_oebps]}/image") \
+          && FileTest.file?("#{img_pth}/#{x}")
+            FileUtils::cp("#{img_pth}/#{x}","#{@md.env.processing_path.epub}/#{Ep[:d_oebps]}/image")
+          else STDERR.puts %{\t*WARN* did not find image - "#{x}" in #{img_src_pth} or #{img_pth} [#{__FILE__}:#{__LINE__}]}
+          end
+        end
+      end
+      def concordance
+        SiSU_XHTML_EPUB2_Concordance::Source.new(@md.opt).read
+      end
+      def output_zip
+        FileUtils::mkdir_p(@md.file.output_path.epub.dir) unless FileTest.directory?(@md.file.output_path.epub.dir)
+        if FileTest.directory?(@md.env.processing_path.epub) \
+        and SiSU_Env::SystemCall.new.zip
+          pwd=Dir.pwd
+          Dir.chdir(@md.env.processing_path.epub)
+          system("
+            zip -qXr9D #{@epub_doc} *
+          ")
+          FileUtils::mv(@epub_doc, @md.file.place_file.epub.dir)
+          Dir.chdir(pwd)
+          unless @md.opt.act[:maintenance][:set]==:on
+            FileUtils::rm_r(@md.env.processing_path.epub)
+          end
+        else
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).mark('*EXITED epub* zip program not found') unless SiSU_Env::SystemCall.new.zip
+        end
+      end
+      def make_cover_image
+        begin
+          if @md.make.cover_image? \
+          and @md.make.cover_image.is_a?(Hash) \
+          and @md.make.cover_image[:cover] =~/\S+/
+            filename_xhtml=@make_file.epub.xhtml_cover_image
+            cover_image=<<WOK
+<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>Cover</title>
+    <meta http-equiv="Content-Type" content='text/html; charset=utf-8' />
+    <link rel="stylesheet" href="css/xhtml.css" type="text/css" />
+    <style type="text/css"> img { max-width: 100%; } </style>
+  </head>
+  <body xml:lang="en">
+    <div class="svg_outer">
+      <div class="svg_inner">
+        <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="0 0 #{@md.make.cover_image[:w]} #{@md.make.cover_image[:h]}" preserveAspectRatio="xMidYMid meet">
+        <image width="#{@md.make.cover_image[:w]}" height="#{@md.make.cover_image[:h]}" xl:href="image/#{@md.make.cover_image[:cover]}" />
+        </svg>
+      </div>
+    </div>
+  </body>
+</html>
+WOK
+            filename_xhtml.puts cover_image,"\n"
+            filename_xhtml.close
+          end
+        rescue
+          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+        end
+      end
+      def make_segtoc
+        begin
+          if @make.build.toc?
+            filename_xhtml=@make_file.epub.xhtml_index
+            @output.each do |para|
+              para=para.strip
+              unless para =~/\A\s*\Z/
+                filename_xhtml.puts para,"\n"
+              end
+            end
+            filename_xhtml.close
+          end
+        rescue
+          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** xhtml_epub2_concordance.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xhtml_epub2_concordance.rb"
+# <<sisu_document_header>>
+module SiSU_XHTML_EPUB2_Concordance
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+    include SiSU_Particulars
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'xhtml_parts'                        # xhtml_parts.rb
+  require_relative 'xhtml_epub2_format'                 # xhtml_epub2_format.rb
+    include SiSU_XHTML_EPUB2_Format
+  class Source
+    def initialize(opt)
+      @opt=opt
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+    end
+    def read
+      begin
+        @env,@md=@particulars.env,@particulars.md
+        wordmax=@env.concord_max
+        unless @md.wc_words.nil?
+          if @md.wc_words < wordmax
+            SiSU_XHTML_EPUB2_Concordance::Source::Words.new(@particulars).songsheet
+          else
+            SiSU_Screen::Ansi.new(
+              @md.opt.act[:color_state][:set],
+              "*WARN* concordance skipped, large document has over #{wordmax} words (#{@md.wc_words})"
+            ).warn unless @md.opt.act[:quiet][:set]==:on
+          end
+        else
+          SiSU_Screen::Ansi.new(
+            @md.opt.act[:color_state][:set],
+            "*WARN* wc (word count) is off, concordance will be processed for all files including those over the max set size of: #{wordmax} words"
+          ).warn unless @md.opt.act[:quiet][:set]==:on
+          SiSU_XHTML_EPUB2_Concordance::Source::Words.new(@particulars).songsheet
+        end
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    private
+    class DocTitle
+      #revisit, both requires (html & xml_shared) needed for stand alone operation (sisu -w [filename])
+      require_relative 'xhtml_epub2'                    # xhtml_epub2.rb
+      def initialize(particulars)
+        @particulars,@md=particulars,particulars.md
+        @data=SiSU_XHTML_EPUB2::Source::XHTML_Environment.new(particulars).tuned_file_instructions
+        @fnb=@md.fnb
+        @lex_button=%{<a href="http://www.jus.uio.no/sisu/" target="_top"><img border="0" height="44" width="144" valign="center" src="../_sisu/image/sisu.png" alt="SiSU home"></a>}
+        @doc_details =<<WOK
+<table summary="links to text related to this rudimentary index" width="96%" border="0" bgcolor="white" cellpadding="0" align="center"><tr><td width="2%" align="right">#{$ep[:hsp]}</td><td width="94%" valign="top" align="justify"><h1 class="small"><a href="#{@md.file.base_filename.epub}"><b>#{@md.title.full}</b></a></h1><p class="bold">#{@md.creator.author}</p></td></tr></table>
+WOK
+      end
+      def create
+        @css=SiSU_Env::CSS_Stylesheet.new(@particulars.md)
+        format_head_toc=SiSU_XHTML_EPUB2_Format::HeadToc.new(@md)
+        dochead=format_head_toc.head
+        <<WOK
+#{dochead}
+<div class="content">
+ #{@doc_details}
+<p>Word index links are to html versions of the text the segmented version followed by the scroll (single document) version.<br />[For segmented text references [T1], [T2] or [T3] appearing without a link, indicates that the word appears in a title (or subtitle) of the text (that is identifiable by the appended object citation number).]</p>
+<p>(The word listing/index is Case sensitive: Capitalized words appear before lower case)</p>
+  <p>
+    <b>word</b> (number of occurences)<br />linked references to word within document <br />
+    [if number of occurences exceed number of references - word occurs more than once in at least one reference. Footnote/endnotes are either assigned to the paragraph from which they are referenced or ignored, so it is relevant to check the footnotes referenced from within a paragraph as well.]
+  </p>
+  <p>
+    (After the page is fully loaded) you can jump directly to a word by appending a hash (#) and the word to the url for this text, (do not forget that words are case sensitive, and may be listed twice (starting with and without an upper case letter)), #your_word # [#{$ep[:hsp]}http://[web host]/#{@fnb}/concordance.html#your_word#{$ep[:hsp]}]
+  </p>
+WOK
+      end
+    end
+    class Word
+      @@word_previous=''
+      def initialize(word,freq)
+        @word,@freq=word,freq
+      end
+      def html
+        w=if @word.capitalize==@@word_previous
+          %{\n<p class="concordance_word">#{@word}</p><p class="concordance_count">(#{@freq})</p>\n\t<p class="concordance_object"> }
+        else n=@word.strip.gsub(/\s+/,'_') #also need to convert extended character set to html
+          %{\n<p class="concordance_word"><a name="#{n}">#{@word}</a></p><p class="concordance_count">(#{@freq})</p>\n\t<p class="concordance_object"> }
+        end
+        @@word_previous=@word.capitalize
+        w
+      end
+    end
+    class Words
+      require_relative 'xhtml_epub2_format'             # xhtml_epub2_format.rb
+        include SiSU_XHTML_EPUB2_Format
+      require_relative 'se'                             # se.rb
+        include SiSU_Screen
+      def initialize(particulars)
+        @particulars=particulars
+        begin
+          @env,@md,@ao_array=particulars.env,particulars.md,particulars.ao_array
+          @path="#{@env.processing_path.epub}"
+          @freq=Hash.new(0)
+          @rxp_lv0=/^#{Mx[:lv_o]}0:/
+          @rxp_lv1=/^#{Mx[:lv_o]}1:/
+          @rxp_lv2=/^#{Mx[:lv_o]}2:/
+          @rxp_lv3=/^#{Mx[:lv_o]}3:/
+          @rxp_seg=/^#{Mx[:lv_o]}4:(\S+?)#{Mx[:lv_c]}/
+          @rxp_title=Regexp.new("^#{Mx[:meta_o]}title#{Mx[:meta_c]}\s*(.+?)\s*$")
+          @rxp_t0=Regexp.new('^T0')
+          @rxp_t1=Regexp.new('^T1')
+          @rxp_t2=Regexp.new('^T2')
+          @rxp_t3=Regexp.new('^T3')
+          @rxp_excluded1=/(?:https?|file|ftp):\/\/\S+/
+          @rxp_excluded0=/^(?:#{Mx[:fa_bold_o]}|#{Mx[:fa_italics_o]})?(?:to\d+|\d+|&nbsp;|#{Mx[:br_endnotes]}|EOF|#{Mx[:br_eof]}|thumb_\S+|snap_\S+|_+|-+|[(]?(?:ii+|iv|vi+|ix|xi+|xiv|xv|xvi+|xix|xx)[).]?|\S+?_\S+|[\d_]+\w\S+|[\w\d]{1,2}|\d{1,3}\w?|[0-9a-f]{16,64}|\d{2,3}x\d{2,3}|\S{0,2}sha\d|\S{0,3}\d{4}w\d\d|\b\w\d+|\d_all\b|e\.?g\.?)(?:#{Mx[:fa_bold_c]}|#{Mx[:fa_italics_c]})?$/mi #this regex causes and cures a stack dump in ruby 1.9 !!!
+          @rgx_splitlist=%r{[—.,;:-]+|#{Mx[:nbsp]}+}mi
+          @rgx_scanlist=%r{#{Mx[:fa_italics_o]}[a-zA-Z0-9"\s]{2,12}#{Mx[:fa_italics_c]}|#{Mx[:fa_bold_o]}[a-zA-Z0-9"\s]{2,12}#{Mx[:fa_bold_c]}|#{Mx[:url_o]}https?://\S+?#{Mx[:url_c]}|file://\S+|<\S+?>|\w+|[a-zA-Z]+}mi
+        rescue
+          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+        end
+      end
+      def songsheet
+        begin
+          #fix to use
+          p __LINE__.to_s + ':' + __FILE__
+          p "#{@path}/content/#{@md.fn[:epub_concord]}"
+          p "#{@md.file.output_path.epub.dir}/#{@md.file.base_filename.epub}"
+          @file_concordance=File.open("#{@path}/content/#{@md.fn[:epub_concord]}",'w')
+          map_para
+        rescue
+          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+        ensure
+          @file_concordance.close
+        end
+      end
+    protected
+      def location_scroll(wordlocation,show)
+        @wordlocation=wordlocation
+        %{<a href="doc#{Sfx[:epub_xhtml]}\##{@wordlocation}">#{@wordlocation}</a>;  }
+      end
+      def location_seg(wordlocation,show)
+        @wordlocation,@show=wordlocation,show
+        @word_location_seg=wordlocation.gsub(/(.+?)\#(\d+)/,"\\1#{Sfx[:epub_xhtml]}#o\\2") unless wordlocation.nil?
+        case @wordlocation
+        when @rxp_t1
+          %{[<a href="doc#{Sfx[:epub_xhtml]}##{@show}">H</a>]#{@show},  }
+        when @rxp_t2
+          %{[<a href="doc#{Sfx[:epub_xhtml]}##{@show}">H</a>]#{@show},  }
+        when @rxp_t3
+          %{[<a href="doc#{Sfx[:epub_xhtml]}##{@show}">H</a>]#{@show},  }
+        else %{<a href="#{@word_location_seg}">#{@show}</a>,  }
+        end
+      end
+      def map_para
+        @seg,toy=nil,nil
+        @word_map={}
+        @ao_array.each do |line|
+          if defined? line.ocn
+            if (line.is ==:heading \
+            || line.is ==:heading_insert) \
+            && line.ln==4
+              @seg=line.name
+            end
+            if line.ocn.to_s =~/\d+/ then toy=line.ocn.to_s
+            end
+            if toy =~/\d+/ \
+            and toy !~/^0$/
+              line.obj=line.obj.split(@rgx_splitlist).join(' ') #%take in word or other match
+              for word in line.obj.scan(@rgx_scanlist) #%take in word or other match
+                word=word.gsub(/#{Mx[:lnk_o]}|#{Mx[:lnk_c]}|#{Mx[:url_o]}|#{Mx[:url_c]}/,'').
+                  gsub(/#{Mx[:fa_o]}\S+?#{Mx[:fa_o_c]}/,'').
+                  gsub(/#{Mx[:fa_c_o]}\S+?#{Mx[:fa_c]}/,'').
+                  gsub(/#{Mx[:gl_o]}#[a-z]+#{Mx[:gl_c]}/,'').
+                  gsub(/#{Mx[:gl_o]}#[0-9]+#{Mx[:gl_c]}/,'').
+                  gsub(/^\S$/,'')
+                word=nil if word.empty?
+                word=nil if word =~@rxp_excluded0 #watch
+                word=nil if word =~@rxp_excluded1 #watch
+                word=nil if word =~/^\S$/
+                if word
+                  word=word.gsub(/#{Mx[:br_nl]}|#{Mx[:br_line]}/,' ').
+                    gsub(/#{Mx[:fa_o]}[a-z]{1,7}#{Mx[:fa_o_c]}|#{Mx[:fa_c_o]}[a-z]{1,7}#{Mx[:fa_c]}/,'').
+                    gsub(/#{Mx[:mk_o]}(?:[0-9a-f]{32}:[0-9a-f]{32}|[0-9a-f]{64}:[0-9a-f]{64})#{Mx[:mk_c]}/,'').
+                    gsub(/#{Mx[:mk_o]}(?:[0-9a-f]{32}|[0-9a-f]{64})#{Mx[:mk_c]}/,'').
+                    gsub(/#{Mx[:en_a_o]}(?:\d|[*+])*|#{Mx[:en_b_o]}(?:\d|[*+])*|#{Mx[:en_a_c]}|#{Mx[:en_b_c]}/mi,'').
+                    gsub(/#{Mx[:fa_o]}\S+?#{Mx[:fa_o_c]}/,'').gsub(/#{Mx[:fa_c_o]}\S+?#{Mx[:fa_c]}/,'').
+                    gsub(/<\/?\S+?>/,'').
+                    gsub(/^\@+/,'').
+                    strip.
+                    gsub(/#{Mx[:tc_p]}.+/,'').
+                    gsub(/[\.,;:"]$/,'').
+                    gsub(/["]/,'').
+                    gsub(/^\s*[\(]/,'').
+                    gsub(/[\(]\s*$/,'').
+                    gsub(/^(?:See|e\.?g\.?).+/,'').
+                    gsub(/^\s*[.,;:]\s*/,'').
+                    strip.
+                    gsub(/^\(?[a-zA-Z]\)$/,'').
+                    gsub(/^\d+(st|nd|rd|th)$/,'').
+                    gsub(/^(\d+\.?)+$/, '').
+                    gsub(/#{Mx[:mk_o]}|#{Mx[:mk_c]}/,'').
+                    gsub(/:name#\S+/,'').
+                    gsub(/^\S$/,'')
+                  word=nil if word =~/^\S$/
+                  word=nil if word =~/^\s*$/ #watch
+                  if word
+                    unless word =~/[A-Z][A-Z]/ \
+                    or word =~/\w+\s\w+/
+                      word=word.capitalize
+                    end
+                    @freq[word] +=1
+                    @word_map[word] ||= []
+                    if line !~@rxp_lv0 \
+                    and line !~@rxp_lv1 \
+                    and line !~@rxp_lv2 \
+                    and line !~@rxp_lv3
+                      @word_map[word] << location_seg("#{@seg}\##{toy}",toy)
+                    else
+                      @word_map[word] << case line
+                      when @rxp_lv0 then location_seg('T0',toy)
+                      when @rxp_lv1 then location_seg('T1',toy)
+                      when @rxp_lv2 then location_seg('T2',toy)
+                      when @rxp_lv3 then location_seg('T3',toy)
+                      end
+                    end
+                  end
+                end
+              end
+            end
+          end
+        end
+        seg=''
+        @file_concordance << SiSU_XHTML_EPUB2_Concordance::Source::DocTitle.new(@particulars).create
+        alph=%W[A B C D E F G H I J K L M N O P Q R S T U V W X Y Z]
+        @file_concordance << '<p>'
+        alph.each {|x| @file_concordance << %{<a href="##{x}">#{x}</a>,#{$ep[:hsp]}}}
+        @file_concordance << '</p>'
+        letter=alph.shift
+        @file_concordance << %{\n<p class="letter"><a name="A">A</a></p>}
+        for word in @freq.keys.sort! {|a,b| a.downcase<=>b.downcase}
+          f=/^(\S)/.match(word)[1]
+          if letter < f.upcase
+            while letter < f.upcase
+              if alph.length > 0
+                letter=alph.shift
+                @file_concordance << %{\n<p class="letter"><a name="#{letter}">#{letter}</a></p>}
+              else break
+              end
+            end
+          end
+          keyword=SiSU_XHTML_EPUB2_Concordance::Source::Word.new(word,@freq[word]).html
+          if keyword !~ @rxp_excluded0
+            if @word_map[word][0] =~ /\d+/
+              @file_concordance << %{#{keyword}#{seg}#{@word_map[word].uniq.compact.join}}
+            end
+            @file_concordance << '</p>'
+          end
+          # special cases endnotes and header levels 1 - 3
+        end
+        credits=SiSU_Proj_XHTML::Bits.new.credits_sisu_epub
+        @file_concordance << %{</div>#{credits}</body>\n</html>} # footer
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** xhtml_epub2_format.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xhtml_epub2_format.rb"
+# <<sisu_document_header>>
+module SiSU_XHTML_EPUB2_Format
+  class ParagraphNumber
+    def initialize(md,ocn)
+      @md,@ocn=md,ocn.to_s
+      @ocn ||=''
+    end
+    def ocn_display
+      make=SiSU_Env::ProcessingSettings.new(@md)
+      if make.build.ocn?
+        ocn_class='ocn'
+        if @ocn==nil \
+        or @ocn.to_i==0 \
+        or @ocn.empty?
+          %{<label class="ocn_off"></label>}
+        else
+          @ocn.gsub(/^(\d+|)$/,
+            %{<label class="#{ocn_class}"><a href="#o\\1" class="lnk#{ocn_class}">\\1</a></label>})
+        end
+      else
+        %{<label class="ocn_off"></label>}
+      end
+    end
+    def name
+      (@ocn==nil || @ocn.empty?) ? '' : %{<a name="#{@ocn}"></a>}
+    end
+    def id #w3c? "tidy" complains about numbers as identifiers ! annoying
+      (@ocn==nil || @ocn.empty?) ? '' : %{id="o#{@ocn}"}
+    end
+    def goto
+      (@ocn==nil || @ocn.empty?) ? '' : %{<a href="##{@ocn}">}
+    end
+  end
+  class CSS
+    def css_epub_xhtml
+      <<-WOK
+/* SiSU epub css default stylesheet */
+  body {
+    color: black;
+    background: #ffffff;
+    background-color: #ffffff;
+  }
+/*
+    table {
+      margin-left: 5%;
+      display: block;
+    }
+    tr {
+      display: block;
+    }
+    th,td {
+      display: inline;
+      vertical-align: top;
+    }
+*/
+  a:link {
+    color: #003399;
+    text-decoration: none;
+  }
+  a:visited {
+    color: #003399;
+    text-decoration: none;
+  }
+  a:hover {
+    color: #000000;
+    background-color: #f9f9aa;
+  }
+/*
+  a:hover {
+    border-bottom: 2px solid #777777;
+    background-color: #fff3b6;
+  }
+*/
+  a:hover img {
+    background-color: #ffffff;
+  }
+  a:active {
+    color: #003399;
+    text-decoration: underline;
+  }
+  a.lnkocn:link {
+    color: #777777;
+    text-decoration: none;
+  }
+  div {
+    margin-left: 0;
+    margin-right: 0;
+  }
+  div.p {
+    margin-left: 5%;
+    margin-right: 1%;
+  }
+
+  .norm, .bold, .verse, .group, .block, .alt {
+    line-height: 133%;
+    margin-left: 0em;
+    margin-right: 2em;
+    margin-top: 12px;
+    margin-bottom: 0px;
+    padding-left: 0em;
+    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: 133%;
+    text-align: justify;
+    margin-left: 0em;
+    margin-right: 2em;
+    text-indent: 0mm;
+    margin-top: 0.8em;
+    margin-bottom: 0.8em;
+  }
+  p.norm { }
+  p.i1 {padding-left: 1em;}
+  p.i2 {padding-left: 2em;}
+  p.i3 {padding-left: 3em;}
+  p.i4 {padding-left: 4em;}
+  p.i5 {padding-left: 5em;}
+  p.i6 {padding-left: 6em;}
+  p.i7 {padding-left: 7em;}
+  p.i8 {padding-left: 8em;}
+  p.i9 {padding-left: 9em;}
+
+  p.h0i0 {
+    padding-left: 0em;
+    text-indent:  0em;
+  }
+  p.h0i1 {
+    padding-left: 1em;
+    text-indent: -1em;
+  }
+  p.h0i2 {
+    padding-left: 2em;
+    text-indent: -2em;
+  }
+  p.h0i3 {
+    padding-left: 3em;
+    text-indent: -3em;
+  }
+  p.h0i4 {
+    padding-left: 4em;
+    text-indent: -4em;
+  }
+  p.h0i5 {
+    padding-left: 5em;
+    text-indent: -5em;
+  }
+  p.h0i6 {
+    padding-left: 6em;
+    text-indent: -6em;
+  }
+  p.h0i7 {
+    padding-left: 7em;
+    text-indent: -7em;
+  }
+  p.h0i8 {
+    padding-left: 8em;
+    text-indent: -8em;
+  }
+  p.h0i9 {
+    padding-left: 9em;
+    text-indent: -9em;
+  }
+
+  p.h1i0 {
+    padding-left: 0em;
+    text-indent:  1em;
+  }
+  p.h1i1 {
+    padding-left: 1em;
+    text-indent:  0em;
+  }
+  p.h1i2 {
+    padding-left: 2em;
+    text-indent: -1em;
+  }
+  p.h1i3 {
+    padding-left: 3em;
+    text-indent: -2em;
+  }
+  p.h1i4 {
+    padding-left: 4em;
+    text-indent: -3em;
+  }
+  p.h1i5 {
+    padding-left: 5em;
+    text-indent: -4em;
+  }
+  p.h1i6 {
+    padding-left: 6em;
+    text-indent: -5em;
+  }
+  p.h1i7 {
+    padding-left: 7em;
+    text-indent: -6em;
+  }
+  p.h1i8 {
+    padding-left: 8em;
+    text-indent: -7em;
+  }
+  p.h1i9 {
+    padding-left: 9em;
+    text-indent: -8em;
+  }
+
+  p.h2i0 {
+    padding-left: 0em;
+    text-indent:  2em;
+  }
+  p.h2i1 {
+    padding-left: 1em;
+    text-indent:  1em;
+  }
+  p.h2i2 {
+    padding-left: 2em;
+    text-indent:  0em;
+  }
+  p.h2i3 {
+    padding-left: 3em;
+    text-indent: -1em;
+  }
+  p.h2i4 {
+    padding-left: 4em;
+    text-indent: -2em;
+  }
+  p.h2i5 {
+    padding-left: 5em;
+    text-indent: -3em;
+  }
+  p.h2i6 {
+    padding-left: 6em;
+    text-indent: -4em;
+  }
+  p.h2i7 {
+    padding-left: 7em;
+    text-indent: -5em;
+  }
+  p.h2i8 {
+    padding-left: 8em;
+    text-indent: -6em;
+  }
+  p.h2i9 {
+    padding-left: 9em;
+    text-indent: -7em;
+  }
+
+  p.h3i0 {
+    padding-left: 0em;
+    text-indent:  3em;
+  }
+  p.h3i1 {
+    padding-left: 1em;
+    text-indent:  2em;
+  }
+  p.h3i2 {
+    padding-left: 2em;
+    text-indent:  1em;
+  }
+  p.h3i3 {
+    padding-left: 3em;
+    text-indent:  0em;
+  }
+  p.h3i4 {
+    padding-left: 4em;
+    text-indent: -1em;
+  }
+  p.h3i5 {
+    padding-left: 5em;
+    text-indent: -2em;
+  }
+  p.h3i6 {
+    padding-left: 6em;
+    text-indent: -3em;
+  }
+  p.h3i7 {
+    padding-left: 7em;
+    text-indent: -4em;
+  }
+  p.h3i8 {
+    padding-left: 8em;
+    text-indent: -5em;
+  }
+  p.h3i9 {
+    padding-left: 9em;
+    text-indent: -6em;
+  }
+
+  p.h4i0 {
+    padding-left: 0em;
+    text-indent:  4em;
+  }
+  p.h4i1 {
+    padding-left: 1em;
+    text-indent:  3em;
+  }
+  p.h4i2 {
+    padding-left: 2em;
+    text-indent:  2em;
+  }
+  p.h4i3 {
+    padding-left: 3em;
+    text-indent:  1em;
+  }
+  p.h4i4 {
+    padding-left: 4em;
+    text-indent:  0em;
+  }
+  p.h4i5 {
+    padding-left: 5em;
+    text-indent: -1em;
+  }
+  p.h4i6 {
+    padding-left: 6em;
+    text-indent: -2em;
+  }
+  p.h4i7 {
+    padding-left: 7em;
+    text-indent: -3em;
+  }
+  p.h4i8 {
+    padding-left: 8em;
+    text-indent: -4em;
+  }
+  p.h4i9 {
+    padding-left: 9em;
+    text-indent: -5em;
+  }
+
+  p.h5i0 {
+    padding-left: 0em;
+    text-indent:  5em;
+  }
+  p.h5i1 {
+    padding-left: 1em;
+    text-indent:  4em;
+  }
+  p.h5i2 {
+    padding-left: 2em;
+    text-indent:  3em;
+  }
+  p.h5i3 {
+    padding-left: 3em;
+    text-indent:  2em;
+  }
+  p.h5i4 {
+    padding-left: 4em;
+    text-indent:  1em;
+  }
+  p.h5i5 {
+    padding-left: 5em;
+    text-indent:  0em;
+  }
+  p.h5i6 {
+    padding-left: 6em;
+    text-indent: -1em;
+  }
+  p.h5i7 {
+    padding-left: 7em;
+    text-indent: -2em;
+  }
+  p.h5i8 {
+    padding-left: 8em;
+    text-indent: -3em;
+  }
+  p.h5i9 {
+    padding-left: 9em;
+    text-indent: -4em;
+  }
+
+  p.h6i0 {
+    padding-left: 0em;
+    text-indent:  6em;
+  }
+  p.h6i1 {
+    padding-left: 1em;
+    text-indent:  5em;
+  }
+  p.h6i2 {
+    padding-left: 2em;
+    text-indent:  4em;
+  }
+  p.h6i3 {
+    padding-left: 3em;
+    text-indent:  3em;
+  }
+  p.h6i4 {
+    padding-left: 4em;
+    text-indent:  2em;
+  }
+  p.h6i5 {
+    padding-left: 5em;
+    text-indent:  1em;
+  }
+  p.h6i6 {
+    padding-left: 6em;
+    text-indent:  0em;
+  }
+  p.h6i7 {
+    padding-left: 7em;
+    text-indent: -1em;
+  }
+  p.h6i8 {
+    padding-left: 8em;
+    text-indent: -2em;
+  }
+  p.h6i9 {
+    padding-left: 9em;
+    text-indent: -3em;
+  }
+
+  p.h7i0 {
+    padding-left: 0em;
+    text-indent:  7em;
+  }
+  p.h7i1 {
+    padding-left: 1em;
+    text-indent:  6em;
+  }
+  p.h7i2 {
+    padding-left: 2em;
+    text-indent:  5em;
+  }
+  p.h7i3 {
+    padding-left: 3em;
+    text-indent:  4em;
+  }
+  p.h7i4 {
+    padding-left: 4em;
+    text-indent:  3em;
+  }
+  p.h7i5 {
+    padding-left: 5em;
+    text-indent:  2em;
+  }
+  p.h7i6 {
+    padding-left: 6em;
+    text-indent:  1em;
+  }
+  p.h7i7 {
+    padding-left: 7em;
+    text-indent:  0em;
+  }
+  p.h7i8 {
+    padding-left: 8em;
+    text-indent: -1em;
+  }
+  p.h7i9 {
+    padding-left: 9em;
+    text-indent: -2em;
+  }
+
+  p.h8i0 {
+    padding-left: 0em;
+    text-indent:  8em;
+  }
+  p.h8i1 {
+    padding-left: 1em;
+    text-indent:  7em;
+  }
+  p.h8i2 {
+    padding-left: 2em;
+    text-indent:  6em;
+  }
+  p.h8i3 {
+    padding-left: 3em;
+    text-indent:  5em;
+  }
+  p.h8i4 {
+    padding-left: 4em;
+    text-indent:  4em;
+  }
+  p.h8i5 {
+    padding-left: 5em;
+    text-indent:  3em;
+  }
+  p.h8i6 {
+    padding-left: 6em;
+    text-indent:  2em;
+  }
+  p.h8i7 {
+    padding-left: 7em;
+    text-indent:  1em;
+  }
+  p.h8i8 {
+    padding-left: 8em;
+    text-indent:  0em;
+  }
+  p.h8i9 {
+    padding-left: 9em;
+    text-indent: -1em;
+  }
+
+  p.h9i0 {
+    padding-left: 0em;
+    text-indent:  9em;
+  }
+  p.h9i1 {
+    padding-left: 1em;
+    text-indent:  8em;
+  }
+  p.h9i2 {
+    padding-left: 2em;
+    text-indent:  7em;
+  }
+  p.h9i3 {
+    padding-left: 3em;
+    text-indent:  6em;
+  }
+  p.h9i4 {
+    padding-left: 4em;
+    text-indent:  5em;
+  }
+  p.h9i5 {
+    padding-left: 5em;
+    text-indent:  4em;
+  }
+  p.h9i6 {
+    padding-left: 6em;
+    text-indent:  3em;
+  }
+  p.h9i7 {
+    padding-left: 7em;
+    text-indent:  2em;
+  }
+  p.h9i8 {
+    padding-left: 8em;
+    text-indent:  1em;
+  }
+  p.h9i9 {
+    padding-left: 9em;
+    text-indent:  0em;
+  }
+
+  p.it0 {
+    margin-left: 0em;
+    margin-top: 6px;
+    margin-bottom: 0px;
+    line-height: 100%;
+  }
+  p.it1 {
+    margin-left: 1em;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    line-height: 100%;
+  }
+  p.it2 {
+    margin-left: 2em;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    line-height: 100%;
+  }
+  p.it3 {
+    margin-left: 3em;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    line-height: 100%;
+  }
+  p.it4 {
+    margin-left: 4em;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    line-height: 100%;
+  }
+  p.it5 {
+    margin-left: 5em;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    line-height: 100%;
+  }
+  p.it6 {
+    margin-left: 6em;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    line-height: 100%;
+  }
+  p.it7 {
+    margin-left: 7em;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    line-height: 100%;
+  }
+  p.it8 {
+    margin-left: 8em;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    line-height: 100%;
+  }
+  p.it9 {
+    margin-left: 9em;
+    margin-bottom: 0px;
+    margin-top: 0px;
+    line-height: 100%;
+  }
+
+  p.group { }
+
+  p.block { }
+
+  p.alt { }
+
+  p.verse {
+    margin-bottom: 6px;
+  }
+
+  p.code {
+    font-family: inconsolata, andale mono, courier new, courier, monospace;
+    font-size: 90%;
+    text-align: left;
+    background-color: #eeeeee;
+  }
+
+  p.caption {
+    text-align: left;
+    font-size: 80%;
+    display: inline;
+  }
+
+  p.endnote {
+    font-size: 96%;
+    line-height: 120%;
+    text-align: left;
+    margin-right: 2em;
+  }
+  p.endnote_indent {
+    font-size: 96%;
+    line-height: 120%;
+    text-align: left;
+    margin-left: 2em;
+    margin-right: 2em;
+  }
+
+  p.center {
+    text-align: center;
+  }
+  p.align_right {
+    text-align: right;
+  }
+  p.bold {
+    font-weight: bold;
+  }
+  p.bold_left {
+    font-weight: bold;
+    text-align: left;
+  }
+  p.centerbold {
+    text-align: center;
+    font-weight: bold;
+  }
+  p.em {
+    font-weight: bold;
+    font-style: normal;
+    background: #fff3b6;
+  }
+
+  p.small {
+    font-size: 80%;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    margin-right: 6px;
+    text-align: left;
+  }
+
+  .tiny, .tiny_left, .tiny_right, .tiny_center {
+    font-size: 10px;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    color: #777777;
+    margin-right: 6px;
+    text-align: left;
+  }
+  p.tiny { }
+  p.tiny_left {
+    margin-left: 0px;
+    margin-right: 0px;
+    text-align: left;
+  }
+  p.tiny_right {
+    margin-right: 1em;
+    text-align: right;
+  }
+  p.tiny_center {
+    margin-left: 0px;
+    margin-right: 0px;
+    text-align: center;
+  }
+
+  p.concordance_word {
+    line-height: 150%;
+    font-weight: bold;
+    display: inline;
+    margin-top: 4px;
+    margin-bottom: 1px;
+  }
+  p.concordance_count {
+    font-size: 80%;
+    color: #777777;
+    display: inline;
+    margin-left: 0em;
+  }
+  p.concordance_object {
+    font-size: 80%;
+    line-height: 120%;
+    text-align: left;
+    margin-left: 3em;
+    margin-top: 1px;
+    margin-bottom: 3px;
+  }
+  p.book_index_lev1 {
+    line-height: 100%;
+    margin-top: 4px;
+    margin-bottom: 1px;
+  }
+  p.book_index_lev2 {
+    line-height: 100%;
+    text-align: left;
+    margin-left: 3em;
+    margin-top: 1px;
+    margin-bottom: 3px;
+  }
+
+  p.quickref {
+    font-size: 10px;
+    font-style: italic;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    color: #777777;
+    margin-right: 5px;
+    text-align: left;
+  }
+  p.bigref {
+    font-size: 11px;
+    font-weight: bold;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    color: #777777;
+    margin-right: 5px;
+    text-align: center;
+  }
+
+  p.letter {
+    font-weight: bold;
+    font-size: 80%;
+    margin-left: 0em;
+    margin-top: 2px;
+    margin-bottom: 2px;
+    margin-right: 6px;
+    text-align: left;
+    color: white;
+    background: #880000;
+  }
+
+  tt {
+    font-family: inconsolata, andale mono, courier new, courier, monospace;
+    background-color: #eeeeee;
+  }
+
+  label.ocn {
+    width: 2%;
+    float: right;
+    top: 0;
+    font-size: 10px;
+    margin-top: 0px;
+    margin-bottom: 5px;
+    color: #777777;
+    margin-right: 5px;
+    text-align: right;
+    background-color: #ffffff;
+  }
+
+  table { }
+  tr { }
+  th,td {
+    vertical-align: top;
+    text-align: left;
+  }
+  th {
+    font-weight: bold;
+  }
+
+  p.left, th.left, td.left {
+    text-align: left;
+  }
+  p.small_left, th.small_left, td.small_left {
+    text-align: left;
+    font-size: 80%;
+  }
+  p.right, th.right, td.right {
+    text-align: right;
+  }
+
+  #horizontal_links {
+    background: #eeeeee;
+    margin-left: 5%;
+    margin-right: 5%;
+  }
+  #horizontal {
+    margin: 0;
+    padding: 0 0 0 10px;
+    border-top: 1px solid #000077;
+    border-bottom: 1px solid #000077;
+  }
+  #horizontal li {
+    margin: 0 0 0 0;
+    padding: 0 16px 0 0;
+    display: inline;
+    list-style-type: none;
+    text-align: left;
+    background: none;
+  }
+  #horizontal a {
+    line-height: 12px;
+    margin: 0 0 0 0;
+    text-decoration: none;
+    color: #000077;
+  }
+  #horizontal a.active, #horizontal a:hover {
+    border-bottom: 2px solid #777777;
+    padding-bottom: 2px;
+    color: #000077;
+  }
+  #horizontal a:hover {
+    color: #000077;
+  }
+
+  #document_versions {
+    position: absolute;
+    top: 10mm;
+    right: 2%;
+    width: 12%;
+    float: right;
+  }
+
+  #vertical_links {
+    position: absolute;
+    top: 10mm;
+    right: 0px;
+    width: 20%;
+    background: #dddddd;
+    float: right;
+  }
+  #vertical {
+    padding: 0 12px 0px 0px;
+    margin-left: 2%;
+    margin-right: 2%;
+  }
+  #vertical li {
+    display: block;
+    list-style-type: none;
+  }
+  #vertical a {
+    line-height: 12px;
+    text-decoration: none;
+    color: #000077;
+  }
+  #vertical a.active, #vertical a:hover {
+    border-bottom: 2px solid #777777;
+    padding-bottom: 2px;
+    color: #000077;
+  }
+
+  ul, li {
+    list-style-type: none;
+    list-style: none;
+    padding-left: 20px;
+    display: block;
+    font-family: verdana, arial, georgia, tahoma, sans-serif, helvetica, times, roman;
+    font-weight: normal;
+    line-height: 150%;
+    text-align: justify;
+    text-indent: 0mm;
+    margin-left: 1em;
+    margin-right: 2em;
+    margin-top: 3px;
+    margin-bottom: 3px;
+  }
+
+  li {
+    background: url(../image/bullet_09.png) no-repeat 0px 6px;
+  }
+
+  ul {
+  }
+  li.bullet { margin-left: 0em; }
+  li.i1 { margin-left: 1em; }
+  li.i2 { margin-left: 2em; }
+  li.i3 { margin-left: 3em; }
+  li.i4 { margin-left: 4em; }
+  li.i5 { margin-left: 5em; }
+  li.i6 { margin-left: 6em; }
+  li.i7 { margin-left: 7em; }
+  li.i8 { margin-left: 8em; }
+  li.i9 { margin-left: 9em; }
+
+  li.doc, li.ref, li.refcenter {
+    margin-top: 0px;
+    margin-bottom: 0px;
+    margin-right: 0px;
+    font-size: 8px;
+    font-style: normal;
+    text-align: left;
+  }
+  li.doc {
+    background: url(../image/bullet_09.png) no-repeat 0px 6px;
+    padding-left: 16px;
+    margin-left: 10px;
+    margin-right: 0px;
+  }
+  li.ref {
+    background: none;
+    padding-left: 0;
+    margin-left: 0;
+    color: #777777;
+  }
+  li.refcenter {
+    background: url(../image/bullet_09.png) no-repeat 0px 6px;
+    padding-left: 20px;
+    margin-left: 10%;
+    font-size: 9px;
+    color: #777777;
+    text-align: center;
+  }
+  li.refbold {
+    list-style-type: none;
+    padding-left: 16px;
+    margin-left: 0;
+    margin-right: 10mm;
+    font-weight: bold;
+  }
+
+  h0, h1, h2, h3, h4, h5, h6, h7 {
+    font-weight: bold;
+    line-height: 120%;
+    text-align: left;
+    margin-top: 20px;
+    margin-bottom: 10px;
+  }
+  h4.norm, h5.norm, h6.norm, h7.norm {
+    margin-top: 10px;
+    margin-bottom: 0px;
+  }
+  h1.center, h2.center, h3.center, h4.center, h5.center, h6.center, h7.center {
+    text-align: center;
+  }
+  h1 { font-size: 120%; }
+  h2 { font-size: 115%; }
+  h3 { font-size: 110%; }
+  h4 { font-size: 105%; }
+  h5 { font-size: 100%; }
+  h6 { font-size: 100%; }
+  h7 { font-size: 100%; }
+  h0 { font-size: 80%; }
+
+  h1.i {margin-left: 2em;}
+  h2.i {margin-left: 3em;}
+  h3.i {margin-left: 4em;}
+  h4.i {margin-left: 5em;}
+  h5.i {margin-left: 6em;}
+  h6.i {margin-left: 7em;}
+  h7.i {margin-left: 8em;}
+  h8.i {margin-left: 9em;}
+  h9.i {margin-left: 10em;}
+
+  .toc {
+    font-weight: normal;
+    margin-top: 6px;
+    margin-bottom: 6px;
+  }
+  h1.toc {
+    margin-left: 1em;
+    font-size: 115%;
+    line-height: 150%;
+  }
+  h2.toc {
+    margin-left: 2em;
+    font-size: 110%;
+    line-height: 140%;
+  }
+  h3.toc {
+    margin-left: 3em;
+    font-size: 105%;
+    line-height: 120%;
+  }
+  h4.toc {
+    margin-left: 4em;
+    font-size: 100%;
+    line-height: 120%;
+  }
+  h5.toc {
+    margin-left: 5em;
+    font-size: 95%;
+    line-height: 110%;
+  }
+  h6.toc {
+    margin-left: 6em;
+    font-size: 90%;
+    line-height: 110%;
+  }
+  h7.toc {
+    margin-left: 7em;
+    font-size: 90%;
+    line-height: 105%;
+  }
+
+  .microtoc {
+    margin-top: 2px;
+    margin-bottom: 2px;
+  }
+
+  h1.microtoc {
+    margin-left: 0mm;
+    font-size: 115%;
+  }
+  h2.microtoc {
+    margin-left: 5mm;
+    font-size: 110%;
+  }
+  h3.microtoc {
+    margin-left: 10mm;
+    font-size: 105%;
+  }
+  h4.microtoc {
+    margin-left: 15mm;
+    font-weight: normal;
+    font-size: 100%;
+  }
+  h5.microtoc {
+    margin-left: 20mm;
+    font-weight: normal;
+    font-size: 95%;
+  }
+  h6.microtoc {
+    margin-left: 25mm;
+    font-weight: normal;
+    font-size: 90%;
+  }
+  h7.microtoc {
+    margin-left: 30mm;
+    font-weight: normal;
+    font-size: 85%;
+  }
+
+  .subtoc {
+    margin-right: 34%;
+    font-weight: normal;
+  }
+  h5.subtoc {
+    margin-left: 2em;
+    font-size: 80%;
+    margin-top: 2px;
+    margin-bottom: 2px;
+  }
+  h6.subtoc {
+    margin-left: 3em;
+    font-size: 75%;
+    margin-top: 0px;
+    margin-bottom: 0px;
+  }
+  h7.subtoc {
+    margin-left: 4em;
+    font-size: 70%;
+    margin-top: 0px;
+    margin-bottom: 0px;
+  }
+
+  div.substance {
+    width: 100%;
+    background-color: #ffffff;
+  }
+  div.ocn {
+    width: 5%;
+    float: right;
+    top: 0;
+    background-color: #ffffff;
+  }
+  div.endnote {
+    width: 100%;
+    background-color: #fffffff;
+  }
+  div.toc {
+    position: absolute;
+    float: left;
+    margin: 0;
+    padding: 0;
+    padding-top: 0.5em;
+    border: 0;
+    width: 5%;
+    background-color: #eeeeee;
+    margin-right:1em;
+  }
+  div.summary {
+    margin: 0;
+    padding: 0;
+    border-left: 2em solid #eeeeee;
+    padding-left: 0em;
+    background-color: #eeeeee;
+  }
+  div.content, div.main_column {
+    margin: 0;
+    padding: 0;
+    border-left: 0% solid #ffffff;
+    padding-left: 5%;
+  }
+  div.content:after {
+    content:' ';
+    clear:both;
+    display:block;
+    height:0;
+    overflow:hidden
+  }
+  div.footer {
+    clear:left;
+    padding: 0.5em;
+    font-size: 80%;
+    margin: 0;
+  }
+  div.toc ul {
+    list-style: none;
+    padding: 0;
+    margin: 0;
+  }
+  div.toc li ul a, li ul span.currentlink
+  {
+    font-weight: normal;
+    font-size: 90%;
+    padding-left: 2em;
+    background-color: #eeeeee;
+  }
+  div.toc a, span.currentlink{
+    display:block;
+    text-decoration: none;
+    padding-left: 0.5em;
+    color: #0000aa;
+  }
+  hr {
+    width: 90%;
+  }
+
+  span.currentlink {
+    text-decoration: none;
+    background-color: #aaaaf9;
+  }
+
+  div.toc a:visited {
+    color: #0000aa;
+  }
+  div.toc a:hover {
+    color: #000000;
+    background-color: #f9f9aa;
+  }
+
+  h1.c, h2.c, h3.c, h4.c, h5.c, h6.c, h7.c, p.c {
+    text-align: center
+  }
+  h1.red, h2.red, h3.red, h4.red, h5.red, h6.red, h7.red {
+    text-align: center;
+    color: #ff0000;
+    margin-left: 5mm;
+    text-indent: 5mm;
+    margin-top: 30px;
+    margin-bottom: 20px;
+    margin-right: 15mm;
+  }
+  h1.ruby, h2.ruby, h3.ruby, h4.ruby, h5.ruby, h6.ruby, h7.ruby {
+    text-align: center;
+    color: #990000;
+    margin-left: 5mm;
+    text-indent: 5mm;
+    margin-top: 30px;
+    margin-bottom: 20px;
+    margin-right: 15mm;
+  }
+      WOK
+    end
+  end
+  module SanitizeXML
+    require_relative 'xhtml_parts'                        # xhtml_parts.rb
+    def self.xml(x)
+      if x.is_a?(String)
+        x=x.gsub(/&nbsp;/,' ') if Ep[:alt]==:on
+        x.gsub(/&/,'&amp;').
+          gsub(/</,"&lt;").gsub(/>/,"&gt;").
+          gsub(/#{Dx[:url_o]}/,Dx[:url_o_xml]).gsub(/#{Dx[:url_c]}/,Dx[:url_c_xml]).
+          #gsub(/</,'&#60;').gsub(/>/,'&#62;').
+          gsub(/\\\\/,'<br />').
+          gsub(/&lt;br(?: \/)?&gt;/,'<br />')
+      else x
+      end
+    end
+  end
+  class HeadInformation
+    attr_reader :md,:rdf
+    def initialize(md)
+      @md=md
+      # DublinCore 1 - title
+      @css=SiSU_Env::CSS_Stylesheet.new(md)
+      @per=SiSU_XHTML_EPUB2_Persist::Persist.new
+      @per.seg_name_x=SiSU_XHTML_EPUB2::Seg.new.seg_name_x
+      @per.seg_name_x_tracker=SiSU_XHTML_EPUB2::Seg.new.seg_name_x_tracker
+      @tocband_scroll,@tocband_segtoc=nil,nil
+      @index,@metalink='index','#metadata'
+    end
+    def doc_type_xhtml
+      <<-WOK
+<?xml version='1.0' encoding='utf-8'?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+      WOK
+    end
+=begin
+~/epub
+  |-- META-INF
+  |   `-- container.xml                # simple, make sure full-path of rootfile points to metadata.opf
+  |-- content
+  |   |-- 1.xhtml
+  |   |-- 2.xhtml
+  |   |-- 3.xhtml
+  |   |-- ... .xhtml
+  |   |-- concordance.xhtml
+  |   |-- css
+  |   |   `-- xhtml.css
+  |   |-- endnotes.xhtml
+  |   |-- image
+  |   |   |-- arrow_next_red.png
+  |   |   |-- arrow_prev_red.png
+  |   |   |-- arrow_up_red.png
+  |   |   `-- bullet_09.png
+  |   |-- index.xhtml
+  |   |-- meta.xhtml
+  |   |-- metadata.xhtml
+  |   `-- toc.xhtml
+  |-- metadata.opf                     #(i) metadata dc; (ii) manifest (contents); (iii) spine (mimetypes)
+  |-- mimetype                         # application/epub+zip
+  `-- toc.ncx                          #(i) head (ii) doc title (iii) navmap, list of navigation points (like chapters)
+=end
+    def doc_type
+      doc_type_xhtml
+    end
+    def mimetype
+      <<-WOK
+application/epub+zip
+      WOK
+    end
+    def metainf_container #container.xml file in META-INF directory
+      #simple, make sure full-path of rootfile points to metadata.opf
+      #epub_metadata.opf content.opf
+      <<-WOK
+<?xml version='1.0' encoding='utf-8'?>
+<container version="1.0"
+  xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
+  <rootfiles>
+    <rootfile full-path="#{Ep[:d_oebps]}/#{Ep[:f_opf]}"
+      media-type="application/oebps-package+xml" />
+  </rootfiles>
+</container>
+      WOK
+    end
+    def sections(dob,fn_base)
+      name=fn_base + Sfx[:epub_xhtml]
+      dir_epub_cont=@md.env.processing_path.epub + '/' + Ep[:d_oebps]
+      segfilename=dir_epub_cont + '/' + name
+      output_epub_cont_seg=File.new(segfilename,'w')
+      txt=dob.obj.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'')
+      output_epub_cont_seg << %{#{doc_type}
+  <head>
+    <title>
+      #{dob.obj} -
+      #{@md.html_title}
+    </title>
+    <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
+    #{@css.xhtml_epub}
+  </head>
+    <body lang="#{@md.opt.lng}">
+    <div class="content">
+      <div class="substance">
+        <label class="ocn"><a href="#o#{dob.ocn}" class="lnkocn">#{dob.ocn}</a></label>
+        <h1 class="norm" id="o#{dob.ocn}">
+          #{txt}
+        </h1>
+      </div>
+    </div>
+    </body>
+  </html>}
+output_epub_cont_seg.close
+    end
+    def toc_ncx #list of navigation points (like chapters), table of contents, listing each navigation point (chapters and such) under the navigation map
+      def structure
+        open
+        head_open
+        head
+        head_close
+        doc_title
+        doc_author
+        navmap_open
+       #navmap ...
+        navmap_close
+        close
+      end
+      def open
+        <<-WOK
+<?xml version='1.0' encoding='utf-8'?>
+<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
+        WOK
+      end
+      def close
+        <<-WOK
+</ncx>
+        WOK
+      end
+      def head_open
+        <<-WOK
+  <head>
+        WOK
+      end
+      def head
+        depth=@md.lvs[1] + @md.lvs[2] + @md.lvs[3] + @md.lvs[4]
+        title=SanitizeXML.xml(@md.title.full)
+        author=SanitizeXML.xml(@md.author)
+        dgst=(@md.dgst.is_a?(Array) and @md.dgst.length > 1) ? @md.dgst[1] : 'na'
+        <<-WOK
+    <!-- four required metadata items (for all NCX documents,
+      (including the relaxed constraints of OPS 2.0) -->
+    <title>#{title} by #{author}</title>
+    <link href="css/xhtml.css" rel="stylesheet" type="text/css" id="main-css" />
+    <meta name="dtb:uid" content="urn:uuid:#{dgst}" />
+    <!-- <meta name="epub-creator" content="#{@md.publisher}" /> -->
+    <meta name="dtb:depth" content="#{depth}" />
+    <meta name="dtb:totalPageCount" content="0" />
+    <meta name="dtb:maxPageNumber" content="0" />
+        WOK
+      end
+      def head_close
+        <<-WOK
+  </head>
+        WOK
+      end
+      def doc_title
+        txt=SanitizeXML.xml(@md.title.full)
+        <<-WOK
+  <docTitle>
+    <text>#{txt}</text>
+  </docTitle>
+        WOK
+      end
+      def doc_author
+        txt=SanitizeXML.xml(@md.author)
+        <<-WOK
+  <docAuthor>
+    <text>#{txt}</text>
+  </docAuthor>
+        WOK
+      end
+      def navmap_open
+        <<-WOK
+  <navMap>
+        WOK
+      end
+      def navmap_sisu_toc(no)
+        id_u=DISABLE[:epub][:ncx_navpoint_unique_id] \
+        ? ''
+        : "-#{no}"
+        <<-WOK
+      <navPoint id="navpoint#{id_u}" playOrder="#{no}">
+        <navLabel>
+          <text>Table of Contents</text>
+        </navLabel>
+        <content src="index#{Sfx[:epub_xhtml]}" />
+      </navPoint>
+        WOK
+      end
+      def navpoint(dob,no,fn_base,hashtag=nil)
+        fn=fn_base + Sfx[:epub_xhtml]
+        name=hashtag ? fn + hashtag : fn
+        id_u=DISABLE[:epub][:ncx_navpoint_unique_id] \
+        ? ''
+        : "-#{no}"
+        txt=dob.obj.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'')
+        <<-WOK
+      <navPoint class="chapter" id="navpoint#{id_u}" playOrder="#{no}">
+        <navLabel>
+          <text>#{txt}</text>
+        </navLabel>
+        <content src="#{name}" />
+        WOK
+      end
+      def navpoint_close
+        <<-WOK
+      </navPoint>
+        WOK
+      end
+      def navmap_close
+        <<-WOK
+  </navMap>
+        WOK
+      end
+      self
+    end
+    def metadata_opf #(i) metadata dc; (ii) manifest (contents); (iii) spine (mimetypes)
+      def structure
+        package_open
+        metadata_open
+        metadata_close
+        manifest_open
+        manifest_close
+        spine_open
+        spine_close
+        guide_open
+        guide_close
+        package_close
+      end
+      def package_open
+        <<-WOK
+<?xml version='1.0' encoding='utf-8'?>
+<package xmlns="http://www.idpf.org/2007/opf" version="2.0" unique-identifier="EPB-UUID">
+        WOK
+      end
+      def package_close
+        <<-WOK
+</package>
+        WOK
+      end
+      def metadata #metadata dc
+        cover_image=if defined? @md.make.cover_image \
+        and @md.make.cover_image.is_a?(Hash) \
+        and @md.make.cover_image[:cover] =~/\S+/
+          %{\n    <#{$ep[:o]}meta name="cover" content="cover_image" />}
+        else ''
+        end
+        author=if defined? @md.creator.author \
+        and @md.creator.author =~/\S+/
+          m=''
+          @md.creator.author_detail.each do |i|
+            surname=i[:the] \
+            ? i[:the]
+            : ''
+            other_names=i[:others] \
+            ? ', ' + i[:others]
+            : ''
+            m=(m.empty?) \
+            ? (surname + other_names)
+            : (m + '; ' + surname + ', ' + other_names)
+            m=SanitizeXML.xml(m)
+          end
+          x=@md.creator.author.dup
+          x=SanitizeXML.xml(x)
+          %{\n    <dc:creator opf:file-as="#{m}" opf:role="aut">#{x}</dc:creator>}
+        else ''
+        end
+        editor=if defined? @md.creator.editor \
+        and @md.creator.editor =~/\S+/
+          m=''
+          @md.creator.editor_detail.each do |i|
+            surname=i[:the] \
+            ? i[:the]
+            : ''
+            other_names=i[:others] \
+            ? ', ' + i[:others]
+            : ''
+            m=(m.empty?) \
+            ? (surname + other_names)
+            : (m + '; ' + surname + ', ' + other_names)
+            m=SanitizeXML.xml(m)
+          end
+          x=@md.creator.editor.dup
+          x=SanitizeXML.xml(x)
+          %{\n    <dc:creator opf:file-as="#{m}" opf:role="edt">#{x}</dc:creator>}
+        else ''
+        end
+        translator=if defined? @md.creator.translator \
+        and @md.creator.translator =~/\S+/
+          m=''
+          @md.creator.translator_detail.each do |i|
+            surname=i[:the] \
+            ? i[:the]
+            : ''
+            other_names=i[:others] \
+            ? ', ' + i[:others]
+            : ''
+            m=(m.empty?) \
+            ? (surname + other_names)
+            : (m + '; ' + surname + ', ' + other_names)
+            m=SanitizeXML.xml(m)
+          end
+          x=@md.creator.translator.dup
+          x=SanitizeXML.xml(x)
+          %{\n    <dc:creator opf:file-as="#{m}" opf:role="trl">#{x}</dc:creator>}
+        else ''
+        end
+        illustrator=if defined? @md.creator.illustrator \
+        and @md.creator.illustrator =~/\S+/
+          m=''
+          @md.creator.illustrator_detail.each do |i|
+            surname=i[:the] \
+            ? i[:the]
+            : ''
+            other_names=i[:others] \
+            ? ', ' + i[:others]
+            : ''
+            m=(m.empty?) \
+            ? (surname + other_names)
+            : (m + '; ' + surname + ', ' + other_names)
+            m=SanitizeXML.xml(m)
+          end
+          x=@md.creator.illustrator.dup
+          x=SanitizeXML.xml(x)
+          %{\n    <dc:creator opf:file-as="#{m}" opf:role="ill">#{x}</dc:creator>}
+        else ''
+        end
+        date_published=if defined? @md.date.published \
+        and @md.date.published =~/\S+/
+          x=@md.date.published.dup
+          x=SanitizeXML.xml(x)
+          %{\n    <dc:date opf:event="published">#{x}</dc:date>}
+        else ''
+        end
+        subject=if defined? @md.classify.subject \
+        and @md.classify.subject =~/\S+/
+          x=@md.classify.subject.dup
+          x=SanitizeXML.xml(x)
+          %{\n    <dc:subject>#{x}</dc:subject>}
+        else ''
+        end
+        language=if defined? @md.opt.lng \
+        and @md.opt.lng =~/\S+/
+          language=@md.opt.lng.gsub(/<br>/,'<br />')
+          %{\n    <dc:language>#{language}</dc:language>}
+        else ''
+        end
+        rights=if defined? @md.rights.all \
+        and @md.rights.all =~/\S+/
+          rights=SanitizeXML.xml(@md.rights.all)
+          rights=rights.gsub(/<br\s*\/?>/,' ')
+          %{\n    <dc:rights>#{rights}</dc:rights>}
+        else ''
+        end
+        f=SiSU_Env::FileOp.new(@md)
+        dgst=(@md.dgst.is_a?(Array) and @md.dgst.length > 1) ? @md.dgst[1] : 'na'
+        <<-WOK
+  <#{$ep[:o]}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:#{dgst}" version="2.0">
+    <dc:title>#{@md.title.full}</dc:title>
+    #{cover_image}#{author}#{editor}#{translator}#{illustrator}#{language}#{date_published}#{subject}#{rights}
+    <dc:identifier opf:scheme="URI">#{f.output_path.epub.url.gsub(/http:\/\//,'')}/#{f.base_filename.epub}</dc:identifier>
+    <dc:identifier id="bookid">urn:uuid:#{dgst}</dc:identifier>
+    <!-- <dc:identifier id="EPB-UUID">urn:uuid:#{dgst}</dc:identifier> -->
+  </#{$ep[:o]}metadata>
+        WOK
+      end
+      def manifest_open
+        <<-WOK
+  <manifest>
+    <!-- NCX -->
+    <item id="ncx" href="#{Ep[:f_ncx]}" media-type="application/x-dtbncx+xml" />
+    <!-- CSS Style Sheets -->
+    <item id="main-css" href="css/xhtml.css" media-type="text/css" />
+    <!-- Content Documents -->
+        WOK
+      end
+      def manifest_content_sisu_toc
+        <<-WOK
+    <item id="index#{Sfx[:epub_xhtml]}" href="index#{Sfx[:epub_xhtml]}" media-type="application/xhtml+xml" />
+        WOK
+      end
+      def manifest_cover_image_information(md)
+        if defined? md.make.cover_image \
+        and @md.make.cover_image.is_a?(Hash) \
+        and md.make.cover_image[:cover] =~/\S+/
+          <<-WOK
+    <item id="cover_image#{Sfx[:epub_xhtml]}" href="cover_image#{Sfx[:epub_xhtml]}" media-type="application/xhtml+xml" />
+          WOK
+        else ''
+        end
+      end
+      def manifest_content(dob,fn_base,hashtag=nil)
+         fn=fn_base + Sfx[:epub_xhtml]
+         name=hashtag ? fn + hashtag : fn
+        <<-WOK
+    <item id="#{name}" href="#{name}" media-type="application/xhtml+xml" />
+        WOK
+      end
+      def manifest_images(imgs)
+        imgs=imgs + ['arrow_next_red.png','arrow_prev_red.png','arrow_up_red.png','bullet_09.png']
+        images=["    <!-- Images -->\n"]
+        imgs.each do |i|
+          image,type=/(\S+?)\.(png|jpg|gif)/.match(i)[1,2]
+          type=type.sub(/jpg/,'jpeg')
+          images<<<<-WOK
+    <item id="#{image}" href="image/#{image}.#{type}" media-type="image/#{type}" />
+          WOK
+        end
+        images=images.join('')
+        images
+      end
+      def manifest_close
+        <<-WOK
+  </manifest>
+        WOK
+      end
+      def spine_open
+        #spine: reading order of XHTML files from manifest, idref attribute refers back to id in manifest (exclude images, CSS etc.).
+        <<-WOK
+  <spine toc="ncx">
+        WOK
+      end
+      def spine_cover_image
+        <<-WOK
+    <itemref idref="cover_image#{Sfx[:epub_xhtml]}" />
+        WOK
+      end
+      def spine_sisu_toc
+        <<-WOK
+    <itemref idref="index#{Sfx[:epub_xhtml]}" linear="yes" />
+        WOK
+      end
+      def spine(dob,fn_base,hashtag=nil)
+         fn=fn_base + Sfx[:epub_xhtml]
+         name=hashtag ? fn + hashtag : fn
+        <<-WOK
+    <itemref idref="#{name}" linear="yes" />
+        WOK
+      end
+      def spine_close
+        <<-WOK
+  </spine>
+        WOK
+      end
+      def guide_open
+        #guide: presentation order of XHTML files by reader).
+        <<-WOK
+  <guide>
+        WOK
+      end
+      def guide_cover_image
+        <<-WOK
+    <reference type="cover" title="Cover of #{SanitizeXML.xml(@md.title.full)}" href="cover_image#{Sfx[:epub_xhtml]}" />
+        WOK
+      end
+      def guide_sisu_toc
+        <<-WOK
+    <reference type="index#{Sfx[:epub_xhtml]}" href="index#{Sfx[:epub_xhtml]}" />
+        WOK
+      end
+      def guide(dob,fn_base,hashtag=nil)
+         fn=fn_base + Sfx[:epub_xhtml]
+         name=hashtag ? fn + hashtag : fn
+        name=name ? name : dob.name
+        guide_name=(name =~/#{Sfx[:epub_xhtml]}/) ? name : (name + Sfx[:epub_xhtml])
+        <<-WOK
+    <reference type="text" href="#{guide_name}" />
+        WOK
+      end
+      def guide_close
+        <<-WOK
+  </guide>
+        WOK
+      end
+      self
+    end
+    def table_close
+      %{  </font>
+#{the_table_close}}
+    end
+    def xhtml_close
+    %{#{SiSU_Proj_XHTML::Bits.new.credits_sisu_epub}
+  </body>
+</html>}
+    end
+  end
+  class HeadToc < HeadInformation
+    include SiSU_Parts_XHTML
+    def initialize(md)
+      super(md)
+      @md=md
+      @tocband_segtoc=make_seg
+    end
+    def manifest_link(text)
+  %{ <a href="#{@md.file.output_path.manifest.url}/#{@md.file.base_filename.manifest}" target="_top">#{text}</a>}
+    end
+    def concordance_link(text)
+      if @md.concord_make
+  %{<a href="#{@md.file.base_filename.html_concordance}" target="_top">
+      #{text}
+    </a>}
+      else ''
+      end
+    end
+    def head
+      %{#{doc_type}
+  <head>
+    <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
+    #{@css.xhtml_epub}
+  </head>
+    <body lang="#{@md.opt.lng}">}
+    end
+    def concordance
+      if @md.concord_make
+      %{#{the_margin.css}
+      <h4 class="toc">
+        <a href="./#{@md.file.base_filename.html_concordance}">
+          <i>Concordance</i>
+        </a>
+      </h4>
+#{the_table_close}}
+      else
+      %{#{the_margin.css}
+#{the_table_close}}
+      end
+    end
+    def links_guide_open(type='horizontal')
+      (type=='vertical') \
+      ? links_guide_vertical_open
+      : links_guide_horizontal_open
+    end
+    def prefix_a
+    end
+    def rights
+      def all
+        rights=SanitizeXML.xml(@md.rights.all)
+        %{<p class="small_left">Rights: #{rights}</p>}
+      end
+      self
+    end
+    def prefix_b
+      %{<p class="small_left">Prefix: #{@md.prefix_b}}
+    end
+    def make_seg
+      concord=concordance_link(the_nav.txt_concordance)
+      %{<table summary="toc segment" border="0" cellpadding="3" cellspacing="0">
+<tr><td align="center" bgcolor="white">
+  #{the_nav.txt_toc_link}
+</td>
+<td align="center" bgcolor="white">
+  <font size=2>
+   #{concord}
+#{the_table_close}}
+    end
+    def manifest #check structure
+      manifest=manifest_link(the_nav.txt_manifest)
+      %{#{the_margin.txt_3}
+  #{the_font.paragraph_font_small}
+   #{manifest}
+    </font>
+#{the_table_close}}
+    end
+    def concordance #check structure
+      concord=concordance_link(the_nav.txt_concordance)
+      %{#{the_margin.txt_3}
+  #{the_font.paragraph_font_small}
+   #{concord}
+    </font>
+#{the_table_close}}
+    end
+    def metadata
+      %{#{the_margin.css}
+  <h4 class="toc">
+    <a href="#{@metalink}">
+      <i>MetaData</i>
+    </a>
+  </h4>
+#{the_table_close}}
+    end
+  end
+  class HeadSeg < HeadInformation
+    def initialize(md)
+      super(md)
+    end
+    def head
+      %{#{doc_type}
+  <head>
+    <title>
+      #{@per.seg_name_x[@per.seg_name_x_tracker]} -
+      #{@md.html_title}
+    </title>
+    <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
+    #{@css.xhtml_epub}
+  </head>
+    <body lang="#{@md.opt.lng}">}
+    end
+    def endnote_mark
+%{
+  <hr class="endnote" />
+}
+    end
+  end
+  class HeadScroll < HeadToc
+    def initialize(md)
+      super(md)
+    end
+    def toc_owner_details
+      %{#{the_margin.txt_3}
+#{the_font.paragraph_font_small}
+  <a href="#owner.details">
+    Owner Details
+    <font size="1" color="#777777">
+      #{$ep[:hsp]*3}
+    </font>
+  </a>
+  </font>
+#{the_table_close}}
+    end
+  end
+  class FormatTextObject
+    include SiSU_Parts_XHTML
+    attr_accessor :md,:t_o,:txt,:ocn,:format,:table,:link,:linkname,:paranum,:p_num,:headname,:banner,:url
+    def initialize(md,t_o)
+      @md,@t_o=md,t_o
+      if t_o.is_a?(Hash)
+        @txt            =t_o[:txt]            || nil
+        @ocn            =t_o[:ocn]            || nil
+        @ocn_display    =t_o[:ocn_display]    || nil
+        @headname       =t_o[:headname]       || nil
+        @trailer        =t_o[:trailer]        || nil
+        @endnote_part_a =t_o[:endnote_part_a] || nil
+        @endnote_part_b =t_o[:endnote_part_b] || nil
+        @lnk_url        =t_o[:lnk_url]        || nil
+        @lnk_txt        =t_o[:lnk_txt]        || nil
+        @format         =t_o[:format]         || nil
+        @target         =t_o[:target]         || nil #occasionally passed but not used
+        if @format and not @format.empty?
+          if @format=~/^\d:(\S+)/ #need more reliable marker #if @format =~ /#{Rx[:lv]}/
+            headname=$1 #format[/\d~(\S+)/m,1]
+            @headname=(headname =~/^[a-zA-Z]/) \
+            ? %{<id="#{headname}">}
+            : %{<id="h#{headname}"></a>}
+            @headname=(headname =~/^[a-zA-Z]/) \
+            ? %{<a name="#{headname}" id="#{headname}"></a>}
+            : %{<a name="h#{headname}" id="h#{headname}"></a>}
+          end
+        end
+      elsif t_o.class.inspect =~/Object/
+        @dob=t_o if defined? t_o.is
+        @named=nametags_seg(@dob)
+        @txt=((defined? t_o.obj) ? t_o.obj : nil)
+        @ocn=((defined? t_o.ocn) ? t_o.ocn.to_s : nil)
+        @headname=((t_o.is==:heading and defined? t_o.name) ? t_o.name : nil)
+      else
+        if @md.opt.act[:maintenance][:set]==:on
+          p __FILE__ << ':' << __LINE__.to_s
+          p t_o.class
+          p caller
+        end
+      end
+      if @txt and not @txt.empty?
+        @txt=@txt.gsub(/#{Mx[:mk_o]}[-~]##{Mx[:mk_c]}/,'')
+      end
+      @p_num=ParagraphNumber.new(@md,@ocn)
+    end
+    def nametags_seg(dob) #FIX
+      tags=''
+      if defined? dob.tags \
+      and dob.tags.length > 0 # insert tags "hypertargets"
+        dob.tags.each do |t|
+          tags=tags << %{<a name="#{t}" />}
+        end
+      end
+      tags
+    end
+    def endnote_body
+      %{
+<p class="endnote">
+  #{@txt}
+</p>
+}
+    end
+    def endnote_body_indent
+      %{
+  <p class="endnote_indent">
+    #{@txt}
+  </p>
+}
+    end
+    def no_paranum
+      %{
+<div class="substance">
+  <label class="ocn">#{$ep[:hsp]}</label>
+  <p class="norm">
+    #{@txt}
+  </p>
+</div>
+}
+    end
+    def para_form_css(tag,attrib,txt)                                                    # regular paragraphs shaped here
+      ul=ulc=''
+      ul,ulc="<ul>\n  ","\n  </ul>" if @tag =~/li/
+      %{
+<div class="substance">
+  #{@p_num.ocn_display}
+  #{ul}<#{tag} class="#{attrib}" #{@p_num.id}>
+    #{@named}#{txt}
+  </#{tag}>#{ulc}
+</div>
+}
+    end
+    def para
+      para_form_css('p','norm',@txt)
+    end
+    def group
+      para_form_css('p','group',@txt)
+    end
+    def block
+      para_form_css('p','block',@txt)
+    end
+    def alt
+      para_form_css('p','alt',@txt)
+    end
+    def verse
+      para_form_css('p','verse',@txt)
+    end
+    def code
+      para_form_css('p','code',@txt)
+    end
+    def center
+      para_form_css('p','center',@txt)
+    end
+    def bold
+      para_form_css('p','bold',@txt)
+    end
+    def bullet
+      para_form_css('li','bullet',@txt)
+    end
+    def table
+      @txt=if @t_o.obj !~/^<table\s/
+        table=SiSU_XHTML_Shared::TableXHTML.new(@t_o) #move, make happen earlier
+        table.table.obj
+      else @txt
+      end
+      para_form_css('p','norm',@txt)
+    end
+    def break
+      @txt=@txt.gsub(/#{Mx[:br_page_new]}|#{Mx[:br_page]}|#{Mx[:br_page_line]}/,'<hr /><br />').
+        gsub(/#{Mx[:br_obj]}/,'<hr style="width:30%" /><br />')
+      para_form_css('p','norm',@txt)
+    end
+    def format(tag,attrib)
+      para_form_css(tag,attrib,@txt)
+    end
+    def title_heading(tag,attrib)
+      %{
+<div class="content">
+<#{tag} class="#{attrib}">
+    #{@named}#{@txt}
+  </#{tag}>
+</div>
+}
+    end
+    def title_heading0
+      DISABLE[:epub][:per_section_title] \
+      ? ''
+      : title_heading('h1','tiny')
+    end
+    def title_heading1
+      DISABLE[:epub][:per_section_title] \
+      ? ''
+      : title_heading('h1','tiny')
+    end
+    def title_heading2
+      DISABLE[:epub][:per_section_title] \
+      ? ''
+      : title_heading('h2','tiny')
+    end
+    def title_heading3
+      DISABLE[:epub][:per_section_title] \
+      ? ''
+      : title_heading('h3','tiny')
+    end
+    def title_heading4
+      ''
+    end
+    def seg_heading_sub(tag,attrib,txt)
+      txt=txt.gsub(/(?:#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})\s*/m,' ')
+      %{
+<div class="substance">
+  #{@p_num.ocn_display}
+  <#{tag} class="#{attrib}" #{@p_num.id}>#{@p_num.name}
+    #{@named}#{@txt}
+  </#{tag}>
+</div>
+}
+    end
+    def seg_heading4
+      %{
+<div class="substance">
+  #{@p_num.ocn_display}
+  <h1 class="norm" #{@p_num.id}>
+    #{@txt}
+  </h1>
+</div>
+}
+    end
+    def seg_heading5
+      seg_heading_sub('p','bold',@txt)
+    end
+    def seg_heading6
+      seg_heading_sub('p','bold',@txt)
+    end
+    def seg_heading7
+      seg_heading_sub('p','bold',@txt)
+    end
+    def dl #check :trailer
+      "<dl><b>#{@txt}</b> #{@trailer}</dl>"
+    end
+    def table_css_end
+      '</table>
+    </p>
+  </div>'
+    end
+    def gsub_body #unused
+      @txt=case @txt
+      when /^(?:#{Mx[:pa_o]}i[1-9]#{Mx[:pa_c]}\s*)?\((i+|iv|v|vi+|ix|x|xi+)\)/
+        @txt.gsub(/^\((i+|iv|v|vi+|ix|x|xi+)\)/,'<b>(\1)</b>').
+          gsub(/^(#{Mx[:pa_o]}i[1-9]#{Mx[:pa_c]})\s*\((i+|iv|v|vi+|ix|x|xi+)\)/,'\1<b>(\2)</b>')
+      when /^(?:#{Mx[:pa_o]}i[1-9]#{Mx[:pa_c]}\s*)?\(?(\d|[a-z])+\)/
+        @txt.gsub(/^\((\d+|[a-z])+\)/,'<b>(\1)</b>').
+          gsub(/^(#{Mx[:pa_o]}i[1-9]#{Mx[:pa_c]})\s*\((\d+|[a-z])+\)/,'\1<b>(\2)</b>')
+      when /^\s*\d{1,3}\.\s/
+        @txt.gsub(/^\s*(\d+\.)/,'<b>\1</b>')
+      when /^\s*[A-Z]\.\s/
+        @txt.gsub(/^\s*([A-Z]\.)/,'<b>\1</b>')
+      else @txt
+      end
+    end
+    def bold_para
+      %{#{the_margin.txt_0}
+  <p class="bold">
+    #{@txt}
+  </p>
+#{the_margin.num_css}
+  #{$ep[:hsp]*3}
+#{the_table_close}}
+    end
+    def bold_heading #unused
+      @txt=@txt.gsub(/[1-9]~\S+/,'').
+        gsub(/[1-9]~/,'')
+      %{<p class="bold">
+    #{@txt}
+  </p>
+#{the_margin.num_css}
+  #{$ep[:hsp]*3}
+#{the_table_close}}
+    end
+    def toc_head_copy_at
+      @txt=SanitizeXML.xml(@txt)
+      %{<p class="center">#{@txt}</p>\n}
+    end
+    def center
+      @txt=SanitizeXML.xml(@txt)
+      %{<p class="center">#{@txt}</p>\n}
+    end
+    def bold
+      @txt=SanitizeXML.xml(@txt)
+      %{<p class="bold">#{@txt}</p>\n}
+    end
+    def center_bold
+      @txt=SanitizeXML.xml(@txt)
+      %{<p class="centerbold">#{@txt}</p>\n}
+    end
+  end
+  class FormatScroll < FormatTextObject
+    def initialize(md,txt)
+      super(md,txt)
+    end
+  end
+  class FormatSeg < FormatTextObject
+    def initialize(md,txt)
+      super(md,txt)
+    end
+    def endnote_seg_body(fn='')  #FIX                                                #url construction keep within single line... BUG WATCH 200408
+      fn='doc' if fn.to_s.empty? #you may wish to reconsider, sends to 'doc' where no segment info
+      %{
+  <p class="endnote">
+    #{@endnote_part_a}#{fn}#{Sfx[:epub_xhtml]}#{@endnote_part_b}
+  </p>
+}
+    end
+    def clean(txt)
+      txt=txt.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}/,'').
+        gsub(/#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'')
+    end
+    def subtoc_lev(tag,attrib)
+      @txt=clean(@txt)
+      txt=if @txt \
+      and @txt =~/<\/?i>|<a\s+name="\S+?">/mi
+        @txt.gsub(/<\/?i>|<a\s+name="\S+?">/mi,'') #removes name markers from subtoc, go directly to substantive text
+      else @txt
+      end
+      note=''
+      if txt =~/(#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})/m # had \s* at end
+        note=$1
+        note=note.gsub(/[\s]+/m,' ')
+        txt=txt.gsub(/(?:#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})\s*/m,' ').
+          gsub(/<a[\n\s]+"[\n\s]+href="##{Mx[:note_ref]}\d+">#{$ep[:hsp]}<sup id="#{Mx[:note]}\d+">\d+<\/sup>#{$ep[:hsp]}/m,'').
+          gsub(/<a[\n\s]+"[\n\s]+href="##{Mx[:note_ref]}\d+">#{$ep[:hsp]}<sup id="#{Mx[:note]}\d+">\d+<\/sup>#{$ep[:hsp]}/m,'') #remove
+      end
+      %{<#{tag} class="#{attrib}">
+    <a href="#o#{@ocn}"><i>#{txt}</i></a> #{note}
+  </#{tag}>}
+    end
+    def subtoc_lev5
+      subtoc_lev('h5','subtoc') if @txt
+    end
+    def subtoc_lev6
+      subtoc_lev('h6','subtoc') if @txt
+    end
+    def subtoc_lev7
+      subtoc_lev('h7','subtoc') if @txt
+    end
+    def heading_sub(tag,attrib,txt)
+      txt=txt.gsub(/(?:#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})\s*/m,' ')
+      %{
+<div class="substance">
+  #{@p_num.ocn_display}
+  <#{tag} class="#{attrib}" #{@p_num.id}> #{@headname}
+    #{@txt}
+  </#{tag}>
+</div>
+}
+    end
+    def heading4
+      %{
+<div class="substance">
+  #{@p_num.ocn_display}
+  <h1 class="norm" #{@p_num.id}>
+    #{@t_o[:format]}
+    #{@txt}
+  </h1>
+</div>
+}
+    end
+    def heading5
+      heading_sub('p','bold',@txt)
+    end
+    def heading6
+      heading_sub('p','bold',@txt)
+    end
+    def heading7
+      heading_sub('h7','bold',@txt)
+    end
+    def navigation_heading4
+      %{<table summary="navigation segment heading 4" width=100% bgcolor="#08163f" border="0">
+<tr><td align="center">
+<p class="bold">
+  #{@txt}
+</p>
+#{the_table_close}}
+    end
+    def navigation_heading5
+      %{<p class="bold">
+  #{@txt}
+</p>}
+    end
+    def navigation_heading6
+      %{<p class="bold">
+  #{@txt}
+</p>}
+    end
+    def navigation_heading7
+      %{<p class="bold">
+  #{@txt}
+</p>}
+    end
+    def navigation_center
+      %{<p class="centerbold">#{@txt}</p>}
+    end
+  end
+  class FormatToc < FormatTextObject
+    def initialize(md,txt)
+      super(md,txt)
+    end
+    def links_guide
+      %{  <li class="doc">
+    <a href="#{@lnk_url}" target="_top">
+      #{@lnk_txt}
+    </a>
+  </li>
+}
+    end
+    def lev(tag,attrib)
+      if @txt
+        %{<#{tag} class="#{attrib}">
+    #{@txt}
+  </#{tag}>
+}
+      else ''
+      end
+    end
+    def lev1
+      lev('h1','toc')
+    end
+    def lev2
+      lev('h2','toc')
+    end
+    def lev3
+      lev('h3','toc')
+    end
+    def lev4
+      lev('h4','toc')
+    end
+    def lev5
+      lev('h5','toc')
+    end
+    def lev6
+      lev('h6','toc')
+    end
+    def lev7
+      lev('h7','toc')
+    end
+    def lev0 #docinfo
+      lev('h0','toc')
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** xhtml_epub2_persist.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xhtml_epub2_persist.rb"
+# <<sisu_document_header>>
+module SiSU_XHTML_EPUB2_Persist
+  class Persist
+    @@persist=nil
+    attr_accessor :is0,:is1,:is2,:is3,:is4,:heading0,:heading1,:heading2,:heading3,:heading4, :title, :nav, :tocband_banner, :tocband_bannerless, :headings, :heading_endnotes, :main, :endnote_all, :tail, :credits, :heading_idx, :idx, :seg_endnotes, :seg_endnotes_array, :closed, :get_hash_fn, :get_hash_to, :seg_subtoc, :seg_subtoc_array, :fn, :seg_name ,:seg_name_x,:seg_name_x_tracker
+    def initialize(args=nil)
+      @@persist=args=(args ? args : (@@persist || persist_init_hash_values))
+      @is0=args[:is0]
+      @is1=args[:is1]
+      @is2=args[:is2]
+      @is3=args[:is3]
+      @is4=args[:is4]
+      @heading0=args[:heading0]
+      @heading1=args[:heading1]
+      @heading2=args[:heading2]
+      @heading3=args[:heading3]
+      @heading4=args[:heading4]
+      @title=args[:title]
+      @nav=args[:nav]
+      @tocband_banner=args[:tocband_banner]
+      @tocband_bannerless=args[:tocband_bannerless]
+      @headings=args[:headings]
+      @heading_endnotes=args[:heading_endnotes]
+      @main=args[:main]
+      @endnote_all=args[:endnote_all]
+      @tail=args[:tail]
+      @credits=args[:credits]
+      #@heading_idx=args[:heading_idx]
+      @idx=args[:idx]
+      @seg_endnotes=args[:seg_endnotes]
+      @seg_endnotes_array=args[:seg_endnotes_array]
+      @closed=args[:closed]
+      @get_hash_to=args[:get_hash_to]
+      @get_hash_fn=args[:get_hash_fn]
+      @seg_subtoc=args[:seg_subtoc]
+      @seg_subtoc_array=args[:seg_subtoc_array]
+      @fn=args[:fn]
+      @seg_name=args[:seg_name]
+      @seg_name_x=args[:seg_name_x]
+      @seg_name_x_tracker=args[:seg_name_x_tracker]
+    end
+    def is0
+      @is0
+    end
+    def is1
+      @is1
+    end
+    def is2
+      @is2
+    end
+    def is3
+      @is3
+    end
+    def is4
+      @is4
+    end
+    def heading0
+      @heading0
+    end
+    def heading1
+      @heading1
+    end
+    def heading2
+      @heading2
+    end
+    def heading3
+      @heading3
+    end
+    def heading4
+      @heading4
+    end
+    def title
+      @title
+    end
+    def nav
+      @nav
+    end
+    def tocband_banner
+      @tocband_banner
+    end
+    def tocband_bannerless
+      @tocband_bannerless
+    end
+    def headings
+      @headings
+    end
+    def heading_endnotes
+      @heading_endnotes
+    end
+    def main
+      @main
+    end
+    def endnote_all
+      @endnote_all
+    end
+    def tail
+      @tail
+    end
+    def credits
+      @credits
+    end
+    def heading_idx
+      @heading_idx
+    end
+    def idx
+      @idx
+    end
+    def seg_endnotes
+      @seg_endnotes
+    end
+    def seg_endnotes_array
+      @seg_endnotes_array
+    end
+    def closed
+      @closed
+    end
+    def get_hash_to
+      @get_hash_to
+    end
+    def get_hash_fn
+      @get_hash_fn
+    end
+    def seg_subtoc
+      @seg_subtoc
+    end
+    def seg_subtoc_array
+      @seg_subtoc_array
+    end
+    def fn
+      @fn
+    end
+    def seg_name
+      @seg_name
+    end
+    def seg_name_x
+      @seg_name_x
+    end
+    def seg_name_x_tracker
+      @seg_name_x_tracker
+    end
+    def persist_init_hash_values
+      {
+        is0: 0,
+        is1: 0,
+        is2: 0,
+        is3: 0,
+        is4: 0,
+        heading0: '',
+        heading1: '',
+        heading2: '',
+        heading3: '',
+        heading4: '',
+        tocband_banner: [],
+        tocband_bannerless: [],
+        title: [],
+        nav: [],
+        headings: [],
+        main: [],
+        idx: [],
+        tail: [],
+        credits: [],
+        endnote_all: [],
+        heading_endnotes: '',
+        seg_endnotes: {},
+        seg_endnotes_array: [],
+        closed: [],
+        get_hash_fn: '',
+        get_hash_to: '',
+        seg_subtoc: {},
+        seg_subtoc_array: [],
+        fn: '',
+        seg_name: [],
+        seg_name_x: [],
+        seg_name_x_tracker: 0,
+      }
+    end
+    def persist_init
+      @@persist=nil
+      Persist.new(persist_init_hash_values)
+    end
+  end
+  class PersistTOC
+    @@persist=nil
+    attr_accessor :seg,:seg_mini,:scr,:ncx,:opf
+    def initialize(args=nil)
+      @@persist=args=(args ? args : (@@persist || persist_init_hash_values))
+      @seg=args[:seg]
+      @seg_mini=args[:seg_mini]
+      @scr=args[:scr]
+      @ncx=args[:ncx]
+      @opf=args[:opf]
+    end
+    def seg
+      @seg
+    end
+    def seg_mini
+      @seg_mini
+    end
+    def scr
+      @scr
+    end
+    def ncx
+      @ncx
+    end
+    def opf
+      @opf
+    end
+    def persist_init_hash_values
+      {
+        seg: [],
+        seg_mini: [],
+        scr: [],
+        ncx: [],
+        opf: [],
+      }
+    end
+    def persist_init
+      @@persist=nil
+      PersistTOC.new(persist_init_hash_values)
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** xhtml_epub2_segments.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xhtml_epub2_segments.rb"
+# <<sisu_document_header>>
+module SiSU_XHTML_EPUB2_Seg
+  require_relative 'xhtml_shared'                       # xhtml_shared.rb
+  require_relative 'xhtml_epub2'                        # xhtml_epub2.rb
+  require_relative 'xhtml_epub2_persist'                # xhtml_epub2_persist.rb
+  require_relative 'shared_metadata'                    # shared_metadata.rb
+  class Output
+    def initialize(md,outputfile,per,type='')
+      @md, @output_epub_cont_seg,@per,@type=
+        md,outputfile,           per, type
+    end
+    def output
+      if @per.title =~/\S/
+        filename_seg=[]
+        filename_seg \
+        << @per.title \
+        << @per.nav
+        if @type=='endnotes'
+          @per.headings=[] #watch
+          txt_obj={ txt: 'Endnotes', ocn_display: ''}
+          format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
+          @per.headings \
+          << format_seg.title_heading1
+          filename_seg \
+          << @per.heading_endnotes \
+          << @per.headings \
+          << %{\n<div class="content">\n} \
+          << @per.endnote_all \
+          << '</div>'
+        elsif @type=='idx'
+          @per.headings=[]
+          txt_obj={ txt: 'Index', ocn_display: ''}
+          format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
+          @per.headings << format_seg.title_heading1
+          filename_seg \
+          << @per.heading_idx \
+          << @per.headings \
+          << %{\n<div class="content">\n} \
+          << @per.idx \
+          << '</div>'
+        elsif @type=='metadata'
+          metadata=SiSU_Metadata::Summary.new(@md).xhtml_display.metadata
+          @per.headings=[]
+          txt_obj={ txt: 'Metadata', ocn_display: ''}
+          format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
+          @per.headings \
+          << format_seg.title_heading1
+          filename_seg \
+          << @per.heading_idx \
+          << @per.headings \
+          << %{\n<div class="content">\n} \
+          << metadata \
+          << '</div>'
+        elsif @type=='sisu_manifest'
+          env=SiSU_Env::InfoEnv.new(@md.fns)
+          path_and_name,url_and_name= \
+            "#{env.path.output}/#{@md.fnb}/sisu_manifest.html",
+            "#{env.url.root}/#{@md.fnb}/sisu_manifest.html"
+          manifest=if FileTest.file?("#{path_and_name}")==true
+            <<WOK
+<p>A list of available output types may be available at the following url:</p>
+<p><a href="#{url_and_name}">#{url_and_name}</a></p>
+WOK
+          else ''
+          end
+          @per.headings=[]
+          txt_obj={ txt: 'Manifest', ocn_display: ''}
+          format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
+          @per.headings \
+          << format_seg.title_heading1
+          filename_seg \
+          << @per.heading_idx \
+          << @per.headings \
+          << %{\n<div class="content">\n} \
+          << manifest \
+          << '</div>'
+        else
+          filename_seg \
+          << @per.headings \
+          << @per.main \
+          << "\n</div>\n"
+        end
+        filename_seg \
+        << @per.tail \
+        << @per.nav \
+        << @per.closed
+        filename_seg=filename_seg.flatten.compact #watch
+        filename_seg.each do |str|
+          unless str =~/\A\s*\Z/
+            @output_epub_cont_seg \
+            << str.strip
+          end
+        end
+        @output_epub_cont_seg.close
+      end
+    end
+  end
+  class Seg
+    @@seg_name=[]
+    @@seg_url=''
+    @@tracker=0
+    attr_reader :seg_name_x,:seg_name_x_tracker
+    def initialize(md='',data='')
+      @md,@data=md,data
+      @per=SiSU_XHTML_EPUB2_Persist::Persist.new
+      @seg_name_x=@per.seg_name_x=(@@seg_name || [])
+      @seg_name_x_tracker=@per.seg_name_x_tracker=(@@tracker || 0)
+      @make=SiSU_Env::ProcessingSettings.new(@md) if @md
+    end
+    def songsheet
+      begin
+        data=get_subtoc_endnotes(@data,@per)
+        data=articles(data,@per)
+        SiSU_XHTML_EPUB2_Seg::Seg.new.cleanup(@md,@per) # (((( added ))))
+        #### (((( END )))) ####
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        SiSU_XHTML_EPUB2_Persist::Persist.new.persist_init
+        @@seg_name=@per.seg_name=[]
+      end
+    end
+  protected
+    def articles(data,per)
+      @per=per
+      tracking,newfile=0,0
+      printed_endnote_seg='n'
+      idx_xhtml=nil
+      if @md.book_idx
+        idx_xhtml=SiSU_Particulars::CombinedSingleton.
+          instance.get_idx_xhtml(@md).xhtml_idx
+        idx_xhtml.each do |x|
+          @per.idx << x
+        end
+        @per.heading_idx=''
+      end
+      data.each do |dob|
+        if (dob.is == :heading \
+        || dob.is == :heading_insert) \
+        && dob.ln == 4
+          @@seg_name << dob.name
+          @per.seg_name = @@seg_name
+          dob.name
+        end
+      end
+      @per.seg_name_x=@per.seg_name
+      @per.seg_name.length
+      testforartnum=@per.seg_name_x
+      if (@md.opt.act[:verbose][:set]==:on \
+      || @md.opt.act[:verbose_plus][:set]==:on \
+      || @md.opt.act[:maintenance][:set]==:on)
+        SiSU_Screen::Ansi.new(
+          @md.opt.act[:color_state][:set],
+          @per.seg_name.length
+        )
+      end
+      SiSU_Particulars::CombinedSingleton.
+        instance.get_map_nametags(@md).nametags_map #p map_nametags
+      data.each do |dob|
+        #if defined? dob.obj \
+        #and dob.obj =~/href="#{Xx[:segment]}#+\S+?"/
+        #  ##Consider: remove, reinstate earlier?
+        #  #while dob.obj =~/href="#{Xx[:segment]}#+(\S+?)"/
+        #  #  m=$1
+        #  #  if map_nametags[m][:segname]
+        #  #    dob.obj=dob.obj.sub(/href="#{Xx[:segment]}#+(\S+?)"/,%{href="#{map_nametags[m][:segname]}#{Sfx[:html]}#\\1"})
+        #  #  else
+        #  #    p "NOT FOUND name_tags: #{m}"
+        #  #    dob.obj=dob.obj.sub(/href="#{Xx[:segment]}#+(\S+?)"/,%{href="#\\1"}) # not satisfactory
+        #  #  end
+        #  #end
+        #end
+        if (dob.is==:heading \
+        || dob.is==:heading_insert) \
+        && dob.ln==4
+          @per.heading4=dob.obj
+          @per.is4=newfile=1
+        end
+        if (dob.is==:heading \
+        || dob.is==:heading_insert) \
+        && dob.ln==3
+          @per.heading3=dob.obj
+          @per.is4,@per.is3=0,1
+        end
+        if (dob.is==:heading \
+        || dob.is==:heading_insert) \
+        && dob.ln==2
+          @per.heading2=dob.obj
+          @per.is4,@per.is3,@per.is2=0,0,1
+        end
+        if (dob.is==:heading \
+        || dob.is==:heading_insert) \
+        && dob.ln==1
+          @per.heading1=dob.obj
+          @per.is4,@per.is3,@per.is2,@per.is1=0,0,0,1
+        end
+        if (dob.is==:heading \
+        || dob.is==:heading_insert) \
+        && dob.ln==0
+          @per.heading0=dob.obj
+          @per.is4,@per.is3,@per.is2,@per.is1,@per.is0=0,0,0,0,1
+        end
+        if (@per.is0 && !@per.is1 && !@per.is2 && !@per.is3 && !@per.is4)
+          if not (dob.is==:heading \
+          || dob.is==:heading_insert) \
+          && dob.ln==0
+            $_ #; check
+          end
+        end
+        if @per.is4==1
+          dir_epub_cont="#{@md.env.processing_path.epub}/#{Ep[:d_oebps]}"
+          if newfile==1 \
+          or dob.obj =~/^#{Mx[:br_endnotes]}|^#{Mx[:br_eof]}/
+            newfile=0
+            if (dob.is==:heading \
+            || dob.is==:heading_insert) \
+            && dob.ln==4
+              if tracking != 0
+                tail(@md,@per)
+                #SiSU_XHTML_EPUB2_Seg::Seg.new(@md,@per).tail
+                segfilename="#{dir_epub_cont}/#{@per.seg_name_x[tracking-1]}#{Sfx[:epub_xhtml]}"
+                output_epub_cont_seg=File.new(segfilename,'w') if @per.seg_name_x[tracking-1]
+                if dob.is==:heading \
+                or @per.seg_name_x[tracking-1] !~/endnotes|book_index|metadata/
+                  SiSU_XHTML_EPUB2_Seg::Output.new(@md,output_epub_cont_seg,@per).output
+                elsif dob.is==:heading_insert
+                  if @per.seg_name_x[tracking-1]=='endnotes'
+                    SiSU_XHTML_EPUB2_Seg::Output.new(@md,output_epub_cont_seg,@per,'endnotes').output
+                  elsif @per.seg_name_x[tracking-1]=='book_index'
+                    SiSU_XHTML_EPUB2_Seg::Output.new(@md,output_epub_cont_seg,@per,'idx').output
+                    @per.idx=[]
+                  elsif @per.seg_name_x[tracking-1]=='metadata' # navigation bug FIX
+                    SiSU_XHTML_EPUB2_Seg::Output.new(@md,output_epub_cont_seg,@per,'metadata').output
+                  else puts "#{__FILE__}::#{__LINE__}"
+                  end
+                else puts "#{__FILE__}::#{__LINE__}"
+                end
+                SiSU_XHTML_EPUB2_Seg::Seg.new.reinitialise(per)
+                heading_art(dob)
+                head(dob)
+                if @per.seg_name_x[tracking] =='metadata'
+                  segfilename="#{dir_epub_cont}/#{@per.seg_name_x[tracking]}#{Sfx[:epub_xhtml]}"
+                  output_epub_cont_seg=File.new(segfilename,'w')
+                  SiSU_XHTML_EPUB2_Seg::Output.new(@md,output_epub_cont_seg,@per,'metadata').output
+                  SiSU_XHTML_EPUB2_Seg::Seg.new.reinitialise(per)
+                  #BUG navigation bug with items following metadata, and occurring before manifest, this becomes a bug ... work area for book index, FIX
+                end
+               #@output_epub_cont_seg.closed                                         #%(((( EOF )))) -->
+              end
+              if tracking==0
+                heading_art(dob)
+                head(dob)
+              end
+            end
+            tracking=tracking+1
+          end
+          if (dob.is==:heading \
+          || dob.is==:heading_insert) \
+          && dob.ln==4 \
+          && dob.name
+            @per.get_hash_to=dob.name
+            @per.get_hash_fn=dob.name
+          end
+          if dob.obj.is_a?(String)
+            markup(dob)
+          elsif dob.obj.is_a?(Array)
+            dob.obj.each do |pg|
+              markup(pg)
+            end
+          end
+          if testforartnum[tracking-1] =~/endnote/
+            if printed_endnote_seg=='n'
+              printed_endnote_seg='y'
+            end
+          end
+        end
+      end
+      data
+    end
+    def heading_art(dob)
+      @per.title=SiSU_XHTML_EPUB2_Format::HeadSeg.new(@md).head
+    end
+    def head(dob)
+      clean=/<!.*?!>|<:.*?>$/
+      @p_num ||= ''
+      if @per.is0==1
+        if defined? @md.creator.author \
+        and @md.creator.author
+          @author=%{<b>#{@md.creator.author}</b>\n}
+        end
+        @p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,dob.ocn)
+        txt_obj={ txt: @per.heading0, ocn_display: @p_num.ocn_display }
+        format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
+        @per.headings << format_seg.title_heading0.gsub(clean,'')
+        @per.heading0=@per.heading0.
+          gsub(/#{$ep[:hsp]}<a name="-[\d*+]+" href="#_[\d*+]+">#{$ep[:hsp]}<sup>[\d*+]+<\/sup>#{$ep[:hsp]}<\/a>/,'')
+      end
+      if @per.is1==1
+        @p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,dob.ocn)
+        txt_obj={ txt: @per.heading1, ocn_display: @p_num.ocn_display }
+        format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
+        @per.headings << format_seg.title_heading1.gsub(clean,'')
+        @per.heading1=@per.heading1.
+          gsub(/#{$ep[:hsp]}<a name="-[\d*+]+" href="#_[\d*+]+">#{$ep[:hsp]}<sup>[\d*+]+<\/sup>#{$ep[:hsp]}<\/a>/,'')
+      end
+      if @per.is2==1
+        heading2=@per.heading2
+        @p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,dob.ocn)
+        txt_obj={ txt: heading2, ocn_display: @p_num.ocn_display }
+        format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
+        @per.headings << format_seg.title_heading2.gsub(clean,'')
+        @per.heading2=@per.heading2.
+          gsub(/#{$ep[:hsp]}<a name="-[\d*+]+" href="#_[\d*+]+">#{$ep[:hsp]}<sup>[\d*+]+<\/sup>#{$ep[:hsp]}<\/a>/,'')
+      end
+      if @per.is3==1
+        heading3=@per.heading3
+        @p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,dob.ocn)
+        txt_obj={ txt: heading3, ocn_display: @p_num.ocn_display }
+        format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
+        @per.headings << format_seg.title_heading3.gsub(clean,'')
+        @per.heading3=@per.heading3.
+          gsub(/#{$ep[:hsp]}<a name="-[\d*+]+" href="#_[\d*+]+">#{$ep[:hsp]}<sup>[\d*+]+<\/sup>#{$ep[:hsp]}<\/a>/,'')
+      end
+      if @per.is4==1
+        heading4=@per.heading4
+        @p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,dob.ocn)
+        txt_obj={ txt: heading4, ocn_display: @p_num.ocn_display }
+        format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
+        @per.headings \
+        << format_seg.title_heading4.gsub(clean,'')
+      end
+      @@tracker=@@tracker+1
+    end
+    def markup(dob)
+      @debug=[]
+      if dob.is ==:heading \
+      || dob.is ==:heading_insert \
+      || dob.is ==:para
+        #extend as necessary FIX
+        @p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,dob.ocn)
+      end
+      sto=SiSU_XHTML_EPUB2_Format::FormatTextObject.new(@md,dob)
+      dob_xhtml=if dob.is==:heading \
+      || dob.is==:heading_insert \
+      || dob.is==:para
+        dob_xhtml=if dob.is==:heading \
+        or dob.is==:heading_insert
+          if dob.ln==4
+            sto.seg_heading4 # work on see SplitTextObject
+          elsif dob.ln==5
+            sto.seg_heading5
+          elsif dob.ln==6
+            sto.seg_heading6
+          elsif dob.ln==7
+            sto.seg_heading7
+          end
+        elsif dob.is==:para
+          if dob.indent \
+          and dob.hang \
+          and dob.indent =~/[0-9]/ \
+          and dob.hang =~/[0-9]/
+            if dob.bullet_
+              (dob.indent =~/[1-9]/) \
+              ? sto.format('li',"i#{dob.indent}")
+              : sto.format('li','bullet')
+            elsif dob.indent == dob.hang
+              sto.format('p',"i#{dob.indent}")
+            elsif dob.indent != dob.hang
+              sto.format('p',"h#{dob.hang}i#{dob.indent}")
+            else sto.para
+            end
+          else sto.para
+          end
+        end
+      elsif dob.is ==:block \
+      || dob.is ==:group \
+      || dob.is ==:alt
+        sto.para #fix this should be block type specific #FIX
+      elsif dob.is==:verse
+        sto.verse
+      elsif dob.is==:code
+        sto.code
+      elsif dob.is==:table
+        sto.table
+      elsif dob.is==:break
+        sto.break
+      end
+      if @md.flag_separate_endnotes # may need to revisit, check
+        dob.obj=dob.obj.gsub(/"\s+href="##{Mx[:note_ref]}(\d+)">/,
+          %{" href=\"endnotes#{Sfx[:epub_xhtml]}##{Mx[:note_ref]}\\1">})
+          #endnote- twice #removed file type
+      end
+      if (dob.is ==:heading \
+      || dob.is==:heading_insert \
+      || dob.is==:para) \
+      && (not dob.ocn or dob.ocn.to_s.empty?)
+        format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,dob)
+      end
+      if (dob.is==:heading \
+      || dob.is==:heading_insert \
+      || dob.is==:para) \
+      and dob.note_
+        #dob.obj =~/<a href="#note_ref\d+">&nbsp;<sup id=/       #endnote- note-
+        format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,dob)
+        dob.obj=format_seg.no_paranum
+      end
+      if (dob.is==:heading \
+      || dob.is==:heading_insert) \
+      and dob.ln==4
+        @per.main <<  %{\n<div class="content">\n}
+        @per.main << dob_xhtml
+        if @make.build.segsubtoc?
+          @per.main << @per.seg_subtoc[@per.get_hash_fn]
+          #% insertion of sub-toc
+        end
+      else
+        @per.main << dob_xhtml
+      end
+    end
+    def tail(md,per)
+      @md,@per=md,per
+      format_head_seg=SiSU_XHTML_EPUB2_Format::HeadSeg.new(@md)
+      if @md.flag_auto_endnotes \
+      and @per.seg_endnotes[@per.get_hash_fn]
+        @per.tail <<  %{\n<div class="content">\n<div class="endnote">\n}
+        if @per.seg_endnotes[@per.get_hash_fn].flatten.length > 0
+          @per.tail << format_head_seg.endnote_mark
+          @per.tail << @per.seg_endnotes[@per.get_hash_fn].flatten
+          #endnotes deposited at end of individual segments ||@|EXTRACTION OF ENDNOTES|
+        end
+        @per.tail << '</div>'
+        @per.tail << '</div>' #this div closes div class content
+      end
+      @per.closed=[]
+      @per.closed << format_head_seg.xhtml_close
+    end
+    def reinitialise(per)
+      per.headings,per.main,per.tail,per.credits=Array.new(4){[]}
+    end
+    def cleanup(md,per)
+      reinitialise(per)
+      @@tracker=0
+      @per.seg_endnotes,@per.seg_subtoc={},{}
+      @per.seg_endnotes_array,@per.seg_subtoc_array=[],[]
+      per.endnote_all=[]
+    end
+    def get_subtoc_endnotes(data,per) #get endnotes & sub-table of contents subtoc
+      @per=per
+      data.each do |dob|
+        dob.obj=dob.obj.gsub(/<a name=\"h\d.*?\">(.+?)<\/a>/mi,'\1')
+        if @md.flag_auto_endnotes
+          if (dob.is==:heading \
+          || dob.is==:heading_insert) \
+          && dob.ln.to_s =~/^[1-4]/ \
+          and not @per.fn.to_s.empty?
+            @per.seg_endnotes[@per.fn]=[]
+            @per.seg_endnotes[@per.fn] << @per.seg_endnotes_array
+            @per.seg_endnotes_array=[] if dob.ln==4
+          end
+          if (dob.is==:heading \
+          || dob.is==:heading_insert) \
+          && dob.ln==4
+            #%  EXTRACTION OF SUB-TOCs & SEGMENT NAME, after EXTRACTION OF ENDNOTES & SUB-TOCs
+            @per.seg_subtoc[@per.fn]=@per.seg_subtoc_array
+            @per.seg_subtoc_array=[]
+            if dob.name \
+            and dob.obj
+              @per.fn=dob.name
+            else
+              @per.fn=(dob.name =~/\S+/) \
+              ? dob.name
+              : ''
+            end
+          end
+        end
+        if dob.is==:heading \
+        && dob.ln.to_s =~/^[5-7]/
+          case dob.ln
+          when 5
+            format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,dob)
+            subtoc=format_seg.subtoc_lev5 #keep and make available, this is the subtoc
+          when 6
+            format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,dob)
+            subtoc=format_seg.subtoc_lev6 #keep and make available, this is the subtoc
+          when 7
+            format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,dob)
+            subtoc=format_seg.subtoc_lev7 #keep and make available, this is the subtoc
+          end
+          @per.seg_subtoc_array << subtoc
+        end
+        if @md.flag_auto_endnotes
+          ast,pls='&#042;','&#043;'
+          if dob.obj =~/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})(?:\d|#{ast}|#{pls})+ / \
+          and dob.is !=:code # endnote-
+            endnote_array=[]
+            if dob.obj=~/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}/m
+              endnote_array << dob.obj.scan(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}/m)
+            end
+            if dob.obj=~/#{Mx[:en_b_o]}#{ast}\d+\s.+?#{Mx[:en_b_c]}/m
+              endnote_array \
+              << dob.obj.scan(/#{Mx[:en_b_o]}#{ast}\d+\s.+?#{Mx[:en_b_c]}/m)
+            end
+            if dob.obj=~/#{Mx[:en_b_o]}#{pls}\d+\s.+?#{Mx[:en_b_c]}/m
+              endnote_array \
+              << dob.obj.scan(/#{Mx[:en_b_o]}#{pls}\d+\s.+?#{Mx[:en_b_c]}/m)
+            end
+            endnote_array=endnote_array.flatten #.compact #check compacting
+            endnote_array.each do |note|
+              note_match=note.dup
+              note_match_seg=note.dup
+              e_n=note_match_seg[/(?:#{Mx[:en_a_o]}(?:\d|#{ast}|#{pls})+|#{Mx[:en_b_o]}(?:#{ast}|#{pls})\d+)\s+(.+?)(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/m,1]
+              try=e_n.split(/<br(?: \/)?>/)
+              try.each do |e|
+                txt_obj={ txt: e }
+                format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
+                note_match=if e =~/#{Mx[:pa_o]}i[1-9]#{Mx[:pa_c]}/
+                  format_seg.endnote_body_indent
+                else format_seg.endnote_body
+                end
+                @per.seg_endnotes_array << note_match
+              end
+              try.join('<br \/>')
+              #% creation of separate end segment/page of all endnotes referenced back to reference segment
+              m=/(?:#{Mx[:en_a_o]}(?:\d|#{ast}|#{pls})+|#{Mx[:en_b_o]}(?:#{ast}|#{pls})\d+)\s+(.+?href=")(##{Mx[:note_ref]}(?:\d|_a|_b)+".+)(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/mi
+              endnote_part_a=note_match_seg[m,1]
+              endnote_part_b=note_match_seg[m,2]
+              txt_obj={
+                endnote_part_a: endnote_part_a,
+                endnote_part_b: endnote_part_b
+              }
+              format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
+              note_match_all_seg=format_seg.endnote_seg_body(@per.fn) #BUG WATCH 200408
+              @per.endnote_all << note_match_all_seg
+            end
+            dob.obj=dob.obj.gsub(/(?:#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})\s*/m,' ')
+          end
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** xhtml_epub2_tune.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xhtml_epub2_tune.rb"
+# <<sisu_document_header>>
+require_relative 'dp'                                   # dp.rb
+module SiSU_XHTML_EPUB2_Tune
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env; include SiSU_Screen
+  require_relative 'xhtml_parts'                        # xhtml_parts.rb
+  require_relative 'xhtml_epub2_format'                 # xhtml_epub2_format.rb #watch
+  @@line_mode=''
+  @@endnote_array=[]
+  @@endnote_call_counter=1
+  @@table_align='<table summary='' width="96%" border="0" bgcolor="white" cellpadding="0" col="3">
+<tr ...><td width="2%" align="right">
+&nbsp\;</td>
+<td width="94%" valign="top" align="justify">'
+  @@table_align_close='</td>
+<td width="4%" align="right" valign="top">
+<font size="1" color="#777777">
+&nbsp;&nbsp;&nbsp;</font> </td></tr></table>'
+  @@counter,@@column,@columns=0,0,0
+  class Output
+    def initialize(data,md)
+      @data,@md=data,md
+      @file=SiSU_Env::InfoFile.new(@md.fns)
+      @cX=SiSU_Screen::Ansi.new(@md.opt.act[:color_state][:set]).cX
+    end
+    def hard_output
+      @filename_tune=@file.write_file_processing.html_tune
+      data=[]
+      @data.each {|x| x.obj.strip; data << x if not x.obj.empty?} #1.9 array?
+      data.each do |dob|
+        @filename_tune.puts dob, "\n" #check
+      end
+    end
+    def marshal
+      File.open(@file.marshal.xhtml_tune,'w') {|f| Marshal.dump(@data.to_a,f)}
+    end
+  end
+  class CleanXHTML
+    def initialize(html='')
+      @html=html
+    end
+    def clean
+      html=@html
+      str=if html.is_a?(String)
+        html
+      else html.obj
+      end
+      str=str.gsub(/#{Mx[:gl_o]}(#[0-9]{3})#{Mx[:gl_c]}/u,'&\1;').
+        gsub(/#{Mx[:gl_o]}#([a-z]{2,4})#{Mx[:gl_c]}/u,'&\1;').
+        gsub(/<br>/u,'<br />').
+        gsub(/#{Mx[:nbsp]}/u,$ep[:hsp])
+    end
+  end
+  class Tune
+    include SiSU_Parts_XHTML
+    def initialize(data,md)
+      @data,@md=data,md
+      @sys=SiSU_Env::SystemCall.new
+      @env=SiSU_Env::InfoEnv.new(@md.fns)
+    end
+    def songsheet
+      begin
+        @cX=SiSU_Screen::Ansi.new(@md.opt.act[:color_state][:set]).cX
+        if (@md.opt.act[:verbose][:set]==:on \
+        || @md.opt.act[:verbose_plus][:set]==:on \
+        || @md.opt.act[:maintenance][:set]==:on)
+          SiSU_Screen::Ansi.new(
+            @md.opt.act[:color_state][:set],
+            'Tune'
+          ).txt_grey
+        end
+        data=SiSU_XHTML_EPUB2_Tune::Tune.new(@data,@md).amp_angle_brackets
+        data=SiSU_XHTML_EPUB2_Tune::Tune.new(data,@md).endnotes_html
+        data=SiSU_XHTML_EPUB2_Tune::Tune.new(data,@md).url_markup
+        data=SiSU_XHTML_EPUB2_Tune::Tune.new(data,@md).markup
+        if @md.opt.act[:maintenance][:set]==:on #Hard Output Tune Optional on/off here
+          data=SiSU_XHTML_EPUB2_Tune::Output.new(data,@md).hard_output
+          SiSU_XHTML_EPUB2_Tune::Output.new(data,@md).marshal
+        end
+        SiSU_XHTML_EPUB2_Tune::Tune.new(@data,@md).output
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    def markup
+      @tuned_file=[]
+      @data.each do |dob|
+        dob.obj=dob.obj.gsub(/#{Mx[:mk_o]}#([a-zA-Z]+)#{Mx[:mk_c]}/,'&\1;').
+          gsub(/#{Mx[:mk_o]}(#[0-9]+)#{Mx[:mk_c]}/,'&\1;')
+        dob.obj=dob.obj.gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/,'<br />') unless dob.is==:table
+        dob.obj=dob.obj.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'<b>\1</b>').
+          gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'<i>\1</i>').
+          gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'<u>\1</u>').
+          gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'<sup>\1</sup>').
+          gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'<sub>\1</sub>').
+          gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'<ins>\1</ins>').
+          gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'<cite>\1</cite>').
+          gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'<del>\1</del>').
+          gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,'<tt>\1</tt>'). # tt, kbd
+          gsub(/#{Mx[:mk_o]}:name#(\S+?)#{Mx[:mk_c]}/,'').
+          gsub(/#{Mx[:gl_bullet]}/m,"●#{$ep[:hsp]*2}").
+          gsub(/#{Dx[:url_o]}/,Dx[:url_o_xml]).gsub(/#{Dx[:url_c]}/,Dx[:url_c_xml]).
+          gsub(/#{Mx[:nbsp]}/,$ep[:hsp]).
+          gsub(/<(p|br)>/,'<\1 />')
+        dob.obj=SiSU_XHTML_EPUB2_Tune::CleanXHTML.new(dob.obj).clean
+        @tuned_file << dob
+      end
+    end
+    def urls(data)
+      @words=[]
+      map_nametags=SiSU_Particulars::CombinedSingleton.instance.get_map_nametags(@md).nametags_map #p map_nametags
+      data.each do |word|
+        @words << if word=~/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)/
+          http_=true
+          if word =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/
+            m,u=/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/.match(word).captures
+          elsif word =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}/
+            http_=false
+            m,u=/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}(\S+?)#{Mx[:rel_c]}/.match(word).captures
+          elsif word =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}image/
+            m,u=/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}(image)/.match(word).captures
+          end
+          case m
+          when /\.png|\.jpg|\.gif|c=|\s\d+x\d+/
+            w,h=/\s(\d+)x(\d+)/.match(m).captures if m =~/\s\d+x\d+/
+            w=%{width="#{w}"} if w
+            h=%{height="#{h}"} if h
+            c=m[/"(.+?)"/m,1]
+            caption=%{<br /><p class="caption">#{c}</p>} if c
+            png=m.scan(/\S+/)[0]
+            image_path=@md.file.output_path.epub.rel_image #image_path=@env.url.images_epub
+            ins=if u \
+            and u.strip !~/^image$/
+              %{<a href="#{u}"><img src="#{image_path}/#{png}" #{w} #{h} naturalsizeflag="0" align="bottom" border="0" /></a>#{caption}}
+            else %{<img src="#{image_path}/#{png}" #{w} #{h} naturalsizeflag="0" align="bottom" border="0" />#{caption}}
+            end
+            word=word.gsub(/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|image)/,ins)
+          else
+            link=m[/(.+)/m]
+            png=m.scan(/\S+/)[0].strip
+            link=link.strip
+            u=u.sub(/^#*/,'') #make neater
+            if map_nametags[u] \
+            and map_nametags[u][:segname]
+              u=unless http_
+                u=if u=~/^\d+$/
+                  u.gsub(/^(\d+)$/,"#{map_nametags[u][:segname]}#{Sfx[:xhtml]}#o\\1") if u !~/\//
+                else
+                  u.gsub(/(\S+)/,"#{map_nametags[u][:segname]}#{Sfx[:xhtml]}#\\1") if u !~/\//
+                end
+              else u
+              end
+            elsif u =~/^:/
+              u=u.gsub(/^:/,"#{@env.url.root}/")
+            elsif u =~/^\.\.\//
+              u=u.gsub(/^\.\.\//,"#{@env.url.root}/")
+            elsif u =~/https?:\/\//
+            else p "NOT FOUND name_tags: #{u}"
+            end
+            ins=%{<a href="#{u}">#{link}</a>}
+            word=word.gsub(/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/,ins).
+              gsub(/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}/,ins)
+          end
+          word
+        else word
+        end
+        word
+      end
+      @words=@words.join(' ')
+    end
+    def url_markup
+      data=@data
+      @tuned_file=[]
+      data.each do |dob|
+        unless dob.is==:code
+          if dob.obj =~/<::\s+/ #watch
+            dob.obj=dob.obj.gsub(/<::\s+(\S+?)\s+!>/,
+              %{<img src="#{@env.url.images_epub}/c_\\1.png" alt="\\1" width="14" height="14" align="bottom" border="0" />})
+          end
+          if dob.obj =~/<:image\s+/
+            dob.obj=dob.obj.gsub(/<:image\s+(http\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+>/,
+                %{<a href="\\1"><img src="#{@env.url.images_epub}/\\2" \\3 \\4 naturalsizeflag="0" align="bottom" border="0" /></a>}).
+              gsub(/<:image\s+(http\S+)\s+(\S+)\s+>/,
+                %{<a href="\\1"><img src="#{@env.url.images_epub}/\\2" naturalsizeflag="0" align="bottom" border="0" /></a>}).
+              gsub(/<:image\s+(\S+)\s+(\S+)\s+(\S+)\s+>/,
+                %{<img src="#{@env.url.images_epub}/\\1" \\2 \\3 naturalsizeflag="0" align="bottom" border="0" />}).
+              gsub(/<:image\s+(\S+)\s+>/,
+                %{<img src="#{@env.url.images_epub}/\\1" naturalsizeflag="0" align="bottom" border="0" />})
+          end
+          if dob.obj =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)/
+            @word_mode=dob.obj.scan(/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)[()\[\]]*[,.;:!?'"]{0,2}|(?:#{Mx[:gl_o]}\S+?#{Mx[:gl_c]})+|[^#{Mx[:lnk_o]}#{Mx[:lnk_c]}]+/mu)
+            words=urls(@word_mode)
+            dob.obj=dob.obj.gsub(/.+/m,words)
+          end
+          dob.obj=dob.obj.gsub(/\\copyright/i,%{<sup>&copy;</sup>})
+          dob.obj=if (dob.obj !~/\<:ad\s+\.\.\//)
+            dob.obj.gsub(/\<:ad\s+(\S+)?\s+(\S+\.png)\s+(.+)?\;\s+(.+)?\;\s*!\>/,
+              %{\n<center><a href="http:\/\/\\1" target="external"><img src="#{@env.url.images_epub}/\\2" alt="\\3" /></a></center>\n})
+          else
+            dob.obj.gsub(/\<:ad\s+(\S+)?\s+(\S+\.png)\s+(.+)?\;\s+(.+)?\;\s*\>/,
+              %{\n<center><a href="\\1" target="_top"><img src="#{@env.url.images_epub}/\\2" alt="\\3" /></a></center>\n})
+          end
+          dob.obj=dob.obj.gsub(/!pick/,%{<img border="0" height="15" width="15" src="#{@env.url.images_epub}/#{the_icon.i_choice}" alt="stellar" />}).
+            gsub(/!new/,%{#{$ep[:hsp]}<img border="0" height="15" width="15" src="#{@env.url.images_epub}/#{the_icon.i_new}" alt="new" />}).
+            gsub(/<:h(.{1,7}?)>/,'<a href="#h\1">\1</a>').
+            gsub(/<:to(\d{1,7}?)>/,%{<a href="#to\\1">to#{$ep[:hsp]}\{#{$ep[:hsp]}\\1#{$ep[:hsp]}\}</a> }).
+            gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,'<a href="\1" target="_top">\1</a>'). #http ftp matches escaped, no decoration
+            gsub(/#{Mx[:url_o]}([a-zA-Z0-9._-]+\@\S+?\.[a-zA-Z0-9._-]+)#{Mx[:url_c]}/,%{#{the_url_decoration.xml_open}<a href="mailto:\\1">\\1</a>#{the_url_decoration.xml_close}}).
+            gsub(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,%{#{the_url_decoration.xml_open}<a href="\\1" target="_top">\\1</a>#{the_url_decoration.xml_close}}) #http ftp matches with decoration
+          if dob.obj =~/..\/\S+/ \
+          and dob.obj !~/(\"..\/\S+?\"|>\s*..\/\S+<)/
+            dob.obj=dob.obj.gsub(/(\.\.\/\S+)/,'<a href="\1">\1</a>')
+          end
+          dob.obj=dob.obj.gsub(/<a href="\.\.\//,%{<a href="#{the_url.site}/})
+        else
+          dob.obj=dob.obj.gsub(/</m,'&lt;').gsub(/>/m,'&gt;')
+        end
+        @tuned_file << dob
+      end
+    end
+    def amp_angle_brackets
+      data,data_new=@data,[]
+      data.each do |dob|
+        dob.obj=dob.obj.
+          gsub(/&/u,'&amp;').
+          gsub(/</u,'&lt;').gsub(/>/u,'&gt;')
+        data_new << dob
+      end
+      data_new
+    end
+    def endnotes_html
+      data=@data
+      @tuned_file=[]
+      a,s='_a','_s'
+      ast,pls='&#042;','&#043;'
+      data.each do |dob|
+        unless dob.is ==:code
+          dob.obj=dob.obj.gsub(/(#{Mx[:en_a_o]}|#{Mx[:en_b_o]})(\d+)\s+(.+?)(#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/,
+              %{#{Mx[:nbsp]}<a href="##{Mx[:note]}\\2">#{Mx[:nbsp]}<sup id="#{Mx[:note_ref]}\\2">\\2</sup>#{Mx[:nbsp]}</a> } +  #note- endnote-
+              %{\\1\\2 <a href="##{Mx[:note_ref]}\\2">#{Mx[:nbsp]}<sup id="#{Mx[:note]}\\2">\\2.</sup></a> \\3 \\4}). #endnote- note- (careful may have switched)
+            gsub(/(#{Mx[:en_b_o]})[*](\d+)\s+(.+?)(#{Mx[:en_b_c]})/,
+              %{#{Mx[:nbsp]}<a href="##{Mx[:note_astx]}\\2">#{Mx[:nbsp]}<sup id="#{Mx[:note_ref_astx]}\\2">#{ast}\\2</sup>#{Mx[:nbsp]}</a> } +  #note- endnote-
+              %{\\1#{ast}\\2 <a href="##{Mx[:note_ref_astx]}\\2">#{Mx[:nbsp]}<sup id="#{Mx[:note_astx]}\\2">#{ast}\\2.</sup></a> \\3 \\4}). #endnote- note- (careful may have switched)
+            gsub(/(#{Mx[:en_b_o]})[+](\d+)\s+(.+?)(#{Mx[:en_b_c]})/,
+              %{#{Mx[:nbsp]}<a href="##{Mx[:note_plus]}\\2">#{Mx[:nbsp]}<sup id="#{Mx[:note_ref_plus]}\\2">#{pls}\\2</sup>#{Mx[:nbsp]}</a> } +  #note- endnote-
+              %{\\1#{pls}\\2 <a href="##{Mx[:note_ref_plus]}\\2">#{Mx[:nbsp]}<sup id="#{Mx[:note_plus]}\\2">#{pls}\\2.</sup></a> \\3 \\4}) #endnote- note- (careful may have switched) # double-check there may here be a bug
+          if dob.obj =~/#{Mx[:en_a_o]}([*+]+)\s+.+?#{Mx[:en_a_c]}/
+            m=$1.length.to_i
+            dob.obj=dob.obj.gsub(/(#{Mx[:en_a_o]})[*]+\s+(.+?)(#{Mx[:en_a_c]})/,
+                %{#{Mx[:nbsp]}<a href="##{Mx[:note]}#{a*m}">#{Mx[:nbsp]}<sup id="#{Mx[:note_ref]}#{a*m}">#{ast*m}</sup>#{Mx[:nbsp]}</a> } +  #note- endnote-
+                %{\\1#{ast*m} <a href="##{Mx[:note_ref]}#{a*m}">#{Mx[:nbsp]}<sup id="#{Mx[:note]}#{a*m}">#{ast*m}</sup></a> \\2 \\3}). #endnote- note- (careful may have switched)
+              gsub(/(#{Mx[:en_a_o]})([+]+)\s+(.+?)(#{Mx[:en_a_c]})/,
+                %{#{Mx[:nbsp]}<a href="##{Mx[:note]}#{s*m}">#{Mx[:nbsp]}<sup id="#{Mx[:note_ref]}#{s*m}">#{pls*m}</sup>#{Mx[:nbsp]}</a> } +  #note- endnote-
+                %{\\1#{pls*m} <a href="##{Mx[:note_ref]}#{s*m}">#{Mx[:nbsp]}<sup id="#{Mx[:note]}#{s*m}">#{pls*m}</sup></a> \\2 \\3}) #endnote- note- (careful may have switched)
+          end
+        end
+        @tuned_file << dob
+      end
+    end
+    def output
+      data=@data
+      @tuned_file=[]
+      data.each do |dob|
+        dob.obj=dob.obj.strip.chomp
+        @tuned_file << dob
+      end
+      @tuned_file << "\n<EOF>" if (@md.fns =~/\.sst0/) #remove
+      @tuned_file
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* xhtml shared
+** xhtml_parts.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xhtml_parts.rb"
+# <<sisu_document_header>>
+module SiSU_Parts_XHTML
+  require_relative 'generic_parts'                       # generic_parts.rb
+  include SiSU_Parts_Generic
+  def the_line_break
+    '<br />'
+  end
+  def the_table_close
+    '</td></tr>
+</table>'
+  end
+  def the_url
+    def home
+      'http://www.sisudoc.org/' # used in pdf header
+    end
+    def site #used as stub... where there are subdirectories and is different from home
+      home
+    end
+    self
+  end
+  def the_url_decoration
+    def xml_open                     #'&lt;'
+      Dx[:url_o]
+    end
+    def xml_close                    #'&gt;'
+      Dx[:url_c]
+    end
+    def txt_open
+      '<'
+    end
+    def txt_close
+      '>'
+    end
+    self
+  end
+  def the_margin
+    def txt_0
+      %{<table summary="" width=#{the_width.table_txt} border="0" cellpadding="2" align="center">
+<tr><td width=#{indent_level_0} align="right">
+</td><td valign="top" align="justify">}
+    end
+    def txt_1
+      %{<table summary="" width=#{the_width.table_txt} border="0" cellpadding="2" align="center">
+<tr><td width=#{indent_level_1} align="right"></td><td valign="top" align="justify">}
+    end
+    def txt_2
+      %{<table summary="" width=#{the_width.table_txt} border="0" cellpadding="2" align="center">
+<tr><td width=#{indent_level_2} align="right">
+</td>
+<td valign="top" align="justify">}
+    end
+    def txt_3
+      %{<table summary="" width=#{the_width.table_txt} border="0" cellpadding="2" align="center">
+<tr><td width=#{indent_level_3} align="right">
+</td>
+<td valign="top" align="justify">}
+    end
+    def css
+      '<table summary="normal text css" width="100%" border="0" cellpadding="2" align="center">
+<tr><td valign="top" align="justify"> '
+    end
+    def num_css
+      '</td>
+<td width="2%" align="right" valign="top">  '
+    end
+    self
+  end
+  def the_font
+    def set_fonts
+      'verdana, arial, georgia, tahoma, sans-serif, helvetica, times, roman'
+     #'verdana, arial, georgia, tahoma, sans-serif, helvetica, "times new roman", times, roman'
+    end
+    def set_small
+      'size="3"'
+    end
+    def set_tiny
+      'size="2"'
+    end
+    def paragraph_font_tiny
+      %{<font #{set_tiny} #{set_face}>}
+    end
+    def paragraph_font_small
+      %{<font #{set_small} #{set_face}>}
+    end
+    self
+  end
+  def the_nav
+    def txt_concordance
+      %{  <font face="#{the_font.set_fonts}" size="2">
+    &nbsp;&nbsp;A-Z&nbsp;
+  </font> }
+    end
+    def txt_toc_link
+      %{  <font face="#{the_font.set_fonts}" size="2">
+    &nbsp;&nbsp;toc&nbsp;
+  </font> }
+    end
+    def txt_manifest
+      #{png_manifest}&nbsp;document&nbsp;manifest
+      %{  <font face="#{the_font.set_fonts}" size="2">
+    [&nbsp;document&nbsp;manifest&nbsp;]
+  </font> }
+    end
+    def txt_concordance
+      %{  <font face="#{the_font.set_fonts}" size="2">
+    &nbsp;&nbsp;A-Z&nbsp;
+  </font> }
+    end
+    self
+  end
+end
+module SiSU_Proj_XHTML
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  class Bits
+    include SiSU_Parts_HTML
+    def initialize
+      @v=SiSU_Env::InfoVersion.instance.get_version
+    end
+    def credits_sisu_epub
+      %{<div class="substance">
+<p class="center"><a href="http://www.openebook.org"><b>EPUB</b></a> generated by <a href="http://www.sisudoc.org"><b>#{@v.project}</b></a> v#{@v.version}, GPL3</p>
+</div>}
+      ''
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** xhtml_shared.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xhtml_shared.rb"
+# <<sisu_document_header>>
+module SiSU_XHTML_Shared
+  require_relative 'xhtml_table'                        # xhtml_table.rb
+  class TableXHTML < SiSU_XHTML_Table::TableXHTML
+  end
+end
+__END__
+#+END_SRC
+
+** xhtml_table.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xhtml_table.rb"
+# <<sisu_document_header>>
+module SiSU_XHTML_Table
+  require_relative 'xhtml_parts'                         # xhtml_parts.rb
+  class TableXHTML
+    include SiSU_Parts_XHTML
+    @@tablefoot=[] #watch
+    def initialize(table)
+      @table_obj=table
+    end
+    def table
+      table_obj=@table_obj
+      if table_obj.obj !~/^<table\s/m
+        table_obj=table_rows_and_columns_array(table_obj)
+      else p __LINE__; p caller
+      end
+      table_obj
+    end
+    def table_rows_and_columns_array(table_obj) # provides basic (x)html table
+      table_rows,nr=[],0
+      table_obj.obj.split(Mx[:tc_c]).each do |table_row|
+        table_row_with_columns=table_row.split(Mx[:tc_p])
+        trc,nc=[],0
+        table_row_with_columns.each do |c|
+          c=c.gsub(/^~$/,''). # tilde / empty cell
+            gsub(/<:br>/,the_line_break)
+          trc <<= if table_obj.head_ and nr==0; %{<th width="#{table_obj.widths[nc]}%">#{c}</th>}
+          else %{<td width="#{table_obj.widths[nc]}%">#{c}</td>}
+          end
+          nc+=1
+        end
+        trc=(trc.is_a?(Array)) ? trc.flatten.join : trc
+        trc="      <tr>#{trc}</tr>\n"
+        nr+=1
+        table_rows << trc
+      end
+      table_rows=table_rows.flatten.join
+      table_obj.obj=%{<table summary="normal text css" width="100%" border="0" bgcolor="white" cellpadding="2" align="center">\n#{table_rows}    </table>}
+      table_obj
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    xhtml
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
diff --git a/org/xml.org b/org/xml.org
new file mode 100644
index 00000000..68452bfa
--- /dev/null
+++ b/org/xml.org
@@ -0,0 +1,5583 @@
+-*- mode: org -*-
+#+TITLE:       sisu xml including odf
+#+DESCRIPTION: documents - structuring, various output representations & search
+#+FILETAGS:    :sisu:xml:
+#+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
+
+* xml native
+** xml_sax.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xml_sax.rb"
+# <<sisu_document_header>>
+module SiSU_XML_SAX
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+    include SiSU_Particulars
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'xml_shared'                         # xml_shared.rb
+    include SiSU_XML_Munge
+  require_relative 'xml_format'                         # xml_format.rb
+    include SiSU_XML_Format
+  require_relative 'xml_persist'                        # xml_persist.rb
+  require_relative 'rexml'                              # rexml.rb
+    include SiSU_Rexml
+  require_relative 'shared_metadata'                    # shared_metadata.rb
+  @@alt_id_count=0
+  @@tablefoot=''
+  class Source
+    def initialize(opt)
+      @opt=opt
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+    end
+    def read
+      begin
+        @env,              @md,            @ao_arr=
+          @particulars.env,@particulars.md,@particulars.ao_array
+        unless @opt.act[:quiet][:set]==:on
+          tool=if (@opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on)
+            @env.program.web_browser \
+            + ' file://' \
+            + @md.file.output_path.xml_sax.dir + '/' \
+            + @md.file.base_filename.xml_sax + "\n\t" \
+            + @env.program.xml_viewer \
+            + ' file://' \
+            + @md.file.output_path.xml_sax.dir + '/' \
+            + @md.file.base_filename.xml_sax
+          elsif @opt.act[:verbose][:set]==:on
+            @env.program.web_browser \
+            + ' file://' \
+            + @md.file.output_path.xml_sax.dir + '/' \
+            + @md.file.base_filename.xml_sax
+          else "[#{@opt.f_pth[:lng_is]}] #{@opt.fno}"
+          end
+          (@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on) \
+          ? SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'XML SAX',
+              tool
+            ).green_hi_blue
+          : SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'XML SAX',
+              tool
+            ).green_title_hi
+          if (@opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on)
+            SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              @opt.fns,
+              'file://' \
+              + @md.file.output_path.xml_sax.dir + '/' \
+              + @md.file.base_filename.xml_sax
+            ).flow
+          end
+        end
+        SiSU_XML_SAX::Source::Songsheet.new(@particulars).song
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        #file closed in songsheet
+        SiSU_Env::CreateSite.new(@opt).cp_css
+        Dir.chdir(@opt.f_pth[:pth])
+      end
+    end
+    private
+    class Songsheet
+      def initialize(particulars)
+        @env,             @md,           @ao_arr,             @particulars=
+          particulars.env,particulars.md,particulars.ao_array,particulars
+        @file=SiSU_Env::FileOp.new(@md)
+      end
+      def song
+        begin
+          SiSU_XML_SAX::Source::Scroll.new(@particulars).songsheet
+          if (@md.opt.act[:verbose][:set]==:on \
+          || @md.opt.act[:verbose_plus][:set]==:on \
+          || @md.opt.act[:maintenance][:set]==:on)
+            SiSU_XML_SAX::Source::Tidy.new(@md,@file.place_file.xml_sax.dir).xml # test wellformedness, comment out when not in use
+          end
+          SiSU_Rexml::Rexml.new(@md,@file.place_file.xml_sax.dir).xml if @md.opt.act[:maintenance][:set]==:on # test rexml parsing, comment out when not in use #debug
+        rescue
+          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+        ensure
+        end
+      end
+    end
+    class Scroll
+      require_relative 'txt_shared'                     # txt_shared.rb
+        include SiSU_TextUtils
+      require_relative 'css'                            # css.rb
+      require_relative 'xhtml_shared'                   # decide use, whether xml rather than xhtml
+      def initialize(particulars)
+        @env,             @md,           @ao_arr=
+          particulars.env,particulars.md,particulars.ao_array
+        @trans=SiSU_XML_Munge::Trans.new(@md)
+        @sys=SiSU_Env::SystemCall.new
+        @per=SiSU_XML_Persist::Persist.new
+      end
+      def songsheet
+        begin
+          pre
+          @data=markup(@ao_arr)
+          post
+          publish
+        ensure
+          SiSU_XML_Persist::Persist.new.persist_init
+        end
+      end
+    protected
+      def embedded_endnotes(dob='')
+        dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}(\d+)\s+(.+?)#{Mx[:en_a_c]}/,
+            '<endnote><number>\1</number><note>\2</note></endnote> ').
+          gsub(/#{Mx[:en_b_o]}([*+]\d+)\s+(.+?)#{Mx[:en_b_c]}/,
+            '<endnote><symbol>\1</symbol><note>\2</note></endnote> ').
+          gsub(/#{Mx[:en_a_o]}([*+]+)\s+(.+?)#{Mx[:en_a_c]}/,
+            '<endnote><symbol>\1</symbol><note>\2</note></endnote> ')
+      end
+      def extract_endnotes(dob='')
+        notes=dob.obj.scan(/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})([\d*+]+\s+.+?)(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/)
+        notes.flatten.each do |e|
+          s=e.to_s
+          util=SiSU_TextUtils::Wrap.new(s,70)
+          wrap=util.line_wrap
+          wrap=wrap.gsub(/^(\d+)\s+(.+?)\s*\Z/m, <<WOK
+#{Ax[:tab]*1}<endnote notenumber="\\1">
+#{Ax[:tab]*2}<number>\\1</number>
+#{Ax[:tab]*2}<note>
+#{Ax[:tab]*3}\\2
+#{Ax[:tab]*2}</note>
+#{Ax[:tab]*1}</endnote>
+WOK
+).
+            gsub(/^([*+]\d+)\s+(.+?)\s*\Z/m, <<WOK
+#{Ax[:tab]*1}<endnote symbol="\\1">
+#{Ax[:tab]*2}<symbol>\\1</symbol>
+#{Ax[:tab]*2}<note>
+#{Ax[:tab]*3}\\2
+#{Ax[:tab]*2}</note>
+#{Ax[:tab]*1}</endnote>
+WOK
+).
+            gsub(/^([*+]+)\s+(.+?)\s*\Z/m, <<WOK
+#{Ax[:tab]*1}<endnote symbol="\\1.length">
+#{Ax[:tab]*2}<symbol>\\1</symbol>
+#{Ax[:tab]*2}<note>
+#{Ax[:tab]*3}\\2
+#{Ax[:tab]*2}</note>
+#{Ax[:tab]*1}</endnote>
+WOK
+)
+          @endnotes << wrap
+        end
+      end
+      def xml_head
+        metadata=SiSU_Metadata::Summary.new(@md).xml_sax.metadata
+        @per.head << metadata
+      end
+      def xml_sc(md='')
+        sc=if @md.sc_info
+          <<WOK
+    <source_control>
+      <meta>filename:</meta>
+      <sc class="sourcefile">
+        #{@md.sc_filename}
+      </sc><br />
+      <meta>version number:</meta>
+      <sc class="number">
+        #{@md.sc_number}
+      </sc><br />
+      <meta>version date:</meta>
+      <sc class="date">
+        #{@md.sc_date}
+      </sc><br />
+    </source_control>
+WOK
+        else ''
+        end
+        @per.sc=sc
+      end
+      def xml_structure(dob,type='norm')
+        if dob.is==:heading
+          lv=dob.ln
+          dob.ln + 2
+        else lv=nil
+        end
+        extract_endnotes(dob)
+        dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'<en>\1</en>'). #footnote/endnote clean
+          gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'<en>\1</en>') #footnote/endnote clean
+        #if defined? dob.obj
+        #t_ograph="#{dob.obj}"
+        util=SiSU_TextUtils::Wrap.new(dob.obj,70)
+        wrapped=util.line_wrap
+        #end
+        @per.body << if defined? dob.ocn; %{#{Ax[:tab]*0}<object id="#{dob.ocn}">}
+        else                              "#{Ax[:tab]*0}<object>"
+        end
+        @per.body << "#{Ax[:tab]*1}<ocn>#{dob.ocn}</ocn>" if defined? dob.ocn
+        @per.body << if lv; %{#{Ax[:tab]*1}<text class="h#{lv}">\n#{Ax[:tab]*2}#{wrapped}\n#{Ax[:tab]*1}</text>}
+        else                   %{#{Ax[:tab]*1}<text class="#{type}">\n#{Ax[:tab]*2}#{wrapped}\n#{Ax[:tab]*1}</text>} # main text, contents, body KEEP
+        end
+        @per.body << @endnotes if @endnotes
+        ##@per.body << "#{Ax[:tab]*1}<text>#{dob[@regx,2]}</text>" if dob[@regx,2] # old unwrapped main text, contents, body KEEP
+        @per.body << "#{Ax[:tab]*0}</object>"
+        @endnotes=[]
+      end
+      def block_structure(dob='')
+        extract_endnotes(dob)
+        dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'<en>\1</en>'). #footnote/endnote clean
+          gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'<en>\1</en>') #footnote/endnote clean
+        dob=@trans.markup_block(dob)
+        dob.obj=dob.obj.strip
+        @per.body << %{#{Ax[:tab]*0}<object id="#{dob.ocn}">}
+        @per.body << %{#{Ax[:tab]*1}<ocn>#{dob.ocn}</ocn>}
+        @per.body << %{#{Ax[:tab]*1}<text class="block">#{Ax[:tab]*1}}
+        @per.body << %{#{Ax[:tab]*2}#{dob.obj}#{Ax[:tab]*1}}
+        @per.body << %{#{Ax[:tab]*1}</text>}
+        @per.body << "#{Ax[:tab]*0}</object>"
+        @per.body << @endnotes if @endnotes
+        @endnotes=[]
+      end
+      def group_structure(dob='')
+        extract_endnotes(dob)
+        dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'<en>\1</en>'). #footnote/endnote clean
+          gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'<en>\1</en>') #footnote/endnote clean
+        dob=@trans.markup_group(dob)
+        dob.obj=dob.obj.strip
+        @per.body << %{#{Ax[:tab]*0}<object id="#{dob.ocn}">}
+        @per.body << %{#{Ax[:tab]*1}<ocn>#{dob.ocn}</ocn>}
+        @per.body << %{#{Ax[:tab]*1}<text class="group">#{Ax[:tab]*1}}
+        @per.body << %{#{Ax[:tab]*2}#{dob.obj}#{Ax[:tab]*1}}
+        @per.body << %{#{Ax[:tab]*1}</text>}
+        @per.body << "#{Ax[:tab]*0}</object>"
+        @per.body << @endnotes if @endnotes
+        @endnotes=[]
+      end
+      def poem_structure(dob='')
+        dob=@trans.markup_group(dob)
+        #dob.obj.gsub(/\s\s/,'&#160;&#160;')
+        dob.obj=dob.obj.strip
+        @per.body << %{#{Ax[:tab]*0}<object id="#{dob.ocn}">}
+        @per.body << %{#{Ax[:tab]*1}<ocn>#{dob.ocn}</ocn>}
+        @per.body << %{#{Ax[:tab]*1}<text class="verse">#{Ax[:tab]*1}}
+        @per.body << %{#{Ax[:tab]*2}#{dob.obj}#{Ax[:tab]*1}}
+        @per.body << %{#{Ax[:tab]*1}</text>}
+        @per.body << %{#{Ax[:tab]*0}</object>}
+      end
+      def code_structure(dob='')
+        dob=@trans.markup_group(dob)
+        dob.obj=dob.obj.gsub(/\s\s/,'&#160;&#160;').strip
+        @per.body << %{#{Ax[:tab]*0}<object id="#{dob.ocn}">}
+        @per.body << %{#{Ax[:tab]*1}<ocn>#{dob.ocn}</ocn>}
+        @per.body << %{#{Ax[:tab]*1}<text class="code">#{Ax[:tab]*1}}
+        @per.body << %{#{Ax[:tab]*2}#{dob.obj}#{Ax[:tab]*1}}
+        @per.body << %{#{Ax[:tab]*1}</text>}
+        @per.body << "#{Ax[:tab]*0}</object>"
+      end
+      def table_structure(dob)
+        table=SiSU_XHTML_Shared::TableXHTML.new(dob)
+        @per.body << %{#{Ax[:tab]*0}<object id="#{dob.ocn}">}
+        @per.body << %{#{Ax[:tab]*1}<ocn>#{dob.ocn}</ocn>}
+        @per.body << %{#{Ax[:tab]*1}<text class="table">#{Ax[:tab]*1}}
+        @per.body << %{#{Ax[:tab]*2}#{table.table.obj}}
+        @per.body << %{#{Ax[:tab]*1}</text>}
+        #@per.body << %{#{tab*1}</text>}
+        @per.body << "#{Ax[:tab]*0}</object>"
+       #@per.body << %{#{Ax[:tab]*0}<object id="#{ocn}">}
+       #@per.body << %{#{Ax[:tab]*1}#{table}\n#{Ax[:tab]*1}} # unless lv  # main text, contents, body KEEP
+       #@per.body << "#{Ax[:tab]*0}</object>"
+       #@endnotes=[]
+      end
+      def markup(data)
+        xml_sc(@md)
+        @endnotes,@level,@cont,@copen,@xml_contents_close=[],[],[],[],[]
+        @rcdc=false
+        xml_head
+        (0..7).each { |x| @cont[x]=@level[x]=false }
+        (4..7).each { |x| @xml_contents_close[x]='' }
+        data.each do |dob|
+          @trans.char_enc.utf8(dob) if @sys.locale =~/utf-?8/i #% utf8
+          dob=@trans.markup(dob)
+          if @rcdc==false \
+          and (dob.is ==:meta \
+          and dob.obj =~/Document Information/)
+            @rcdc=true
+          end
+          if dob.obj !~/(^#{Rx[:meta]}|#{Mx[:br_eof]}|#{Mx[:br_endnotes]})/
+            if defined? dob.ocn #look to move to format section
+              ocn=((dob.ocn.to_s =~/\d+/) ? dob.ocn : nil)
+              @p_num=SiSU_XML_Format::ParagraphNumber.new(@md,ocn)
+            end
+            if not @rcdc
+              if defined? dob.ocn \
+              and dob.ocn.to_s =~/\d+/
+                x=SiSU_XML_Format::FormatSeg.new(@md,dob)
+                if dob.is==:heading
+                  xml_structure(dob)
+                  dob.obj=case dob.ln
+                  when 1 then x.heading_body1
+                  when 2 then x.heading_body2
+                  when 3 then x.heading_body3
+                  when 4 then x.heading_body4
+                  when 5 then x.heading_body5
+                  when 6 then x.heading_body6
+                  when 7 then x.heading_body7
+                  end
+                else
+                  if dob.is==:verse
+                    poem_structure(dob)
+                  elsif dob.is==:group
+                    group_structure(dob)
+                  elsif dob.is==:block
+                    block_structure(dob)
+                  elsif dob.is==:code
+                    code_structure(dob)
+                  elsif dob.is==:table # FIX, check css, will need to modify
+                    table_structure(dob)
+                  elsif dob.is ==:para \
+                  and dob.indent.to_s =~/[1-9]/ \
+                  and dob.bullet_==true
+                    xml_structure(dob,"indent_bullet#{dob.indent}")
+                  elsif dob.is ==:para \
+                  and dob.indent.to_s =~/[1-9]/ \
+                  and dob.indent == dob.hang
+                    xml_structure(dob,"indent#{dob.indent}")
+                  elsif dob.is ==:para \
+                  and dob.hang.to_s =~/[0-9]/ \
+                  and dob.indent != dob.hang
+                    xml_structure(dob,"hang#{dob.hang.to_s}_indent#{dob.indent.to_s}")
+                  else xml_structure(dob)
+                  end
+                end
+              elsif dob.obj =~/(#{Mx[:br_eof]}|#{Mx[:br_endnotes]})/
+              elsif dob.obj =~/MetaData/
+                txt_obj={ txt: '<br /><a name="metadata">MetaData</a>' }
+                format_scroll=FormatScroll.new(@md,txt_obj)
+                dob.obj=format_scroll.bold_para
+              elsif dob.obj =~/(Owner Details)/
+#               txt_obj={ txt: '<br /><a name="owner.details">Owner Details</a>' }
+#               format_scroll=FormatScroll.new(@md,txt_obj)
+#               @per.owner_details=format_scroll.bold_para
+                dob.obj=''
+              end
+              if dob.obj =~/<a name="n\d+">/ \
+              and dob.obj =~/^(-\{{2}~\d+|<!e[:_]\d+!>)/ # -endnote
+                dob.obj=''
+              end
+              if dob.obj =~/.*<:#>.*$/ #investigate removal
+                dob.obj=if dob.obj =~ /#{Mx[:pa_o]}:i[1-9]#{Mx[:pa_c]}/
+                  txt_obj={ txt: dob }
+                  format_text=FormatTextObject.new(@md,txt_obj)
+                  format_text.scr_inden_ocn_e_no_paranum
+                end
+              end
+            else #
+            end
+            dob.obj=dob.obj.gsub(/#{Mx[:pa_o]}:\S+#{Mx[:pa_c]}/,'') if dob.obj
+          end
+        end
+        7.downto(4) do |x|
+          y=x - 1; v=x - 3
+          @per.body << "#{Ax[:tab]*5}</content>\n#{Ax[:tab]*y}</contents#{v}>" if @level[x]==true
+        end
+        3.downto(1) do |x|
+          y=x - 1
+          @per.body << "#{Ax[:tab]*y}</heading#{x}>" if @level[x]==true
+        end
+        #7.downto(1) { |x| y=x - 1; @per.body << "#{Ax[:tab]*y}</level #{x}>" if @level[x]==true }
+      end
+      def pre
+        rdf=SiSU_XML_Tags::RDF.new(@md)
+        @per.head,@per.body=[],[]
+        stylesheet=SiSU_Style::CSS_HeadInfo.new(@md,'xml_sax').stylesheet
+        encoding=if @sys.locale =~/utf-?8/i then '<?xml version="1.0" encoding="UTF-8" standalone="no"?>'
+        else                                     '<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>'
+        end
+        @per.open =<<WOK
+#{encoding}
+#{stylesheet.css_head_xml}
+#{rdf.comment_xml}
+<document>
+WOK
+        @per.head << '<head>'
+        @per.body << '<body>'
+      end
+      def post
+        @per.head << @per.sc
+        @per.head << '</head>'
+        @per.body << '</body>'
+        @per.close = '</document>'
+      end
+      def publish
+        content=[]
+        content << @per.open << @per.head << @per.body #<< @per.metadata
+        #content << @per.owner_details if @md.stmp =~/\w\w/
+        content << @per.tail << @per.close
+        content=content.flatten.compact
+        Output.new(content,@md).xml
+        @@xml={}
+      end
+    end
+    class Output
+      def initialize(data,md)
+        @data,@md=data,md
+        @file=SiSU_Env::FileOp.new(@md)
+      end
+      def xml
+        SiSU_Env::FileOp.new(@md).mkdir
+        filename_xml=@file.write_file.xml_sax
+        @data.each do |str|
+          str=str.gsub(/\A\s+\Z/m,'')
+          filename_xml.puts str unless str.empty?
+        end
+        filename_xml.close
+      end
+    end
+    class Tidy
+      def initialize(md,file)
+        @md,@file=md,file
+        @prog=SiSU_Env::InfoProgram.new
+      end
+      def xml
+        if @prog.tidy !=false #note values can be other than true
+          if (@md.opt.act[:verbose_plus][:set]==:on \
+          || @md.opt.act[:maintenance][:set]==:on)
+            unless @md.opt.act[:quiet][:set]==:on
+              SiSU_Screen::Ansi.new(
+                @md.opt.act[:color_state][:set],
+                'invert',
+                'Using XML Tidy',
+                'check document structure'
+              ).colorize
+              tell=SiSU_Screen::Ansi.new(
+                @md.opt.act[:color_state][:set],
+                'invert',
+                '',
+                ''
+              )
+              tell.grey_open
+            end
+            tidyfile='/dev/null' #don't want one or screen output, check for alternative flags
+            tidy=SiSU_Env::SystemCall.new(@file,tidyfile)
+            tidy.well_formed?
+            tell.p_off unless @md.opt.act[:quiet][:set]==:on
+          end
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** xml_dom.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xml_dom.rb"
+# <<sisu_document_header>>
+module SiSU_XML_DOM
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+    include SiSU_Particulars
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'ao'                                 # ao.rb
+  require_relative 'xml_shared'                         # xml_shared.rb
+    include SiSU_XML_Munge
+  require_relative 'xml_format'                         # xml_format.rb
+    include SiSU_XML_Format
+  require_relative 'xml_persist'                        # xml_persist.rb
+  require_relative 'rexml'                              # rexml.rb
+    include SiSU_Rexml
+  require_relative 'shared_metadata'                    # shared_metadata.rb
+  @@alt_id_count=0
+  @@tablefoot=''
+  class Source
+    def initialize(opt)
+      @opt=opt
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+    end
+    def read
+      begin
+        @env,              @md,            @ao_arr=
+          @particulars.env,@particulars.md,@particulars.ao_array
+        unless @opt.act[:quiet][:set]==:on
+          tool=if (@opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on)
+            @env.program.web_browser \
+            + ' file://' \
+            + @md.file.output_path.xml_dom.dir + '/' \
+            + @md.file.base_filename.xml_dom + "\n\t" \
+            + @env.program.xml_viewer \
+            + ' file://' \
+            + @md.file.output_path.xml_dom.dir + '/' \
+            + @md.file.base_filename.xml_dom
+          elsif @opt.act[:verbose][:set]==:on
+            @env.program.web_browser \
+            + ' file://' \
+            + @md.file.output_path.xml_dom.dir + '/' \
+            + @md.file.base_filename.xml_dom
+          else "[#{@opt.f_pth[:lng_is]}] #{@opt.fno}"
+          end
+          (@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on) \
+          ? SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'XML DOM',
+              tool
+            ).green_hi_blue
+          : SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'XML DOM',
+              tool
+            ).green_title_hi
+          if (@opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on)
+            SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              @opt.fns,
+              'file://' \
+              + @md.file.output_path.xml_dom.dir + '/' \
+              + @md.file.base_filename.xml_dom
+            ).flow
+          end
+        end
+        SiSU_XML_DOM::Source::Songsheet.new(@particulars).songsheet
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        SiSU_Env::CreateSite.new(@opt).cp_css
+        Dir.chdir(@opt.f_pth[:pth])
+      end
+    end
+    private
+    class Songsheet
+      def initialize(particulars)
+        @env,             @md,           @ao_arr,             @particulars=
+          particulars.env,particulars.md,particulars.ao_array,particulars
+        @file=SiSU_Env::FileOp.new(@md)
+      end
+      def songsheet
+        begin
+          SiSU_XML_DOM::Source::Scroll.new(@particulars).songsheet
+          if (@md.opt.act[:verbose][:set]==:on \
+          || @md.opt.act[:verbose_plus][:set]==:on \
+          || @md.opt.act[:maintenance][:set]==:on)
+            SiSU_XML_DOM::Source::Tidy.new(@md,@file.place_file.xml_dom.dir).xml # test wellformedness, comment out when not in use
+          end
+          SiSU_Rexml::Rexml.new(@md,@file.place_file.xml_dom.dir).xml if @md.opt.act[:maintenance][:set]==:on # test rexml parsing, comment out when not in use #debug
+        rescue
+          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
+            __LINE__.to_s + ':' + __FILE__
+          end
+        ensure
+        end
+      end
+    end
+    class Scroll
+      require_relative 'txt_shared'                     # txt_shared.rb
+        include SiSU_TextUtils
+      require_relative 'xhtml_shared'                   # decide use, whether xml rather than xhtml
+      def initialize(particulars)
+        @env,             @md,           @ao_arr=
+          particulars.env,particulars.md,particulars.ao_array
+        @trans=SiSU_XML_Munge::Trans.new(@md)
+        @sys=SiSU_Env::SystemCall.new
+        @per=SiSU_XML_Persist::Persist.new
+      end
+      def songsheet
+        begin
+          pre
+          @data=markup(@ao_arr)
+          post
+          publish
+        ensure
+          SiSU_XML_Persist::Persist.new.persist_init
+        end
+      end
+    protected
+      def xml_markup(dob='')
+        dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}(\d+)\s+(.+?)#{Mx[:en_a_c]}/,
+            '<endnote><number>\1</number><note>\2</note></endnote> ').
+          gsub(/#{Mx[:en_b_o]}([*+]\d+)\s+(.+?)#{Mx[:en_b_c]}/,
+            '<endnote><symbol>\1</symbol><note>\2</note></endnote> ').
+          gsub(/#{Mx[:en_a_o]}([*+]+)\s+(.+?)#{Mx[:en_a_c]}/,
+            '<endnote><symbol>\1</symbol><note>\2</note></endnote> ')
+      end
+      def xml_head
+        metadata=SiSU_Metadata::Summary.new(@md).xml_dom.metadata
+        @per.head << metadata
+      end
+      def xml_sc(md='')
+        sc=if @md.sc_info
+          <<WOK
+    <source_control>
+      <meta>filename:</meta>
+      <sc class="sourcefile">
+        #{@md.sc_filename}
+      </sc><br />
+      <meta>version number:</meta>
+      <sc class="number">
+        #{@md.sc_number}
+      </sc><br />
+      <meta>version date:</meta>
+      <sc class="date">
+        #{@md.sc_date}
+      </sc><br />
+    </source_control>
+WOK
+        else ''
+        end
+        @per.sc=sc
+      end
+      def xml_element(dob,xml_el='',xml_content='',type='norm')
+        n=n1=n2=n3=0
+        if dob.is==:heading
+          lv=dob.ln
+          n=dob.ln
+          n1=dob.ln
+          n2=dob.ln + 2
+          n3=dob.ln + 3
+        else lv=nil
+        end
+        tag=if defined? dob.name and dob.name=~/\S+/
+          "\n#{Ax[:tab]*n3}<nametag>#{dob.name}</nametag>"
+        else ''
+        end
+        xml_el ||=''
+        @per.body <<<<WOK
+#{Ax[:tab]*n}#{xml_el}
+#{Ax[:tab]*n1}<heading>
+#{Ax[:tab]*n2}<object id="#{dob.ocn}">
+#{Ax[:tab]*n3}<ocn>#{dob.ocn}</ocn>#{tag}
+#{Ax[:tab]*n3}<text class="#{type}">#{dob.obj}</text>
+#{Ax[:tab]*n2}</object>
+#{Ax[:tab]*n1}</heading>#{xml_content}
+WOK
+        if lv==4
+          @copen[1]=true
+          @copen[2]=@copen[3]=@copen[4]=false
+        elsif lv==5
+          @copen[2]=true
+          @copen[3]=@copen[4]=false
+        elsif lv==6
+          @copen[3]=true
+          @copen[4]=false
+        elsif lv==7
+          @copen[4]=true
+        end
+      end
+      def xml_structure(dob,type='norm')
+        n=n1=n2=n3=0
+        if dob.is==:heading
+          lv=dob.ln
+          n=dob.ln - 1
+          n1=dob.ln
+          n2=dob.ln + 1
+          n3=dob.ln + 2
+          dob.ln - 3
+        else lv=nil
+        end
+        case lv
+        when 1..3
+          xml_el="<heading#{lv}>"
+          3.downto(lv) do |x|
+            y=x - 1
+            if @cont[1] \
+            or @cont[2] \
+            or @cont[3]
+              @per.body << "#{Ax[:tab]*5}</content>"
+            end
+            @cont[1]=false if @cont[1]
+            @cont[2]=false if @cont[2]
+            @cont[3]=false if @cont[3]
+            ####### attempt to close contents
+            if @copen[4] # 4~
+              [4,3,2,1].each { |v| @per.body << "#{Ax[:tab]*n}</contents#{v}>" }
+              @copen[1]=@copen[2]=@copen[3]=@copen[4]=false
+            elsif @copen[3] # 3~
+              [3,2,1].each { |v| @per.body << "#{Ax[:tab]*n}</contents#{v}>" }
+              @copen[1]=@copen[2]=@copen[3]=false
+            elsif @copen[2] # 2~
+              [2,1].each { |v| @per.body << "#{Ax[:tab]*n}</contents#{v}>" }
+              @copen[1]=@copen[2]=@copen[3]=false
+            elsif @copen[1] # 1~
+              [1].each { |v| @per.body << "#{Ax[:tab]*n}</contents#{v}>" }
+              @copen[1]=@copen[2]=@copen[3]=false
+            end
+            @per.body << "#{Ax[:tab]*y}</heading#{x}>" if @level[x]
+            @level[x]=false
+          end
+        when 4..7
+          7.downto(lv) do |x|
+            if @level[x]==true
+              @xml_contents_close[x]=''
+            end
+          end
+          cv=lv - 3
+          xml_el="<contents#{cv}>"
+          xml_content="\n#{Ax[:tab]*5}<content>"
+          case lv
+          when 4
+            @per.body << "#{Ax[:tab]*5}</content>" if @cont[1]
+            if @copen[4]==true # 4~
+              [4,3,2,1].each { |v| @per.body << "#{Ax[:tab]*n}</contents#{v}>" }
+            elsif @copen[3]==true # 3~
+              [3,2,1].each { |v| @per.body << "#{Ax[:tab]*n}</contents#{v}>" }
+            elsif @copen[2]==true # 2~
+              [2,1].each { |v| @per.body << "#{Ax[:tab]*n}</contents#{v}>" }
+            elsif @copen[1]==true # 1~
+              [1].each { |v| @per.body << "#{Ax[:tab]*n}</contents#{v}>" }
+            end
+            @cont[1]=true
+          when 5
+            if @cont[3] \
+            or @cont[2] \
+            or @cont[1]
+              @per.body << "#{Ax[:tab]*5}</content>"
+            end
+            if @copen[4]==true  #4~
+              [4,3,2].each { |v| @per.body << "#{Ax[:tab]*n}</contents#{v}>" }
+            elsif @copen[3]==true  #3~
+              [3,2].each { |v| @per.body << "#{Ax[:tab]*n}</contents#{v}>" }
+            elsif @copen[2]==true #2~
+              [2].each { |v| @per.body << "#{Ax[:tab]*n}</contents#{v}>" }
+            end
+            @cont[2]=true
+          when 6
+            if @cont[4] \
+            or @cont[3] \
+            or @cont[2] \
+            or @cont[1]
+              @per.body << "#{Ax[:tab]*5}</content>"
+            end
+            if @copen[4] #4~
+              [4,3].each { |v| @per.body << "#{Ax[:tab]*n}</contents#{v}>" }
+            elsif @copen[3] #3~
+              [3].each { |v| @per.body << "#{Ax[:tab]*n}</contents#{v}>" }
+            end
+            @cont[3]=true
+          when 7
+            if @cont[4] \
+            or @cont[3] \
+            or @cont[2] \
+            or @cont[1]
+              @per.body << "#{Ax[:tab]*5}</content>"
+            end
+            if @copen[4] #4~
+              [4].each { |v| @per.body << "#{Ax[:tab]*n}</contents#{v}>" }
+            end
+            @cont[4]=true
+          end
+        end
+        xml_el ||=''
+        xml_element(dob,xml_el,xml_content,type)
+        if lv
+          @level[lv]=true
+          ((lv+1)..7).each { |x| @level[x]=false }
+        end
+      end
+      def add_to_body(dob,type='norm')
+        if defined? dob.obj # main text, contents, body KEEP
+          if defined? dob.ocn \
+          and dob.ocn
+            @per.body << %{#{Ax[:tab]*6}<object id="#{dob.ocn}">}
+            @per.body << %{#{Ax[:tab]*7}<ocn>#{dob.ocn}</ocn>} if defined? dob.ocn
+          end
+          #@per.body << %{#{Ax[:tab]*7}<text class="#{type}">#{dob.obj}</text>}
+          #@per.body << %{#{Ax[:tab]*7}<text class="#{dob.is}">#{Ax[:tab]*1}}
+          @per.body << %{#{Ax[:tab]*7}<text class="#{type}">#{Ax[:tab]*1}}
+          @per.body << %{#{Ax[:tab]*8}#{dob.obj}#{Ax[:tab]*1}}
+          @per.body << %{#{Ax[:tab]*7}</text>}
+          @per.body << %{#{Ax[:tab]*6}</object>}
+        end
+      end
+      def block_structure(dob)
+        dob=@trans.markup_block(dob) #decide check & FIX
+        dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}(\d+)\s+(.+?)#{Mx[:en_a_c]}/m,
+          '<endnote><number>\1</number><note>\2</note></endnote> ').strip
+        dob
+      end
+      def group_structure(dob)
+        dob=@trans.markup_group(dob) #decide check & FIX
+        dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}(\d+)\s+(.+?)#{Mx[:en_a_c]}/m,
+          '<endnote><number>\1</number><note>\2</note></endnote> ').strip
+        dob
+      end
+      def poem_structure(dob)
+        dob=@trans.markup_group(dob) #decide check & FIX
+        dob.obj=dob.obj.strip
+        dob
+      end
+      def code_structure(dob)
+        dob=@trans.markup_group(dob) #decide check & FIX
+        dob.obj=dob.obj.gsub(/\s\s/,'&#160;&#160;').strip
+        dob
+      end
+      def table_structure(dob) #tables
+        SiSU_XHTML_Shared::TableXHTML.new(dob)
+      end
+      def markup(data)
+        xml_sc(@md)
+        @level,@cont,@copen,@xml_contents_close=[],[],[],[]
+        @rcdc=false
+        type='norm'
+        (0..7).each { |x| @cont[x]=@level[x]=false }
+        (4..7).each { |x| @xml_contents_close[x]='' }
+        xml_head
+        data.each do |dob|
+          @trans.char_enc.utf8(dob) if @sys.locale =~/utf-?8/i #% utf8
+          dob=@trans.markup(dob)
+          if @rcdc==false \
+          and (dob.is ==:meta \
+          and dob.obj =~/Document Information/)
+            @rcdc=true
+          end
+          if dob !~/(^#{Rx[:meta]}|#{Mx[:br_eof]}|#{Mx[:br_endnotes]})/
+            @p_num=SiSU_XML_Format::ParagraphNumber.new(@md,dob.ocn) if defined? dob.ocn
+            if not @rcdc
+              if defined? dob.ocn \
+              and dob.ocn.to_s =~/\d+/
+                format_scroll=SiSU_XML_Format::FormatScroll.new(@md,dob) if dob.is==:para and dob.indent ##FIX
+                x=SiSU_XML_Format::FormatSeg.new(@md,dob)
+                if dob.is==:heading
+                  if dob.ln==0
+                    type="heading_section_#{dob.ln.to_s}"
+                    xml_markup(dob)
+                    xml_structure(dob,type)
+                    dob.obj=x.heading_body0
+                  elsif dob.ln==1
+                    type="heading_section_#{dob.ln.to_s}"
+                    xml_markup(dob)
+                    xml_structure(dob,type)
+                    dob.obj=x.heading_body1
+                  elsif dob.ln==2
+                    type="heading_section_#{dob.ln.to_s}"
+                    xml_markup(dob)
+                    xml_structure(dob,type)
+                    dob.obj=x.heading_body2
+                  elsif dob.ln==3
+                    type="heading_section_#{dob.ln.to_s}"
+                    xml_markup(dob)
+                    xml_structure(dob,type)
+                    dob.obj=x.heading_body3
+                  elsif dob.ln==4
+                    type="heading_content_#{dob.lv}"
+                    xml_markup(dob)
+                    xml_structure(dob,type)
+                    dob.obj=x.heading_body4
+                  elsif dob.ln==5
+                    type="heading_content_#{dob.lv}"
+                    xml_markup(dob)
+                    xml_structure(dob,type)
+                    dob.obj=x.heading_body5
+                  elsif dob.ln==6
+                    type="heading_content_#{dob.lv}"
+                    xml_structure(dob,type)
+                    dob.obj=x.heading_body6
+                  elsif dob.ln==7
+                    type="heading_content_#{dob.lv}"
+                    xml_structure(dob,type)
+                    dob.obj=x.heading_body7
+                  end
+                else
+                  dob.ocn
+                  if dob.is==:verse
+                    type='verse'
+                    poem_structure(dob) #redo
+                  elsif dob.is==:group
+                    type='group'
+                    group_structure(dob) #redo
+                  elsif dob.is==:block
+                    type='block'
+                    block_structure(dob) #redo
+                  elsif dob.is==:code
+                    type='code'
+                    code_structure(dob) #redo
+                  elsif dob.is==:table # tables come as single block #work area 2005w13
+                    type='table'
+                    table_structure(dob)
+                  elsif dob.is==:para \
+                  and dob.indent.to_s =~/[1-9]/ \
+                  and dob.bullet_
+                    type="indent_bullet#{dob.indent.to_s}"
+                    xml_markup(dob)
+                  elsif dob.is==:para \
+                  and dob.indent.to_s =~/[1-9]/ \
+                  and dob.indent == dob.hang
+                    type="indent#{dob.indent.to_s}"
+                    xml_markup(dob)
+                  elsif dob.is==:para \
+                  and dob.hang.to_s =~/[0-9]/ \
+                  and dob.indent != dob.hang
+                    type="hang#{dob.hang.to_s}_indent#{dob.indent.to_s}"
+                    xml_markup(dob)
+                  else
+                    type='norm'
+                    xml_markup(dob)
+                  end
+                  add_to_body(dob,type)
+                end
+              elsif dob.obj =~/(#{Mx[:br_eof]}|#{Mx[:br_endnotes]})/
+              elsif dob.obj =~/(MetaData)/
+                txt_obj={ txt: '<br /><a name="metadata">MetaData</a>' }
+                format_scroll=FormatScroll.new(@md,txt_obj)
+                dob.obj=format_scroll.bold_para
+              elsif dob.obj =~/(Owner Details)/
+                dob.obj=''
+              end
+              if dob.obj =~/<a name="n\d+">/ \
+              and dob.obj =~/^(-\{{2}~\d+|<!e[:_]\d+!>)/ # -endnote
+                dob.obj=''
+              end
+              if dob.obj =~/.*<:#>.*$/
+                dob.obj=if dob.obj =~ /#{Mx[:pa_o]}:i[1-9]#{Mx[:pa_c]}/
+                  txt_obj={ txt: dob.obj }
+                  format_text=FormatTextObject.new(@md,txt_obj)
+                  format_text.scr_inden_ocn_e_no_paranum
+                end
+              end
+            else #
+            end
+            dob.obj=dob.obj.gsub(/#{Mx[:pa_o]}:\S+#{Mx[:pa_c]}/,'') if dob.obj
+          end
+        end
+        @content_flag=true
+        7.downto(4) do |x|
+          y=x - 1; v=x - 3
+          if @level[x]==true #2004w36 bug fix? watch/test previous logic broke on free.for.all @coontent_flag introduced
+            if @content_flag==true
+              @per.body << "#{Ax[:tab]*5}</content>\n#{Ax[:tab]*y}</contents#{v}>"
+              @content_flag=false
+            else
+              @per.body << "\n#{Ax[:tab]*y}</contents#{v}>"
+            end
+          end
+        end
+        3.downto(1) do |x|
+          y=x - 1
+          @per.body << "#{Ax[:tab]*y}</heading#{x}>" if @level[x]==true
+        end
+      end
+      def pre
+        rdf=SiSU_XML_Tags::RDF.new(@md)
+        stylesheet=SiSU_Style::CSS_HeadInfo.new(@md,'xml_dom').stylesheet
+        encoding=if @sys.locale =~/utf-?8/i then '<?xml version="1.0" encoding="UTF-8" standalone="no"?>'
+        else                                     '<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>'
+        end
+        @per.open =<<WOK
+#{encoding}
+#{stylesheet.css_head_xml}
+#{rdf.comment_xml}
+<document>
+WOK
+        @per.head << '<head>'
+        @per.body << '<body>'
+      end
+      def post
+        @per.head << @per.sc
+        @per.head << '</head>'
+        @per.body << '</body>'
+        @per.close << '</document>'
+      end
+      def publish
+        content=[]
+        content << @per.open << @per.head << @per.body # << @per.metadata
+        content << @per.tail << @per.close
+        content=content.flatten.compact
+        Output.new(content,@md).xml
+        @per.head,@per.body,@per.tail=[],[],[] # check whether should be nil
+      end
+    end
+    class Output
+      include SiSU_Param
+      def initialize(data,md)
+        @data,@md=data,md
+        @file=SiSU_Env::FileOp.new(@md)
+      end
+      def xml
+        SiSU_Env::FileOp.new(@md).mkdir
+        filename_xml=@file.write_file.xml_dom
+        @data.each do |str|
+          str=str.gsub(/#{Mx[:pa_o]}:\S+#{Mx[:pa_c]}/,'')
+          filename_xml.puts str unless str.empty?
+        end
+        filename_xml.close
+      end
+    end
+    class Tidy
+      def initialize(md,file)
+        @md,@file=md,file
+        @prog=SiSU_Env::InfoProgram.new
+      end
+      def xml
+        if @prog.tidy !=false
+          if (@md.opt.act[:verbose_plus][:set]==:on \
+          || @md.opt.act[:maintenance][:set]==:on)
+            unless @md.opt.act[:quiet][:set]==:on
+              SiSU_Screen::Ansi.new(
+                @md.opt.act[:color_state][:set],
+                'invert',
+                'Using XML Tidy',
+                'check document structure'
+              ).colorize
+              tell=SiSU_Screen::Ansi.new(
+                @md.opt.act[:color_state][:set],
+                'invert',
+                '',
+                ''
+              )
+              tell.grey_open
+            end
+            tidyfile='/dev/null' #don't want one or screen output, check for alternative flags
+            tidy=SiSU_Env::SystemCall.new(@file,tidyfile)
+            tidy.well_formed?
+            tell.p_off unless @md.opt.act[:quiet][:set]==:on
+          end
+        end
+      end
+    end
+  end
+end
+__END__
+,** Notes: tidy -xml dom.xml >> index.tidy
+#+END_SRC
+
+#+END_SRC
+
+* xml shared
+** xml_shared.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xml_shared.rb"
+# <<sisu_document_header>>
+module SiSU_XML_Munge
+  require_relative 'xml_parts'                          # xml_parts.rb
+  class Trans
+    include SiSU_Parts_XML
+    def initialize(md)
+      @md=md
+      @sys=SiSU_Env::SystemCall.new
+      @dir=SiSU_Env::InfoEnv.new(@md.fns)
+      if @md.sem_tag
+        @ab ||=semantic_tags.default
+      end
+    end
+    def semantic_tags
+      def default
+        {
+          pub:   'publication',
+          conv:  'convention',
+          vol:   'volume',
+          pg:    'page',
+          cty:   'city',
+          org:   'organization',
+          uni:   'university',
+          dept:  'department',
+          fac:   'faculty',
+          inst:  'institute',
+          co:    'company',
+          com:   'company',
+          dt:    'date',
+          y:     'year',
+          m:     'month',
+          d:     'day',
+          ti:    'title',
+          au:    'author',
+          ed:    'editor', #editor?
+          v:     'version', #edition
+          n:     'name',
+          fn:    'firstname',
+          mn:    'middlename',
+          ln:    'lastname',
+          in:    'initials',
+          qt:    'quote',
+          ct:    'cite',
+          ref:   'reference',
+          ab:    'abreviation',
+          def:   'define',
+          desc:  'description',
+          trans: 'translate',
+        }
+      end
+      self
+    end
+    def char_enc #character encode
+      def utf8(dob='')
+        if @sys.locale =~/utf-?8/i # instead ucs for utf8 # String#encode Iñtërnâtiônàlizætiøn
+          str=if defined? dob.obj then dob.obj
+          elsif dob.is_a?(String) then dob
+          end
+          if str
+            #¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûü
+            #¢£¥§©ª«®°±²³µ¶¹º»¼½¾×÷
+            str=str.gsub(/</um,'&#60;').    # '&lt;'     # &#060;
+              gsub(/>/um,'&#62;').    # '&gt;'     # &#062;
+              gsub(/¢/um,'&#162;').   # '&cent;'   # &#162;
+              gsub(/£/um,'&#163;').   # '&pound;'  # &#163;
+              gsub(/¥/um,'&#165;').   # '&yen;'    # &#165;
+              gsub(/§/um,'&#167;').   # '&sect;'   # &#167;
+              gsub(/©/um,'&#169;').   # '&copy;'   # &#169;
+              gsub(/ª/um,'&#170;').   # '&ordf;'   # &#170;
+              gsub(/«/um,'&#171;').   # '&laquo;'  # &#171;
+              gsub(/®/um,'&#174;').   # '&reg;'    # &#174;
+              gsub(/°/um,'&#176;').   # '&deg;'    # &#176;
+              gsub(/±/um,'&#177;').   # '&plusmn;' # &#177;
+              gsub(/²/um,'&#178;').   # '&sup2;'   # &#178;
+              gsub(/³/um,'&#179;').   # '&sup3;'   # &#179;
+              gsub(/µ/um,'&#181;').   # '&micro;'  # &#181;
+              gsub(/¶/um,'&#182;').   # '&para;'   # &#182;
+              gsub(/¹/um,'&#185;').   # '&sup1;'   # &#185;
+              gsub(/º/um,'&#186;').   # '&ordm;'   # &#186;
+              gsub(/»/um,'&#187;').   # '&raquo;'  # &#187;
+              gsub(/¼/um,'&#188;').   # '&frac14;' # &#188;
+              gsub(/½/um,'&#189;').   # '&frac12;' # &#189;
+              gsub(/¾/um,'&#190;').   # '&frac34;' # &#190;
+              gsub(/×/um,'&#215;').   # '&times;'  # &#215;
+              gsub(/÷/um,'&#247;').   # '&divide;' # &#247;
+              gsub(/¿/um,'&#191;').   # '&iquest;' # &#191;
+              gsub(/À/um,'&#192;').   # '&Agrave;' # &#192;
+              gsub(/Á/um,'&#193;').   # '&Aacute;' # &#193;
+              gsub(/Â/um,'&#194;').   # '&Acirc;'  # &#194;
+              gsub(/Ã/um,'&#195;').   # '&Atilde;' # &#195;
+              gsub(/Ä/um,'&#196;').   # '&Auml;'   # &#196;
+              gsub(/Å/um,'&#197;').   # '&Aring;'  # &#197;
+              gsub(/Æ/um,'&#198;').   # '&AElig;'  # &#198;
+              gsub(/Ç/um,'&#199;').   # '&Ccedil;' # &#199;
+              gsub(/È/um,'&#200;').   # '&Egrave;' # &#200;
+              gsub(/É/um,'&#201;').   # '&Eacute;' # &#201;
+              gsub(/Ê/um,'&#202;').   # '&Ecirc;'  # &#202;
+              gsub(/Ë/um,'&#203;').   # '&Euml;'   # &#203;
+              gsub(/Ì/um,'&#204;').   # '&Igrave;' # &#204;
+              gsub(/Í/um,'&#205;').   # '&Iacute;' # &#205;
+              gsub(/Î/um,'&#206;').   # '&Icirc;'  # &#206;
+              gsub(/Ï/um,'&#207;').   # '&Iuml;'   # &#207;
+              gsub(/Ð/um,'&#208;').   # '&ETH;'    # &#208;
+              gsub(/Ñ/um,'&#209;').   # '&Ntilde;' # &#209;
+              gsub(/Ò/um,'&#210;').   # '&Ograve;' # &#210;
+              gsub(/Ó/um,'&#211;').   # '&Oacute;' # &#211;
+              gsub(/Ô/um,'&#212;').   # '&Ocirc;'  # &#212;
+              gsub(/Õ/um,'&#213;').   # '&Otilde;' # &#213;
+              gsub(/Ö/um,'&#214;').   # '&Ouml;'   # &#214;
+              gsub(/Ø/um,'&#216;').   # '&Oslash;' # &#216;
+              gsub(/Ù/um,'&#217;').   # '&Ugrave;' # &#217;
+              gsub(/Ú/um,'&#218;').   # '&Uacute;' # &#218;
+              gsub(/Û/um,'&#219;').   # '&Ucirc;'  # &#219;
+              gsub(/Ü/um,'&#220;').   # '&Uuml;'   # &#220;
+              gsub(/Ý/um,'&#221;').   # '&Yacute;' # &#221;
+              gsub(/Þ/um,'&#222;').   # '&THORN;'  # &#222;
+              gsub(/ß/um,'&#223;').   # '&szlig;'  # &#223;
+              gsub(/à/um,'&#224;').   # '&agrave;' # &#224;
+              gsub(/á/um,'&#225;').   # '&aacute;' # &#225;
+              gsub(/â/um,'&#226;').   # '&acirc;'  # &#226;
+              gsub(/ã/um,'&#227;').   # '&atilde;' # &#227;
+              gsub(/ä/um,'&#228;').   # '&auml;'   # &#228;
+              gsub(/å/um,'&#229;').   # '&aring;'  # &#229;
+              gsub(/æ/um,'&#230;').   # '&aelig;'  # &#230;
+              gsub(/ç/um,'&#231;').   # '&ccedil;' # &#231;
+              gsub(/è/um,'&#232;').   # '&egrave;' # &#232;
+              gsub(/é/um,'&#233;').   # '&acute;'  # &#233;
+              gsub(/ê/um,'&#234;').   # '&circ;'   # &#234;
+              gsub(/ë/um,'&#235;').   # '&euml;'   # &#235;
+              gsub(/ì/um,'&#236;').   # '&igrave;' # &#236;
+              gsub(/í/um,'&#237;').   # '&acute;'  # &#237;
+              gsub(/î/um,'&#238;').   # '&icirc;'  # &#238;
+              gsub(/ï/um,'&#239;').   # '&iuml;'   # &#239;
+              gsub(/ð/um,'&#240;').   # '&eth;'    # &#240;
+              gsub(/ñ/um,'&#241;').   # '&ntilde;' # &#241;
+              gsub(/ò/um,'&#242;').   # '&ograve;' # &#242;
+              gsub(/ó/um,'&#243;').   # '&oacute;' # &#243;
+              gsub(/ô/um,'&#244;').   # '&ocirc;'  # &#244;
+              gsub(/õ/um,'&#245;').   # '&otilde;' # &#245;
+              gsub(/ö/um,'&#246;').   # '&ouml;'   # &#246;
+              gsub(/ø/um,'&#248;').   # '&oslash;' # &#248;
+              gsub(/ù/um,'&#250;').   # '&ugrave;' # &#250;
+              gsub(/ú/um,'&#251;').   # '&uacute;' # &#251;
+              gsub(/û/um,'&#252;').   # '&ucirc;'  # &#252;
+              gsub(/ü/um,'&#253;').   # '&uuml;'   # &#253;
+              gsub(/þ/um,'&#254;').   # '&thorn;'  # &#254;
+              gsub(/ÿ/um,'&#255;').   # '&yuml;'   # &#255;
+              gsub(/‘/um,'&#8216;').  # '&lsquo;'  # &#8216;
+              gsub(/’/um,'&#8217;').  # '&rsquo;'  # &#8217;
+              gsub(/“/um,'&#8220;').  # &ldquo;    # &#8220;
+              gsub(/”/um,'&#8221;').  # &rdquo;    # &#8221;
+              gsub(/–/um,'&#8211;').  # &ndash;    # &#8211;
+              gsub(/—/um,'&#8212;').  # &mdash;    # &#8212;
+              gsub(/∝/um,'&#8733;').  # &prop;     # &#8733;
+              gsub(/∞/um,'&#8734;').  # &infin;    # &#8734;
+              gsub(/™/um,'&#8482;').  # &trade;    # &#8482;
+              gsub(/✠/um,'&#10016;'). # &cross;    # &#10016;
+              gsub(/ /um,' ').       # space identify
+              gsub(/ /um,' ')       # space identify
+          end
+          dob=if defined? dob.obj
+            dob.obj=str
+            dob
+          elsif dob.is_a?(String)
+            str
+          end
+          dob
+        end
+      end
+      def html(dob='')
+        if @sys.locale =~/utf-?8/i # instead ucs for utf8 # String#encode Iñtërnâtiônàlizætiøn
+          dob.obj=dob.obj.gsub(/ /u,' ').           # space identify
+            gsub(/ /u,' ')           # space identify
+        end
+      end
+      self
+    end
+    def tidywords(wordlist)
+      wordlist_new=[]
+      wordlist.each do |x|
+        #imperfect solution will not catch all possible cases
+        x=x.gsub(/&/,'&amp;') unless x =~/&\S+;/
+        x=x.gsub(/&([A-Z])/,'&amp;\1')
+        wordlist_new << x
+      end
+      wordlist_new
+    end
+    def markup(dob='')
+      wordlist=dob.obj.scan(/&[#0-9a-z]+;|\S+|\n/) #\n needed for tables, check though added 2005w17
+      dob.obj=tidywords(wordlist).join(' ').strip
+      unless dob.is==:table
+        dob.obj=dob.obj.gsub(/#{Mx[:br_line]}/u,'<br />').
+          gsub(/#{Mx[:br_paragraph]}/u,'<br />').
+          gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/,'<br />')
+      end
+      dob.obj=dob.obj.gsub(/#{Mx[:mk_o]}:name#\S+?#{Mx[:mk_c]}/,'').
+        gsub(/#{Mx[:mk_o]}#([a-zA-Z]+)#{Mx[:mk_c]}/,'&\1;').
+        gsub(/#{Mx[:mk_o]}(#[0-9]+)#{Mx[:mk_c]}/,'&\1;').
+        gsub(/(^|#{Mx[:gl_c]}|\s+)<\s+/,'\1&lt; ').gsub(/\s+>(\s+|$)/,' &gt;\1').
+        #gsub(/#{Mx[:fa_emphasis_o]}(.+?)#{Mx[:fa_emphasis_c]}/,'<em>\1</em>'). #reinstate
+        gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/m,'<b>\1</b>').
+        gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/m,'<i>\1</i>').
+        gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'<u>\1</u>').
+        gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'<sup>\1</sup>').
+        gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'<sub>\1</sub>').
+        gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'<ins>\1</ins>').
+        gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'<cite>\1</cite>').
+        gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'<del>\1</del>').
+        gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,'<tt>\1</tt>').
+        gsub(/<:pb>\s*/,''). #Fix
+        gsub(/<+[-~]#>+/,'')
+      if dob.is !=:code
+        #embeds a red-bullet image -->
+        dob.obj=dob.obj.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'<b>\1</b>').
+          gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'<i>\1</i>').
+          gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'<u>\1</u>').
+          gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'<del>\1</del>')
+        dob.obj=dob.obj.gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/,'<br />') unless dob.is==:table
+        dob.obj=dob.obj.gsub(/#{Mx[:br_page]}\s*/,'').
+          gsub(/#{Mx[:br_page_new]}\s*/,'').
+          gsub(/#{Mx[:br_page_line]}\s*/,'').
+          gsub(/#{Mx[:pa_non_object_no_heading]}|#{Mx[:pa_non_object_dummy_heading]}/,'').
+          gsub(/<[-~]#>/,'').
+          gsub(/href="#{Xx[:segment]}/m,'href="').
+          gsub(/#{Mx[:lnk_o]}([^#{Mx[:lnk_o]}#{Mx[:lnk_c]}#{Mx[:rel_o]}#{Mx[:rel_c]}]+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}(\.\.\/\S+?)#{Mx[:rel_c]}/,
+            '<link xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:href="\2">\1</link>').
+          gsub(/#{Mx[:lnk_o]}([^#{Mx[:lnk_o]}#{Mx[:lnk_c]}#{Mx[:rel_o]}#{Mx[:rel_c]}]+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}:(\S+?)#{Mx[:rel_c]}/,
+            '<link xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:href="../\2">\1</link>').
+          gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}(\S+?)#{Mx[:rel_c]}/,
+            '<link xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:href="#\2">\1</link>').
+          gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}[ ]*(\S+?\.(?:jpg|png|gif))[ ]+(\d+)x(\d+)(\s+[^}]+)?#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,
+            %{<image xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:actuate="onLoad" xl:show="embed" xl:href="#{@md.file.output_path.xml.rel_image}/\\1" width="\\2" height="\\3" />[\\1] \\4}).
+          gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}[ ]*(\S+?\.(?:jpg|png|gif))([ ]+[^}]+)?#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,
+            %{<image xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:actuate="onLoad" xl:show="embed" xl:href="#{@md.file.output_path.xml.rel_image}/\\1"/>\\1}).
+          gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}[ ]*(\S+?\.(?:jpg|png|gif))[ ]+(\d+)x(\d+)(\s+[^}]+)?#{Mx[:lnk_c]}image/,
+            %{<image xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:actuate="onLoad" xl:show="embed" xl:href="#{@md.file.output_path.xml.rel_image}/\\1" width="\\2" height="\\3" />[\\1] \\4}).
+          gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}[ ]*(\S+?\.(?:jpg|png|gif))([ ]+[^}]+)?#{Mx[:lnk_c]}image/,
+            %{<image xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:actuate="onLoad" xl:show="embed" xl:href="#{@md.file.output_path.xml.rel_image}/\\1"/>\\1}).
+          gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,
+            '<link xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:href="\2">\1</link>'). #watch, compare html_tune
+          gsub(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,
+            %{#{the_url_decoration.xml_open}<link xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:href="\\1">\\1</link>#{the_url_decoration.xml_close}}).
+          gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,
+            '<link xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:href="\1">\1</link>') #escaped urls not linked, deal with later
+      else
+        dob.obj=dob.obj.gsub(/</m,'&lt;').gsub(/>/m,'&gt;')
+      end
+      if dob.of==:block
+        dob.obj=dob.obj.gsub(/#{Mx[:gl_bullet]}/,'● ')
+      end
+      dob.obj=dob.obj.gsub(/#{Mx[:url_o]}([a-zA-Z0-9._-]+\@\S+?\.[a-zA-Z0-9._-]+)#{Mx[:url_c]}/,
+          %{#{the_url_decoration.xml_open}\\1#{the_url_decoration.xml_close}}).
+        gsub(/#{Dx[:url_o]}/,"#{Dx[:url_o_xml]}").
+        gsub(/#{Dx[:url_c]}/,"#{Dx[:url_c_xml]}").
+        gsub(/&nbsp;|#{Mx[:nbsp]}/m,'&#160;').
+        gsub(/;&([^#]|(?:[^gl][^t]|[^a][^m][^p]|[^n][^b][^s][^p])[^;])/,';&amp;\1') # pattern not to match
+      dob
+    end
+    def markup_light(dob='')
+      dob.obj=dob.obj.gsub(/\/\{(.+?)\}\//,'<i>\1</i>').
+        gsub(/[*!]\{(.+?)\}[*!]/,'<b>\1</b>').
+        gsub(/_\{(.+?)\}_/,'<u>\1</u>').
+        gsub(/-\{(.+?)\}-/,'<del>\1</del>').
+        gsub(/<br(\s*\/)?>/,'<br />').
+        gsub(/<:pb>\s*/,'').
+        gsub(/<[-~]#>/,'').
+        gsub(/(^|#{Mx[:gl_c]}|\s)&\s+/,'\1&amp; '). #sort
+        gsub(/&([^;]{1,5})/,'&amp;\1'). #sort, rough estimate, revisit #WATCH found in node not sax
+        gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}(\S+?\.(?:png|jpg|gif))[ ]+.+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|image)/,
+          "<image.path>#{@md.file.output_path.xml.rel_image}\/\\1</image.path>").
+        gsub(/&nbsp;|#{Mx[:nbsp]}/,'&#160;').
+        gsub(/;&([^#]|(?:[^gl][^t]|[^a][^m][^p]|[^n][^b][^s][^p])[^;])/,';&amp;\1') # pattern not to match
+      wordlist=dob.obj.scan(/&[#0-9a-z]+;|\S+|\n/) #\n needed for tables, check though added 2005w17
+      dob.obj=tidywords(wordlist).join(' ').strip
+      dob
+    end
+    def clean(str)
+      str=str.gsub(/#{Mx[:gl_o]}(#[0-9]{3})#{Mx[:gl_c]}/u,'&\1;').
+        gsub(/#{Mx[:gl_o]}#([a-z]{2,4})#{Mx[:gl_c]}/u,'&\1;')
+    end
+    def markup_fictionbook(str='',is='')
+      str=str.gsub(/#{Mx[:en_a_o]}([\d+*]+).+?#{Mx[:en_a_c]}/m,'<a xl:href="#footnote\1" type="note">[\1]</a>').
+        gsub(/&/,'&amp;'). #sort
+        gsub(/#{Mx[:mk_o]}#([a-zA-Z]+)#{Mx[:mk_c]}/,'&\1;').
+        gsub(/(^|#{Mx[:gl_c]}|\s)&\s+/,'\1&amp; '). #sort
+        gsub(/#{Mx[:mk_o]}(#[0-9]+)#{Mx[:mk_c]}/,'&\1;')
+      str=str.gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/,'<br />') unless is==:table
+      str=str.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'<b>\1</b>').
+        gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'<i>\1</i>').
+        gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'<u>\1</u>').
+        gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'<sup>\1</sup>').
+        gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'<sub>\1</sub>').
+        gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'<ins>\1</ins>').
+        gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'<cite>\1</cite>').
+        gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'<del>\1</del>').
+        gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,'<tt>\1</tt>'). # tt, kbd
+        gsub(/#{Mx[:lnk_o]}\s*(\S+?\.(?:png|jpg|gif)).+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)/m,'<image xl:href="#\1" />').
+        gsub(/#{Mx[:url_o]}(.+?)#{Mx[:url_c]}/,"#{Dx[:url_o]}\\1#{Dx[:url_c]}").
+        gsub(/#{Mx[:mk_o]}:name#(\S+?)#{Mx[:mk_c]}/,'<a name="\1"></a>').
+        gsub(/#{Mx[:gl_bullet]}/m,'● '). #&nbsp; not available
+        gsub(/#{Mx[:nbsp]}/,' '). #&nbsp; not available
+        gsub(/<(p|br)>/,'<\1 />')
+      clean(str)
+    end
+    def markup_docbook(dob='')                                  # work on, initially a copy of fictionbook!
+      if dob.is !=:code
+        dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}(\d+)\s*(.+?)#{Mx[:en_a_c]}/m,'<footnote><para><!-- fn\1 -->\2</para></footnote>').
+          gsub(/\\\\/,'</para><para>').
+          gsub(/&/,'&amp;'). #sort
+          gsub(/#{Mx[:mk_o]}#([a-zA-Z]+)#{Mx[:mk_c]}/,'&\1;').
+          gsub(/(^|#{Mx[:gl_c]}|\s)&\s+/,'\1&amp; '). #sort
+          gsub(/#{Mx[:mk_o]}(#[0-9]+)#{Mx[:mk_c]}/,'&\1;')
+        dob.obj=dob.obj.gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/,'<br />') unless dob.is==:table
+        dob.obj=dob.obj.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'<b>\1</b>').
+          gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'<i>\1</i>').
+          gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'<u>\1</u>').
+          gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'<sup>\1</sup>').
+          gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'<sub>\1</sub>').
+          gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'<ins>\1</ins>').
+          gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'<cite>\1</cite>').
+          gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'<del>\1</del>').
+          gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,'<tt>\1</tt>'). # tt, kbd
+          gsub(/#{Mx[:lnk_o]}\s*(\S+?)\.(png|jpg|gif).+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)/m,
+            %{#{Xx[:split]}:spaces0:<figure id="fig-\\1">\n:spaces1:<title></title>\n:spaces1:<graphic fileref="../../_sisu/image/\\1.\\2" align="center" width="50%"></graphic>\n:spaces0:</figure>#{Xx[:split]}}). # common image location, else use ./images
+          gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(.+?)#{Mx[:url_c]}/,
+            '<ulink url="\2">\1</ulink>').
+          gsub(/#{Mx[:url_o]}(.+?)#{Mx[:url_c]}/,
+            '<ulink url="\1">\1</ulink>').
+          gsub(/#{Mx[:mk_o]}:name#(\S+?)#{Mx[:mk_c]}/,'<a name="\1"></a>').
+          gsub(/#{Mx[:gl_bullet]}/m,'● '). #&nbsp; not available
+          gsub(/#{Mx[:nbsp]}/,' '). #&nbsp; not available
+          gsub(/<(p|br)>/,'<\1 />')
+        dob.obj=clean(dob.obj)
+      elsif dob.is == :code
+        dob.obj=dob.obj.gsub(/&/m,'&amp;'). #sort
+          gsub(/</,'&lt;').gsub(/>/,'&gt;')
+      else # p dob.is ??
+      end
+      dob
+    end
+    def markup_group(dob='')
+      dob.obj=dob.obj.gsub(/</,'&lt;').gsub(/>/,'&gt;').
+        gsub(/&lt;:?br(?:\s+\/)?&gt;/,'<br />').
+        gsub(/&lt;(link xmlns:xl=".+?")&gt;/,'<\1>').
+        gsub(/&lt;(\/link)&gt;/,'<\1>').
+        gsub(/&lt;(\/?en)&gt;/,'<\1>')
+      dob
+    end
+    def markup_block(dob='')
+      dob.obj=dob.obj.gsub(/</,'&lt;').gsub(/>/,'&gt;').
+        gsub(/&lt;:?br(?:\s+\/)?&gt;/,'<br />').
+        gsub(/&lt;(link xmlns:xl=".+?")&gt;/,'<\1>').
+        gsub(/&lt;(\/link)&gt;/,'<\1>').
+        gsub(/&lt;(\/?en)&gt;/,'<\1>')
+      dob
+    end
+    def xml_sem_block_paired(matched) # colon depth: many, recurs
+      matched=matched.gsub(/\b(au):\{(.+?)\}:\1\b/m,  %{<sem:#{@ab[:au]} depth="many">\\2</sem:#{@ab[:au]}>}).
+        gsub(/\b(vol):\{(.+?)\}:\1\b/m, %{<sem:#{@ab[:vol]} depth="many">\\2</sem:#{@ab[:vol]}>}).
+        gsub(/\b(pub):\{(.+?)\}:\1\b/m, %{<sem:#{@ab[:pub]} depth="many">\\2</sem:#{@ab[:pub]}>}).
+        gsub(/\b(ref):\{(.+?)\}:\1\b/m, %{<sem:#{@ab[:ref]} depth="many">\\2</sem:#{@ab[:ref]}>}).
+        gsub(/\b(desc):\{(.+?)\}:\1\b/m,%{<sem:#{@ab[:desc]} depth="many">\\2</sem:#{@ab[:desc]}>}).
+        gsub(/\b(conv):\{(.+?)\}:\1\b/m,%{<sem:#{@ab[:conv]} depth="many">\\2</sem:#{@ab[:conv]}>}).
+        gsub(/\b(ct):\{(.+?)\}:\1\b/m,  %{<sem:#{@ab[:ct]} depth="many">\\2</sem:#{@ab[:ct]}>}).
+        gsub(/\b(cty):\{(.+?)\}:\1\b/m, %{<sem:#{@ab[:cty]} depth="many">\\2</sem:#{@ab[:cty]}>}).
+        gsub(/\b(org):\{(.+?)\}:\1\b/m, %{<sem:#{@ab[:org]} depth="many">\\2</sem:#{@ab[:org]}>}).
+        gsub(/\b(dt):\{(.+?)\}:\1\b/m,  %{<sem:#{@ab[:dt]} depth="many">\\2</sem:#{@ab[:dt]}>}).
+        gsub(/\b(n):\{(.+?)\}:\1\b/m,   %{<sem:#{@ab[:n]} depth="many">\\2</sem:#{@ab[:n]}>}).
+        gsub(/([a-z]+(?:[_:.][a-z]+)*)(?::\{(.+?)\}:\1)/m,'<sem:\1 depth="many">\2</sem:\1>')
+    end
+    def xml_semantic_tags(dob)
+      if @md.sem_tag
+        dob.obj.gsub!(/([a-z]+(?:[_:.][a-z]+)*)(?::\{(.+?)\}:\1)/m) {|c| xml_sem_block_paired(c) }
+        dob.obj.gsub!(/([a-z]+(?:[_:.][a-z]+)*)(?::\{(.+?)\}:\1)/m) {|c| xml_sem_block_paired(c) }
+        dob.obj.gsub!(/([a-z]+(?:[_:.][a-z]+)*)(?::\{(.+?)\}:\1)/m) {|c| xml_sem_block_paired(c) }
+        dob.obj=dob.obj.gsub(/:\{(.+?)\}:au\b/m,             %{<sem:#{@ab[:au]} depth="one">\\1</sem:#{@ab[:au]}>}).
+          gsub(/:\{(.+?)\}:n\b/m,              %{<sem:#{@ab[:n]} depth="one">\\1</sem:#{@ab[:n]}>}).
+          gsub(/:\{(.+?)\}:ti\b/m,             %{<sem:#{@ab[:ti]} depth="one">\\1</sem:#{@ab[:ti]}>}).
+          gsub(/:\{(.+?)\}:ref\b/m,            %{<sem:#{@ab[:ref]} depth="one">\\1</sem:#{@ab[:ref]}>}).
+          gsub(/:\{(.+?)\}:desc\b/m,           %{<sem:#{@ab[:desc]} depth="one">\\1</sem:#{@ab[:desc]}>}).
+          gsub(/:\{(.+?)\}:cty\b/m,            %{<sem:#{@ab[:cty]} depth="one">\\1</sem:#{@ab[:cty]}>}).
+          gsub(/:\{(.+?)\}:org\b/m,            %{<sem:#{@ab[:org]} depth="one">\\1</sem:#{@ab[:org]}>}).
+          gsub(/:\{(.+?)\}:([a-z]+(?:[_:.][a-z]+)*)/m,'<sem:\2 depth="one">\1</sem:\2>').
+          gsub(/;\{([^}]+(?![;]))\};ti\b/m,    %{<sem:#{@ab[:ti]} depth="zero">\\1</sem:#{@ab[:ti]}>}).
+          gsub(/;\{([^}]+(?![;]))\};qt\b/m,    %{<sem:#{@ab[:qt]} depth="zero">\\1</sem:#{@ab[:qt]}>}).
+          gsub(/;\{([^}]+(?![;]))\};ref\b/m,   %{<sem:#{@ab[:ref]} depth="zero">\\1</sem:#{@ab[:ref]}>}).
+          gsub(/;\{([^}]+(?![;]))\};ed\b/m,    %{<sem:#{@ab[:ed]} depth="zero">\\1</sem:#{@ab[:ed]}>}).
+          gsub(/;\{([^}]+(?![;]))\};v\b/m,     %{<sem:#{@ab[:v]} depth="zero">\\1</sem:#{@ab[:v]}>}).
+          gsub(/;\{([^}]+(?![;]))\};desc\b/m,  %{<sem:#{@ab[:desc]} depth="zero">\\1</sem:#{@ab[:desc]}>}).
+          gsub(/;\{([^}]+(?![;]))\};def\b/m,   %{<sem:#{@ab[:def]} depth="zero">\\1</sem:#{@ab[:def]}>}).
+          gsub(/;\{([^}]+(?![;]))\};trans\b/m, %{<sem:#{@ab[:trans]} depth="zero">\\1</sem:#{@ab[:trans]}>}).
+          gsub(/;\{([^}]+(?![;]))\};y\b/m,     %{<sem:#{@ab[:y]} depth="zero">\\1</sem:#{@ab[:y]}>}).
+          gsub(/;\{([^}]+(?![;]))\};ab\b/m,    %{<sem:#{@ab[:ab]} depth="zero">\\1</sem:#{@ab[:ab]}>}).
+          gsub(/;\{([^}]+(?![;]))\};pg\b/m,    %{<sem:#{@ab[:pg]} depth="zero">\\1</sem:#{@ab[:pg]}>}).
+          gsub(/;\{([^}]+(?![;]))\};fn?\b/m,   %{<sem:#{@ab[:fn]} depth="zero">\\1</sem:#{@ab[:fn]}>}).
+          gsub(/;\{([^}]+(?![;]))\};mn?\b/m,   %{<sem:#{@ab[:mn]} depth="zero">\\1</sem:#{@ab[:mn]}>}).
+          gsub(/;\{([^}]+(?![;]))\};ln?\b/m,   %{<sem:#{@ab[:ln]} depth="zero">\\1</sem:#{@ab[:ln]}>}).
+          gsub(/;\{([^}]+(?![;]))\};in\b/m,    %{<sem:#{@ab[:in]} depth="zero">\\1</sem:#{@ab[:in]}>}).
+          gsub(/;\{([^}]+(?![;]))\};uni\b/m,   %{<sem:#{@ab[:uni]} depth="zero">\\1</sem:#{@ab[:uni]}>}).
+          gsub(/;\{([^}]+(?![;]))\};fac\b/m,   %{<sem:#{@ab[:fac]} depth="zero">\\1</sem:#{@ab[:fac]}>}).
+          gsub(/;\{([^}]+(?![;]))\};inst\b/m,  %{<sem:#{@ab[:inst]} depth="zero">\\1</sem:#{@ab[:inst]}>}).
+          gsub(/;\{([^}]+(?![;]))\};dept\b/m,  %{<sem:#{@ab[:dpt]} depth="zero">\\1</sem:#{@ab[:dept]}>}).
+          gsub(/;\{([^}]+(?![;]))\};org\b/m,   %{<sem:#{@ab[:org]} depth="zero">\\1</sem:#{@ab[:org]}>}).
+          gsub(/;\{([^}]+(?![;]))\};com?\b/m,  %{<sem:#{@ab[:com]} depth="zero">\\1</sem:#{@ab[:com]}>}).
+          gsub(/;\{([^}]+(?![;]))\};cty\b/m,   %{<sem:#{@ab[:cty]} depth="zero">\\1</sem:#{@ab[:cty]}>}).
+          gsub(/;\{([^}]+(?![;]))\};([a-z]+(?:[_:.][a-z]+)*)/m,'<sem:\2 depth="zero">\1</sem:\2>')
+      end
+      dob
+    end
+  end
+end
+module SiSU_XML_Tags #Format
+  require_relative 'dp'                                 # dp.rb
+    include SiSU_Param
+  class RDF
+    include SiSU_Parts_XML
+    def initialize(md='',seg_name=[],tracker=0)
+      @full_title=@subtitle=@author=@subject=@description=@publisher=@contributor=@date=@date_created=@date_issued=@date_available=@date_valid=@date_modified=@type=@format=@identifier=@source=@language=@relation=@coverage=@rights=@copyright=@owner=@keywords=''
+      @md=md
+      @rdfurl=%{  rdf:about="http://www.jus.uio.no/lm/toc"\n}
+      if defined? @md.title.full \
+      and @md.title.full                          # DublinCore 1 - title
+        @rdf_title=%{    dc.title="#{seg_name}#{@md.title.full}"\n}
+        @full_title=%{  <meta name="dc.title" content="#{@md.title.full}" />\n}
+      end
+      if defined? @md.creator.author \
+      and @md.creator.author=~/\S+/                                            # DublinCore 2 - creator/author (author)
+        @rdf_author=%{    dc.author="#{@md.creator.author}"\n}
+        content=meta_content_clean(@md.creator.author)
+        @author=%{  <meta name="dc.author" content="#{content}" />\n}
+      end
+      if defined? @md.publisher \
+      and @md.publisher                                                        # DublinCore 5 - publisher (current copy published by)
+        @rdf_publisher=%{    dc.publisher="#{@md.publisher}"\n}
+        content=meta_content_clean(@md.publisher)
+        @publisher=%{  <meta name="dc.publisher" content="#{content}" />\n}
+      end
+      if defined? @md.creator.contributor \
+      and @md.creator.contributor=~/\S+/                                      # DublinCore 6 - contributor
+        @rdf_contributor=%{    dc.contributor="#{@md.creator.contributor}"\n}
+        content=meta_content_clean(@md.creator.contributor)
+        @contributor=%{  <meta name="dc.contributor" content="#{content}" />\n}
+      end
+      if defined? @md.date.published \
+      and @md.date.published=~/\S+/                                           # DublinCore 7 - date year-mm-dd
+        @rdf_date=%{    dc.date="#{@md.date.published}"\n}
+        @date=%{  <meta name="dc.date" content="#{@md.date.published}" #{@md.date_scheme} />\n} # fix @md.date_scheme
+      end
+      if defined? @md.date.created \
+      and @md.date.created=~/\S+/                                             # DublinCore 7 - date.created year-mm-dd
+        @rdf_date_created=%{    dc.date.created="#{@md.date.created}"\n}
+        @date_created=%{  <meta name="dc.date.created" content="#{@md.date.created}" #{@md.date_scheme} />\n}
+      end
+      if defined? @md.date.issued \
+      and @md.date.issued=~/\S+/                                              # DublinCore 7 - date.issued year-mm-dd
+        @rdf_date_issued=%{    dc.date.issued="#{@md.date.issued}"\n}
+        @date_issued=%{  <meta name="dc.date.issued" content="#{@md.date.issued}" #{@md.date_scheme} />\n}
+      end
+      if defined? @md.date.available \
+      and @md.date.available=~/\S+/                                           # DublinCore 7 - date.available year-mm-dd
+        @rdf_date_available=%{    dc.date.available="#{@md.date.available}"\n}
+        @date_available=%{  <meta name="dc.date.available" content="#{@md.date.available}" #{@md.date_scheme} />\n}
+      end
+      if defined? @md.date.valid \
+      and @md.date.valid=~/\S+/                                               # DublinCore 7 - date.valid year-mm-dd
+        @rdf_date_valid=%{    dc.date.valid="#{@md.date.valid}"\n}
+        @date_valid=%{  <meta name="dc.date.valid" content="#{@md.date.valid}" #{@md.date_scheme} />\n}
+      end
+      if defined? @md.date.modified \
+      and @md.date.modified=~/\S+/                                            # DublinCore 7 - date.modified year-mm-dd
+        @rdf_date_modified=%{    dc.date.modified="#{@md.date.modified}"\n}
+        @date_modified=%{  <meta name="dc.date.modified" content="#{@md.date.modified}" #{@md.date_scheme} />\n}
+      end
+      if defined? @md.rights.all \
+      and @md.rights.all                                                      # DublinCore 15 - rights
+        @rdf_rights=%{    dc.rights="#{@md.rights.all}"\n}
+        content=meta_content_clean(@md.rights.all)
+        @rights=%{  <meta name="dc.rights" content="#{content}" />\n}
+      end
+      if defined? @md.classify.subject \
+      and @md.classify.subject=~/\S+/                                          # DublinCore 3 - subject (us library of congress, eric or udc, or schema???)
+        @rdf_subject=%{    dc.subject="#{@md.classify.subject}"\n}
+        content=meta_content_clean(@md.classify.subject)
+        @subject=%{  <meta name="dc.subject" content="#{content}" />\n}
+      end
+      if defined? @md.notes.description \
+      and @md.notes.description=~/\S+/                                         # DublinCore 4 - description
+        @rdf_description=%{    dc.description="#{@md.notes.description}"\n}
+        content=meta_content_clean(@md.notes.description)
+        @description=%{  <meta name="dc.description" content="#{content}" />\n}
+      end
+      if defined? @md.notes.coverage \
+      and @md.notes.coverage=~/\S+/                                            # DublinCore 14 - coverage
+        @rdf_coverage=%{    dc.coverage="#{@md.notes.coverage}"\n}
+        content=meta_content_clean(@md.notes.coverage)
+        @coverage=%{  <meta name="dc.coverage" content="#{content}" />\n}
+      end
+      if defined? @md.notes.relation \
+      and @md.notes.relation=~/\S+/                                            # DublinCore 13 - relation
+        @rdf_relation=%{    dc.relation="#{@md.notes.relation}"\n}
+        content=meta_content_clean(@md.notes.relation)
+        @relation=%{  <meta name="dc.relation" content="#{content}" />\n}
+      end
+      if defined? @md.notes.type \
+      and @md.notes.type                                                       # DublinCore 8 - type (genre eg. report, convention etc)
+        @rdf_type=%{    dc.type="#{@md.notes.type}"\n}
+        content=meta_content_clean(@md.notes.type)
+        @type=%{  <meta name="dc.type" content="#{content}" />\n}
+      end
+      if defined? @md.notes.format \
+      and @md.notes.format=~/\S+/                                              # DublinCore 9 - format (use your mime type)
+        @rdf_format=%{    dc.format="#{@md.notes.format}"\n}
+        content=meta_content_clean(@md.notes.format)
+        @format=%{  <meta name="dc.format" content="#{content}" />\n}
+      end
+      #if defined? @md.identifier.sisupod \
+      #and @md.identifier.sisupod=~/\S+/                                       # DublinCore 10 - identifier (your identifier, could use urn which is free)
+      #  @rdf_identifier=%{    dc.identifier="#{@md.identifier.sisupod}"\n}
+      #  content=meta_content_clean(@md.identifier.sisupod)
+      #  @identifier=%{  <meta name="dc.identifier" content="#{content}" />\n}
+      #end
+      if defined? @md.original.source \
+      and @md.original.source=~/\S+/                                           # DublinCore 11 - source (document source)
+        @rdf_source=%{    dc.source="#{@md.original.source}"\n}
+        content=meta_content_clean(@md.original.source)
+        @source=%{  <meta name="dc.source" content="#{content}" />\n}
+      end
+      if defined? @md.title.language \
+      and @md.title.language=~/\S+/                                            # DublinCore 12 - language (English)
+        @rdf_language=%{    dc.language="#{@md.title.language}"\n}
+        @language=%{  <meta name="dc.language" content="#{@md.title.language}" />\n}
+      end
+      if defined? @md.original.language \
+      and @md.original.language=~/\S+/
+        @rdf_language_original=%{    dc.language="#{@md.original.language}"\n}
+        @language_original=%{  <meta name="dc.language" content="#{@md.original.language}" />\n}
+      end
+      content=meta_content_clean(@md.keywords)
+      @keywords=%{  <meta name="keywords" content="#{content}" />\n} if @md.keywords
+    end
+    def meta_content_clean(content='')
+      content=if not content.nil?
+        content=content.tr('"',"'").
+           gsub(/&/,'&amp;')
+      else content
+      end
+    end
+    def rdfseg #segHead
+      rdftoc
+    end
+    def comment_xml(extra='')
+      generator="Generated by: #{@md.project_details.project} #{@md.project_details.version} of #{@md.project_details.date_stamp} (#{@md.project_details.date})"  if @md.project_details.version
+      lastdone="Last Generated on: #{Time.now}"
+      rubyv="Ruby version: #{@md.ruby_version}"
+      sc=if @md.sc_info
+        "Source file: #{@md.sc_filename} version: #{@md.sc_number} of: #{@md.sc_date}"
+      else ''
+      end
+      if extra.empty?
+<<WOK
+<!-- Document processing information:
+     ,* #{generator}
+     ,* #{rubyv}
+     ,* #{sc}
+     ,* #{lastdone}
+     ,* SiSU http://www.jus.uio.no/sisu
+-->
+WOK
+     else
+<<WOK
+<!-- Document processing information:
+     ,* #{extra}
+     ,* #{generator}
+     ,* #{rubyv}
+     ,* #{sc}
+     ,* #{lastdone}
+     ,* SiSU http://www.jus.uio.no/sisu
+-->
+WOK
+      end
+    end
+    def comment_xml_sax
+      desc='SiSU XML, SAX type representation'
+      comment_xml(desc)
+    end
+    def comment_xml_node
+      desc='SiSU XML, Node type representation'
+      comment_xml(desc)
+    end
+    def comment_xml_dom
+      desc='SiSU XML, DOM type representation'
+      comment_xml(desc)
+    end
+    def metatag_html #values strung together, because some empty, and resulting output (line breaks) is much better
+<<WOK
+#{@full_title}#{@subtitle}#{@author}#{@subject}#{@description}#{@publisher}#{@contributor}#{@date}#{@date_created}#{@date_issued}#{@date_available}#{@date_valid}#{@date_modified}#{@type}#{@format}#{@identifier}#{@source}#{@language}#{@relation}#{@coverage}#{@rights}#{@copyright}#{@owner}
+#{SiSU_Proj_XML::Bits.new.txt_generator}
+#{the_png.ico}
+WOK
+    end
+  end
+end
+module SiSU_Tables
+  require_relative 'xml_tables'                         # xml_tables.rb
+end
+__END__
+#+END_SRC
+
+** xml_tables.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xml_tables.rb"
+# <<sisu_document_header>>
+module SiSU_Tables
+  class Table #_xml
+    @@tablehead=0
+    @@tablefoot=[] #watch #bug??? #check was @@tablefoot
+    def initialize(one,ocn='')
+      @one,@parablock,@ocn=one,one,ocn
+    end
+    def table_split                                                            #% used but, no longer operational, revisit
+      @new_content=[]
+      @one.split(/\n/).each do |parablock|
+        table=TableXML.new("#{parablock}\n")
+        @new_content << table.table
+      end
+      @new_content.join
+    end
+  end
+  class TableXML <Table
+    @@tablehead=0
+    @@tablefoot=[]
+    def initialize(one,ocn='')
+      @one,@parablock,@ocn=one,one,ocn
+    end
+    def table
+      m=@parablock[/<!f(.+?)!>/,1]
+      @@tablefoot << m if m
+      @parablock=@parablock.gsub(/<!f.+?!>/,'')
+      @@tablehead=1 if @parablock =~/#{Mx[:gr_o]}Th#{Mx[:tc_p]}/u
+      if @parablock =~/#{Mx[:gr_o]}Th?#{Mx[:tc_p]}/u
+        @parablock=@parablock.gsub(/#{Mx[:gr_o]}Th?#{Mx[:tc_p]}.+?#{Mx[:tc_p]}~(\d+);\w\d+;\w\d+#{Mx[:gr_c]}/u,
+          %{\n<ocn>#{@ocn}</ocn><table summary="normal text css" width="100%" border="0" bgcolor="white" cellpadding="2" align="center">})
+      end
+      if @parablock =~/#{Mx[:gr_o]}TZ#{Mx[:gr_c]}/
+        tablefoot=[]
+        @@tablefoot.each {|x| tablefoot << ''}
+        @@tablefoot=[]
+      end
+      if @@tablehead==1
+        if @parablock =~/#{Mx[:tc_p]}#{Mx[:tc_p]}/u
+          @parablock=@parablock.gsub(/#{Mx[:tc_o]}#{Mx[:tc_p]}#{Mx[:tc_p]}(\d+?)#{Mx[:tc_p]}/u,
+            %{<tr>
+  <td width="\\1%" valign="top"><b>}).
+            gsub(/#{Mx[:tc_p]}#{Mx[:tc_p]}(\d+?)#{Mx[:tc_p]}/u,
+              %{</b></td><td width="\\1%" valign="top"><b>}).
+            gsub(/#{Mx[:tc_c]}/,"</b>\n</td>\n</tr>")
+          @@tablehead=0
+        end
+        @parablock
+      else
+        @parablock=@parablock.gsub(/#{Mx[:tc_o]}#{Mx[:tc_p]}#{Mx[:tc_p]}(\d+?)#{Mx[:tc_p]}/u,
+          %{<tr>
+  <td width="\\1%" valign="top">}).
+          gsub(/#{Mx[:tc_p]}#{Mx[:tc_p]}(\d+?)#{Mx[:tc_p]}/u,
+            %{
+  </td>
+  <td width="\\1%" valign="top">}).
+          gsub(/#{Mx[:tc_c]}/,"\n</td>\n</tr>\n")
+      end
+      @parablock
+    end
+  end
+  class TableXMLdocbook
+    @@tablehead=0
+    @@tablefoot=[] #watch
+    def initialize(table,id='')
+      @table_obj,@id=table,id
+    end
+    def spaces
+      Ax[:spaces]
+    end
+    def table
+      table_obj=@table_obj
+      if table_obj.obj !~/^<table\s/m
+        table_obj=table_rows_and_columns_array(table_obj)
+      else p __LINE__; p caller
+      end
+      table_obj
+    end
+    def table_rows_and_columns_array(table_obj) # provides basic (x)html table
+      table_rows,nr=[],0
+      table_obj.obj.split(Mx[:tc_c]).each do |table_row|
+        table_row_with_columns=table_row.split(Mx[:tc_p])
+        trc,nc=[],0
+        table_row_with_columns.each do |c|
+          c=c.gsub(/^(?:~|&nbsp;)$/,''). # tilde / empty cell
+            gsub(/&nbsp;/,' ').
+            gsub(/<:br>/,'<br />')
+          trc <<= if table_obj.head_ and nr==0
+            %{#{spaces*6}<entry>#{c}</entry>\n}
+          else %{#{spaces*6}<entry>#{c}</entry>\n}
+          end
+          nc+=1
+        end
+        trc=(trc.is_a?(Array)) ? trc.flatten.join : trc
+        trc = if table_obj.head_ and nr==0
+          "#{spaces*4}<thead>\n#{spaces*5}<row>\n#{trc}#{spaces*5}</row>\n#{spaces*4}</thead>\n#{spaces*4}<tbody>\n"
+        else
+          "#{spaces*5}<row>\n#{trc}#{spaces*5}</row>\n"
+        end
+        nr+=1
+        table_rows << trc
+      end
+      tbody_close=if table_obj.head_
+        "#{spaces*4}</tbody>"
+      else ''
+      end
+      table_rows=table_rows.flatten.join
+      # include table_id <table id=''>
+      table_obj.obj=%{#{spaces*3}<para #{@id}>
+#{spaces*4}<table>
+#{spaces*4}<tgroup cols="#{table_obj.cols}" align="char">
+#{table_rows}#{tbody_close}
+#{spaces*4}</tgroup>
+#{spaces*4}</table>
+#{spaces*3}</para>}
+      table_obj
+    end
+  end
+  class TableXMLexp <Table
+    @@tablehead=0
+    @@tablefoot=[]
+    def initialize(one)
+      @one,@parablock=one,one
+    end
+    def table_close
+      '</td></tr>
+</table>'
+    end
+    def margin_numless
+      '</td><td width="4%" align="right" valign="top">'
+    end
+    def table_head(inf)
+      %{<table summary="normal text css" width="100%" border="0" bgcolor="white" cellpadding="2" align="center">
+  <tr>
+    <td valign="top" align="justify">
+      <a name="#{inf}"></a>
+    </td>
+    <td>
+<table summary="normal text css" width="100%" border="0" bgcolor="white" cellpadding="2" align="center">}
+    end
+    def table_end(tablefoot='')
+      %{</table>#{the_margin_numless}#{the_margin_numless}&nbsp;#{the_table_close}
+#{tablefoot}}
+    end
+    def table_row(inf,h=false)
+      bold=h ? '<b>' : ''
+      %{
+<tr>
+  <td width="#{inf}%" valign="top">#{bold}}
+    end
+    def table_cell(inf,h=false)
+      if h; %{</b></td><td width="#{inf}%" valign="top"><b>}
+      else  %{</td><td width="#{inf}%" valign="top">}
+      end
+    end
+    def table_row_close(h=false)
+      bold_close=h ? '<b>' : ''
+      "#{bold_close}</td></tr>"
+    end
+    def table
+      m=@parablock[/<!f(.+?)!>/,1]
+      @@tablefoot << m if m
+      @parablock=@parablock.gsub(/<!f.+?!>/,'')
+      @@tablehead=1 if @parablock =~/#{Mx[:gr_o]}Th#{Mx[:tc_p]}/u
+      if @parablock =~/#{Mx[:gr_o]}Th?#{Mx[:tc_p]}.+?#{Mx[:tc_p]}~(\d+);\w\d+;\w\d+#{Mx[:gr_c]}/u
+        @parablock=table_head($1)
+      end
+      if @parablock =~/#{Mx[:gr_o]}TZ#{Mx[:gr_c]}/
+        tablefoot=[]
+        @@tablefoot.each {|x| tablefoot << ''}
+        @@tablefoot=[]
+        if @parablock =~/#{Mx[:gr_o]}TZ#{Mx[:gr_c]}/
+          @parablock=table_end
+        end
+      end
+      if @@tablehead==1
+        if @parablock =~/#{Mx[:tc_p]}#{Mx[:tc_p]}/u
+          if @parablock =~/#{Mx[:tc_o]}#{Mx[:tc_p]}#{Mx[:tc_p]}(\d+?)#{Mx[:tc_p]}/u
+            @parablock=@parablock.gsub(/#{Mx[:tc_o]}#{Mx[:tc_p]}#{Mx[:tc_p]}(\d+?)#{Mx[:tc_p]}/u,table_row($1,true))
+          end
+          if @parablock =~/#{Mx[:tc_p]}#{Mx[:tc_p]}(\d+?)#{Mx[:tc_p]}/u
+            @parablock=@parablock.gsub(/#{Mx[:tc_p]}#{Mx[:tc_p]}(\d+?)#{Mx[:tc_p]}/u,table_cell($1,true))
+          end
+          if @parablock =~/#{Mx[:tc_c]}/
+            @parablock=@parablock.gsub(/#{Mx[:tc_c]}/,table_row_close(true))
+          end
+          @@tablehead=0
+        end
+        @parablock
+      else
+        if @parablock =~/^#{Mx[:tc_p]}#{Mx[:tc_p]}(\d+?)#{Mx[:tc_p]}/u
+          @parablock=@parablock.gsub(/^#{Mx[:tc_p]}#{Mx[:tc_p]}(\d+?)#{Mx[:tc_p]}/u,table_row($1))
+        end
+        if @parablock =~/#{Mx[:tc_p]}#{Mx[:tc_p]}(\d+?)#{Mx[:tc_p]}/u
+          @parablock=@parablock.gsub(/#{Mx[:tc_p]}#{Mx[:tc_p]}(\d+?)#{Mx[:tc_p]}/u,table_cell($1))
+        end
+        if @parablock =~/#{Mx[:tc_c]}/
+          @parablock=@parablock.gsub(/#{Mx[:tc_c]}/,table_row_close)
+        end
+        @parablock
+      end
+      @parablock
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** xml_format.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xml_format.rb"
+# <<sisu_document_header>>
+module SiSU_XML_Format
+  require_relative 'dp'                                 # dp.rb
+  require_relative 'xml_parts'                          # xml_parts.rb
+  include SiSU_Param
+  class ParagraphNumber
+    def initialize(md,paranum)
+      @md=md
+      @paranum=(paranum ? (/(\d+)/m.match(paranum)[1]) : nil)
+    end
+    def display
+      p_num_display=if @paranum
+        @paranum.gsub(/(\d+)/,
+        '<font size="1" color="#777777">' +
+        '&nbsp;&nbsp;\1</font>')
+      else ''
+      end
+      p_num_display
+    end
+    def name
+      p_num_name=@paranum.gsub(/(\d+)/,'<a name="\1"></a>')
+      p_num_name
+    end
+    def goto
+      p_num_goto=@paranum.gsub(/(\d+)/,'<a href="#\1">')
+      p_num_goto
+    end
+  end
+  class HeadInformation
+    include SiSU_Parts_XML
+    def initialize #dc rdf
+      @full_title=@subtitle=@author=@subject=@description=@publisher=@contributor=@date=@type=@format=@identifier=@source=@language=@relation=@coverage=@rights=@copyright=@owner=@keywords=''
+      @md=@@md
+      # DublinCore 1 - title
+      @rdfurl=%{  rdf:about="http://www.jus.uio.no/lm/toc"\n}
+      if defined? @md.title.full \
+      and @md.title.full                          # DublinCore 1 - title
+        @rdf_title=%{    dc.title="#{seg_name}#{@md.title.full}"\n}
+        @full_title=%{<meta name="dc.title" content="#{seg_name}#{@md.title.full}" />\n}
+      end
+      if defined? @md.creator.author \
+      and @md.creator.author                                                  # DublinCore 2 - creator/author (author)
+        @rdf_author=%{    dc.author="#{@md.creator.author}"\n}
+        @author=%{<meta name="dc.author" content="#{@md.creator.author}" />\n}
+      end
+      if defined? @md.classify.subject \
+      and @md.classify.subject=~/\S+/                                          # DublinCore 3 - subject (us library of congress, eric or udc, or schema???)
+        @rdf_subject=%{    dc.subject="#{@md.classify.subject}"\n}
+        @subject=%{<meta name="dc.subject" content="#{@md.classify.subject}" />\n}
+      end
+      if defined? @md.notes.description \
+      and @md.notes.description=~/\S+/                                        # DublinCore 4 - description
+        @rdf_description=%{    dc.description="#{@md.notes.description}"\n}
+        @description=%{<meta name="dc.description" content="#{@md.notes.description}" />\n}
+      end
+      if defined? @md.publisher \
+      and @md.publisher=~/\S+/                                                # DublinCore 5 - publisher (current copy published by)
+        @rdf_publisher=%{    dc.publisher="#{@md.publisher}"\n}
+        @publisher=%{<meta name="dc.publisher" content="#{@md.publisher}" />\n}
+      end
+      if defined? @md.creator.contributor \
+      and @md.creator.contributor=~/\S+/                                      # DublinCore 6 - contributor
+        @rdf_contributor=%{    dc.contributor="#{@md.creator.contributor}"\n}
+        @contributor=%{<meta name="dc.contributor" content="#{@md.creator.contributor}" />\n}
+      end
+      if defined? @md.date.published \
+      and @md.date.published                                                  # DublinCore 7 - date year-mm-dd
+        @rdf_date=%{    dc.date="#{@md.date.published}"\n}
+        @date=%{<meta name="dc.date" content="#{@md.date.published}" #{@md.date_scheme} />\n}
+      end
+      if defined? @md.date.created \
+      and @md.date.created                                                    # DublinCore 7 - date.created year-mm-dd
+        @rdf_date_created=%{    dc.date.created="#{@md.date.created}"\n}
+        @date_created=%{<meta name="dc.date.created" content="#{@md.date.created}" #{@md.date_created_scheme} />\n}
+      end
+      if defined? @md.date.issued \
+      and @md.date.issued                                                      # DublinCore 7 - date.issued year-mm-dd
+        @rdf_date_issued=%{    dc.date.issued="#{@md.date.issued}"\n}
+        @date_issued=%{<meta name="dc.date.issued" content="#{@md.date.issued}" #{@md.date_issued_scheme} />\n}
+      end
+      if defined? @md.date.available \
+      and @md.date.available                                                  # DublinCore 7 - date.available year-mm-dd
+        @rdf_date_available=%{    dc.date.available="#{@md.date.available}"\n}
+        @date_available=%{<meta name="dc.date.available" content="#{@md.date.available}" #{@md.date_available_scheme} />\n}
+      end
+      if defined? @md.date.valid \
+      and @md.date.valid                                                      # DublinCore 7 - date.valid year-mm-dd
+        @rdf_date_valid=%{    dc.date.valid="#{@md.date.valid}"\n}
+        @date_valid=%{<meta name="dc.date.valid" content="#{@md.date.valid}" #{@md.date_valid_scheme} />\n}
+      end
+      if defined? @md.date.modified \
+      and @md.date.modified                                                   # DublinCore 7 - date.modified year-mm-dd
+        @rdf_date_modified=%{    dc.date.modified="#{@md.date.modified}"\n}
+        @date_modified=%{<meta name="dc.date.modified" content="#{@md.date.modified}" #{@md.date_modified_scheme} />\n}
+      end
+      if defined? @md.notes.coverage \
+      and @md.notes.coverage=~/\S+/                                        # DublinCore 14 - coverage
+        @rdf_coverage=%{    dc.coverage="#{@md.notes.coverage}"\n}
+        @coverage=%{<meta name="dc.coverage" content="#{@md.notes.coverage}" />\n}
+      end
+      if defined? @md.notes.relation \
+      and @md.notes.relation=~/\S+/                                         # DublinCore 13 - relation
+        @rdf_relation=%{    dc.relation="#{@md.notes.relation}"\n}
+        @relation=%{<meta name="dc.relation" content="#{@md.notes.relation}" />\n}
+      end
+      if defined? @md.notes.type \
+      and @md.notes.type                                                            # DublinCore 8 - type (genre eg. report, convention etc)
+        @rdf_type=%{    dc.type="#{@md.notes.type}"\n}
+        @type=%{<meta name="dc.type" content="#{@md.notes.type}" />\n}
+      end
+      if defined? @md.notes.format \
+      and @md.notes.format=~/\S+/                                              # DublinCore 9 - format (use your mime type)
+        @rdf_format=%{    dc.format="#{@md.notes.format}"\n}
+        @format=%{<meta name="dc.format" content="#{@md.notes.format}" />\n}
+      end
+      #if defined? @md.identifier.sisupod \
+      #and @md.identifier.sisupod=~/\S+/                                       # DublinCore 10 - identifier (your identifier, could use urn which is free)
+      #  @rdf_identifier=%{    dc.identifier="#{@md.identifier.sisupod}"\n}
+      #  @identifier=%{<meta name="dc.identifier" content="#{@md.identifier.sisupod}" />\n}
+      #end
+      if defined? @md.original.source \
+      and @md.original.source=~/\S+/                                           # DublinCore 11 - source (document source)
+        @rdf_source=%{    dc.source="#{@md.original.source}"\n}
+        @source=%{<meta name="dc.source" content="#{@md.source}" />\n}
+      end
+      if defined? @md.original.language \
+      and @md.original.language=~/\S+/                                         # DublinCore 12 - language (English)
+        @rdf_language=%{    dc.language="#{@md.original.title}"\n}
+        @language=%{<meta name="dc.language" content="#{@md.language[:name]}" />\n}
+      end
+      if defined? @md.rights.all \
+      and @md.rights.all=~/\S+/                                               # DublinCore 15 - rights
+        rights=meta_content_clean(@md.rights.all)
+        copyright=meta_content_clean(@md.rights.copyright.all)
+        @rdf_rights=%{    dc.rights="#{rights}"\n}
+        @rights=%{<meta name="dc.rights" content="#{rights}" />\n}
+      end
+      @copyright=%{<meta name="copyright" content="#{copyright}" />\n} \
+        if @md.rights.copyright.all # possibly redundant see dc.rights
+      @owner=%{<meta name="owner" content="#{@md.owner}" />\n} if @md.owner
+      @keywords=%{<meta name="keywords" content="#{@md.keywords}" />\n} if @md.keywords
+      @index='index'
+    end
+    def meta_content_clean(content='')
+      content=if not content.nil?
+        content=content.tr('"',"'").
+           gsub(/&/,'&amp;')
+        content=SiSU_XML_Munge::Trans.new(@md).char_enc.utf8(content)
+      else content
+      end
+    end
+    def table_close
+      '</font> </td></tr></table>'
+    end
+    def toc_head
+      <<WOK
+<html>
+<head>
+<title>#{@md.html_title}</title>
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+         xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <rdf:Description
+#{@rdfurl}
+#{@rdf_title}
+#{@rdf_subtitle}
+#{@rdf_author}
+#{@rdf_subject}
+#{@rdf_description}
+#{@rdf_publisher}
+#{@rdf_contributor}
+#{@rdf_date}
+#{@rdf_date_created}
+#{@rdf_date_issued}
+#{@rdf_date_available}
+#{@rdf_date_valid}
+#{@rdf_date_modified}
+#{@rdf_type}
+#{@rdf_format}
+#{@rdf_identifier}
+#{@rdf_source}
+#{@rdf_language}
+#{@rdf_relation}
+#{@rdf_coverage}
+#{@rdf_rights}
+  />
+</rdf:RDF>
+#{@full_title}
+#{@author}
+#{@subject}
+#{@description}
+#{@publisher}
+#{@contributor}
+#{@date}
+#{@date_created}
+#{@date_issued}
+#{@date_available}
+#{@date_valid}
+#{@date_modified}
+#{@type}
+#{@format}
+#{@identifier}
+#{@source}
+#{@language}
+#{@relation}
+#{@coverage}
+#{@rights}
+#{@copyright}
+#{@owner}
+#{@png.ico}
+#{@txt.generator}
+#{@js.head}
+\n</head>
+#{@color.body}
+#{@font.css_table_file}
+<a name="top"></a>
+<a name="up"></a>
+<a name="start"></a>
+#{@js.top}
+WOK
+    end
+  end
+  class FormatTextObject
+    include SiSU_Parts_XML
+    attr_accessor :md,:txt,:format,:paranum,:p_num,:para_id,:headname,:font
+    def initialize(md,dob)
+      @md,@dob=md,dob
+      if @dob[:ocn]=~/\d+/
+        @paranum=/(\d+)/m.match(@dob[:ocn])[1]
+        @headname=''
+        @headname=%{<a name="h#{dob.name}"></a>} if defined? dob.name
+        @p_num=SiSU_XML_Format::ParagraphNumber.new(@md,dob.ocn)
+      end
+      rgx=/^[1-6-]~{1,2}/ #watch
+      @lnk_url=@lnk_url.gsub(rgx,'') if @lnk_url =~rgx
+      rgx=/~\{\d+\s+(.+?)\}~/
+      @lnk_url=@lnk_url.gsub(rgx,'\1') if @lnk_url =~rgx
+    end
+    def scr_endnote_body
+      "<endnote>#{@txt}</endnote> "
+    end
+  end
+  class FormatScroll < FormatTextObject
+    def initialize(md,dob)
+      super(md,dob)
+    end
+    def heading_body
+      %{<p class="norm">#{@p_num.name}#{@headname}#{@dob.obj} </p>} +
+      %{<p class="paranum"><font size="1" color="#777777">&nbsp;&nbsp;#{@dob.ocn}</font></p>\n}
+    end
+    def heading_body0
+      %{<h1 class="norm">#{@p_num.name}#{@headname}#{@dob.obj}</h1>} +
+      %{<p class="paranum"><font size="1" color="#777777">&nbsp;&nbsp;#{@dob.ocn}</font></p>\n}
+    end
+    def heading_body1
+      %{<h2 class="norm">#{@p_num.name}#{@headname}#{@dob.obj}</h2>} +
+      %{<p class="paranum"><font size="1" color="#777777">&nbsp;&nbsp;#{@dob.ocn}</font></p>\n}
+    end
+    def heading_body2
+      %{<h3 class="norm">#{@p_num.name}#{@headname}#{@dob.obj}</h3>} +
+      %{<p class="paranum"><font size="1" color="#777777">&nbsp;&nbsp;#{@dob.ocn}</font></p>\n}
+    end
+    def heading_body3
+      %{<h4 class="norm">#{@p_num.name}#{@headname}#{@dob.obj}</h4>} +
+      %{<p class="paranum"><font size="1" color="#777777">&nbsp;&nbsp;#{@dob.ocn}</font></p>\n}
+    end
+    def heading_body4
+      %{<h5 class="norm">#{@p_num.name}#{@headname}#{@dob.obj}</h5>} +
+      %{<p class="paranum"><font size="1" color="#777777">&nbsp;&nbsp;#{@dob.ocn}</font></p>\n}
+    end
+    def heading_body5
+      %{<h6 class="norm">#{@p_num.name}#{@headname}#{@dob.obj}</h6>} +
+      %{<p class="paranum"><font size="1" color="#777777">&nbsp;&nbsp;#{@dob.ocn}</font></p>\n}
+    end
+    def heading_body6
+      %{<h7 class="norm">#{@p_num.name}#{@headname}#{@dob.obj}</h7>} +
+      %{<p class="paranum"><font size="1" color="#777777">&nbsp;&nbsp;#{@dob.ocn}</font></p>\n}
+    end
+  end
+  class ParagraphNumber
+    def initialize(md,ocn)
+      @md,@ocn=md,ocn.to_s
+      @ocn ||=''
+    end
+    def ocn_display
+      @make=SiSU_Env::ProcessingSettings.new(@md)
+      if @make.build.ocn?
+        ocn_class='ocn'
+        if @ocn.to_i==0
+          @ocn.gsub(/^(\d+|)$/,
+            %{<label class="#{ocn_class}"><a name="#{@ocn}">&nbsp;</a></label>})
+        else
+          @ocn.gsub(/^(\d+|)$/,
+            %{<label class="#{ocn_class}"><a name="#{@ocn}">\\1</a></label>})
+        end
+      else
+        ocn_class='ocn_off'
+        @ocn.gsub(/^(\d+|)$/,
+          %{<label class="#{ocn_class}">&nbsp;</label>})
+      end
+    end
+    def name
+      %{<a name="#{@ocn}"></a>}
+    end
+    def id #w3c? "tidy" complains about numbers as identifiers ! annoying
+      %{id="o#{@ocn}"}
+    end
+    def goto
+      %{<a href="##{@ocn}">}
+    end
+  end
+  class HeadInformation
+    include SiSU_Parts_XML
+    attr_reader :md,:sfx,:pdf,:rdf,:vz
+    def initialize(md)
+      @md=md
+      @rdf=SiSU_XML_Tags::RDF.new(md)
+      # DublinCore 1 - title
+      @stylesheet=SiSU_Style::CSS_HeadInfo.new(md).stylesheet
+      @seg_name_html=(SiSU_HTML::Source::Seg.new.seg_name_html || [])
+      @seg_name_html_tracker=(SiSU_HTML::Source::Seg.new.seg_name_html_tracker || [])
+      @index='index'
+      @metalink='#metadata'
+      @tocband_scroll,@tocband_segtoc=nil,nil
+    end
+    def doc_type
+      %{<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">\n}
+    end
+    def table_close
+      %{  </font>
+#{the_table_close}}
+    end
+    def html_close #moved
+    %{</body>
+</html>}
+    end
+  end
+  class XML
+  end
+  class FormatTextObject
+    include SiSU_Parts_XML
+    attr_accessor :md,:dob,:txt,:ocn,:format,:table,:link,:linkname,:paranum,:p_num,:headname,:banner,:url
+    def initialize(md,t_o)
+      @md,@t_o=md,t_o
+      if t_o.is_a?(Hash)
+        @txt            =t_o[:txt]            || nil
+        @ocn            =t_o[:ocn]            || nil
+        @ocn_display    =t_o[:ocn_display]    || nil
+        @headname       =t_o[:headname]       || nil
+        @trailer        =t_o[:trailer]        || nil
+        @endnote_part_a =t_o[:endnote_part_a] || nil
+        @endnote_part_b =t_o[:endnote_part_b] || nil
+        @lnk_url        =t_o[:lnk_url]        || nil
+        @lnk_txt        =t_o[:lnk_txt]        || nil
+        @format         =t_o[:format]         || nil
+        @target         =t_o[:target]         || nil #occasionally passed but not used
+      elsif t_o.class.inspect =~/Object/
+        @txt=if defined? t_o.obj; t_o.obj
+        else nil
+        end
+        @ocn=if defined? t_o.ocn; t_o.ocn.to_s
+        else nil
+        end
+        @headname=if t_o.is==:heading and defined? t_o.name; t_o.name
+        else nil
+        end
+      else
+        if @md.opt.act[:maintenance][:set]==:on
+          p __FILE__ << ':' << __LINE__.to_s
+          p t_o.class
+          p caller
+        end
+      end
+      if defined? @t_o.ocn
+        ocn=((@t_o.ocn.to_s =~/\d+/) ? @t_o.ocn : nil)
+        @p_num=ParagraphNumber.new(@md,ocn)
+      end
+      if @format and not @format.empty?
+        if @format=~/^\d:(\S+)/ #need more reliable marker #if @format =~ /#{Rx[:lv]}/
+          headname=$1 #format[/\d~(\S+)/m,1]
+          @headname=if headname =~/^[a-zA-Z]/; %{<a name="#{headname}" id="#{headname}"></a>} #consider: h_#{headname}
+          else %{<a name="h#{headname}" id="h#{headname}"></a>}
+          end
+        end
+      end
+      @dob=t_o if defined? t_o.is
+    end
+    def endnote_body
+      %{
+<p class="endnote">
+  #{@txt}
+</p>
+}
+    end
+    def endnote_body_indent
+      %{
+  <p class="endnote_indent">
+    #{@txt}
+  </p>
+}
+    end
+    def no_paranum
+      %{
+<div class="substance">
+  <label class="ocn">&nbsp;</label>
+  <p class="norm">
+    #{@txt}
+  </p>
+</div>
+}
+    end
+    def para_form_css(tag,attrib)                                                    # regular paragraphs shaped here
+      ul=ulc=''
+      ul,ulc="<ul>\n  ","\n  </ul>" if @tag =~/li/
+      %{
+<div class="substance">
+  #{@p_num.ocn_display}
+  #{ul}<#{tag} class="#{attrib}" #{@p_num.id}>
+    #{@txt}
+  </#{tag}>#{ulc}
+</div>
+}
+    end
+    def para
+      para_form_css('p','norm')
+    end
+    def code
+      para_form_css('p','code')
+    end
+    def center
+      para_form_css('p','center')
+    end
+    def bold
+      para_form_css('p','bold')
+    end
+    def bullet
+      para_form_css('li','bullet')
+    end
+    def format(tag,attrib)
+      para_form_css(tag,attrib)
+    end
+    def heading_normal(tag,attrib)
+      %{
+<div class="substance">
+  #{@p_num.ocn_display}
+  <#{tag} class="#{attrib}" #{@p_num.id}>#{@p_num.name}
+    #{@headname}#{@txt}
+  </#{tag}>
+</div>
+}
+    end
+    def heading_body
+      heading_normal('p','norm')
+    end
+    def heading_body0
+      heading_normal('h1','norm')
+    end
+    def heading_body1
+      heading_normal('h1','norm')
+    end
+    def heading_body2
+      heading_normal('h2','norm')
+    end
+    def heading_body3
+      heading_normal('h3','norm')
+    end
+    def heading_body4
+      heading_normal('h4','norm')
+    end
+    def heading_body5
+      heading_normal('h5','norm')
+    end
+    def heading_body6
+      heading_normal('h6','norm')
+    end
+    def heading_body7
+      heading_normal('h7','norm')
+    end
+    def title_header(tag,attrib)
+      %{
+<div class="content">
+<#{tag} class="#{attrib}">
+    #{@txt}
+  </#{tag}>
+</div>
+}
+    end
+    def title_header1
+      title_header('h1','tiny')
+    end
+    def title_header2
+      title_header('h2','tiny')
+    end
+    def title_header3
+      title_header('h3','tiny')
+    end
+    def title_header4
+      ''
+    end
+    def title_header4_old
+      %{
+<div class="substance">
+  <label class="ocn">&nbsp;</label>
+  <h4 class="banner">
+    #{@txt}
+  </h4>
+</div>
+}
+    end
+    def dl #check :trailer
+      "<dl><b>#{@txt}</b> #{@trailer}</dl>"
+    end
+    def table_css_end      #<!TZ!>
+      '</table>
+    </p>
+  </div>'
+    end
+    def gsub_body
+#fix
+      @txt=case @txt
+      when /^\s*\((i+|iv|v|vi+|ix|x|xi+)\)/
+        @txt.gsub(/^\((i+|iv|v|vi+|ix|x|xi+)\)/,'<b>(\1)</b>').
+          gsub(/^(#{Mx[:pa_o]}i[1-9]#{Mx[:pa_c]})\s*\((i+|iv|v|vi+|ix|x|xi+)\)/,'\1<b>(\2)</b>')
+      when /^\s*\(?(\d|[a-z])+\)/
+        @txt.gsub(/^\((\d+|[a-z])+\)/,'<b>(\1)</b>').
+          gsub(/^(#{Mx[:pa_o]}i[1-9]#{Mx[:pa_c]})\s*\((\d+|[a-z])+\)/,'\1<b>(\2)</b>')
+      when /^\s*\d{1,3}\.\s/
+        @txt.gsub(/^\s*(\d+\.)/,'<b>\1</b>')
+      when /^\s*[A-Z]\.\s/
+        @txt.gsub(/^\s*([A-Z]\.)/,'<b>\1</b>')
+      else @txt
+      end
+    end
+    def bold_para
+      %{#{the_margin.txt_0}
+  <p class="bold">
+    #{@txt}
+  </p>
+#{the_margin.num_css}
+  &nbsp;&nbsp;&nbsp;
+#{the_table_close}}
+    end
+    def bold_header
+      @txt=@txt.gsub(/[1-9]~(\S+)/,'<a name="\1"></a>').
+        gsub(/[1-9]~/,'')
+      %{<p class="bold">
+    #{@txt}
+  </p>
+#{the_margin.num_css}
+  &nbsp;&nbsp;&nbsp;
+#{the_table_close}}
+    end
+    def toc_head_copy_at
+      %{<p class="center">#{@txt}</p>\n}
+    end
+    def center
+      %{<p class="center">#{@txt}</p>\n}
+    end
+    def bold
+      %{<p class="bold">#{@txt}</p>\n}
+    end
+    def center_bold
+      %{<p class="centerbold">#{@txt}</p>\n}
+    end
+  end
+  class FormatScroll < FormatTextObject
+    include SiSU_Parts_XML
+    def initialize(md,txt)
+      super(md,txt)
+    end
+  end
+  class FormatSeg < FormatTextObject
+    def initialize(md,txt)
+      super(md,txt)
+    end
+    def navigation_toc_lev1_advert
+      %{#{@banner.home_button}\n
+<center>
+#{@txt}
+#{@two}
+</a></center><p />}
+    end
+    def navigation_toc_lev1
+      %{#{@banner.nav_toc}}
+    end
+    def navigation_toc_lev2                                                      #change bold use css
+      %{<p />
+<table summary="navigation segment level 2">
+<tr><td width ="20">
+</td>
+<td>
+  <font size="3" #{the_font.set_face}>
+    <b>#{@txt}</b>
+  </font>
+  </p>
+#{the_table_close}}
+    end
+    def navigation_toc_lev3                                                      #change bold use css
+      %{<p />
+<table summary="navigation segment level 3">
+<tr><td width ="20">
+</td>
+<td>
+  <font size="3" #{the_font.set_face}>
+    <b>#{@txt}</b>
+  </font>
+  </p>
+#{the_table_close}}
+    end
+    def navigation_toc_lev4
+      %{<table summary="navigation segment level 4">
+<tr><td width ="80">
+</td>
+<td>
+<p>
+  #{@txt}
+</p>
+#{the_table_close}}
+    end
+    def navigation_toc_lev5
+    end
+    def navigation_toc_lev6
+    end
+    def endnote_seg_body(fn='')  #FIX                                                #url construction keep within single line... BUG WATCH 200408
+      fn='doc' if fn.empty? #you may wish to reconsider, sends to 'doc' where no segment info # Sfx[:html] or Sfx[:xhtml] ?
+      %{
+  <p class="endnote">
+    #{@endnote_part_a}#{fn}#{@md.lang_code_insert}#{Sfx[:html]}#{@endnote_part_b}
+  </p>
+}
+    end
+    def subtoc_lev(tag,attrib)
+      txt=if @txt \
+      and @txt =~/<\/?i>|<a\s+name="\S+?">/mi
+        @txt.gsub(/<\/?i>|<a\s+name="\S+?">/mi,'') #removes name markers from subtoc, go directly to substantive text
+      else @txt
+      end
+      note=''
+      if txt =~/(#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}\s*)/m
+        note=$1
+        note=note.gsub(/[\n\s]+/m,' ')
+        txt=txt.gsub(/(?:#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})\s*/m,' ').
+          gsub(/<a[\n\s]+name="-\d+"[\n\s]+href="#_\d+">&nbsp;<sup>\d+<\/sup>&nbsp;/m,'')
+      end
+      %{<#{tag} class="#{attrib}">
+    <a href="##{@ocn}"><i>#{txt}</i></a> #{note}
+  </#{tag}>}
+    end
+    def subtoc_lev5
+      subtoc_lev('h5','subtoc') if @txt
+    end
+    def subtoc_lev6
+      subtoc_lev('h6','subtoc') if @txt
+    end
+    def subtoc_lev7
+      subtoc_lev('h7','subtoc') if @txt
+    end
+    #% para sisu
+    def header_sub(tag,attrib)
+      @txt=@txt.gsub(/(?:#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})\s*/m,' ')
+      %{
+<div class="substance">
+  #{@p_num.ocn_display}
+  <#{tag} class="#{attrib}" #{@p_num.id}>#{@p_num.name} #{@headname}
+    #{@txt}
+  </#{tag}>
+</div>
+}
+    end
+    def header4
+      %{
+<div class="substance">
+  #{@p_num.ocn_display}
+  <h1 class="norm" #{@p_num.id}>#{@p_num.name}
+    #{@t_o[:format]}
+    #{@txt}
+  </h1>
+</div>
+}
+    end
+    def header5
+      header_sub('p','bold')
+    end
+    def header6
+      header_sub('p','bold')
+    end
+    def header7
+      header_sub('p','bold')
+    end
+    def navigation_header4
+      %{<table summary="navigation segment header 4" width=100% bgcolor="#08163f" border="0">
+<tr><td align="center">
+<p class="bold">
+  #{@txt}
+</p>
+#{the_table_close}}
+    end
+    def navigation_header5
+      %{<p class="bold">
+  #{@txt}
+</p>}
+    end
+    def navigation_header6
+      %{<p class="bold">
+  #{@txt}
+</p>}
+    end
+    def navigation_header7
+      %{<p class="bold">
+  #{@txt}
+</p>}
+    end
+    def navigation_center
+      "<center>#{@txt}</center>"
+    end
+  end
+  class FormatToc < FormatTextObject
+    def initialize(md,txt)
+      super(md,txt)
+    end
+    def links_guide
+      %{  <li class="doc">
+    <a href="#{@lnk_url}" target="_top">
+      #{@lnk_txt}
+    </a>
+  </li>
+}
+    end
+    def lev(tag,attrib)
+      if @txt
+        %{<#{tag} class="#{attrib}">
+    #{@txt}
+  </#{tag}>
+}
+      else ''
+      end
+    end
+    def lev1
+      lev('h1','toc')
+    end
+    def lev2
+      lev('h2','toc')
+    end
+    def lev3
+      lev('h3','toc')
+    end
+    def lev4
+      lev('h4','toc')
+    end
+    def lev5
+      lev('h5','toc')
+    end
+    def lev6
+      lev('h6','toc')
+    end
+    def lev7
+      lev('h7','toc')
+      #lev('b','toc')
+    end
+    def lev0 #docinfo
+      lev('h0','toc')
+    end
+    def mini_lev1
+      lev('h1','minitoc')
+    end
+    def mini_lev2
+      lev('h2','minitoc')
+    end
+    def mini_lev3
+      lev('h3','minitoc')
+    end
+    def mini_lev4
+      lev('h4','minitoc')
+    end
+    def mini_lev5
+      lev('h5','minitoc')
+    end
+    def mini_lev6
+      lev('h6','minitoc')
+    end
+    def mini_lev7
+      lev('h7','minitoc')
+    end
+    def mini_lev0 #docinfo
+      lev('h0','minitoc')
+    end
+    def mini_tail
+  %{
+  <h4 class="minitoc">
+    <a href="sisu_manifest.html">Manifest (alternative outputs)</a>
+  </h4>
+}
+    end
+    def mini_concord_tail
+  %{
+  <h4 class="minitoc">
+    <a href="concordance.html">Concordance (wordlist)</a>
+  </h4>
+  <h4 class="minitoc">
+    <a href="sisu_manifest.html">Manifest (alternative outputs)</a>
+  </h4>
+}
+    end
+  end
+  class XML
+  end
+end
+__END__
+,** Notes: tidy -xml index.xml >> index.tidy
+#+END_SRC
+
+** xml_md_oai_pmh_dc.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xml_md_oai_pmh_dc.rb"
+# <<sisu_document_header>>
+module SiSU_XML_Metadata
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'dp'                                 # dp.rb
+    include SiSU_Param
+  class OAI_PMH
+    def initialize(opt)
+      @md=SiSU_Param::Parameters.new(opt).get
+      @oai_pmh=[]
+    end
+    def read
+      output
+    end
+    def pre
+<<WOK
+<?xml version="1.0" encoding="UTF-8"?>
+<oai_dc:dc
+  xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/"
+  xmlns:dc="http://purl.org/dc/elements/1.1/"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai_dc/
+  http://www.openarchives.org/OAI/2.0/oai_dc.xsd">
+WOK
+    end
+    def body
+      if defined? @md.title.full \
+      and @md.title.full=~/\S+/                                               # DublinCore 1 - title
+        @oai_pmh << %{  <dc:title xml:lang="en">#{@md.title.full}</dc:title>\n}
+      end
+      if defined? @md.creator.author \
+      and @md.creator.author=~/\S+/                                           # DublinCore 2 - creator/author (author)
+        txt=meta_content_clean(@md.creator.author)
+        @oai_pmh << %{  <dc:author>#{txt}</dc:author>\n}
+      end
+      if defined? @md.classify.subject \
+      and @md.classify.subject=~/\S+/                                          # DublinCore 3 - subject (us library of congress, eric or udc, or schema???)
+        txt=meta_content_clean(@md.classify.subject)
+        @oai_pmh << %{  <dc:subject>#{txt}</dc:subject>\n}
+      end
+      if defined? @md.classify.keywords \
+      and @md.classify.keywords=~/\S+/
+        txt=meta_content_clean(@md.classify.keywords)
+        @oai_pmh << %{  <dc:keywords>#{txt}</dc:keywords>\n}
+      end
+      if @md.publisher                                                         # DublinCore 5 - publisher (current copy published by)
+        txt=meta_content_clean(@md.publisher)
+        @oai_pmh << %{  <dc:publisher>#{txt}</dc:publisher>\n}
+      end
+      if defined? @md.creator.contributor \
+      and @md.creator.contributor=~/\S+/                                       # DublinCore 6 - contributor
+        txt=meta_content_clean(@md.creator.contributor)
+        @oai_pmh << %{  <dc:contributor>#{txt}</dc:contributor>\n}
+      end
+      if defined? @md.date.published \
+      and @md.date.published=~/\S+/                                            # DublinCore 7 - date year-mm-dd
+        @oai_pmh << %{  <dc:date>#{@md.date.published}</dc:date>\n}
+      end
+      if defined? @md.date.created \
+      and @md.date.created=~/\S+/                                              # DublinCore 7 - date.created
+        @oai_pmh << %{  <dc:date_created>#{@md.date.created}</dc:date_created>\n}
+      end
+      if defined? @md.date.issued \
+      and @md.date.issued=~/\S+/                                               # DublinCore 7 - date.issued
+        @oai_pmh << %{  <dc:date_issued>#{@md.date.issued}</dc:date_issued>\n}
+      end
+      if defined? @md.date.available \
+      and @md.date.available=~/\S+/                                            # DublinCore 7 - date.available
+        @oai_pmh << %{  <dc:date_available>#{@md.date.available}</dc:date_available>\n}
+      end
+      if defined? @md.date.valid \
+      and @md.date.valid=~/\S+/                                                # DublinCore 7 - date.valid
+        @oai_pmh << %{  <dc:date_valid>#{@md.date.valid}</dc:date_valid>\n}
+      end
+      if defined? @md.date.modified \
+      and @md.date.modified=~/\S+/                                             # DublinCore 7 - date.modified
+        @oai_pmh <<  %{  <dc:date_modified>#{@md.date.modified}</dc:date_modified>\n}
+      end
+      if defined? @md.notes.description \
+      and @md.notes.description=~/\S+/                                         # DublinCore 4 - description
+        txt=meta_content_clean(@md.notes.description)
+        @oai_pmh << %{  <dc:description>#{txt}</dc:description>\n}
+      end
+      if defined? @md.notes.coverage \
+      and @md.notes.coverage=~/\S+/                                            # DublinCore 14 - coverage
+        txt=meta_content_clean(@md.notes.coverage)
+        @oai_pmh << %{  <dc:coverage>#{txt}</dc:coverage>\n}
+      end
+      if defined? @md.notes.relation \
+      and @md.notes.relation=~/\S+/                                            # DublinCore 13 - relation
+        txt=meta_content_clean(@md.notes.relation)
+        @oai_pmh << %{  <dc:relation>#{txt}</dc:relation>\n}
+      end
+      if defined? @md.notes.type \
+      and @md.notes.type=~/\S+/                                                # DublinCore 8 - type
+        txt=meta_content_clean(@md.notes.type)
+        @oai_pmh << %{  <dc:type>#{txt}</dc:type>\n}
+      end
+      if defined? @md.notes.format \
+      and @md.notes.format=~/\S+/                                              # DublinCore 9 - format
+        txt=meta_content_clean(@md.notes.format)
+        @oai_pmh << %{  <dc:format>#{txt}</dc:format>\n}
+      end
+      #if defined? @md.identifier.sisupod \
+      #and @md.identifier.sisupod=~/\S+/                                       # DublinCore 10 - identifier
+      #  txt=meta_content_clean(@md.identifier.sisupod)
+      #  @oai_pmh << %{  <dc:identifier>#{txt}</dc:identifier>\n}
+      #end
+      if defined? @md.original.source \
+      and @md.original.source=~/\S+/                                           # DublinCore 11 - source
+        txt=meta_content_clean(@md.original.source)
+        @oai_pmh << %{  <dc:source>#{txt}</dc:source>\n}
+      end
+      if defined? @md.title.language \
+      and @md.title.language=~/\S+/                                            # DublinCore 12 - language (English)
+        @oai_pmh << %{  <dc:language>#{@md.title.language}</dc:language>\n}
+      end
+      if defined? @md.original.language \
+      and @md.original.language=~/\S+/
+        @oai_pmh << %{  <dc:language>#{@md.original.language}</dc:language>\n}
+      end
+      if defined? @md.rights.all \
+      and @md.rights.all=~/\S+/                                                # DublinCore 15 - rights
+        txt=meta_content_clean(@md.rights.all)
+        @oai_pmh << %{  <dc:rights>#{txt}</dc:rights>\n}
+      end
+      @oai_pmh
+    end
+    def meta_content_clean(content='')
+      unless content.nil?
+        content=content.tr('"',"'")
+      end
+      content
+    end
+    def post
+      '</oai_dc:dc>'
+    end
+    def output
+      SiSU_Env::FileOp.new(@md).mkdir
+      oai_pmh=SiSU_Env::FileOp.new(@md,@md.fn[:oai_pmh]).mkfile #implement in param
+      oai_pmh << pre
+      body.each do |x|
+        oai_pmh << x
+      end
+      oai_pmh << post
+    end
+  end
+end
+__END__
+http://www.openarchives.org/pmh/
+http://www.openarchives.org/OAI/2.0/openarchivesprotocol.htm#dublincore
+http://es.dublincore.org/documents/usageguide/elements.shtml
+http://dublincore.org/documents/dces/
+see also http://dublincore.org/documents/dcmes-xml/
+#http://www.openarchives.org/OAI/2.0/openarchivesprotocol.htm#dublincore
+#sample implementation, e.g. 2
+<?xml version="1.0" encoding="UTF-8"?>
+<oai_dc:dc
+    xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/"
+    xmlns:dc="http://purl.org/dc/elements/1.1/"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai_dc/
+    http://www.openarchives.org/OAI/2.0/oai_dc.xsd">
+  <dc:title xml:lang="en">Grassmann's space analysis</dc:title>
+  <dc:author>Hyde, E. W. (Edward Wyllys)</dc:author>
+  <dc:subject>LCSH:Ausdehnungslehre; LCCN QA205.H99</dc:subject>
+  <dc:publisher>J. Wiley &amp; Sons</dc:publisher>
+  <dc:date>Created: 1906; Available: 1991</dc:date>
+  <dc:type>text</dc:type>
+  <dc:identifier>http://resolver.library.cornell.edu/math/1796949
+     </dc:identifier>
+  <dc:language>english</dc:language>
+  <dc:rights xml:lang="en">Public Domain</dc:rights>
+</oai_dc:dc>
+#+END_SRC
+
+** xml_parts.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xml_parts.rb"
+# <<sisu_document_header>>
+module SiSU_Parts_XML
+  require_relative 'generic_parts'                       # generic_parts.rb
+  include SiSU_Parts_Generic
+  def the_line_break
+    '<br />'
+  end
+  def the_table_close
+    '</td></tr>
+</table>'
+  end
+  def the_url_decoration
+    def xml_open                     #'&lt;'
+      Dx[:url_o]
+    end
+    def xml_close                    #'&gt;'
+      Dx[:url_c]
+    end
+    def txt_open
+      '<'
+    end
+    def txt_close
+      '>'
+    end
+    self
+  end
+  def the_color
+    def white
+      '#ffffff'
+    end
+    def black
+      '#000000'
+    end
+    def grey_pale
+      '#eeeeee'
+    end
+    def grey_medium
+      '#cccccc'
+    end
+    def grey
+      '#999999'
+    end
+    def blue_ink
+      '#003399'
+    end
+    def blue_tinge
+      '#e3ecef'
+    end
+    def yellow_light
+      '#fff3b6'
+    end
+    def table1
+      'ffffcc'
+    end
+    def table2
+      'c0d0f0'
+    end
+    def band1
+      %{"#{white}"}
+    end
+    def band2
+      %{"#{white}"}
+    end
+    self
+  end
+  def the_png
+    def _url_path_image_base #used for html image display
+      "#{Xx[:html_relative2]}_sisu/image"
+    end
+    def ico
+      %{  <link rel="shortcut icon" href="../_sisu/image/#{the_icon.i_ico}" />}
+    end
+    def png_home
+      %{<img border="0" src="#{_url_path_image_base}/#{the_icon.home_button}" alt="#{the_text.home} --&gt;" />}
+    end
+    def png_home_button
+      rel=@dir.path_rel_links.html_scroll_2
+      %{<img border="0" src="#{rel}/#{the_icon.home_button}" alt="#{the_text.home} --&gt;" />}
+    end
+    self
+  end
+  def the_font
+    def set_fonts
+      'verdana, arial, georgia, tahoma, sans-serif, helvetica, times, roman'
+     #'verdana, arial, georgia, tahoma, sans-serif, helvetica, "times new roman", times, roman'
+    end
+    def set_face
+      %{face="#{set_fonts}"}
+    end
+    #def set_color
+    #  'color="#000000"'
+    #end
+    #def set_size_endnote
+    #  'size="3"'
+    #end
+    #def set_small
+    #  'size="3"'
+    #end
+    #def set_tiny
+    #  'size="2"'
+    #end
+    #def paragraph_font_tiny
+    #  %{<font #{set_tiny} #{set_face}>}
+    #end
+    #def paragraph_font_small
+    #  %{<font #{set_small} #{set_face}>}
+    #end
+    self
+  end
+  def the_banner
+    def home_button_only
+      %{<a href="#{url.site}/">
+  #{the_png.png_home_button}
+  </a>}
+    end
+    def banner_band
+      %{<table summary="home button" width="100%" border="0" cellpadding="3" align="center">
+<tr><td align="left" valign="middle">
+  <a href="#{url.site}/" target="_top">
+    #{the_png.png_home}
+  </a>
+</td>
+<td width="90%">
+#{the_table_close}}
+    end
+    self
+  end
+end
+module SiSU_Proj_XML
+  require_relative 'html_parts'                         # html_parts.rb
+  require_relative 'se'                                 # se.rb
+  include SiSU_Env
+  class Bits < SiSU_Proj_HTML::Bits
+  end
+end
+__END__
+#+END_SRC
+
+** xml_persist.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xml_persist.rb"
+# <<sisu_document_header>>
+module SiSU_XML_Persist
+  class Persist
+    @@persist=nil
+    attr_accessor :head,:toc,:body,:tail,:open,:close,:sc,:endnotes,:book_idx,:metadata
+    #attr_accessor :head,:body,:tail,:open,:close,:sc
+#@@odf={ body: [], head: [], toc: [],  metadata: [], tail: [], book_idx: [], endnotes: [] }
+    def initialize(args=nil)
+      @@persist=args=(args ? args : (@@persist || persist_init_hash_values))
+      @head=args[:head]
+      @toc=args[:toc]
+      @body=args[:body]
+      @tail=args[:tail]
+      @open=args[:open]
+      @close=args[:close]
+      @sc=args[:sc]
+      @endnotes=args[:endnotes]
+      @book_idx=args[:book_idx]
+      @metadata=args[:metadata]
+    end
+    def head
+      @head
+    end
+    def toc
+      @toc
+    end
+    def body
+      @body
+    end
+    def tail
+      @tail
+    end
+    def open
+      @open
+    end
+    def close
+      @close
+    end
+    def sc
+      @sc
+    end
+    def endnotes
+      @endnotes
+    end
+    def book_idx
+      @book_idx
+    end
+    def metadata
+      @metadata
+    end
+    def persist_init_hash_values
+      {
+        head: [],
+        toc: [],
+        body: [],
+        tail: [],
+        open: [],
+        close: [],
+        sc: [],
+        endnotes: [],
+        book_idx: [],
+        metadata: [],
+      }
+    end
+    def persist_init
+      @@persist=nil
+      Persist.new(persist_init_hash_values)
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** xml_scaffold_structure_collapsed.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xml_scaffold_structure_collapsed.rb"
+# <<sisu_document_header>>
+module SiSU_XML_Scaffold_Structure_Collapse
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+    include SiSU_Particulars
+  require_relative 'ao'                                 # ao.rb
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  class Source
+    def initialize(opt)
+      @opt=opt
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+    end
+    def spaces
+      Ax[:spaces]
+    end
+    def read
+      begin
+        @md,@ao_array=@particulars.md,@particulars.ao_array
+        SiSU_XML_Scaffold_Structure_Collapse::Source::Scroll.new(@ao_array,@md).songsheet
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    private
+    class Scroll <Source
+      def initialize(data='',md='')
+        @data,@md=data,md
+      end
+      def songsheet
+        @t='sisu'
+        data=@data
+        if @md.opt.act[:verbose_plus][:set]==:on
+          structure_collapsed(data)
+        end
+        structure_build_collapsed(data)
+      end
+      def tags
+        # collapsed -->
+        def collapsed
+          [ '0',
+            '1',
+            '2',
+            '3',
+            '4',
+            '5',
+            '6'
+          ]
+        end
+        def docbook
+        end
+        def fictionbook
+        end
+        self
+      end
+      def output(o,lev=nil,comment='')
+         puts lev == (0..6) \
+         ? "#{spaces*lev}<#{lev}>[#{o.ocn}] #{o.ln} #{o.obj}</#{lev}>#{comment}"
+         : "<#{lev}>[#{o.ocn}] #{o.ln} #{o.obj}</#{lev}>#{comment}"
+      end
+      def structure_collapsed(data)
+        puts "\ncollapsed structure, heading outline --->\n\n"
+        data.each_with_index do |o,i|
+          if  (o.is ==:heading || o.is ==:heading_insert)
+            output(o,o.lc)
+          end
+        end
+      end
+      def structure_build_collapsed(data)
+        @s=tags.collapsed
+        puts "\nXML [#{@t} type] structure outline --->\n\n"
+        h=[0,false,false,false]
+        puts "<#{@s[0]}>"
+        data.each_with_index do |o,i|
+          if  (o.is ==:heading || o.is ==:heading_insert)
+            lev=o.lc
+            structure_build_tag_close(lev,h)
+            puts "#{spaces*lev}<#{@s[lev]}>\n#{spaces*lev}  [#{o.ocn}] #{lev} {#{o.node}}"
+            h[0]=lev
+          end
+        end
+        structure_build_tag_close(0,h)
+      end
+      def structure_build_tag_close(lev,h)
+        case h[0]
+        when 1
+          puts "#{spaces*1}</#{@s[1]}>" if (lev <= 1)
+          puts "</#{@s[0]}>"         if (lev==0)
+        when 2
+          puts "#{spaces*2}</#{@s[2]}>" if (lev <= 2)
+          puts "#{spaces*1}</#{@s[1]}>" if (lev <= 1)
+          puts "</#{@s[0]}>"         if (lev==0)
+        when 3
+          puts "#{spaces*3}</#{@s[3]}>" if (lev <= 3)
+          puts "#{spaces*2}</#{@s[2]}>" if (lev <= 2)
+          puts "#{spaces*1}</#{@s[1]}>" if (lev <= 1)
+          puts "</#{@s[0]}>"         if (lev==0)
+        when 4
+          puts "#{spaces*4}</#{@s[4]}>" if (lev <= 4)
+          puts "#{spaces*3}</#{@s[3]}>" if (lev <= 3)
+          puts "#{spaces*2}</#{@s[2]}>" if (lev <= 2)
+          puts "#{spaces*1}</#{@s[1]}>" if (lev <= 1)
+          puts "</#{@s[0]}>"         if (lev==0)
+        when 5
+          puts "#{spaces*5}</#{@s[5]}>" if (lev <= 5)
+          puts "#{spaces*4}</#{@s[4]}>" if (lev <= 4)
+          puts "#{spaces*3}</#{@s[3]}>" if (lev <= 3)
+          puts "#{spaces*2}</#{@s[2]}>" if (lev <= 2)
+          puts "#{spaces*1}</#{@s[1]}>" if (lev <= 1)
+          puts "</#{@s[0]}>"         if (lev==0)
+        when 6
+          puts "#{spaces*6}</#{@s[6]}>" if (lev <= 6)
+          puts "#{spaces*5}</#{@s[5]}>" if (lev <= 5)
+          puts "#{spaces*4}</#{@s[4]}>" if (lev <= 4)
+          puts "#{spaces*3}</#{@s[3]}>" if (lev <= 3)
+          puts "#{spaces*2}</#{@s[2]}>" if (lev <= 2)
+          puts "#{spaces*1}</#{@s[1]}>" if (lev <= 1)
+          puts "</#{@s[0]}>"         if (lev==0)
+        end
+      end
+    end
+  end
+end
+__END__
+@s=['0',
+  'A',
+  'B',
+  'C',
+  '1',
+  '2',
+  '3'
+]
+#@t='docbook'         #@t='fictionbook'
+#@s=['book',          #@s=['body',
+#  'part',            #  'section',
+#  'subpart N/A',     #  'section',
+#  'sub-subpart N/A', #  'section',
+#  'chapter',         #  'section',
+#  'sect1',           #  'section',
+#  'sect2'            #  'section'
+#]                    #]
+#+END_SRC
+
+** xml_scaffold_structure_sisu.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xml_scaffold_structure_sisu.rb"
+# <<sisu_document_header>>
+module SiSU_XML_Scaffold_Structure_Sisu
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+    include SiSU_Particulars
+  require_relative 'ao'                                 # ao.rb
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  class Source
+    def initialize(opt)
+      @opt=opt
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+    end
+    def spaces
+      Ax[:spaces]
+    end
+    def read
+      begin
+        @md,@ao_array=@particulars.md,@particulars.ao_array
+        SiSU_XML_Scaffold_Structure_Sisu::Source::Scroll.new(@ao_array,@md).songsheet
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+      end
+    end
+    private
+    class Scroll <Source
+      def initialize(data='',md='')
+        @data,@md=data,md
+      end
+      def songsheet
+        @t='sisu'
+        data=@data
+        if @md.opt.act[:verbose_plus][:set]==:on
+          structure_sisu_simple(data)
+        end
+        structure_build_sisu(data)
+      end
+      def tags
+        def sisu
+          [ '0',
+            'A',
+            'B',
+            'C',
+            '1',
+            '2',
+            '3'
+          ]
+        end
+        self
+      end
+      def structure_sisu_simple(data)
+        puts "\nsisu structure, heading outline --->\n\n"
+        data.each_with_index do |o,i|
+          if  (o.is ==:heading || o.is ==:heading_insert)
+            puts "#{spaces*o.ln}<#{tags.sisu[o.ln]}>[#{o.ocn}] #{o.ln} #{o.obj}</#{tags.sisu[o.ln]}>"
+          end
+        end
+      end
+      def output(o,lev=nil,comment='')
+         puts lev == (0..6) \
+         ? "#{spaces*lev}<#{lev}>[#{o.ocn}] #{o.ln} #{o.obj}</#{lev}>#{comment}"
+         : "<#{lev}>[#{o.ocn}] #{o.ln} #{o.obj}</#{lev}>#{comment}"
+      end
+      def structure_build_sisu(data)
+        @s=tags.sisu
+        puts "\nXML [#{@t} type] structure outline --->\n\n"
+        h=[0,false,false,false]
+        puts "<#{@s[0]}>"
+        data.each_with_index do |o,i|
+          if  (o.is ==:heading || o.is ==:heading_insert)
+            structure_build_tag_close(o.ln,h)
+            puts "#{spaces*o.ln}<#{@s[o.ln]}>\n#{spaces*o.ln}  [#{o.ocn}] #{o.ln} {#{o.node}}"
+            case o.ln
+            when 1
+              h=[o.ln,true,false,false]
+            when 2
+              h=[o.ln,true,true,false]
+            when 3
+              h=[o.ln,true,true,true]
+            when 4..6
+              h[0]=o.ln
+            end
+          end
+        end
+        structure_build_tag_close(0,h)
+      end
+      def structure_build_tag_close(lev,h)
+        case h[0]
+        when 1
+          puts "#{spaces*1}</#{@s[1]}>" if (lev <= 1) && h[1]
+          puts "</#{@s[0]}>"         if (lev==0)
+        when 2
+          puts "#{spaces*2}</#{@s[2]}>" if (lev <= 2) && h[2]
+          puts "#{spaces*1}</#{@s[1]}>" if (lev <= 1) && h[1]
+          puts "</#{@s[0]}>"         if (lev==0)
+        when 3
+          puts "#{spaces*3}</#{@s[3]}>" if (lev <= 3) && h[3]
+          puts "#{spaces*2}</#{@s[2]}>" if (lev <= 2) && h[2]
+          puts "#{spaces*1}</#{@s[1]}>" if (lev <= 1) && h[1]
+          puts "</#{@s[0]}>"         if (lev==0)
+        when 4
+          puts "#{spaces*4}</#{@s[4]}>" if (lev <= 4)
+          puts "#{spaces*3}</#{@s[3]}>" if (lev <= 3) && h[3]
+          puts "#{spaces*2}</#{@s[2]}>" if (lev <= 2) && h[2]
+          puts "#{spaces*1}</#{@s[1]}>" if (lev <= 1) && h[1]
+          puts "</#{@s[0]}>"         if (lev==0)
+        when 5
+          puts "#{spaces*5}</#{@s[5]}>" if (lev <= 5)
+          puts "#{spaces*4}</#{@s[4]}>" if (lev <= 4)
+          puts "#{spaces*3}</#{@s[3]}>" if (lev <= 3) && h[3]
+          puts "#{spaces*2}</#{@s[2]}>" if (lev <= 2) && h[2]
+          puts "#{spaces*1}</#{@s[1]}>" if (lev <= 1) && h[1]
+          puts "</#{@s[0]}>"         if (lev==0)
+        when 6
+          puts "#{spaces*6}</#{@s[6]}>" if (lev <= 6)
+          puts "#{spaces*5}</#{@s[5]}>" if (lev <= 5)
+          puts "#{spaces*4}</#{@s[4]}>" if (lev <= 4)
+          puts "#{spaces*3}</#{@s[3]}>" if (lev <= 3) && h[3]
+          puts "#{spaces*2}</#{@s[2]}>" if (lev <= 2) && h[2]
+          puts "#{spaces*1}</#{@s[1]}>" if (lev <= 1) && h[1]
+          puts "</#{@s[0]}>"         if (lev==0)
+        end
+      end
+    end
+  end
+end
+__END__
+@s=['0',
+  'A',
+  'B',
+  'C',
+  '1',
+  '2',
+  '3'
+]
+#@t='docbook'         #@t='fictionbook'
+#@s=['book',          #@s=['body',
+#  'part',            #  'section',
+#  'subpart N/A',     #  'section',
+#  'sub-subpart N/A', #  'section',
+#  'chapter',         #  'section',
+#  'sect1',           #  'section',
+#  'sect2'            #  'section'
+#]                    #]
+#+END_SRC
+
+* odf
+** xml_odf_odt.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xml_odf_odt.rb"
+# <<sisu_document_header>>
+module SiSU_XML_ODF_ODT
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+    include SiSU_Particulars
+  require_relative 'ao'                                 # ao.rb
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'xml_parts'                          # xml_parts.rb
+  require_relative 'xml_odf_odt_format'                 # xml_odf_odt_format.rb
+    include SiSU_XML_ODF_ODT_Format
+  require_relative 'shared_metadata'                    # shared_metadata.rb
+  require_relative 'txt_shared'                         # txt_shared.rb
+  require_relative 'xml_shared'                         # xml_shared.rb
+    include SiSU_XML_Munge
+  require_relative 'xml_persist'                        # xml_persist.rb
+  @@alt_id_count,@@alt_id_count=0,0
+  class Source
+    begin
+      require 'zlib'
+      require 'find'
+    rescue LoadError
+      SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+        error('zlib or find NOT FOUND (LoadError)')
+    end
+    def initialize(opt)
+      @opt=opt
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+      @@endnotes_para=[]
+    end
+    def read
+      begin
+        @md,@env,@ao_array=@particulars.md,@particulars.env,@particulars.ao_array
+        unless  @opt.act[:quiet][:set]==:on
+          tool=(@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on) \
+          ? "#{@env.program.odf_viewer} file://#{@md.file.output_path.odt.dir}/#{@md.file.base_filename.odt}"
+          : "[#{@opt.f_pth[:lng_is]}] #{@opt.fno}"
+          (@opt.act[:verbose][:set]==:on \
+          || @opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on) \
+          ? SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'Opendocument (ODF:ODT)',
+              tool
+            ).green_hi_blue
+          : SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              'Opendocument (ODF:ODT)',
+              tool
+            ).green_title_hi
+          if (@opt.act[:verbose_plus][:set]==:on \
+          || @opt.act[:maintenance][:set]==:on)
+            SiSU_Screen::Ansi.new(
+              @opt.act[:color_state][:set],
+              @opt.fns,
+              'file://' \
+              + @md.file.output_path.odt.dir + '/' \
+              + @md.file.base_filename.odt
+            ).flow
+          end
+        end
+        SiSU_XML_ODF_ODT::Source::Scroll.new(@particulars).songsheet
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        Dir.chdir(@opt.f_pth[:pth])
+      end
+    end
+    private
+    class Scroll <Source
+      require_relative 'txt_shared'                     # txt_shared.rb
+      include SiSU_Parts_XML
+      @@img_count=0
+      @@docstart=true
+      @@fns=nil
+      def initialize(particulars)
+        @md,@env,@ao_array=particulars.md,particulars.env,particulars.ao_array
+        @make=SiSU_Env::ProcessingSettings.new(@md)
+        @tab="\t"
+        @br=(@md.opt.act[:maintenance][:set]==:on) \
+        ? '' : ''
+      end
+      def songsheet
+        begin
+          @per=SiSU_XML_Persist::Persist.new
+          pre
+          @data=markup(@ao_array)
+          publish
+        ensure
+          SiSU_XML_Persist::Persist.new.persist_init
+          unless (@md.opt.act[:verbose_plus][:set]==:on \
+          || @md.opt.act[:maintenance][:set]==:on)
+            if @env.processing_path.odt =~/od[ft]/
+              #p "rm -r #{@env.processing_path.odt}" if @md.opt.selections.str =~/v/
+              FileUtils::rm_r(@env.processing_path.odf_pth)
+              #system("rm -r #{@env.processing_path.odt}")
+            end
+          end
+        end
+      end
+      def break_line
+        (@md.opt.act[:maintenance][:set]==:on) \
+        ? "\n" : ''
+      end
+      # Used for extraction of endnotes from paragraphs
+      def extract_endnotes(dob='')
+        notes=dob.obj.scan(/#{Mx[:en_a_o]}(\d+\s+.+?)#{Mx[:en_a_c]}/)[1] #FIX
+        @n=[]
+        notes.each do |n| #high cost to deal with <br> appropriately within odf, consider
+          n=n.dup.to_s
+          if n =~/#{Mx[:br_line]}/
+            fix=n.split(/#{Mx[:br_line]}/) #watch #added
+            fix.each do |x|
+              if x =~/\S+/ then @n << x
+              end
+            end
+          else                  @n << n
+          end
+        end
+      end
+      def odf_book_idx
+      if @md.book_idx
+        idx_arr=[]
+        idx_raw=SiSU_Particulars::CombinedSingleton.
+          instance.get_idx_raw(@md.opt).raw_idx
+        idx_raw.each do |x|
+          x=if x.is_a?(String)
+            SiSU_XML_ODF_ODT_Format::FormatBookIndex.new(x).
+              book_idx_bookmark
+          else nil
+          end
+          idx_arr << x.strip if x.is_a?(String)
+        end
+        @per.book_idx=idx_arr.join
+      end
+      end
+      def odf_metadata
+        @per.metadata=SiSU_Metadata::Summary.new(@md).
+          odf.metadata
+      end
+      def odf_tail
+        manifest="#{@md.file.output_path.manifest.url}/#{@md.file.base_filename.manifest}"
+        @per.tail << %{<text:p text:style-name="P_normal">Available document outputs: <br /> &lt;<text:a xl:type="simple" xl:href="#{manifest}">#{manifest}</text:a>&gt;</text:p>}
+        @per.tail << %{\n<text:p text:style-name="P_normal">SiSU: &lt;<text:a xl:type="simple" xl:href="http://www.jus.uio.no/lm">www.jus.uio.no/sisu</text:a>&gt; and &lt;<text:a xl:type="simple" xl:href="http://www.sisudoc.org">www.sisudoc.org</text:a>&gt;</text:p>}
+        @per.tail << "\n</office:text></office:body></office:document-content>"
+      end
+      def set_bookmark_tag(dob)
+        SiSU_XML_ODF_ODT_Format::Tags.new.set_bookmark_tag(dob)
+      end
+      def heading(dob,p_num)
+        dob=footnote(dob)
+        m=/#{$1}/
+        breakpage=''
+        if @md.fns \
+        and @md.fns != '' \
+        and @md.fns !=@@fns
+          @@docstart=true
+          @@fns=@md.fns
+        end
+        unless @@docstart
+          breakpage=if (@md.pagenew || @md.pagebreak) \
+          and (@md.pagenew.to_s =~m \
+            or @md.pagebreak.to_s =~m)
+            '<text:p text:style-name="P_normal_page_new"> </text:p>'
+          elsif @md.pageline \
+          and @md.pageline =~m #fix
+          else ''
+          end
+        end
+        @@docstart=false
+        if dob.use_ != :dummy
+          dob.tmp=dob.obj
+          dob.obj=%{#{breakpage}<text:h text:style-name="H_#{dob.ln}" text:outline-level="#{dob.ln}">} \
+          + %{#{p_num[:set_ref]}#{set_bookmark_tag(dob)}#{dob.obj}#{p_num[:display]}</text:h>}
+        else dob.tmp,dob.obj='',''
+        end
+        dob
+      end
+      def toc(dob,p_num)
+        hardspace=(dob.lv =~/[A-D]/i) \
+        ? '<text:p text:style-name="Standard"/>'
+        : ''
+        toc_heading=dob.ocn \
+        ? (%{<text:bookmark-ref text:reference-format="text" text:ref-name="#{dob.ocn}">} \
+          + %{#{dob.tmp}</text:bookmark-ref>})
+        : dob.tmp
+        dob.obj=%{<text:h text:style-name="H_#{dob.ln}" text:outline-level="#{dob.ln}">} \
+        + %{#{toc_heading}</text:h>#{hardspace}}
+        dob
+      end
+      def image_src(i)
+        if @md.fns =~/\.ss[tm]$/ \
+        and FileTest.file?("#{@env.path.image_source_include(@md)}/#{i}") #review
+          @env.path.image_source_include(@md)
+        elsif @md.opt.f_pth[:pth] =~/\/\S+?\/sisupod\/\S+?\/sisupod\/doc/
+          pt=/(\/\S+?\/sisupod\/\S+?\/sisupod)\/doc/.match(@md.opt.f_pth[:pth])[1]
+          img_src=pt + '/image'
+          if FileTest.file?("#{img_src}/#{i}")
+            img_src
+          else
+            SiSU_Screen::Ansi.new(
+              @md.opt.act[:color_state][:set],
+              "ERROR - image:",
+              %{"#{i}" missing},
+              "search locations: #{@env.path.image_source_include_local}," \
+              + "#{@env.path.image_source_include_remote} and" \
+              + "#{@env.path.image_source_include}"
+            ).error2 unless @md.opt.act[:quiet][:set]==:on
+            nil
+          end
+        elsif @md.fns =~/\.ss[tm]$/ \
+        and FileTest.file?("#{@env.path.image_source_include_local}/#{i}") #review
+          @env.path.image_source_include_local
+        elsif @md.fns =~/\.ss[tm]$/ \
+        and FileTest.file?("#{@env.path.image_source_sisu_includes(@md)}/#{i}")
+          @env.path.image_source_sisu_includes(@md)
+        elsif @md.fns =~/\.-ss[tm]$/ \
+        and FileTest.file?("#{@env.path.image_source_include_remote}/#{i}")
+          @env.path.image_source_include_remote
+        else
+          SiSU_Screen::Ansi.new(
+            @md.opt.act[:color_state][:set],
+            "ERROR - image:",
+              %{"#{i}" missing},
+              "search locations: " \
+              + @env.path.image_source_include_local + ',' \
+              + @env.path.image_source_include_remote + 'and' \
+              + @env.path.image_source_include \
+              + @md.opt.sisu_data_dir?
+          ).error2 unless @md.opt.act[:quiet][:set]==:on
+          nil
+        end
+      end
+      def image_odf(img)
+        # copy image to od image directory (unless exists)
+        # divide pixel dimension by 37.79485 and retain 3 decimal places
+        m=img[1]
+        i=/^(\S+?\.(?:png|jpg|gif))/.match(m).captures.join \
+          if m =~/^(\S+?\.(?:png|jpg|gif))/
+        c=/^\S+?\.(?:png|jpg|gif)\s+.+?"(.*?)"/.match(m).captures.join \
+          if m =~/^\S+?\.(?:png|jpg|gif)\s+.+?"(.*?)"/
+        w,h=/\s(\d+)x(\d+)/.match(m).captures if m =~/\s\d+x\d+/
+        w=(w.to_i/37.79485).to_s
+        h=(h.to_i/37.79485).to_s
+        h=/([0-9]+\.\d{0,3})/.match(h).captures.join
+        w=/([0-9]+\.\d{0,3})/.match(w).captures.join
+        image_source=image_src(i)
+        if image_source
+          if FileTest.file?("#{image_source}/#{i}")
+            FileUtils::cp(
+              "#{image_source}/#{i}",
+              "#{@env.processing_path.odt}/Pictures/#{i}"
+            )
+          else STDERR.puts %{\t*WARN* did not find image - "#{image_source}/#{i}" [#{__FILE__}:#{__LINE__}]}
+          end
+        end
+        img=if i.to_s =~/jpg|png|gif/ \
+        and h.to_s =~/\d/ \
+        and w.to_s =~/\d/
+          @@img_count +=1
+          %{<draw:frame draw:style-name="fr1" draw:name="graphics#{@@img_count}" text:anchor-type="as-char" svg:width="#{w}cm" svg:height="#{h}cm" draw:z-index="2"><draw:image xl:href="Pictures/#{i}" xl:type="simple" xl:show="embed" xl:actuate="onLoad"/></draw:frame>#{c}} #anchor-type: as-char or paragraph or char or ...
+        else %{<text:p text:style-name="P_normal">[image omitted]</text:p>}
+        end
+      end
+      def image(dob)
+        m=if dob.obj =~/#{Mx[:lnk_o]}[ ]*(.+?)[ ]*#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/
+          dob.obj.scan(/(#{Mx[:lnk_o]}[ ]*(.+?)[ ]*#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]})/)
+        elsif dob.obj =~/#{Mx[:lnk_o]}[ ]*(.+?)[ ]*#{Mx[:lnk_c]}image/
+          dob.obj.scan(/(#{Mx[:lnk_o]}[ ]*(.+?)[ ]*#{Mx[:lnk_c]}(image))/)
+        else nil
+        end
+        if m then m.each do |i|
+            cont,url=i[1],i[2]
+            cont=cont.gsub(/([)(\]\[])/,"\\\\\\1").
+              gsub(/([+?])/,"\\\\\\1") # incorrect handling of +
+            url=url.gsub(/([+?])/,"\\\\\\1")
+            dob.obj=dob.obj.sub(/#{Mx[:lnk_o]}[ ]*#{cont}[ ]*#{Mx[:lnk_c]}image/m,image_odf(i)).
+              sub(/#{Mx[:lnk_o]}[ ]*#{cont}[ ]*#{Mx[:lnk_c]}#{Mx[:url_o]}#{url}#{Mx[:url_c]}/m,image_odf(i)).
+              sub(/\\([)(\]\[?])/,'\1') #clumsy fix
+          end
+          m=nil
+        end
+        dob
+      end
+      def text_link_odf(txt,url,trail)
+        txt=txt.gsub(/(\\\+)/,'+') #this is convoluted, and risky :-(
+        url=url.gsub(/(\\\+)/,'+') #this is convoluted, and risky :-(
+        map_nametags=SiSU_Particulars::CombinedSingleton.
+          instance.get_map_nametags(@md).nametags_map
+        t=case url
+        when /^https?:/
+          %{<text:a xl:type="simple" xl:href="#{url}">#{txt.strip}</text:a>#{trail}}
+        when /^:/                 # site same document collection html link
+          url=url.gsub(/^:/,"#{@env.url.root}/")
+          %{<text:a xl:type="simple" xl:href="#{url}">#{txt.strip}</text:a>#{trail}}
+        when /^\.\.\//                 # site same document collection html link
+          url=url.gsub(/^\.\.\//,"#{@env.url.root}/")
+          %{<text:a xl:type="simple" xl:href="#{url}">#{txt.strip}</text:a>#{trail}}
+        else                           # document internal link
+          if map_nametags[url] \
+          and map_nametags[url][:segname]
+          else p "NOT FOUND name_tags: #{url}"
+          end
+          t=map_nametags[url] \
+          && map_nametags[url][:segname] \
+          ? (%{<text:a xl:type="simple" xl:href="#{@env.url.root}/#{@md.fnb}/#{map_nametags[url][:segname]}#{Sfx[:html]}##{url}">} \
+            + %{#{txt.strip}</text:a>#{trail}})
+          : %{#{txt.strip}#{trail}}
+        end
+        t
+      end
+      def text_link_odf_bookmark(txt,url,trail)
+        SiSU_Particulars::CombinedSingleton.instance.get_map_nametags(@md).nametags_map
+        %{<text:bookmark-ref text:reference-format="text" text:ref-name="#{url}">#{txt.strip}</text:bookmark-ref>#{trail}}
+      end
+      def text_link(dob)
+        m=dob.obj.scan(/(#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]})/) #sort
+        if m
+          m.each do |i|
+            txt,url,trail=i[1],i[2]
+            txt=txt.gsub(/([)(\]\[])/,"\\\\\\1").
+              gsub(/([+?*])/,"\\\\\\1") # problems with +
+            url=url.gsub(/([+?])/,"\\\\\\1") # problems with +
+            dob.obj=dob.obj.gsub(/#{Mx[:lnk_o]}[ ]*#{txt}#{Mx[:lnk_c]}#{Mx[:url_o]}#{url}#{Mx[:url_c]}/m,
+                text_link_odf(txt,url,trail)). #make sure trailing ']' are not caught in url
+              gsub(/\\([)(\]\[?])/,'\1') #clumsy fix
+          end
+          m=nil
+        end
+        dob
+      end
+      def text_link_relative(dob)
+        m=dob.obj.scan(/(#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}(\S+?)#{Mx[:rel_c]})/) #sort
+        if m
+          m.each do |i|
+            txt,url,trail=i[1],i[2]
+            txt=txt.gsub(/([)(\]\[])/,"\\\\\\1").
+              gsub(/([+?*])/,"\\\\\\1") # problems with +
+            url=url.gsub(/([+?])/,"\\\\\\1") # problems with +
+            dob.obj=dob.obj.gsub(/#{Mx[:lnk_o]}[ ]*#{txt}#{Mx[:lnk_c]}#{Mx[:rel_o]}#{url}#{Mx[:rel_c]}/m,
+                text_link_odf_bookmark(txt,url,trail)). #make sure trailing ']' are not caught in url
+              gsub(/\\([)(\]\[?])/,'\1') #clumsy fix
+          end
+          m=nil
+        end
+        dob
+      end
+      def text_link_relative_(dob)
+        m=dob.obj.scan(/(#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}(\S+?)#{Mx[:rel_c]})/) #sort
+        if m
+          m.each do |i|
+            txt,url,trail=i[1],i[2]
+            txt=txt.gsub(/([)(\]\[])/,"\\\\\\1")
+            dob.obj=dob.obj.gsub(/#{Mx[:lnk_o]}[ ]*#{txt}#{Mx[:lnk_c]}#{Mx[:rel_o]}#{url}#{Mx[:rel_c]}/m,
+                text_link_odf(txt,url,trail)). #make sure trailing ']' are not caught in url
+              gsub(/\\([)(\]\[?])/,'\1') #clumsy fix
+          end
+          m=nil
+        end
+        dob
+      end
+      def normal(dob,p_num)                                                           #P1 - P3
+        dob=footnote(dob)
+        dob.obj=dob.obj.gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,
+            '<text:a xl:type="simple" xl:href="\1">\1</text:a>'). #http ftp matches escaped, no decoration
+          gsub(/#{Mx[:url_o]}([a-zA-Z0-9._-]+\@\S+?\.[a-zA-Z0-9._-]+)#{Mx[:url_c]}/,
+            %{#{the_url_decoration.xml_open}<text:a xl:type="simple" xl:href="mailto:\\1">\\1</text:a>#{the_url_decoration.xml_close}}).
+          gsub(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,
+            %{#{the_url_decoration.xml_open}<text:a xl:type="simple" xl:href="\\1">\\1</text:a>#{the_url_decoration.xml_close}}) #http ftp matches with decoration
+        dob.obj= if dob.is==:para \
+        and dob.indent.to_s =~/[0-9]/ \
+        and dob.indent == dob.hang
+          %{<text:p text:style-name="P_indent_#{dob.indent}">#{p_num[:set_ref]}#{set_bookmark_tag(dob)}#{dob.obj}#{p_num[:display]}</text:p>}
+        elsif dob.is==:para \
+        and dob.hang.to_s =~/[0-9]/ \
+        and dob.indent != dob.hang
+          %{<text:p text:style-name="P_h#{dob.hang}_i#{dob.indent}">#{p_num[:set_ref]}#{set_bookmark_tag(dob)}#{dob.obj}#{p_num[:display]}</text:p>}
+        else %{<text:p text:style-name="P_normal">#{p_num[:set_ref]}#{set_bookmark_tag(dob)}#{dob.obj}#{p_num[:display]}</text:p>}
+        end
+        dob
+      end
+      def fontface(dob)
+      end
+      def footnote_urls(str)
+        str=str.gsub(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,
+          %{#{the_url_decoration.xml_open}<text:a xl:type="simple" xl:href="\\1">\\1</text:a>#{the_url_decoration.xml_close}})
+        str=text_link(str) if str =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/
+        str=text_link_relative(str) if str =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}/
+        str
+      end
+      def footnote(t_o)
+        str=if defined? t_o.obj then t_o.obj
+        elsif t_o.is_a?(String) then t_o
+        end
+        if str
+          @astx||=10000
+          @astxs||=20000
+          if str =~/#{Mx[:en_a_o]}\d+\s+/
+            str=str.gsub(/#{Mx[:en_a_o]}(\d+)\s+(.+?)#{Mx[:en_a_c]}/,
+              '<text:note text:id="ftn\1" text:note-class="footnote"><text:note-citation>\1</text:note-citation><text:note-body><text:p text:style-name="Footnote"> \2</text:p><text:p text:style-name="Footnote"/></text:note-body></text:note>')
+          end
+          if str =~/#{Mx[:en_a_o]}([*]+)\s+/
+            a=$1.gsub(/([*])/,"\\\\\\1")
+              str=str.gsub(/#{Mx[:en_a_o]}([*]+)\s+(.+?)#{Mx[:en_a_c]}/,
+                %{<text:note text:id="ftn#{@astx.to_s}" text:note-class="footnote"><text:note-citation text:label="\\1">\\1</text:note-citation><text:note-body><text:p text:style-name="Footnote"> \\2</text:p><text:p text:style-name="Footnote"/></text:note-body></text:note>})
+              @astxs+=1
+          end
+          if str=~/#{Mx[:en_a_o]}[*+]+\s/
+            asterisk=str.scan(/#{Mx[:en_a_o]}([*+]+)\s+(.+?)#{Mx[:en_a_c]}/)
+            asterisk.each do |x|
+              a=x[0].gsub(/([*+])/,"\\\\\\1")
+              str=group_clean(str)
+              str=footnote_urls(str)
+              str=str.gsub(/#{Mx[:en_a_o]}(#{a})\s+(.+?)#{Mx[:en_a_c]}/,
+                %{<text:note text:id="ftn#{@astx.to_s}" text:note-class="footnote"><text:note-citation text:label="\\1">\\1</text:note-citation><text:note-body><text:p text:style-name="Footnote"> \\2</text:p><text:p text:style-name="Footnote"/></text:note-body></text:note>})
+              @astx+=1
+            end
+          end
+          if str=~/#{Mx[:en_b_o]}[*+]\d+\s/
+            asterisk=str.scan(/#{Mx[:en_b_o]}([*+]\d+)\s+(.+?)#{Mx[:en_b_c]}/)
+            asterisk.each do |x|
+              a=x[0].gsub(/([*+])/,"\\\\\\1")
+              str=group_clean(str)
+              str=footnote_urls(str)
+              str=str.gsub(/#{Mx[:en_b_o]}(#{a})\s+(.+?)#{Mx[:en_b_c]}/,
+                %{<text:note text:id="ftn#{@astx.to_s}" text:note-class="footnote"><text:note-citation text:label="\\1">\\1</text:note-citation><text:note-body><text:p text:style-name="Footnote"> \\2</text:p><text:p text:style-name="Footnote"/></text:note-body></text:note>})
+              @astx+=1
+            end
+          end
+        end
+        if defined? t_o.obj     then t_o.obj=str
+        elsif t_o.is_a?(String) then t_o=str
+        end
+        t_o
+      end
+      def group_clean(str)
+        str=str.gsub(/&amp;nbsp;|&nbsp;|#{Mx[:nbsp]}/,'&#160;').
+          gsub(/</,'&lt;').gsub(/>/,'&gt;').
+          gsub(/&lt;(text:span text:style-name="Span_\S+?"|\/text:span)&gt;/,'<\1>'). #works, not ideal
+          gsub(/#{Mx[:br_line]}/,'<br />').
+          gsub(/&lt;br(?:\s+\/)?&gt;/,'<br />')
+      end
+      def poem(dob,p_num)                                                             #P4 #same as group
+        parray=[]
+        dob.obj.split(/#{Mx[:br_line]}|#{Mx[:br_nl]}/).each_with_index do |parablock,i|
+          set_ref=(i==0) ? "#{p_num[:set_ref]}#{set_bookmark_tag(dob)}" : ''
+          parablock=group_clean(parablock)
+          parablock=footnote(parablock)
+          parray << %{<text:p text:style-name="P_group">#{set_ref}#{parablock}</text:p>} if parablock =~/\S+/
+        end
+        dob.obj=parray.join \
+        + %{<text:p text:style-name="P_group">#{p_num[:display]}</text:p>} \
+        + '<text:p text:style-name="Standard"/>'
+        dob
+      end
+      def group(dob,p_num)                                                            #P4 #same as verse
+        parray=[]
+        dob.obj=dob.obj.gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,
+            '<text:a xl:type="simple" xl:href="\1">\1</text:a>'). #http ftp matches escaped, no decoration
+          gsub(/#{Mx[:url_o]}([a-zA-Z0-9._-]+\@\S+?\.[a-zA-Z0-9._-]+)#{Mx[:url_c]}/,
+            %{#{the_url_decoration.xml_open}<text:a xl:type="simple" xl:href="mailto:\\1">\\1</text:a>#{the_url_decoration.xml_close}}).
+          gsub(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,
+            %{#{the_url_decoration.xml_open}<text:a xl:type="simple" xl:href="\\1">\\1</text:a>#{the_url_decoration.xml_close}}) #http ftp matches with decoration
+        dob.obj.split(/#{Mx[:br_line]}|#{Mx[:br_nl]}/).each_with_index do |parablock,i|
+          set_ref=(i==0) ? "#{p_num[:set_ref]}#{set_bookmark_tag(dob)}" : ''
+          parablock=group_clean(parablock)
+          parablock=parablock.gsub(/&lt;text:a xl:type="simple" xl:href="(.+?)"&gt;/m,
+              '<text:a xl:type="simple" xl:href="\1">').
+            gsub(/&lt;(\/text:a)&gt;/,'<\1>').
+            gsub(/&lt;(text:note text:id=.+?)&gt;/,'<\1>').
+            gsub(/&lt;(text:p text:style-name="Footnote")&gt;/,'<\1>').
+            gsub(/&lt;(\/?text:(?:note-citation|note-body|note|p))&gt;/,'<\1>')
+          parablock=footnote(parablock)
+          parray << %{<text:p text:style-name="P_group">#{set_ref}#{parablock}</text:p>} if parablock =~/\S+/
+        end
+        dob.obj=parray.join \
+        + %{<text:p text:style-name="P_group">#{p_num[:display]}</text:p>} \
+        + '<text:p text:style-name="Standard"/>'
+        dob
+      end
+      def block(dob,p_num)                                                            #P4 #same as verse
+        parray=[]
+        dob.obj=dob.obj.gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,
+            '<text:a xl:type="simple" xl:href="\1">\1</text:a>'). #http ftp matches escaped, no decoration
+          gsub(/#{Mx[:url_o]}([a-zA-Z0-9._-]+\@\S+?\.[a-zA-Z0-9._-]+)#{Mx[:url_c]}/,
+            %{#{the_url_decoration.xml_open}<text:a xl:type="simple" xl:href="mailto:\\1">\\1</text:a>#{the_url_decoration.xml_close}}).
+          gsub(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,
+            %{#{the_url_decoration.xml_open}<text:a xl:type="simple" xl:href="\\1">\\1</text:a>#{the_url_decoration.xml_close}}) #http ftp matches with decoration
+        dob.obj.split(/#{Mx[:br_line]}|#{Mx[:br_nl]}/).each_with_index do |parablock,i|
+          set_ref=(i==0) ? "#{p_num[:set_ref]}#{set_bookmark_tag(dob)}" : ''
+          parablock=group_clean(parablock)
+          parablock=parablock.gsub(/&lt;text:a xl:type="simple" xl:href="(.+?)"&gt;/m,
+              '<text:a xl:type="simple" xl:href="\1">').
+            gsub(/&lt;(\/text:a)&gt;/,'<\1>').
+            gsub(/&lt;(text:note text:id=.+?)&gt;/,'<\1>').
+            gsub(/&lt;(text:p text:style-name="Footnote")&gt;/,'<\1>').
+            gsub(/&lt;(\/?text:(?:note-citation|note-body|note|p))&gt;/,'<\1>')
+          parablock=footnote(parablock)
+          parray << %{<text:p text:style-name="P_group">#{set_ref}#{parablock}</text:p>} \
+            if parablock =~/\S+/
+        end
+        dob.obj=parray.join \
+        + %{<text:p text:style-name="P_group">#{p_num[:display]}</text:p>} \
+        + '<text:p text:style-name="Standard"/>'
+        dob
+      end
+      def code(dob,p_num)                                                             #P5
+        if dob.is==:code
+          dob.obj=dob.obj.gsub(/\s\s/,'&#160;&#160;')
+          parray=[]
+          dob.obj.split(/#{Mx[:br_line]}|#{Mx[:br_nl]}/).each_with_index do |parablock,i|
+            set_ref=(i==0) ? "#{p_num[:set_ref]}#{set_bookmark_tag(dob)}" : ''
+            parablock=group_clean(parablock)
+            parablock=parablock.gsub(/^\s*$/,'<br />').
+              gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,
+                '<text:a xl:type="simple" xl:href="\1">\1</text:a>') #http ftp matches escaped, no decoration
+            parray << %{<text:p text:style-name="P_code">#{set_ref}#{parablock}</text:p>} if parablock =~/\S+/
+          end
+          dob.obj=parray.join \
+          + %{<text:p text:style-name="P_group">#{p_num[:display]}</text:p>} \
+          + '<text:p text:style-name="Standard"/>'
+        end
+        dob
+      end
+      def table(dob,p_num)                                                            #
+        if dob.is ==:table
+          dob=footnote(dob) #check
+          table=SiSU_XML_ODF_ODT_Format::Table.new(@md,dob,p_num)
+          dob=table.table
+        end
+        dob
+      end
+      def obj_break(dob)
+        if dob.is ==:break
+          br=SiSU_XML_ODF_ODT_Format::FormatObjBreak.new(@md,dob)
+          if dob.obj==Mx[:br_page] \
+          or dob.obj==Mx[:br_page_new]
+            dob=br.br_page
+          elsif dob.obj==Mx[:br_page_line]
+            dob=br.br_page_line
+          elsif dob.obj==Mx[:br_obj]
+            dob=br.obj_sep
+          end
+        end
+        dob
+      end
+      def odf_structure(md,dob)
+        @md,@dob=md,dob
+        dob=if dob.is !=:code
+          dob=image(dob) if dob.obj =~/#{Mx[:lnk_o]}[ ]*\S+?\.(?:png|jpg|gif)\s.+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|image)/
+          dob=text_link(dob) if dob.obj =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/
+          dob=text_link_relative(dob) if dob.obj =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}/
+          dob
+        else dob
+        end
+        p_num={ display: '', set_ref: '' }
+        if dob.is !~/(^#{Rx[:meta]}|#{Mx[:br_eof]}|#{Mx[:br_endnotes]})/
+          if @make.build.odt_ocn?
+            if defined? dob.ocn \
+            and dob.ocn.is_a?(Integer)
+              p_num=SiSU_XML_ODF_ODT_Format::ParagraphNumber.new(@make,dob.ocn).set_bookmark_and_display
+            end
+          end
+        end
+        if dob.is==:heading
+          @per.body << heading(dob,p_num).obj << break_line*2
+          if SiSU_Env::ProcessingSettings.new(md).build.toc?
+            if dob.lv =~/[A-D1]/i
+              @per.toc << toc(dob,p_num).obj
+            end
+          end
+        elsif dob.is ==:verse
+          @per.body << poem(dob,p_num).obj << break_line*2
+        elsif dob.is==:group
+          @per.body << group(dob,p_num).obj << break_line*2
+        elsif dob.is==:block
+          @per.body << block(dob,p_num).obj << break_line*2
+        elsif dob.is==:code
+          @per.body << code(dob,p_num).obj << break_line*2
+        elsif dob.is==:table #elsif dob.obj =~ /<!Th?¡/u
+          @per.body << table(dob,p_num).obj << break_line*2
+        elsif dob.is==:break
+          @per.body << obj_break(dob).obj << break_line*2
+        else
+          @per.body << normal(dob,p_num).obj << break_line*2 # main text, contents, body KEEP
+        end
+        @@endnotes_para=[]
+      end
+      def tidywords(wordlist)
+        wordlist
+      end
+      def markup(data)                                                                 # Used for major markup instructions
+        #safe_characters=/[^a-zA-Z0-9}{\/?,."';:)(><\-_&!@%~#\]\[*=$| \n+`#{Mx[:tc_p]}]/u
+        dir=SiSU_Env::InfoEnv.new(@md.fns)
+        dir.path.odt_bld
+        @data_mod,@endnotes,@level,@cont,@copen,@odf_contents_close=Array.new(6){[]}
+        @rcdc=false
+        (0..7).each { |x| @cont[x]=@level[x]=false }
+        (4..7).each { |x| @odf_contents_close[x]='' }
+        odf_tail #($1,$2)
+        bullet=image_src('bullet_09.png')
+        if bullet
+          if FileTest.file?("#{bullet}/bullet_09.png")
+            FileUtils::cp("#{bullet}/bullet_09.png","#{@env.processing_path.odt}/Pictures/.")
+          else STDERR.puts %{\t*WARN* did not find image - "#{bullet}/bullet_09.png" [#{__FILE__}:#{__LINE__}]}
+          end
+        end
+        odf_book_idx
+        odf_metadata
+        data.each do |dob|
+          #p dob.obj if dob.obj =~safe_characters and @md.opt.selections.str =~/V/ #KEEP
+          dob.obj='' if dob.obj =~/#{Mx[:lv_o]}\d+:.*?#{Mx[:lv_c]}.+?#{Mx[:pa_non_object_dummy_heading]}/ #fix Mx[:lv_o]
+          para_array=[]
+          dob.obj=dob.obj.gsub(/</,'&lt;').gsub(/>/,'&gt;')
+          word=dob.obj.scan(/\S+|\n/)
+          if word
+            word.each do |w| # _ - / # | : ! ^ ~
+              unless dob.obj =~/^(?:#{Rx[:meta]}|%+ )/m
+                w=w.gsub(/&#(?:126|152);/,'~'). #126 usual
+                  gsub(/&nbsp;/,'&#160;')
+                if w !~/(?:&\S{2,7}?;)+/
+                  w=w.gsub(/&/,'&amp;')
+                end
+                if w !~/&\S{1,7}?;(?:&\S{1,7}?;)+/    #imperfect
+                  w=w.gsub(/(&\S{1,7};)+&/,'\1&amp;')
+                end
+              end
+              para_array << w
+            end
+            dob.obj=para_array.join(' ')
+            dob.obj=dob.obj.strip
+          end
+          if dob.is==:code #{Mx[:gr_o]}code#{Mx[:gr_c]}/ #fix #code-block: angle brackets special characters #fix
+            dob.obj=dob.obj.gsub(/(^|[^}])_(?:<|&lt;)/m,'\1&lt;').gsub(/(^|[^}])_(?:>|&gt;)/m,'\1&gt;').
+              gsub(/(^|[^}])_(?:<|&lt;)/m,'\1&lt;').gsub(/(^|[^}])_(?:>|&gt;)/m,'\1&gt;')
+          end
+          if dob.of==:block
+            dob.obj=dob.obj.gsub(/#{Mx[:gl_bullet]}/,'● ')
+          end
+          dob.obj=dob.obj.gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'<del>\1</del>').
+            gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'<ins>\1</ins>').
+            gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'<cite>\1</cite>').
+            gsub(/#{Mx[:tag_o]}\S+?#{Mx[:tag_c]}/,
+              '<text:bookmark-start text:name="\1"/><text:bookmark-end text:name="\1"/>'). #check
+            gsub(/#{Mx[:mk_o]}#([a-zA-Z]+)#{Mx[:mk_c]}/,'&\1;').
+            gsub(/#{Mx[:mk_o]}(#[0-9]+)#{Mx[:mk_c]}/,'&\1;').
+            gsub(/#{Mx[:mk_o]}[~-]##{Mx[:mk_c]}/,'')
+          if dob.is==:para \
+          and dob.bullet_
+            dob.obj='<draw:frame draw:style-name="gr1" text:anchor-type="as-char" svg:width="0.22cm" svg:height="0.22cm" draw:z-index="2"><draw:image xl:href="Pictures/bullet_09.png" xl:type="simple" xl:show="embed" xl:actuate="onLoad"/></draw:frame> ' +
+              dob.obj
+          end
+          dob.obj=dob.obj.gsub(/#{Mx[:br_line]}/,'<br />').
+            gsub(/&#169;/,'©'). #too arbitrary
+            gsub(/.+?<-#>/,'').                                           # remove dummy headings (used by html) #check
+            gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,
+              '<text:span text:style-name="Span_bold">\1</text:span>').
+            gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,
+              '<text:span text:style-name="Span_italic">\1</text:span>').
+            gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,
+              '<text:span text:style-name="Span_underscore">\1</text:span>').
+            gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,
+              '<text:span text:style-name="Span_superscript">\1</text:span>').
+            gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,
+              '<text:span text:style-name="Span_subscript">\1</text:span>').
+            gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,
+              '<text:span text:style-name="Span_monospace">\1</text:span>').
+            gsub(/­/u,'-').
+            gsub(/ /u, ' ').       # space identify
+            gsub(/ /u, ' ').       # space identify
+            gsub(/·/u,'*').
+            gsub(/[­–—]/u,'-').   #— – chk
+            gsub(/ < /i,'&#060;').
+            gsub(/\\copy(?:right)?\b/,'&#169;').
+            gsub(/\\trademark\b|\\tm\b/,'&#174;').
+            gsub(/\44/,'&#36;'). #$ watch
+            gsub(/<a href=".+?">(.+?)<\/a>/,'\1').
+            gsub(/#{Mx[:mk_o]}name#\S+?#{Mx[:mk_c]}/,'')                                       # remove name links
+          wordlist=dob.obj.scan(/\S+/)
+          dob.obj=tidywords(wordlist).join(' ').strip
+          @rcdc=true if @rcdc==false \
+          and (dob.obj =~/~metadata/ \
+          or dob.obj =~/#{Mx[:lv_o]}1:meta#{Mx[:lv_x]}\s*Document Information/) #fix Mx[:lv_o]
+          if dob.is !~/(^#{Rx[:meta]}|#{Mx[:br_eof]}|#{Mx[:br_endnotes]})/ #check
+            if defined? dob.ocn and dob.ocn.to_s =~/\d+/
+              @p_num=SiSU_XML_ODF_ODT_Format::ParagraphNumber.new(@make,dob.ocn)
+            end
+            if dob.is ==:heading \
+            || dob.is ==:para \
+            || dob.is ==:group \
+            || dob.is ==:verse \
+            || dob.is ==:code \
+            || dob.is ==:table \
+            || dob.is ==:break
+              odf_structure(@md,dob)
+            end
+            if dob.obj ## Clean Prepared Text
+              dob.obj=dob.obj.gsub(/<!.+!>/,' ').
+                gsub(/#{Mx[:tc_o]}.+?#{Mx[:tc_c]}/,' ').
+                gsub(/<:\S+>/,' ')
+            end
+          end
+        end
+      end
+      def pre
+        table=if @md.flag_tables
+          x=<<WOK
+  <style:style style:name="Table1" style:family="table"><style:table-properties style:width="16.999cm" table:align="margins"/></style:style>
+  <style:style style:name="Table1.A" style:family="table-column"><style:table-column-properties style:column-width="16.999cm" style:rel-column-width="65535*"/></style:style>
+  <style:style style:name="Table1.B" style:family="table-column"><style:table-column-properties style:column-width="8.499cm" style:rel-column-width="32767*"/></style:style>
+  <style:style style:name="Table1.C" style:family="table-column"><style:table-column-properties style:column-width="5.666cm" style:rel-column-width="21845*"/></style:style>
+  <style:style style:name="Table1.D" style:family="table-column"><style:table-column-properties style:column-width="4.349cm" style:rel-column-width="16383*"/></style:style>
+  <style:style style:name="Table1.E" style:family="table-column"><style:table-column-properties style:column-width="3.399cm" style:rel-column-width="13107*"/></style:style>
+  <style:style style:name="Table1.F" style:family="table-column"><style:table-column-properties style:column-width="2.833cm" style:rel-column-width="10922*"/></style:style>
+  <style:style style:name="Table1.G" style:family="table-column"><style:table-column-properties style:column-width="2.428cm" style:rel-column-width="9362*"/></style:style>
+  <style:style style:name="Table1.H" style:family="table-column"><style:table-column-properties style:column-width="2.124cm" style:rel-column-width="8191*"/></style:style>
+  <style:style style:name="Table2" style:family="table"><style:table-properties style:width="16.999cm" table:align="margins"/></style:style>
+  <style:style style:name="Table2.A" style:family="table-column"><style:table-column-properties style:column-width="16.999cm" style:rel-column-width="65535*"/></style:style>
+  <style:style style:name="Table2.B" style:family="table-column"><style:table-column-properties style:column-width="8.499cm" style:rel-column-width="32767*"/></style:style>
+  <style:style style:name="Table2.C" style:family="table-column"><style:table-column-properties style:column-width="5.666cm" style:rel-column-width="21845*"/></style:style>
+  <style:style style:name="Table2.D" style:family="table-column"><style:table-column-properties style:column-width="4.349cm" style:rel-column-width="16383*"/></style:style>
+  <style:style style:name="Table2.E" style:family="table-column"><style:table-column-properties style:column-width="3.999cm" style:rel-column-width="13107*"/></style:style>
+  <style:style style:name="Table2.F" style:family="table-column"><style:table-column-properties style:column-width="2.833cm" style:rel-column-width="10922*"/></style:style>
+  <style:style style:name="Table2.G" style:family="table-column"><style:table-column-properties style:column-width="2.428cm" style:rel-column-width="9362*"/></style:style>
+  <style:style style:name="Table2.H" style:family="table-column"><style:table-column-properties style:column-width="2.124cm" style:rel-column-width="8191*"/></style:style>
+  <style:style style:name="Table2.I" style:family="table-column"><style:table-column-properties style:column-width="1.8887cm" style:rel-column-width="7281*"/></style:style>
+  <style:style style:name="Table2.J" style:family="table-column"><style:table-column-properties style:column-width="1.6999cm" style:rel-column-width="6553*"/></style:style>
+  <style:style style:name="Table2.K" style:family="table-column"><style:table-column-properties style:column-width="1.5453cm" style:rel-column-width="5957*"/></style:style>
+  <style:style style:name="Table2.L" style:family="table-column"><style:table-column-properties style:column-width="1.416cm" style:rel-column-width="5461*"/></style:style>
+  <style:style style:name="Table2.M" style:family="table-column"><style:table-column-properties style:column-width="1.307" style:rel-column-width="5041*"/></style:style>
+  <style:style style:name="Table2.N" style:family="table-column"><style:table-column-properties style:column-width="1.214cm" style:rel-column-width="4681*"/></style:style>
+WOK
+          x=x.strip
+          x=x.gsub(/\n+/m,'') unless @md.opt.act[:maintenance][:set]==:on
+          x
+        else ''
+        end
+        x=<<WOK
+<?xml version="1.0" encoding="UTF-8"?>
+<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xl="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2"><office:scripts/>
+<office:font-face-decls><style:font-face style:name="DejaVu Sans Mono" svg:font-family="'DejaVu Sans Mono'" style:font-adornments="Book" style:font-family-generic="modern" style:font-pitch="fixed"/><style:font-face style:name="Inconsolata" svg:font-family="Inconsolata" style:font-adornments="Regular" style:font-pitch="fixed"/><style:font-face style:name="Liberation Mono" svg:font-family="'Liberation Mono'" style:font-adornments="Regular" style:font-family-generic="modern" style:font-pitch="fixed"/><style:font-face style:name="DejaVu Sans" svg:font-family="'DejaVu Sans'" style:font-adornments="ExtraLight" style:font-family-generic="swiss" style:font-pitch="variable"/><style:font-face style:name="Nimbus Sans L" svg:font-family="&apos;Nimbus Sans L&apos;" style:font-pitch="variable"/><style:font-face style:name="Tahoma" svg:font-family="Tahoma, Lucidasans, &apos;Lucida Sans&apos;, &apos;Arial Unicode MS&apos;" style:font-pitch="variable"/><style:font-face style:name="Nimbus Roman No9 L" svg:font-family="&apos;Nimbus Roman No9 L&apos;" style:font-family-generic="roman" style:font-pitch="variable"/><style:font-face style:name="Bitstream Vera Sans" svg:font-family="&apos;Bitstream Vera Sans&apos;" style:font-family-generic="swiss" style:font-pitch="variable"/></office:font-face-decls>
+<office:automatic-styles>
+#{table}
+  <style:style style:name="P_table_cell" style:family="paragraph" style:parent-style-name="Table_Contents"><style:paragraph-properties fo:text-align="justify" style:justify-single-word="false"/></style:style>
+</office:automatic-styles>
+<office:body>
+  <office:text text:use-soft-page-breaks="true">
+    <office:forms form:automatic-focus="false" form:apply-design-mode="false"/>
+    <text:sequence-decls><text:sequence-decl text:display-outline-level="0" text:name="Illustration"/><text:sequence-decl text:display-outline-level="0" text:name="Table"/><text:sequence-decl text:display-outline-level="0" text:name="Text"/><text:sequence-decl text:display-outline-level="0" text:name="Drawing"/></text:sequence-decls>
+WOK
+        x=x.strip
+        x=x.gsub(/\n+/m,'') unless @md.opt.act[:maintenance][:set]==:on
+        @per.head << x
+      end
+      def publish
+        content=[]
+        br_pg='<text:p text:style-name="P_normal_page_new"> </text:p>'
+        content <<
+          @per.head <<
+          @per.toc <<
+          br_pg <<
+          @per.body <<
+          @per.book_idx <<
+          br_pg <<
+          @per.metadata <<
+          @per.tail
+        SiSU_XML_ODF_ODT::Source::Output.new(content,@md,@env).odf
+        @@odf={ head: [], toc: [], body: [], tail: [], book_idx: [], metadata: [] }
+      end
+    end
+    class Output <Source
+      def initialize(content,md,env)
+        @content,@md,@env=content,md,env
+      end
+      def odf                                                           #%odf output
+        env=SiSU_Env::FileOp.new(@md)
+        env.mkdir
+        header=SiSU_XML_ODF_ODT_Format::ODT_Head_1_2.new(@md)
+        filename="#{@env.processing_path.odt}/manifest.rdf"
+        od=File.new(filename,'w+')
+        od << header.manifest_rdf
+        od.close
+        filename="#{@env.processing_path.odt}/META-INF/manifest.xml"
+        od=File.new(filename,'w+')
+        od << header.meta_inf_manifest_xml(@md)
+        od.close
+        filename="#{@env.processing_path.odt}/meta.xml"
+        od=File.new(filename,'w+')
+        od << header.meta_xml
+        od.close
+        filename="#{@env.processing_path.odt}/settings.xml"
+        od=File.new(filename,'w+')
+        od << header.settings_xml
+        od.close
+        filename="#{@env.processing_path.odt}/styles.xml"
+        od=File.new(filename,'w+')
+        od << header.styles_xml
+        od.close
+        filename="#{@env.processing_path.odt}/mimetype"
+        od=File.new(filename,'w+')
+        od << header.mimetype
+        od.close
+        env.make_path(@env.processing_path.odt)
+        env.make_path(@md.file.output_path.odt.dir)
+        filename="#{@env.processing_path.odt}/content.xml"
+        od=File.new(filename,'w+')
+        @content.flatten.compact.each do |para|             # this is a hack, check change does not alter behavior
+          od.puts para unless para =~/\A\s*\Z/
+        end
+        od.close
+        opendoc=@md.file.base_filename.odt #watch where output by language
+        FileUtils::mkdir_p(@md.file.output_path.odt.dir) \
+          unless FileTest.directory?(@md.file.output_path.odt.dir)
+        if FileTest.directory?(@env.processing_path.odt) \
+        and SiSU_Env::SystemCall.new.zip
+          pwd=Dir.pwd
+          Dir.chdir(@env.processing_path.odt)
+          system("
+            zip -qr #{opendoc} *
+          ")
+          FileUtils::mv(opendoc, @md.file.place_file.odt.dir)
+          Dir.chdir(pwd)
+        else
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).mark('*EXITED odf* zip program not found') unless SiSU_Env::SystemCall.new.zip
+        end
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+** xml_odf_odt_format.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xml_odf_odt_format.rb"
+# <<sisu_document_header>>
+module SiSU_XML_ODF_ODT_Format
+  require_relative 'dp'                                 # dp.rb
+    include SiSU_Param
+  class ParagraphNumber
+    def initialize(make,paranum)
+      @make=make
+      @paranum=/(\d+)/m.match(paranum.to_s)[1]
+    end
+    def set_ref_and_display
+      set_ref=@paranum.gsub(/(\d+)/,
+        ' <text:span text:style-name="Span_subscript"><text:reference-mark-start text:name="\1"/><text:reference-mark-end text:name="\1"/></text:span>')
+      disp=@paranum.gsub(/(\d+)/,
+        (@make.build.odt_ocn?) \
+        ? %{ <text:span text:style-name="Span_subscript">#{Dx[:ocn_o]}\\1#{Dx[:ocn_c]}</text:span>}
+        : '')
+      { display: disp, set_ref: set_ref }
+    end
+    def set_bookmark_and_display
+      set_ref=@paranum.gsub(/(\d+)/,
+        ' <text:span text:style-name="Span_subscript"><text:bookmark-start text:name="\1"/><text:bookmark-end text:name="\1"/></text:span>')
+      disp=@paranum.gsub(/(\d+)/,
+        (@make.build.odt_ocn?) \
+        ? %{ <text:span text:style-name="Span_subscript">#{Dx[:ocn_o]}\\1#{Dx[:ocn_c]}</text:span>}
+        : '')
+      { display: disp, set_ref: set_ref }
+    end
+    def name
+      @paranum.gsub(/(\d+)/,'<a name="\1"></a>')
+    end
+    def goto
+      @paranum.gsub(/(\d+)/,'<a href="#\1">')
+    end
+  end
+  class FormatBookIndex
+    def initialize(idx_str)
+      @idx_str=idx_str
+    end
+    def book_idx_bookmark
+      map_nametags=SiSU_Particulars::CombinedSingleton.instance.get_map_nametags(@md).nametags_map #p map_nametags
+      rgx_bookmark=/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:rel_o]}#?\S+?#{Mx[:rel_c]}/m
+      while @idx_str =~/#{Mx[:lnk_o]}([^#{Mx[:lnk_o]}#{Mx[:lnk_c]}]+)#{Mx[:lnk_c]}#{Mx[:rel_o]}#?(\S+?)#{Mx[:rel_c]}/m
+        link,url=$1,$2
+        link,url=link.strip,url.strip
+        @idx_str=@idx_str.gsub(/&/m,"&amp;")
+        ocn_lnk=if map_nametags[url] \
+        and map_nametags[url][:ocn]
+          map_nametags[url][:ocn]
+        else nil
+        end
+        ocn_lnk=(url=~/^\d+$/ ? url : ocn_lnk)
+        if ocn_lnk and not ocn_lnk.empty?
+          @idx_str=@idx_str.sub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,
+              '<text:span text:style-name="Span_bold">\1</text:span>').
+            sub(rgx_bookmark,
+              %{<text:bookmark-ref text:reference-format="text" text:ref-name="#{url}">#{link.strip}</text:bookmark-ref>})
+        else
+          puts %{name tag: "#{url}" not found}
+          @idx_str.sub!(rgx_bookmark,"#{link}")
+        end
+      end
+      @idx_str=@idx_str.gsub(/#{Xx[:protect]}/m,'').
+        sub(/,\s*$/m,'').
+        gsub(/\n/,'')
+      @idx_str='<text:p text:style-name="P_normal">' + @idx_str + '</text:p>'
+    end
+  end
+  class Tags
+    def set_bookmark_tag(dob)
+      tags=''
+      if dob.tags.length > 0
+        dob.tags.each do |tag|
+          tags +=%{ <text:span text:style-name="Span_subscript"><text:bookmark-start text:name="#{tag}"/><text:bookmark-end text:name="#{tag}"/></text:span>}
+        end
+      end
+      tags
+    end
+  end
+  class FormatTextObject
+    def initialize(md,t_o)
+      @md,@t_o=md,t_o
+      if t_o.is_a?(Hash)
+        @txt =t_o[:txt]            || nil
+      else
+        p t_o.class
+        p caller
+      end
+      rgx=/#{Mx[:en_a_o]}\d+\s+(.+?)#{Mx[:en_a_c]}/
+      @txt=@txt.gsub(rgx,'\1') if @txt =~rgx
+    end
+    def scr_endnote_body
+      "<endnote>#{@txt}</endnote> "
+    end
+    def heading_body1
+    end
+    def heading_body2
+    end
+    def heading_body3
+    end
+    def heading_body4
+    end
+    def heading_body5
+    end
+    def heading_body6
+    end
+    def heading_body7
+    end
+  end
+  class Table
+    @@table_counter=0
+    @@tablefoot=[] #watch
+    @@fns=''
+    def initialize(md,dob,p_num)
+      @md,@dob,@p_num=md,dob,p_num
+      @txt=dob.obj
+      if @md.fns != @@fns
+        @@table_counter=0
+        @@fns=@md.fns
+      end
+    end
+    def break_line
+      (@md.opt.act[:maintenance][:set]==:on) \
+      ? "\n" : ''
+    end
+    def table_head_open(count)
+      type=(@dob.head_) \
+      ? 1
+      : 2
+      alpha=case @dob.cols
+      when  1 then 'A'
+      when  2 then 'B'
+      when  3 then 'C'
+      when  4 then 'D'
+      when  5 then 'E'
+      when  6 then 'F'
+      when  7 then 'G'
+      when  8 then 'H'
+      when  9 then 'I'
+      when 10 then 'J'
+      when 11 then 'K'
+      when 12 then 'L'
+      when 13 then 'M'
+      when 14 then 'N'
+      else         'D'
+      end
+      tag=SiSU_XML_ODF_ODT_Format::Tags.new.set_bookmark_tag(@dob)
+      %{<table:table table:name="Table#{count}" table:style-name="Table#{type}">#{@p_num[:set_ref]}#{tag}#{break_line}} +
+      %{<table:table-column table:style-name="Table#{type}.#{alpha}" table:number-columns-repeated="#{@dob.cols}"/>#{break_line}}
+    end
+    def table_close(tablefoot='')
+      '</table:table>' \
+      + %{<text:p text:style-name="P_group">#{@p_num[:display]}</text:p>}
+    end
+    def table_tag_cell(str,i)
+      txt_name_cell=if i==0 \
+      and @dob.head_
+        'Table_Heading'
+      else 'P_table_cell'
+      end
+      str=str.gsub(/^~$/,'') # tilde / empty cell
+      %{<table:table-cell office:value-type="string">#{break_line}} +
+      %{<text:p text:style-name="#{txt_name_cell}">#{break_line}} +
+      %{#{str}} +
+      %{</text:p>#{break_line}} +
+      %{</table:table-cell>#{break_line}}
+    end
+    def table_tag_row(str,i)
+      %{<table:table-row>#{break_line}} +
+      %{#{str}} +
+      %{</table:table-row>#{break_line}}
+    end
+    def table_tag_row_dump(str,i)
+      txt_name_row=if i==0 \
+      and @dob.head_
+        'Table_Heading'
+      else 'P_table_cell'
+      end
+      %{<table:table-row>#{break_line}} +
+      %{<table:table-cell office:value-type="string">#{break_line}} +
+      %{<text:p text:style-name="#{txt_name_row}">#{break_line}} +
+      %{#{str}} +
+      %{</text:p>#{break_line}} +
+      %{</table:table-cell>#{break_line}} +
+      %{</table:table-row>#{break_line}}
+    end
+    def table_row(row,i)
+      row='' if row =~/^<!$/
+      m=row[/<!f(.+?)!>/,1]
+      @@tablefoot << m if m
+      row=row.gsub(/<!f.+?!>/,'')
+      @cells=[]
+      row.split(/\s*#{Mx[:tc_p]}/).each do |cell|
+        @cells << table_tag_cell(cell,i)
+      end
+      row=@cells.join
+      row=table_tag_row(row,i)
+      row
+    end
+    def table
+      @@table_counter+=1
+      table_head_open(@@table_counter)
+      @table=[]
+      @dob.obj.split(/\s*#{Mx[:tc_c]}/).each_with_index do |r,i|
+        @table << table_row(r,i)
+      end
+      @dob.obj= table_head_open(@@table_counter) + @table.join + table_close
+      @dob
+    end
+  end
+  class ODT_Head_1_2
+    def initialize(md)
+      @md=md
+      @generator="#{@md.project_details.project} #{@md.project_details.version} #{@md.project_details.date_stamp} (#{@md.project_details.date})"
+    end
+    def manifest_rdf
+      x=<<WOK
+<?xml version="1.0" encoding="utf-8"?>
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+  <rdf:Description rdf:about="styles.xml">
+    <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/odf#StylesFile"/>
+  </rdf:Description>
+  <rdf:Description rdf:about="">
+    <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="styles.xml"/>
+  </rdf:Description>
+  <rdf:Description rdf:about="content.xml">
+    <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/odf#ContentFile"/>
+  </rdf:Description>
+  <rdf:Description rdf:about="">
+    <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="content.xml"/>
+  </rdf:Description>
+  <rdf:Description rdf:about="">
+    <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#Document"/>
+  </rdf:Description>
+</rdf:RDF>
+WOK
+      x=x.strip
+      x=x.gsub(/\n+/m,'') unless @md.opt.act[:maintenance][:set]==:on
+      x
+    end
+    def meta_inf_manifest_xml(md)
+      images=['  <manifest:file-entry manifest:media-type="" manifest:full-path="Pictures/bullet_09.png"/>']
+      if md.ec[:image].length > 0
+        md.ec[:image].each do |i|
+          images<<<<WOK
+  <manifest:file-entry manifest:media-type="" manifest:full-path="Pictures/#{i}"/>
+WOK
+        end
+      end
+      images=images.join('')
+      x=<<WOK
+<?xml version="1.0" encoding="UTF-8"?>
+<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">
+  <manifest:file-entry manifest:media-type="application/vnd.oasis.opendocument.text" manifest:version="1.2" manifest:full-path="/"/>
+  <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="styles.xml"/>
+  <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="content.xml"/>
+  #{images}
+  <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="meta.xml"/>
+  <manifest:file-entry manifest:media-type="application/rdf+xml" manifest:full-path="manifest.rdf"/>
+  <manifest:file-entry manifest:media-type="image/png" manifest:full-path="Thumbnails/thumbnail.png"/>
+  <manifest:file-entry manifest:media-type="application/binary" manifest:full-path="layout-cache"/>
+  <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="settings.xml"/>
+  <manifest:file-entry manifest:media-type="" manifest:full-path="Configurations2/accelerator/current.xml"/>
+  <manifest:file-entry manifest:media-type="application/vnd.sun.xml.ui.configuration" manifest:full-path="Configurations2/"/>
+</manifest:manifest>
+WOK
+      x=x.strip
+      x=x.gsub(/\n+/m,'') unless @md.opt.act[:maintenance][:set]==:on
+      x
+    end
+    def meta_xml
+      x=<<WOK
+<?xml version="1.0" encoding="UTF-8"?>
+<office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:xl="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:grddl="http://www.w3.org/2003/g/data-view#" office:version="1.2">
+  <office:meta>
+    <meta:generator>#{@generator}</meta:generator>
+    <meta:creation-date>#{@md.generated}</meta:creation-date>
+    <dc:date>#{@md.generated}</dc:date>
+    <dc:language>en-US</dc:language>
+  </office:meta>
+</office:document-meta>
+WOK
+      x=x.strip
+      x=x.gsub(/\n+/m,'') unless @md.opt.act[:maintenance][:set]==:on
+      x
+    end
+    def settings_xml
+      x=<<WOK
+<?xml version="1.0" encoding="UTF-8"?>
+<office:document-settings xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:xl="http://www.w3.org/1999/xlink" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" office:version="1.2">
+  <office:settings>
+    <config:config-item-set config:name="ooo:view-settings">
+      <config:config-item config:name="ViewAreaTop" config:type="int">0</config:config-item>
+      <config:config-item config:name="ViewAreaLeft" config:type="int">0</config:config-item>
+      <config:config-item config:name="ViewAreaWidth" config:type="int">0</config:config-item>
+      <config:config-item config:name="ViewAreaHeight" config:type="int">0</config:config-item>
+      <config:config-item config:name="ShowRedlineChanges" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="InBrowseMode" config:type="boolean">false</config:config-item>
+      <config:config-item-map-indexed config:name="Views">
+        <config:config-item-map-entry>
+          <config:config-item config:name="ViewId" config:type="string">view2</config:config-item>
+          <config:config-item config:name="ViewLeft" config:type="int">0</config:config-item>
+          <config:config-item config:name="ViewTop" config:type="int">0</config:config-item>
+          <config:config-item config:name="VisibleLeft" config:type="int">0</config:config-item>
+          <config:config-item config:name="VisibleTop" config:type="int">0</config:config-item>
+          <config:config-item config:name="VisibleRight" config:type="int">0</config:config-item>
+          <config:config-item config:name="VisibleBottom" config:type="int">0</config:config-item>
+          <config:config-item config:name="ZoomType" config:type="short">0</config:config-item>
+          <config:config-item config:name="ViewLayoutColumns" config:type="short">2</config:config-item>
+          <config:config-item config:name="ViewLayoutBookMode" config:type="boolean">true</config:config-item>
+          <config:config-item config:name="ZoomFactor" config:type="short">100</config:config-item>
+          <config:config-item config:name="IsSelectedFrame" config:type="boolean">false</config:config-item>
+        </config:config-item-map-entry>
+      </config:config-item-map-indexed>
+    </config:config-item-set>
+    <config:config-item-set config:name="ooo:configuration-settings">
+      <config:config-item config:name="ChartAutoUpdate" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="IsLabelDocument" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="MathBaselineAlignment" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="OutlineLevelYieldsNumbering" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="PrintLeftPages" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="DoNotJustifyLinesWithManualBreak" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="AlignTabStopPosition" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="PrintTextPlaceholder" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="UseOldNumbering" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="CurrentDatabaseCommand" config:type="string"/>
+      <config:config-item config:name="ProtectForm" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="PrintBlackFonts" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="PrintProspectRTL" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="SmallCapsPercentage66" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="PrintControls" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="CharacterCompressionType" config:type="short">0</config:config-item>
+      <config:config-item config:name="PrintHiddenText" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="UseFormerTextWrapping" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="IsKernAsianPunctuation" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="PrintProspect" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="PrintEmptyPages" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="UseFormerObjectPositioning" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="ConsiderTextWrapOnObjPos" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="TableRowKeep" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="PrintReversed" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="TabsRelativeToIndent" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="PrintRightPages" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="PrintPaperFromSetup" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="AddFrameOffsets" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="AddParaSpacingToTableCells" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="UpdateFromTemplate" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="AddExternalLeading" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="PrintSingleJobs" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="PrinterIndependentLayout" config:type="string">high-resolution</config:config-item>
+      <config:config-item config:name="LinkUpdateMode" config:type="short">1</config:config-item>
+      <config:config-item config:name="PrintAnnotationMode" config:type="short">0</config:config-item>
+      <config:config-item config:name="UseOldPrinterMetrics" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="RedlineProtectionKey" config:type="base64Binary"/>
+      <config:config-item config:name="PrinterSetup" config:type="base64Binary"/>
+      <config:config-item config:name="IgnoreFirstLineIndentInNumbering" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="CollapseEmptyCellPara" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="PrinterName" config:type="string"/>
+      <config:config-item config:name="InvertBorderSpacing" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="PrintPageBackground" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="DoNotCaptureDrawObjsOnPage" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="ApplyUserData" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="TabAtLeftIndentForParagraphsInList" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="UnxForceZeroExtLeading" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="SaveVersionOnClose" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="PrintFaxName" config:type="string"/>
+      <config:config-item config:name="AddParaTableSpacing" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="PrintDrawings" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="LoadReadonly" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="PrintGraphics" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="FieldAutoUpdate" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="AllowPrintJobCancel" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="UseFormerLineSpacing" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="SaveGlobalDocumentLinks" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="CurrentDatabaseDataSource" config:type="string"/>
+      <config:config-item config:name="IgnoreTabsAndBlanksForLineCalculation" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="CurrentDatabaseCommandType" config:type="int">0</config:config-item>
+      <config:config-item config:name="DoNotResetParaAttrsForNumFont" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="ClipAsCharacterAnchoredWriterFlyFrames" config:type="boolean">false</config:config-item>
+      <config:config-item config:name="PrintTables" config:type="boolean">true</config:config-item>
+      <config:config-item config:name="AddParaTableSpacingAtStart" config:type="boolean">true</config:config-item>
+    </config:config-item-set>
+  </office:settings>
+</office:document-settings>
+WOK
+      x=x.strip
+      x=x.gsub(/\n+/m,'') unless @md.opt.act[:maintenance][:set]==:on
+      x
+    end
+    def styles_xml
+      x=<<WOK
+<?xml version="1.0" encoding="UTF-8"?>
+<office:document-styles xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xl="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2">
+  <office:font-face-decls>
+    <style:font-face style:name="DejaVu Sans Mono" svg:font-family="'DejaVu Sans Mono'" style:font-adornments="Book" style:font-family-generic="modern" style:font-pitch="fixed"/>
+    <style:font-face style:name="Nimbus Sans L" svg:font-family="'Nimbus Sans L'" style:font-pitch="variable"/>
+    <style:font-face style:name="Tahoma" svg:font-family="Tahoma, Lucidasans, 'Lucida Sans', 'Arial Unicode MS'" style:font-pitch="variable"/>
+    <style:font-face style:name="Nimbus Roman No9 L" svg:font-family="'Nimbus Roman No9 L'" style:font-family-generic="roman" style:font-pitch="variable"/>
+    <style:font-face style:name="Bitstream Vera Sans" svg:font-family="'Bitstream Vera Sans'" style:font-family-generic="swiss" style:font-pitch="variable"/>
+  </office:font-face-decls>
+  <office:styles>
+    <style:default-style style:family="graphic">
+      <style:graphic-properties fo:wrap-option="wrap" draw:shadow-offset-x="0.3cm" draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" draw:start-line-spacing-vertical="0.283cm" draw:end-line-spacing-horizontal="0.283cm" draw:end-line-spacing-vertical="0.283cm" style:flow-with-text="false"/>
+      <style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" style:writing-mode="lr-tb" style:font-independent-line-spacing="false">
+        <style:tab-stops/>
+      </style:paragraph-properties>
+      <style:text-properties style:use-window-font-color="true" fo:font-size="12pt" fo:language="en" fo:country="US" style:font-size-asian="12pt" style:language-asian="zxx" style:country-asian="none" style:font-size-complex="12pt" style:language-complex="zxx" style:country-complex="none"/>
+    </style:default-style>
+    <style:default-style style:family="paragraph">
+      <style:paragraph-properties fo:hyphenation-ladder-count="no-limit" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="1.251cm" style:writing-mode="page"/>
+      <style:text-properties style:use-window-font-color="true" style:font-name="Nimbus Roman No9 L" fo:font-size="12pt" fo:language="en" fo:country="US" style:font-name-asian="Nimbus Sans L" style:font-size-asian="12pt" style:language-asian="zxx" style:country-asian="none" style:font-name-complex="Nimbus Sans L" style:font-size-complex="12pt" style:language-complex="zxx" style:country-complex="none" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2"/>
+    </style:default-style>
+    <style:default-style style:family="table">
+      <style:table-properties table:border-model="collapsing"/>
+    </style:default-style>
+    <style:default-style style:family="table-row">
+      <style:table-row-properties fo:keep-together="auto"/>
+    </style:default-style>
+    <style:style style:name="Standard" style:family="paragraph" style:class="text"/>
+    <style:style style:name="Text_body" style:display-name="Text body" style:family="paragraph" style:class="text"><style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0.212cm"/></style:style>
+    <style:style style:name="P_page_break" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties fo:break-before="page"/></style:style>
+    <style:style style:name="P_normal" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties  fo:margin-top="0.199cm" fo:margin-bottom="0.199cm" fo:line-height="150%" fo:text-align="justify" style:justify-single-word="false"/></style:style>
+    <style:style style:name="P_normal_page_new" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties fo:break-after="page"/></style:style>
+    <style:style style:name="P_indent_0" style:display-name="Paragraph indent 0" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties  fo:margin-top="0.199cm" fo:margin-bottom="0.199cm" fo:line-height="150%" fo:text-align="justify" style:justify-single-word="false"/></style:style>
+    <style:style style:name="P_indent_1" style:display-name="Paragraph indent 1" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties  fo:margin-top="0.199cm" fo:margin-bottom="0.199cm" fo:line-height="150%" fo:margin-left="1cm" fo:margin-right="0cm" fo:text-align="justify" style:justify-single-word="false" fo:text-indent="0cm" style:auto-text-indent="false"/></style:style>
+    <style:style style:name="P_indent_2" style:display-name="Paragraph indent 2" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties  fo:margin-top="0.199cm" fo:margin-bottom="0.199cm" fo:line-height="150%" fo:margin-left="2cm" fo:margin-right="0cm" fo:text-align="justify" style:justify-single-word="false" fo:text-indent="0cm" style:auto-text-indent="false"/></style:style>
+    <style:style style:name="P_indent_3" style:display-name="Paragraph indent 3" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties  fo:margin-top="0.199cm" fo:margin-bottom="0.199cm" fo:line-height="150%" fo:margin-left="3cm" fo:margin-right="0cm" fo:text-align="justify" style:justify-single-word="false" fo:text-indent="0cm" style:auto-text-indent="false"/></style:style>
+    <style:style style:name="P_indent_4" style:display-name="Paragraph indent 4" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties  fo:margin-top="0.199cm" fo:margin-bottom="0.199cm" fo:line-height="150%" fo:margin-left="4cm" fo:margin-right="0cm" fo:text-align="justify" style:justify-single-word="false" fo:text-indent="0cm" style:auto-text-indent="false"/></style:style>
+    <style:style style:name="P_indent_5" style:display-name="Paragraph indent 5" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties  fo:margin-top="0.199cm" fo:margin-bottom="0.199cm" fo:line-height="150%" fo:margin-left="5cm" fo:margin-right="0cm" fo:text-align="justify" style:justify-single-word="false" fo:text-indent="0cm" style:auto-text-indent="false"/></style:style>
+    <style:style style:name="P_indent_6" style:display-name="Paragraph indent 6" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties  fo:margin-top="0.199cm" fo:margin-bottom="0.199cm" fo:line-height="150%" fo:margin-left="6cm" fo:margin-right="0cm" fo:text-align="justify" style:justify-single-word="false" fo:text-indent="0cm" style:auto-text-indent="false"/></style:style>
+    <style:style style:name="P_indent_7" style:display-name="Paragraph indent 7" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties  fo:margin-top="0.199cm" fo:margin-bottom="0.199cm" fo:line-height="150%" fo:margin-left="7cm" fo:margin-right="0cm" fo:text-align="justify" style:justify-single-word="false" fo:text-indent="0cm" style:auto-text-indent="false"/></style:style>
+    <style:style style:name="P_indent_8" style:display-name="Paragraph indent 8" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties  fo:margin-top="0.199cm" fo:margin-bottom="0.199cm" fo:line-height="150%" fo:margin-left="8cm" fo:margin-right="0cm" fo:text-align="justify" style:justify-single-word="false" fo:text-indent="0cm" style:auto-text-indent="false"/></style:style>
+    <style:style style:name="P_indent_9" style:display-name="Paragraph indent 9" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties  fo:margin-top="0.199cm" fo:margin-bottom="0.199cm" fo:line-height="150%" fo:margin-left="9cm" fo:margin-right="0cm" fo:text-align="justify" style:justify-single-word="false" fo:text-indent="0cm" style:auto-text-indent="false"/></style:style>
+    <style:style style:name="P_h0_i0" style:display-name="Hang 0 Indent 0" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h0_i1" style:display-name="Hang 0 Indent 1" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="1cm" fo:margin-right="0cm" fo:text-indent="-1cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h0_i2" style:display-name="Hang 0 Indent 2" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="2cm" fo:margin-right="0cm" fo:text-indent="-2cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h0_i3" style:display-name="Hang 0 Indent 3" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="3cm" fo:margin-right="0cm" fo:text-indent="-3cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h0_i4" style:display-name="Hang 0 Indent 4" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="4cm" fo:margin-right="0cm" fo:text-indent="-4cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h0_i5" style:display-name="Hang 0 Indent 5" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="5cm" fo:margin-right="0cm" fo:text-indent="-5cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h0_i6" style:display-name="Hang 0 Indent 6" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="6cm" fo:margin-right="0cm" fo:text-indent="-6cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h0_i7" style:display-name="Hang 0 Indent 7" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="7cm" fo:margin-right="0cm" fo:text-indent="-7cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h0_i8" style:display-name="Hang 0 Indent 8" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="8cm" fo:margin-right="0cm" fo:text-indent="-8cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h0_i9" style:display-name="Hang 0 Indent 9" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="9cm" fo:margin-right="0cm" fo:text-indent="-9cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h1_i0" style:display-name="Hang 1 Indent 0" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="1cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h1_i1" style:display-name="Hang 1 Indent 1" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="1cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h1_i2" style:display-name="Hang 1 Indent 2" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="2cm" fo:margin-right="0cm" fo:text-indent="-1cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h1_i3" style:display-name="Hang 1 Indent 3" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="3cm" fo:margin-right="0cm" fo:text-indent="-2cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h1_i4" style:display-name="Hang 1 Indent 4" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="4cm" fo:margin-right="0cm" fo:text-indent="-3cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h1_i5" style:display-name="Hang 1 Indent 5" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="5cm" fo:margin-right="0cm" fo:text-indent="-4cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h1_i6" style:display-name="Hang 1 Indent 6" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="6cm" fo:margin-right="0cm" fo:text-indent="-5cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h1_i7" style:display-name="Hang 1 Indent 7" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="7cm" fo:margin-right="0cm" fo:text-indent="-6cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h1_i8" style:display-name="Hang 1 Indent 8" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="8cm" fo:margin-right="0cm" fo:text-indent="-7cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h1_i9" style:display-name="Hang 1 Indent 9" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="9cm" fo:margin-right="0cm" fo:text-indent="-8cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h2_i0" style:display-name="Hang 2 Indent 0" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="2cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h2_i1" style:display-name="Hang 2 Indent 1" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="1cm" fo:margin-right="0cm" fo:text-indent="1cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h2_i2" style:display-name="Hang 2 Indent 2" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="2cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h2_i3" style:display-name="Hang 2 Indent 3" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="3cm" fo:margin-right="0cm" fo:text-indent="-1cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h2_i4" style:display-name="Hang 2 Indent 4" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="4cm" fo:margin-right="0cm" fo:text-indent="-2cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h2_i5" style:display-name="Hang 2 Indent 5" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="5cm" fo:margin-right="0cm" fo:text-indent="-3cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h2_i6" style:display-name="Hang 2 Indent 6" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="6cm" fo:margin-right="0cm" fo:text-indent="-4cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h2_i7" style:display-name="Hang 2 Indent 7" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="7cm" fo:margin-right="0cm" fo:text-indent="-5cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h2_i8" style:display-name="Hang 2 Indent 8" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="8cm" fo:margin-right="0cm" fo:text-indent="-6cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h2_i9" style:display-name="Hang 2 Indent 9" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="9cm" fo:margin-right="0cm" fo:text-indent="-7cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h3_i0" style:display-name="Hang 3 Indent 0" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="3cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h3_i1" style:display-name="Hang 3 Indent 1" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="1cm" fo:margin-right="0cm" fo:text-indent="2cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h3_i2" style:display-name="Hang 3 Indent 2" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="2cm" fo:margin-right="0cm" fo:text-indent="1cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h3_i3" style:display-name="Hang 3 Indent 3" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="3cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h3_i4" style:display-name="Hang 3 Indent 4" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="4cm" fo:margin-right="0cm" fo:text-indent="-1cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h3_i5" style:display-name="Hang 3 Indent 5" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="5cm" fo:margin-right="0cm" fo:text-indent="-2cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h3_i6" style:display-name="Hang 3 Indent 6" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="6cm" fo:margin-right="0cm" fo:text-indent="-3cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h3_i7" style:display-name="Hang 3 Indent 7" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="7cm" fo:margin-right="0cm" fo:text-indent="-4cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h3_i8" style:display-name="Hang 3 Indent 8" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="8cm" fo:margin-right="0cm" fo:text-indent="-5cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h3_i9" style:display-name="Hang 3 Indent 9" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="9cm" fo:margin-right="0cm" fo:text-indent="-6cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h4_i0" style:display-name="Hang 4 Indent 0" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="4cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h4_i1" style:display-name="Hang 4 Indent 1" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="1cm" fo:margin-right="0cm" fo:text-indent="3cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h4_i2" style:display-name="Hang 4 Indent 2" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="2cm" fo:margin-right="0cm" fo:text-indent="2cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h4_i3" style:display-name="Hang 4 Indent 3" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="3cm" fo:margin-right="0cm" fo:text-indent="1cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h4_i4" style:display-name="Hang 4 Indent 4" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="4cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h4_i5" style:display-name="Hang 4 Indent 5" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="5cm" fo:margin-right="0cm" fo:text-indent="-1cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h4_i6" style:display-name="Hang 4 Indent 6" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="6cm" fo:margin-right="0cm" fo:text-indent="-2cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h4_i7" style:display-name="Hang 4 Indent 7" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="7cm" fo:margin-right="0cm" fo:text-indent="-3cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h4_i8" style:display-name="Hang 4 Indent 8" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="8cm" fo:margin-right="0cm" fo:text-indent="-4cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h4_i9" style:display-name="Hang 4 Indent 9" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="9cm" fo:margin-right="0cm" fo:text-indent="-5cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h5_i0" style:display-name="Hang 5 Indent 0" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="5cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h5_i1" style:display-name="Hang 5 Indent 1" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="1cm" fo:margin-right="0cm" fo:text-indent="4cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h5_i2" style:display-name="Hang 5 Indent 2" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="2cm" fo:margin-right="0cm" fo:text-indent="3cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h5_i3" style:display-name="Hang 5 Indent 3" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="3cm" fo:margin-right="0cm" fo:text-indent="2cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h5_i4" style:display-name="Hang 5 Indent 4" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="4cm" fo:margin-right="0cm" fo:text-indent="1cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h5_i5" style:display-name="Hang 5 Indent 5" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="5cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h5_i6" style:display-name="Hang 5 Indent 6" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="6cm" fo:margin-right="0cm" fo:text-indent="-1cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h5_i7" style:display-name="Hang 5 Indent 7" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="7cm" fo:margin-right="0cm" fo:text-indent="-2cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h5_i8" style:display-name="Hang 5 Indent 8" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="8cm" fo:margin-right="0cm" fo:text-indent="-3cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h5_i9" style:display-name="Hang 5 Indent 9" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="9cm" fo:margin-right="0cm" fo:text-indent="-4cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h6_i0" style:display-name="Hang 6 Indent 0" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="6cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h6_i1" style:display-name="Hang 6 Indent 1" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="1cm" fo:margin-right="0cm" fo:text-indent="5cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h6_i2" style:display-name="Hang 6 Indent 2" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="2cm" fo:margin-right="0cm" fo:text-indent="4cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h6_i3" style:display-name="Hang 6 Indent 3" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="3cm" fo:margin-right="0cm" fo:text-indent="3cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h6_i4" style:display-name="Hang 6 Indent 4" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="4cm" fo:margin-right="0cm" fo:text-indent="2cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h6_i5" style:display-name="Hang 6 Indent 5" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="5cm" fo:margin-right="0cm" fo:text-indent="1cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h6_i6" style:display-name="Hang 6 Indent 6" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="6cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h6_i7" style:display-name="Hang 6 Indent 7" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="7cm" fo:margin-right="0cm" fo:text-indent="-1cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h6_i8" style:display-name="Hang 6 Indent 8" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="8cm" fo:margin-right="0cm" fo:text-indent="-2cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h6_i9" style:display-name="Hang 6 Indent 9" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="9cm" fo:margin-right="0cm" fo:text-indent="-3cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h7_i0" style:display-name="Hang 7 Indent 0" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="7cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h7_i1" style:display-name="Hang 7 Indent 1" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="1cm" fo:margin-right="0cm" fo:text-indent="6cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h7_i2" style:display-name="Hang 7 Indent 2" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="2cm" fo:margin-right="0cm" fo:text-indent="5cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h7_i3" style:display-name="Hang 7 Indent 3" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="3cm" fo:margin-right="0cm" fo:text-indent="4cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h7_i4" style:display-name="Hang 7 Indent 4" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="4cm" fo:margin-right="0cm" fo:text-indent="3cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h7_i5" style:display-name="Hang 7 Indent 5" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="5cm" fo:margin-right="0cm" fo:text-indent="2cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h7_i6" style:display-name="Hang 7 Indent 6" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="6cm" fo:margin-right="0cm" fo:text-indent="1cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h7_i7" style:display-name="Hang 7 Indent 7" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="7cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h7_i8" style:display-name="Hang 7 Indent 8" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="8cm" fo:margin-right="0cm" fo:text-indent="-1cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h7_i9" style:display-name="Hang 7 Indent 9" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="9cm" fo:margin-right="0cm" fo:text-indent="-2cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h8_i0" style:display-name="Hang 8 Indent 0" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="8cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h8_i1" style:display-name="Hang 8 Indent 1" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="1cm" fo:margin-right="0cm" fo:text-indent="7cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h8_i2" style:display-name="Hang 8 Indent 2" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="2cm" fo:margin-right="0cm" fo:text-indent="6cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h8_i3" style:display-name="Hang 8 Indent 3" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="3cm" fo:margin-right="0cm" fo:text-indent="5cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h8_i4" style:display-name="Hang 8 Indent 4" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="4cm" fo:margin-right="0cm" fo:text-indent="4cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h8_i5" style:display-name="Hang 8 Indent 5" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="5cm" fo:margin-right="0cm" fo:text-indent="3cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h8_i6" style:display-name="Hang 8 Indent 6" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="6cm" fo:margin-right="0cm" fo:text-indent="2cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h8_i7" style:display-name="Hang 8 Indent 7" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="7cm" fo:margin-right="0cm" fo:text-indent="1cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h8_i8" style:display-name="Hang 8 Indent 8" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="8cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h8_i9" style:display-name="Hang 8 Indent 9" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="9cm" fo:margin-right="0cm" fo:text-indent="-1cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h9_i0" style:display-name="Hang 9 Indent 0" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="9cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h9_i1" style:display-name="Hang 9 Indent 1" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="1cm" fo:margin-right="0cm" fo:text-indent="8cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h9_i2" style:display-name="Hang 9 Indent 2" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="2cm" fo:margin-right="0cm" fo:text-indent="7cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h9_i3" style:display-name="Hang 9 Indent 3" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="3cm" fo:margin-right="0cm" fo:text-indent="6cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h9_i4" style:display-name="Hang 9 Indent 4" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="4cm" fo:margin-right="0cm" fo:text-indent="5cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h9_i5" style:display-name="Hang 9 Indent 5" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="5cm" fo:margin-right="0cm" fo:text-indent="4cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h9_i6" style:display-name="Hang 9 Indent 6" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="6cm" fo:margin-right="0cm" fo:text-indent="3cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h9_i7" style:display-name="Hang 9 Indent 7" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="7cm" fo:margin-right="0cm" fo:text-indent="2cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h9_i8" style:display-name="Hang 9 Indent 8" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="8cm" fo:margin-right="0cm" fo:text-indent="1cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="P_h9_i9" style:display-name="Hang 9 Indent 9" style:family="paragraph" style:parent-style-name="Text_body" style:class="text"><style:paragraph-properties fo:margin-left="9cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false"><style:tab-stops><style:tab-stop style:position="0cm"/></style:tab-stops></style:paragraph-properties></style:style>
+    <style:style style:name="Span_bold" style:family="text"><style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"/></style:style>
+    <style:style style:name="Span_italic" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic"/></style:style>
+    <style:style style:name="Span_underscore" style:family="text"><style:text-properties style:text-underline-style="solid" style:text-underline-width="auto" style:text-underline-color="font-color"/></style:style>
+    <style:style style:name="Span_superscript" style:family="text"><style:text-properties style:text-position="super 58%"/></style:style>
+    <style:style style:name="Span_subscript" style:family="text"><style:text-properties style:text-position="sub 58%"/></style:style>
+    <style:style style:name="Span_monospace" style:family="text"><style:text-properties style:font-name="DejaVu Sans Mono" fo:font-size="10pt" fo:font-weight="normal" fo:background-color="#e6e6e6"/></style:style>
+    <style:style style:name="Heading" style:family="paragraph" style:next-style-name="Text_body" style:class="text"> <style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm" fo:keep-with-next="always"/><style:text-properties style:font-name="Bitstream Vera Sans" fo:font-size="14pt" style:font-size-asian="14pt" style:font-name-complex="Tahoma" style:font-size-complex="14pt"/></style:style>
+    <style:style style:name="H_1" style:display-name="Heading 1" style:family="paragraph" style:next-style-name="Text_body" style:default-outline-level="1" style:class="text"><style:text-properties fo:font-size="120%" fo:font-weight="bold" style:font-size-asian="120%" style:font-weight-asian="bold" style:font-size-complex="115%" style:font-weight-complex="bold"/></style:style>
+    <style:style style:name="H_2" style:display-name="Heading 2" style:family="paragraph" style:next-style-name="Text_body" style:default-outline-level="2" style:class="text"><style:text-properties fo:font-size="115%" fo:font-weight="bold" style:font-size-asian="115%" style:font-weight-asian="bold" style:font-size-complex="115%" style:font-weight-complex="bold"/></style:style>
+    <style:style style:name="H_3" style:display-name="Heading 3" style:family="paragraph" style:next-style-name="Text_body" style:default-outline-level="3" style:class="text"><style:text-properties fo:font-size="110%" fo:font-weight="bold" style:font-size-asian="110%" style:font-weight-asian="bold" style:font-size-complex="115%" style:font-weight-complex="bold"/></style:style>
+    <style:style style:name="H_4" style:display-name="Heading 4" style:family="paragraph" style:next-style-name="Text_body" style:default-outline-level="4" style:class="text"><style:text-properties fo:font-size="12pt" fo:font-style="italic" fo:font-weight="bold" style:font-size-asian="12pt" style:font-style-asian="italic" style:font-weight-asian="bold" style:font-size-complex="12pt" style:font-style-complex="italic" style:font-weight-complex="bold"/></style:style>
+    <style:style style:name="H_5" style:display-name="Heading 5" style:family="paragraph" style:next-style-name="Text_body" style:default-outline-level="5" style:class="text"><style:text-properties fo:font-size="90%" fo:font-style="italic" fo:font-weight="bold" style:font-size-asian="90%" style:font-style-asian="italic" style:font-weight-asian="bold" style:font-size-complex="90%" style:font-style-complex="italic" style:font-weight-complex="bold"/></style:style>
+    <style:style style:name="H_6" style:display-name="Heading 6" style:family="paragraph" style:next-style-name="Text_body" style:default-outline-level="6" style:class="text"><style:text-properties fo:font-size="80%" fo:font-style="italic" fo:font-weight="bold" style:font-size-asian="80%" style:font-style-asian="italic" style:font-weight-asian="bold" style:font-size-complex="80%" style:font-style-complex="italic" style:font-weight-complex="bold"/></style:style>
+    <style:style style:name="P_group" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" fo:line-height="100%" fo:text-align="justify" style:justify-single-word="false"/></style:style>
+    <style:style style:name="P_code" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" fo:line-height="100%" fo:text-align="start" style:justify-single-word="false"/><style:text-properties style:font-name="DejaVu Sans Mono" fo:font-size="9pt" fo:font-weight="normal" fo:background-color="#e6e6e6"/></style:style>
+    <style:style style:name="Footnote" style:family="paragraph" style:class="extra"><style:paragraph-properties fo:margin-left="0.499cm" fo:margin-right="0cm" fo:text-indent="-0.499cm" style:auto-text-indent="false" text:number-lines="false" text:line-number="0"/> <style:text-properties fo:font-size="10pt" style:font-size-asian="10pt" style:font-size-complex="10pt"/></style:style>
+    <style:style style:name="Table_Contents" style:display-name="Table Contents" style:family="paragraph" style:parent-style-name="Standard" style:class="extra"><style:paragraph-properties text:number-lines="false" text:line-number="0"/></style:style>
+    <style:style style:name="Footnote_symbol" style:display-name="Footnote Symbol" style:family="text"/>
+    <style:style style:name="Footnote_anchor" style:display-name="Footnote Anchor" style:family="text"><style:text-properties style:text-position="super 58%"/></style:style>
+    <style:style style:name="Internet_link" style:display-name="Internet link" style:family="text"><style:text-properties fo:color="#000080" fo:language="zxx" fo:country="none" style:text-underline-style="solid" style:text-underline-width="auto" style:text-underline-color="font-color" style:language-asian="zxx" style:country-asian="none" style:language-complex="zxx" style:country-complex="none"/></style:style>
+    <style:style style:name="Graphics" style:family="graphic"><style:graphic-properties text:anchor-type="paragraph" svg:x="0cm" svg:y="0cm" style:wrap="dynamic" style:number-wrapped-paragraphs="no-limit" style:wrap-contour="false" style:vertical-pos="top" style:vertical-rel="paragraph" style:horizontal-pos="center" style:horizontal-rel="paragraph"/></style:style>
+    <text:outline-style style:name="Outline"><text:outline-level-style text:level="1" style:num-format=""><style:list-level-properties text:min-label-distance="0.381cm"/></text:outline-level-style>
+      <text:outline-level-style text:level="2" style:num-format=""><style:list-level-properties text:min-label-distance="0.381cm"/></text:outline-level-style>
+      <text:outline-level-style text:level="3" style:num-format=""><style:list-level-properties text:min-label-distance="0.381cm"/></text:outline-level-style>
+      <text:outline-level-style text:level="4" style:num-format=""><style:list-level-properties text:min-label-distance="0.381cm"/></text:outline-level-style>
+      <text:outline-level-style text:level="5" style:num-format=""><style:list-level-properties text:min-label-distance="0.381cm"/></text:outline-level-style>
+      <text:outline-level-style text:level="6" style:num-format=""><style:list-level-properties text:min-label-distance="0.381cm"/></text:outline-level-style>
+      <text:outline-level-style text:level="7" style:num-format=""><style:list-level-properties text:min-label-distance="0.381cm"/></text:outline-level-style>
+      <text:outline-level-style text:level="8" style:num-format=""><style:list-level-properties text:min-label-distance="0.381cm"/></text:outline-level-style>
+      <text:outline-level-style text:level="9" style:num-format=""><style:list-level-properties text:min-label-distance="0.381cm"/></text:outline-level-style>
+      <text:outline-level-style text:level="10" style:num-format=""><style:list-level-properties text:min-label-distance="0.381cm"/></text:outline-level-style>
+    </text:outline-style>
+    <text:notes-configuration text:note-class="footnote" text:citation-style-name="Footnote_symbol" text:citation-body-style-name="Footnote_anchor" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document"/>
+    <text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0"/>
+    <text:linenumbering-configuration text:number-lines="false" text:offset="0.499cm" style:num-format="1" text:number-position="left" text:increment="5"/>
+    <style:style style:name="fr1" style:family="graphic" style:parent-style-name="Graphics"><style:graphic-properties style:wrap="none" style:horizontal-pos="left" style:horizontal-rel="paragraph" style:mirror="none" fo:clip="rect(0cm 0cm 0cm 0cm)" draw:luminance="0%" draw:contrast="0%" draw:red="0%" draw:green="0%" draw:blue="0%" draw:gamma="100%" draw:color-inversion="false" draw:image-opacity="100%" draw:color-mode="standard"/></style:style>
+    <style:style style:name="gr1" style:family="graphic"><style:graphic-properties draw:stroke="none" draw:fill="none" draw:textarea-horizontal-align="center" draw:textarea-vertical-align="middle" draw:color-mode="standard" draw:luminance="0%" draw:contrast="0%" draw:gamma="100%" draw:red="0%" draw:green="0%" draw:blue="0%" fo:clip="rect(0cm 0cm 0cm 0cm)" draw:image-opacity="100%" style:mirror="none" style:run-through="background" style:wrap="none" style:vertical-pos="top" style:vertical-rel="baseline" style:horizontal-pos="left" style:horizontal-rel="paragraph" draw:wrap-influence-on-position="once-concurrent" style:flow-with-text="false"/></style:style>
+    <style:style style:name="gr2" style:family="graphic"><style:graphic-properties draw:stroke="none" draw:fill="none" draw:textarea-horizontal-align="center" draw:textarea-vertical-align="middle" draw:color-mode="standard" draw:luminance="0%" draw:contrast="0%" draw:gamma="100%" draw:red="0%" draw:green="0%" draw:blue="0%" fo:clip="rect(0cm 0cm 0cm 0cm)" draw:image-opacity="100%" style:mirror="none" style:run-through="background" style:wrap="none" style:vertical-pos="middle" style:vertical-rel="baseline" style:horizontal-pos="left" style:horizontal-rel="paragraph" draw:wrap-influence-on-position="once-concurrent" style:flow-with-text="false"/></style:style>
+  </office:styles>
+  <office:automatic-styles>
+    <style:page-layout style:name="Mpm1">
+      <style:page-layout-properties fo:page-width="20.999cm" fo:page-height="29.699cm" style:num-format="1" style:print-orientation="portrait" fo:margin-top="2cm" fo:margin-bottom="2cm" fo:margin-left="2cm" fo:margin-right="2cm" style:writing-mode="lr-tb" style:footnote-max-height="0cm">
+        <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="none" style:adjustment="left" style:rel-width="25%" style:color="#000000"/>
+      </style:page-layout-properties>
+      <style:header-style/>
+      <style:footer-style/>
+    </style:page-layout>
+  </office:automatic-styles>
+  <office:master-styles>
+    <style:master-page style:name="Standard" style:page-layout-name="Mpm1"/>
+  </office:master-styles>
+</office:document-styles>
+WOK
+      x=x.strip
+      x=x.gsub(/\n+/m,'') unless @md.opt.act[:maintenance][:set]==:on
+      x
+    end
+    def mimetype
+      x=<<WOK
+application/vnd.oasis.opendocument.text
+WOK
+      x=x.strip
+    end
+  end
+  class FormatObjBreak
+    def initialize(md,t_o)
+      @md,@t_o=md,t_o
+    end
+    def br_page
+      @t_o.obj='<text:p text:style-name="P_page_break"> </text:p>'
+      @t_o
+    end
+    def br_page_line
+      sep='_'
+      @t_o.obj=%{<text:p text:style-name="P_normal">#{sep*60}</text:p>}
+      @t_o
+    end
+    def obj_sep #center later
+      sep='--- '
+      @t_o.obj=%{<text:p text:style-name="P_normal">#{sep*20}</text:p>}
+      @t_o
+    end
+  end
+  class XML
+  end
+end
+__END__
+#+END_SRC
+
+* docbook5rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xml_docbook5.rb"
+# <<sisu_document_header>>
+module SiSU_XML_Docbook_Book
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+    include SiSU_Particulars
+  require_relative 'ao'                                 # ao.rb
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'txt_shared'                         # txt_shared.rb
+    include SiSU_TextUtils
+  require_relative 'xml_shared'                         # xml_shared.rb
+    include SiSU_XML_Munge
+  require_relative 'shared_metadata'                    # shared_metadata.rb
+  class Source
+    def initialize(opt)
+      @opt=opt
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+    end
+    def read
+      begin
+        @md,@ao_array=@particulars.md,@particulars.ao_array
+        @env=@particulars.env
+        report
+        SiSU_XML_Docbook_Book::Source::Scroll.new(@ao_array,@md).songsheet
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        #SiSU_Env::CreateSite.new(@opt.selections.str).cp_css
+        #SiSU_Env::CreateSite.new(@opt.selections.str).cp_base_images
+        Dir.chdir(@opt.f_pth[:pth])
+      end
+    end
+    private
+    def report
+      unless @opt.act[:quiet][:set]==:on
+        tool=(@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on) \
+        ? "#{@env.program.docbook_viewer} #{@md.file.output_path.xml_docbook_book.dir}/#{@md.file.base_filename.xml_docbook_book}"
+        : "[#{@opt.f_pth[:lng_is]}] #{@opt.fno}"
+        (@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on) \
+        ? SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'DocBook',
+            tool
+          ).green_hi_blue
+        : SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'DocBook',
+            tool
+          ).green_title_hi
+        if (@opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on)
+          SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            @opt.fns,
+            "#{@md.file.output_path.xml_docbook_book.dir}/#{@md.file.base_filename.xml_docbook_book}"
+          ).flow
+        end
+      end
+    end
+    class Scroll <Source
+      def initialize(data='',md='')
+        @data,@md=data,md
+        @trans=SiSU_XML_Munge::Trans.new(md)
+        @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(md.opt)
+        @env=@particulars.env
+        @make ||=SiSU_Env::ProcessingSettings.new(md)
+      end
+      def songsheet
+        @t='sisu'
+        data=@data
+        if @md.opt.act[:verbose_plus][:set]==:on
+          structure_collapsed(data)
+        end
+        #head
+        #extract_endnotes
+        data=markup_text(data)
+        structure_build_collapsed(data)
+        document_images if @md.ec[:image] and @md.ec[:image].length > 0
+        #tail
+      end
+      def document_images
+        img_pth={
+          src:  @md.opt.image_src_path,
+          dest: @md.env.path.webserv + '/_sisu/image',
+        }
+        unless FileTest.directory?(img_pth[:dest])
+          #mkdir?
+        end
+        if FileTest.directory?(img_pth[:dest])
+          @md.ec[:image].each do |x|
+            img={
+              src:  "#{img_pth[:src]}/#{x}",
+              dest: "#{img_pth[:dest]}/#{x}",
+            }
+            if FileTest.file?(img[:src])
+              FileUtils::cp(img[:src],img[:dest])
+            else p "Not Found: #{img[:src]}/#{x}"
+            end
+          end
+        end
+      end
+      def spaces
+        Ax[:spaces]
+      end
+      def tags
+        # collapsed -->
+        def collapsed
+          %w[ 0 1 2 3 4 5 ]
+        end
+        def docbook_tag(lc,chlv='')
+          case lc
+          when 0 then 'book'
+          when 1 then lc==chlv ? 'chapter' : 'section'
+          when 2 then lc==chlv ? 'chapter' : 'section'
+          when 3 then lc==chlv ? 'chapter' : 'section'
+          when 4 then 'section'
+          when 5 then 'section'
+          when 6 then 'section'
+          end
+        end
+        self
+      end
+      def put(line)
+        #@file_docbook.puts line                           #look into and use perhaps
+        puts line if @md.opt.act[:verbose_plus][:set]==:on
+      end
+      def head
+        rdf=SiSU_XML_Tags::RDF.new(@md)
+        stylesheet=SiSU_Style::CSS_HeadInfo.new(@md,'xml_docbook').stylesheet
+        <<-WOK
+<?xml version="1.0" encoding="utf-8"?>
+#{stylesheet.css_head_xml}
+#{rdf.comment_xml}
+<book xmlns="http://docbook.org/ns/docbook"
+  xmlns:xl="http://www.w3.org/1999/xlink"
+  version="5.0">
+        WOK
+      end
+      def markup_text(data)
+        data.each_with_index do |o,i|
+          if o.is ==:heading \
+          || o.is ==:para \
+          || o.of ==:block \
+          || o.is ==:open_close_tags
+            o=@trans.markup_docbook(o) #unless o.obj==nil
+          end
+        end
+        data
+      end
+      def tail
+        tail=<<-WOK
+</book>
+        WOK
+        put(tail)
+      end
+      def output(o,comment='')
+         puts o.lc == (0..6) \
+         ? "#{spaces*o.lc}<#{o.lc}>[#{o.ocn}] #{o.ln} #{o.obj}</#{o.lc}>#{comment}"
+         : "<#{o.lc}>[#{o.ocn}] #{o.ln} #{o.obj}</#{o.lc}>#{comment}"
+      end
+      def structure_collapsed(data)
+        puts "\ncollapsed structure, heading outline --->\n\n"
+        data.each_with_index do |o,i|
+          if  (o.is ==:heading || o.is ==:heading_insert)
+            output(o)
+          end
+        end
+      end
+      #def chapterlevel
+      #end
+      def xml_head
+        [
+          '<docinfo>',
+          SiSU_Metadata::Summary.new(@md).xml_docbook.metadata,
+          '</docinfo>'
+        ].flatten
+      end
+      def code_output(o,ocn,filename_docbook)
+        filename_docbook.puts o.obj.gsub(/\n?(?:#{Mx[:br_line]}|#{Mx[:br_nl]})\n?/m,"\n")
+      end
+      def adjust_output(o,ocn,filename_docbook,splv)
+        if o.obj =~/#{Xx[:split]}/
+          outs=o.obj.split(/#{Xx[:split]}/)
+          outs.each do |out|
+            if out =~/<figure id=/m
+              out=out.gsub(/:spaces0:/m,
+                  %{#{spaces*(splv)}#{spaces}}).
+                gsub(/:spaces1:/m,
+                  %{#{spaces*(splv)}#{spaces*2}})
+              filename_docbook.puts out
+              filename_docbook.puts "#{spaces*3}#{ocn}"
+            else
+              unless out.empty?
+                filename_docbook.puts SiSU_TextUtils::Wrap.new(out,80,(splv*2+2),nil).line_wrap
+                filename_docbook.puts "#{spaces*3}#{ocn}"
+              end
+            end
+          end
+        else
+          filename_docbook.puts SiSU_TextUtils::Wrap.new(o.obj,80,(splv*2+2),nil,ocn).line_wrap
+        end
+      end
+      def structure_build_collapsed(data)
+        #output_file=@md.file.output_path.xml_docbook_book.dir + '/' + @md.file.base_filename.xml_docbook_book
+        file=SiSU_Env::FileOp.new(@md)
+        filename_docbook=file.write_file.xml_docbook_book
+        h=0
+        @chlv=chlv=0
+        doc_position=:head
+        filename_docbook.puts head
+        filename_docbook.puts xml_head
+        data.each_with_index do |o,i|
+          if (defined? o.ocn and not o.ocn.nil?)
+            ocn=(@make.build.ocn?) \
+            ? "<!-- o#{o.ocn} -->"
+            : ''
+            id=%{ id="o#{o.ocn}" }
+          else
+            ocn,id='',''
+          end
+          if  (o.is ==:heading || o.is ==:heading_insert)
+            chlv=(o.lv.to_i == 1) \
+            ? @chlv=o.lc.to_i
+            : 0
+            @splv=o.lc
+            tag_id=o.tags[0] ? %{ id="#{o.tags[0]}" } : ''
+            if doc_position ==:head
+               filename_docbook.puts  %{#{spaces*o.lc}<title#{id}>}
+              doc_position=:body_and_tail
+            else
+              filename_docbook.puts structure_build_tag_close(o.lc,h)
+              filename_docbook.puts  %{#{spaces*(o.lc)}<#{tags.docbook_tag(o.lc,chlv)}#{tag_id}>
+#{spaces*o.lc}<title#{id}>
+}
+            end
+            adjust_output(o,ocn,filename_docbook,@splv)
+            filename_docbook.puts %{#{spaces*o.lc}</title>}
+            h=o.lc
+          elsif o.of ==:layout \
+          and o.is ==:open_close_tags
+            xml_tag=case o.sym
+            when :quote_open then '<blockquote>'
+            when :quote_close then '</blockquote>'
+            else ''
+            end
+            unless xml_tag.empty?
+              filename_docbook.puts "#{spaces*(@splv)}#{xml_tag}"
+            end
+          elsif o.of ==:block
+            if o.is ==:table
+              filename_docbook.puts SiSU_Tables::TableXMLdocbook.new(o,id).table.obj
+            elsif o.is ==:code
+              filename_docbook.puts "#{spaces*(@splv)}<para#{id}>"
+              filename_docbook.puts "#{spaces*(@splv+1)}<programlisting>"
+              code_output(o,ocn,filename_docbook)
+              filename_docbook.puts "#{spaces*(@splv+1)}</programlisting>"
+              filename_docbook.puts "#{spaces*(@splv)}</para>"
+            else
+              filename_docbook.puts "#{spaces*(@splv)}<para#{id}>"
+              adjust_output(o,ocn,filename_docbook,@splv)
+              filename_docbook.puts "#{spaces*(@splv)}</para>"
+            end
+          elsif o.of ==:para
+            filename_docbook.puts "#{spaces*(@splv)}<para#{id}>"
+            adjust_output(o,ocn,filename_docbook,@splv)
+            filename_docbook.puts "#{spaces*(@splv)}</para>"
+          end
+        end
+        filename_docbook.puts structure_build_tag_close(0,h)
+        filename_docbook.close
+      end
+      def structure_build_tag_close(lc,h)
+        x=[]
+        case h
+        when 0
+          x << "#{spaces*0}</#{tags.docbook_tag(0)}>"       if (lc <= 0)
+        when 1
+          x << "#{spaces*1}</#{tags.docbook_tag(1,@chlv)}>" if (lc <= 1)
+          x << "#{spaces*0}</#{tags.docbook_tag(0)}>"       if (lc <= 0)
+        when 2
+          x << "#{spaces*2}</#{tags.docbook_tag(2,@chlv)}>" if (lc <= 2)
+          x << "#{spaces*1}</#{tags.docbook_tag(1,@chlv)}>" if (lc <= 1)
+          x << "#{spaces*0}</#{tags.docbook_tag(0)}>"       if (lc <= 0)
+        when 3
+          x << "#{spaces*3}</#{tags.docbook_tag(3,@chlv)}>" if (lc <= 3)
+          x << "#{spaces*2}</#{tags.docbook_tag(2,@chlv)}>" if (lc <= 2)
+          x << "#{spaces*1}</#{tags.docbook_tag(1,@chlv)}>" if (lc <= 1)
+          x << "#{spaces*0}</#{tags.docbook_tag(0)}>"       if (lc <= 0)
+        when 4
+          x << "#{spaces*4}</#{tags.docbook_tag(4,@chlv)}>" if (lc <= 4)
+          x << "#{spaces*3}</#{tags.docbook_tag(3,@chlv)}>" if (lc <= 3)
+          x << "#{spaces*2}</#{tags.docbook_tag(2,@chlv)}>" if (lc <= 2)
+          x << "#{spaces*1}</#{tags.docbook_tag(1,@chlv)}>" if (lc <= 1)
+          x << "#{spaces*0}</#{tags.docbook_tag(0)}>"       if (lc <= 0)
+        when 5
+          x << "#{spaces*5}</#{tags.docbook_tag(5)}>"       if (lc <= 5)
+          x << "#{spaces*4}</#{tags.docbook_tag(4,@chlv)}>" if (lc <= 4)
+          x << "#{spaces*5}</#{tags.docbook_tag(3,@chlv)}>" if (lc <= 3)
+          x << "#{spaces*2}</#{tags.docbook_tag(2,@chlv)}>" if (lc <= 2)
+          x << "#{spaces*1}</#{tags.docbook_tag(1,@chlv)}>" if (lc <= 1)
+          x << "#{spaces*0}</#{tags.docbook_tag(0)}>"       if (lc <= 0)
+        when 6
+          x << "#{spaces*6}</#{tags.docbook_tag(6)}>"       if (lc <= 6)
+          x << "#{spaces*5}</#{tags.docbook_tag(5)}>"       if (lc <= 5)
+          x << "#{spaces*4}</#{tags.docbook_tag(4,@chlv)}>" if (lc <= 4)
+          x << "#{spaces*3}</#{tags.docbook_tag(3,@chlv)}>" if (lc <= 3)
+          x << "#{spaces*2}</#{tags.docbook_tag(2,@chlv)}>" if (lc <= 2)
+          x << "#{spaces*1}</#{tags.docbook_tag(1,@chlv)}>" if (lc <= 1)
+          x << "#{spaces*0}</#{tags.docbook_tag(0)}>"       if (lc <= 0)
+        end
+        x.join("\n")
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* fictionbook2.rb
+
+#+BEGIN_SRC ruby  :tangle "../lib/sisu/xml_fictionbook2.rb"
+# <<sisu_document_header>>
+module SiSU_XML_Fictionbook
+  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
+    include SiSU_Particulars
+  require_relative 'ao'                                 # ao.rb
+  require_relative 'se'                                 # se.rb
+    include SiSU_Env
+  require_relative 'txt_shared'                         # txt_shared.rb
+    include SiSU_TextUtils
+  require_relative 'xml_shared'                         # xml_shared.rb
+    include SiSU_XML_Munge
+  class Source
+    def initialize(opt)
+      @opt=opt
+      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
+    end
+    def read
+      begin
+        @md,@ao_array=@particulars.md,@particulars.ao_array
+        @env=@particulars.env
+        report
+        SiSU_XML_Fictionbook::Source::Scroll.new(@ao_array,@md).songsheet
+      rescue
+        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
+          __LINE__.to_s + ':' + __FILE__
+        end
+      ensure
+        Dir.chdir(@opt.f_pth[:pth])
+      end
+    end
+    private
+    def report
+      unless @opt.act[:quiet][:set]==:on
+        tool=(@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on) \
+        ? "#{@env.program.fictionbook_viewer} #{@md.file.output_path.xml_fictionbook.dir}/#{@md.file.base_filename.xml_fictionbook}"
+        : "[#{@opt.f_pth[:lng_is]}] #{@opt.fno}"
+        (@opt.act[:verbose][:set]==:on \
+        || @opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on) \
+        ? SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'Fictionbook',
+            tool
+          ).green_hi_blue
+        : SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            'Fictionbook',
+            tool
+          ).green_title_hi
+        if (@opt.act[:verbose_plus][:set]==:on \
+        || @opt.act[:maintenance][:set]==:on)
+          SiSU_Screen::Ansi.new(
+            @opt.act[:color_state][:set],
+            @opt.fns,
+            "#{@md.file.output_path.xml_fictionbook.dir}/#{@md.file.base_filename.xml_fictionbook}"
+          ).flow
+        end
+      end
+    end
+    class Scroll <Source
+      def initialize(data='',md='')
+        @data,@md=data,md
+        @trans=SiSU_XML_Munge::Trans.new(@md)
+        @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(md.opt)
+        @env=@particulars.env
+      end
+      def songsheet
+        @t='sisu'
+        data=@data
+        if @md.opt.act[:verbose_plus][:set]==:on
+          structure_collapsed(data)
+        end
+        head
+        endnotes=extract_endnotes
+        images_base64=extract_images
+        data=markup_text(data)
+        structure_build_collapsed(data,endnotes,images_base64)
+      end
+      def spaces
+        Ax[:spaces]
+      end
+      def tags
+        # collapsed -->
+        def collapsed
+          %w[ 0 1 2 3 4 5 ]
+        end
+        def fictionbook
+          [
+            'section',
+            'section',
+            'section',
+            'section',
+            'section',
+            'section',
+            'section'
+          ]
+        end
+        self
+      end
+      def put(line)
+        puts line if @md.opt.act[:verbose_plus][:set]==:on
+      end
+      def head
+        version=SiSU_Env::InfoVersion.instance.get_version
+        rb_ver=SiSU_Env::InfoVersion.instance.rbversion
+        date_available=if defined? @md.date.available; "\n     <p>#{@md.date.available} Initial version</p>"
+        else ''
+        end
+        date_modified=if defined? @md.date.modified; "\n      <p>#{@md.date.modified} Last Modified</p>"
+        else ''
+        end
+        coverpageimage=if defined? @md.make.cover_image[:cover]
+          %{\n    <coverpage><image href="##{@md.make.cover_image[:cover]}" /></coverpage>}
+        else ''
+        end
+        if defined? @md.authors \
+        and @md.authors.length > 0
+          authors=[]
+          @md.authors.each do |author|
+            authors << '    <author>'
+            if not author[:others].empty?
+              authors << %{      <first-name>#{author[:others]}</first-name>}
+            end
+            if not author[:the].empty?
+              authors << %{      <last-name>#{author[:the]}</last-name>}
+            end
+            authors << '    </author>'
+          end
+          authors=authors.join("\n")
+        end
+        <<-WOK
+<?xml version="1.0" encoding="UTF-8"?>
+<FictionBook xmlns:xl="http://www.w3.org/1999/xlink"
+ xmlns="http://www.gribuser.ru/xml/fictionbook/2.0">
+<description>
+  <title-info>
+    <genre match="100">***</genre>
+#{authors}
+    <book-title>#{@md.title.full}</book-title>#{coverpageimage}
+    <annotation>
+    </annotation>
+    <date value="#{@md.date.published}">#{@md.date.published}</date>
+  </title-info>
+     <document-info>
+    <author>
+      <first-name/>
+      <last-name/>
+      <nickname/>
+    </author>
+    <program-used>#{version.project} #{version.version} and #{rb_ver}</program-used>
+    <date value="#{version.date}">#{version.date}</date>
+    <src-url>#{@md.file.output_path.manifest.url}/#{@md.file.base_filename.manifest}</src-url>
+    <id></id>
+    <version>1.0</version>
+    <history>#{date_available}#{date_modified}
+    </history>
+  </document-info>
+</description>
+<body>
+        WOK
+      end
+      def extract_endnotes                                #work on
+        endnotes,endnotes_raw,endnotes_b=[],[],[]
+        @data.each do |para|
+          endnotes_raw << para.obj.scan(/#{Mx[:en_a_o]}(.+?)#{Mx[:en_a_c]}/m)
+          endnotes_b << para.obj.scan(/#{Mx[:en_b_o]}(.+?)#{Mx[:en_b_c]}/m)
+        end
+        endnotes_raw.flatten.each do |en|
+          en=@trans.markup_fictionbook(en)
+          endnotes << en.gsub(/([\d+*]+)\s+(.+)/m,
+            %{<section id="footnote\\1">\n
+<title><p>\\1.</p></title>\n
+<p>\\2</p>\n
+</section>})
+        end
+        endnotes_raw=[]
+        endnotes
+      end
+      def extract_images                                #work on
+        begin
+          require 'base64'
+        rescue LoadError
+          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
+            error('base64 NOT FOUND (LoadError)')
+        end
+        images_raw,images_base64_fb2=[],[]
+        images_base64={}
+        if defined? @md.make.cover_image[:cover]
+          images_raw << @md.make.cover_image[:cover]
+        end
+        @data.each do |para|
+          images_raw << para.obj.scan(/#{Mx[:lnk_o]}\s*(\S+?\.(?:png|jpg|gif)).+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)/m)
+        end
+        images_raw.flatten.sort.each do |img|
+          imgpth=@env.url.images_local + '/' + img
+          open(imgpth)
+          if FileTest.file?(imgpth)
+            images_base64[img]=Base64.encode64(File.read(imgpth))
+          end
+        end
+        images_raw=[]
+        images_base64.each_key do |k|
+          imgtype=case k
+          when /\.jpg/ then 'jpeg'
+          when /\.png/ then 'png'
+          when /\.gif/ then 'gif'
+          else              'jpeg'
+          end
+          images_base64_fb2 << %{<binary content-type="image/#{imgtype}" id="#{k}">#{images_base64[k]}
+</binary>
+}
+        end
+        images_base64_fb2.join("\n")
+      end
+      def markup_text(data)
+        data.each_with_index do |o,i|
+          if o.is ==:heading || o.is ==:para
+            o.obj=@trans.markup_fictionbook(o.obj,o.is) #unless o.obj==nil
+          end
+        end
+        data
+      end
+      def tail(images_base64_fb2)
+        <<-WOK
+</body>
+#{images_base64_fb2}
+</FictionBook>
+        WOK
+      end
+      def output(o,comment='')
+         puts o.lc == (0..6) \
+         ? "#{spaces*o.lc}<#{o.lc}>[#{o.ocn}] #{o.ln} #{o.obj}</#{o.lc}>#{comment}"
+         : "<#{o.lc}>[#{o.ocn}] #{o.ln} #{o.obj}</#{o.lc}>#{comment}"
+      end
+      def structure_collapsed(data)
+        puts "\ncollapsed structure, heading outline --->\n\n"
+        data.each_with_index do |o,i|
+          if  (o.is ==:heading || o.is ==:heading_insert)
+            output(o)
+          end
+        end
+      end
+      def endnotes_build(endnotes,filename_fictionbook)
+        if endnotes.length > 0
+          filename_fictionbook.puts %{</body><body name="notes">}
+          endnotes.each do |en|
+            filename_fictionbook.puts SiSU_TextUtils::Wrap.new(en,80,6).line_wrap
+          end
+        end
+      end
+      def structure_build_collapsed(data,endnotes,images_base64)
+        file=SiSU_Env::FileOp.new(@md)
+        filename_fictionbook=file.write_file.xml_fictionbook
+        h=0
+        doc_position=:head
+        filename_fictionbook.puts head
+        data.each_with_index do |o,i|
+          ocn=if @make.build.ocn?
+            (defined? o.ocn and not o.ocn.nil?) \
+            ? "\n#{Dx[:ocn_o]}#{o.ocn}#{Dx[:ocn_c]}"
+            : ''
+          else ''
+          end
+          if  o.is ==:heading
+            unless doc_position==:head
+              filename_fictionbook.puts structure_build_tag_close(o.lc,h)
+            end
+            doc_position=:body_and_tail
+            filename_fictionbook.puts %{#{spaces*o.lc}<#{tags.fictionbook[o.lc]}>
+#{spaces*o.lc}<title>
+}
+            filename_fictionbook.puts SiSU_TextUtils::Wrap.new("<p>#{o.obj}#{ocn}</p>",80,(o.lc*2+2)).line_wrap
+            filename_fictionbook.puts %{#{spaces*o.lc}</title>}
+            h=o.lc
+          elsif  o.is ==:heading_insert \
+          and o.obj =~/Endnotes/ \
+          and o.ln == 1
+            break
+          elsif (o.of ==:para or o.of ==:block)
+            filename_fictionbook.puts SiSU_TextUtils::Wrap.new("<p>#{o.obj}#{ocn}</p>",80,6).line_wrap
+          end
+        end
+        filename_fictionbook.puts structure_build_tag_close(0,h)
+        endnotes_build(endnotes,filename_fictionbook)
+        filename_fictionbook.puts tail(images_base64)
+        filename_fictionbook.close
+      end
+      def structure_build_tag_close(lc,h)
+        x=[]
+        case h
+        when 0
+          x << "#{spaces*0}</#{tags.fictionbook[0]}>" if (lc <= 0)
+        when 1
+          x << "#{spaces*1}</#{tags.fictionbook[1]}>" if (lc <= 1)
+          x << "#{spaces*0}</#{tags.fictionbook[0]}>" if (lc <= 0)
+        when 2
+          x << "#{spaces*2}</#{tags.fictionbook[2]}>" if (lc <= 2)
+          x << "#{spaces*1}</#{tags.fictionbook[1]}>" if (lc <= 1)
+          x << "#{spaces*0}</#{tags.fictionbook[0]}>" if (lc <= 0)
+        when 3
+          x << "#{spaces*3}</#{tags.fictionbook[3]}>" if (lc <= 3)
+          x << "#{spaces*2}</#{tags.fictionbook[2]}>" if (lc <= 2)
+          x << "#{spaces*1}</#{tags.fictionbook[1]}>" if (lc <= 1)
+          x << "#{spaces*0}</#{tags.fictionbook[0]}>" if (lc <= 0)
+        when 4
+          x << "#{spaces*4}</#{tags.fictionbook[4]}>" if (lc <= 4)
+          x << "#{spaces*3}</#{tags.fictionbook[3]}>" if (lc <= 3)
+          x << "#{spaces*2}</#{tags.fictionbook[2]}>" if (lc <= 2)
+          x << "#{spaces*1}</#{tags.fictionbook[1]}>" if (lc <= 1)
+          x << "#{spaces*0}</#{tags.fictionbook[0]}>" if (lc <= 0)
+        when 5
+          x << "#{spaces*5}</#{tags.fictionbook[5]}>" if (lc <= 5)
+          x << "#{spaces*4}</#{tags.fictionbook[4]}>" if (lc <= 4)
+          x << "#{spaces*3}</#{tags.fictionbook[3]}>" if (lc <= 3)
+          x << "#{spaces*2}</#{tags.fictionbook[2]}>" if (lc <= 2)
+          x << "#{spaces*1}</#{tags.fictionbook[1]}>" if (lc <= 1)
+          x << "#{spaces*0}</#{tags.fictionbook[0]}>" if (lc <= 0)
+        when 6
+          x << "#{spaces*6}</#{tags.fictionbook[6]}>" if (lc <= 6)
+          x << "#{spaces*5}</#{tags.fictionbook[5]}>" if (lc <= 5)
+          x << "#{spaces*4}</#{tags.fictionbook[4]}>" if (lc <= 4)
+          x << "#{spaces*3}</#{tags.fictionbook[3]}>" if (lc <= 3)
+          x << "#{spaces*2}</#{tags.fictionbook[2]}>" if (lc <= 2)
+          x << "#{spaces*1}</#{tags.fictionbook[1]}>" if (lc <= 1)
+          x << "#{spaces*0}</#{tags.fictionbook[0]}>" if (lc <= 0)
+        end
+        x.join("\n")
+      end
+    end
+  end
+end
+__END__
+#+END_SRC
+
+* document header
+
+#+NAME: sisu_document_header
+#+BEGIN_SRC text
+encoding: utf-8
+- Name: SiSU
+
+  - Description: documents, structuring, processing, publishing, search
+    xml
+
+  - Author: Ralph Amissah
+    <ralph.amissah@gmail.com>
+
+  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+    2020, 2021, Ralph Amissah,
+    All Rights Reserved.
+
+  - License: GPL 3 or later:
+
+    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 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 <http://www.gnu.org/licenses/>.
+
+    If you have Internet connection, the latest version of the GPL should be
+    available at these locations:
+    <http://www.fsf.org/licensing/licenses/gpl.html>
+    <http://www.gnu.org/licenses/gpl.html>
+
+    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
+
+  - SiSU uses:
+    - Standard SiSU markup syntax,
+    - Standard SiSU meta-markup syntax, and the
+    - Standard SiSU object citation numbering and system
+
+  - Homepages:
+    <http://www.sisudoc.org>
+
+  - Git
+    <https://git.sisudoc.org/projects/>
+    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
+    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
+#+END_SRC
-- 
cgit v1.2.3