-*- mode: org -*-
#+TITLE:       sisu xhtml including epub
#+DESCRIPTION: documents - structuring, various output representations & search
#+FILETAGS:    :sisu:xhtml:
#+AUTHOR:      Ralph Amissah
#+EMAIL:       [[mailto:ralph.amissah@gmail.com][ralph.amissah@gmail.com]]
#+COPYRIGHT:   Copyright (C) 2015 - 2021 Ralph Amissah
#+LANGUAGE:    en
#+STARTUP:     content hideblocks hidestars noindent entitiespretty
#+OPTIONS:     H:3 num:nil toc:t \n:nil @:t ::t |:t ^:nil _:nil -:t f:t *:t <:t
#+PROPERTY:    header-args  :exports code
#+PROPERTY:    header-args+ :noweb yes
#+PROPERTY:    header-args+ :eval no
#+PROPERTY:    header-args+ :results no
#+PROPERTY:    header-args+ :cache no
#+PROPERTY:    header-args+ :padline no
#+PROPERTY:    header-args+ :mkdirp yes

* xhtml.rb

#+HEADER: :tangle "../lib/sisu/xhtml.rb"
#+BEGIN_SRC ruby
#<<sisu_document_header>>
module SiSU_XHTML
  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
    include SiSU_Particulars
  require_relative 'se'                                 # se.rb
    include SiSU_Env
  require_relative 'xml_shared'                         # xml_shared.rb
    include SiSU_XML_Munge
  require_relative 'xml_format'                         # xml_format.rb
    include SiSU_XML_Format
  require_relative 'xml_persist'                        # xml_persist.rb
  require_relative 'rexml'                              # rexml.rb
    include SiSU_Rexml
  require_relative 'shared_metadata'                    # shared_metadata.rb
  @@alt_id_count=0
  @@tablefoot=''
  class Source
    def initialize(opt)
      @opt=opt
      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
    end
    def read
      begin
        @env,@md,@ao_array=@particulars.env,@particulars.md,@particulars.ao_array
        unless @opt.act[:quiet][:set]==:on
          tool=if (@opt.act[:verbose_plus][:set]==:on \
          || @opt.act[:maintenance][:set]==:on)
            "#{@env.program.web_browser} file://#{@md.file.output_path.xhtml.dir}/#{@md.file.base_filename.xhtml}"
          elsif @opt.act[:verbose][:set]==:on
            "#{@env.program.web_browser} file://#{@md.file.output_path.xhtml.dir}/#{@md.file.base_filename.xhtml}"
          else "[#{@opt.f_pth[:lng_is]}] #{@opt.fno}"
          end
          (@opt.act[:verbose][:set]==:on \
          || @opt.act[:verbose_plus][:set]==:on \
          || @opt.act[:maintenance][:set]==:on) \
          ? SiSU_Screen::Ansi.new(
              @opt.act[:color_state][:set],
              'XHTML',
              tool
            ).green_hi_blue
          : SiSU_Screen::Ansi.new(
              @opt.act[:color_state][:set],
              'XHTML',
              tool
            ).green_title_hi
          if (@opt.act[:verbose_plus][:set]==:on \
          || @opt.act[:maintenance][:set]==:on)
            SiSU_Screen::Ansi.new(
              @opt.act[:color_state][:set],
              @opt.fns,
              "/#{@md.file.output_path.xhtml.dir}/#{@md.file.base_filename.xhtml}"
            ).flow
          end
        end
        SiSU_XHTML::Source::Songsheet.new(@particulars).song
      rescue
        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
          __LINE__.to_s + ':' + __FILE__
        end
      ensure
        SiSU_Env::CreateSite.new(@opt).cp_css
        Dir.chdir(@opt.f_pth[:pth])
      end
    end
    private
    class Songsheet
      def initialize(particulars)
        @env,@md,@ao_array,@particulars=particulars.env,particulars.md,particulars.ao_array,particulars
        @file=SiSU_Env::FileOp.new(@md)
      end
      def song
        begin
          SiSU_XHTML::Source::Scroll.new(@particulars).songsheet
          if (@md.opt.act[:verbose][:set]==:on \
          || @md.opt.act[:verbose_plus][:set]==:on \
          || @md.opt.act[:maintenance][:set]==:on)
            SiSU_XHTML::Source::Tidy.new(@md,@file.place_file.xhtml.dir).xml # test wellformedness, comment out when not in use
          end
          SiSU_Rexml::Rexml.new(@md,@file.place_file.xhtml.dir).xml if @md.opt.act[:maintenance][:set]==:on # test rexml parsing, comment out when not in use #debug
        rescue
          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
            __LINE__.to_s + ':' + __FILE__
          end
        ensure
        end
      end
    end
    class Scroll
      require_relative 'xhtml_shared'                   # xhtml_shared.rb #check already called
      require_relative 'txt_shared'                     # txt_shared.rb
        include SiSU_TextUtils
      require_relative 'css'                            # css.rb
      def initialize(particulars)
        @env,@md,@ao_array=particulars.env,particulars.md,particulars.ao_array
        @tab="\t"
        @trans=SiSU_XML_Munge::Trans.new(@md)
        @sys=SiSU_Env::SystemCall.new
        @per=SiSU_XML_Persist::Persist.new
      end
      def songsheet
        begin
          pre
          @data=markup(@ao_array)
          post
          publish
        ensure
          SiSU_XML_Persist::Persist.new.persist_init
        end
      end
    protected
      def embedded_endnotes(dob='')
        dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}(\d+)\s+(.+?)#{Mx[:en_a_c]}/,
            '<endnote><number>\1</number><note>\2</note></endnote> ').
          gsub(/#{Mx[:en_b_o]}([*+]\d+)\s+(.+?)#{Mx[:en_b_c]}/,
            '<endnote><symbol>\1</symbol><note>\2</note></endnote> ').
          gsub(/#{Mx[:en_a_o]}([*+]+)\s+(.+?)#{Mx[:en_a_c]}/,
            '<endnote><symbol>\1</symbol><note>\2</note></endnote> ')
      end
      def extract_endnotes(dob='')
        notes=dob.obj.scan(/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})([\d*+]+\s+.+?)(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/)
        notes.flatten.each do |e|
          s=e.to_s
          util=SiSU_TextUtils::Wrap.new(s,70)
          wrap=util.line_wrap
          wrap=wrap.gsub(/^(\d+)\s+(.+?)\s*\Z/m, <<WOK
#{Ax[:tab]*1}<endnote notenumber="\\1">
#{Ax[:tab]*2}\\1. \\2
#{Ax[:tab]*1}</endnote>
WOK
).
            gsub(/^([*+]\d+)\s+(.+?)\s*\Z/m, <<WOK
#{Ax[:tab]*1}<endnote symbol="\\1">
#{Ax[:tab]*2}\\1 \\2
#{Ax[:tab]*1}</endnote>
WOK
).
            gsub(/^([*+]+)\s+(.+?)\s*\Z/m, <<WOK
#{Ax[:tab]*1}<endnote symbol="\\1.length">
#{Ax[:tab]*2}\\1 \\2
#{Ax[:tab]*1}</endnote>
WOK
)
#KEEP alternative presentation of endnotes
#        wrap=wrap.gsub(/^(\d+)\s+(.+?)\s*\Z/m, <<WOK
##{Ax[:tab]*1}<p class="endnote" notenumber="\\1">
##{Ax[:tab]*2}\\1. \\2
##{Ax[:tab]*1}</p>
#WOK
#)
          @endnotes << wrap
        end
      end
      def xml_head
        metadata=SiSU_Metadata::Summary.new(@md).xhtml_scroll.metadata
        @per.head << metadata
      end
      def name_tags(dob)
        tags=''
        if defined? dob.tags \
        and dob.tags.length > 0 # insert tags "hypertargets"
          dob.tags.each do |t|
            tags=tags << %{<named id="#{t}" />}
          end
        end
        tags
      end
      def xml_structure(dob,type='norm')
        if dob.is ==:para \
        || dob.is ==:heading
          named=name_tags(dob)
          if dob.is==:heading
            lv=dob.ln
            dob.ln + 2
          else lv=nil
          end
          extract_endnotes(dob)
          dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'<en>\1</en>'). #footnote/endnote clean
            gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'<en>\1</en>')
          util=SiSU_TextUtils::Wrap.new(dob.obj,70)
          wrapped=util.line_wrap
          @per.body << if defined? dob.ocn
            %{#{Ax[:tab]*0}<object id="#{dob.ocn}">}
          else                        "#{Ax[:tab]*0}<object>"
          end
          @per.body << %{#{Ax[:tab]*1}<text class="#{type}">#{named}\n#{Ax[:tab]*2}#{wrapped}\n#{Ax[:tab]*1}</text>} unless lv  # main text, contents, body KEEP
          @per.body << %{#{Ax[:tab]*1}<text class="h#{lv}">#{named}\n#{Ax[:tab]*2}#{wrapped}\n#{Ax[:tab]*1}</text>} if lv # main text, contents, body KEEP
          @per.body << @endnotes.compact.join if @endnotes.length > 0 # main text, endnotes KEEP
          @per.body << "#{Ax[:tab]*1}<ocn>#{dob.ocn}</ocn>" if defined? dob.ocn
          @per.body << "#{Ax[:tab]*0}</object>"
          @endnotes=[]
        end
      end
      def block_structure(dob)
        named=name_tags(dob)
        dob=@trans.markup_block(dob)
        dob.obj=dob.obj.strip.
          gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'<en>\1</en>'). #footnote/endnote clean
          gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'<en>\1</en>') #footnote/endnote clean
        @per.body << %{#{Ax[:tab]*0}<object id="#{dob.ocn}">}
        @per.body << %{#{Ax[:tab]*1}<ocn>#{dob.ocn}</ocn>}
        @per.body << %{#{Ax[:tab]*1}<text class="block">#{named}#{Ax[:tab]*1}}
        @per.body << %{#{Ax[:tab]*2}#{dob.obj}#{Ax[:tab]*1}}
        @per.body << %{#{Ax[:tab]*1}</text>}
        @per.body << "#{Ax[:tab]*0}</object>"
      end
      def group_structure(dob)
        named=name_tags(dob)
        dob=@trans.markup_group(dob)
        dob.obj=dob.obj.strip.
          gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'<en>\1</en>'). #footnote/endnote clean
          gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'<en>\1</en>') #footnote/endnote clean
        @per.body << %{#{Ax[:tab]*0}<object id="#{dob.ocn}">}
        @per.body << %{#{Ax[:tab]*1}<ocn>#{dob.ocn}</ocn>}
        @per.body << %{#{Ax[:tab]*1}<text class="group">#{named}#{Ax[:tab]*1}}
        @per.body << %{#{Ax[:tab]*2}#{dob.obj}#{Ax[:tab]*1}}
        @per.body << %{#{Ax[:tab]*1}</text>}
        @per.body << "#{Ax[:tab]*0}</object>"
      end
      def poem_structure(dob)
        named=name_tags(dob)
        dob=@trans.markup_group(dob)
        dob.obj=dob.obj.strip
        @per.body << %{#{Ax[:tab]*0}<object id="#{dob.ocn}">}
        @per.body << %{#{Ax[:tab]*1}<ocn>#{dob.ocn}</ocn>}
        @per.body << %{#{Ax[:tab]*1}<text class="verse">#{named}#{Ax[:tab]*1}}
        @per.body << %{#{Ax[:tab]*2}#{dob.obj}#{Ax[:tab]*1}}
        @per.body << %{#{Ax[:tab]*1}</text>}
        @per.body << "#{Ax[:tab]*0}</object>"
      end
      def code_structure(dob)
        named=name_tags(dob)
        dob=@trans.markup_group(dob)
        dob.obj=dob.obj.gsub(/\s\s/,'&#160;&#160;').strip
        @per.body << %{#{Ax[:tab]*0}<object id="#{dob.ocn}">}
        @per.body << %{#{Ax[:tab]*1}<ocn>#{dob.ocn}</ocn>}
        @per.body << %{#{Ax[:tab]*1}<text class="code">#{named}#{Ax[:tab]*1}}
        @per.body << %{#{Ax[:tab]*2}#{dob.obj}#{Ax[:tab]*1}}
        @per.body << %{#{Ax[:tab]*1}</text>}
        @per.body << "#{Ax[:tab]*0}</object>"
      end
      def table_structure(dob)
        named=name_tags(dob)
        table=SiSU_XHTML_Shared::TableXHTML.new(dob)
        @per.body << %{#{Ax[:tab]*0}<object id="#{dob.ocn}">}
        @per.body << %{#{Ax[:tab]*1}<ocn>#{dob.ocn}</ocn>}
        @per.body << %{#{Ax[:tab]*2}#{named}#{table.table.obj}}
        @per.body << "#{Ax[:tab]*0}</object>"
      end
      def markup(data)
        @endnotes=[]
        @rcdc=false
        @level,@cont,@copen,@xml_contents_close=[],[],[],[]
        xml_head
        (0..7).each { |x| @cont[x]=@level[x]=false }
        (4..7).each { |x| @xml_contents_close[x]='' }
        data.each do |dob|
          dob=@trans.markup(dob)
          if @rcdc==false \
          and (dob.obj =~/~meta/ \
          and dob.obj =~/Document Information/)
            @rcdc=true
          end
          if dob.obj !~/(^#{Rx[:meta]}|#{Mx[:br_eof]}|#{Mx[:br_endnotes]})/
            if defined? dob.ocn #look to move to format section
              ocn=(dob.ocn.to_s =~/\d+/) ? dob.ocn : nil
              @p_num=SiSU_XML_Format::ParagraphNumber.new(@md,ocn)
            end
            if not @rcdc
              x=SiSU_XML_Format::FormatSeg.new(@md,dob)
              if dob.is==:heading
                xml_structure(dob)
                dob.obj=case dob.ln
                when 0 then x.heading_body0
                when 1 then x.heading_body1
                when 2 then x.heading_body2
                when 3 then x.heading_body3
                when 4 then x.heading_body4
                when 5 then x.heading_body5
                when 6 then x.heading_body6
                when 7 then x.heading_body7
                end
              else
                if dob.is ==:verse
                  poem_structure(dob)
                elsif dob.is ==:group
                  group_structure(dob)
                elsif dob.is ==:block
                  block_structure(dob)
                elsif dob.is ==:code
                  code_structure(dob)
                elsif dob.is ==:table
                  table_structure(dob)
                elsif dob.is ==:para \
                and dob.indent.to_s =~/[1-9]/ \
                and dob.bullet_==true
                  xml_structure(dob,"indent_bullet#{dob.indent}")
                elsif dob.is ==:para \
                and dob.indent.to_s =~/[1-9]/ \
                and dob.indent == dob.hang
                  xml_structure(dob,"indent#{dob.indent}")
                elsif dob.is==:para \
                and dob.hang.to_s =~/[0-9]/ \
                and dob.indent != dob.hang
                  xml_structure(dob,"hang#{dob.hang.to_s}_indent#{dob.indent.to_s}")
                else xml_structure(dob)
                end
              end
              if dob.obj =~/.*<:#>.*$/ #investigate removal
                dob.obj=if dob.obj =~ /#{Mx[:pa_o]}:i[1-9]#{Mx[:pa_c]}/
                  txt_obj={ txt: dob }
                  format_text=FormatTextObject.new(@md,txt_obj)
                  format_text.scr_inden_ocn_e_no_paranum
                end
              end
            else #
            end
            dob.obj=dob.obj.gsub(/#{Mx[:pa_o]}:\S+#{Mx[:pa_c]}/,'') if dob.obj
          end
        end
        6.downto(4) do |x|
          y=x - 1; v=x - 3
          @per.body << "#{Ax[:tab]*5}</content>\n#{Ax[:tab]*y}</contents#{v}>" if @level[x]==true
        end
        3.downto(1) do |x|
          y=x - 1
          @per.body << "#{Ax[:tab]*y}</heading#{x}>" if @level[x]==true
        end
      end
      def pre
        rdf=SiSU_XML_Tags::RDF.new(@md)
        @per.head,@per.body=[],[]
        stylesheet=SiSU_Style::CSS_HeadInfo.new(@md,'xhtml').stylesheet
        encoding=(@sys.locale =~/utf-?8/i) \
        ? '<?xml version="1.0" encoding="UTF-8" standalone="no"?>'
        : '<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>'
        @per.open =<<WOK
#{encoding}
#{stylesheet.css_head_xml}
#{rdf.comment_xml}
<document>
WOK
        @per.head << %{<head>\n\t<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />}
        @per.body << '<body>'
      end
      def post
        @per.head << '</head>'
        @per.body << '</body>'
        @per.close = '</document>'
      end
      def publish
        content=[]
        content << @per.open << @per.head << @per.body << @per.metadata
        content << @per.tail << @per.close
        content=content.flatten.compact
        Output.new(content,@md).xhtml
        @@xml={}
      end
    end
    class Output
      def initialize(data,md)
        @data,@md=data,md
        @file=SiSU_Env::FileOp.new(@md)
      end
      def xhtml
        SiSU_Env::FileOp.new(@md).mkdir
        filename_xml=@file.write_file.xhtml
        @data.each do |str|
          str=str.gsub(/\A\s+\Z/m,'') #str.gsub(/^\s+$/,'')
          filename_xml.puts str unless str.empty?
        end
        filename_xml.close
      end
    end
    class Tidy
      def initialize(md,file)
        @md,@file=md,file
        @prog=SiSU_Env::InfoProgram.new
      end
      def xml
        if @prog.tidy !=false
          if (@md.opt.act[:verbose_plus][:set]==:on \
          || @md.opt.act[:maintenance][:set]==:on)
            unless @md.opt.act[:quiet][:set]==:on
              SiSU_Screen::Ansi.new(
                @md.opt.act[:color_state][:set],
                'invert',
                'Using XML Tidy',
                'check document structure'
              ).colorize
              tell=SiSU_Screen::Ansi.new(
                @md.opt.act[:color_state][:set],
                'invert',
                '',
                ''
              )
              tell.grey_open
            end
            tidyfile='/dev/null' #don't want one or screen output, check for alternative flags
            tidy=SiSU_Env::SystemCall.new(@file,tidyfile)
            tidy.well_formed?
            tell.p_off unless @md.opt.act[:quiet][:set]==:on
          end
        end
      end
    end
  end
end
__END__
,** Notes:
tidy -xml scroll.xhtml >> index.tidy
<?xml version="1.0"?>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml version="1.0" encoding="UTF-16" standalone="no"?>
#+END_SRC

* epub2.rb
** xhtml_epub2.rb

#+HEADER: :tangle "../lib/sisu/xhtml_epub2.rb"
#+BEGIN_SRC ruby
#<<sisu_document_header>>
module SiSU_XHTML_EPUB2
  begin
    require 'pstore'
  rescue LoadError
    SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).
      error('pstore NOT FOUND (LoadError)')
  end
  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
    include SiSU_Particulars
  require_relative 'xml_shared'                         # xml_shared.rb
    include SiSU_XML_Munge
  require_relative 'xhtml_table'                        # xhtml_table.rb
  require_relative 'xhtml_epub2_format'                 # xhtml_epub2_format.rb
    include SiSU_XHTML_EPUB2_Format
  require_relative 'xhtml_epub2_segments'               # xhtml_epub2_segments.rb
    include SiSU_XHTML_EPUB2_Seg
  require_relative 'xhtml_epub2_tune'                   # xhtml_epub2_tune.rb
    include SiSU_XHTML_EPUB2_Tune
  require_relative 'xhtml_epub2_concordance'            # xhtml_epub2_concordance.rb
  require_relative 'xhtml_epub2_persist'                # xhtml_epub2_persist.rb
  class Source
    def initialize(opt)
      @opt=opt
      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
    end
    def read
      begin
        songsheet
      ensure
        Dir.chdir(@opt.f_pth[:pth])
      end
    end
    def songsheet
      begin
        @md=@particulars.md
        @fnb=@md.fnb
        @env=@particulars.env
        unless @opt.act[:quiet][:set]==:on
          tool=(@opt.act[:verbose][:set]==:on \
          || @opt.act[:verbose_plus][:set]==:on \
          || @opt.act[:maintenance][:set]==:on) \
          ? "#{@env.program.epub_viewer} #{@md.file.output_path.epub.dir}/#{@md.file.base_filename.epub}"
          : "[#{@opt.f_pth[:lng_is]}] #{@opt.fno}"
          (@opt.act[:verbose][:set]==:on \
          || @opt.act[:verbose_plus][:set]==:on \
          || @opt.act[:maintenance][:set]==:on) \
          ? SiSU_Screen::Ansi.new(
              @opt.act[:color_state][:set],
              'EPUB',
              tool
            ).green_hi_blue
          : SiSU_Screen::Ansi.new(
              @opt.act[:color_state][:set],
              'EPUB',
              tool
            ).green_title_hi
          if (@opt.act[:verbose_plus][:set]==:on \
          || @opt.act[:maintenance][:set]==:on)
            SiSU_Screen::Ansi.new(
              @opt.act[:color_state][:set],
              @opt.fns,
              "#{@md.file.output_path.epub.dir}/#{@md.file.base_filename.epub}"
            ).flow
          end
        end
        @env.processing_path.epub_bld #(@md)
        @env.processing_path.epub_cp_images(@md)
        data=nil
        SiSU_Env::FileOp.new(@md).mkdir.output.epub
        @tuned_file_array=SiSU_XHTML_EPUB2::Source::XHTML_Environment.new(@particulars).tuned_file_instructions
        data=@tuned_file_array
        per=SiSU_XHTML_EPUB2::Source::Toc.new(@md,data).songsheet
        data=@tuned_file_array
        SiSU_XHTML_EPUB2::Source::ScrollHeadAndSegToc.new(@md,per).in_common #watch
        SiSU_XHTML_EPUB2::Source::Seg.new(@md,data).songsheet
        SiSU_XHTML_EPUB2::Source::Output.new(@md).songsheet
      rescue
        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
          __LINE__.to_s + ':' + __FILE__
        end
      ensure
        unless (@opt.act[:verbose_plus][:set]==:on \
        || @opt.act[:maintenance][:set]==:on)
          texfiles=Dir["#{@env.processing_path.tune}/#{@opt.fns}*"]
          texfiles.each do |f|
            if FileTest.file?(f)
              File.unlink(f)
            end
          end
        end
        SiSU_Env::Clear.new(@opt.selections.str,@opt.fns).param_instantiate
        @@flag,@@scr,@@seg,@@seg_endnotes,@@seg_subtoc={},{},{},{},{}
        @@tracker=0
        @@seg_name,@@seg_name_html,@@seg_subtoc_array,@@seg_endnotes_array,@@tablefoot=Array.new(5){[]}
        @@filename_seg,@@seg_url,@@to_lev4,@@get_hash_to,@@get_hash_fn='','','','',''
      end
    end
    private
    class XHTML_Environment
      def initialize(particulars)
        @particulars=particulars
        @md,@env=particulars.md,particulars.env
        @env,@css=particulars.env,SiSU_Style::CSS.new
      end
      def directories
        SiSU_Env::FileOp.new(@md).mkdir.output.epub
      end
      def tuned_file_instructions
        @tell=SiSU_Screen::Ansi.new(@md.opt.act[:color_state][:set])
        directories
        ao_array=@particulars.ao_array # ao file drawn here
        @tuned_file_array=SiSU_XHTML_EPUB2_Tune::Tune.new(ao_array,@md).songsheet
        @tuned_file_array
      end
    end
    class Endnotes
      include SiSU_XHTML_EPUB2_Format
      def initialize(md,data)
        @md,@data=md,data
      end
      def scroll
        @scr_endnotes=[]
        @data.each do |dob|
          pg=dob.dup
          unless pg.is ==:code
            if pg.obj =~/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})[\d*+]+ /
              endnote_array=[]
              if pg.obj=~/#{Mx[:en_a_o]}[\d*+].+?#{Mx[:en_a_c]}/m
                endnote_array = pg.obj.scan(/#{Mx[:en_a_o]}[\d*+]+(.+?)#{Mx[:en_a_c]}/m)
              end
              if pg.obj=~/#{Mx[:en_b_o]}[\d*]+\s.+?#{Mx[:en_b_c]}/m
                endnote_array = pg.obj.scan(/#{Mx[:en_b_o]}[\d*]+(.+?)#{Mx[:en_b_c]}/m)
              end
              if pg.obj=~/#{Mx[:en_b_o]}[\d+]+\s.+?#{Mx[:en_b_c]}/m
                endnote_array = pg.obj.scan(/#{Mx[:en_b_o]}[\d+]+(.+?)#{Mx[:en_b_c]}/m)
              end
              endnote_array.flatten.each do |note|
                txt_obj={ txt: note }
                format_scroll=SiSU_XHTML_EPUB2_Format::FormatScroll.new(@md,txt_obj)
                @scr_endnotes << format_scroll.endnote_body
              end
            end
          end
        end
        @scr_endnotes
      end
    end
    class Toc
      @@seg_url=''
      @@firstseg=nil
      def initialize(md=nil,data='')
        @md,@data=md,data
        @epub=SiSU_XHTML_EPUB2_Format::HeadInformation.new(@md)
        @tell=SiSU_Screen::Ansi.new(@md.opt.act[:color_state][:set]) if @md
        @make=SiSU_Env::ProcessingSettings.new(@md)
        @per=SiSU_XHTML_EPUB2_Persist::PersistTOC.new
      end
      def songsheet #extracts toc for scroll & seg
        begin
          if (@md.opt.act[:verbose][:set]==:on \
          || @md.opt.act[:verbose_plus][:set]==:on \
          || @md.opt.act[:maintenance][:set]==:on)
            SiSU_Screen::Ansi.new(
              @md.opt.act[:color_state][:set],
              'Toc'
            ).txt_grey
          end
          toc=nil
          @@firstseg=nil
          SiSU_XHTML_EPUB2_Persist::PersistTOC.new.persist_init
          md_opf_a_content,md_opf_a_spine,md_opf_a_guide=[],[],[]
          @nav_no=0
          @s_a_no,@s_b_no,@s_c_no,@s_d_no,@lv5_no,@lv6_no=0,0,0,0,0,0
          @per.ncx << @epub.toc_ncx.open #epub ncx navmap
          @per.ncx << @epub.toc_ncx.head_open << @epub.toc_ncx.head << @epub.toc_ncx.head_close
          @per.ncx << @epub.toc_ncx.doc_title << @epub.toc_ncx.doc_author
          @per.ncx << @epub.toc_ncx.navmap_open
          @per.opf << @epub.metadata_opf.package_open
          @per.opf << @epub.metadata_opf.metadata
          @per.opf << @epub.metadata_opf.manifest_open
          @per.seg << %{<div class="content">\n<div class="substance">}
          @per.scr << %{<div class="content">\n<div class="substance">}
          if defined? @md.make.cover_image \
          and @md.make.cover_image.is_a?(Hash) \
          and @md.make.cover_image[:cover] =~/\S+/
            md_opf_a_content << @epub.metadata_opf.manifest_cover_image_information(@md)
            md_opf_a_spine << @epub.metadata_opf.spine_cover_image
            md_opf_a_guide << @epub.metadata_opf.guide_cover_image
          end
          md_opf_a_content << @epub.metadata_opf.manifest_content_sisu_toc
          if @make.build.toc?
            md_opf_a_spine << @epub.metadata_opf.spine_sisu_toc
            md_opf_a_guide << @epub.metadata_opf.guide_sisu_toc
          end
          @ncxo=[false,false,false,false,false,false,false]
          @dob_toc2,@dob_toc3=nil,nil
          @ncx_cls=[]
          @level_a_first_occurrence=true
          @data.each do |dob|
            if dob.is==:heading \
            || dob.is==:heading_insert
              dob_toc=dob.dup
              toc=case dob_toc.ln
              when 0
                @s_a_no +=1
                lv_name='section_a' + @s_a_no.to_s
                @nav_no+=1
                @nav_no2=@nav_no
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[7]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[6]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[5]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[4]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[3]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[2]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[1]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[0]
                @ncxo[0],@ncxo[1],@ncxo[2],@ncxo[3],@ncxo[4],@ncxo[5],@ncxo[6],@ncxo[7]=
                  true,  false,   false,   false,   false,   false,   false,   false
                @epub.sections(dob_toc,lv_name)
                if @level_a_first_occurrence \
                && @make.build.toc?
                  @per.ncx << @epub.toc_ncx.navmap_sisu_toc(@nav_no) #epub ncx navmap, toc
                  @nav_no+=1
                  @level_a_first_occurrence=false
                end
                @per.ncx << @epub.toc_ncx.navpoint(dob_toc,@nav_no,lv_name) if dob_toc
                md_opf_a_content << @epub.metadata_opf.manifest_content(dob_toc,lv_name)
                md_opf_a_spine << @epub.metadata_opf.spine(dob_toc,lv_name)
                md_opf_a_guide << @epub.metadata_opf.guide(dob_toc,lv_name)
                SiSU_XHTML_EPUB2::Source::Toc.new(@md,dob_toc).level_0
              when 1
                @s_b_no +=1
                lv_name='section_b' + @s_b_no.to_s
                @nav_no+=1
                @nav_no2=@nav_no
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[7]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[6]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[5]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[4]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[3]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[2]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[1]
                @ncxo[1],@ncxo[2],@ncxo[3],@ncxo[4],@ncxo[5],@ncxo[6],@ncxo[7]=
                  true,  false,   false,   false,   false,   false,   false
                @epub.sections(dob_toc,lv_name)
                @per.ncx << @epub.toc_ncx.navpoint(dob_toc,@nav_no,lv_name) if dob_toc
                md_opf_a_content << @epub.metadata_opf.manifest_content(dob_toc,lv_name)
                md_opf_a_spine << @epub.metadata_opf.spine(dob_toc,lv_name)
                md_opf_a_guide << @epub.metadata_opf.guide(dob_toc,lv_name)
                SiSU_XHTML_EPUB2::Source::Toc.new(@md,dob_toc).level_1
              when 2
                @s_c_no +=1
                lv_name='section_c' + @s_c_no.to_s
                @nav_no+=1
                @nav_no2=@nav_no
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[7]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[6]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[5]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[4]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[3]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[2]
                @ncxo[2],@ncxo[3],@ncxo[4],@ncxo[5],@ncxo[6],@ncxo[7]=
                  true,  false,   false,   false,   false,   false
                @epub.sections(dob_toc,lv_name)
                @per.ncx << @epub.toc_ncx.navpoint(dob_toc,@nav_no,lv_name) if dob_toc
                md_opf_a_content << @epub.metadata_opf.manifest_content(dob_toc,lv_name)
                md_opf_a_spine << @epub.metadata_opf.spine(dob_toc,lv_name)
                md_opf_a_guide << @epub.metadata_opf.guide(dob_toc,lv_name)
                SiSU_XHTML_EPUB2::Source::Toc.new(@md,dob_toc).level_2
              when 3
                @s_d_no +=1
                lv_name='section_d' + @s_d_no.to_s
                @nav_no+=1
                @nav_no3=@nav_no
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[7]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[6]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[5]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[4]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[3]
                @ncxo[3],@ncxo[4],@ncxo[5],@ncxo[6],@ncxo[7]=
                  true,  false,   false,   false,   false
                @epub.sections(dob_toc,lv_name)
                @per.ncx << @epub.toc_ncx.navpoint(dob_toc,@nav_no,lv_name) if dob_toc
                md_opf_a_content << @epub.metadata_opf.manifest_content(dob_toc,lv_name)
                md_opf_a_spine << @epub.metadata_opf.spine(dob_toc,lv_name)
                md_opf_a_guide << @epub.metadata_opf.guide(dob_toc,lv_name)
                SiSU_XHTML_EPUB2::Source::Toc.new(@md,dob_toc).level_3
              when 4
                @ncx_cls=[]
                lv_name=dob_toc.name
                @nav_no+=1
                @dob_name=dob.name
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[7]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[6]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[5]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[4]
                @ncxo[4],@ncxo[5],@ncxo[6],@ncxo[7]=
                  true,  false,   false,   false
                @per.ncx << @epub.toc_ncx.navpoint(dob_toc,@nav_no,lv_name) if dob_toc
                md_opf_a_content << @epub.metadata_opf.manifest_content(dob_toc,lv_name)
                md_opf_a_spine << @epub.metadata_opf.spine(dob_toc,lv_name)
                md_opf_a_guide << @epub.metadata_opf.guide(dob_toc,lv_name)
                SiSU_XHTML_EPUB2::Source::Toc.new(@md,dob_toc).level_4
              when 5
                @ncx_cls=[]
                hashtag='#o' + dob_toc.ocn.to_s
                lv_name=@dob_name
                @nav_no+=1
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[7]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[6]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[5]
                @ncxo[5],@ncxo[6],@ncxo[7]=
                  true,  false, false
                @per.ncx << @epub.toc_ncx.navpoint(dob_toc,@nav_no,lv_name,hashtag) if dob_toc
                md_opf_a_content << @epub.metadata_opf.manifest_content(dob_toc,lv_name,hashtag)
                md_opf_a_spine << @epub.metadata_opf.spine(dob_toc,lv_name,hashtag)
                md_opf_a_guide << @epub.metadata_opf.guide(dob_toc,lv_name,hashtag)
                SiSU_XHTML_EPUB2::Source::Toc.new(@md,dob_toc).level_5
              when 6
                @ncx_cls=[]
                hashtag='#o' + dob_toc.ocn.to_s
                lv_name=@dob_name
                @nav_no+=1
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[7]
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[6]
                @ncxo[6],@ncxo[7]=
                  true,  false
                @per.ncx << @epub.toc_ncx.navpoint(dob_toc,@nav_no,lv_name,hashtag) if dob_toc
                md_opf_a_content << @epub.metadata_opf.manifest_content(dob_toc,lv_name,hashtag)
                md_opf_a_spine << @epub.metadata_opf.spine(dob_toc,lv_name,hashtag)
                md_opf_a_guide << @epub.metadata_opf.guide(dob_toc,lv_name,hashtag)
                SiSU_XHTML_EPUB2::Source::Toc.new(@md,dob_toc).level_6
              when 7
                @ncx_cls=[]
                hashtag='#o' + dob_toc.ocn.to_s
                lv_name=@dob_name
                @nav_no+=1
                @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[7]
                @ncxo[7]=true
                @per.ncx << @epub.toc_ncx.navpoint(dob_toc,@nav_no,lv_name,hashtag) if dob_toc
                md_opf_a_content << @epub.metadata_opf.manifest_content(dob_toc,lv_name,hashtag)
                md_opf_a_spine << @epub.metadata_opf.spine(dob_toc,lv_name,hashtag)
                md_opf_a_guide << @epub.metadata_opf.guide(dob_toc,lv_name,hashtag)
                SiSU_XHTML_EPUB2::Source::Toc.new(@md,dob_toc).level_7
              else nil
              end
              toc.each do |k,d|
                d.gsub!(/(?:#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})\s*/m,' ')
              end if toc
              if @@firstseg.nil? \
              and dob.ln==4 \
              and dob.name =~/\S+/
                @@firstseg=dob.name
              end
              if toc
                begin
                  @per.seg << toc[:seg]
                  @per.scr << toc[:seg]
                rescue
                  SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
                    __LINE__.to_s + ':' + __FILE__
                  end
                end
              end
            end
          end
          @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[6]
          @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[5]
          @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[4]
          @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[3]
          @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[2]
          @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[1]
          @per.ncx << @epub.toc_ncx.navpoint_close if @ncxo[0]
          @ncxo[0],@ncxo[1],@ncxo[2],@ncxo[3],@ncxo[4],@ncxo[5],@ncxo[6]=false,false,false,false,false,false,false
          md_opf_a_content << @epub.metadata_opf.manifest_images(@md.ec[:image])
          @per.seg << "</div>\n</div>"
          @per.scr << "</div>\n</div>"
          @per.ncx << @epub.toc_ncx.navmap_close
          @per.ncx << @epub.toc_ncx.close
          @per.opf << md_opf_a_content << @epub.metadata_opf.manifest_close
          @per.opf << @epub.metadata_opf.spine_open << md_opf_a_spine << @epub.metadata_opf.spine_close
          @per.opf << @epub.metadata_opf.guide_open << md_opf_a_guide << @epub.metadata_opf.guide_close
          @per.opf << @epub.metadata_opf.package_close
          @per.opf=@per.opf.flatten
          SiSU_XHTML_EPUB2::Source::Output.new(@md,@per.opf).epub_metadata_opf
          SiSU_XHTML_EPUB2::Source::Output.new(@md,@per.ncx).epub_toc_ncx
          @md.firstseg=@@firstseg
          @per
        ensure
          SiSU_XHTML_EPUB2_Persist::Persist.new.persist_init
        end
      end
    protected
      def level_0
        dob=@data
        linkname=dob.obj.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'').strip
        link=dob.ocn
        title=linkname
        toc={}
        txt_obj={ txt: title }
        format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
        toc[:seg]=format_toc.lev1
        title=if dob.ocn ==0 then linkname
        else
          @per.scr <<  '<br />'
          link=(dob.ln) \
          ? dob.ln
          : ''
          %{<b><a href="##{link}">#{linkname}</a></b>}
        end
        txt_obj={ txt: title }
        format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
        toc[:scr]=format_toc.lev1
        toc
      end
      def level_1
        dob=@data
        linkname=dob.obj.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'').strip
        link=dob.ocn
        title=if dob.obj !~/Document Information/
          linkname
        else
          link='metadata'
          %{<b><a href="#{link}#{Sfx[:epub_xhtml]}">#{linkname}</a></b>}
        end
        toc={}
        txt_obj={ txt: title }
        format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
        toc[:seg]=if dob.name =~/^meta/ \
        and dob.obj =~/Document Information/ #check
          format_toc.lev0
        else format_toc.lev1
        end
        title=if dob.ocn ==0
          if dob.name =~/^meta/ \
          and dob.obj =~/Document Information/
            %{<a href="#docinfo">#{linkname}</a>}
          else linkname
          end
        else
          @per.scr <<  '<br />'
          link=(dob.ln) \
          ? dob.ln
          : ''
          %{<b><a href="##{link}">#{linkname}</a></b>}
        end
        txt_obj={ txt: title }
        format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
        toc[:scr]=if dob.name =~/^meta/ \
        and dob.obj =~/Document Information/
          format_toc.lev0
        else format_toc.lev1
        end
        toc
      end
      def level_2
        dob=@data
        linkname=dob.obj.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'').strip
        ocn=dob.ocn
        if ocn \
        and ocn !~/#/
          p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,ocn)
        end
        txt_obj={ txt: linkname }
        format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
        toc={}
        toc[:seg]=format_toc.lev2
        if p_num
          title=%{#{p_num.goto}#{linkname}</a>}
          txt_obj={ txt: title }
          format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
          toc[:scr]=format_toc.lev2
        end
        toc
      end
      def level_3
        dob=@data
        linkname=dob.obj.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'').strip
        ocn=dob.ocn
        if ocn \
        and ocn !~/#/
          p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,ocn)
        end
        txt_obj={ txt: linkname }
        format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
        toc={}
        toc[:seg]=format_toc.lev3
        if p_num
          title=%{#{p_num.goto}#{linkname}</a>}
          txt_obj={ txt: title }
          format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
          toc[:scr]=format_toc.lev3
        end
        toc
      end
      def level_4
        dob=@data
        linkname=dob.obj.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'').strip
        ocn=dob.ocn
        p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,ocn) if ocn
        if dob.ln==4
          seg_link=%{  <a href="#{dob.name}#{Sfx[:epub_xhtml]}">
    #{dob.obj}
  </a> }
          @@seg_url=dob.name
        elsif dob.obj =~/\d+.\d+.\d+.\d+|\d+.\d+.\d+|\d+.\d+|\d+/
          seg_link=dob.obj.gsub(/^(\d+.\d+.\d+.\d+|\d+.\d+.\d+|\d+.\d+|\d+)(.*)/,
            %{<a href="\\1#{Sfx[:epub_xhtml]}">} +
            %{\\1 \\2</a> })
        end
        p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,ocn) if ocn
        txt_obj={ txt: seg_link }
        format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
        toc={}
        toc[:seg]=format_toc.lev4
        title=%{#{p_num.goto}#{linkname}</a>} if p_num
        txt_obj={ txt: title }
        format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
        toc[:scr]=format_toc.lev4
        toc
      end
      def level_5
        dob=@data
        linkname=dob.obj.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'').strip
        ocn=dob.ocn
        toc={}
        if ocn \
        and ocn.to_s !~/#/
          p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,ocn)
          lnk_n_txt=%{  <a href="#{@@seg_url}#{Sfx[:epub_xhtml]}#o#{ocn}">
    #{linkname}
  </a>}
          txt_obj={ txt: lnk_n_txt }
          format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
          toc[:seg]=format_toc.lev5
          title=%{#{p_num.goto}#{linkname}</a>}
          txt_obj={ txt: title }
          format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
          toc[:scr]=format_toc.lev5
        end
        toc
      end
      def level_6
        dob=@data
        linkname=dob.obj.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'').strip
        ocn=dob.ocn
        toc={}
        if ocn \
        and ocn.to_s !~/#/
          p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,ocn)
          lnk_n_txt=%{  <a href="#{@@seg_url}#{Sfx[:epub_xhtml]}#o#{ocn}">
  #{linkname}
</a>}
          txt_obj={ txt: lnk_n_txt }
          format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
          toc[:seg]=format_toc.lev6
          title=%{#{p_num.goto}#{linkname}</a>}
          txt_obj={ txt: title }
          format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
          toc[:scr]=format_toc.lev6
        end
        toc
      end
      def level_7
        dob=@data
        linkname=dob.obj.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'').strip
        ocn=dob.ocn
        toc={}
        if ocn \
        and ocn.to_s !~/#/
          p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,ocn)
          lnk_n_txt=%{  <a href="#{@@seg_url}#{Sfx[:epub_xhtml]}#o#{ocn}">
  #{linkname}
</a>}
          txt_obj={ txt: lnk_n_txt }
          format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
          toc[:seg]=format_toc.lev7
          title=%{#{p_num.goto}#{linkname}</a>}
          txt_obj={ txt: title }
          format_toc=SiSU_XHTML_EPUB2_Format::FormatToc.new(@md,txt_obj)
          toc[:scr]=format_toc.lev7
        end
        toc
      end
    end
    class ScrollHeadAndSegToc < Toc
      def initialize(md='',per='',links_guide_toc='')
        @md,@per,@links_guide_toc=md,per,links_guide_toc
      end
      def in_common
        toc_shared=[]
        segtoc=[]
        if (@md.opt.act[:verbose][:set]==:on \
        || @md.opt.act[:verbose_plus][:set]==:on \
        || @md.opt.act[:maintenance][:set]==:on)
          SiSU_Screen::Ansi.new(
            @md.opt.act[:color_state][:set],
            'Scroll & Segtoc'
          ).txt_grey
        end
        format_head_toc=SiSU_XHTML_EPUB2_Format::HeadToc.new(@md)
        dochead=format_head_toc.head
        dochead=dochead.gsub(/toc\.(html)/,'doc.\1') #kludge
        toc_shared << dochead #<< ads.div.major
        segtoc << format_head_toc.head #<< ads.div.major
        if defined? @md.rights.all \
        and @md.rights.all
          rights=format_head_toc.rights.all
          rights=SiSU_XHTML_EPUB2_Tune::CleanXHTML.new(rights).clean
        end
        if defined? @md.notes.prefix_b \
        and @md.notes.prefix_b
          prefix_b=format_head_toc.prefix_b
          prefix_b=SiSU_XHTML_EPUB2_Tune::CleanXHTML.new(prefix_b).clean
        end
        tmp_head=nil
        doc_title_endnote=@md.title.full.gsub(/(\*+)/,'<sup><a href="#endnotes">\1</a></sup>')
        tmp_head=doc_title_endnote + "\n"
        txt_obj={ txt: tmp_head }
        format_txt_obj=SiSU_XHTML_EPUB2_Format::FormatTextObject.new(@md,txt_obj)
        toc_shared << format_txt_obj.center_bold
        segtoc << format_txt_obj.center_bold
        if defined? @md.creator.author \
        and @md.creator.author
          creator_endnote=@md.creator.author.gsub(/(\*+)/,%{#{$ep[:hsp]}<sup><a href="#notes">\\1</a></sup>})
          tmp_head=creator_endnote + "\n"
          txt_obj={ txt: tmp_head }
          format_txt_obj=SiSU_XHTML_EPUB2_Format::FormatTextObject.new(@md,txt_obj)
          toc_shared << format_txt_obj.center_bold
          segtoc << format_txt_obj.center_bold
        end
        tmp_head=nil
        if defined? @md.prefix_a \
        and @md.prefix_a
          tmp_head ||= %{#{@md.prefix_a}\n}
          toc_shared << tmp_head.dup
          segtoc << tmp_head.dup
        end
        tmp_head=nil
        toc_shared << @links_guide_toc
        if defined? @md.rights.all \
        and @md.rights.all
          toc_shared << rights
        end
        if defined? @md.prefix_b \
        and @md.prefix_b
          toc_shared << prefix_b
        end
        #Table of Contents added/appended here
        toc_shared << @per.scr
        segtoc << @links_guide_toc
        segtoc << @per.seg
        if defined? @md.rights.all \
        and @md.rights.all
          segtoc << rights
        end
        if defined? @md.prefix_b \
        and @md.prefix_b
          segtoc << prefix_b
        end
        #Segtoc tail added here
        segtoc << format_head_toc.xhtml_close
        segtoc=segtoc.flatten.compact #watch
        SiSU_XHTML_EPUB2::Source::Output.new(@md).make_cover_image
        SiSU_XHTML_EPUB2::Source::Output.new(@md,segtoc).make_segtoc
        segtoc=[]
        @per.scr,@per.seg=[],[]
        toc_shared
      end
    end
    class Table < SiSU_XHTML_Table::TableXHTML
    end
    class Seg < SiSU_XHTML_EPUB2_Seg::Seg
    end
    class Output
      def initialize(md,output='')
        @md,@output=md,output
        @epub_doc="#{@md.fnb}.epub"
        @epub_header=SiSU_XHTML_EPUB2_Format::HeadInformation.new(@md)
        @make=SiSU_Env::ProcessingSettings.new(@md)
        @make_file=SiSU_Env::CreateFile.new(@md.fns)
      end
      def songsheet
        mimetype
        metainf_container
        css
        images if @md.ec[:image]
       #concordance #uncomment to enable inclusion of concordance file
        output_zip
      end
      def mimetype
        out=@make_file.epub.mimetype
        out<<@epub_header.mimetype
        out.close
      end
      def metainf_container #container.xml file in META-INF directory
        out=@make_file.epub.metainf_cont
        out<<@epub_header.metainf_container
        out.close
      end
      def css
        out=@make_file.epub.xhtml_css
        out << SiSU_XHTML_EPUB2_Format::CSS.new.css_epub_xhtml
        out.close
      end
      def epub_toc_ncx
        begin
          out=@make_file.epub.toc_ncx
          @output.each do |para|
            unless para =~/\A\s*\Z/
              out.puts para
            end
          end
          out.close
        rescue
          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
            __LINE__.to_s + ':' + __FILE__
          end
        end
      end
      def epub_metadata_opf
        begin
          out=@make_file.epub.metadata
          @output.each do |para|
            unless para =~/\A\s*\Z/
              out.puts para
            end
          end
          out.close
        rescue
          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
            __LINE__.to_s + ':' + __FILE__
          end
        end
      end
      def images
#puts @md.env.path.image_source_include
#puts @md.env.processing_path.epub
#puts @md.env.path.image_source_include_local
puts @md.file.output_path.epub.rel_image
        #img_pth=$sisu_base_data + '/image'
        img_pth=@md.env.path.image_source_include
        img_src_pth=unless @md.opt.f_pth[:pth] =~/\/\S+?\/sisupod\/\S+?\/sisupod\/doc/
          @md.file.output_path.epub.rel_image
        else
          pt=/(\/\S+?\/sisupod\/\S+?\/sisupod)\/doc/.match(@md.opt.f_pth[:pth])[1]
          pt + '/image'
        end
        @md.ec[:image].each do |x|
          if FileTest.directory?("#{@md.env.processing_path.epub}/#{Ep[:d_oebps]}/image") \
          && FileTest.file?("#{img_src_pth}/#{x}")
            FileUtils::cp("#{img_src_pth}/#{x}","#{@md.env.processing_path.epub}/#{Ep[:d_oebps]}/image")
          #elsif FileTest.directory?("#{$sisu_base_data}/image") \
          #&& FileTest.file?("#{img_pth}/#{x}")
          #  FileUtils::cp("#{img_pth}/#{x}","#{@md.env.processing_path.epub}/#{Ep[:d_oebps]}/image")
          elsif FileTest.directory?("#{@md.env.processing_path.epub}/#{Ep[:d_oebps]}/image") \
          && FileTest.file?("#{img_pth}/#{x}")
            FileUtils::cp("#{img_pth}/#{x}","#{@md.env.processing_path.epub}/#{Ep[:d_oebps]}/image")
          else STDERR.puts %{\t*WARN* did not find image - "#{x}" in #{img_src_pth} or #{img_pth} [#{__FILE__}:#{__LINE__}]}
          end
        end
      end
      def concordance
        SiSU_XHTML_EPUB2_Concordance::Source.new(@md.opt).read
      end
      def output_zip
        FileUtils::mkdir_p(@md.file.output_path.epub.dir) unless FileTest.directory?(@md.file.output_path.epub.dir)
        if FileTest.directory?(@md.env.processing_path.epub) \
        and SiSU_Env::SystemCall.new.zip
          pwd=Dir.pwd
          Dir.chdir(@md.env.processing_path.epub)
          system("
            zip -qXr9D #{@epub_doc} *
          ")
          FileUtils::mv(@epub_doc, @md.file.place_file.epub.dir)
          Dir.chdir(pwd)
          unless @md.opt.act[:maintenance][:set]==:on
            FileUtils::rm_r(@md.env.processing_path.epub)
          end
        else
          SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).mark('*EXITED epub* zip program not found') unless SiSU_Env::SystemCall.new.zip
        end
      end
      def make_cover_image
        begin
          if @md.make.cover_image? \
          and @md.make.cover_image.is_a?(Hash) \
          and @md.make.cover_image[:cover] =~/\S+/
            filename_xhtml=@make_file.epub.xhtml_cover_image
            cover_image=<<WOK
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Cover</title>
    <meta http-equiv="Content-Type" content='text/html; charset=utf-8' />
    <link rel="stylesheet" href="css/xhtml.css" type="text/css" />
    <style type="text/css"> img { max-width: 100%; } </style>
  </head>
  <body xml:lang="en">
    <div class="svg_outer">
      <div class="svg_inner">
        <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="0 0 #{@md.make.cover_image[:w]} #{@md.make.cover_image[:h]}" preserveAspectRatio="xMidYMid meet">
        <image width="#{@md.make.cover_image[:w]}" height="#{@md.make.cover_image[:h]}" xl:href="image/#{@md.make.cover_image[:cover]}" />
        </svg>
      </div>
    </div>
  </body>
</html>
WOK
            filename_xhtml.puts cover_image,"\n"
            filename_xhtml.close
          end
        rescue
          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
            __LINE__.to_s + ':' + __FILE__
          end
        end
      end
      def make_segtoc
        begin
          if @make.build.toc?
            filename_xhtml=@make_file.epub.xhtml_index
            @output.each do |para|
              para=para.strip
              unless para =~/\A\s*\Z/
                filename_xhtml.puts para,"\n"
              end
            end
            filename_xhtml.close
          end
        rescue
          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
            __LINE__.to_s + ':' + __FILE__
          end
        end
      end
    end
  end
end
__END__
#+END_SRC

** xhtml_epub2_concordance.rb

#+HEADER: :tangle "../lib/sisu/xhtml_epub2_concordance.rb"
#+BEGIN_SRC ruby
#<<sisu_document_header>>
module SiSU_XHTML_EPUB2_Concordance
  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
    include SiSU_Particulars
  require_relative 'se'                                 # se.rb
    include SiSU_Env
  require_relative 'xhtml_parts'                        # xhtml_parts.rb
  require_relative 'xhtml_epub2_format'                 # xhtml_epub2_format.rb
    include SiSU_XHTML_EPUB2_Format
  class Source
    def initialize(opt)
      @opt=opt
      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
    end
    def read
      begin
        @env,@md=@particulars.env,@particulars.md
        wordmax=@env.concord_max
        unless @md.wc_words.nil?
          if @md.wc_words < wordmax
            SiSU_XHTML_EPUB2_Concordance::Source::Words.new(@particulars).songsheet
          else
            SiSU_Screen::Ansi.new(
              @md.opt.act[:color_state][:set],
              "*WARN* concordance skipped, large document has over #{wordmax} words (#{@md.wc_words})"
            ).warn unless @md.opt.act[:quiet][:set]==:on
          end
        else
          SiSU_Screen::Ansi.new(
            @md.opt.act[:color_state][:set],
            "*WARN* wc (word count) is off, concordance will be processed for all files including those over the max set size of: #{wordmax} words"
          ).warn unless @md.opt.act[:quiet][:set]==:on
          SiSU_XHTML_EPUB2_Concordance::Source::Words.new(@particulars).songsheet
        end
      rescue
        SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
          __LINE__.to_s + ':' + __FILE__
        end
      ensure
      end
    end
    private
    class DocTitle
      #revisit, both requires (html & xml_shared) needed for stand alone operation (sisu -w [filename])
      require_relative 'xhtml_epub2'                    # xhtml_epub2.rb
      def initialize(particulars)
        @particulars,@md=particulars,particulars.md
        @data=SiSU_XHTML_EPUB2::Source::XHTML_Environment.new(particulars).tuned_file_instructions
        @fnb=@md.fnb
        @lex_button=%{<a href="http://www.jus.uio.no/sisu/" target="_top"><img border="0" height="44" width="144" valign="center" src="../_sisu/image/sisu.png" alt="SiSU home"></a>}
        @doc_details =<<WOK
<table summary="links to text related to this rudimentary index" width="96%" border="0" bgcolor="white" cellpadding="0" align="center"><tr><td width="2%" align="right">#{$ep[:hsp]}</td><td width="94%" valign="top" align="justify"><h1 class="small"><a href="#{@md.file.base_filename.epub}"><b>#{@md.title.full}</b></a></h1><p class="bold">#{@md.creator.author}</p></td></tr></table>
WOK
      end
      def create
        @css=SiSU_Env::CSS_Stylesheet.new(@particulars.md)
        format_head_toc=SiSU_XHTML_EPUB2_Format::HeadToc.new(@md)
        dochead=format_head_toc.head
        <<WOK
#{dochead}
<div class="content">
 #{@doc_details}
<p>Word index links are to html versions of the text the segmented version followed by the scroll (single document) version.<br />[For segmented text references [T1], [T2] or [T3] appearing without a link, indicates that the word appears in a title (or subtitle) of the text (that is identifiable by the appended object citation number).]</p>
<p>(The word listing/index is Case sensitive: Capitalized words appear before lower case)</p>
  <p>
    <b>word</b> (number of occurences)<br />linked references to word within document <br />
    [if number of occurences exceed number of references - word occurs more than once in at least one reference. Footnote/endnotes are either assigned to the paragraph from which they are referenced or ignored, so it is relevant to check the footnotes referenced from within a paragraph as well.]
  </p>
  <p>
    (After the page is fully loaded) you can jump directly to a word by appending a hash (#) and the word to the url for this text, (do not forget that words are case sensitive, and may be listed twice (starting with and without an upper case letter)), #your_word # [#{$ep[:hsp]}http://[web host]/#{@fnb}/concordance.html#your_word#{$ep[:hsp]}]
  </p>
WOK
      end
    end
    class Word
      @@word_previous=''
      def initialize(word,freq)
        @word,@freq=word,freq
      end
      def html
        w=if @word.capitalize==@@word_previous
          %{\n<p class="concordance_word">#{@word}</p><p class="concordance_count">(#{@freq})</p>\n\t<p class="concordance_object"> }
        else n=@word.strip.gsub(/\s+/,'_') #also need to convert extended character set to html
          %{\n<p class="concordance_word"><a name="#{n}">#{@word}</a></p><p class="concordance_count">(#{@freq})</p>\n\t<p class="concordance_object"> }
        end
        @@word_previous=@word.capitalize
        w
      end
    end
    class Words
      require_relative 'xhtml_epub2_format'             # xhtml_epub2_format.rb
        include SiSU_XHTML_EPUB2_Format
      require_relative 'se'                             # se.rb
        include SiSU_Screen
      def initialize(particulars)
        @particulars=particulars
        begin
          @env,@md,@ao_array=particulars.env,particulars.md,particulars.ao_array
          @path="#{@env.processing_path.epub}"
          @freq=Hash.new(0)
          @rxp_lv0=/^#{Mx[:lv_o]}0:/
          @rxp_lv1=/^#{Mx[:lv_o]}1:/
          @rxp_lv2=/^#{Mx[:lv_o]}2:/
          @rxp_lv3=/^#{Mx[:lv_o]}3:/
          @rxp_seg=/^#{Mx[:lv_o]}4:(\S+?)#{Mx[:lv_c]}/
          @rxp_title=Regexp.new("^#{Mx[:meta_o]}title#{Mx[:meta_c]}\s*(.+?)\s*$")
          @rxp_t0=Regexp.new('^T0')
          @rxp_t1=Regexp.new('^T1')
          @rxp_t2=Regexp.new('^T2')
          @rxp_t3=Regexp.new('^T3')
          @rxp_excluded1=/(?:https?|file|ftp):\/\/\S+/
          @rxp_excluded0=/^(?:#{Mx[:fa_bold_o]}|#{Mx[:fa_italics_o]})?(?:to\d+|\d+|&nbsp;|#{Mx[:br_endnotes]}|EOF|#{Mx[:br_eof]}|thumb_\S+|snap_\S+|_+|-+|[(]?(?:ii+|iv|vi+|ix|xi+|xiv|xv|xvi+|xix|xx)[).]?|\S+?_\S+|[\d_]+\w\S+|[\w\d]{1,2}|\d{1,3}\w?|[0-9a-f]{16,64}|\d{2,3}x\d{2,3}|\S{0,2}sha\d|\S{0,3}\d{4}w\d\d|\b\w\d+|\d_all\b|e\.?g\.?)(?:#{Mx[:fa_bold_c]}|#{Mx[:fa_italics_c]})?$/mi #this regex causes and cures a stack dump in ruby 1.9 !!!
          @rgx_splitlist=%r{[—.,;:-]+|#{Mx[:nbsp]}+}mi
          @rgx_scanlist=%r{#{Mx[:fa_italics_o]}[a-zA-Z0-9"\s]{2,12}#{Mx[:fa_italics_c]}|#{Mx[:fa_bold_o]}[a-zA-Z0-9"\s]{2,12}#{Mx[:fa_bold_c]}|#{Mx[:url_o]}https?://\S+?#{Mx[:url_c]}|file://\S+|<\S+?>|\w+|[a-zA-Z]+}mi
        rescue
          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
            __LINE__.to_s + ':' + __FILE__
          end
        end
      end
      def songsheet
        begin
          #fix to use
          p __LINE__.to_s + ':' + __FILE__
          p "#{@path}/content/#{@md.fn[:epub_concord]}"
          p "#{@md.file.output_path.epub.dir}/#{@md.file.base_filename.epub}"
          @file_concordance=File.open("#{@path}/content/#{@md.fn[:epub_concord]}",'w')
          map_para
        rescue
          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
            __LINE__.to_s + ':' + __FILE__
          end
        ensure
          @file_concordance.close
        end
      end
    protected
      def location_scroll(wordlocation,show)
        @wordlocation=wordlocation
        %{<a href="doc#{Sfx[:epub_xhtml]}\##{@wordlocation}">#{@wordlocation}</a>;  }
      end
      def location_seg(wordlocation,show)
        @wordlocation,@show=wordlocation,show
        @word_location_seg=wordlocation.gsub(/(.+?)\#(\d+)/,"\\1#{Sfx[:epub_xhtml]}#o\\2") unless wordlocation.nil?
        case @wordlocation
        when @rxp_t1
          %{[<a href="doc#{Sfx[:epub_xhtml]}##{@show}">H</a>]#{@show},  }
        when @rxp_t2
          %{[<a href="doc#{Sfx[:epub_xhtml]}##{@show}">H</a>]#{@show},  }
        when @rxp_t3
          %{[<a href="doc#{Sfx[:epub_xhtml]}##{@show}">H</a>]#{@show},  }
        else %{<a href="#{@word_location_seg}">#{@show}</a>,  }
        end
      end
      def map_para
        @seg,toy=nil,nil
        @word_map={}
        @ao_array.each do |line|
          if defined? line.ocn
            if (line.is ==:heading \
            || line.is ==:heading_insert) \
            && line.ln==4
              @seg=line.name
            end
            if line.ocn.to_s =~/\d+/ then toy=line.ocn.to_s
            end
            if toy =~/\d+/ \
            and toy !~/^0$/
              line.obj=line.obj.split(@rgx_splitlist).join(' ') #%take in word or other match
              for word in line.obj.scan(@rgx_scanlist) #%take in word or other match
                word=word.gsub(/#{Mx[:lnk_o]}|#{Mx[:lnk_c]}|#{Mx[:url_o]}|#{Mx[:url_c]}/,'').
                  gsub(/#{Mx[:fa_o]}\S+?#{Mx[:fa_o_c]}/,'').
                  gsub(/#{Mx[:fa_c_o]}\S+?#{Mx[:fa_c]}/,'').
                  gsub(/#{Mx[:gl_o]}#[a-z]+#{Mx[:gl_c]}/,'').
                  gsub(/#{Mx[:gl_o]}#[0-9]+#{Mx[:gl_c]}/,'').
                  gsub(/^\S$/,'')
                word=nil if word.empty?
                word=nil if word =~@rxp_excluded0 #watch
                word=nil if word =~@rxp_excluded1 #watch
                word=nil if word =~/^\S$/
                if word
                  word=word.gsub(/#{Mx[:br_nl]}|#{Mx[:br_line]}/,' ').
                    gsub(/#{Mx[:fa_o]}[a-z]{1,7}#{Mx[:fa_o_c]}|#{Mx[:fa_c_o]}[a-z]{1,7}#{Mx[:fa_c]}/,'').
                    gsub(/#{Mx[:mk_o]}(?:[0-9a-f]{32}:[0-9a-f]{32}|[0-9a-f]{64}:[0-9a-f]{64})#{Mx[:mk_c]}/,'').
                    gsub(/#{Mx[:mk_o]}(?:[0-9a-f]{32}|[0-9a-f]{64})#{Mx[:mk_c]}/,'').
                    gsub(/#{Mx[:en_a_o]}(?:\d|[*+])*|#{Mx[:en_b_o]}(?:\d|[*+])*|#{Mx[:en_a_c]}|#{Mx[:en_b_c]}/mi,'').
                    gsub(/#{Mx[:fa_o]}\S+?#{Mx[:fa_o_c]}/,'').gsub(/#{Mx[:fa_c_o]}\S+?#{Mx[:fa_c]}/,'').
                    gsub(/<\/?\S+?>/,'').
                    gsub(/^\@+/,'').
                    strip.
                    gsub(/#{Mx[:tc_p]}.+/,'').
                    gsub(/[\.,;:"]$/,'').
                    gsub(/["]/,'').
                    gsub(/^\s*[\(]/,'').
                    gsub(/[\(]\s*$/,'').
                    gsub(/^(?:See|e\.?g\.?).+/,'').
                    gsub(/^\s*[.,;:]\s*/,'').
                    strip.
                    gsub(/^\(?[a-zA-Z]\)$/,'').
                    gsub(/^\d+(st|nd|rd|th)$/,'').
                    gsub(/^(\d+\.?)+$/, '').
                    gsub(/#{Mx[:mk_o]}|#{Mx[:mk_c]}/,'').
                    gsub(/:name#\S+/,'').
                    gsub(/^\S$/,'')
                  word=nil if word =~/^\S$/
                  word=nil if word =~/^\s*$/ #watch
                  if word
                    unless word =~/[A-Z][A-Z]/ \
                    or word =~/\w+\s\w+/
                      word=word.capitalize
                    end
                    @freq[word] +=1
                    @word_map[word] ||= []
                    if line !~@rxp_lv0 \
                    and line !~@rxp_lv1 \
                    and line !~@rxp_lv2 \
                    and line !~@rxp_lv3
                      @word_map[word] << location_seg("#{@seg}\##{toy}",toy)
                    else
                      @word_map[word] << case line
                      when @rxp_lv0 then location_seg('T0',toy)
                      when @rxp_lv1 then location_seg('T1',toy)
                      when @rxp_lv2 then location_seg('T2',toy)
                      when @rxp_lv3 then location_seg('T3',toy)
                      end
                    end
                  end
                end
              end
            end
          end
        end
        seg=''
        @file_concordance << SiSU_XHTML_EPUB2_Concordance::Source::DocTitle.new(@particulars).create
        alph=%W[A B C D E F G H I J K L M N O P Q R S T U V W X Y Z]
        @file_concordance << '<p>'
        alph.each {|x| @file_concordance << %{<a href="##{x}">#{x}</a>,#{$ep[:hsp]}}}
        @file_concordance << '</p>'
        letter=alph.shift
        @file_concordance << %{\n<p class="letter"><a name="A">A</a></p>}
        for word in @freq.keys.sort! {|a,b| a.downcase<=>b.downcase}
          f=/^(\S)/.match(word)[1]
          if letter < f.upcase
            while letter < f.upcase
              if alph.length > 0
                letter=alph.shift
                @file_concordance << %{\n<p class="letter"><a name="#{letter}">#{letter}</a></p>}
              else break
              end
            end
          end
          keyword=SiSU_XHTML_EPUB2_Concordance::Source::Word.new(word,@freq[word]).html
          if keyword !~ @rxp_excluded0
            if @word_map[word][0] =~ /\d+/
              @file_concordance << %{#{keyword}#{seg}#{@word_map[word].uniq.compact.join}}
            end
            @file_concordance << '</p>'
          end
          # special cases endnotes and header levels 1 - 3
        end
        credits=SiSU_Proj_XHTML::Bits.new.credits_sisu_epub
        @file_concordance << %{</div>#{credits}</body>\n</html>} # footer
      end
    end
  end
end
__END__
#+END_SRC

** xhtml_epub2_format.rb

#+HEADER: :tangle "../lib/sisu/xhtml_epub2_format.rb"
#+BEGIN_SRC ruby
#<<sisu_document_header>>
module SiSU_XHTML_EPUB2_Format
  class ParagraphNumber
    def initialize(md,ocn)
      @md,@ocn=md,ocn.to_s
      @ocn ||=''
    end
    def ocn_display
      make=SiSU_Env::ProcessingSettings.new(@md)
      if make.build.ocn?
        ocn_class='ocn'
        if @ocn==nil \
        or @ocn.to_i==0 \
        or @ocn.empty?
          %{<label class="ocn_off"></label>}
        else
          @ocn.gsub(/^(\d+|)$/,
            %{<label class="#{ocn_class}"><a href="#o\\1" class="lnk#{ocn_class}">\\1</a></label>})
        end
      else
        %{<label class="ocn_off"></label>}
      end
    end
    def name
      (@ocn==nil || @ocn.empty?) ? '' : %{<a name="#{@ocn}"></a>}
    end
    def id #w3c? "tidy" complains about numbers as identifiers ! annoying
      (@ocn==nil || @ocn.empty?) ? '' : %{id="o#{@ocn}"}
    end
    def goto
      (@ocn==nil || @ocn.empty?) ? '' : %{<a href="##{@ocn}">}
    end
  end
  class CSS
    def css_epub_xhtml
      <<-WOK
/* SiSU epub css default stylesheet */
  body {
    color: black;
    background: #ffffff;
    background-color: #ffffff;
  }
/*
    table {
      margin-left: 5%;
      display: block;
    }
    tr {
      display: block;
    }
    th,td {
      display: inline;
      vertical-align: top;
    }
*/
  a:link {
    color: #003399;
    text-decoration: none;
  }
  a:visited {
    color: #003399;
    text-decoration: none;
  }
  a:hover {
    color: #000000;
    background-color: #f9f9aa;
  }
/*
  a:hover {
    border-bottom: 2px solid #777777;
    background-color: #fff3b6;
  }
*/
  a:hover img {
    background-color: #ffffff;
  }
  a:active {
    color: #003399;
    text-decoration: underline;
  }
  a.lnkocn:link {
    color: #777777;
    text-decoration: none;
  }
  div {
    margin-left: 0;
    margin-right: 0;
  }
  div.p {
    margin-left: 5%;
    margin-right: 1%;
  }

  .norm, .bold, .verse, .group, .block, .alt {
    line-height: 133%;
    margin-left: 0em;
    margin-right: 2em;
    margin-top: 12px;
    margin-bottom: 0px;
    padding-left: 0em;
    text-indent: 0mm;
  }
  p, h0, h1, h2, h3, h4, h5, h6, h7 {
    display: block;
    font-family: verdana, arial, georgia, tahoma, sans-serif, helvetica, times, roman;
    font-size: 100%;
    font-weight: normal;
    line-height: 133%;
    text-align: justify;
    margin-left: 0em;
    margin-right: 2em;
    text-indent: 0mm;
    margin-top: 0.8em;
    margin-bottom: 0.8em;
  }
  p.norm { }
  p.i1 {padding-left: 1em;}
  p.i2 {padding-left: 2em;}
  p.i3 {padding-left: 3em;}
  p.i4 {padding-left: 4em;}
  p.i5 {padding-left: 5em;}
  p.i6 {padding-left: 6em;}
  p.i7 {padding-left: 7em;}
  p.i8 {padding-left: 8em;}
  p.i9 {padding-left: 9em;}

  p.h0i0 {
    padding-left: 0em;
    text-indent:  0em;
  }
  p.h0i1 {
    padding-left: 1em;
    text-indent: -1em;
  }
  p.h0i2 {
    padding-left: 2em;
    text-indent: -2em;
  }
  p.h0i3 {
    padding-left: 3em;
    text-indent: -3em;
  }
  p.h0i4 {
    padding-left: 4em;
    text-indent: -4em;
  }
  p.h0i5 {
    padding-left: 5em;
    text-indent: -5em;
  }
  p.h0i6 {
    padding-left: 6em;
    text-indent: -6em;
  }
  p.h0i7 {
    padding-left: 7em;
    text-indent: -7em;
  }
  p.h0i8 {
    padding-left: 8em;
    text-indent: -8em;
  }
  p.h0i9 {
    padding-left: 9em;
    text-indent: -9em;
  }

  p.h1i0 {
    padding-left: 0em;
    text-indent:  1em;
  }
  p.h1i1 {
    padding-left: 1em;
    text-indent:  0em;
  }
  p.h1i2 {
    padding-left: 2em;
    text-indent: -1em;
  }
  p.h1i3 {
    padding-left: 3em;
    text-indent: -2em;
  }
  p.h1i4 {
    padding-left: 4em;
    text-indent: -3em;
  }
  p.h1i5 {
    padding-left: 5em;
    text-indent: -4em;
  }
  p.h1i6 {
    padding-left: 6em;
    text-indent: -5em;
  }
  p.h1i7 {
    padding-left: 7em;
    text-indent: -6em;
  }
  p.h1i8 {
    padding-left: 8em;
    text-indent: -7em;
  }
  p.h1i9 {
    padding-left: 9em;
    text-indent: -8em;
  }

  p.h2i0 {
    padding-left: 0em;
    text-indent:  2em;
  }
  p.h2i1 {
    padding-left: 1em;
    text-indent:  1em;
  }
  p.h2i2 {
    padding-left: 2em;
    text-indent:  0em;
  }
  p.h2i3 {
    padding-left: 3em;
    text-indent: -1em;
  }
  p.h2i4 {
    padding-left: 4em;
    text-indent: -2em;
  }
  p.h2i5 {
    padding-left: 5em;
    text-indent: -3em;
  }
  p.h2i6 {
    padding-left: 6em;
    text-indent: -4em;
  }
  p.h2i7 {
    padding-left: 7em;
    text-indent: -5em;
  }
  p.h2i8 {
    padding-left: 8em;
    text-indent: -6em;
  }
  p.h2i9 {
    padding-left: 9em;
    text-indent: -7em;
  }

  p.h3i0 {
    padding-left: 0em;
    text-indent:  3em;
  }
  p.h3i1 {
    padding-left: 1em;
    text-indent:  2em;
  }
  p.h3i2 {
    padding-left: 2em;
    text-indent:  1em;
  }
  p.h3i3 {
    padding-left: 3em;
    text-indent:  0em;
  }
  p.h3i4 {
    padding-left: 4em;
    text-indent: -1em;
  }
  p.h3i5 {
    padding-left: 5em;
    text-indent: -2em;
  }
  p.h3i6 {
    padding-left: 6em;
    text-indent: -3em;
  }
  p.h3i7 {
    padding-left: 7em;
    text-indent: -4em;
  }
  p.h3i8 {
    padding-left: 8em;
    text-indent: -5em;
  }
  p.h3i9 {
    padding-left: 9em;
    text-indent: -6em;
  }

  p.h4i0 {
    padding-left: 0em;
    text-indent:  4em;
  }
  p.h4i1 {
    padding-left: 1em;
    text-indent:  3em;
  }
  p.h4i2 {
    padding-left: 2em;
    text-indent:  2em;
  }
  p.h4i3 {
    padding-left: 3em;
    text-indent:  1em;
  }
  p.h4i4 {
    padding-left: 4em;
    text-indent:  0em;
  }
  p.h4i5 {
    padding-left: 5em;
    text-indent: -1em;
  }
  p.h4i6 {
    padding-left: 6em;
    text-indent: -2em;
  }
  p.h4i7 {
    padding-left: 7em;
    text-indent: -3em;
  }
  p.h4i8 {
    padding-left: 8em;
    text-indent: -4em;
  }
  p.h4i9 {
    padding-left: 9em;
    text-indent: -5em;
  }

  p.h5i0 {
    padding-left: 0em;
    text-indent:  5em;
  }
  p.h5i1 {
    padding-left: 1em;
    text-indent:  4em;
  }
  p.h5i2 {
    padding-left: 2em;
    text-indent:  3em;
  }
  p.h5i3 {
    padding-left: 3em;
    text-indent:  2em;
  }
  p.h5i4 {
    padding-left: 4em;
    text-indent:  1em;
  }
  p.h5i5 {
    padding-left: 5em;
    text-indent:  0em;
  }
  p.h5i6 {
    padding-left: 6em;
    text-indent: -1em;
  }
  p.h5i7 {
    padding-left: 7em;
    text-indent: -2em;
  }
  p.h5i8 {
    padding-left: 8em;
    text-indent: -3em;
  }
  p.h5i9 {
    padding-left: 9em;
    text-indent: -4em;
  }

  p.h6i0 {
    padding-left: 0em;
    text-indent:  6em;
  }
  p.h6i1 {
    padding-left: 1em;
    text-indent:  5em;
  }
  p.h6i2 {
    padding-left: 2em;
    text-indent:  4em;
  }
  p.h6i3 {
    padding-left: 3em;
    text-indent:  3em;
  }
  p.h6i4 {
    padding-left: 4em;
    text-indent:  2em;
  }
  p.h6i5 {
    padding-left: 5em;
    text-indent:  1em;
  }
  p.h6i6 {
    padding-left: 6em;
    text-indent:  0em;
  }
  p.h6i7 {
    padding-left: 7em;
    text-indent: -1em;
  }
  p.h6i8 {
    padding-left: 8em;
    text-indent: -2em;
  }
  p.h6i9 {
    padding-left: 9em;
    text-indent: -3em;
  }

  p.h7i0 {
    padding-left: 0em;
    text-indent:  7em;
  }
  p.h7i1 {
    padding-left: 1em;
    text-indent:  6em;
  }
  p.h7i2 {
    padding-left: 2em;
    text-indent:  5em;
  }
  p.h7i3 {
    padding-left: 3em;
    text-indent:  4em;
  }
  p.h7i4 {
    padding-left: 4em;
    text-indent:  3em;
  }
  p.h7i5 {
    padding-left: 5em;
    text-indent:  2em;
  }
  p.h7i6 {
    padding-left: 6em;
    text-indent:  1em;
  }
  p.h7i7 {
    padding-left: 7em;
    text-indent:  0em;
  }
  p.h7i8 {
    padding-left: 8em;
    text-indent: -1em;
  }
  p.h7i9 {
    padding-left: 9em;
    text-indent: -2em;
  }

  p.h8i0 {
    padding-left: 0em;
    text-indent:  8em;
  }
  p.h8i1 {
    padding-left: 1em;
    text-indent:  7em;
  }
  p.h8i2 {
    padding-left: 2em;
    text-indent:  6em;
  }
  p.h8i3 {
    padding-left: 3em;
    text-indent:  5em;
  }
  p.h8i4 {
    padding-left: 4em;
    text-indent:  4em;
  }
  p.h8i5 {
    padding-left: 5em;
    text-indent:  3em;
  }
  p.h8i6 {
    padding-left: 6em;
    text-indent:  2em;
  }
  p.h8i7 {
    padding-left: 7em;
    text-indent:  1em;
  }
  p.h8i8 {
    padding-left: 8em;
    text-indent:  0em;
  }
  p.h8i9 {
    padding-left: 9em;
    text-indent: -1em;
  }

  p.h9i0 {
    padding-left: 0em;
    text-indent:  9em;
  }
  p.h9i1 {
    padding-left: 1em;
    text-indent:  8em;
  }
  p.h9i2 {
    padding-left: 2em;
    text-indent:  7em;
  }
  p.h9i3 {
    padding-left: 3em;
    text-indent:  6em;
  }
  p.h9i4 {
    padding-left: 4em;
    text-indent:  5em;
  }
  p.h9i5 {
    padding-left: 5em;
    text-indent:  4em;
  }
  p.h9i6 {
    padding-left: 6em;
    text-indent:  3em;
  }
  p.h9i7 {
    padding-left: 7em;
    text-indent:  2em;
  }
  p.h9i8 {
    padding-left: 8em;
    text-indent:  1em;
  }
  p.h9i9 {
    padding-left: 9em;
    text-indent:  0em;
  }

  p.it0 {
    margin-left: 0em;
    margin-top: 6px;
    margin-bottom: 0px;
    line-height: 100%;
  }
  p.it1 {
    margin-left: 1em;
    margin-top: 0px;
    margin-bottom: 0px;
    line-height: 100%;
  }
  p.it2 {
    margin-left: 2em;
    margin-top: 0px;
    margin-bottom: 0px;
    line-height: 100%;
  }
  p.it3 {
    margin-left: 3em;
    margin-top: 0px;
    margin-bottom: 0px;
    line-height: 100%;
  }
  p.it4 {
    margin-left: 4em;
    margin-top: 0px;
    margin-bottom: 0px;
    line-height: 100%;
  }
  p.it5 {
    margin-left: 5em;
    margin-top: 0px;
    margin-bottom: 0px;
    line-height: 100%;
  }
  p.it6 {
    margin-left: 6em;
    margin-top: 0px;
    margin-bottom: 0px;
    line-height: 100%;
  }
  p.it7 {
    margin-left: 7em;
    margin-top: 0px;
    margin-bottom: 0px;
    line-height: 100%;
  }
  p.it8 {
    margin-left: 8em;
    margin-top: 0px;
    margin-bottom: 0px;
    line-height: 100%;
  }
  p.it9 {
    margin-left: 9em;
    margin-bottom: 0px;
    margin-top: 0px;
    line-height: 100%;
  }

  p.group { }

  p.block { }

  p.alt { }

  p.verse {
    margin-bottom: 6px;
  }

  p.code {
    font-family: inconsolata, andale mono, courier new, courier, monospace;
    font-size: 90%;
    text-align: left;
    background-color: #eeeeee;
  }

  p.caption {
    text-align: left;
    font-size: 80%;
    display: inline;
  }

  p.endnote {
    font-size: 96%;
    line-height: 120%;
    text-align: left;
    margin-right: 2em;
  }
  p.endnote_indent {
    font-size: 96%;
    line-height: 120%;
    text-align: left;
    margin-left: 2em;
    margin-right: 2em;
  }

  p.center {
    text-align: center;
  }
  p.align_right {
    text-align: right;
  }
  p.bold {
    font-weight: bold;
  }
  p.bold_left {
    font-weight: bold;
    text-align: left;
  }
  p.centerbold {
    text-align: center;
    font-weight: bold;
  }
  p.em {
    font-weight: bold;
    font-style: normal;
    background: #fff3b6;
  }

  p.small {
    font-size: 80%;
    margin-top: 0px;
    margin-bottom: 0px;
    margin-right: 6px;
    text-align: left;
  }

  .tiny, .tiny_left, .tiny_right, .tiny_center {
    font-size: 10px;
    margin-top: 0px;
    margin-bottom: 0px;
    color: #777777;
    margin-right: 6px;
    text-align: left;
  }
  p.tiny { }
  p.tiny_left {
    margin-left: 0px;
    margin-right: 0px;
    text-align: left;
  }
  p.tiny_right {
    margin-right: 1em;
    text-align: right;
  }
  p.tiny_center {
    margin-left: 0px;
    margin-right: 0px;
    text-align: center;
  }

  p.concordance_word {
    line-height: 150%;
    font-weight: bold;
    display: inline;
    margin-top: 4px;
    margin-bottom: 1px;
  }
  p.concordance_count {
    font-size: 80%;
    color: #777777;
    display: inline;
    margin-left: 0em;
  }
  p.concordance_object {
    font-size: 80%;
    line-height: 120%;
    text-align: left;
    margin-left: 3em;
    margin-top: 1px;
    margin-bottom: 3px;
  }
  p.book_index_lev1 {
    line-height: 100%;
    margin-top: 4px;
    margin-bottom: 1px;
  }
  p.book_index_lev2 {
    line-height: 100%;
    text-align: left;
    margin-left: 3em;
    margin-top: 1px;
    margin-bottom: 3px;
  }

  p.quickref {
    font-size: 10px;
    font-style: italic;
    margin-top: 0px;
    margin-bottom: 0px;
    color: #777777;
    margin-right: 5px;
    text-align: left;
  }
  p.bigref {
    font-size: 11px;
    font-weight: bold;
    margin-top: 0px;
    margin-bottom: 0px;
    color: #777777;
    margin-right: 5px;
    text-align: center;
  }

  p.letter {
    font-weight: bold;
    font-size: 80%;
    margin-left: 0em;
    margin-top: 2px;
    margin-bottom: 2px;
    margin-right: 6px;
    text-align: left;
    color: white;
    background: #880000;
  }

  tt {
    font-family: inconsolata, andale mono, courier new, courier, monospace;
    background-color: #eeeeee;
  }

  label.ocn {
    width: 2%;
    float: right;
    top: 0;
    font-size: 10px;
    margin-top: 0px;
    margin-bottom: 5px;
    color: #777777;
    margin-right: 5px;
    text-align: right;
    background-color: #ffffff;
  }

  table { }
  tr { }
  th,td {
    vertical-align: top;
    text-align: left;
  }
  th {
    font-weight: bold;
  }

  p.left, th.left, td.left {
    text-align: left;
  }
  p.small_left, th.small_left, td.small_left {
    text-align: left;
    font-size: 80%;
  }
  p.right, th.right, td.right {
    text-align: right;
  }

  #horizontal_links {
    background: #eeeeee;
    margin-left: 5%;
    margin-right: 5%;
  }
  #horizontal {
    margin: 0;
    padding: 0 0 0 10px;
    border-top: 1px solid #000077;
    border-bottom: 1px solid #000077;
  }
  #horizontal li {
    margin: 0 0 0 0;
    padding: 0 16px 0 0;
    display: inline;
    list-style-type: none;
    text-align: left;
    background: none;
  }
  #horizontal a {
    line-height: 12px;
    margin: 0 0 0 0;
    text-decoration: none;
    color: #000077;
  }
  #horizontal a.active, #horizontal a:hover {
    border-bottom: 2px solid #777777;
    padding-bottom: 2px;
    color: #000077;
  }
  #horizontal a:hover {
    color: #000077;
  }

  #document_versions {
    position: absolute;
    top: 10mm;
    right: 2%;
    width: 12%;
    float: right;
  }

  #vertical_links {
    position: absolute;
    top: 10mm;
    right: 0px;
    width: 20%;
    background: #dddddd;
    float: right;
  }
  #vertical {
    padding: 0 12px 0px 0px;
    margin-left: 2%;
    margin-right: 2%;
  }
  #vertical li {
    display: block;
    list-style-type: none;
  }
  #vertical a {
    line-height: 12px;
    text-decoration: none;
    color: #000077;
  }
  #vertical a.active, #vertical a:hover {
    border-bottom: 2px solid #777777;
    padding-bottom: 2px;
    color: #000077;
  }

  ul, li {
    list-style-type: none;
    list-style: none;
    padding-left: 20px;
    display: block;
    font-family: verdana, arial, georgia, tahoma, sans-serif, helvetica, times, roman;
    font-weight: normal;
    line-height: 150%;
    text-align: justify;
    text-indent: 0mm;
    margin-left: 1em;
    margin-right: 2em;
    margin-top: 3px;
    margin-bottom: 3px;
  }

  li {
    background: url(../image/bullet_09.png) no-repeat 0px 6px;
  }

  ul {
  }
  li.bullet { margin-left: 0em; }
  li.i1 { margin-left: 1em; }
  li.i2 { margin-left: 2em; }
  li.i3 { margin-left: 3em; }
  li.i4 { margin-left: 4em; }
  li.i5 { margin-left: 5em; }
  li.i6 { margin-left: 6em; }
  li.i7 { margin-left: 7em; }
  li.i8 { margin-left: 8em; }
  li.i9 { margin-left: 9em; }

  li.doc, li.ref, li.refcenter {
    margin-top: 0px;
    margin-bottom: 0px;
    margin-right: 0px;
    font-size: 8px;
    font-style: normal;
    text-align: left;
  }
  li.doc {
    background: url(../image/bullet_09.png) no-repeat 0px 6px;
    padding-left: 16px;
    margin-left: 10px;
    margin-right: 0px;
  }
  li.ref {
    background: none;
    padding-left: 0;
    margin-left: 0;
    color: #777777;
  }
  li.refcenter {
    background: url(../image/bullet_09.png) no-repeat 0px 6px;
    padding-left: 20px;
    margin-left: 10%;
    font-size: 9px;
    color: #777777;
    text-align: center;
  }
  li.refbold {
    list-style-type: none;
    padding-left: 16px;
    margin-left: 0;
    margin-right: 10mm;
    font-weight: bold;
  }

  h0, h1, h2, h3, h4, h5, h6, h7 {
    font-weight: bold;
    line-height: 120%;
    text-align: left;
    margin-top: 20px;
    margin-bottom: 10px;
  }
  h4.norm, h5.norm, h6.norm, h7.norm {
    margin-top: 10px;
    margin-bottom: 0px;
  }
  h1.center, h2.center, h3.center, h4.center, h5.center, h6.center, h7.center {
    text-align: center;
  }
  h1 { font-size: 120%; }
  h2 { font-size: 115%; }
  h3 { font-size: 110%; }
  h4 { font-size: 105%; }
  h5 { font-size: 100%; }
  h6 { font-size: 100%; }
  h7 { font-size: 100%; }
  h0 { font-size: 80%; }

  h1.i {margin-left: 2em;}
  h2.i {margin-left: 3em;}
  h3.i {margin-left: 4em;}
  h4.i {margin-left: 5em;}
  h5.i {margin-left: 6em;}
  h6.i {margin-left: 7em;}
  h7.i {margin-left: 8em;}
  h8.i {margin-left: 9em;}
  h9.i {margin-left: 10em;}

  .toc {
    font-weight: normal;
    margin-top: 6px;
    margin-bottom: 6px;
  }
  h1.toc {
    margin-left: 1em;
    font-size: 115%;
    line-height: 150%;
  }
  h2.toc {
    margin-left: 2em;
    font-size: 110%;
    line-height: 140%;
  }
  h3.toc {
    margin-left: 3em;
    font-size: 105%;
    line-height: 120%;
  }
  h4.toc {
    margin-left: 4em;
    font-size: 100%;
    line-height: 120%;
  }
  h5.toc {
    margin-left: 5em;
    font-size: 95%;
    line-height: 110%;
  }
  h6.toc {
    margin-left: 6em;
    font-size: 90%;
    line-height: 110%;
  }
  h7.toc {
    margin-left: 7em;
    font-size: 90%;
    line-height: 105%;
  }

  .microtoc {
    margin-top: 2px;
    margin-bottom: 2px;
  }

  h1.microtoc {
    margin-left: 0mm;
    font-size: 115%;
  }
  h2.microtoc {
    margin-left: 5mm;
    font-size: 110%;
  }
  h3.microtoc {
    margin-left: 10mm;
    font-size: 105%;
  }
  h4.microtoc {
    margin-left: 15mm;
    font-weight: normal;
    font-size: 100%;
  }
  h5.microtoc {
    margin-left: 20mm;
    font-weight: normal;
    font-size: 95%;
  }
  h6.microtoc {
    margin-left: 25mm;
    font-weight: normal;
    font-size: 90%;
  }
  h7.microtoc {
    margin-left: 30mm;
    font-weight: normal;
    font-size: 85%;
  }

  .subtoc {
    margin-right: 34%;
    font-weight: normal;
  }
  h5.subtoc {
    margin-left: 2em;
    font-size: 80%;
    margin-top: 2px;
    margin-bottom: 2px;
  }
  h6.subtoc {
    margin-left: 3em;
    font-size: 75%;
    margin-top: 0px;
    margin-bottom: 0px;
  }
  h7.subtoc {
    margin-left: 4em;
    font-size: 70%;
    margin-top: 0px;
    margin-bottom: 0px;
  }

  div.substance {
    width: 100%;
    background-color: #ffffff;
  }
  div.ocn {
    width: 5%;
    float: right;
    top: 0;
    background-color: #ffffff;
  }
  div.endnote {
    width: 100%;
    background-color: #fffffff;
  }
  div.toc {
    position: absolute;
    float: left;
    margin: 0;
    padding: 0;
    padding-top: 0.5em;
    border: 0;
    width: 5%;
    background-color: #eeeeee;
    margin-right:1em;
  }
  div.summary {
    margin: 0;
    padding: 0;
    border-left: 2em solid #eeeeee;
    padding-left: 0em;
    background-color: #eeeeee;
  }
  div.content, div.main_column {
    margin: 0;
    padding: 0;
    border-left: 0% solid #ffffff;
    padding-left: 5%;
  }
  div.content:after {
    content:' ';
    clear:both;
    display:block;
    height:0;
    overflow:hidden
  }
  div.footer {
    clear:left;
    padding: 0.5em;
    font-size: 80%;
    margin: 0;
  }
  div.toc ul {
    list-style: none;
    padding: 0;
    margin: 0;
  }
  div.toc li ul a, li ul span.currentlink
  {
    font-weight: normal;
    font-size: 90%;
    padding-left: 2em;
    background-color: #eeeeee;
  }
  div.toc a, span.currentlink{
    display:block;
    text-decoration: none;
    padding-left: 0.5em;
    color: #0000aa;
  }
  hr {
    width: 90%;
  }

  span.currentlink {
    text-decoration: none;
    background-color: #aaaaf9;
  }

  div.toc a:visited {
    color: #0000aa;
  }
  div.toc a:hover {
    color: #000000;
    background-color: #f9f9aa;
  }

  h1.c, h2.c, h3.c, h4.c, h5.c, h6.c, h7.c, p.c {
    text-align: center
  }
  h1.red, h2.red, h3.red, h4.red, h5.red, h6.red, h7.red {
    text-align: center;
    color: #ff0000;
    margin-left: 5mm;
    text-indent: 5mm;
    margin-top: 30px;
    margin-bottom: 20px;
    margin-right: 15mm;
  }
  h1.ruby, h2.ruby, h3.ruby, h4.ruby, h5.ruby, h6.ruby, h7.ruby {
    text-align: center;
    color: #990000;
    margin-left: 5mm;
    text-indent: 5mm;
    margin-top: 30px;
    margin-bottom: 20px;
    margin-right: 15mm;
  }
      WOK
    end
  end
  module SanitizeXML
    require_relative 'xhtml_parts'                        # xhtml_parts.rb
    def self.xml(x)
      if x.is_a?(String)
        x=x.gsub(/&nbsp;/,' ') if Ep[:alt]==:on
        x.gsub(/&/,'&amp;').
          gsub(/</,"&lt;").gsub(/>/,"&gt;").
          gsub(/#{Dx[:url_o]}/,Dx[:url_o_xml]).gsub(/#{Dx[:url_c]}/,Dx[:url_c_xml]).
          #gsub(/</,'&#60;').gsub(/>/,'&#62;').
          gsub(/\\\\/,'<br />').
          gsub(/&lt;br(?: \/)?&gt;/,'<br />')
      else x
      end
    end
  end
  class HeadInformation
    attr_reader :md,:rdf
    def initialize(md)
      @md=md
      # DublinCore 1 - title
      @css=SiSU_Env::CSS_Stylesheet.new(md)
      @per=SiSU_XHTML_EPUB2_Persist::Persist.new
      @per.seg_name_x=SiSU_XHTML_EPUB2::Seg.new.seg_name_x
      @per.seg_name_x_tracker=SiSU_XHTML_EPUB2::Seg.new.seg_name_x_tracker
      @tocband_scroll,@tocband_segtoc=nil,nil
      @index,@metalink='index','#metadata'
    end
    def doc_type_xhtml
      <<-WOK
<?xml version='1.0' encoding='utf-8'?>
<html xmlns="http://www.w3.org/1999/xhtml">
      WOK
    end
=begin
~/epub
  |-- META-INF
  |   `-- container.xml                # simple, make sure full-path of rootfile points to metadata.opf
  |-- content
  |   |-- 1.xhtml
  |   |-- 2.xhtml
  |   |-- 3.xhtml
  |   |-- ... .xhtml
  |   |-- concordance.xhtml
  |   |-- css
  |   |   `-- xhtml.css
  |   |-- endnotes.xhtml
  |   |-- image
  |   |   |-- arrow_next_red.png
  |   |   |-- arrow_prev_red.png
  |   |   |-- arrow_up_red.png
  |   |   `-- bullet_09.png
  |   |-- index.xhtml
  |   |-- meta.xhtml
  |   |-- metadata.xhtml
  |   `-- toc.xhtml
  |-- metadata.opf                     #(i) metadata dc; (ii) manifest (contents); (iii) spine (mimetypes)
  |-- mimetype                         # application/epub+zip
  `-- toc.ncx                          #(i) head (ii) doc title (iii) navmap, list of navigation points (like chapters)
=end
    def doc_type
      doc_type_xhtml
    end
    def mimetype
      <<-WOK
application/epub+zip
      WOK
    end
    def metainf_container #container.xml file in META-INF directory
      #simple, make sure full-path of rootfile points to metadata.opf
      #epub_metadata.opf content.opf
      <<-WOK
<?xml version='1.0' encoding='utf-8'?>
<container version="1.0"
  xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
  <rootfiles>
    <rootfile full-path="#{Ep[:d_oebps]}/#{Ep[:f_opf]}"
      media-type="application/oebps-package+xml" />
  </rootfiles>
</container>
      WOK
    end
    def sections(dob,fn_base)
      name=fn_base + Sfx[:epub_xhtml]
      dir_epub_cont=@md.env.processing_path.epub + '/' + Ep[:d_oebps]
      segfilename=dir_epub_cont + '/' + name
      output_epub_cont_seg=File.new(segfilename,'w')
      txt=dob.obj.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'')
      output_epub_cont_seg << %{#{doc_type}
  <head>
    <title>
      #{dob.obj} -
      #{@md.html_title}
    </title>
    <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
    #{@css.xhtml_epub}
  </head>
    <body lang="#{@md.opt.lng}">
    <div class="content">
      <div class="substance">
        <label class="ocn"><a href="#o#{dob.ocn}" class="lnkocn">#{dob.ocn}</a></label>
        <h1 class="norm" id="o#{dob.ocn}">
          #{txt}
        </h1>
      </div>
    </div>
    </body>
  </html>}
output_epub_cont_seg.close
    end
    def toc_ncx #list of navigation points (like chapters), table of contents, listing each navigation point (chapters and such) under the navigation map
      def structure
        open
        head_open
        head
        head_close
        doc_title
        doc_author
        navmap_open
       #navmap ...
        navmap_close
        close
      end
      def open
        <<-WOK
<?xml version='1.0' encoding='utf-8'?>
<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
        WOK
      end
      def close
        <<-WOK
</ncx>
        WOK
      end
      def head_open
        <<-WOK
  <head>
        WOK
      end
      def head
        depth=@md.lvs[1] + @md.lvs[2] + @md.lvs[3] + @md.lvs[4]
        title=SanitizeXML.xml(@md.title.full)
        author=SanitizeXML.xml(@md.author)
        dgst=(@md.dgst.is_a?(Array) and @md.dgst.length > 1) ? @md.dgst[1] : 'na'
        <<-WOK
    <!-- four required metadata items (for all NCX documents,
      (including the relaxed constraints of OPS 2.0) -->
    <title>#{title} by #{author}</title>
    <link href="css/xhtml.css" rel="stylesheet" type="text/css" id="main-css" />
    <meta name="dtb:uid" content="urn:uuid:#{dgst}" />
    <!-- <meta name="epub-creator" content="#{@md.publisher}" /> -->
    <meta name="dtb:depth" content="#{depth}" />
    <meta name="dtb:totalPageCount" content="0" />
    <meta name="dtb:maxPageNumber" content="0" />
        WOK
      end
      def head_close
        <<-WOK
  </head>
        WOK
      end
      def doc_title
        txt=SanitizeXML.xml(@md.title.full)
        <<-WOK
  <docTitle>
    <text>#{txt}</text>
  </docTitle>
        WOK
      end
      def doc_author
        txt=SanitizeXML.xml(@md.author)
        <<-WOK
  <docAuthor>
    <text>#{txt}</text>
  </docAuthor>
        WOK
      end
      def navmap_open
        <<-WOK
  <navMap>
        WOK
      end
      def navmap_sisu_toc(no)
        id_u=DISABLE[:epub][:ncx_navpoint_unique_id] \
        ? ''
        : "-#{no}"
        <<-WOK
      <navPoint id="navpoint#{id_u}" playOrder="#{no}">
        <navLabel>
          <text>Table of Contents</text>
        </navLabel>
        <content src="index#{Sfx[:epub_xhtml]}" />
      </navPoint>
        WOK
      end
      def navpoint(dob,no,fn_base,hashtag=nil)
        fn=fn_base + Sfx[:epub_xhtml]
        name=hashtag ? fn + hashtag : fn
        id_u=DISABLE[:epub][:ncx_navpoint_unique_id] \
        ? ''
        : "-#{no}"
        txt=dob.obj.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'')
        <<-WOK
      <navPoint class="chapter" id="navpoint#{id_u}" playOrder="#{no}">
        <navLabel>
          <text>#{txt}</text>
        </navLabel>
        <content src="#{name}" />
        WOK
      end
      def navpoint_close
        <<-WOK
      </navPoint>
        WOK
      end
      def navmap_close
        <<-WOK
  </navMap>
        WOK
      end
      self
    end
    def metadata_opf #(i) metadata dc; (ii) manifest (contents); (iii) spine (mimetypes)
      def structure
        package_open
        metadata_open
        metadata_close
        manifest_open
        manifest_close
        spine_open
        spine_close
        guide_open
        guide_close
        package_close
      end
      def package_open
        <<-WOK
<?xml version='1.0' encoding='utf-8'?>
<package xmlns="http://www.idpf.org/2007/opf" version="2.0" unique-identifier="EPB-UUID">
        WOK
      end
      def package_close
        <<-WOK
</package>
        WOK
      end
      def metadata #metadata dc
        cover_image=if defined? @md.make.cover_image \
        and @md.make.cover_image.is_a?(Hash) \
        and @md.make.cover_image[:cover] =~/\S+/
          %{\n    <#{$ep[:o]}meta name="cover" content="cover_image" />}
        else ''
        end
        author=if defined? @md.creator.author \
        and @md.creator.author =~/\S+/
          m=''
          @md.creator.author_detail.each do |i|
            surname=i[:the] \
            ? i[:the]
            : ''
            other_names=i[:others] \
            ? ', ' + i[:others]
            : ''
            m=(m.empty?) \
            ? (surname + other_names)
            : (m + '; ' + surname + ', ' + other_names)
            m=SanitizeXML.xml(m)
          end
          x=@md.creator.author.dup
          x=SanitizeXML.xml(x)
          %{\n    <dc:creator opf:file-as="#{m}" opf:role="aut">#{x}</dc:creator>}
        else ''
        end
        editor=if defined? @md.creator.editor \
        and @md.creator.editor =~/\S+/
          m=''
          @md.creator.editor_detail.each do |i|
            surname=i[:the] \
            ? i[:the]
            : ''
            other_names=i[:others] \
            ? ', ' + i[:others]
            : ''
            m=(m.empty?) \
            ? (surname + other_names)
            : (m + '; ' + surname + ', ' + other_names)
            m=SanitizeXML.xml(m)
          end
          x=@md.creator.editor.dup
          x=SanitizeXML.xml(x)
          %{\n    <dc:creator opf:file-as="#{m}" opf:role="edt">#{x}</dc:creator>}
        else ''
        end
        translator=if defined? @md.creator.translator \
        and @md.creator.translator =~/\S+/
          m=''
          @md.creator.translator_detail.each do |i|
            surname=i[:the] \
            ? i[:the]
            : ''
            other_names=i[:others] \
            ? ', ' + i[:others]
            : ''
            m=(m.empty?) \
            ? (surname + other_names)
            : (m + '; ' + surname + ', ' + other_names)
            m=SanitizeXML.xml(m)
          end
          x=@md.creator.translator.dup
          x=SanitizeXML.xml(x)
          %{\n    <dc:creator opf:file-as="#{m}" opf:role="trl">#{x}</dc:creator>}
        else ''
        end
        illustrator=if defined? @md.creator.illustrator \
        and @md.creator.illustrator =~/\S+/
          m=''
          @md.creator.illustrator_detail.each do |i|
            surname=i[:the] \
            ? i[:the]
            : ''
            other_names=i[:others] \
            ? ', ' + i[:others]
            : ''
            m=(m.empty?) \
            ? (surname + other_names)
            : (m + '; ' + surname + ', ' + other_names)
            m=SanitizeXML.xml(m)
          end
          x=@md.creator.illustrator.dup
          x=SanitizeXML.xml(x)
          %{\n    <dc:creator opf:file-as="#{m}" opf:role="ill">#{x}</dc:creator>}
        else ''
        end
        date_published=if defined? @md.date.published \
        and @md.date.published =~/\S+/
          x=@md.date.published.dup
          x=SanitizeXML.xml(x)
          %{\n    <dc:date opf:event="published">#{x}</dc:date>}
        else ''
        end
        subject=if defined? @md.classify.subject \
        and @md.classify.subject =~/\S+/
          x=@md.classify.subject.dup
          x=SanitizeXML.xml(x)
          %{\n    <dc:subject>#{x}</dc:subject>}
        else ''
        end
        language=if defined? @md.opt.lng \
        and @md.opt.lng =~/\S+/
          language=@md.opt.lng.gsub(/<br>/,'<br />')
          %{\n    <dc:language>#{language}</dc:language>}
        else ''
        end
        rights=if defined? @md.rights.all \
        and @md.rights.all =~/\S+/
          rights=SanitizeXML.xml(@md.rights.all)
          rights=rights.gsub(/<br\s*\/?>/,' ')
          %{\n    <dc:rights>#{rights}</dc:rights>}
        else ''
        end
        f=SiSU_Env::FileOp.new(@md)
        dgst=(@md.dgst.is_a?(Array) and @md.dgst.length > 1) ? @md.dgst[1] : 'na'
        <<-WOK
  <#{$ep[:o]}metadata
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:opf="http://www.idpf.org/2007/opf"
    xmlns:dcterms="http://purl.org/dc/terms/"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    unique-identifier="urn:uuid:#{dgst}" version="2.0">
    <dc:title>#{@md.title.full}</dc:title>
    #{cover_image}#{author}#{editor}#{translator}#{illustrator}#{language}#{date_published}#{subject}#{rights}
    <dc:identifier opf:scheme="URI">#{f.output_path.epub.url.gsub(/http:\/\//,'')}/#{f.base_filename.epub}</dc:identifier>
    <dc:identifier id="bookid">urn:uuid:#{dgst}</dc:identifier>
    <!-- <dc:identifier id="EPB-UUID">urn:uuid:#{dgst}</dc:identifier> -->
  </#{$ep[:o]}metadata>
        WOK
      end
      def manifest_open
        <<-WOK
  <manifest>
    <!-- NCX -->
    <item id="ncx" href="#{Ep[:f_ncx]}" media-type="application/x-dtbncx+xml" />
    <!-- CSS Style Sheets -->
    <item id="main-css" href="css/xhtml.css" media-type="text/css" />
    <!-- Content Documents -->
        WOK
      end
      def manifest_content_sisu_toc
        <<-WOK
    <item id="index#{Sfx[:epub_xhtml]}" href="index#{Sfx[:epub_xhtml]}" media-type="application/xhtml+xml" />
        WOK
      end
      def manifest_cover_image_information(md)
        if defined? md.make.cover_image \
        and @md.make.cover_image.is_a?(Hash) \
        and md.make.cover_image[:cover] =~/\S+/
          <<-WOK
    <item id="cover_image#{Sfx[:epub_xhtml]}" href="cover_image#{Sfx[:epub_xhtml]}" media-type="application/xhtml+xml" />
          WOK
        else ''
        end
      end
      def manifest_content(dob,fn_base,hashtag=nil)
         fn=fn_base + Sfx[:epub_xhtml]
         name=hashtag ? fn + hashtag : fn
        <<-WOK
    <item id="#{name}" href="#{name}" media-type="application/xhtml+xml" />
        WOK
      end
      def manifest_images(imgs)
        imgs=imgs + ['arrow_next_red.png','arrow_prev_red.png','arrow_up_red.png','bullet_09.png']
        images=["    <!-- Images -->\n"]
        imgs.each do |i|
          image,type=/(\S+?)\.(png|jpg|gif)/.match(i)[1,2]
          type=type.sub(/jpg/,'jpeg')
          images<<<<-WOK
    <item id="#{image}" href="image/#{image}.#{type}" media-type="image/#{type}" />
          WOK
        end
        images=images.join('')
        images
      end
      def manifest_close
        <<-WOK
  </manifest>
        WOK
      end
      def spine_open
        #spine: reading order of XHTML files from manifest, idref attribute refers back to id in manifest (exclude images, CSS etc.).
        <<-WOK
  <spine toc="ncx">
        WOK
      end
      def spine_cover_image
        <<-WOK
    <itemref idref="cover_image#{Sfx[:epub_xhtml]}" />
        WOK
      end
      def spine_sisu_toc
        <<-WOK
    <itemref idref="index#{Sfx[:epub_xhtml]}" linear="yes" />
        WOK
      end
      def spine(dob,fn_base,hashtag=nil)
         fn=fn_base + Sfx[:epub_xhtml]
         name=hashtag ? fn + hashtag : fn
        <<-WOK
    <itemref idref="#{name}" linear="yes" />
        WOK
      end
      def spine_close
        <<-WOK
  </spine>
        WOK
      end
      def guide_open
        #guide: presentation order of XHTML files by reader).
        <<-WOK
  <guide>
        WOK
      end
      def guide_cover_image
        <<-WOK
    <reference type="cover" title="Cover of #{SanitizeXML.xml(@md.title.full)}" href="cover_image#{Sfx[:epub_xhtml]}" />
        WOK
      end
      def guide_sisu_toc
        <<-WOK
    <reference type="index#{Sfx[:epub_xhtml]}" href="index#{Sfx[:epub_xhtml]}" />
        WOK
      end
      def guide(dob,fn_base,hashtag=nil)
         fn=fn_base + Sfx[:epub_xhtml]
         name=hashtag ? fn + hashtag : fn
        name=name ? name : dob.name
        guide_name=(name =~/#{Sfx[:epub_xhtml]}/) ? name : (name + Sfx[:epub_xhtml])
        <<-WOK
    <reference type="text" href="#{guide_name}" />
        WOK
      end
      def guide_close
        <<-WOK
  </guide>
        WOK
      end
      self
    end
    def table_close
      %{  </font>
#{the_table_close}}
    end
    def xhtml_close
    %{#{SiSU_Proj_XHTML::Bits.new.credits_sisu_epub}
  </body>
</html>}
    end
  end
  class HeadToc < HeadInformation
    include SiSU_Parts_XHTML
    def initialize(md)
      super(md)
      @md=md
      @tocband_segtoc=make_seg
    end
    def manifest_link(text)
  %{ <a href="#{@md.file.output_path.manifest.url}/#{@md.file.base_filename.manifest}" target="_top">#{text}</a>}
    end
    def concordance_link(text)
      if @md.concord_make
  %{<a href="#{@md.file.base_filename.html_concordance}" target="_top">
      #{text}
    </a>}
      else ''
      end
    end
    def head
      %{#{doc_type}
  <head>
    <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
    #{@css.xhtml_epub}
  </head>
    <body lang="#{@md.opt.lng}">}
    end
    def concordance
      if @md.concord_make
      %{#{the_margin.css}
      <h4 class="toc">
        <a href="./#{@md.file.base_filename.html_concordance}">
          <i>Concordance</i>
        </a>
      </h4>
#{the_table_close}}
      else
      %{#{the_margin.css}
#{the_table_close}}
      end
    end
    def links_guide_open(type='horizontal')
      (type=='vertical') \
      ? links_guide_vertical_open
      : links_guide_horizontal_open
    end
    def prefix_a
    end
    def rights
      def all
        rights=SanitizeXML.xml(@md.rights.all)
        %{<p class="small_left">Rights: #{rights}</p>}
      end
      self
    end
    def prefix_b
      %{<p class="small_left">Prefix: #{@md.prefix_b}}
    end
    def make_seg
      concord=concordance_link(the_nav.txt_concordance)
      %{<table summary="toc segment" border="0" cellpadding="3" cellspacing="0">
<tr><td align="center" bgcolor="white">
  #{the_nav.txt_toc_link}
</td>
<td align="center" bgcolor="white">
  <font size=2>
   #{concord}
#{the_table_close}}
    end
    def manifest #check structure
      manifest=manifest_link(the_nav.txt_manifest)
      %{#{the_margin.txt_3}
  #{the_font.paragraph_font_small}
   #{manifest}
    </font>
#{the_table_close}}
    end
    def concordance #check structure
      concord=concordance_link(the_nav.txt_concordance)
      %{#{the_margin.txt_3}
  #{the_font.paragraph_font_small}
   #{concord}
    </font>
#{the_table_close}}
    end
    def metadata
      %{#{the_margin.css}
  <h4 class="toc">
    <a href="#{@metalink}">
      <i>MetaData</i>
    </a>
  </h4>
#{the_table_close}}
    end
  end
  class HeadSeg < HeadInformation
    def initialize(md)
      super(md)
    end
    def head
      %{#{doc_type}
  <head>
    <title>
      #{@per.seg_name_x[@per.seg_name_x_tracker]} -
      #{@md.html_title}
    </title>
    <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
    #{@css.xhtml_epub}
  </head>
    <body lang="#{@md.opt.lng}">}
    end
    def endnote_mark
%{
  <hr class="endnote" />
}
    end
  end
  class HeadScroll < HeadToc
    def initialize(md)
      super(md)
    end
    def toc_owner_details
      %{#{the_margin.txt_3}
#{the_font.paragraph_font_small}
  <a href="#owner.details">
    Owner Details
    <font size="1" color="#777777">
      #{$ep[:hsp]*3}
    </font>
  </a>
  </font>
#{the_table_close}}
    end
  end
  class FormatTextObject
    include SiSU_Parts_XHTML
    attr_accessor :md,:t_o,:txt,:ocn,:format,:table,:link,:linkname,:paranum,:p_num,:headname,:banner,:url
    def initialize(md,t_o)
      @md,@t_o=md,t_o
      if t_o.is_a?(Hash)
        @txt            =t_o[:txt]            || nil
        @ocn            =t_o[:ocn]            || nil
        @ocn_display    =t_o[:ocn_display]    || nil
        @headname       =t_o[:headname]       || nil
        @trailer        =t_o[:trailer]        || nil
        @endnote_part_a =t_o[:endnote_part_a] || nil
        @endnote_part_b =t_o[:endnote_part_b] || nil
        @lnk_url        =t_o[:lnk_url]        || nil
        @lnk_txt        =t_o[:lnk_txt]        || nil
        @format         =t_o[:format]         || nil
        @target         =t_o[:target]         || nil #occasionally passed but not used
        if @format and not @format.empty?
          if @format=~/^\d:(\S+)/ #need more reliable marker #if @format =~ /#{Rx[:lv]}/
            headname=$1 #format[/\d~(\S+)/m,1]
            @headname=(headname =~/^[a-zA-Z]/) \
            ? %{<id="#{headname}">}
            : %{<id="h#{headname}"></a>}
            @headname=(headname =~/^[a-zA-Z]/) \
            ? %{<a name="#{headname}" id="#{headname}"></a>}
            : %{<a name="h#{headname}" id="h#{headname}"></a>}
          end
        end
      elsif t_o.class.inspect =~/Object/
        @dob=t_o if defined? t_o.is
        @named=nametags_seg(@dob)
        @txt=((defined? t_o.obj) ? t_o.obj : nil)
        @ocn=((defined? t_o.ocn) ? t_o.ocn.to_s : nil)
        @headname=((t_o.is==:heading and defined? t_o.name) ? t_o.name : nil)
      else
        if @md.opt.act[:maintenance][:set]==:on
          p __FILE__ << ':' << __LINE__.to_s
          p t_o.class
          p caller
        end
      end
      if @txt and not @txt.empty?
        @txt=@txt.gsub(/#{Mx[:mk_o]}[-~]##{Mx[:mk_c]}/,'')
      end
      @p_num=ParagraphNumber.new(@md,@ocn)
    end
    def nametags_seg(dob) #FIX
      tags=''
      if defined? dob.tags \
      and dob.tags.length > 0 # insert tags "hypertargets"
        dob.tags.each do |t|
          tags=tags << %{<a name="#{t}" />}
        end
      end
      tags
    end
    def endnote_body
      %{
<p class="endnote">
  #{@txt}
</p>
}
    end
    def endnote_body_indent
      %{
  <p class="endnote_indent">
    #{@txt}
  </p>
}
    end
    def no_paranum
      %{
<div class="substance">
  <label class="ocn">#{$ep[:hsp]}</label>
  <p class="norm">
    #{@txt}
  </p>
</div>
}
    end
    def para_form_css(tag,attrib,txt)                                                    # regular paragraphs shaped here
      ul=ulc=''
      ul,ulc="<ul>\n  ","\n  </ul>" if @tag =~/li/
      %{
<div class="substance">
  #{@p_num.ocn_display}
  #{ul}<#{tag} class="#{attrib}" #{@p_num.id}>
    #{@named}#{txt}
  </#{tag}>#{ulc}
</div>
}
    end
    def para
      para_form_css('p','norm',@txt)
    end
    def group
      para_form_css('p','group',@txt)
    end
    def block
      para_form_css('p','block',@txt)
    end
    def alt
      para_form_css('p','alt',@txt)
    end
    def verse
      para_form_css('p','verse',@txt)
    end
    def code
      para_form_css('p','code',@txt)
    end
    def center
      para_form_css('p','center',@txt)
    end
    def bold
      para_form_css('p','bold',@txt)
    end
    def bullet
      para_form_css('li','bullet',@txt)
    end
    def table
      @txt=if @t_o.obj !~/^<table\s/
        table=SiSU_XHTML_Shared::TableXHTML.new(@t_o) #move, make happen earlier
        table.table.obj
      else @txt
      end
      para_form_css('p','norm',@txt)
    end
    def break
      @txt=@txt.gsub(/#{Mx[:br_page_new]}|#{Mx[:br_page]}|#{Mx[:br_page_line]}/,'<hr /><br />').
        gsub(/#{Mx[:br_obj]}/,'<hr style="width:30%" /><br />')
      para_form_css('p','norm',@txt)
    end
    def format(tag,attrib)
      para_form_css(tag,attrib,@txt)
    end
    def title_heading(tag,attrib)
      %{
<div class="content">
<#{tag} class="#{attrib}">
    #{@named}#{@txt}
  </#{tag}>
</div>
}
    end
    def title_heading0
      DISABLE[:epub][:per_section_title] \
      ? ''
      : title_heading('h1','tiny')
    end
    def title_heading1
      DISABLE[:epub][:per_section_title] \
      ? ''
      : title_heading('h1','tiny')
    end
    def title_heading2
      DISABLE[:epub][:per_section_title] \
      ? ''
      : title_heading('h2','tiny')
    end
    def title_heading3
      DISABLE[:epub][:per_section_title] \
      ? ''
      : title_heading('h3','tiny')
    end
    def title_heading4
      ''
    end
    def seg_heading_sub(tag,attrib,txt)
      txt=txt.gsub(/(?:#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})\s*/m,' ')
      %{
<div class="substance">
  #{@p_num.ocn_display}
  <#{tag} class="#{attrib}" #{@p_num.id}>#{@p_num.name}
    #{@named}#{@txt}
  </#{tag}>
</div>
}
    end
    def seg_heading4
      %{
<div class="substance">
  #{@p_num.ocn_display}
  <h1 class="norm" #{@p_num.id}>
    #{@txt}
  </h1>
</div>
}
    end
    def seg_heading5
      seg_heading_sub('p','bold',@txt)
    end
    def seg_heading6
      seg_heading_sub('p','bold',@txt)
    end
    def seg_heading7
      seg_heading_sub('p','bold',@txt)
    end
    def dl #check :trailer
      "<dl><b>#{@txt}</b> #{@trailer}</dl>"
    end
    def table_css_end
      '</table>
    </p>
  </div>'
    end
    def gsub_body #unused
      @txt=case @txt
      when /^(?:#{Mx[:pa_o]}i[1-9]#{Mx[:pa_c]}\s*)?\((i+|iv|v|vi+|ix|x|xi+)\)/
        @txt.gsub(/^\((i+|iv|v|vi+|ix|x|xi+)\)/,'<b>(\1)</b>').
          gsub(/^(#{Mx[:pa_o]}i[1-9]#{Mx[:pa_c]})\s*\((i+|iv|v|vi+|ix|x|xi+)\)/,'\1<b>(\2)</b>')
      when /^(?:#{Mx[:pa_o]}i[1-9]#{Mx[:pa_c]}\s*)?\(?(\d|[a-z])+\)/
        @txt.gsub(/^\((\d+|[a-z])+\)/,'<b>(\1)</b>').
          gsub(/^(#{Mx[:pa_o]}i[1-9]#{Mx[:pa_c]})\s*\((\d+|[a-z])+\)/,'\1<b>(\2)</b>')
      when /^\s*\d{1,3}\.\s/
        @txt.gsub(/^\s*(\d+\.)/,'<b>\1</b>')
      when /^\s*[A-Z]\.\s/
        @txt.gsub(/^\s*([A-Z]\.)/,'<b>\1</b>')
      else @txt
      end
    end
    def bold_para
      %{#{the_margin.txt_0}
  <p class="bold">
    #{@txt}
  </p>
#{the_margin.num_css}
  #{$ep[:hsp]*3}
#{the_table_close}}
    end
    def bold_heading #unused
      @txt=@txt.gsub(/[1-9]~\S+/,'').
        gsub(/[1-9]~/,'')
      %{<p class="bold">
    #{@txt}
  </p>
#{the_margin.num_css}
  #{$ep[:hsp]*3}
#{the_table_close}}
    end
    def toc_head_copy_at
      @txt=SanitizeXML.xml(@txt)
      %{<p class="center">#{@txt}</p>\n}
    end
    def center
      @txt=SanitizeXML.xml(@txt)
      %{<p class="center">#{@txt}</p>\n}
    end
    def bold
      @txt=SanitizeXML.xml(@txt)
      %{<p class="bold">#{@txt}</p>\n}
    end
    def center_bold
      @txt=SanitizeXML.xml(@txt)
      %{<p class="centerbold">#{@txt}</p>\n}
    end
  end
  class FormatScroll < FormatTextObject
    def initialize(md,txt)
      super(md,txt)
    end
  end
  class FormatSeg < FormatTextObject
    def initialize(md,txt)
      super(md,txt)
    end
    def endnote_seg_body(fn='')  #FIX                                                #url construction keep within single line... BUG WATCH 200408
      fn='doc' if fn.to_s.empty? #you may wish to reconsider, sends to 'doc' where no segment info
      %{
  <p class="endnote">
    #{@endnote_part_a}#{fn}#{Sfx[:epub_xhtml]}#{@endnote_part_b}
  </p>
}
    end
    def clean(txt)
      txt=txt.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}/,'').
        gsub(/#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/,'')
    end
    def subtoc_lev(tag,attrib)
      @txt=clean(@txt)
      txt=if @txt \
      and @txt =~/<\/?i>|<a\s+name="\S+?">/mi
        @txt.gsub(/<\/?i>|<a\s+name="\S+?">/mi,'') #removes name markers from subtoc, go directly to substantive text
      else @txt
      end
      note=''
      if txt =~/(#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})/m # had \s* at end
        note=$1
        note=note.gsub(/[\s]+/m,' ')
        txt=txt.gsub(/(?:#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})\s*/m,' ').
          gsub(/<a[\n\s]+"[\n\s]+href="##{Mx[:note_ref]}\d+">#{$ep[:hsp]}<sup id="#{Mx[:note]}\d+">\d+<\/sup>#{$ep[:hsp]}/m,'').
          gsub(/<a[\n\s]+"[\n\s]+href="##{Mx[:note_ref]}\d+">#{$ep[:hsp]}<sup id="#{Mx[:note]}\d+">\d+<\/sup>#{$ep[:hsp]}/m,'') #remove
      end
      %{<#{tag} class="#{attrib}">
    <a href="#o#{@ocn}"><i>#{txt}</i></a> #{note}
  </#{tag}>}
    end
    def subtoc_lev5
      subtoc_lev('h5','subtoc') if @txt
    end
    def subtoc_lev6
      subtoc_lev('h6','subtoc') if @txt
    end
    def subtoc_lev7
      subtoc_lev('h7','subtoc') if @txt
    end
    def heading_sub(tag,attrib,txt)
      txt=txt.gsub(/(?:#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})\s*/m,' ')
      %{
<div class="substance">
  #{@p_num.ocn_display}
  <#{tag} class="#{attrib}" #{@p_num.id}> #{@headname}
    #{@txt}
  </#{tag}>
</div>
}
    end
    def heading4
      %{
<div class="substance">
  #{@p_num.ocn_display}
  <h1 class="norm" #{@p_num.id}>
    #{@t_o[:format]}
    #{@txt}
  </h1>
</div>
}
    end
    def heading5
      heading_sub('p','bold',@txt)
    end
    def heading6
      heading_sub('p','bold',@txt)
    end
    def heading7
      heading_sub('h7','bold',@txt)
    end
    def navigation_heading4
      %{<table summary="navigation segment heading 4" width=100% bgcolor="#08163f" border="0">
<tr><td align="center">
<p class="bold">
  #{@txt}
</p>
#{the_table_close}}
    end
    def navigation_heading5
      %{<p class="bold">
  #{@txt}
</p>}
    end
    def navigation_heading6
      %{<p class="bold">
  #{@txt}
</p>}
    end
    def navigation_heading7
      %{<p class="bold">
  #{@txt}
</p>}
    end
    def navigation_center
      %{<p class="centerbold">#{@txt}</p>}
    end
  end
  class FormatToc < FormatTextObject
    def initialize(md,txt)
      super(md,txt)
    end
    def links_guide
      %{  <li class="doc">
    <a href="#{@lnk_url}" target="_top">
      #{@lnk_txt}
    </a>
  </li>
}
    end
    def lev(tag,attrib)
      if @txt
        %{<#{tag} class="#{attrib}">
    #{@txt}
  </#{tag}>
}
      else ''
      end
    end
    def lev1
      lev('h1','toc')
    end
    def lev2
      lev('h2','toc')
    end
    def lev3
      lev('h3','toc')
    end
    def lev4
      lev('h4','toc')
    end
    def lev5
      lev('h5','toc')
    end
    def lev6
      lev('h6','toc')
    end
    def lev7
      lev('h7','toc')
    end
    def lev0 #docinfo
      lev('h0','toc')
    end
  end
end
__END__
#+END_SRC

** xhtml_epub2_persist.rb

#+HEADER: :tangle "../lib/sisu/xhtml_epub2_persist.rb"
#+BEGIN_SRC ruby
#<<sisu_document_header>>
module SiSU_XHTML_EPUB2_Persist
  class Persist
    @@persist=nil
    attr_accessor :is0,:is1,:is2,:is3,:is4,:heading0,:heading1,:heading2,:heading3,:heading4, :title, :nav, :tocband_banner, :tocband_bannerless, :headings, :heading_endnotes, :main, :endnote_all, :tail, :credits, :heading_idx, :idx, :seg_endnotes, :seg_endnotes_array, :closed, :get_hash_fn, :get_hash_to, :seg_subtoc, :seg_subtoc_array, :fn, :seg_name ,:seg_name_x,:seg_name_x_tracker
    def initialize(args=nil)
      @@persist=args=(args ? args : (@@persist || persist_init_hash_values))
      @is0=args[:is0]
      @is1=args[:is1]
      @is2=args[:is2]
      @is3=args[:is3]
      @is4=args[:is4]
      @heading0=args[:heading0]
      @heading1=args[:heading1]
      @heading2=args[:heading2]
      @heading3=args[:heading3]
      @heading4=args[:heading4]
      @title=args[:title]
      @nav=args[:nav]
      @tocband_banner=args[:tocband_banner]
      @tocband_bannerless=args[:tocband_bannerless]
      @headings=args[:headings]
      @heading_endnotes=args[:heading_endnotes]
      @main=args[:main]
      @endnote_all=args[:endnote_all]
      @tail=args[:tail]
      @credits=args[:credits]
      #@heading_idx=args[:heading_idx]
      @idx=args[:idx]
      @seg_endnotes=args[:seg_endnotes]
      @seg_endnotes_array=args[:seg_endnotes_array]
      @closed=args[:closed]
      @get_hash_to=args[:get_hash_to]
      @get_hash_fn=args[:get_hash_fn]
      @seg_subtoc=args[:seg_subtoc]
      @seg_subtoc_array=args[:seg_subtoc_array]
      @fn=args[:fn]
      @seg_name=args[:seg_name]
      @seg_name_x=args[:seg_name_x]
      @seg_name_x_tracker=args[:seg_name_x_tracker]
    end
    def is0
      @is0
    end
    def is1
      @is1
    end
    def is2
      @is2
    end
    def is3
      @is3
    end
    def is4
      @is4
    end
    def heading0
      @heading0
    end
    def heading1
      @heading1
    end
    def heading2
      @heading2
    end
    def heading3
      @heading3
    end
    def heading4
      @heading4
    end
    def title
      @title
    end
    def nav
      @nav
    end
    def tocband_banner
      @tocband_banner
    end
    def tocband_bannerless
      @tocband_bannerless
    end
    def headings
      @headings
    end
    def heading_endnotes
      @heading_endnotes
    end
    def main
      @main
    end
    def endnote_all
      @endnote_all
    end
    def tail
      @tail
    end
    def credits
      @credits
    end
    def heading_idx
      @heading_idx
    end
    def idx
      @idx
    end
    def seg_endnotes
      @seg_endnotes
    end
    def seg_endnotes_array
      @seg_endnotes_array
    end
    def closed
      @closed
    end
    def get_hash_to
      @get_hash_to
    end
    def get_hash_fn
      @get_hash_fn
    end
    def seg_subtoc
      @seg_subtoc
    end
    def seg_subtoc_array
      @seg_subtoc_array
    end
    def fn
      @fn
    end
    def seg_name
      @seg_name
    end
    def seg_name_x
      @seg_name_x
    end
    def seg_name_x_tracker
      @seg_name_x_tracker
    end
    def persist_init_hash_values
      {
        is0: 0,
        is1: 0,
        is2: 0,
        is3: 0,
        is4: 0,
        heading0: '',
        heading1: '',
        heading2: '',
        heading3: '',
        heading4: '',
        tocband_banner: [],
        tocband_bannerless: [],
        title: [],
        nav: [],
        headings: [],
        main: [],
        idx: [],
        tail: [],
        credits: [],
        endnote_all: [],
        heading_endnotes: '',
        seg_endnotes: {},
        seg_endnotes_array: [],
        closed: [],
        get_hash_fn: '',
        get_hash_to: '',
        seg_subtoc: {},
        seg_subtoc_array: [],
        fn: '',
        seg_name: [],
        seg_name_x: [],
        seg_name_x_tracker: 0,
      }
    end
    def persist_init
      @@persist=nil
      Persist.new(persist_init_hash_values)
    end
  end
  class PersistTOC
    @@persist=nil
    attr_accessor :seg,:seg_mini,:scr,:ncx,:opf
    def initialize(args=nil)
      @@persist=args=(args ? args : (@@persist || persist_init_hash_values))
      @seg=args[:seg]
      @seg_mini=args[:seg_mini]
      @scr=args[:scr]
      @ncx=args[:ncx]
      @opf=args[:opf]
    end
    def seg
      @seg
    end
    def seg_mini
      @seg_mini
    end
    def scr
      @scr
    end
    def ncx
      @ncx
    end
    def opf
      @opf
    end
    def persist_init_hash_values
      {
        seg: [],
        seg_mini: [],
        scr: [],
        ncx: [],
        opf: [],
      }
    end
    def persist_init
      @@persist=nil
      PersistTOC.new(persist_init_hash_values)
    end
  end
end
__END__
#+END_SRC

** xhtml_epub2_segments.rb

#+HEADER: :tangle "../lib/sisu/xhtml_epub2_segments.rb"
#+BEGIN_SRC ruby
#<<sisu_document_header>>
module SiSU_XHTML_EPUB2_Seg
  require_relative 'xhtml_shared'                       # xhtml_shared.rb
  require_relative 'xhtml_epub2'                        # xhtml_epub2.rb
  require_relative 'xhtml_epub2_persist'                # xhtml_epub2_persist.rb
  require_relative 'shared_metadata'                    # shared_metadata.rb
  class Output
    def initialize(md,outputfile,per,type='')
      @md, @output_epub_cont_seg,@per,@type=
        md,outputfile,           per, type
    end
    def output
      if @per.title =~/\S/
        filename_seg=[]
        filename_seg \
        << @per.title \
        << @per.nav
        if @type=='endnotes'
          @per.headings=[] #watch
          txt_obj={ txt: 'Endnotes', ocn_display: ''}
          format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
          @per.headings \
          << format_seg.title_heading1
          filename_seg \
          << @per.heading_endnotes \
          << @per.headings \
          << %{\n<div class="content">\n} \
          << @per.endnote_all \
          << '</div>'
        elsif @type=='idx'
          @per.headings=[]
          txt_obj={ txt: 'Index', ocn_display: ''}
          format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
          @per.headings << format_seg.title_heading1
          filename_seg \
          << @per.heading_idx \
          << @per.headings \
          << %{\n<div class="content">\n} \
          << @per.idx \
          << '</div>'
        elsif @type=='metadata'
          metadata=SiSU_Metadata::Summary.new(@md).xhtml_display.metadata
          @per.headings=[]
          txt_obj={ txt: 'Metadata', ocn_display: ''}
          format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
          @per.headings \
          << format_seg.title_heading1
          filename_seg \
          << @per.heading_idx \
          << @per.headings \
          << %{\n<div class="content">\n} \
          << metadata \
          << '</div>'
        elsif @type=='sisu_manifest'
          env=SiSU_Env::InfoEnv.new(@md.fns)
          path_and_name,url_and_name= \
            "#{env.path.output}/#{@md.fnb}/sisu_manifest.html",
            "#{env.url.root}/#{@md.fnb}/sisu_manifest.html"
          manifest=if FileTest.file?("#{path_and_name}")==true
            <<WOK
<p>A list of available output types may be available at the following url:</p>
<p><a href="#{url_and_name}">#{url_and_name}</a></p>
WOK
          else ''
          end
          @per.headings=[]
          txt_obj={ txt: 'Manifest', ocn_display: ''}
          format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
          @per.headings \
          << format_seg.title_heading1
          filename_seg \
          << @per.heading_idx \
          << @per.headings \
          << %{\n<div class="content">\n} \
          << manifest \
          << '</div>'
        else
          filename_seg \
          << @per.headings \
          << @per.main \
          << "\n</div>\n"
        end
        filename_seg \
        << @per.tail \
        << @per.nav \
        << @per.closed
        filename_seg=filename_seg.flatten.compact #watch
        filename_seg.each do |str|
          unless str =~/\A\s*\Z/
            @output_epub_cont_seg \
            << str.strip
          end
        end
        @output_epub_cont_seg.close
      end
    end
  end
  class Seg
    @@seg_name=[]
    @@seg_url=''
    @@tracker=0
    attr_reader :seg_name_x,:seg_name_x_tracker
    def initialize(md='',data='')
      @md,@data=md,data
      @per=SiSU_XHTML_EPUB2_Persist::Persist.new
      @seg_name_x=@per.seg_name_x=(@@seg_name || [])
      @seg_name_x_tracker=@per.seg_name_x_tracker=(@@tracker || 0)
      @make=SiSU_Env::ProcessingSettings.new(@md) if @md
    end
    def songsheet
      begin
        data=get_subtoc_endnotes(@data,@per)
        data=articles(data,@per)
        SiSU_XHTML_EPUB2_Seg::Seg.new.cleanup(@md,@per) # (((( added ))))
        #### (((( END )))) ####
      rescue
        SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
          __LINE__.to_s + ':' + __FILE__
        end
      ensure
        SiSU_XHTML_EPUB2_Persist::Persist.new.persist_init
        @@seg_name=@per.seg_name=[]
      end
    end
  protected
    def articles(data,per)
      @per=per
      tracking,newfile=0,0
      printed_endnote_seg='n'
      idx_xhtml=nil
      if @md.book_idx
        idx_xhtml=SiSU_Particulars::CombinedSingleton.
          instance.get_idx_xhtml(@md).xhtml_idx
        idx_xhtml.each do |x|
          @per.idx << x
        end
        @per.heading_idx=''
      end
      data.each do |dob|
        if (dob.is == :heading \
        || dob.is == :heading_insert) \
        && dob.ln == 4
          @@seg_name << dob.name
          @per.seg_name = @@seg_name
          dob.name
        end
      end
      @per.seg_name_x=@per.seg_name
      @per.seg_name.length
      testforartnum=@per.seg_name_x
      if (@md.opt.act[:verbose][:set]==:on \
      || @md.opt.act[:verbose_plus][:set]==:on \
      || @md.opt.act[:maintenance][:set]==:on)
        SiSU_Screen::Ansi.new(
          @md.opt.act[:color_state][:set],
          @per.seg_name.length
        )
      end
      SiSU_Particulars::CombinedSingleton.
        instance.get_map_nametags(@md).nametags_map #p map_nametags
      data.each do |dob|
        #if defined? dob.obj \
        #and dob.obj =~/href="#{Xx[:segment]}#+\S+?"/
        #  ##Consider: remove, reinstate earlier?
        #  #while dob.obj =~/href="#{Xx[:segment]}#+(\S+?)"/
        #  #  m=$1
        #  #  if map_nametags[m][:segname]
        #  #    dob.obj=dob.obj.sub(/href="#{Xx[:segment]}#+(\S+?)"/,%{href="#{map_nametags[m][:segname]}#{Sfx[:html]}#\\1"})
        #  #  else
        #  #    p "NOT FOUND name_tags: #{m}"
        #  #    dob.obj=dob.obj.sub(/href="#{Xx[:segment]}#+(\S+?)"/,%{href="#\\1"}) # not satisfactory
        #  #  end
        #  #end
        #end
        if (dob.is==:heading \
        || dob.is==:heading_insert) \
        && dob.ln==4
          @per.heading4=dob.obj
          @per.is4=newfile=1
        end
        if (dob.is==:heading \
        || dob.is==:heading_insert) \
        && dob.ln==3
          @per.heading3=dob.obj
          @per.is4,@per.is3=0,1
        end
        if (dob.is==:heading \
        || dob.is==:heading_insert) \
        && dob.ln==2
          @per.heading2=dob.obj
          @per.is4,@per.is3,@per.is2=0,0,1
        end
        if (dob.is==:heading \
        || dob.is==:heading_insert) \
        && dob.ln==1
          @per.heading1=dob.obj
          @per.is4,@per.is3,@per.is2,@per.is1=0,0,0,1
        end
        if (dob.is==:heading \
        || dob.is==:heading_insert) \
        && dob.ln==0
          @per.heading0=dob.obj
          @per.is4,@per.is3,@per.is2,@per.is1,@per.is0=0,0,0,0,1
        end
        if (@per.is0 && !@per.is1 && !@per.is2 && !@per.is3 && !@per.is4)
          if not (dob.is==:heading \
          || dob.is==:heading_insert) \
          && dob.ln==0
            $_ #; check
          end
        end
        if @per.is4==1
          dir_epub_cont="#{@md.env.processing_path.epub}/#{Ep[:d_oebps]}"
          if newfile==1 \
          or dob.obj =~/^#{Mx[:br_endnotes]}|^#{Mx[:br_eof]}/
            newfile=0
            if (dob.is==:heading \
            || dob.is==:heading_insert) \
            && dob.ln==4
              if tracking != 0
                tail(@md,@per)
                #SiSU_XHTML_EPUB2_Seg::Seg.new(@md,@per).tail
                segfilename="#{dir_epub_cont}/#{@per.seg_name_x[tracking-1]}#{Sfx[:epub_xhtml]}"
                output_epub_cont_seg=File.new(segfilename,'w') if @per.seg_name_x[tracking-1]
                if dob.is==:heading \
                or @per.seg_name_x[tracking-1] !~/endnotes|book_index|metadata/
                  SiSU_XHTML_EPUB2_Seg::Output.new(@md,output_epub_cont_seg,@per).output
                elsif dob.is==:heading_insert
                  if @per.seg_name_x[tracking-1]=='endnotes'
                    SiSU_XHTML_EPUB2_Seg::Output.new(@md,output_epub_cont_seg,@per,'endnotes').output
                  elsif @per.seg_name_x[tracking-1]=='book_index'
                    SiSU_XHTML_EPUB2_Seg::Output.new(@md,output_epub_cont_seg,@per,'idx').output
                    @per.idx=[]
                  elsif @per.seg_name_x[tracking-1]=='metadata' # navigation bug FIX
                    SiSU_XHTML_EPUB2_Seg::Output.new(@md,output_epub_cont_seg,@per,'metadata').output
                  else puts "#{__FILE__}::#{__LINE__}"
                  end
                else puts "#{__FILE__}::#{__LINE__}"
                end
                SiSU_XHTML_EPUB2_Seg::Seg.new.reinitialise(per)
                heading_art(dob)
                head(dob)
                if @per.seg_name_x[tracking] =='metadata'
                  segfilename="#{dir_epub_cont}/#{@per.seg_name_x[tracking]}#{Sfx[:epub_xhtml]}"
                  output_epub_cont_seg=File.new(segfilename,'w')
                  SiSU_XHTML_EPUB2_Seg::Output.new(@md,output_epub_cont_seg,@per,'metadata').output
                  SiSU_XHTML_EPUB2_Seg::Seg.new.reinitialise(per)
                  #BUG navigation bug with items following metadata, and occurring before manifest, this becomes a bug ... work area for book index, FIX
                end
               #@output_epub_cont_seg.closed                                         #%(((( EOF )))) -->
              end
              if tracking==0
                heading_art(dob)
                head(dob)
              end
            end
            tracking=tracking+1
          end
          if (dob.is==:heading \
          || dob.is==:heading_insert) \
          && dob.ln==4 \
          && dob.name
            @per.get_hash_to=dob.name
            @per.get_hash_fn=dob.name
          end
          if dob.obj.is_a?(String)
            markup(dob)
          elsif dob.obj.is_a?(Array)
            dob.obj.each do |pg|
              markup(pg)
            end
          end
          if testforartnum[tracking-1] =~/endnote/
            if printed_endnote_seg=='n'
              printed_endnote_seg='y'
            end
          end
        end
      end
      data
    end
    def heading_art(dob)
      @per.title=SiSU_XHTML_EPUB2_Format::HeadSeg.new(@md).head
    end
    def head(dob)
      clean=/<!.*?!>|<:.*?>$/
      @p_num ||= ''
      if @per.is0==1
        if defined? @md.creator.author \
        and @md.creator.author
          @author=%{<b>#{@md.creator.author}</b>\n}
        end
        @p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,dob.ocn)
        txt_obj={ txt: @per.heading0, ocn_display: @p_num.ocn_display }
        format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
        @per.headings << format_seg.title_heading0.gsub(clean,'')
        @per.heading0=@per.heading0.
          gsub(/#{$ep[:hsp]}<a name="-[\d*+]+" href="#_[\d*+]+">#{$ep[:hsp]}<sup>[\d*+]+<\/sup>#{$ep[:hsp]}<\/a>/,'')
      end
      if @per.is1==1
        @p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,dob.ocn)
        txt_obj={ txt: @per.heading1, ocn_display: @p_num.ocn_display }
        format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
        @per.headings << format_seg.title_heading1.gsub(clean,'')
        @per.heading1=@per.heading1.
          gsub(/#{$ep[:hsp]}<a name="-[\d*+]+" href="#_[\d*+]+">#{$ep[:hsp]}<sup>[\d*+]+<\/sup>#{$ep[:hsp]}<\/a>/,'')
      end
      if @per.is2==1
        heading2=@per.heading2
        @p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,dob.ocn)
        txt_obj={ txt: heading2, ocn_display: @p_num.ocn_display }
        format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
        @per.headings << format_seg.title_heading2.gsub(clean,'')
        @per.heading2=@per.heading2.
          gsub(/#{$ep[:hsp]}<a name="-[\d*+]+" href="#_[\d*+]+">#{$ep[:hsp]}<sup>[\d*+]+<\/sup>#{$ep[:hsp]}<\/a>/,'')
      end
      if @per.is3==1
        heading3=@per.heading3
        @p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,dob.ocn)
        txt_obj={ txt: heading3, ocn_display: @p_num.ocn_display }
        format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
        @per.headings << format_seg.title_heading3.gsub(clean,'')
        @per.heading3=@per.heading3.
          gsub(/#{$ep[:hsp]}<a name="-[\d*+]+" href="#_[\d*+]+">#{$ep[:hsp]}<sup>[\d*+]+<\/sup>#{$ep[:hsp]}<\/a>/,'')
      end
      if @per.is4==1
        heading4=@per.heading4
        @p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,dob.ocn)
        txt_obj={ txt: heading4, ocn_display: @p_num.ocn_display }
        format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
        @per.headings \
        << format_seg.title_heading4.gsub(clean,'')
      end
      @@tracker=@@tracker+1
    end
    def markup(dob)
      @debug=[]
      if dob.is ==:heading \
      || dob.is ==:heading_insert \
      || dob.is ==:para
        #extend as necessary FIX
        @p_num=SiSU_XHTML_EPUB2_Format::ParagraphNumber.new(@md,dob.ocn)
      end
      sto=SiSU_XHTML_EPUB2_Format::FormatTextObject.new(@md,dob)
      dob_xhtml=if dob.is==:heading \
      || dob.is==:heading_insert \
      || dob.is==:para
        dob_xhtml=if dob.is==:heading \
        or dob.is==:heading_insert
          if dob.ln==4
            sto.seg_heading4 # work on see SplitTextObject
          elsif dob.ln==5
            sto.seg_heading5
          elsif dob.ln==6
            sto.seg_heading6
          elsif dob.ln==7
            sto.seg_heading7
          end
        elsif dob.is==:para
          if dob.indent \
          and dob.hang \
          and dob.indent =~/[0-9]/ \
          and dob.hang =~/[0-9]/
            if dob.bullet_
              (dob.indent =~/[1-9]/) \
              ? sto.format('li',"i#{dob.indent}")
              : sto.format('li','bullet')
            elsif dob.indent == dob.hang
              sto.format('p',"i#{dob.indent}")
            elsif dob.indent != dob.hang
              sto.format('p',"h#{dob.hang}i#{dob.indent}")
            else sto.para
            end
          else sto.para
          end
        end
      elsif dob.is ==:block \
      || dob.is ==:group \
      || dob.is ==:alt
        sto.para #fix this should be block type specific #FIX
      elsif dob.is==:verse
        sto.verse
      elsif dob.is==:code
        sto.code
      elsif dob.is==:table
        sto.table
      elsif dob.is==:break
        sto.break
      end
      if @md.flag_separate_endnotes # may need to revisit, check
        dob.obj=dob.obj.gsub(/"\s+href="##{Mx[:note_ref]}(\d+)">/,
          %{" href=\"endnotes#{Sfx[:epub_xhtml]}##{Mx[:note_ref]}\\1">})
          #endnote- twice #removed file type
      end
      if (dob.is ==:heading \
      || dob.is==:heading_insert \
      || dob.is==:para) \
      && (not dob.ocn or dob.ocn.to_s.empty?)
        format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,dob)
      end
      if (dob.is==:heading \
      || dob.is==:heading_insert \
      || dob.is==:para) \
      and dob.note_
        #dob.obj =~/<a href="#note_ref\d+">&nbsp;<sup id=/       #endnote- note-
        format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,dob)
        dob.obj=format_seg.no_paranum
      end
      if (dob.is==:heading \
      || dob.is==:heading_insert) \
      and dob.ln==4
        @per.main <<  %{\n<div class="content">\n}
        @per.main << dob_xhtml
        if @make.build.segsubtoc?
          @per.main << @per.seg_subtoc[@per.get_hash_fn]
          #% insertion of sub-toc
        end
      else
        @per.main << dob_xhtml
      end
    end
    def tail(md,per)
      @md,@per=md,per
      format_head_seg=SiSU_XHTML_EPUB2_Format::HeadSeg.new(@md)
      if @md.flag_auto_endnotes \
      and @per.seg_endnotes[@per.get_hash_fn]
        @per.tail <<  %{\n<div class="content">\n<div class="endnote">\n}
        if @per.seg_endnotes[@per.get_hash_fn].flatten.length > 0
          @per.tail << format_head_seg.endnote_mark
          @per.tail << @per.seg_endnotes[@per.get_hash_fn].flatten
          #endnotes deposited at end of individual segments ||@|EXTRACTION OF ENDNOTES|
        end
        @per.tail << '</div>'
        @per.tail << '</div>' #this div closes div class content
      end
      @per.closed=[]
      @per.closed << format_head_seg.xhtml_close
    end
    def reinitialise(per)
      per.headings,per.main,per.tail,per.credits=Array.new(4){[]}
    end
    def cleanup(md,per)
      reinitialise(per)
      @@tracker=0
      @per.seg_endnotes,@per.seg_subtoc={},{}
      @per.seg_endnotes_array,@per.seg_subtoc_array=[],[]
      per.endnote_all=[]
    end
    def get_subtoc_endnotes(data,per) #get endnotes & sub-table of contents subtoc
      @per=per
      data.each do |dob|
        dob.obj=dob.obj.gsub(/<a name=\"h\d.*?\">(.+?)<\/a>/mi,'\1')
        if @md.flag_auto_endnotes
          if (dob.is==:heading \
          || dob.is==:heading_insert) \
          && dob.ln.to_s =~/^[1-4]/ \
          and not @per.fn.to_s.empty?
            @per.seg_endnotes[@per.fn]=[]
            @per.seg_endnotes[@per.fn] << @per.seg_endnotes_array
            @per.seg_endnotes_array=[] if dob.ln==4
          end
          if (dob.is==:heading \
          || dob.is==:heading_insert) \
          && dob.ln==4
            #%  EXTRACTION OF SUB-TOCs & SEGMENT NAME, after EXTRACTION OF ENDNOTES & SUB-TOCs
            @per.seg_subtoc[@per.fn]=@per.seg_subtoc_array
            @per.seg_subtoc_array=[]
            if dob.name \
            and dob.obj
              @per.fn=dob.name
            else
              @per.fn=(dob.name =~/\S+/) \
              ? dob.name
              : ''
            end
          end
        end
        if dob.is==:heading \
        && dob.ln.to_s =~/^[5-7]/
          case dob.ln
          when 5
            format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,dob)
            subtoc=format_seg.subtoc_lev5 #keep and make available, this is the subtoc
          when 6
            format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,dob)
            subtoc=format_seg.subtoc_lev6 #keep and make available, this is the subtoc
          when 7
            format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,dob)
            subtoc=format_seg.subtoc_lev7 #keep and make available, this is the subtoc
          end
          @per.seg_subtoc_array << subtoc
        end
        if @md.flag_auto_endnotes
          ast,pls='&#042;','&#043;'
          if dob.obj =~/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})(?:\d|#{ast}|#{pls})+ / \
          and dob.is !=:code # endnote-
            endnote_array=[]
            if dob.obj=~/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}/m
              endnote_array << dob.obj.scan(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}/m)
            end
            if dob.obj=~/#{Mx[:en_b_o]}#{ast}\d+\s.+?#{Mx[:en_b_c]}/m
              endnote_array \
              << dob.obj.scan(/#{Mx[:en_b_o]}#{ast}\d+\s.+?#{Mx[:en_b_c]}/m)
            end
            if dob.obj=~/#{Mx[:en_b_o]}#{pls}\d+\s.+?#{Mx[:en_b_c]}/m
              endnote_array \
              << dob.obj.scan(/#{Mx[:en_b_o]}#{pls}\d+\s.+?#{Mx[:en_b_c]}/m)
            end
            endnote_array=endnote_array.flatten #.compact #check compacting
            endnote_array.each do |note|
              note_match=note.dup
              note_match_seg=note.dup
              e_n=note_match_seg[/(?:#{Mx[:en_a_o]}(?:\d|#{ast}|#{pls})+|#{Mx[:en_b_o]}(?:#{ast}|#{pls})\d+)\s+(.+?)(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/m,1]
              try=e_n.split(/<br(?: \/)?>/)
              try.each do |e|
                txt_obj={ txt: e }
                format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
                note_match=if e =~/#{Mx[:pa_o]}i[1-9]#{Mx[:pa_c]}/
                  format_seg.endnote_body_indent
                else format_seg.endnote_body
                end
                @per.seg_endnotes_array << note_match
              end
              try.join('<br \/>')
              #% creation of separate end segment/page of all endnotes referenced back to reference segment
              m=/(?:#{Mx[:en_a_o]}(?:\d|#{ast}|#{pls})+|#{Mx[:en_b_o]}(?:#{ast}|#{pls})\d+)\s+(.+?href=")(##{Mx[:note_ref]}(?:\d|_a|_b)+".+)(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/mi
              endnote_part_a=note_match_seg[m,1]
              endnote_part_b=note_match_seg[m,2]
              txt_obj={
                endnote_part_a: endnote_part_a,
                endnote_part_b: endnote_part_b
              }
              format_seg=SiSU_XHTML_EPUB2_Format::FormatSeg.new(@md,txt_obj)
              note_match_all_seg=format_seg.endnote_seg_body(@per.fn) #BUG WATCH 200408
              @per.endnote_all << note_match_all_seg
            end
            dob.obj=dob.obj.gsub(/(?:#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}|#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]})\s*/m,' ')
          end
        end
      end
    end
  end
end
__END__
#+END_SRC

** xhtml_epub2_tune.rb

#+HEADER: :tangle "../lib/sisu/xhtml_epub2_tune.rb"
#+BEGIN_SRC ruby
#<<sisu_document_header>>
require_relative 'dp'                                   # dp.rb
module SiSU_XHTML_EPUB2_Tune
  require_relative 'se'                                 # se.rb
    include SiSU_Env; include SiSU_Screen
  require_relative 'xhtml_parts'                        # xhtml_parts.rb
  require_relative 'xhtml_epub2_format'                 # xhtml_epub2_format.rb #watch
  @@line_mode=''
  @@endnote_array=[]
  @@endnote_call_counter=1
  @@table_align='<table summary='' width="96%" border="0" bgcolor="white" cellpadding="0" col="3">
<tr ...><td width="2%" align="right">
&nbsp\;</td>
<td width="94%" valign="top" align="justify">'
  @@table_align_close='</td>
<td width="4%" align="right" valign="top">
<font size="1" color="#777777">
&nbsp;&nbsp;&nbsp;</font> </td></tr></table>'
  @@counter,@@column,@columns=0,0,0
  class Output
    def initialize(data,md)
      @data,@md=data,md
      @file=SiSU_Env::InfoFile.new(@md.fns)
      @cX=SiSU_Screen::Ansi.new(@md.opt.act[:color_state][:set]).cX
    end
    def hard_output
      @filename_tune=@file.write_file_processing.html_tune
      data=[]
      @data.each {|x| x.obj.strip; data << x if not x.obj.empty?} #1.9 array?
      data.each do |dob|
        @filename_tune.puts dob, "\n" #check
      end
    end
    def marshal
      File.open(@file.marshal.xhtml_tune,'w') {|f| Marshal.dump(@data.to_a,f)}
    end
  end
  class CleanXHTML
    def initialize(html='')
      @html=html
    end
    def clean
      html=@html
      str=if html.is_a?(String)
        html
      else html.obj
      end
      str=str.gsub(/#{Mx[:gl_o]}(#[0-9]{3})#{Mx[:gl_c]}/u,'&\1;').
        gsub(/#{Mx[:gl_o]}#([a-z]{2,4})#{Mx[:gl_c]}/u,'&\1;').
        gsub(/<br>/u,'<br />').
        gsub(/#{Mx[:nbsp]}/u,$ep[:hsp])
    end
  end
  class Tune
    include SiSU_Parts_XHTML
    def initialize(data,md)
      @data,@md=data,md
      @sys=SiSU_Env::SystemCall.new
      @env=SiSU_Env::InfoEnv.new(@md.fns)
    end
    def songsheet
      begin
        @cX=SiSU_Screen::Ansi.new(@md.opt.act[:color_state][:set]).cX
        if (@md.opt.act[:verbose][:set]==:on \
        || @md.opt.act[:verbose_plus][:set]==:on \
        || @md.opt.act[:maintenance][:set]==:on)
          SiSU_Screen::Ansi.new(
            @md.opt.act[:color_state][:set],
            'Tune'
          ).txt_grey
        end
        data=SiSU_XHTML_EPUB2_Tune::Tune.new(@data,@md).amp_angle_brackets
        data=SiSU_XHTML_EPUB2_Tune::Tune.new(data,@md).endnotes_html
        data=SiSU_XHTML_EPUB2_Tune::Tune.new(data,@md).url_markup
        data=SiSU_XHTML_EPUB2_Tune::Tune.new(data,@md).markup
        if @md.opt.act[:maintenance][:set]==:on #Hard Output Tune Optional on/off here
          data=SiSU_XHTML_EPUB2_Tune::Output.new(data,@md).hard_output
          SiSU_XHTML_EPUB2_Tune::Output.new(data,@md).marshal
        end
        SiSU_XHTML_EPUB2_Tune::Tune.new(@data,@md).output
      rescue
        SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
          __LINE__.to_s + ':' + __FILE__
        end
      ensure
      end
    end
    def markup
      @tuned_file=[]
      @data.each do |dob|
        dob.obj=dob.obj.gsub(/#{Mx[:mk_o]}#([a-zA-Z]+)#{Mx[:mk_c]}/,'&\1;').
          gsub(/#{Mx[:mk_o]}(#[0-9]+)#{Mx[:mk_c]}/,'&\1;')
        dob.obj=dob.obj.gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/,'<br />') unless dob.is==:table
        dob.obj=dob.obj.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'<b>\1</b>').
          gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'<i>\1</i>').
          gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'<u>\1</u>').
          gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'<sup>\1</sup>').
          gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'<sub>\1</sub>').
          gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'<ins>\1</ins>').
          gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'<cite>\1</cite>').
          gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'<del>\1</del>').
          gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,'<tt>\1</tt>'). # tt, kbd
          gsub(/#{Mx[:mk_o]}:name#(\S+?)#{Mx[:mk_c]}/,'').
          gsub(/#{Mx[:gl_bullet]}/m,"●#{$ep[:hsp]*2}").
          gsub(/#{Dx[:url_o]}/,Dx[:url_o_xml]).gsub(/#{Dx[:url_c]}/,Dx[:url_c_xml]).
          gsub(/#{Mx[:nbsp]}/,$ep[:hsp]).
          gsub(/<(p|br)>/,'<\1 />')
        dob.obj=SiSU_XHTML_EPUB2_Tune::CleanXHTML.new(dob.obj).clean
        @tuned_file << dob
      end
    end
    def urls(data)
      @words=[]
      map_nametags=SiSU_Particulars::CombinedSingleton.instance.get_map_nametags(@md).nametags_map #p map_nametags
      data.each do |word|
        @words << if word=~/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)/
          http_=true
          if word =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/
            m,u=/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/.match(word).captures
          elsif word =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}/
            http_=false
            m,u=/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}(\S+?)#{Mx[:rel_c]}/.match(word).captures
          elsif word =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}image/
            m,u=/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}(image)/.match(word).captures
          end
          case m
          when /\.png|\.jpg|\.gif|c=|\s\d+x\d+/
            w,h=/\s(\d+)x(\d+)/.match(m).captures if m =~/\s\d+x\d+/
            w=%{width="#{w}"} if w
            h=%{height="#{h}"} if h
            c=m[/"(.+?)"/m,1]
            caption=%{<br /><p class="caption">#{c}</p>} if c
            png=m.scan(/\S+/)[0]
            image_path=@md.file.output_path.epub.rel_image #image_path=@env.url.images_epub
            ins=if u \
            and u.strip !~/^image$/
              %{<a href="#{u}"><img src="#{image_path}/#{png}" #{w} #{h} naturalsizeflag="0" align="bottom" border="0" /></a>#{caption}}
            else %{<img src="#{image_path}/#{png}" #{w} #{h} naturalsizeflag="0" align="bottom" border="0" />#{caption}}
            end
            word=word.gsub(/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|image)/,ins)
          else
            link=m[/(.+)/m]
            png=m.scan(/\S+/)[0].strip
            link=link.strip
            u=u.sub(/^#*/,'') #make neater
            if map_nametags[u] \
            and map_nametags[u][:segname]
              u=unless http_
                u=if u=~/^\d+$/
                  u.gsub(/^(\d+)$/,"#{map_nametags[u][:segname]}#{Sfx[:xhtml]}#o\\1") if u !~/\//
                else
                  u.gsub(/(\S+)/,"#{map_nametags[u][:segname]}#{Sfx[:xhtml]}#\\1") if u !~/\//
                end
              else u
              end
            elsif u =~/^:/
              u=u.gsub(/^:/,"#{@env.url.root}/")
            elsif u =~/^\.\.\//
              u=u.gsub(/^\.\.\//,"#{@env.url.root}/")
            elsif u =~/https?:\/\//
            else p "NOT FOUND name_tags: #{u}"
            end
            ins=%{<a href="#{u}">#{link}</a>}
            word=word.gsub(/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/,ins).
              gsub(/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}/,ins)
          end
          word
        else word
        end
        word
      end
      @words=@words.join(' ')
    end
    def url_markup
      data=@data
      @tuned_file=[]
      data.each do |dob|
        unless dob.is==:code
          if dob.obj =~/<::\s+/ #watch
            dob.obj=dob.obj.gsub(/<::\s+(\S+?)\s+!>/,
              %{<img src="#{@env.url.images_epub}/c_\\1.png" alt="\\1" width="14" height="14" align="bottom" border="0" />})
          end
          if dob.obj =~/<:image\s+/
            dob.obj=dob.obj.gsub(/<:image\s+(http\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+>/,
                %{<a href="\\1"><img src="#{@env.url.images_epub}/\\2" \\3 \\4 naturalsizeflag="0" align="bottom" border="0" /></a>}).
              gsub(/<:image\s+(http\S+)\s+(\S+)\s+>/,
                %{<a href="\\1"><img src="#{@env.url.images_epub}/\\2" naturalsizeflag="0" align="bottom" border="0" /></a>}).
              gsub(/<:image\s+(\S+)\s+(\S+)\s+(\S+)\s+>/,
                %{<img src="#{@env.url.images_epub}/\\1" \\2 \\3 naturalsizeflag="0" align="bottom" border="0" />}).
              gsub(/<:image\s+(\S+)\s+>/,
                %{<img src="#{@env.url.images_epub}/\\1" naturalsizeflag="0" align="bottom" border="0" />})
          end
          if dob.obj =~/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)/
            @word_mode=dob.obj.scan(/#{Mx[:lnk_o]}.+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)[()\[\]]*[,.;:!?'"]{0,2}|(?:#{Mx[:gl_o]}\S+?#{Mx[:gl_c]})+|[^#{Mx[:lnk_o]}#{Mx[:lnk_c]}]+/mu)
            words=urls(@word_mode)
            dob.obj=dob.obj.gsub(/.+/m,words)
          end
          dob.obj=dob.obj.gsub(/\\copyright/i,%{<sup>&copy;</sup>})
          dob.obj=if (dob.obj !~/\<:ad\s+\.\.\//)
            dob.obj.gsub(/\<:ad\s+(\S+)?\s+(\S+\.png)\s+(.+)?\;\s+(.+)?\;\s*!\>/,
              %{\n<center><a href="http:\/\/\\1" target="external"><img src="#{@env.url.images_epub}/\\2" alt="\\3" /></a></center>\n})
          else
            dob.obj.gsub(/\<:ad\s+(\S+)?\s+(\S+\.png)\s+(.+)?\;\s+(.+)?\;\s*\>/,
              %{\n<center><a href="\\1" target="_top"><img src="#{@env.url.images_epub}/\\2" alt="\\3" /></a></center>\n})
          end
          dob.obj=dob.obj.gsub(/!pick/,%{<img border="0" height="15" width="15" src="#{@env.url.images_epub}/#{the_icon.i_choice}" alt="stellar" />}).
            gsub(/!new/,%{#{$ep[:hsp]}<img border="0" height="15" width="15" src="#{@env.url.images_epub}/#{the_icon.i_new}" alt="new" />}).
            gsub(/<:h(.{1,7}?)>/,'<a href="#h\1">\1</a>').
            gsub(/<:to(\d{1,7}?)>/,%{<a href="#to\\1">to#{$ep[:hsp]}\{#{$ep[:hsp]}\\1#{$ep[:hsp]}\}</a> }).
            gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,'<a href="\1" target="_top">\1</a>'). #http ftp matches escaped, no decoration
            gsub(/#{Mx[:url_o]}([a-zA-Z0-9._-]+\@\S+?\.[a-zA-Z0-9._-]+)#{Mx[:url_c]}/,%{#{the_url_decoration.xml_open}<a href="mailto:\\1">\\1</a>#{the_url_decoration.xml_close}}).
            gsub(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,%{#{the_url_decoration.xml_open}<a href="\\1" target="_top">\\1</a>#{the_url_decoration.xml_close}}) #http ftp matches with decoration
          if dob.obj =~/..\/\S+/ \
          and dob.obj !~/(\"..\/\S+?\"|>\s*..\/\S+<)/
            dob.obj=dob.obj.gsub(/(\.\.\/\S+)/,'<a href="\1">\1</a>')
          end
          dob.obj=dob.obj.gsub(/<a href="\.\.\//,%{<a href="#{the_url.site}/})
        else
          dob.obj=dob.obj.gsub(/</m,'&lt;').gsub(/>/m,'&gt;')
        end
        @tuned_file << dob
      end
    end
    def amp_angle_brackets
      data,data_new=@data,[]
      data.each do |dob|
        dob.obj=dob.obj.
          gsub(/&/u,'&amp;').
          gsub(/</u,'&lt;').gsub(/>/u,'&gt;')
        data_new << dob
      end
      data_new
    end
    def endnotes_html
      data=@data
      @tuned_file=[]
      a,s='_a','_s'
      ast,pls='&#042;','&#043;'
      data.each do |dob|
        unless dob.is ==:code
          dob.obj=dob.obj.gsub(/(#{Mx[:en_a_o]}|#{Mx[:en_b_o]})(\d+)\s+(.+?)(#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/,
              %{#{Mx[:nbsp]}<a href="##{Mx[:note]}\\2">#{Mx[:nbsp]}<sup id="#{Mx[:note_ref]}\\2">\\2</sup>#{Mx[:nbsp]}</a> } +  #note- endnote-
              %{\\1\\2 <a href="##{Mx[:note_ref]}\\2">#{Mx[:nbsp]}<sup id="#{Mx[:note]}\\2">\\2.</sup></a> \\3 \\4}). #endnote- note- (careful may have switched)
            gsub(/(#{Mx[:en_b_o]})[*](\d+)\s+(.+?)(#{Mx[:en_b_c]})/,
              %{#{Mx[:nbsp]}<a href="##{Mx[:note_astx]}\\2">#{Mx[:nbsp]}<sup id="#{Mx[:note_ref_astx]}\\2">#{ast}\\2</sup>#{Mx[:nbsp]}</a> } +  #note- endnote-
              %{\\1#{ast}\\2 <a href="##{Mx[:note_ref_astx]}\\2">#{Mx[:nbsp]}<sup id="#{Mx[:note_astx]}\\2">#{ast}\\2.</sup></a> \\3 \\4}). #endnote- note- (careful may have switched)
            gsub(/(#{Mx[:en_b_o]})[+](\d+)\s+(.+?)(#{Mx[:en_b_c]})/,
              %{#{Mx[:nbsp]}<a href="##{Mx[:note_plus]}\\2">#{Mx[:nbsp]}<sup id="#{Mx[:note_ref_plus]}\\2">#{pls}\\2</sup>#{Mx[:nbsp]}</a> } +  #note- endnote-
              %{\\1#{pls}\\2 <a href="##{Mx[:note_ref_plus]}\\2">#{Mx[:nbsp]}<sup id="#{Mx[:note_plus]}\\2">#{pls}\\2.</sup></a> \\3 \\4}) #endnote- note- (careful may have switched) # double-check there may here be a bug
          if dob.obj =~/#{Mx[:en_a_o]}([*+]+)\s+.+?#{Mx[:en_a_c]}/
            m=$1.length.to_i
            dob.obj=dob.obj.gsub(/(#{Mx[:en_a_o]})[*]+\s+(.+?)(#{Mx[:en_a_c]})/,
                %{#{Mx[:nbsp]}<a href="##{Mx[:note]}#{a*m}">#{Mx[:nbsp]}<sup id="#{Mx[:note_ref]}#{a*m}">#{ast*m}</sup>#{Mx[:nbsp]}</a> } +  #note- endnote-
                %{\\1#{ast*m} <a href="##{Mx[:note_ref]}#{a*m}">#{Mx[:nbsp]}<sup id="#{Mx[:note]}#{a*m}">#{ast*m}</sup></a> \\2 \\3}). #endnote- note- (careful may have switched)
              gsub(/(#{Mx[:en_a_o]})([+]+)\s+(.+?)(#{Mx[:en_a_c]})/,
                %{#{Mx[:nbsp]}<a href="##{Mx[:note]}#{s*m}">#{Mx[:nbsp]}<sup id="#{Mx[:note_ref]}#{s*m}">#{pls*m}</sup>#{Mx[:nbsp]}</a> } +  #note- endnote-
                %{\\1#{pls*m} <a href="##{Mx[:note_ref]}#{s*m}">#{Mx[:nbsp]}<sup id="#{Mx[:note]}#{s*m}">#{pls*m}</sup></a> \\2 \\3}) #endnote- note- (careful may have switched)
          end
        end
        @tuned_file << dob
      end
    end
    def output
      data=@data
      @tuned_file=[]
      data.each do |dob|
        dob.obj=dob.obj.strip.chomp
        @tuned_file << dob
      end
      @tuned_file << "\n<EOF>" if (@md.fns =~/\.sst0/) #remove
      @tuned_file
    end
  end
end
__END__
#+END_SRC

* xhtml shared
** xhtml_parts.rb

#+HEADER: :tangle "../lib/sisu/xhtml_parts.rb"
#+BEGIN_SRC ruby
#<<sisu_document_header>>
module SiSU_Parts_XHTML
  require_relative 'generic_parts'                       # generic_parts.rb
  include SiSU_Parts_Generic
  def the_line_break
    '<br />'
  end
  def the_table_close
    '</td></tr>
</table>'
  end
  def the_url
    def home
      'http://www.sisudoc.org/' # used in pdf header
    end
    def site #used as stub... where there are subdirectories and is different from home
      home
    end
    self
  end
  def the_url_decoration
    def xml_open                     #'&lt;'
      Dx[:url_o]
    end
    def xml_close                    #'&gt;'
      Dx[:url_c]
    end
    def txt_open
      '<'
    end
    def txt_close
      '>'
    end
    self
  end
  def the_margin
    def txt_0
      %{<table summary="" width=#{the_width.table_txt} border="0" cellpadding="2" align="center">
<tr><td width=#{indent_level_0} align="right">
</td><td valign="top" align="justify">}
    end
    def txt_1
      %{<table summary="" width=#{the_width.table_txt} border="0" cellpadding="2" align="center">
<tr><td width=#{indent_level_1} align="right"></td><td valign="top" align="justify">}
    end
    def txt_2
      %{<table summary="" width=#{the_width.table_txt} border="0" cellpadding="2" align="center">
<tr><td width=#{indent_level_2} align="right">
</td>
<td valign="top" align="justify">}
    end
    def txt_3
      %{<table summary="" width=#{the_width.table_txt} border="0" cellpadding="2" align="center">
<tr><td width=#{indent_level_3} align="right">
</td>
<td valign="top" align="justify">}
    end
    def css
      '<table summary="normal text css" width="100%" border="0" cellpadding="2" align="center">
<tr><td valign="top" align="justify"> '
    end
    def num_css
      '</td>
<td width="2%" align="right" valign="top">  '
    end
    self
  end
  def the_font
    def set_fonts
      'verdana, arial, georgia, tahoma, sans-serif, helvetica, times, roman'
     #'verdana, arial, georgia, tahoma, sans-serif, helvetica, "times new roman", times, roman'
    end
    def set_small
      'size="3"'
    end
    def set_tiny
      'size="2"'
    end
    def paragraph_font_tiny
      %{<font #{set_tiny} #{set_face}>}
    end
    def paragraph_font_small
      %{<font #{set_small} #{set_face}>}
    end
    self
  end
  def the_nav
    def txt_concordance
      %{  <font face="#{the_font.set_fonts}" size="2">
    &nbsp;&nbsp;A-Z&nbsp;
  </font> }
    end
    def txt_toc_link
      %{  <font face="#{the_font.set_fonts}" size="2">
    &nbsp;&nbsp;toc&nbsp;
  </font> }
    end
    def txt_manifest
      #{png_manifest}&nbsp;document&nbsp;manifest
      %{  <font face="#{the_font.set_fonts}" size="2">
    [&nbsp;document&nbsp;manifest&nbsp;]
  </font> }
    end
    def txt_concordance
      %{  <font face="#{the_font.set_fonts}" size="2">
    &nbsp;&nbsp;A-Z&nbsp;
  </font> }
    end
    self
  end
end
module SiSU_Proj_XHTML
  require_relative 'se'                                 # se.rb
    include SiSU_Env
  class Bits
    include SiSU_Parts_HTML
    def initialize
      @v=SiSU_Env::InfoVersion.instance.get_version
    end
    def credits_sisu_epub
      %{<div class="substance">
<p class="center"><a href="http://www.openebook.org"><b>EPUB</b></a> generated by <a href="http://www.sisudoc.org"><b>#{@v.project}</b></a> v#{@v.version}, GPL3</p>
</div>}
      ''
    end
  end
end
__END__
#+END_SRC

** xhtml_shared.rb

#+HEADER: :tangle "../lib/sisu/xhtml_shared.rb"
#+BEGIN_SRC ruby
#<<sisu_document_header>>
module SiSU_XHTML_Shared
  require_relative 'xhtml_table'                        # xhtml_table.rb
  class TableXHTML < SiSU_XHTML_Table::TableXHTML
  end
end
__END__
#+END_SRC

** xhtml_table.rb

#+HEADER: :tangle "../lib/sisu/xhtml_table.rb"
#+BEGIN_SRC ruby
#<<sisu_document_header>>
module SiSU_XHTML_Table
  require_relative 'xhtml_parts'                         # xhtml_parts.rb
  class TableXHTML
    include SiSU_Parts_XHTML
    @@tablefoot=[] #watch
    def initialize(table)
      @table_obj=table
    end
    def table
      table_obj=@table_obj
      if table_obj.obj !~/^<table\s/m
        table_obj=table_rows_and_columns_array(table_obj)
      else p __LINE__; p caller
      end
      table_obj
    end
    def table_rows_and_columns_array(table_obj) # provides basic (x)html table
      table_rows,nr=[],0
      table_obj.obj.split(Mx[:tc_c]).each do |table_row|
        table_row_with_columns=table_row.split(Mx[:tc_p])
        trc,nc=[],0
        table_row_with_columns.each do |c|
          c=c.gsub(/^~$/,''). # tilde / empty cell
            gsub(/<:br>/,the_line_break)
          trc <<= if table_obj.head_ and nr==0; %{<th width="#{table_obj.widths[nc]}%">#{c}</th>}
          else %{<td width="#{table_obj.widths[nc]}%">#{c}</td>}
          end
          nc+=1
        end
        trc=(trc.is_a?(Array)) ? trc.flatten.join : trc
        trc="      <tr>#{trc}</tr>\n"
        nr+=1
        table_rows << trc
      end
      table_rows=table_rows.flatten.join
      table_obj.obj=%{<table summary="normal text css" width="100%" border="0" bgcolor="white" cellpadding="2" align="center">\n#{table_rows}    </table>}
      table_obj
    end
  end
end
__END__
#+END_SRC

* document header

#+NAME: sisu_document_header
#+BEGIN_SRC text
encoding: utf-8
- Name: SiSU

  - Description: documents, structuring, processing, publishing, search
    xhtml

  - Author: Ralph Amissah
    <ralph.amissah@gmail.com>

  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
    2020, 2021, Ralph Amissah,
    All Rights Reserved.

  - License: GPL 3 or later:

    SiSU, a framework for document structuring, publishing and search

    Copyright (C) Ralph Amissah

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

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

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

    If you have Internet connection, the latest version of the GPL should be
    available at these locations:
    <http://www.fsf.org/licensing/licenses/gpl.html>
    <http://www.gnu.org/licenses/gpl.html>

    <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>

  - SiSU uses:
    - Standard SiSU markup syntax,
    - Standard SiSU meta-markup syntax, and the
    - Standard SiSU object citation numbering and system

  - Homepages:
    <http://www.sisudoc.org>

  - Git
    <https://git.sisudoc.org/projects/>
    <https://git.sisudoc.org/projects/?p=software/sisu.git;a=summary>
    <https://git.sisudoc.org/projects/?p=markup/sisu-markup-samples.git;a=summary>
#+END_SRC
