From 954419b5ae79efb032d28b145ee40d0b61c80c23 Mon Sep 17 00:00:00 2001
From: Ralph Amissah <ralph@amissah.com>
Date: Tue, 1 Jul 2014 00:33:49 -0400
Subject: v5: merge what was sisu_6.0.8 into v5

* ao,
  * syntax, able optionally to indicate the language syntax of a code block
  * syntax, introduce box text block/group
  * syntax, introduce tics quotes markup (blockquote equivalent)
* docbook,
  * ocn & footnote numbers (as xml comments)
  * metadata header (docinfo)
  * quotes (blockquote)
  * tables
  * images
  * code block
* vim syntax, add
  * code block, language syntax, optional
  * box block
  * quote block
---
 data/doc/sisu/CHANGELOG_v5          |  17 ++++
 lib/sisu/v5/ao_doc_objects.rb       |  49 +++++++++--
 lib/sisu/v5/ao_doc_str.rb           | 164 +++++++++++++++++++++++++-----------
 lib/sisu/v5/ao_expand_insertions.rb |   2 +-
 lib/sisu/v5/ao_misc_arrange.rb      |  48 ++++++++---
 lib/sisu/v5/ao_syntax.rb            |   3 +-
 lib/sisu/v5/shared_metadata.rb      |  66 +++++++++++++++
 lib/sisu/v5/txt_shared.rb           |   9 +-
 lib/sisu/v5/xml_docbook5.rb         | 128 ++++++++++++++++++++--------
 lib/sisu/v5/xml_shared.rb           |  49 ++++++-----
 lib/sisu/v5/xml_tables.rb           |  58 +++++++++++++
 11 files changed, 461 insertions(+), 132 deletions(-)

diff --git a/data/doc/sisu/CHANGELOG_v5 b/data/doc/sisu/CHANGELOG_v5
index 7f876e7c..07221ecf 100644
--- a/data/doc/sisu/CHANGELOG_v5
+++ b/data/doc/sisu/CHANGELOG_v5
@@ -38,6 +38,23 @@ http://www.jus.uio.no/sisu/pkg/src/sisu_5.4.3.orig.tar.xz
   sisu_5.4.3.orig.tar.xz
   sisu_5.4.3-1.dsc
 
+* merge what was sisu_6.0.8 into v5
+  * ao,
+    * syntax, able optionally to indicate the language syntax of a code block
+    * syntax, introduce box text block/group
+    * syntax, introduce tics quotes markup (blockquote equivalent)
+  * docbook,
+    * ocn & footnote numbers (as xml comments)
+    * metadata header (docinfo)
+    * quotes (blockquote)
+    * tables
+    * images
+    * code block
+  * vim syntax, add
+    * code block, language syntax, optional
+    * box block
+    * quote block
+
 %% 5.4.2.orig.tar.xz (2014-06-22:24/7)
 http://sources.sisudoc.org/gitweb/?p=code/sisu.git;a=shortlog;h=refs/tags/sisu_5.4.2
 http://sources.sisudoc.org/gitweb/?p=code/sisu.git;a=shortlog;h=refs/tags/debian/sisu_5.4.2-1
diff --git a/lib/sisu/v5/ao_doc_objects.rb b/lib/sisu/v5/ao_doc_objects.rb
index c53c60d6..dd0a44cd 100644
--- a/lib/sisu/v5/ao_doc_objects.rb
+++ b/lib/sisu/v5/ao_doc_objects.rb
@@ -184,10 +184,10 @@ module SiSU_AO_DocumentStructure
     end
   end
   class ObjectPara
-    attr_accessor :obj,:is,:tags,:of,:name,:idx,:bullet_,:indent,:hang,:ocn,:odv,:osp,:parent,:note_,:image_,:ocn_,:digest,:tmp
+    attr_accessor :obj,:is,:tags,:of,:name,:idx,:quote_,:bullet_,:indent,:hang,:ocn,:odv,:osp,:parent,:note_,:image_,:ocn_,:digest,:tmp
     def initialize
       @of=:para
-      @is=@obj=@name=@idx=@bullet_=@indent=@hang=@size=@ocn=@odv=@osp=@parent=@note_=@image_=@ocn_=@digest=@tmp=nil
+      @is=@obj=@name=@idx=@quote_=@bullet_=@indent=@hang=@size=@ocn=@odv=@osp=@parent=@note_=@image_=@ocn_=@digest=@tmp=nil
       @tags=[]
     end
     def paragraph(h,o=nil)
@@ -204,6 +204,7 @@ module SiSU_AO_DocumentStructure
       indent= h[:indent].to_s || ((defined? o.indent) ? o.indent.to_s : nil)   #Integer, indent level
       hang=   h[:hang].to_s || ((defined? o.hang)    ? o.hang.to_s : nil)      #Integer, hanging indent level
       bullet_=h[:bullet_] || ((defined? o.bullet_)   ? o.bullet_ : false)      #Bool, bulleted?
+      quote_= h[:quote_]  || ((defined? o.quote_)    ? o.quote_  : false)      #Bool, quote (blockquote)?
       note_=  h[:note_]   || ((defined? o.note_)     ? o.note_   : false)      #Bool, endnotes/footnotes? (processing optimization)
       image_= h[:image_]  || ((defined? o.image_)    ? o.image_  : false)      #Bool, images? (processing optimization)
       ocn_=if h[:ocn_].nil? then ((defined? o.ocn_)  ? o.ocn_    : true)       #Bool? no ocn, non-substantive content, do not include in toc #consider
@@ -211,7 +212,7 @@ module SiSU_AO_DocumentStructure
       end
       digest= h[:digest]  || ((defined? o.digest)    ? o.digest  : nil)        #hash digests, sha512, sha256 or md5
       tmp=    h[:tmp]     || ((defined? o.tmp)       ? o.tmp     : nil)        #available for processing, empty after use
-      @of,@is,@name,@tags,@obj,@indent,@hang,@bullet_,@idx,@ocn,@odv,@osp,@parent,@image_,@note_,@ocn_,@digest,@tmp=of,is,name,tags,obj,indent,hang,bullet_,idx,ocn,odv,osp,parent,image_,note_,ocn_,digest,tmp
+      @of,@is,@name,@tags,@obj,@indent,@hang,@bullet_,@quote_,@idx,@ocn,@odv,@osp,@parent,@image_,@note_,@ocn_,@digest,@tmp=of,is,name,tags,obj,indent,hang,bullet_,quote_,idx,ocn,odv,osp,parent,image_,note_,ocn_,digest,tmp
       self
     end
     def docinfo(h,o=nil)
@@ -240,10 +241,10 @@ module SiSU_AO_DocumentStructure
     end
   end
   class ObjectBlockTxt
-    attr_accessor :obj,:is,:of,:tags,:idx,:ocn,:odv,:osp,:parent,:note_,:number_,:ocn_,:digest,:tmp
+    attr_accessor :obj,:is,:of,:tags,:lngsyn,:idx,:ocn,:odv,:osp,:parent,:note_,:number_,:ocn_,:digest,:tmp
     def initialize
       @of=:block
-      @is=@obj=@idx=@ocn=@odv=@osp=@parent=@note_=@number_=@ocn_=@digest=@tmp=nil
+      @is=@obj=@lngsyn=@idx=@ocn=@odv=@osp=@parent=@note_=@number_=@ocn_=@digest=@tmp=nil
       @tags=[]
     end
     def code(h,o=nil)
@@ -251,6 +252,7 @@ module SiSU_AO_DocumentStructure
       is=      :code                                                           #Symbol, classification - specific type
       tags=    h[:tags]    || ((defined? o.tags)     ? o.tags    : [])         #Array, associated object tags, names if any
       obj=     h[:obj]     || ((defined? o.obj)      ? o.obj     : nil)        #String, text content
+      lngsyn=  h[:lngsyn]  || ((defined? o.lngsyn)   ? o.lngsyn  : :txt)       #symbol, code lngsyn
       idx=     h[:idx]     || ((defined? o.idx)      ? o.idx     : nil)        #String, book index provided?
       ocn=     h[:ocn]     || ((defined? o.ocn)      ? o.ocn     : nil)        #Integer, sequential on substantive-content objects
       odv=     h[:odv]     || ((defined? o.odv)      ? o.odv     : nil)
