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