-*- 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