@@ -264,7 +266,27 @@ module SiSU_AO_DocumentStructure
       num=     h[:num]     || ((defined? o.num)      ? o.num     : nil)
       digest=  h[:digest]  || ((defined? o.digest)   ? o.digest  : nil)        #hash digests, sha512, sha256 or md5
       tmp=     h[:tmp]     || ((defined? o.tmp)      ? o.tmp     : nil)        #available for processing, empty after use
-      @of,@is,@tags,@obj,@idx,@ocn,@odv,@osp,@parent,@number_,@note_,@ocn_,@num,@digest,@tmp=of,is,tags,obj,idx,ocn,odv,osp,parent,number_,note_,ocn_,num,digest,tmp
+      @of,@is,@tags,@obj,@lngsyn,@idx,@ocn,@odv,@osp,@parent,@number_,@note_,@ocn_,@num,@digest,@tmp=of,is,tags,obj,lngsyn,idx,ocn,odv,osp,parent,number_,note_,ocn_,num,digest,tmp
+      self
+    end
+    def box(h,o=nil)
+      of=      @of                                                             #Symbol, classification - group
+      is=      :box                                                            #Symbol, classification - specific type
+      tags=    h[:tags]    || ((defined? o.tags)     ? o.tags    : [])         #Array, associated object tags, names if any
+      obj=     h[:obj]     || ((defined? o.obj)      ? o.obj     : nil)        #String, text content
+      idx=     h[:idx]     || ((defined? o.idx)      ? o.idx     : nil)        #String, book index provided?
+      ocn=     h[:ocn]     || ((defined? o.ocn)      ? o.ocn     : nil)        #Integer, sequential on substantive-content objects
+      odv=     h[:odv]     || ((defined? o.odv)      ? o.odv     : nil)
+      osp=     h[:osp]     || ((defined? o.osp)      ? o.osp     : nil)
+      parent=  h[:parent]  || ((defined? o.parent)   ? o.parent  : nil)        #[Node parent]
+      note_=   h[:note_]   || ((defined? o.note_)    ? o.note_   : false)      #Bool, endnotes/footnotes? (processing optimization)
+      ocn_= if h[:ocn_].nil? then ((defined? o.ocn_) ? o.ocn_    : true)       #Bool? no ocn, non-substantive content, do not include in toc #consider
+      else     h[:ocn_]
+      end
+      num=     h[:num]     || ((defined? o.num)      ? o.num     : nil)
+      digest=  h[:digest]  || ((defined? o.digest)   ? o.digest  : nil)        #hash digests, sha512, sha256 or md5
+      tmp=     h[:tmp]     || ((defined? o.tmp)      ? o.tmp     : nil)        #available for processing, empty after use
+      @of,@is,@tags,@obj,@idx,@ocn,@odv,@osp,@parent,@note_,@ocn_,@num,@digest,@tmp=of,is,tags,obj,idx,ocn,odv,osp,parent,note_,ocn_,num,digest,tmp
       self
     end
     def block(h,o=nil)
@@ -455,10 +477,10 @@ module SiSU_AO_DocumentStructure
     end
   end
   class ObjectLayout
-    attr_accessor :obj,:is,:of,:from,:tmp
+    attr_accessor :obj,:sym,:attr,:is,:of,:from,:tmp,:num
     def initialize
       @of=:layout
-      @is=@obj=@from=@tmp=nil
+      @is=@obj=@from=@tmp=@num=nil
     end
     def break(h,f=nil)                                                         #decide how to deal with
       of=     @of                                                              #Symbol, classification - group
@@ -477,6 +499,17 @@ module SiSU_AO_DocumentStructure
       @of,@is,@obj,@tmp=of,is,obj,tmp
       self
     end
+    def open_close(h,o=nil)                                                    #useful for poem & quote
+      of=     @of                                                              #Symbol, classification - group
+      is=     :open_close_tags                                                 #Symbol, classification - specific type
+      obj=    h[:obj]     || ((defined? o.obj)       ? o.obj     : nil)        #String, text content
+      sym=    h[:sym]     || ((defined? o.sym)       ? o.sym     : nil)        #Symbol tag_open, tag_close
+      attr=   h[:attr]    || ((defined? o.attr)      ? o.attr    : nil)        #String, text content
+      tmp=    h[:tmp]     || ((defined? o.tmp)       ? o.tmp     : nil)        #available for processing, empty after use
+      num=    h[:num]     || ((defined? o.num)       ? o.num     : nil)
+      @of,@is,@obj,@sym,@attr,@tmp,@num=of,is,obj,sym,attr,tmp,num
+      self
+    end
   end
   class ObjectComment
     attr_accessor :obj,:is,:of,:tmp
diff --git a/lib/sisu/v5/ao_doc_str.rb b/lib/sisu/v5/ao_doc_str.rb
index 4708a126..e5ed0fd0 100644
--- a/lib/sisu/v5/ao_doc_str.rb
+++ b/lib/sisu/v5/ao_doc_str.rb
@@ -65,10 +65,13 @@ module SiSU_AO_DocumentStructureExtract
     @@flag={
       ocn:         :on,
       code:        :off,
+      lngsyn:      :txt,
       poem:        :off,
       block:       :off,
+      box:         :off,
       group:       :off,
       alt:         :off,
+      quote:       :off,
       table:       :off,
       table_to:    :off,
     }
@@ -81,10 +84,13 @@ module SiSU_AO_DocumentStructureExtract
     @@flag={
       ocn:         :on,
       code:        :off,
+      lngsyn:      :txt,
       poem:        :off,
       block:       :off,
+      box:         :off,
       group:       :off,
       alt:         :off,
+      quote:       :off,
       table:       :off,
       table_to:    :off,
     }
@@ -119,6 +125,11 @@ module SiSU_AO_DocumentStructureExtract
       ? true
       : false
     end
+    def quotes?
+      @@flag[:quote]==:open \
+      ? true
+      : false
+    end
     def hang_and_indent_test(str)
       hang_indent=if str=~/^_([1-9])[^_]/
         [$1,$1]
@@ -229,8 +240,10 @@ module SiSU_AO_DocumentStructureExtract
       @num_id={
         code_block: 0,
         poem:       0,
+        box:        0,
         group:      0,
         alt:        0,
+        quote:      0,
         table:      0,
       }
       @metadata={}
@@ -254,13 +267,14 @@ module SiSU_AO_DocumentStructureExtract
           next
         end
         t_o=t_o.gsub(/(?:\n\s*\n)+/m,"\n") if @@flag[:code]==:off
-        if t_o !~/^(?:code|poem|alt|group|block)\{|^\}(?:code|poem|alt|group|block)|^(?:table\{|\{table)[ ~]/ \
-        and t_o !~/^```[ ]+(?:code|poem|alt|group|block|table)|^```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$/ \
+        if t_o !~/^(?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block)\{|^\}(?:code|poem|alt|group|block)|^(?:table\{|\{table)[ ~]/ \
+        and t_o !~/^```[ ]+(?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block|table)|^```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$|^`:quote_(?:open|close)`/ \
         and @@flag[:code]==:off \
         and @@flag[:poem]==:off \
         and @@flag[:group]==:off \
         and @@flag[:block]==:off \
         and @@flag[:alt]==:off \
+        and @@flag[:box]==:off \
         and @@flag[:table]==:off
           unless t_o =~/^(?:@\S+?:|%+)\s/                  # extract book index for paragraph if any
             idx=if t_o=~/^=\{(.+)\}\s*$\Z/m; m=$1
@@ -364,7 +378,7 @@ module SiSU_AO_DocumentStructureExtract
                     obj << ' ~#'
                   end
                 end
-                h={ bullet_: bullet, hang: hang, indent: indent, obj: obj, idx: idx, note_: note, image_: image, tags: tags }
+                h={ bullet_: bullet, hang: hang, indent: indent, obj: obj, idx: idx, note_: note, image_: image, tags: tags, quote: quotes? }
                 SiSU_AO_DocumentStructure::ObjectPara.new.paragraph(h)
               end
             else nil
@@ -387,7 +401,7 @@ module SiSU_AO_DocumentStructureExtract
                     obj << ' ~#'
                   end
                 end
-                h={ hang: hang, indent: indent, obj: obj, idx: idx, note_: note, image_: image, tags: tags }
+                h={ hang: hang, indent: indent, obj: obj, idx: idx, note_: note, image_: image, tags: tags, quote: quotes? }
                 SiSU_AO_DocumentStructure::ObjectPara.new.paragraph(h)
               end
             else nil
@@ -411,22 +425,32 @@ module SiSU_AO_DocumentStructureExtract
               end
             end
             unless obj=~/\A\s*\Z/m
-              h={ bullet_: false, indent: 0, hang: 0, obj: obj, idx: idx, note_: note, image_: image, tags: tags }
+              h={ bullet_: false, indent: 0, hang: 0, obj: obj, idx: idx, note_: note, image_: image, tags: tags, quote: quotes? }
               SiSU_AO_DocumentStructure::ObjectPara.new.paragraph(h)
             end
           end
         elsif @@flag[:code]==:off
-          if t_o =~/^(?:code\{|```[ ]+code)/
+          if t_o =~/^(?:code(?:\.[a-z][0-9a-z_]+)?\{|```[ ]+code(?:\.[a-z][0-9a-z_]+)?)/
             @@flag[:code]=case t_o
-            when /^code\{/         then :curls
-            when /^```[ ]+code/    then :tics
-            else                   @@flag[:code] #error
+            when /^code(?:\.[a-z][0-9a-z_]+)?\{/ then :curls
+            when /^```[ ]+code/                  then :tics
+            else                                 @@flag[:code] #error
+            end
+            @@flag[:lngsyn]=if t_o =~/^(?:code\.[a-z][0-9a-z_]+\{|```[ ]+code\.[a-z_]+)/
+              case t_o
+              when /^code\.([a-z][0-9a-z_]+)\{/
+                :"#{$1}"
+              when /^```[ ]+code\.([a-z][0-9a-z_]+)/
+                :"#{$1}"
+              else :txt
+              end
+            else :txt
             end
             @@counter=1
-            @codeblock_numbered=(t_o =~/^(?:code\{#|```[ ]+code\s[#])/) ? true : false
+            @codeblock_numbered=(t_o =~/^(?:code(?:\.[a-z][0-9a-z_]+)?\{#|```[ ]+code(?:\.[a-z][0-9a-z_]+)?\s[#])/) ? true : false
             @num_id[:code_block] +=1
-            h={ obj: "group text start #{@num_id[:code_block]}" }
-            t_o=SiSU_AO_DocumentStructure::ObjectComment.new.comment(h)
+            h={  obj: '', sym: :code_block_open, num: @num_id[:code_block], syntax: @@flag[:lngsyn] }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
           elsif t_o =~/^(?:poem\{|```[ ]+poem)/
             @@flag[:poem]=case t_o
             when /^poem\{/        then :curls
@@ -434,8 +458,18 @@ module SiSU_AO_DocumentStructureExtract
             else                  @@flag[:poem] #error
             end
             @num_id[:poem] +=1
-            h={ obj: "poem start #{@num_id[:poem]}" }
-            t_o=SiSU_AO_DocumentStructure::ObjectComment.new.comment(h)
+            h={  obj: '', sym: :poem_open, num: @num_id[:poem] }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+            tuned_file << t_o
+          elsif t_o =~/^(?:box(?:\.[a-z_]+)?\{|```[ ]+box(?:\.[a-z_]+)?)/
+            @@flag[:box]=case t_o
+            when /^box\{/         then :curls
+            when /^```[ ]+box/    then :tics
+            else                  @@flag[:box] #error
+            end
+            @num_id[:box] +=1
+            h={ obj: '', sym: :box_open, num: @num_id[:box] }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
             tuned_file << t_o
           elsif t_o =~/^(?:group\{|```[ ]+group)/
             @@flag[:group]=case t_o
@@ -444,8 +478,8 @@ module SiSU_AO_DocumentStructureExtract
             else                  @@flag[:group] #error
             end
             @num_id[:group] +=1
-            h={ obj: "group text start #{@num_id[:group]}" }
-            t_o=SiSU_AO_DocumentStructure::ObjectComment.new.comment(h)
+            h={ obj: '', sym: :group_open, num: @num_id[:group] }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
             tuned_file << t_o
           elsif t_o =~/^(?:block\{|```[ ]+block)/
             @@flag[:block]=case t_o
@@ -454,8 +488,8 @@ module SiSU_AO_DocumentStructureExtract
             else                  @@flag[:block] #error
             end
             @num_id[:block] +=1
-            h={ obj: "block text start #{@num_id[:block]}" }
-            t_o=SiSU_AO_DocumentStructure::ObjectComment.new.comment(h)
+            h={ obj: '', sym: :block_open, num: @num_id[:block] }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
             tuned_file << t_o
           elsif t_o =~/^(?:alt\{|```[ ]+alt)/
             @@flag[:alt]=case t_o
@@ -464,14 +498,20 @@ module SiSU_AO_DocumentStructureExtract
             else                  @@flag[:alt] #error
             end
             @num_id[:alt] +=1
-            h={ obj: "alt text start #{@num_id[:alt]}" }
-            t_o=SiSU_AO_DocumentStructure::ObjectComment.new.comment(h)
+            h={ obj: '', sym: :alt_open, num: @num_id[:alt] }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
             tuned_file << t_o
+          elsif t_o =~/^`:quote_open`/
+            @@flag[:quote]=:open
+            @num_id[:quote] +=1
+            h={ obj: '', sym: :quote_open, num: @num_id[:quote] }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+            #tuned_file << t_o #% find second source, entered twice, should be once so closed off here
           elsif t_o =~/^(?:table\{|```[ ]+table|\{table)[ ~]/
             @num_id[:table] +=1
-            h={ obj: "table start #{@num_id[:table]}" }
-            ins=SiSU_AO_DocumentStructure::ObjectComment.new.comment(h)
-            tuned_file << ins
+            h={ obj: '', sym: :table_open, num: @num_id[:table] }
+            ins_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+            tuned_file << ins_o
             if t_o=~/^table\{(?:~h)?\s+/
               @@flag[:table]=:curls
               @rows=''
@@ -526,8 +566,8 @@ module SiSU_AO_DocumentStructureExtract
               h={ head_: hd, cols: cols, widths: col, obj: rows, idx: idx, tags: tags, num: @num_id[:table] }
               t_o=SiSU_AO_DocumentStructure::ObjectTable.new.table(h) unless h.nil?
               tuned_file << t_o
-              h={ obj: "table end #{@num_id[:table]}" }
-              t_o=SiSU_AO_DocumentStructure::ObjectComment.new.comment(h)
+              h={ obj: '', sym: :table_close, num: @num_id[:table] }
+              t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
               t_o
             elsif t_o=~/^```[ ]+table(?:~h)?\s+/
               m1,m2,hd=nil,nil,nil
@@ -549,8 +589,8 @@ module SiSU_AO_DocumentStructureExtract
               h={ head_: hd, cols: col.length, widths: col, obj: rows, idx: idx, tags: tags, num: @num_id[:table] }
               t_o=SiSU_AO_DocumentStructure::ObjectTable.new.table(h) unless h.nil?
               tuned_file << t_o
-              h={ obj: "table end #{@num_id[:table]}" }
-              t_o=SiSU_AO_DocumentStructure::ObjectComment.new.comment(h)
+              h={ obj: '', sym: :table_close, num: @num_id[:table] }
+              t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
               t_o
             elsif t_o=~/^\{table(?:~h)?\s+/
               m1,m2,hd=nil,nil,nil
@@ -572,8 +612,8 @@ module SiSU_AO_DocumentStructureExtract
               h={ head_: hd, cols: col.length, widths: col, obj: rows, idx: idx, tags: tags, num: @num_id[:table] }
               t_o=SiSU_AO_DocumentStructure::ObjectTable.new.table(h) unless h.nil?
               tuned_file << t_o
-              h={ obj: "table end #{@num_id[:table]}" }
-              t_o=SiSU_AO_DocumentStructure::ObjectComment.new.comment(h)
+              h={ obj: '', sym: :table_close, num: @num_id[:table] }
+              t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
               t_o
             end
           end
@@ -590,13 +630,13 @@ module SiSU_AO_DocumentStructureExtract
             t_o=SiSU_AO_DocumentStructure::ObjectTable.new.table(@h)
             tuned_file << t_o
             @h,@rows=nil,''
-            h={ obj: "table end #{@num_id[:table]}" }
-            t_o=SiSU_AO_DocumentStructure::ObjectComment.new.comment(h)
+            h={ obj: '', sym: :table_close, num: @num_id[:table] }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
             t_o
           else
             if t_o.is_a?(String) \
             and t_o !~/^(?:table\{|```[ ]+table)/
-              t_o=t_o.gsub(/^\n+/m,''). #check added for ruby 1.9.2 not needed in 1.8 series (tested in v2)
+              t_o=t_o.gsub(/^\n+/m,'').
                 gsub(/\n+/m,"#{Mx[:tc_p]}")
               @rows += t_o + Mx[:tc_c]
             end
@@ -610,12 +650,13 @@ module SiSU_AO_DocumentStructureExtract
             @tuned_code[-1].gsub!(/\s*(?:#{Mx[:br_line]}|#{Mx[:br_nl]})\s*\Z/m,'')
             obj=@tuned_code.join("\n")
             tags=[]
-            h={ obj: obj, tags: tags, num: @num_id[:code_block], number_: @codeblock_numbered }
+            h={ obj: obj, syntax: @@flag[:lngsyn], tags: tags, num: @num_id[:code_block], number_: @codeblock_numbered }
+            @@flag[:lngsyn]=:txt
             t_o=SiSU_AO_DocumentStructure::ObjectBlockTxt.new.code(h)
             @tuned_code=[]
             tuned_file << t_o
-            h={ obj: "code block end #{@num_id[:code_block]}" }
-            t_o=SiSU_AO_DocumentStructure::ObjectComment.new.comment(h)
+            h={ obj: '', sym: :code_close, num: @num_id[:code_block] }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
           end
           if (@@flag[:code]==:curls or @@flag[:code]==:tics) \
           and t_o.is_a?(String)
@@ -627,14 +668,26 @@ module SiSU_AO_DocumentStructureExtract
             t_o=nil
           end
         elsif (@@flag[:poem]==:curls or @@flag[:poem]==:tics) \
+        or (@@flag[:box]==:curls or @@flag[:box]==:tics) \
         or (@@flag[:group]==:curls or @@flag[:group]==:tics) \
         or (@@flag[:block]==:curls or @@flag[:block]==:tics) \
-        or (@@flag[:alt]==:curls or @@flag[:alt]==:tics)
+        or (@@flag[:alt]==:curls or @@flag[:alt]==:tics) \
+        or (@@flag[:quote]==:open and t_o =~/`:quote_close`/m) #not
           if (@@flag[:poem]==:curls and t_o =~/^\}poem/) \
           or (@@flag[:poem]==:tics and t_o =~/^```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$/)
             @@flag[:poem]=:off
-            h={ obj: "poem end #{@num_id[:poem]}" }
-            t_o=SiSU_AO_DocumentStructure::ObjectComment.new.comment(h)
+            h={ obj: '', sym: :poem_close, num: @num_id[:poem] }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+          elsif (@@flag[:box]==:curls and t_o =~/^\}box/) \
+          or (@@flag[:box]==:tics and t_o =~/^```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$/)
+            @@flag[:box]=:off
+            obj,tags=extract_tags(@tuned_block.join("\n"))
+            h={ obj: obj, tags: tags, num: @num_id[:box] }
+            @tuned_block=[]
+            t_o=SiSU_AO_DocumentStructure::ObjectBlockTxt.new.box(h)
+            tuned_file << t_o
+            h={ obj: '', sym: :box_close, num: @num_id[:box] }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
           elsif (@@flag[:group]==:curls and t_o =~/^\}group/) \
           or (@@flag[:group]==:tics and t_o =~/^```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$/)
             @@flag[:group]=:off
@@ -643,8 +696,8 @@ module SiSU_AO_DocumentStructureExtract
             @tuned_block=[]
             t_o=SiSU_AO_DocumentStructure::ObjectBlockTxt.new.group(h)
             tuned_file << t_o
-            h={ obj: "group text end #{@num_id[:group]}" }
-            t_o=SiSU_AO_DocumentStructure::ObjectComment.new.comment(h)
+            h={ obj: '', sym: :group_close, num: @num_id[:group] }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
           elsif (@@flag[:block]==:curls and t_o =~/^\}block/) \
           or (@@flag[:block]==:tics and t_o =~/^```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$/)
             @@flag[:block]=:off
@@ -653,8 +706,8 @@ module SiSU_AO_DocumentStructureExtract
             @tuned_block=[]
             t_o=SiSU_AO_DocumentStructure::ObjectBlockTxt.new.block(h)
             tuned_file << t_o
-            h={ obj: "block text end #{@num_id[:block]}" }
-            t_o=SiSU_AO_DocumentStructure::ObjectComment.new.comment(h)
+            h={ obj: '', sym: :block_close, num: @num_id[:block] }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
           elsif (@@flag[:alt]==:curls and t_o =~/^\}alt/) \
           or (@@flag[:alt]==:tics and t_o =~/^```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$/)
             @@flag[:alt]=:off
@@ -663,15 +716,23 @@ module SiSU_AO_DocumentStructureExtract
             t_o=SiSU_AO_DocumentStructure::ObjectBlockTxt.new.alt(h)
             @tuned_block=[]
             tuned_file << t_o
-            h={ obj: "alt text end #{@num_id[:alt]}" }
-            t_o=SiSU_AO_DocumentStructure::ObjectComment.new.comment(h)
+            h={ obj: '', sym: :alt_close, num: @num_id[:alt] }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+          elsif @@flag[:quote]==:open and t_o =~/`:quote_close`/m
+            @@flag[:quote]=:off
+            h={ obj: '', sym: :quote_close, num: @num_id[:quote] }
+            t_o=SiSU_AO_DocumentStructure::ObjectLayout.new.open_close(h)
+          elsif @@flag[:quote]==:open
+            t_o,tags=extract_tags(t_o)
+            h={ indent: 1, obj: t_o, idx: idx, note_: note, image_: image, tags: tags, quote: quotes? }
+            SiSU_AO_DocumentStructure::ObjectPara.new.paragraph(h)
           end
           if (@@flag[:poem]==:curls or @@flag[:poem]==:tics \
           or @@flag[:group]==:curls or @@flag[:group]==:tics \
           or @@flag[:alt]==:curls or @@flag[:alt]==:tics) \
           and t_o =~/\S/ \
-          and t_o !~/^(?:\}(?:verse|code|alt|group|block)|(?:verse|code|alt|group|block)\{)/ \
-          and t_o !~/^```[ ]+(?:code|poem|alt|group|block)|^```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$/ # fix logic
+          and t_o !~/^(?:\}(?:verse|code|box|alt|group|block)|(?:verse|code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|alt|group|block)\{)/ \
+          and t_o !~/^```[ ]+(?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block)|^```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$/ # fix logic
             sub_array=t_o.dup
             @line_mode=sub_array.scan(/.+/)
             type=if @@flag[:poem]==:curls or @@flag[:poem]==:tics
@@ -692,8 +753,10 @@ module SiSU_AO_DocumentStructureExtract
         end
         if @@flag[:code]==:off
           if @@flag[:poem]==:curls or @@flag[:poem]==:tics \
+          or @@flag[:box]==:curls or @@flag[:box]==:tics \
           or @@flag[:group]==:curls or @@flag[:group]==:tics \
-          or @@flag[:alt]==:curls or @@flag[:alt]==:tics
+          or @@flag[:alt]==:curls or @@flag[:alt]==:tics \
+          or (@@flag[:quote]==:open and t_o =~/`:quote_close`/m)
             if t_o.is_a?(String)
               t_o=t_o.gsub(/\n/m,"#{Mx[:br_nl]}").
                 gsub(/[ ][ ]/m,"#{Mx[:nbsp]*2}").
@@ -702,6 +765,7 @@ module SiSU_AO_DocumentStructureExtract
             elsif t_o.is==:group \
             || t_o.is==:block \
             || t_o.is==:alt \
+            || t_o.is==:box \
             || t_o.is==:verse
               t_o.obj=t_o.obj.gsub(/\n/m,"#{Mx[:br_nl]}").
                 gsub(/[ ][ ]/m,"#{Mx[:nbsp]*2}").
@@ -758,8 +822,8 @@ module SiSU_AO_DocumentStructureExtract
       lines,lines_new=@data,[]
       lines.each do |line|
         line=if line =~/\S/ \
-        and line !~/^(?:code\{|\}code)/ \
-        and line !~/^(?:```[ ]+code|```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$)/ \
+        and line !~/^(?:code(?:\.[a-z][0-9a-z_]+)?\{|\}code)/ \
+        and line !~/^(?:```[ ]+code(?:\.[a-z][0-9a-z_]+)?|```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*$)/ \
         and not line.is_a?(Hash) #watch
           @@counter+=1 if @@flag[:code]==:curls or @@flag[:code]==:tics
           line=line.gsub(/\s\s/,"#{Mx[:nbsp]*2}").
@@ -1190,6 +1254,7 @@ SKIPPED processing file: [#{@md.opt.lng}] "#{@md.fns}"}
               ocnc+=1
               ocn_sp,parent="c#{ocnc}",node
             elsif dob.is==:group \
+            || dob.is==:box \
             || dob.is==:block \
             || dob.is==:alt \
             || dob.is==:verse
@@ -1237,6 +1302,7 @@ SKIPPED processing file: [#{@md.opt.lng}] "#{@md.fns}"}
         if dob.is==:code \
         || dob.is==:verse \
         || dob.is==:alt \
+        || dob.is==:box \
         || dob.is==:group \
         || dob.is==:block
           dob.obj=dob.obj.gsub(/\n+/,"\n") #newlines taken out
diff --git a/lib/sisu/v5/ao_expand_insertions.rb b/lib/sisu/v5/ao_expand_insertions.rb
index ea499119..f47823b6 100644
--- a/lib/sisu/v5/ao_expand_insertions.rb
+++ b/lib/sisu/v5/ao_expand_insertions.rb
@@ -333,7 +333,7 @@ module SiSU_AO_Insertions
       tuned_file,tuned_file_tmp=[],[]
       codeblock_=false
       data.each do |para|
-        codeblock_=if para =~/^(?:code\{|```[ ]+code)/
+        codeblock_=if para =~/^(?:code(?:\.[a-z][0-9a-z_]+)?\{|```[ ]+code(?:\.[a-z][0-9a-z_]+)?)/
           true
         elsif para =~/^(?:\}code|```(?:\s|$))/m
           false
diff --git a/lib/sisu/v5/ao_misc_arrange.rb b/lib/sisu/v5/ao_misc_arrange.rb
index 419241e1..48b421c6 100644
--- a/lib/sisu/v5/ao_misc_arrange.rb
+++ b/lib/sisu/v5/ao_misc_arrange.rb
@@ -77,14 +77,14 @@ module SiSU_AO_MiscArrangeText
     def markup_blocks(para)
       def ticks(para)
         block_open,block_close,text=nil,nil,nil
-        if para =~/\A```[ ]+(?:code|poem|alt|group|block|table).*?\n.+?\n```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*\Z/m
+        if para =~/\A```[ ]+(?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block|table).*?\n.+?\n```(?:\s+[~-][#]|\s+\~\{.+?\}\~)?\s*\Z/m
           @flag=:close
-          block_open,text,block_close=/\A(```[ ]+(?:code|poem|alt|group|block|table).*?)\n(.+?)\n(```([ ]+[~-][#]|\s+\~\{.+?\}\~)?)\s*\Z/m.match(para)[1..3]
+          block_open,text,block_close=/\A(```[ ]+(?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block|table).*?)\n(.+?)\n(```([ ]+[~-][#]|\s+\~\{.+?\}\~)?)\s*\Z/m.match(para)[1..3]
           ((para=~/^```[ ]+table(?:~h)?\s+/) \
           and (para !~/^```[ ]+table(?:~h)?\s+c\d+/)) \
           ? para
           : (para=[]; para << block_open << text << block_close)
-        elsif para =~/\A```[ ]+(?:code|poem|alt|group|block|table).*?\n.*?\Z/m #look at, study
+        elsif para =~/\A```[ ]+(?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block|table).*?\n.*?\Z/m #look at, study
           @flag=:open
           block_open,text=/\A(```(?:[ ]+.+?))\n(.*?)\Z/m.match(para)[1,2]
           para=[]
@@ -115,22 +115,38 @@ module SiSU_AO_MiscArrangeText
           gsub(/```\s*/m,'').
           strip
       end
+      def ticks_quote(para)
+        @flag=:quote_open
+        text=para
+        para=[]
+        if text =~ /```[ ]+quote/m
+          para << '`:quote_open`'
+          text=text.gsub(/```[ ]+quote/m,'')
+        end
+        text=text.gsub(/(?:\n|\A)([^`=\n]+)/m,'_1 \1') #not a perfect match for book index \n={
+        para << text.gsub(/```/m,'')
+        if text =~/```/m
+          @flag=:quote_close
+          para << '`:quote_close`'
+        end
+        para
+      end
       def curly_braces(para)
         block_open,block_close,text=nil,nil,nil
-        para=if para =~/\A(?:code|poem|alt|group|block|table)\{ .+?\n.+?\n\}(?:code|poem|alt|group|block|table)(?: [~-][#])?\s*\Z/m
-          block_open,text,block_close=/\A((?:code|poem|alt|group|block|table)\{ .+?)\n(.+?)\n(\}(?:code|poem|alt|group|block|table)(?: [~-][#])?)\s*\Z/m.match(para)[1..3]
+        para=if para =~/\A(?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block|table)\{ .+?\n.+?\n\}(?:code|box|poem|alt|group|block|table)(?: [~-][#])?\s*\Z/m
+          block_open,text,block_close=/\A((?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block|table)\{ .+?)\n(.+?)\n(\}(?:code|box|poem|alt|group|block|table)(?: [~-][#])?)\s*\Z/m.match(para)[1..3]
           para=[]
           para << block_open << text << block_close
-        elsif para =~/\A(?:code|poem|alt|group|block|table)\{ .+?\n.+?\Z/m
-          block_open,text=/\A((?:code|poem|alt|group|block|table)\{ .+?)\n(.+?)\Z/m.match(para)[1,2]
+        elsif para =~/\A(?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block|table)\{ .+?\n.+?\Z/m
+          block_open,text=/\A((?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block|table)\{ .+?)\n(.+?)\Z/m.match(para)[1,2]
           para=[]
           if not text.to_s.empty?
             para << block_open << text
           else
             para << block_open
           end
-        elsif para =~/\A.+?\n\}(?:code|poem|alt|group|block|table)(?: [~-][#])?\s*\Z/m
-          text,block_close=/\A(.+?)\n(\}(?:code|poem|alt|group|block|table)(?: [~-][#])?)\s*\Z/m.match(para)[1,2]
+        elsif para =~/\A.+?\n\}(?:code|box|poem|alt|group|block|table)(?: [~-][#])?\s*\Z/m
+          text,block_close=/\A(.+?)\n(\}(?:code|box|poem|alt|group|block|table)(?: [~-][#])?)\s*\Z/m.match(para)[1,2]
           para=[]
           if not text.to_s.empty?
             para << text.to_s << block_close
@@ -141,7 +157,11 @@ module SiSU_AO_MiscArrangeText
         end
         para
       end
-      para=if para =~/\A```[ ]+(?:code|poem|alt|group|block|table).*?\n.*?\Z/m \
+      para=if (para =~/\A```[ ]+quote/m \
+      and @flag !=:open) \
+      or @flag==:quote_open
+        ticks_quote(para)
+      elsif para =~/\A```[ ]+(?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block|table).*?\n.*?\Z/m \
       or @flag==:open
         ticks(para)
       elsif para =~/```/m
@@ -149,9 +169,11 @@ module SiSU_AO_MiscArrangeText
       else
         para
       end
-      para=(para =~/^(?:code|poem|alt|group|block|table)\{|^\}(?:code|poem|alt|group|block|table)/m) \
-      ? curly_braces(para)
-      : para
+      para=if para =~/^(?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|poem|alt|group|block|table)\{|^\}(?:code|box|poem|alt|group|block|table)/m
+        curly_braces(para)
+      else
+        para
+      end
     end
     def prepare_text
       data=@data
diff --git a/lib/sisu/v5/ao_syntax.rb b/lib/sisu/v5/ao_syntax.rb
index a75e2690..619c5ac0 100644
--- a/lib/sisu/v5/ao_syntax.rb
+++ b/lib/sisu/v5/ao_syntax.rb
@@ -91,7 +91,7 @@ module SiSU_AO_Syntax
         { o: Mx[:fa_underscore_o], c: Mx[:fa_underscore_c] }
       else p __LINE__.to_s + '::' + __FILE__
       end
-      @http_m=%r{\{.+?\}https?://\S+|https?:\S+|:\S+|\.\.\/\S+|#\S+|\S+?\.png\b|[*]~\S+|^#{Mx[:meta_o]}.+|#{Mx[:gr_o]}(?:code|block|group|alt|verse)(?:-end)?#{Mx[:gr_c]}|#{Mx[:fa_o]}:br#{Mx[:fa_c]}}
+      @http_m=%r{\{.+?\}https?://\S+|https?:\S+|:\S+|\.\.\/\S+|#\S+|\S+?\.png\b|[*]~\S+|^#{Mx[:meta_o]}.+|#{Mx[:gr_o]}(?:code(?:\.[a-z][0-9a-z_]+)?|box(?:\.[a-z_]+)?|block|group|alt|verse)(?:-end)?#{Mx[:gr_c]}|#{Mx[:fa_o]}:br#{Mx[:fa_c]}}
       @manmkp_ital=emph_italics \
       ? '[i/*]\\{.+?\\}[i/*]'
       : '[i/]\\{.+?\\}[i/]'
@@ -163,6 +163,7 @@ module SiSU_AO_Syntax
         && dob.is !=:heading \
         && dob.is !=:heading_insert \
         && dob.is !=:code \
+        && dob.is !=:layout \
         && dob.is !=:comment
           word=dob.obj.scan(@line_scan_ital)
           word=word.flatten.compact
diff --git a/lib/sisu/v5/shared_metadata.rb b/lib/sisu/v5/shared_metadata.rb
index 4ada2db1..1f21af3f 100644
--- a/lib/sisu/v5/shared_metadata.rb
+++ b/lib/sisu/v5/shared_metadata.rb
@@ -297,6 +297,57 @@ module SiSU_Metadata
       end
       meta
     end
+    def metadata_alt
+      meta=[]
+      if @display_heading
+        @tag,@inf=%{<b><u>Document Metadata</u></b>},''
+        meta << self.meta_para
+      end
+      if defined? @md.title.main \
+      and @md.title.main=~/\S+/
+        @tag='title'
+        @inf=@md.title.main
+        meta << self.meta_para
+      end
+      if defined? @md.title.sub \
+      and @md.title.sub=~/\S+/
+        @tag='subtitle'
+        @inf=@md.title.sub
+        meta << self.meta_para
+      end
+      if defined? @md.creator.author \
+      and @md.creator.author=~/\S+/
+        @tag='author'
+        @inf=@md.creator.author
+        meta << self.meta_para
+      end
+      if defined? @md.creator.translator \
+      and @md.creator.translator=~/\S+/
+        @tag='translator'
+        @inf=@md.creator.translator
+        meta << self.meta_para
+      end
+      if defined? @md.creator.illustrator \
+      and @md.creator.illustrator=~/\S+/
+        @tag='illustrator'
+        @inf=@md.creator.illustrator
+        meta << self.meta_para
+      end
+      if defined? @md.rights.copyright.text \
+      and @md.rights.copyright.text=~/\S+/
+        @tag='copyright'
+        @inf=@md.rights.copyright.text # year & holder
+        @inf=@inf.gsub(/(?:Copyright|\(C\))+\s*/,'')
+        meta << self.meta_para
+      end
+      if defined? @md.rights.license \
+      and @md.rights.license=~/\S+/
+        @tag='license'
+        @inf=@md.rights.license
+        meta << self.meta_para
+      end
+      meta
+    end
     def processing_tags
       def make
         def language
@@ -756,6 +807,21 @@ module SiSU_Metadata
       end
       self
     end
+    def xml_docbook
+      def meta_para
+        inf_xml=char_enc(@inf).utf8
+        inf_xml=char_enc(inf_xml).br
+        <<WOK
+#{Ax[:tab]}<#{@tag}>
+#{Ax[:tab]*2}#{inf_xml}
+#{Ax[:tab]}</#{@tag}>
+WOK
+      end
+      def metadata
+        SiSU_Metadata::Summary.new(@md).metadata_alt
+      end
+      self
+    end
     def xml_sax
       def meta_para
         inf_xml=char_enc(@inf).utf8
diff --git a/lib/sisu/v5/txt_shared.rb b/lib/sisu/v5/txt_shared.rb
index 0b6c1953..2bf633ea 100644
--- a/lib/sisu/v5/txt_shared.rb
+++ b/lib/sisu/v5/txt_shared.rb
@@ -62,8 +62,8 @@
 =end
 module SiSU_TextUtils
   class Wrap
-    def initialize(para='',n_char_max=76,n_indent=0,n_hang=nil)
-      @para,@n_char_max,@n_indent=para,n_char_max,n_indent
+    def initialize(para='',n_char_max=76,n_indent=0,n_hang=nil,post='')
+      @para,@n_char_max,@n_indent,@post,=para,n_char_max,n_indent,post
       @n_char_max_extend = n_char_max
       @n_hang=n_hang ? n_hang : @n_indent
     end
@@ -110,7 +110,10 @@ module SiSU_TextUtils
         end
         @oldword=word if word =~/\S+/
       end
-      spaces_hang + out.join(spaces_indent)
+      post=(@post.empty?) \
+      ? ''
+      : "\n" + (' '*@n_indent) +@post
+      spaces_hang + out.join(spaces_indent) + post
     end
     def line_wrap_indent1
       @n_indent,@n_hang=2,2
diff --git a/lib/sisu/v5/xml_docbook5.rb b/lib/sisu/v5/xml_docbook5.rb
index 98450520..3a59f839 100644
--- a/lib/sisu/v5/xml_docbook5.rb
+++ b/lib/sisu/v5/xml_docbook5.rb
@@ -70,6 +70,7 @@ module SiSU_XML_Docbook_Book
     include SiSU_TextUtils
   require_relative 'xml_shared'                         # xml_shared.rb
     include SiSU_XML_Munge
+  require_relative 'shared_metadata'                    # shared_metadata.rb
   class Source
     def initialize(opt)
       @opt=opt
@@ -135,7 +136,7 @@ module SiSU_XML_Docbook_Book
         def collapsed
           %w[ 0 1 2 3 4 5 ]
         end
-        def docbook(lc,chlv='')
+        def docbook_tag(lc,chlv='')
           case lc
           when 0 then 'book'
           when 1 then lc==chlv ? 'chapter' : 'section'
@@ -162,7 +163,7 @@ module SiSU_XML_Docbook_Book
       end
       def markup_text(data)
         data.each_with_index do |o,i|
-          if o.is ==:heading || o.is ==:para
+          if o.is ==:heading || o.is ==:para || o.is ==:open_close_tags
             o=@trans.markup_docbook(o) #unless o.obj==nil
           end
         end
@@ -189,6 +190,38 @@ module SiSU_XML_Docbook_Book
       end
       #def chapterlevel
       #end
+      def xml_head
+        [
+          '<docinfo>',
+          SiSU_Metadata::Summary.new(@md).xml_docbook.metadata,
+          '</docinfo>'
+        ].flatten
+      end
+      def code_output(o,ocn,filename_docbook)
+        filename_docbook.puts o.obj.gsub(/\n?(?:#{Mx[:br_line]}|#{Mx[:br_nl]})\n?/m,"\n")
+      end
+      def adjust_output(o,ocn,filename_docbook,splv)
+        if o.obj =~/#{Xx[:split]}/
+          outs=o.obj.split(/#{Xx[:split]}/)
+          outs.each do |out|
+            if out =~/<figure id=/m
+              out=out.gsub(/:spaces0:/m,
+                  %{#{spaces*(splv)}#{spaces}}).
+                gsub(/:spaces1:/m,
+                  %{#{spaces*(splv)}#{spaces*2}})
+              filename_docbook.puts out
+              filename_docbook.puts "#{spaces*3}#{ocn}"
+            else
+              unless out.empty?
+                filename_docbook.puts SiSU_TextUtils::Wrap.new(out,80,(splv*2+2),nil).line_wrap
+                filename_docbook.puts "#{spaces*3}#{ocn}"
+              end
+            end
+          end
+        else
+          filename_docbook.puts SiSU_TextUtils::Wrap.new(o.obj,80,(splv*2+2),nil,ocn).line_wrap
+        end
+      end
       def structure_build_collapsed(data)
         #output_file=@md.file.output_path.xml_docbook_book.dir + '/' + @md.file.base_filename.xml_docbook_book
         file=SiSU_Env::FileOp.new(@md)
@@ -197,10 +230,11 @@ module SiSU_XML_Docbook_Book
         @chlv=chlv=0
         doc_position=:head
         filename_docbook.puts head
+        filename_docbook.puts xml_head
         data.each_with_index do |o,i|
           if (defined? o.ocn and not o.ocn.nil?)
             ocn=(@make.build.ocn?) \
-            ? "\n#{Dx[:ocn_o]}#{o.ocn}#{Dx[:ocn_c]}"
+            ? "<!-- o#{o.ocn} -->"
             : ''
             id=%{ id="o#{o.ocn}" }
           else
@@ -217,16 +251,40 @@ module SiSU_XML_Docbook_Book
               doc_position=:body_and_tail
             else
               filename_docbook.puts structure_build_tag_close(o.lc,h)
-              filename_docbook.puts  %{#{spaces*(o.lc)}<#{tags.docbook(o.lc,chlv)}#{tag_id}>
+              filename_docbook.puts  %{#{spaces*(o.lc)}<#{tags.docbook_tag(o.lc,chlv)}#{tag_id}>
 #{spaces*o.lc}<title#{id}>
 }
             end
-            filename_docbook.puts SiSU_TextUtils::Wrap.new(o.obj + ocn,80,(@splv*2+2)).line_wrap
+            adjust_output(o,ocn,filename_docbook,@splv)
             filename_docbook.puts %{#{spaces*o.lc}</title>}
             h=o.lc
-          elsif (o.of ==:para or o.of ==:block)
+          elsif o.of ==:layout \
+          and o.is ==:open_close_tags
+            xml_tag=case o.sym
+            when :quote_open then '<blockquote>'
+            when :quote_close then '</blockquote>'
+            else ''
+            end
+            unless xml_tag.empty?
+              filename_docbook.puts "#{spaces*(@splv)}#{xml_tag}"
+            end
+          elsif o.of ==:block
+            if o.is ==:table
+              filename_docbook.puts SiSU_Tables::TableXMLdocbook.new(o,id).table.obj
+            elsif o.is ==:code
+              filename_docbook.puts "#{spaces*(@splv)}<para#{id}>"
+              filename_docbook.puts "#{spaces*(@splv+1)}<programlisting>"
+              code_output(o,ocn,filename_docbook)
+              filename_docbook.puts "#{spaces*(@splv+1)}</programlisting>"
+              filename_docbook.puts "#{spaces*(@splv)}</para>"
+            else
+              filename_docbook.puts "#{spaces*(@splv)}<para#{id}>"
+              adjust_output(o,ocn,filename_docbook,@splv)
+              filename_docbook.puts "#{spaces*(@splv)}</para>"
+            end
+          elsif o.of ==:para
             filename_docbook.puts "#{spaces*(@splv)}<para#{id}>"
-            filename_docbook.puts SiSU_TextUtils::Wrap.new(o.obj + ocn,80,(@splv*2+2)).line_wrap
+            adjust_output(o,ocn,filename_docbook,@splv)
             filename_docbook.puts "#{spaces*(@splv)}</para>"
           end
         end
@@ -237,40 +295,40 @@ module SiSU_XML_Docbook_Book
         x=[]
         case h
         when 0
-          x << "#{spaces*0}</#{tags.docbook(0)}>"       if (lc <= 0)
+          x << "#{spaces*0}</#{tags.docbook_tag(0)}>"       if (lc <= 0)
         when 1
-          x << "#{spaces*1}</#{tags.docbook(1,@chlv)}>" if (lc <= 1)
-          x << "#{spaces*0}</#{tags.docbook(0)}>"       if (lc <= 0)
+          x << "#{spaces*1}</#{tags.docbook_tag(1,@chlv)}>" if (lc <= 1)
+          x << "#{spaces*0}</#{tags.docbook_tag(0)}>"       if (lc <= 0)
         when 2
-          x << "#{spaces*2}</#{tags.docbook(2,@chlv)}>" if (lc <= 2)
-          x << "#{spaces*1}</#{tags.docbook(1,@chlv)}>" if (lc <= 1)
-          x << "#{spaces*0}</#{tags.docbook(0)}>"       if (lc <= 0)
+          x << "#{spaces*2}</#{tags.docbook_tag(2,@chlv)}>" if (lc <= 2)
+          x << "#{spaces*1}</#{tags.docbook_tag(1,@chlv)}>" if (lc <= 1)
+          x << "#{spaces*0}</#{tags.docbook_tag(0)}>"       if (lc <= 0)
         when 3
-          x << "#{spaces*3}</#{tags.docbook(3,@chlv)}>" if (lc <= 3)
-          x << "#{spaces*2}</#{tags.docbook(2,@chlv)}>" if (lc <= 2)
-          x << "#{spaces*1}</#{tags.docbook(1,@chlv)}>" if (lc <= 1)
-          x << "#{spaces*0}</#{tags.docbook(0)}>"       if (lc <= 0)
+          x << "#{spaces*3}</#{tags.docbook_tag(3,@chlv)}>" if (lc <= 3)
+          x << "#{spaces*2}</#{tags.docbook_tag(2,@chlv)}>" if (lc <= 2)
+          x << "#{spaces*1}</#{tags.docbook_tag(1,@chlv)}>" if (lc <= 1)
+          x << "#{spaces*0}</#{tags.docbook_tag(0)}>"       if (lc <= 0)
         when 4
-          x << "#{spaces*4}</#{tags.docbook(4,@chlv)}>" if (lc <= 4)
-          x << "#{spaces*3}</#{tags.docbook(3,@chlv)}>" if (lc <= 3)
-          x << "#{spaces*2}</#{tags.docbook(2,@chlv)}>" if (lc <= 2)
-          x << "#{spaces*1}</#{tags.docbook(1,@chlv)}>" if (lc <= 1)
-          x << "#{spaces*0}</#{tags.docbook(0)}>"       if (lc <= 0)
+          x << "#{spaces*4}</#{tags.docbook_tag(4,@chlv)}>" if (lc <= 4)
+          x << "#{spaces*3}</#{tags.docbook_tag(3,@chlv)}>" if (lc <= 3)
+          x << "#{spaces*2}</#{tags.docbook_tag(2,@chlv)}>" if (lc <= 2)
+          x << "#{spaces*1}</#{tags.docbook_tag(1,@chlv)}>" if (lc <= 1)
+          x << "#{spaces*0}</#{tags.docbook_tag(0)}>"       if (lc <= 0)
         when 5
-          x << "#{spaces*5}</#{tags.docbook(5)}>"       if (lc <= 5)
-          x << "#{spaces*4}</#{tags.docbook(4,@chlv)}>" if (lc <= 4)
-          x << "#{spaces*5}</#{tags.docbook(3,@chlv)}>" if (lc <= 3)
-          x << "#{spaces*2}</#{tags.docbook(2,@chlv)}>" if (lc <= 2)
-          x << "#{spaces*1}</#{tags.docbook(1,@chlv)}>" if (lc <= 1)
-          x << "#{spaces*0}</#{tags.docbook(0)}>"       if (lc <= 0)
+          x << "#{spaces*5}</#{tags.docbook_tag(5)}>"       if (lc <= 5)
+          x << "#{spaces*4}</#{tags.docbook_tag(4,@chlv)}>" if (lc <= 4)
+          x << "#{spaces*5}</#{tags.docbook_tag(3,@chlv)}>" if (lc <= 3)
+          x << "#{spaces*2}</#{tags.docbook_tag(2,@chlv)}>" if (lc <= 2)
+          x << "#{spaces*1}</#{tags.docbook_tag(1,@chlv)}>" if (lc <= 1)
+          x << "#{spaces*0}</#{tags.docbook_tag(0)}>"       if (lc <= 0)
         when 6
-          x << "#{spaces*6}</#{tags.docbook(6)}>"       if (lc <= 6)
-          x << "#{spaces*5}</#{tags.docbook(5)}>"       if (lc <= 5)
-          x << "#{spaces*4}</#{tags.docbook(4,@chlv)}>" if (lc <= 4)
-          x << "#{spaces*3}</#{tags.docbook(3,@chlv)}>" if (lc <= 3)
-          x << "#{spaces*2}</#{tags.docbook(2,@chlv)}>" if (lc <= 2)
-          x << "#{spaces*1}</#{tags.docbook(1,@chlv)}>" if (lc <= 1)
-          x << "#{spaces*0}</#{tags.docbook(0)}>"       if (lc <= 0)
+          x << "#{spaces*6}</#{tags.docbook_tag(6)}>"       if (lc <= 6)
+          x << "#{spaces*5}</#{tags.docbook_tag(5)}>"       if (lc <= 5)
+          x << "#{spaces*4}</#{tags.docbook_tag(4,@chlv)}>" if (lc <= 4)
+          x << "#{spaces*3}</#{tags.docbook_tag(3,@chlv)}>" if (lc <= 3)
+          x << "#{spaces*2}</#{tags.docbook_tag(2,@chlv)}>" if (lc <= 2)
+          x << "#{spaces*1}</#{tags.docbook_tag(1,@chlv)}>" if (lc <= 1)
+          x << "#{spaces*0}</#{tags.docbook_tag(0)}>"       if (lc <= 0)
         end
         x.join("\n")
       end
diff --git a/lib/sisu/v5/xml_shared.rb b/lib/sisu/v5/xml_shared.rb
index fc972833..f1113495 100644
--- a/lib/sisu/v5/xml_shared.rb
+++ b/lib/sisu/v5/xml_shared.rb
@@ -460,28 +460,33 @@ module SiSU_XML_Munge
       clean(str)
     end
     def markup_docbook(dob='')                                  # work on, initially a copy of fictionbook!
-      dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}(.+?)#{Mx[:en_a_c]}/m,'<footnote>\1</footnote>').
-        gsub(/&/,'&amp;'). #sort
-        gsub(/#{Mx[:mk_o]}#([a-zA-Z]+)#{Mx[:mk_c]}/,'&\1;').
-        gsub(/(^|#{Mx[:gl_c]}|\s)&\s+/,'\1&amp; '). #sort
-        gsub(/#{Mx[:mk_o]}(#[0-9]+)#{Mx[:mk_c]}/,'&\1;')
-      dob.obj=dob.obj.gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/,'<br />') unless dob.is==:table
-      dob.obj=dob.obj.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'<b>\1</b>').
-        gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'<i>\1</i>').
-        gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'<u>\1</u>').
-        gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'<sup>\1</sup>').
-        gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'<sub>\1</sub>').
-        gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'<ins>\1</ins>').
-        gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'<cite>\1</cite>').
-        gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'<del>\1</del>').
-        gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,'<tt>\1</tt>'). # tt, kbd
-        gsub(/#{Mx[:lnk_o]}\s*(\S+?\.(?:png|jpg|gif)).+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)/m,'<image xl:href="../../_sisu/image/\1" />'). #taken unmodified except path from fictionbook
-        gsub(/#{Mx[:url_o]}(.+?)#{Mx[:url_c]}/,"#{Dx[:url_o]}\\1#{Dx[:url_c]}").
-        gsub(/#{Mx[:mk_o]}:name#(\S+?)#{Mx[:mk_c]}/,'<a name="\1"></a>').
-        gsub(/#{Mx[:gl_bullet]}/m,'● '). #&nbsp; not available
-        gsub(/#{Mx[:nbsp]}/,' '). #&nbsp; not available
-        gsub(/<(p|br)>/,'<\1 />')
-      dob.obj=clean(dob.obj)
+      if dob.is !=:code
+        dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}(\d+)\s*(.+?)#{Mx[:en_a_c]}/m,'<footnote><para><!-- fn\1 -->\2</para></footnote>').
+          gsub(/\\\\/,'</para><para>').
+          gsub(/&/,'&amp;'). #sort
+          gsub(/#{Mx[:mk_o]}#([a-zA-Z]+)#{Mx[:mk_c]}/,'&\1;').
+          gsub(/(^|#{Mx[:gl_c]}|\s)&\s+/,'\1&amp; '). #sort
+          gsub(/#{Mx[:mk_o]}(#[0-9]+)#{Mx[:mk_c]}/,'&\1;')
+        dob.obj=dob.obj.gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/,'<br />') unless dob.is==:table
+        dob.obj=dob.obj.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'<b>\1</b>').
+          gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'<i>\1</i>').
+          gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'<u>\1</u>').
+          gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'<sup>\1</sup>').
+          gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'<sub>\1</sub>').
+          gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'<ins>\1</ins>').
+          gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'<cite>\1</cite>').
+          gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'<del>\1</del>').
+          gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,'<tt>\1</tt>'). # tt, kbd
+          gsub(/#{Mx[:lnk_o]}\s*(\S+?\.(?:png|jpg|gif)).+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)/m,
+            %{#{Xx[:split]}:spaces0:<figure id="\\1">\n:spaces1:<title></title>\n:spaces1:<graphic fileref="images/\\1" align="center" width="50%"></graphic>\n:spaces0:</figure>#{Xx[:split]}}).
+          gsub(/#{Mx[:url_o]}(.+?)#{Mx[:url_c]}/,"#{Dx[:url_o]}\\1#{Dx[:url_c]}").
+          gsub(/#{Mx[:mk_o]}:name#(\S+?)#{Mx[:mk_c]}/,'<a name="\1"></a>').
+          gsub(/#{Mx[:gl_bullet]}/m,'● '). #&nbsp; not available
+          gsub(/#{Mx[:nbsp]}/,' '). #&nbsp; not available
+          gsub(/<(p|br)>/,'<\1 />')
+        dob.obj=clean(dob.obj)
+      else # codeblock
+      end
       dob
     end
     def markup_group(dob='')
diff --git a/lib/sisu/v5/xml_tables.rb b/lib/sisu/v5/xml_tables.rb
index 4ae41190..1587afbc 100644
--- a/lib/sisu/v5/xml_tables.rb
+++ b/lib/sisu/v5/xml_tables.rb
@@ -122,6 +122,64 @@ module SiSU_Tables
       @parablock
     end
   end
+  class TableXMLdocbook
+    @@tablehead=0
+    @@tablefoot=[] #watch
+    def initialize(table,id='')
+      @table_obj,@id=table,id
+      @vz=SiSU_Viz::Defaults.new
+    end
+    def spaces
+      Ax[:spaces]
+    end
+    def table
+      table_obj=@table_obj
+      if table_obj.obj !~/^<table\s/m
+        table_obj=table_rows_and_columns_array(table_obj)
+      else p __LINE__; p caller
+      end
+      table_obj
+    end
+    def table_rows_and_columns_array(table_obj) # provides basic (x)html table
+      table_rows,nr=[],0
+      table_obj.obj.split(Mx[:tc_c]).each do |table_row|
+        table_row_with_columns=table_row.split(Mx[:tc_p])
+        trc,nc=[],0
+        table_row_with_columns.each do |c|
+          c=c.gsub(/^(?:~|&nbsp;)$/,''). # tilde / empty cell
+            gsub(/&nbsp;/,' ').
+            gsub(/<:br>/,'<br />')
+          trc <<= if table_obj.head_ and nr==0
+            %{#{spaces*6}<entry>#{c}</entry>\n}
+          else %{#{spaces*6}<entry>#{c}</entry>\n}
+          end
+          nc+=1
+        end
+        trc=(trc.is_a?(Array)) ? trc.flatten.join : trc
+        trc = if table_obj.head_ and nr==0
+          "#{spaces*4}<thead>\n#{spaces*5}<row>\n#{trc}#{spaces*5}</row>\n#{spaces*4}</thead>\n#{spaces*4}<tbody>\n"
+        else
+          "#{spaces*5}<row>\n#{trc}#{spaces*5}</row>\n"
+        end
+        nr+=1
+        table_rows << trc
+      end
+      tbody_close=if table_obj.head_
+        "#{spaces*4}</tbody>"
+      else ''
+      end
+      table_rows=table_rows.flatten.join
+      # include table_id <table id=''>
+      table_obj.obj=%{#{spaces*3}<para #{@id}>
+#{spaces*4}<table>
+#{spaces*4}<tgroup cols="#{table_obj.cols}" align="char">
+#{table_rows}#{tbody_close}
+#{spaces*4}</tgroup>
+#{spaces*4}</table>
+#{spaces*3}</para>}
+      table_obj
+    end
+  end
   class TableXMLexp <Table
     @@tablehead=0
     @@tablefoot=[]
-- 
cgit v1.2.3