User:PerfektesChaos/js/WikiSyntaxTextMod/dX.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/// PerfektesChaos/js/WikiSyntaxTextMod/dX.js
/// 2024-05-11  PerfektesChaos@de.wikipedia
/// Fingerprint: #0#0#
/// @license: CC-by-sa/4.0 GPLv3
/// <nowiki>
// WikiSyntaxTextMod:  Wiki syntax specific code: tags <x>...</x>
/* global mw:true, mediaWiki:false                                     */
/* jshint forin:false,
          bitwise:true, curly:true, eqeqeq:true, latedef:true,
          laxbreak:true,
          nocomma:true, strict:true, undef:true, unused:true           */


if ( typeof mediaWiki  !==  "object" ) {   // disconnected
   mw  =  { libs:   { WikiSyntaxTextMod:  { }
                    },
            log:    function () {"use strict";}
          };
}
( function ( mw ) {
   "use strict";
   var version  =  -7.64,
       sign     =  "WikiSyntaxTextMod",
       sub      =  "X",
       rls, self, WSTM;
   if ( typeof mw.loader  ===  "object" ) {
      rls   =  { };
      self  =  "user:PerfektesChaos/" + sign + "/" + sub;
      rls[ self ] = "loading";
      mw.loader.state( rls );
   }
   if ( typeof mw.libs[ sign ]  !==  "object" ) {   // isolated
      mw.libs[ sign ]  =  { };
   }
   WSTM  =  mw.libs[ sign ];
   if ( typeof WSTM.w  !==  "object" ) {
      WSTM.w  =  { tags: { }  };
   }
   if ( typeof WSTM.w.tags  !==  "object" ) {
      WSTM.w.tags  =  { };
   }
   WSTM.w.tags.vsn   =  version;
   WSTM.w.tags.self  =  self;
   if ( typeof WSTM.bb  !==  "object" ) {
      WSTM.bb  =  { };
   }
   if ( typeof WSTM.debugging  !==  "object" ) {
      WSTM.debugging  =  { };
   }
} ( mw ) );



/*
Requires: JavaScript 1.3
          (String.charCodeAt String.fromCharCode String.replace)
          JavaScript 1.5  RegExp non-capturing parenthese
 */



//-----------------------------------------------------------------------



mw.libs.WikiSyntaxTextMod.bb.bbX  =  function ( WSTM ) {
   // Building block and run environment support
   // 2012-05-18 PerfektesChaos@de.wikipedia
   "use strict";
   if ( typeof WSTM.util  !==  "object" ) {
      WSTM.util  =  { };
   }


   if ( typeof WSTM.util.fiatObjects  !==  "function" ) {
      WSTM.util.fiatObjects  =  function ( adult, activate, assign ) {
         // Ensure existence of at least empty object
         // Precondition:
         //    adult     -- parent object
         //    activate  -- String with name of child object
         //    assign    -- optional object with initial definition
         //                 if containing object components,
         //                 they will be asserted as well
         // Postcondition:
         //    adult has been extended
         // Uses:
         //    .util.fiatObjects()  -- recursive
         // 2012-05-18 PerfektesChaos@de.wikipedia
         var elt,
             obj,
             s;
         if ( typeof adult[ activate ]  !==  "object" ) {
            adult[ activate ]  =  ( assign  ?  assign  :  { } );
         }
         if ( assign ) {
            obj  =  adult[ activate ];
            for ( s in assign ) {
               elt  =  assign[ s ];
               if ( typeof elt  ===  "object" ) {
                  WSTM.util.fiatObjects( obj, s, elt );
               }
            }  //  for s in assign
         }
      };   // .util.fiatObjects()
   }


   WSTM.util.fiatObjects( WSTM,  "debugging",  { loud: false } );

};   // .bb.bbX()
mw.libs.WikiSyntaxTextMod.bb.bbX( mw.libs.WikiSyntaxTextMod );
delete mw.libs.WikiSyntaxTextMod.bb.bbX;



//-----------------------------------------------------------------------



mw.libs.WikiSyntaxTextMod.bb.tags  =  function ( WSTM ) {
   // Analyzing and formatting of tags <x>...</x>
   // Uses:
   //    .util.fiatObjects()
   // 2024-05-11 PerfektesChaos@de.wikipedia
   "use strict";
   WSTM.util.fiatObjects( WSTM,  "w",
                          { tags:  { }  }
                        );
   if ( typeof WSTM.w.reWhitespaceMult  !==  "object" ) {
      WSTM.w.reWhitespaceMult  =  new RegExp( "\\s+", "g" );
   }


   WSTM.w.tags.elt  =  { banned:     "a|applet|area|audio"
                                     + "|base|body|button"
                                     + "|command|embed"
                                     + "|form|frame|frameset"
                                     + "|head|html"
                                     + "|iframe|img|input|isindex"
                                     + "|layer|link|map|meta"
                                     + "|object|option"
                                     + "|script|select|style"
                                     + "|textarea|title"
                                     + "|xml",
                         binary:     "blockquote|center|chem|code|dfn"
                                     + "|gallery|graph"
                                     + "|h1|h2|h3|h4|h5|h6"
                                     + "|hiddentext|hiero"
                                     + "|imagemap|includeonly|inputbox"
                                     + "|kbd|li|mapframe|math|noinclude"
                                     + "|ol|onlyinclude|p|poem|pre"
                                     + "|ruby|rb|rbc|rp|rt|rtc"
                                     + "|s|samp|score|strike"
                                     + "|templatedata|ul",
                         blockEnd:   "gallery|graph|imagemap|inputbox"
                                     + "|mapframe|ol|pre"
                                     + "|references|templatedata|ul",
                         codeBlock:  "pre",
                         codeData:   "chem|graph|hiero|imagemap|inputbox"
                                     + "|mapframe|maplink|math|poem"
                                     + "|score"
                                     + "|templatedata"
                                     + "|timeline",
                         codedFix:   "syntaxhighlight|source",
                         codedOpt:   "mapframe",
                         codeInline: "code|dfn|kbd|maplink|poem|samp",
                         comment:    "hiddentext",
                         direct:     "bdi|br|ref|hiddentext"
                                     + "|ruby|rb|rbc|rp|rt|rtc",
                         enclose:    "b|big|center|dfn|em|i"
                                     + "|s|samp|span|strike|strong"
                                     + "|u|var",
                         marker:     "gallery"
                                     + "|imagemap"
                                     + "|includeonly|onlyinclude"
                                     + "|ref|references",
                         obsolet:    + "b|big|blockquote|center|dfn|em"
                                     + "|font|hiddentext|i|samp|strike"
                                     + "|strong|var",
                         parNone:    "graph|hiddentext"
                                     + "|imagemap|includeonly|inputbox"
                                     + "|noinclude|nowiki|onlyinclude"
                                     + "|rb|rbc|rp|rt|rtc"
                                     + "|timeline",
                         parWith:    "bdi|br|code|dfn|div|gallery|hiero"
                                     + "|kbd|mapframe|math|p|poem|pre"
                                     + "|ref|references|ruby"
                                     + "|samp|section|small|source"
                                     + "|span|strike|sub|sup"
                                     + "|syntaxhighlight|tt",
                         unary:      "br|hr|templatestyles|wbr"
                       };   // 2024-05-11
   WSTM.w.tags.pars  =  { gallery:         "caption=|class=|heights="
                                           + "|id=|mode=|perrow="
                                           + "|showfilename|style="
                                           + "|widths=",
                          math:            "display=|chem",
                          ref:             "!|name=|group=",
                          references:      "group="
                                           + "|responsive=|responsive",
                          syntaxhighlight: "class=|enclose=|highlight="
                                           + "|inline|id="
                                           + "|lang=|line=|line"
                                           + "|pre|start=|style=|title="
                        };   // 2023-12-05



   WSTM.w.tags.fade  =  function ( about, assign ) {
      // Update HTML attribute as CSS style
      // Precondition:
      //    about   -- string with HTML attribute name
      //    assign  -- string with old value, trimmed
      // Postcondition:
      //    Returns string with CSS code
      // Uses:
      //    this
      //    >< .html2css
      //    >< .reHashStart
      //    >< .reHex
      //    >< .reDigits
      // 2019-09-07 PerfektesChaos@de.wikipedia
      var r  =  assign;
      if ( typeof this.html2css  !==  "object" ) {
         this.html2css  =  { align:   "text-align",
                             bgcolor: "background",
                             color:   "color",
                             valign:  "vertical-align",
                             width:   "width" };
      }
      switch ( about ) {
         case "bgcolor":
            if ( typeof WSTM.w.encountered.sortable  ===  "boolean" ) {
               this.html2css.bgcolor  =  "background-color";
            }   // fall through
         case "color":
            if ( typeof this.reHashStart  !==  "object" ) {
               this.reHashStart  =  new RegExp( "^#" );
               this.reHex        =  new RegExp( "^[0-9A-Fa-f]+$" );
            }
            if ( ! this.reHashStart.test(r)
                 &&   ( r.length === 3  ||  r.length === 6 )
                 &&   this.reHex.test( r ) ) {
               r  =  "#" + r.toUpperCase();
            }
            break;
         case "width":
            if ( typeof this.reDigits  !==  "object" ) {
               this.reDigits  =  new RegExp( "^[0-9]+$" );
            }
            if ( this.reDigits.test(r) ) {
               r  =  r + "px";
            }
            break;
         default:
            r  =  r.toLowerCase();
      }   // switch about
      r  =  this.html2css[ about ]  +  ":"  +  r;
      return  r;
   };   // .w.tags.fade()



   WSTM.w.tags.fair  =  function (adjust, around) {
      // Analyze and polish class="" declaration
      // 2015-10-15 PerfektesChaos@de.wikipedia
      // Precondition:
      //    adjust  -- class list content, normalized by space separation
      //    around  -- true: <tag>  false: table
      // Postcondition:
      //    Returns modified string, even empty
      // Uses:
      //    this
      //    >  .w.tags.reClassComma
      //    >< .w.tags.reClassDiscard
      //    >< .w.reWhitespaceMult
      //     < .mod.lazy
      //    .hooks.fire()
      //    .str.trim()
      //    .errors.found()
      // 2019-09-07 PerfektesChaos@de.wikipedia
      var r  =  adjust,
          discard, s;
      if ( r ) {
         if ( r.indexOf( "," )  >=  0 ) {
            r              =  r.replace( this.reClassComma,  " " );
            WSTM.mod.lazy  =  false;
         }
         discard  =  WSTM.hooks.fire( "class_discard" );
         if ( discard ) {
            if ( typeof this.reClassDiscard  !==  "object" ) {
               this.reClassDiscard  =  new RegExp( " (" + discard + ") ",
                                                   "g" );
            }
            r  =  " " + r + " ";
            s  =  r.replace( this.reClassDiscard, " " );
            if ( s !== r ) {
               r  =  s.replace( this.reClassDiscard, " " );
            }
         }
         r  =  WSTM.str.trim( r.replace( WSTM.w.reWhitespaceMult,
                                         " " ) );
      } else {
         WSTM.errors.found( ( around ? "tag" : "table" )
                            + "AttrValueEmpty",
                            false,
                            "class=\"\"" );
      }
      return  r;
   };   // .w.tags.fair()



   WSTM.w.tags.feature  =  function (arglist,access,adjust,assign,alone){
      // Retrieve particular tag parameter value, and/or set value
      // Precondition:
      //    arglist  -- tag object
      //                >< .props
      //    access   -- attribute name
      //    adjust   -- true: downcase value
      //    assign   -- true: remove attribute,  string: set value
      //    alone    -- true: set unary
      // Postcondition:
      //    Returns attribute value (string or true for unary),
      //    or false if not available yet
      // 2015-12-20 PerfektesChaos@de.wikipedia
      var r  =  false,
          e  =  arglist.props,
          i  =  0,
          n  =  0,
          p;
      if ( e ) {
         n  =  e.length;
         for ( i = 0;  i < n;  i++ ) {
            p  =  e[ i ];
            if ( p[ 1 ] === access ) {
               r  =  p[ 3 ];
               if ( ! r ) {
                  r  =  p[ 2 ];
                  if ( adjust && r ) {
                     r  =  r.toLowerCase();
                  }
               }
               if ( assign  ||  assign === "" ) {
                  if ( typeof assign  ===  "string" ) {
                     p[2]  =  assign;
                  } else if ( n === 1  &&  ! i ) {
                     arglist.props  =  false;
                  } else {
                     arglist.props.splice( i, 1 );
                  }
               }
               i  =  -1;
               break;   // for i
            }
         }   // for i
      }
      if ( typeof assign  === "string"   &&   i === n ) {
         p  =  [ " ",  access,  assign,  ( alone ? true : false ) ];
         if ( n ) {
            arglist.props.push(p);
         } else {
            arglist.props  =  [ p ];
         }
      }
      return  r;
   };   // .w.tags.feature()



   WSTM.w.tags.features  =  function ( assign, about ) {
      // Parse tag parameters
      // Precondition:
      //    assign  -- non-empty string with attr=val assignments
      //    about   -- tag name
      // Postcondition:
      //    Returns false, if not a valid tag, or Array
      //       Every element is an Array(3)
      //          [0] leading whitespace (standardized)
      //          [1] keyword
      //          [2] value (string content),  or false (sole)
      //          [3] true: unary
      //          or false
      // Uses:
      //    >  .w.tags.reTagAttrL
      //    >  .w.tags.reTagAttrQ
      //    >  .w.tags.reTagAttrX
      //    >  .w.tags.reTagAttrS
      //    >  .w.tags.reTagAttrE
      //    >  .w.tags.attrUnary
      //    >  .w.tags.reTagAttrT
      //    >  .w.tags.reTagAttrU
      //    >  .w.tags.reTagAttr1
      //     < .mod.lazy
      //    .str.isLetter()
      //    .errors.found()
      //    .str.trim()
      //    .str.trimR()
      //    .w.tags.fade()
      //    .str.substrEnd()
      //    .w.tags.fair()
      //    .w.css.fashion()
      // 2020-05-15 PerfektesChaos@de.wikipedia
      var got       =  true,
          letter    =  WSTM.str.isLetter( about ),
          r         =  false,
          stitch    =  "|class|style|",
          stoneage  =  "|bgcolor|color|valign|",
          sub       =  " " + assign,
          vals      =  { },
          i, leap, lone, p, seek, set, show, sign, spc;
      while ( got ) {
         sign  =  false;
         got   =  this.reTagAttrL.exec( "\f" + sub + "\f" );
         if ( got ) {
            set       =  false;
            got[ 0 ]  =  got[ 1 ] + got[ 2 ];
         } else {
            got   =  this.reTagAttrQ.exec( sub );
            if ( got ) {
               if ( got[ 3 ] ) {
                  set  =  got[ 3 ];
               } else {
                  set  =  got[ 4 ];
               }
               if ( typeof set  === "string" ) {
                  set  =  WSTM.str.trim( set, true );
               } else {
                  set  =  "";
               }
               if (! set.length) {
                  WSTM.errors.found( ( letter ? "tag" : "table" )
                                     + "AttrValueEmpty",
                                     false,
                                     ( letter ? "<" : "" )
                                     + about + " " + got[2] + "=\"\""
                                     + ( letter ? ">" : "" ) );
                  set  =  "???????";
               }
            } else {
               got  =  this.reTagAttrX.exec( sub );
               if ( got ) {
                  if ( got[ 3 ] ) {
                     set  =  got[ 3 ];
                  } else if (got[ 4 ]) {
                     set  =  got[ 4 ];
                  } else {
                     set  =  got[ 5 ];
                  }
                  WSTM.mod.lazy  =  false;
                  if ( got[ 6 ] ) {
                     got[ 0 ]  =  WSTM.str.trimR( got[ 0 ], true );
                  }
               } else {
                  set  =  false;
                  got  =  this.reTagAttrS.exec( sub + "/" );
                  if ( got ) {
                     sign  =  sub;
                     got   =  this.reTagAttrE.exec( sub );
                     if ( got ) {
                        sign  =  got[ 1 ];
                        if ( sign  === "responsive"  &&
                             about === "references" ) {
                           got  =  false;
                           sub  =  sign;
                        }
                     }
                     if ( got ) {
                        WSTM.errors.found( ( letter ? "tag" : "table" )
                                           + "AttrValueEmpty",
                                           false,
                                           ( letter ? "<" : "" )
                                           + about + " " + sign + "="
                                           + ( letter ? ">" : "" ) );
                        got  =  false;
                     } else {
                        if ( typeof this.attrUnary[ about ]
                                                        ===  "string" ) {
                           set  =  this.attrUnary[ about ];
                           got  =  this.reTagAttrT.exec( sub + " " );
                           if ( got ) {
                              sign  =  got[ 1 ].toLowerCase();
                              if ( set.indexOf("|" + sign + "|" )
                                                                >=  0 ) {
                                 got  = [ " ", sign, "", true ];
                                 set  =  "";
                                 sub  =  "";
                              } else {
                                 got  =  false;
                              }
                           }
                        }
                        if ( ! got ) {
                           WSTM.errors.found( ( letter ? "tag"
                                                       : "table" )
                                              + "AttrInvalid",
                                              false,
                                              ( letter ? "<" : "" )
                                              + about + " " + assign );
                        }
                     }
                     if ( ! got ) {
                        spc  =  " ";
                        set  =  "???";
                        sub  =  " ";
                     }
                  } else {
                     got  =  this.reTagAttrU.exec( sub + "/" );
                     if ( got ) {
                        WSTM.errors.found( ( letter ? "tag" : "table" )
                                           + "AttrInvalid",
                                           false,
                                           ( letter ? "<" : "" )
                                           + about + " " + assign );
                        set  =  sub;
                     } else {
                        spc   =  " ";
                        sign  =  sub;
                        if ( ! this.reTagAttr1.test( sign ) ) {
                           WSTM.errors.found( ( letter ? "tag"
                                                       : "table" )
                                              + "AttrInvalid",
                                              false,
                                              ( letter ? "<" : "" )
                                              + about + " " + sign );
                           got  =  false;
                        }
                     }
                  }
               }
            }
         }
         if ( got ) {
            spc  =  got[ 1 ];
            p    =  spc.indexOf( "\n" );
            if ( p < 0 ) {
               spc  =  " ";
            } else {
               spc  =  spc.substr( p );
            }
            if ( got[ 2 ] ) {
               sign  =  got[ 2 ].toLowerCase();
               sign  =  WSTM.str.trim( sign, true );
            }
            if ( set ) {
               set  =  WSTM.str.trim( set, true );
            }
            lone  =  got[ 3 ];
            seek  =  "|" + sign + "|";
            if ( stoneage.indexOf( seek )  >=  0 ) {
               set   =  this.fade( sign, set );
               sign  =  "style";
            }
            seek  =  "|" + sign + "|";
            sub   =  sub.substr( got[ 0 ].length );
            if ( typeof vals[ sign ]  !==  "string" ) {
               vals[ sign ]  =  set;
            } else if ( vals[ sign ] === set ) {
               sign  =  "";
            } else {
               show  =  ( letter ? "tag" : "table" )  +  "AttrRepeated";
               leap  =  false;
               got   =  ( letter ? "<" : "" )  +  about  +  " "
                        +  assign.substr( 0,
                                          assign.length - sub.length );
               if ( stitch.indexOf( seek )  >=  0 ) {
                  for ( i = 0;  i < r.length;  i++ ) {
                     p  =  r[ i ];
                     if ( p[ 1 ]  ===  sign ) {
                        WSTM.mod.lazy  =  false;
                        if ( sign === "style"   &&
                            WSTM.str.substrEnd( p[ 2 ], 1 )  !==  ";" ) {
                           p[ 2 ]  =  p[ 2 ] + ";";
                        }
                        set     =  p[ 2 ] + " " + set;
                        r[ i ]  =  [ spc, sign, set ];
                        leap    =  true;
                        break;
                     }
                  }   // for i
               }
               sign  =  "";
               if ( ! leap ) {
                  WSTM.errors.found( show, false, got );
               }
            }
         }
         if ( sign.length ) {
            p  =  [ spc, sign, set, lone ];
            if ( r ) {
               r.push( p );
            } else {
               r  =  [ p ];
            }
         }
      }   // while got
      sub  =  WSTM.str.trim( sub, true );
      if ( sub.length ) {
         WSTM.errors.found( ( letter ? "tag" : "table" )
                            + "AttrInvalid",
                            false,
                            ( letter ? "<" : "" )
                            +  about + " " + assign );
      }
      if ( r ) {
         for ( i = r.length - 1;  i >= 0;  i-- ) {
            p  =  r[ i ];
            switch ( p[ 1 ] ) {
               case "class":
                  if ( p[ 2 ] ) {
                     p[ 2 ]  =  this.fair( p[ 2 ],  letter );
                     if ( ! p[ 2 ] ) {
                        r.splice( i, 1 );
                     }
                  } else {
                     WSTM.errors.found( ( letter ? "tag" : "table" )
                                        + "AttrInvalid",
                                        false,
                                        p[ 1 ] + "=??? in: " + assign );
                  }
                  break;
               case "style":
                  if ( p[ 2 ] ) {
                     set  =  WSTM.w.css.fashion( p[ 2 ], about );
                     if ( set ) {
                        p[ 2 ]           =  set;
                        WSTM.mod.lazy  =  false;
                     }
                  } else {
                     WSTM.errors.found( ( letter ? "tag" : "table" )
                                        + "AttrInvalid",
                                        false,
                                        p[ 1 ] + "=??? in: " + assign );
                  }
                  break;
            }   // switch p[1]
         }   // for i--
      }
      return  r;
   };   // .w.tags.features()



   WSTM.w.tags.fence  =  function ( all, arglist ) {
      // Isolate fixed tag range
      // Precondition:
      //    all      -- WikiTom to be analyzed and subdivided (root)
      //    arglist  -- tag information provided by .tags.fetch()
      //                >  .scope
      //                >  .node
      //                >  .limited
      //                >< .join
      //                >< .move
      //                 < .lookup
      //                 < .lone
      // Postcondition:
      //    Returns true, if found,  or false
      // Uses:
      //    >  .w.chr.whitespace
      //    >< .w.tags.reEndTags
      //    .o.WikiTom().find()
      //    .o.WikiTom().fetch()
      //    .o.WikiTom().flip()
      //    .errors.found()
      // 2012-08-02 PerfektesChaos@de.wikipedia
      var lag  =  false,
          lbb  =  false,
          lbe  =  false,
          leb  =  false,
          lee  =  false,
          re   =  this.reEndTags[ arglist.scope ],
          i,
          j,
          k,
          m,
          n,
          r,
          s;
      if ( ! re ) {
         re  =  "[" + WSTM.w.chr.whitespace + "]*";
         re  =  "(<" + re + "[/\\\\]" + re + arglist.scope + re + ">)" +
                "(\n|<!--)?";
         re  =  new RegExp(re, "i");
         this.reEndTags[ arglist.scope ]  =  re;
      }
      r  =  all.find( [ re, 1 ],
                      arglist.join + arglist.move,
                      arglist.node,
                      true,
                      false );
      if ( r ) {
         j  =  arglist.join;
         m  =  0;
         i  =  r.i;
         n  =  r.r[ 1 ].length;
         k  =  i - j - arglist.move - 1;
         s  =  "";
         if ( arglist.limited ) {
            j  =  ( j  ?  j - 1  :  0 );
            m  =  j - arglist.join + arglist.move + 3;
            s  =  all.fetch(arglist.node, j, false);
            k  =  i - j;
            s  =  s.substr(0, k);
            if ( arglist.scope === "source" ) {
               lag  =  ( s.toLowerCase().indexOf( "syntaxhighlight" )
                                                                   <  0);
               if ( lag ) {
                  arglist.scope  =  "syntaxhighlight";
               }
            }
            if ( arglist.join ) {
               lbb  =  ( s.charCodeAt( 0 ) !== 10 );
               lbe  =  ( s.charCodeAt( m + 1 )  !==  10 );
            }
            leb  =  ( s.charCodeAt( s.length - 1 )  !==  10 );
            lee  =  ( typeof r.r[2]  !==  "string" );
            if ( lbb || lbe ) {
               n  +=  k;
               i   =  j;
               if ( lbe ) {
                  s   =  s.substr( 0,  m + 1 )   +  "\n"
                         +   s.substr( m + 1 );
                  k++;
               }
               if ( lbb ) {
                  s  =  s.substr( 0, 1 )  +  "\n"  +  s.substr( 1 );
                  arglist.join++;
               }
            } else {
               s  =  "";
            }
            if ( leb ) {
               s  =  s + "\n";
               k++;
            }
         }
         if ( k === 1 ) {
            arglist.lone  =  true;
            i--;
            n++;
            s  =  " />";
         } else {
            s              =  s + "</" + arglist.scope + ">";
            arglist.move  +=  arglist.scope.length + 1;
         }
         arglist.move  +=  k - m + 3;
         if ( lee ) {
            s  =  s + "\n";
         }
         arglist.lookup   =  false;
         if ( s  !==  r.r[ 1 ] ) {
            all.flip( arglist.node, i, n, s );
         }
         if ( lag ) {
            all.flip( arglist.node,
                      arglist.join + 1,
                      6,
                      arglist.scope );
         }
         r  =  true;
      } else {
         s  =  all.fetch( arglist.node, arglist.join, false );
         WSTM.errors.found( "tagEndMissing",
                            false,
                            s.substr( 0, 50 ) );
      }
      return  r;
   };   // .w.tags.fence()



   WSTM.w.tags.fetch  =  function (arglist) {
      // Detect and format tag
      // Precondition:
      //    arglist  -- tag object
      //                >< .leader  heading slash present
      //                             <  may be removed
      //                >< .move    number of characters processed
      //                             <  progress
      //                >< .scope   lowercase tag name
      //                >< .source  found text after '<'
      //                             <  limited to '>'
      //                >< .scan    search key (|scope|)
      //                 < .lone    unary
      //                 < .n       length of found tag, with '<' and '>'
      //                            0  if failed; then no more info
      //                 < .props   Array with attributes, or false
      //                 < .shift   re-formatted tag after <, if changed;
      //                            or false
      //                   .leave   neutral (span div)
      //                   .limited single line
      // Postcondition:
      //    Returns false, if seriously failed, or updated arglist
      // Uses:
      //    >  .w.chr.detected.tab
      //    >  .w.tags.reTagEnd
      //    >  .w.tags.single
      //    >  .w.tags.sole
      //    >  .w.tags.pars
      //    >  .w.tags.suckNowiki
      //    .errors.found()
      //    .w.chr.fixTab()
      //    .str.trim()
      //    .w.tags.features()
      //    .w.tags.focus()
      //    .w.tags.format()
      // 2013-04-30 PerfektesChaos@de.wikipedia
      var lucky  =  false,
          got,
          i,
          m,
          n,
          sub;
      arglist.n  =  arglist.source.indexOf( ">", arglist.move )  +  1;
      if ( arglist.n ) {
         lucky           =  true;
         arglist.props   =  false;
         m               =  arglist.n - 1;
         arglist.source  =  arglist.source.substr( 0, m );
         i               =  arglist.source.indexOf( "<", arglist.move );
         n               =  arglist.source.indexOf( "\n\n",
                                                    arglist.move );
         if ( n > arglist.move ) {
            n  =  ( n > 100  ?  100  :  n );
            WSTM.errors.found("tagFormBroken",
                              false,
                              "<"  +  arglist.source.substr(0, n));
            arglist.move  =  ( i > arglist.move  ?  i - 1  :  m );
            lucky         =  false;
         } else if ( i > arglist.move ) {
            arglist.move  =  i - 1;
            i             =  ( i > 100  ?  100  :  i );
            WSTM.errors.found( "tagFormReOpen",
                               false,
                               "<"  +  arglist.source.substr( 0, i ) );
            lucky  =  false;
         } else {
            sub           =  arglist.source.substr( arglist.move );
            arglist.move  =  m;
         }
         if ( lucky ) {
            got  =  this.reTagEnd.exec( sub );
            n    =  sub.length;
            if ( got ) {
               arglist.lone   =  true;
               n             -=  got[1].length;
               sub            =  sub.substr(0, n);
            } else {
               arglist.lone   =  false;
            }
            if ( this.sole.indexOf( arglist.scan )  >=  0 ) {
               arglist.leader  =  false;
               arglist.lone    =  true;
            }
            if ( n ) {
               if ( WSTM.w.chr.detected.tab ) {
                  got  =  WSTM.w.chr.fixTab( sub );
                  if (got) {
                     sub  =  got;
                  }
               }
               got  =  WSTM.str.trim( sub, true, true );
               n    =  got.length;
            }
            if (n) {
               got  =  this.features( sub, arglist.scope );
               if (got) {
                  if (this.single.indexOf(arglist.scan) >= 0) {
                     WSTM.errors.found( "tagAttrUnexpected",
                                        false,
                                        "<"  +
                                        arglist.source.substr( 0,
                                                               200 ) );
                     arglist.n  =  0;
                  }
                  if (arglist.leader) {
                     arglist.source  =  arglist.source.substr(0, 200);
                     WSTM.errors.found( "tagEndAttr",
                                        false,
                                        "<" + arglist.source + ">" );
                     arglist.n  =  0;
                  }
                  if ( arglist.n ) {
                     this.focus( got, arglist );
                  }
               }
            }
         }
         if ( lucky && arglist.n ) {
            if ( arglist.leader && arglist.lone ) {
               WSTM.errors.found( "tooManySlashes",
                                  false,
                                  "<"
                                    +  arglist.source.substr( 0, 100 ) );
               arglist.n  =  0;
            }
            if ( arglist.n ) {
               if ( arglist.lone  &&  ! arglist.props ) {
                  got  =  this.pars[ arglist.scope ];
                  if (got) {
                     got  =  "|" + got;
                     if ( got.indexOf( "|!|" )  >=  0 ) {
                        WSTM.errors.found( "tagUnaryNoAttr",
                                           false,
                                           "<" + arglist.scope + " />" );
                     }
                  }
                  if ( this.suckNowiki.indexOf( arglist.scan )  >=  0 ) {
                     arglist.scope  =  "nowiki";
                     arglist.scan   =  "|nowiki|";
                     arglist.move   =  arglist.source.length;
                  }
               }
               if ( arglist.scope === "strike" ) {
                  arglist.scope  =  "s";
               }
               sub            =  this.format( arglist );
               arglist.shift  =  (sub === arglist.source  ?  false
                                                          :  sub);
            }
         }
      } else {
         WSTM.errors.found("tagFormNoEnd",
                           false,
                           "<"  +  arglist.source.substr(0, 100));
      }
      return  (arglist.n > 0  ?  arglist  :  false);
   };   // .w.tags.fetch()



   WSTM.w.tags.fire  =  function ( all ) {
      // Start tag soup stirring: subdivision of tags and tagged elements
      // Precondition:
      //    all  -- WikiTom to be analyzed and subdivided (root)
      //             < .children
      //             < .shift
      // Postcondition:
      //    all  has been subdivided, if necessary
      // Uses:
      //    >  .w.chr.whitespace
      //    >  .w.tags.elt
      //    >  .w.tags.elt.banned
      //    >  .w.tags.elt.blockEnd
      //    >  .w.tags.elt.codeBlock
      //    >  .w.tags.elt.codeData
      //    >  .w.tags.elt.codedFix
      //    >  .w.tags.elt.codeInline
      //    >  .w.tags.elt.codedOpt
      //    >  .w.tags.elt.comment
      //    >  .w.tags.elt.direct
      //    >  .w.tags.elt.marker
      //    >  .w.tags.elt.parNone
      //    >  .w.tags.elt.unary
      //    >  .w.tags.elt.enclose
      //    >  .warn.attribute
      //    >  .warn.property
      //    >  .warn.tag
      //    >  .w.chr.detected.tab
      //     < .w.tags.attrUnary
      //     < .w.tags.blocks
      //     < .w.tags.pending
      //     < .w.tags.reClassComma
      //     < .w.tags.reCommentBeg
      //     < .w.tags.reEndTags
      //     < .w.tags.reTagAttr1
      //     < .w.tags.reTagAttrE
      //     < .w.tags.reTagAttrQ
      //     < .w.tags.reTagAttrS
      //     < .w.tags.reTagAttrT
      //     < .w.tags.reTagAttrU
      //     < .w.tags.reTagAttrX
      //     < .w.tags.reTagBeg
      //     < .w.tags.reTagEnd
      //     < .w.tags.sealed
      //     < .w.tags.setter
      //     < .w.tags.single
      //     < .w.tags.slice
      //     < .w.tags.sole
      //     < .w.tags.sources
      //     < .w.tags.stack
      //     < .w.tags.stop
      //     < .w.tags.storing
      //     < .w.tags.suckNowiki
      //     < .w.tags.suitable
      //     < .w.tags.supply
      //     < .w.tags.setting
      //     < .w.tags.say
      //    .o.WikiTom().find()
      //    .str.uniques()
      //    .util.regexp.fiat()
      //    .errors.found()
      //    .o.WikiTom().fetch()
      //    .o.WikiTom().flip()
      //    .o.WikiTom().fresh()
      //    .o.WikiTom().frame()
      //    .w.tags.fold()
      //    .w.tags.frame()
      //    .o.WikiTom().fixTab()
      // Requires: JavaScript 1.3   fromCharCode()
      // 2024-05-11 PerfektesChaos@de.wikipedia
      var got   =  all.find("<", 0, 0, true, false),
          open  =  [ ],
          s     =  "([" + WSTM.w.chr.whitespace + "]+)?",
          sat   =  "([-a-z_A-Z:0-9]+)",
          sqd   =  String.fromCharCode(34,8220,8221,8222),
          sqs   =  String.fromCharCode(39,8216,8217,8218),
          j, k, tag;
      this.attrUnary     =  { gallery:         "|showfilename|",
                              math:            "|chem|",
                              references:      "|responsive|",
                              source:          "|inline|line|pre|",
                              syntaxhighlight: "|inline|line|pre|" };
      this.blocks        =  false;
      this.pending       =  { };
      this.reClassComma  =  new RegExp("[, ]+", "g");
      this.reCommentBeg  =  new RegExp("^" + s + "!--");
      this.reEndTags     =  { };
      this.reTagAttr1    =  new RegExp("^[a-z_A-Z:0-9 \n]*$");
      this.reTagAttrE    =  new RegExp("\\b([^ =\n]+)[ \n]*=[ \n]*$");
      this.reTagAttrL    =  new RegExp("\f( *\n *| +)"
                                         + sat
                                         + "(?:" //?:
                                            + "(?: +| *\n *)" //?:
                                            + "[^= \n]"
                                            + "(?:.|\n)*" //?:
                                         + ")\f");
      this.reTagAttrQ    =  new RegExp("^" + "( *\n *| +)"
                                           + sat
                                           + " *\n? *= *\n? *"
                                           + "(?:'([^'\n]*)'"
                                             + "|\"([^\"\n]*)\""
                                           + ")");
      this.reTagAttrS    =  new RegExp("^" + "( *\n *| +)"
                                           + sat
                                           + "(?: *\n? *"
                                              + "([^= ]"
                                                 + "(?:.|\n)*))$");
      this.reTagAttrT    =  new RegExp("^ *([a-zA-Z]+) ");
      this.reTagAttrU    =  new RegExp("^" + "( *\n *| +)"
                                           + "([a-z_A-Z:0-9]+)"
                                           + "(?: *\n? *= *)"
                                              + "((.|\n)*)$");
      this.reTagAttrX    =  new RegExp("^" + "( *\n *| +)"
                                           + sat
                                           + " *\n? *= *\n? *"
                                           + "(?:[" + sqs + "]" +
                                             "([^" + sqs + "]*)" +
                                             "[" + sqs + "]"
                                           + "|[" + sqd + "]" +
                                             "([^" + sqd + "]*)" +
                                             "[" + sqd + "]"
                                           + "|([^ \n]+)"
                                            + "( +|$)"
                                           + ")");
      this.reTagBeg      =  new RegExp("^" + "("
                                              + s
                                              + "([/\\\\]?)"
                                              + s
                                              + "([a-zA-Z]+[1-6]?))"
                                              + "["
                                                  + WSTM.w.chr.whitespace
                                                  + "/\\.>\n<]");
      this.reTagEnd      =  new RegExp("(" + s + "[/\\\\]" + s + ")$");
      this.scream        =  "|" + this.elt.banned + "|";
      this.sealed        =  "|" + this.elt.codeBlock +
                            "|" + this.elt.codeData +
                            "|" + this.elt.codedFix +
                            "|" + this.elt.codeInline +
                            "|" + this.elt.comment + "|";
      this.setter        =  "|div|span|";
      this.shallow       =  "|" + this.elt.codedOpt + "|";
      this.single        =  "|" + this.elt.parNone + "|";
      this.slice         =  "|" + this.elt.marker + "|";
      this.sole          =  "|" + this.elt.unary + "|";
      this.sources       =  "|" + this.elt.codedFix + "|";
      this.spacing       =  "|" + this.elt.direct + "|";
      this.stack         =  "|" + this.elt.blockEnd +
                            "|" + this.elt.codeInline + "|ref|";
      this.stop          =  "|" + this.elt.blockEnd +
                            "|" + this.elt.codeBlock + "|";
      this.storing       =  "|" + this.elt.binary + "|";
      this.suckNowiki    =  "|" + this.elt.enclose + "|";
      if (! this.suitable) {
         this.suitable  =  "";
         for (s in this.elt) {
            this.suitable  =  this.suitable + "|" + this.elt[s];
         }   // for s in elt
         this.suitable  =  "|"
                           +  WSTM.str.uniques(this.suitable, "|")
                           +  "|";
      }
      if ( WSTM.warn ) {
         if ( WSTM.warn.attribute ) {
            k  =  WSTM.warn.attribute.length;
            if ( k ) {
               this.supply  =  "|";
               for ( j = 0;  j < k;  j++ ) {
                  tag  =  WSTM.warn.attribute[ j ];
                  if ( tag
                       &&   typeof tag  ===  "object"
                       &&   tag.length === 2
                       &&   typeof tag[ 0 ]  ===  "string" ) {
                     if ( typeof tag[ 1 ]  ===  "string" ) {
                        tag[ 0 ]     =  tag[ 0 ].toLowerCase();
                        this.supply  =  this.supply + tag[ 0 ] + "|";
                        tag[ 1 ]     =  WSTM.util.regexp.fiat( tag[ 1 ],
                                                 false,
                                                 ".config.warn.attribute"
                                                 + "[" + j + "][1]" );
                     }
                  } else {
                     WSTM.errors.found( "Invalid",
                                        false,
                                        ".config.warn.attribute"
                                        + "[" + j + "]" );
                  }
               }   // for j
            }
         }
         if ( WSTM.warn.property ) {
            k = WSTM.warn.property.length;
            if ( k ) {
               this.setting  =  "|";
               for ( j = 0;  j < k;  j++ ) {
                  this.setting  =  this.setting
                                   + WSTM.warn.property[ j ] + "|";
               }   // for j
               this.setting  =  this.setting.toLowerCase();
            }
         }
         if (WSTM.warn.tag) {
            k = WSTM.warn.tag.length;
            if (k) {
               this.say  =  "|";
               for (j = 0;  j < k;  j++) {
                  this.say  =  this.say + WSTM.warn.tag[j] + "|";
               }   // for j
               this.say  =  this.say.toLowerCase();
            }
         }
      }
      while (got) {
         j  =  got.i + 1;
         k  =  got.k;
         s  =  all.fetch(k, j, false);
         if (s) {
            tag  =  this.fold(s);
            if (tag) {
               if (tag.shift) {
                  all.flip(k, j, tag.move, tag.shift);
                  tag.move   =  tag.shift.length;
                  tag.shift  =  false;
                  all.fresh(false);
               } else if (! tag.move  ||  isNaN(tag.move)) {
                  tag.move  =  0;
               }
               tag.join  =  got.i;
               tag.node  =  k;
               if (tag.scope) {
                  this.frame(all, tag, open);
               } else if (! tag.move) {
                  tag.move  =  1;
               }
               j  =  tag.join + tag.move;
               k  =  tag.node;
            }
         }
         got  =  all.find("<", j, k, true, false);
      }   // while got
      if (open.length) {
         WSTM.errors.found("tagEndMissingFinal",
                           false,
                           "</"  +  open[open.length - 1].scope  +  ">");
      } else if (WSTM.w.chr.detected.tab) {
         if (all.children) {
            for (j = 0;  j < all.children.length;  j++) {
               all.children[j].fixTab(all.children[j]);
            }   // for j
         } else {
            all.fixTab(all);
         }
      }
   };   // .w.tags.fire()



   WSTM.w.tags.fix  =  function ( arglist ) {
      // Improve tag, e.g. BR clear or DIV
      // Precondition:
      //    arglist  -- tag object
      //                >  .scan
      //                >  .scope
      //                >  .lone
      //                >  .props
      //                >  .source
      //                 < .limited
      //                 < .shift
      // Postcondition:
      //    Returns true, if to be folded as limited, or false
      // Uses:
      //    >  .w.tags.setter
      //    .w.tags.feature()
      //    .w.css.fashion()
      //    .w.tags.format()
      //    >< .w.tags.reClear
      // 2020-05-15 PerfektesChaos@de.wikipedia
      var r      =  false,
          lone,
          s,
          style;
      if ( arglist.props   &&
           ( arglist.scope === "br"  ||
             arglist.scope === "div" ) ) {
         s  =  this.feature( arglist, "clear", true );
         if ( s ) {
            lone  =  true;
            this.feature( arglist, "clear", true, true );
            style  =  this.feature( arglist, "style", true );
            if ( style ) {
               if ( typeof this.reClear  !==  "object" ) {
                  this.reClear  =  new RegExp( "; *clear *: *[a-z]+ *;",
                                               "i" );
               }
               if ( this.reClear.test( ";" + style + ";" ) ) {
                  style  =  "clear:" + s + ";" + style;
               }
            } else {
               style  =  "clear:" + s;
            }
            style  =  WSTM.w.css.fashion( style, arglist.scope )
                      ||  style;
            this.feature( arglist, "style", false, style );
            r  =  true;
         } else if ( this.feature( arglist, "style", true ) ) {
            lone  =  true;
         }
         if ( lone  &&  arglist.scope === "br" ) {
            arglist.scope    =  "div";
            arglist.limited  =  true;
            arglist.lone     =  true;
            arglist.scan     =  "|div|";
            r                =  true;
         }
      }
      if ( this.setter.indexOf( arglist.scan )  >=  0
           &&   arglist.lone
           &&   arglist.props ) {
         s  =  this.format( arglist );
         if ( s   &&
              arglist.source.substr( 0, 1 )  !==  "/" ) {
            s  =  s.substr( 0,  s.length - 2 )
                  +   "></" + arglist.scope;
            r  =  true;
         }
         if ( r ) {
            arglist.lone   =  false;
            arglist.shift  =  ( s === arglist.source  ?  false  :  s );
         }
      }
      return  r;
   };   // .w.tags.fix()



   WSTM.w.tags.flow  =  function (all, arglist) {
      // Format tag embedding into content environment
      // Precondition:
      //    all      -- WikiTom to be analyzed and subdivided (root)
      //    arglist  -- tag object of flowing tag
      //                >  .node
      //                >  .scope
      //                >  .move
      //                >< .mode
      //                >< .join
      // Postcondition:
      //    tag object and WikiTom updated
      // Uses:
      //    >  .w.tags.pending.references
      //    >  .o.WikiTom.TagBegin
      //    >  .o.WikiTom.TagEnd
      //    .o.WikiTom().focus()
      //    .str.isBlank()
      //    .w.tags.flip()
      //    .w.tags.free()
      // 2015-01-01 PerfektesChaos@de.wikipedia
      var later    =  false,
          liaison  =  true,
          lonely   =  false,
          c,
          i,
          j,
          s;
      if ( arglist.lone ) {
         later  =  ( arglist.scope === "br" );
      } else {
         later  =  ( arglist.mode === WSTM.o.WikiTom.TagEnd );
         if (arglist.scope === "ref") {
            liaison  =  ( ! this.pending.references );
            lonely   =  ( ! liaison );
         }
      }
      if ( liaison ) {
         if ( arglist.mode === WSTM.o.WikiTom.TagBegin ) {
            i  =  arglist.join + arglist.move;
            s  =  all.fetch( arglist.node, i, false );
            for ( j = 0;  j < s.length;  j++ ) {
               c  =  s.charCodeAt(j);
               if ( !  WSTM.str.isWhiteBlank( c, false, false ) ) {
                  break;   // for j
               }
            }   //   for j
            if ( j ) {
               all.flip( arglist.node, i, j, "" );
            }
         } else if ( later && arglist.join ) {
            i  =  arglist.join - 1;
            j  =  i;
            do {
               c  =  all.fetch( arglist.node, i, true );
               if ( WSTM.str.isWhiteBlank( c, false, false ) ) {
                  i--;
               } else {
                  break;   // while
               }
            } while ( i >= 0 );   // do
            if ( i < j ) {
               all.flip( arglist.node,  i + 1,  j - i,  "" );
               arglist.join  -=  j - i;
            }
         }
      }
      if ( lonely ) {
         this.free( all, arglist );
      }
   };   // .w.tags.flow()



   WSTM.w.tags.flush  =  function (attributes, arglist) {
      // Format attributes
      // Precondition:
      //    attributes  -- Array with attributes
      //    arglist     -- tag description, or false
      //                       < .n
      // Postcondition:
      //    Returns formatted attribute list
      // Uses:
      //    >  .w.tags.setting
      //    >  .w.tags.supply
      //    >  .warn.attribute
      //    .errors.found()
      //    .warn.found()
      // 2015-10-16 PerfektesChaos@de.wikipedia
      var r  =  "",
          e, i, j, p, v, w;
      for (i = 0;  i < attributes.length;  i++) {
         p  =  attributes[i];
         r  =  r + p[0] + p[1];
         if (p[2]) {
            p  =  p[2];
            if (p.indexOf("\"") < 0) {
               r  =  r + "=\"" + p + "\"";
            } else if (p.indexOf("'") < 0) {
               r  =  r + "='" + p + "'";
            } else {
               WSTM.errors.found("tagAttrQuote", false, r);
               if (arglist) {
                  arglist.n  =  0;
               }
            }
         }
      }   // for i
      if (this.setting || this.supply) {
         for (i = 0;  i < attributes.length;  i++) {
            p  =  attributes[i];
            e  =  p[1];
            if (this.setting) {
               if (this.setting.indexOf("|" + e + "|")  >  0) {
                  WSTM.warn.found("property",  e + "=");
               }
            }
            if (this.supply) {
               v  =  p[2];
               if (v  &&  this.supply.indexOf(e) > 0) {
                  for (j = 0;  j < WSTM.warn.attribute.length;  j++) {
                     w  =  WSTM.warn.attribute[j];
                     if (e === w[0]) {
                        if (w[1].test(v)) {
                           WSTM.warn.found("attribute",  e + "=" + v);
                        }
                     }
                  }   // for j
               }
            }
         }   // for i
      }
      return  r;
   };   // .w.tags.flush()



   WSTM.w.tags.focus  =  function (apply, arglist) {
      // Analyse tag parameters; submit error message if unknown
      // Precondition:
      //    apply    -- Array with attributes
      //                Every element is an Array(3)
      //                   [0] leading whitespace (standardized)
      //                   [1] keyword
      //                   [2] value (string content)
      //                   or false
      //    arglist  -- tag object
      //                >  .scope
      //                 < .props
      // Postcondition:
      //    Array .props has been assigned
      // Uses:
      //    .errors.found()
      //    >  .w.tags.pars
      //    .str.trim()
      // 2015-11-09 PerfektesChaos@de.wikipedia
      var support  =  this.pars[ arglist.scope ],
          i, lone, p, s;
      if (support) {
         support  =  "|" + support + "|";
         for (i = 0;  i < apply.length;  i++) {
            p  =  apply[i];
            p[1]  =  WSTM.str.trim(p[1]);
            if (p[1]) {
               lone  =  (! p[2]  ||  p[2] === "???");
               s     =  "|"  +  p[1]  +  (lone ? "|" : "=|");
               if (support.indexOf(s) < 0) {
                  WSTM.errors.found("tagAttrUnknown",
                                    false,
                                    "<" + arglist.scope + " " + p[1]
                                    + (p[2] ? "=...>" : ">"));
               } else if (lone) {
                  apply[i][2]  =  false;
               }
            } else {
               if (! p[2]   &&   i  ===  apply.length - 1) {
                  apply.pop();
               } else {
                  WSTM.errors.found("tagAttrUnknown",
                                    false,
                                    "<" + arglist.scope + " "
                                    + (p[2] ? "=...>" : "=>"));
               }
            }
         }   // for i
      }
      arglist.props  =  apply;
   };   // .w.tags.focus()



   WSTM.w.tags.fold  =  function (adjust) {
      // Detect and format tag
      // Precondition:
      //    adjust  -- string beginning after '<'
      // Postcondition:
      //    Returns false, if not a valid tag, or object
      //       .join    0, or -1 to jump before '<'
      //       .leader  end tag
      //       .lone    unary tag
      //       .mode    type of tag (comment)
      //       .move    number of characters to move forward in source
      //                if tag: length of got tag including '<' until '>'
      //       .props   Array with attributes, or false
      //       .shift   re-formatted tag after '<', if changed;  or false
      //       .scope   standardized keyword
      // Uses:
      //    >  .w.tags.reCommentBeg
      //    >  .o.WikiTom.Comment
      //    >  .warn.comment
      //    >  .w.tags.replComment
      //    >  .o.WikiTom.TextOnly
      //    >  .w.tags.reTagBeg
      //    >  .w.tags.suitable
      //    >  .o.WikiTom.Tag
      //    >< .w.tags.reCommentVsn
      //    .errors.found()
      //    .hooks.fire()
      //    .warn.found()
      //    .str.substrEnd()
      //    .w.tags.fetch()
      // 2015-11-13 PerfektesChaos@de.wikipedia
      var got    =  this.reCommentBeg.exec( adjust ),
          r      =  false,
          j,
          n,
          s,
          seek,
          swift;
      if ( got ) {
         if ( got[ 1 ] ) {
            j  =  got[ 1 ].length;
            n  =  adjust.indexOf( "-->",  j + 3 );
            if ( n < 0 ) {
               r  =  { join: 0,
                       mode:  WSTM.o.WikiTom.Comment,
                       move:  n + 4,
                       shift: adjust.substr( j,  n + 4 - j ) };
               WSTM.errors.found( "tagCommentBegin",
                                  true,
                                  "<"  +  r.shift.substr( 0, 50 ) );
            }
         } else {
            r  =  { join:  0,
                    mode:  WSTM.o.WikiTom.Comment,
                    scan:  "-- --",
                    scope: "-- --" };
            n  =  adjust.indexOf("-->", 3);
            if ( n > 0 ) {
               s       =  adjust.substr( 3,  n - 3 );
               r.move  =  n + 4;
               swift   =  WSTM.hooks.fire( "comment", s );
               if ( swift ) {
                  if ( typeof swift  ===  "string" ) {
                     r.shift  =  "!--" + swift + "-->";
                     n        =  swift.length + 3;
                  } else {
                     r.shift  =  "";
                     r.join   =  -1;
                     r.mode   =  0;
                     n        =  0;
                  }
                  r.move--;
               }
               if ( n ) {
                  if ( WSTM.warn.comment ) {
                     for ( j = 0;  j < WSTM.warn.comment.length;  j++ ) {
                        if ( s.indexOf( WSTM.warn.comment[ j ] )
                                                                >=  0 ) {
                           WSTM.warn.found( "comment",
                                            "&lt;!--" + s + "--&gt;" );
                           break;   // for j
                        }
                     }   // for j
                  }
                  if ( this.replComment ) {
                     swift  =  "<!--" + s + "-->";
                     for ( j = 0;  j < this.replComment.length;  j++ ) {
                        swift  =  swift.replace( this.replComment[j][0],
                                                 this.replComment[j][1]
                                               );
                     }   // for j
                     if ( swift  !==  "<!--" + s + "-->" ) {
                        r.mode  =  WSTM.o.WikiTom.TextOnly;
                        if ( swift.substr(0, 4)  ===  "<!--" ) {
                           if ( WSTM.str.substrEnd( swift, 3 )
                                ===  "-->" ) {
   //                      if (swift.slice(-3) === "-->") {
                              r.mode   =  WSTM.o.WikiTom.Comment;
                              r.shift  =  swift.substr( 1 );
                              r.move--;
                           }
                        }
                        if ( r.mode === WSTM.o.WikiTom.TextOnly ) {
                           // discard comment
                           r.join   =  -1;
                           r.shift  =  swift;
                        }
                     }
                  }
               }
            } else {
               r.move  =  adjust.length + 1;
               WSTM.errors.found( "tagCommentNoEnd",
                                  false,
                                  "<"  +  adjust.substr( 0, 50 ) );
            }
         }
      } else {
         got  =  this.reTagBeg.exec( adjust );
         if ( got ) {
            s     =  got[ 5 ].toLowerCase();
            seek  =  "|" + s + "|";
            if ( this.suitable.indexOf( seek )  >=  0 ) {
               r  =  { leader:  false,
                       move:    got[ 1 ].length,
                       scan:    seek,
                       scope:   s,
                       source:  adjust };
               if ( typeof got[ 3 ]  ===  "string" ) {
                  if ( got[ 3 ].length ) {   // IE save
                     r.leader  =  true;
                  }
               }
               r  =  this.fetch( r );
               if ( ! r ) {
                  r  =  { move: got.move };
               }
            }
         }
      }
      return  r;
   };   // .w.tags.fold()



   WSTM.w.tags.format  =  function (arglist) {
      // Format tag
      // Precondition:
      //    arglist  -- tag object
      //                >  .leader  heading slash present
      //                >  .scope   lowercase tag name
      //                >  .props   Array with attributes, or false
      //                >  .lone    unary tag
      //                 < .n       0 if failed
      // Postcondition:
      //    Returns formatted tag content with exception of '<' and '>'
      // Uses:
      //    .str.trim()
      //    .w.tags.flush()
      // 2012-08-02 PerfektesChaos@de.wikipedia
      var r  =  (arglist.leader ? "/" : "")  +  arglist.scope;
      if (arglist.scope !== WSTM.str.trim(arglist.scope, true)) {
         mw.log(WSTM.debugging,
                ".w.tags.format()    <" + arglist.scope + ">",
                1);
      }
      if (arglist.props) {
         r  =  r + WSTM.w.tags.flush(arglist.props, arglist);
      }
      if (arglist.lone) {
         r  =  r + " /";
         // 2012-08-14     .move
      }
      return  r;
   };   // .w.tags.format()



   WSTM.w.tags.frame  =  function ( all, arglist, ago ) {
      // Isolate tag range and handle specific content formatting
      // Precondition:
      //    all      -- WikiTom to be analyzed and subdivided (root)
      //                 < .mode
      //    arglist  -- tag information provided by .tags.fetch()
      //                >  .scan
      //                >  .scope
      //                >  .stop
      //                >  .props
      //                >  .leader
      //                >  .source
      //                >< .mode
      //                >< .join
      //                >< .lone
      //                >< .node
      //                >< .move
      //                 < .limited
      //                 < .lookup
      //                 < .leave
      //    ago      -- Array with pending opening tags
      //                >< may pop or push
      // Postcondition:
      //    all  has been subdivided or merged, if necessary
      // Uses:
      //    >  .w.tags.say
      //    >  .w.tags.stop
      //    >  .o.WikiTom.Comment
      //    >  .o.WikiTom.TextOnly
      //    >  .o.WikiTom.Nowiki
      //    >  .o.WikiTom.CodedBlock
      //    >  .o.WikiTom.Code
      //    >  .o.WikiTom.CodedInline
      //    >  .o.WikiTom.TagEnd
      //    >  .o.WikiTom.TagBegin
      //    >  .o.WikiTom.TagBinary
      //    >  .w.tags.sealed
      //    >  .w.tags.shallow
      //    >  .w.tags.sources
      //    >  .w.tags.stack
      //    >  .w.tags.shift
      //    >  .w.tags.spacing
      //    >  .w.tags.slice
      //    >  .w.tags.setter
      //    >< .w.tags.pending.*
      //     < .w.encountered.include
      //    .warn.found()
      //    .w.tags.future()
      //    .w.tags.friend()
      //    .w.tags.fence()
      //    .errors.found()
      //    .o.WikiTom().flip()
      //    .w.tags.free()
      //    .w.tags.furnished()
      //    .w.tags.fix()
      //    .w.elem.refgroups
      //    .o.WikiTom().fetch()
      //    .str.trim()
      //    .o.WikiTom().flow()
      //    .o.WikiTom().folder()
      //    .o.WikiTom().fork()
      // 2024-05-11 PerfektesChaos@de.wikipedia
      var l       =  false,
          lapsus  =  false,
          link    =  false,
          m       =  0,
          p       =  false;
      if ( this.say  &&
           this.say.indexOf(arglist.scan) >= 0  &&
           ! arglist.leader ) {
         WSTM.warn.found( "tag",  "&lt;" + arglist.scope + ">" );
      }
      arglist.lookup   =  true;
      arglist.limited  =  ( this.stop.indexOf( arglist.scan )  >=  0 );
      if ( arglist.mode === WSTM.o.WikiTom.Comment ) {
         arglist.lookup  =  false;
         arglist.lone    =  true;
         l  =  true;
      } else if ( arglist.mode === WSTM.o.WikiTom.TextOnly ) {
         void( 0 );
      } else if ( arglist.scope === "nowiki" ) {
         l  =  arglist.lone;
         if ( l ) {
            arglist.mode    =  WSTM.o.WikiTom.Nowiki;
            arglist.move    =  10;
            arglist.lookup  =  false;
         } else {
            l  =  this.fence(all, arglist);
            if ( l ) {
               arglist.mode  =  WSTM.o.WikiTom.Nowiki;
               if ( arglist.props ) {
                  WSTM.errors.found( "tagAttrUnexpected",
                                     false,
                                     "<" + arglist.tags.format() + ">" );
               }
            }
         }
      } else if ( this.sealed.indexOf( arglist.scan )  >=  0 ) {
         if ( arglist.lone ) {
            m  =  0;
            if ( this.shallow.indexOf( arglist.scan )  <  0 ) {
               WSTM.errors.found( "tagUnaryIllegal",
                                  false,
                                  "<" + arglist.scope + " />" );
            }
         } else {
            if ( this.sources.indexOf( arglist.scan )  >=  0 ) {
               m  =  WSTM.o.WikiTom.CodedBlock;
            } else {
               m  =  WSTM.o.WikiTom.Code;
            }
         }
         if ( m  &&  arglist.leader ) {
            p  =  all.fetch( arglist.node,
                             arglist.join + arglist.move + 2,
                             false );
            p  =  WSTM.str.trim( p, true, true );
            if ( ! p.length ) {
               p  =  ( arglist.join > 50  ?  arglist.join - 50
                                          :  0 );
               p  =  all.fetch( arglist.node, p, false );
               p  =  "... " + WSTM.str.trim( p );
            }
            p  =  p.substr(0, 50);
            WSTM.errors.found( "tagEndHeading",
                               false,
                               "</" + arglist.scope + "> " + p );
            lapsus  =  true;
         } else if ( m ) {
            if ( m === WSTM.o.WikiTom.CodedBlock ) {
               if ( arglist.props ) {
                  if ( this.feature( arglist, "lang", false, false ) ) {
                     l  =  false;
                     p  =  this.feature( arglist,
                                         "enclose",
                                         true,
                                         false );
                     if ( p === "none" ) {
                        m  =  WSTM.o.WikiTom.CodedInline;
                        l  =  true;
                        this.feature( arglist,
                                      "enclose",
                                      false,
                                      true );
                        this.feature( arglist,
                                      "inline",
                                      false,
                                      "",
                                      true );
                     } else {
                        if ( p ) {
                           this.feature( arglist,
                                         "enclose",
                                         false,
                                         true );
                           l  =  true;
                        }
                        p  =  this.feature( arglist, "inline" );
                        if (p) {
                           m  =  WSTM.o.WikiTom.CodedInline;
                        } else {
                           arglist.limited  =  true;
                        }
                        p  =  true;
                     }
                     if ( l ) {
                        arglist.shift  =  arglist.scope
                                          + this.flush( arglist.props,
                                                        arglist );
                        all.flip( arglist.node,  arglist.join + 1,
                                  arglist.move,  arglist.shift );
                        arglist.move  =  arglist.shift.length;
                     }
                  }
               }
               if ( ! p ) {
                  WSTM.errors.found("tagAttrMissing",
                                    false,
                                    "<" + arglist.scope + " lang=????>");
               }
            }
            l  =  this.fence( all, arglist );
            if ( l ) {
               arglist.mode  =  m;
            }
         }
      } else if ( this.scream.indexOf( arglist.scan )  >=  0 ) {
         WSTM.errors.found( "tagForbidden",
                            true,
                            "<" + arglist.scope + ">" );
         if ( arglist.join ) {
            all.flip( arglist.node, arglist.join, 1, "&lt;" );
         }
      } else if ( ! arglist.lone ) {
         if ( this.slice.indexOf( arglist.scan )  >=  0 ) {
            if ( arglist.leader ) {
               this.pending[ arglist.scope ]  =  false;
            } else if ( this.pending[ arglist.scope ] ) {
               WSTM.errors.found( "tagNestingSelf",
                                  false,
                                  "<" + arglist.scope + ">" );
            } else {
               this.pending[ arglist.scope ]  =  true;
            }
         }
         if ( arglist.leader ) {
            p  =  ago.length;
            if ( p ) {
               p  =  ago[ p - 1 ];
               if ( p.scope === arglist.scope ) {
                  if ( this.friend( all, p, arglist ) ) {
                     if ( this.pending[ arglist.scope ] ) {
                        this.pending[ arglist.scope ]  =  false;
                     }
                  } else if ( p.leave ) {
                     if ( arglist.node >= p.node ) {
                        all.flip( arglist.node,
                                  arglist.join,
                                  arglist.scope.length + 3,
                                  "" );
                     }
                     all.flip( p.node,
                               p.join,
                               arglist.scope.length + 2,
                               "" );
                     arglist.move  -=  2 * arglist.scope.length + 5;
                     arglist.scope  =  false;
                  }
                  m  =  p.node;
                  ago.pop();
/*
               } else if (this.setter.indexOf(arglist.scan) >= 0) {
                  // TODO: remove pair with insides, if p.leave
                  // Not in cx translation tool.
*/
               } else if ( p.scope ) {
                  WSTM.errors.found( "tagNesting",
                                     false,
                                     "<" + p.scope + ">..." +
                                     "</" + arglist.scope + ">" );
                  lapsus  =  true;
               }
            } else {
               p  =  all.fetch( arglist.node,
                                arglist.join + arglist.move + 2,
                                false );
               p  =  WSTM.str.trim( p, true, true );
               if ( ! p.length ) {
                  p  =  (arglist.join > 50  ?  arglist.join - 50  :  0);
                  p  =  all.fetch(arglist.node, p, false);
                  p  =  "... " + WSTM.str.trim( p );
               }
               p  =  p.substr( 0, 50 );
               WSTM.errors.found( "tagEndHeading",
                                  false,
                                  "</" + arglist.scope + "> " + p );
               lapsus  =  true;
            }
         } else {
            arglist.leave  = ( this.setter.indexOf( arglist.scan )  >=  0
                               &&  ! arglist.props );
            ago.push( arglist );
            if ( this.stack.indexOf( arglist.scan )  >=  0 ) {
               this.future( arglist.scope, true );
            }
         }
      }
      if ( arglist.lone  ||  ! arglist.leader ) {
         if ( ( arglist.scope === "br"  &&  arglist.props )   ||
              arglist.scope === "div"   ||
              arglist.scope === "span" ) {
            if ( this.fix( arglist ) ) {
               if ( arglist.shift ) {
                  all.flip( arglist.node,  arglist.join + 1,
                            arglist.move,  arglist.shift );
                  arglist.move  =  arglist.shift.length;
               }
               l  =  arglist.limited;
            }
         }
         if ( arglist.lone ) {
            if ( this.pending[ arglist.scope ] ) {
               WSTM.errors.found( "tagNestingSelf",
                                  false,
                                  "<" + arglist.scope + ">" );
            }
         }
      }
      if ( ! l ) {
         arglist.move  +=  2;
      }
      if ( arglist.limited ) {
         this.free( all, arglist );
         if ( arglist.scope === "references" ) {
            if ( !  ( arglist.lone || arglist.leader ) ) {
               WSTM.w.elem.refgroups( arglist );
               link  =  ( ! lapsus );
            }
         }
      }
      if ( ! arglist.lone ) {
         if ( this.slice.indexOf( arglist.scan )  >=  0 ) {
            if ( ! lapsus ) {
               arglist.mode  =  ( arglist.leader
                                             ? WSTM.o.WikiTom.TagEnd
                                             : WSTM.o.WikiTom.TagBegin );
               l             =  ( arglist.scope !== "ref" );
            }
         }
      }
      if ( this.spacing.indexOf( arglist.scan )  >=  0 ) {
         this.flow( all, arglist );
      }
      if ( l ) {
         p  =  all.folder( arglist.join,
                           arglist.node,
                           arglist.join + arglist.move,
                           arglist.node );
         if ( p ) {
            p.mode     =  arglist.mode;
            p.limited  =  arglist.limited;
            p.lookup   =  arglist.lookup;
            if ( arglist.join ) {
               arglist.node++;
               arglist.join  =  0;
               m++;
            }
            if ( link ) {
               p  =  { };
               for ( link in arglist ) {
                  p[ link ]  =  arglist[ link ];
               }   // for link in arglist
               ago[ ago.length - 1 ]  =  p;
            }
            if ( arglist.mode === WSTM.o.WikiTom.TagEnd ) {
               m  =  ( m ? --m : 0 );
               l  =  ( arglist.scope === "includeonly"  ||
                       arglist.scope === "onlyinclude" );
               if ( l ) {
                  WSTM.w.encountered.include  =  true;
               }
               all.fork( m,
                         arglist.node,
                         arglist.scope,
                         WSTM.o.WikiTom.TagBinary,
                         l );
               arglist.node  =  m;
            }
            arglist.node++;
            arglist.move  =  0;
         }
      }
   };   // .w.tags.frame()



   WSTM.w.tags.free  =  function (all, arglist) {
      // Place tag on a single line
      // Precondition:
      //    all      -- WikiTom to be analyzed and isolated (root)
      //    arglist  -- tag information provided by .tags.fetch()
      //                >  .node
      //                >< .move
      //                >< .join
      // Uses:
      //    .o.WikiTom().fetch()
      //    .str.isBlank()
      //    .o.WikiTom().flip()
      // 2012-05-10 Perfekteschaos@de.wikipedia
      var late  =  false,
          lead  =  false,
          j     =  (arglist.join > 0  ?  arglist.join - 1  :  0),
          s     =  all.fetch(arglist.node, j, false),
          k,
          m,
          n;
      if (j) {
         lead  =  (s.charCodeAt(0) !== 10);
      }
      m  =  s.indexOf(">");
      if (m > 0) {
         s  =  s.substr(0,  m + 5);
         n  =  s.length;
         if (n > m) {
            m++;
            if (m > n) {
               k  =  s.charCodeAt(m);
               if (k === 60) {   // '<'
                  late  =  (s.substr(m, 3)  !==  "!--");
               } else if (k !== 10) {
                  late  =  true;
               }
            }
         }
      }
      if (lead || late) {
         if (late) {
            s             =  s.substr(0, m)  +  "\n";
            arglist.move  =  m + 1;
         }
         if (lead) {
            s  =  s.substr(0, 1)  +  "\n"  +  s.substr(1, arglist.move);
            arglist.join++;
            if (WSTM.str.isBlank(s.charCodeAt(0), false)) {
               s  =  s.substr(1);
               arglist.join--;
               n  =  j;
               while (n) {
                  k  =  all.fetch(arglist.node,  n - 1,  true);
                  if (WSTM.str.isBlank(k, false)) {
                     arglist.join--;
                     n--;
                  } else {
                     break;   // while
                  }
               }   // while
            }
         }
         all.flip(arglist.node,  j,  arglist.move + 1,  s);
      }
   };   // .w.tags.free()



   WSTM.w.tags.friend  =  function ( all, ancestor, arglist ) {
      // Merge possible pair of tags into one unary tag <x></x>
      // Precondition:
      //    all       -- root WikiTom to be manipulated
      //    ancestor  -- begin tag object; merged with arglist if unary
      //                 >  .join
      //                 >  .node
      //                  < .leader
      //                  < .lone
      //                  < .move
      //    arglist   -- tag object of end
      //                 >< .join
      //                 >< .move
      //                 >< .scan
      //                 >< .scope
      // Postcondition:
      //    Returns true, if strings have been merged, or false
      // Uses:
      //    >  .w.tags.storing
      //    >  .w.tags.setter
      //    >  .w.tags.scan
      //    >  .w.tags.props
      //    .o.WikiTom().fetch()
      //    .str.trim()
      //    .errors.found()
      //    .w.tags.format()
      // 2020-10-11 PerfektesChaos@de.wikipedia
      var r  =  false,
          j  =  arglist.join,
          m  =  -1,
          k,
          s;
      if ( ancestor.node === arglist.node ) {
         j  -=  ancestor.join;
         s   =  all.fetch( ancestor.node, ancestor.join, false );
         m   =  j - ancestor.move;
         if ( m > 0 ) {
            if ( s.charCodeAt( 0 ) === 60 ) {   // '<'
               k  =  s.indexOf( ">" );
            } else {
               k  =  0;
            }
            s  =  s.substr( k + 1,  m );
         }
      } else if ( arglist.node  ===  ancestor.node + 1 ) {
         m  =  arglist.join;
         s  =  all.fetch( arglist.node, m, false );
      }
      if ( m > 0 ) {
         s  =  WSTM.str.trim( s, true, true, true );
         m  =  s.length;
      }
      if ( ! m ) {
         s  =  this.storing + this.setter;
         if ( s.indexOf( arglist.scan )  <  0   &&
              ancestor.source ) {
            s  =  all.fetch( ancestor.node, ancestor.join, false );
            m  =  s.indexOf( ">" );
            s  =  all.fetch( arglist.node, arglist.join, false );
            k  =  s.indexOf( ">" );
            r  =  ( m > 0  &&  k > 0 );
            if ( r ) {
               ancestor.lone    =  true;
               ancestor.leader  =  false;
               ancestor.source  =  this.format( ancestor );
               ancestor.n       =  ancestor.source.length;
               ancestor.mode    =  WSTM.o.WikiTom.TagUnary;
               ancestor.move    =  0;
               if ( arglist.node > ancestor.node ) {
                  all.flip( arglist.node,  0,  k,  "" );
               } else {
                  m  +=  k;
               }
               all.flip( ancestor.node,
                         ancestor.join + 1,
                         m,
                         ancestor.source );
               arglist.lone     =  null;
               arglist.leader   =  null;
               arglist.mode     =  0;
               arglist.move    +=  j - m - k + ancestor.n;
               arglist.join     =  ancestor.join;
               arglist.scope    =  false;
               arglist.source   =  "";
               arglist.scan     =  false;
               arglist.n        =  0;
            }
         } else if ( this.setter.indexOf( arglist.scan )  <  0 ) {
            WSTM.errors.found( "tagEmptyUndesired",
                               false,
                               "<" + arglist.scope + "> </"
                                   + arglist.scope + ">" );
         }
      }
      return  r;
   };   // .w.tags.friend()



   WSTM.w.tags.frozen  =  function () {
      // Prepare comment modification, if any
      // Uses:
      //    >  .mod.comment
      //           -- user defined comment modification object, or false
      //           .raw  array with link replacements
      //                 Each element is an array with 2 or 3 elements
      //                 [0] regexp string
      //                     starting with "<!--"
      //                     terminated with "-->"
      //                 [1] replacement string
      //                 [2] true: case insensitive
      //                     omitted or false: case sensitive
      //           .name  name of user defined request variable
      //     < .w.tags.replComment
      //    .util.isArray()
      //    .errors.found()
      //    .str.substrEnd()
      // 2012-05-10 PerfektesChaos@de.wikipedia
      var p  =  WSTM.mod.comment,
          a,
          d,
          f,
          i,
          l,
          m,
          n,
          r,
          s,
          t,
          x;
      if ( p ) {
         s  =  p.name;
         d  =  p.raw;
         m  =  d.length;
         x  =  [ ];
         for ( i = 0;  i < m;  i++ ) {
            a  =  d[i];
            if ( WSTM.util.isArray( a ) ) {
               n  =  a.length;
               if ( n >= 2 ) {
                  f  =  a[ 0 ];
                  t  =  a[ 1 ];
                  l  =  ( n > 2  ?  a[ 2 ]  :  false );
                  if ( typeof f  !==  "string" ) {
                     WSTM.errors.found( "modStringRequired",
                                        false,
                                        s + "[" + i + "][0]=" + f );
                     a  =  false;
                  }
                  if ( typeof t  !==  "string" ) {
                     WSTM.errors.found( "modStringRequired",
                                        false,
                                        s + "[" + i + "][1]=" + t );
                     a  =  false;
                  }
                  if ( a ) {
                     if ( f.substr( 0, 4 )  ===  "<!--"   &&
                          WSTM.str.substrEnd( f, 3 )  ===  "-->" ) {
//                      f.slice(-3) === "-->") {
                        try {
                           r  =  new RegExp( f,  ( l ? "i" : "" ) );
                           x.push( [ r, t] );
                        } catch ( e ) {
                           WSTM.errors.found( "BadRegExp",
                                              false,
                                              e + " * "
                                              + s + "[" + i + "][0]="
                                              + f );
                        }
                     } else {
                        WSTM.errors.found( "modCommentRequired",
                                           false,
                                           s + "[" + i + "][0]=" + f );
                     }   // valid
                  }   // typeof
               }   // a.length
            } else {
               WSTM.errors.found( "modArrayRequired",
                                  false,
                                  s + "[" + i + "]" );
            }   // isArray
         }   // for i
         if ( x.length ) {
            this.replComment  =  x;
         }   // anything useful
      }
   };   // .w.tags.frozen()



   WSTM.w.tags.furnished  =  function (attributes, access) {
      // Retrieve attribute value
      // Precondition:
      //    attributes  -- Array with properties   .props of this.feature
      //    access      -- attribute name to be accessed
      // Postcondition:
      //    Returns value of access, or false
      // 2012-05-05 PerfektesChaos@de.wikipedia
      var r  =  false,
          e,
          i,
          n;
      if (attributes) {
         n  =  attributes.length;
         for (i = 0;  i < n;  i++) {
            e  =  attributes[i];
            if (e[1] === access) {
               r  =  e[2];
               break;   // for i
            }
         }   // for i
      }
      return  r;
   };   // .w.tags.furnished()



   WSTM.w.tags.future  =  function (assigned, append) {
      // Update list of blocks to be processed later
      // Precondition:
      //    assigned  -- tag name
      //    append    -- true: add item   false: query for assigned
      // Postcondition:
      //    Extends block collection, if tag not yet known
      //    Returns true, if already stored
      // Uses:
      //    .util.isElement()
      //    >< .w.tags.blocks
      // 2012-09-28 PerfektesChaos@de.wikipedia
      var r  =  false;
      if (this.blocks) {
         r  =  WSTM.util.isElement(this.blocks, assigned);
         if (append  &&  ! r) {
            this.blocks.push(assigned);
         }
      } else if (append) {
         this.blocks  =  [ assigned ];
      }
      return  r;
   };   // .w.tags.future()



};   // .bb.tags()
mw.libs.WikiSyntaxTextMod.bb.tags(mw.libs.WikiSyntaxTextMod);
delete mw.libs.WikiSyntaxTextMod.bb.tags;



mw.libs.WikiSyntaxTextMod.bb.css  =  function ( WSTM ) {
   // Analyzing and formatting of tags <x>...</x>
   // Uses:
   //    .util.fiatObjects()
   // 2022-02-02 PerfektesChaos@de.wikipedia
   "use strict";
   WSTM.util.fiatObjects( WSTM,  "w",
                          { css:  { }  }
                        );
   WSTM.w.css.html    =  { align:   "text-align",
                           bgcolor: "background",
                           valign:  "vertical-align" };
   WSTM.w.css.values  =  { "text-align":     "|left|center|right|",
                           "vertical-align": "|top|middle|bottom|"
                                             + "baseline|sub|super|"
                                             + "text-bottom|"
                                             + "text-top|" };



   WSTM.w.css.fashion  =  function ( adjust, about ) {
      // Analyze and polish CSS declaration
      // Precondition:
      //    adjust  -- string with CSS code
      //    about   -- tag name or table code
      // Postcondition:
      //    Returns modified string, or false if unchanged
      // Uses:
      //    this
      //    >  .w.reWhitespaceMult
      //    >  .w.css.reAlpha
      //    >  .w.css.reURL
      //    >  .w.css.reQuote
      //    >  .w.css.reBadchar
      //    >  .w.encountered.sortable
      //    >  .w.css.html
      //    >  .w.css.values
      //    .str.trim()
      //    .errors.found()
      //    .w.css.first()
      //    .w.css.favourite()
      //    .w.css.four()
      //    .w.css.field()
      // 2022-09-12 PerfektesChaos@de.wikipedia
      var i, k, lean, light, n, r, rules, sign, set, style, vals;
      style  =  adjust.replace( WSTM.w.reWhitespaceMult, " " );
      lean   =  ( style.indexOf( "; " )  <  0 );
      rules  =  style.split( ";" );
      n      =  rules.length;
      light  =  ( lean   ||   style.indexOf( ": " )  <  0 );
      for ( i = 0;  i < n;  i++ ) {
         set  =  rules[ i ];
         k    =  set.indexOf( ":" );
         if ( k >= 0 ) {
            sign  =  WSTM.str.trim( set.substr( 0, k ) );
            set   =  WSTM.str.trim( set.substr( k + 1 ) );
            if ( sign === "" ) {
               if ( set === "" ) {
                  k  =  -2;
               } else {
                  k  =  0;
               }
            }
            if ( k > 0 ) {
               this.first( "Alpha" );
               if ( this.reAlpha.test( sign ) ) {
                  if ( set === "" ) {
                     WSTM.errors.found( "cssValueMissing",
                                        false,
                                        sign );
                     set  =  "??????";
                  } else {
                     this.first( "URL" );
                     sign  =  sign.toLowerCase();
                     if ( this.reURL.test( set ) ) {
                        WSTM.errors.found( "cssValueURL",
                                           false,
                                           sign + ": " + set );
                     } else if ( ! this.reQuote.test( set )
                                 &&  sign !== "font-family"
                                 &&  this.reBadchar.test( set ) ) {
                        WSTM.errors.found( "cssValueInvalid",
                                           false,
                                           sign + ": " + set );
                     } else {
                        vals  =  vals || { };
                        switch ( sign ) {
                           case "background-color":
                              if ( about !== "!"   ||
                                   typeof WSTM.w.encountered.sortable
                                                       !==  "boolean" ) {
                                 sign  =  "background";
                              }   // fall through
                           case "border-bottom-color":
                           case "border-left-color":
                           case "border-right-color":
                           case "border-top-color":
                           case "color":
                              set  =  this.favourite( set, sign );
                              break;
                           case "border-color":
                              set  =  this.four( set, "color", sign );
                              break;
                           case "border-bottom-width":
                           case "border-left-width":
                           case "border-right-width":
                           case "border-top-width":
                           case "height":
                           case "line-height":
                           case "min-height":
                           case "min-width":
                           case "margin-bottom":
                           case "margin-left":
                           case "margin-right":
                           case "margin-top":
                           case "max-height":
                           case "max-width":
                           case "padding-bottom":
                           case "padding-left":
                           case "padding-right":
                           case "padding-top":
                           case "width":
                              set  =  this.field( set, sign );
                              break;
                           case "border-width":
                           case "margin":
                           case "padding":
                              set  =  this.four( set, "length", sign );
                              break;
                           case "background":
                           case "border":
                           case "border-bottom":
                           case "border-left":
                           case "border-right":
                           case "border-top":
                              set  =  this.features( set, sign );
                              break;
                           case "position":
                              switch ( set ) {
                                 case "absolute":
                                 case "fixed":
                                 case "relative":
                                 case "static":
                                 case "sticky":
                                    break;
                                 default:
                                    WSTM.errors.found( "cssValueInvalid",
                                                       false,
                                                       "position:" + set
                                                                + ";" );
                              }   // switch set
                              break;
                           case "display":
                           case "font-family":
                              break;
                           case "clear":
                              switch ( set ) {
                                 case "all":
                                    set  =  "both";
                                    break;
                                 case "both":
                                 case "left":
                                 case "right":
                                 case "none":
                                    break;
                                 default:
                                    WSTM.errors.found( "cssValueInvalid",
                                                       false,
                                                       "clear:" + set
                                                                + ";" );
                              }   // switch set
                              break;
                           case "-moz-column-count":
                           case "-webkit-column-count":
                           case "column-count":
                              if ( typeof vals[ "column-count" ]
                                                        ===  "string" ) {
                                 sign  =  false;
                              } else {
                                 sign  =  "column-count";
                              }
                              break;
                           case "-moz-column-width":
                           case "-webkit-column-width":
                           case "column-width":
                              if ( typeof vals[ "column-width" ]
                                                        ===  "string" ) {
                                 sign  =  false;
                              } else {
                                 sign  =  "column-width";
                              }
                              break;
                           default:
                              set  =  set.toLowerCase();
                              if ( typeof this.html[ sign ]
                                                        ===  "string" ) {
                                 WSTM.errors.found("cssHTMLsymbol",
                                                   false,
                                                   "style=\"" + sign
                                                   + ":...\" -> "
                                                   + this.html[sign]);
                              } else if ( typeof this.values[ sign ]
                                                            ===  "string"
                                         &&  this.values[ sign ]
                                                .indexOf("|" + set + "|")
                                             <  0) {
                                 WSTM.errors.found("cssValueInvalid",
                                                   false,
                                                   sign + ": " + set
                                                   + " -> " +
                                                   this.values[ sign ] );
                              }
                        }   // switch sign
                     }
                     if ( sign && set ) {
                        vals  =  vals || { };
                        if ( typeof vals[ sign ]  ===  "string" ) {
                           if ( vals[ sign ]  ===  set ) {
                              sign  =  false;
                              set   =  false;
                           } else {
                              WSTM.errors.found( "cssPropertyRepeated",
                                                 false,
                                                 sign + ": " + set );
                           }
                        } else {
                           vals[ sign ]  =  set;
                        }
                     }
                  }
               } else {
                  WSTM.errors.found( "cssIDinvalid", false, sign );
               }
            }
         } else if ( WSTM.str.trim( set )  !==  "" ) {
            k  =  0;
         }
         if ( ! k ) {
            WSTM.errors.found( "cssIDmissing", false, set );
            sign  =  "???";
         }
         if ( k >= 0  &&  sign  &&  set ) {
            set  =  WSTM.str.trim( set );
            if ( r ) {
               r  =  r  +  ( lean ? ";" : "; " );
            } else {
               r  =  "";
            }
            r  =  r  +  sign  +  ( light ? ":" : ": " )  +  set;
         }
      }   // for i
      if ( r   &&   style.indexOf( ";" )  >  0 ) {
         r  =  r + ";";
      }
      if ( r === adjust ) {
         r  =  false;
      } else if ( ! r ) {
         r  =  "";
      }
      return  r;
   };   // .w.css.fashion()



   WSTM.w.css.favourite  =  function ( assign, about ) {
      // Standardize colour code
      // Precondition:
      //    assign   -- string, trimmed value; #hex or rgb() or name
      //    about    -- string, CSS attribute name
      // Postcondition:
      //    Returns attribute value, may be refined
      // Uses:
      //    >  .w.css.reHEX
      //    >  .w.css.reRGB
      //    >  .w.css.reName
      //    .w.css.first()
      //    .errors.found()
      // 2020-05-28 PerfektesChaos@de.wikipedia
      var s  =  assign,
          got, i, k, limit, max, r;
      if ( s.charCodeAt( 0 )  ===  35 ) {   // #
         s  =  s.substr( 1 ).toUpperCase();
         this.first( "HEX" );
         if ( this.reHEX.test( s ) ) {
            switch ( s.length ) {
               case 1:
                  s  =  s + s + s;   // fall through
               case 3:
                  s  =    s.substr( 0, 1 )  +  s.substr( 0, 1 )
                        + s.substr( 1, 1 )  +  s.substr( 1, 1 )
                        + s.substr( 2, 1 )  +  s.substr( 2, 1 );
                  break;
               case 6:
                  break;
               default:
                  s  =  false;
            }   // switch s.length
         } else {
            s  =  false;
         }
         if ( s ) {
            r  =  "#" + s;
         }
      } else {
         s  =  s.toLowerCase();
         if ( s.substr( 0, 4 )  ===  "rgb(" ) {
            this.first( "RGB" );
            got  =  this.reRGB.exec( s );
            if ( got ) {
               r  =  "#";
               for ( i = 1;  i <= 3;  i++ ) {
                  s  =  got[ i ];
                  k  =  s.length - 1;
                  limit  =  ( s.substr( k, 1 )  ===  "%" );
                  if ( limit ) {
                     s    =  s.substr( 0, k );
                     max  =  100;
                  } else {
                     max  =  255;
                  }
                  if ( s  ===  max + "" ) {
                     r  =  r + "FF";
                  } else {
                     k  =  parseInt( s, 10 );
                     if ( k > max ) {
                        r  =  false;
                        break;   // for i
                     } else {
                        if ( limit ) {
                           k  =  Math.floor( ( k * 256 ) / 256 );
                        }
                     }
                     if ( k < 16 ) {
                        r  =  r + "0";
                     }
                     r  =  r + k.toString( 16 ).toUpperCase();
                  }
               }   // for i
            }
         } else {
            this.first( "Name" );
            if ( this.reName.test( s ) ) {
               r  =  s;
            }
         }
      }
      if ( ! r ) {
         WSTM.errors.found( "cssValueInvalid",
                            false,
                            about + ": " + assign );
         r  =  assign;
      }
      return  r;
   };   // .w.css.favourite()



   WSTM.w.css.features  =  function ( assign, about ) {
      // Correct combined specification
      // Postcondition:
      //    Returns attribute value, may be refined
      // Uses:
      //    .w.css.flat()
      //    .w.css.first()
      //    .w.css.favourite()
      //    .w.css.field()
      //    .errors.found()
      // 2020-07-03 PerfektesChaos@de.wikipedia
      var kColor  = 2,
          kStyle  = 1,
          kWidth  = 0,
          s       =  this.flat( assign ),
          got     =  [ false, false, false ],
          r       =  "",
          tokens  =  s.split( " " ),
          n       =  tokens.length,
          i, k;
      this.first( "Numeric" );
      for ( i = 0;  i < n;  i++ ) {
         s  =  tokens[ i ];
         if ( s.charCodeAt( 0 )  ===  35 ) {   // #
            s  =  this.favourite( s, about );
            k  =  kColor;
         } else if ( this.reNumeric.test( s ) ) {
            s  =  this.field( s, about );
            k  =  kWidth;
         } else {
            s  =  s.toLowerCase();
            switch ( s ) {
               case "thin":
               case "medium":
               case "thick":
                  k  =  kWidth;
                  break;
               case "none":
               case "hidden":
               case "dotted":
               case "dashed":
               case "solid":
               case "double":
               case "groove":
               case "ridge":
               case "inset":
               case "outset":
               case "inherit":
                  k  =  kStyle;
                  break;
               case "cyan":
                  s  =  "aqua";
                  k  =  kColor;
                  break;
               case "magenta":
                  s  =  "fuchsia";
                  k  =  kColor;
                  break;
               case "aqua":
               case "black":
               case "blue":
               case "fuchsia":
               case "gray":
               case "green":
               case "lime":
               case "maroon":
               case "navy":
               case "olive":
               case "orange":
               case "purple":
               case "red":
               case "silver":
               case "teal":
               case "white":
               case "yellow":
               case "transparent":
                  k  =  kColor;
                  break;
               default:
                  if ( s.substr( 0, 4 ) ===  "rgb(" ) {
                     s  =  this.favourite( s, about );
                  }
                  k  =  kColor;
                  break;
            }   // switch s
         }
         if ( k < 2  &&  got[ k ] ) {
            WSTM.errors.found( "cssValueInvalid",
                               false,
                               about + ": " + got[ k ] + " " + s );
         }
         if ( got[ k ] ) {
            got[ k ]  =  got[ k ] + " " + s;
         } else {
            got[ k ]  =  s;
         }
      }   // for i
      for ( i = 0;  i < 3;  i++ ) {
         s  =  got[ i ];
         if ( s ) {
            if ( r ) {
               r  =  r + " " + s;
            } else {
               r  =  s;
            }
         }
      }   // for i
      if ( n > 1 ) {
//       r  =  " " + r;
      }
      return  r;
   };   // .w.css.features()



   WSTM.w.css.field  =  function ( assign, about ) {
      // Correct single length measure
      // Precondition:
      //    assign   -- string, value
      //    about    -- string, CSS attribute name
      // Postcondition:
      //    Returns attribute value, may be refined
      // Uses:
      //    >< .w.css.reDigits
      //    >< .w.css.reLengthListCorr
      //    >< .w.css.reLengthZero
      //    .errors.found()
      // 2020-10-16 PerfektesChaos@de.wikipedia
      var r  =  assign.toLowerCase(),
          s, scan, suffix;
      if ( r !== "auto"   &&  r !== "inherit" ) {
         if ( typeof this.reLengthListCorr  !==  "object"   ||
              typeof this.reDigits  !==  "object" ) {
            s       =  "[0-9]+|[0-9]*\\.[0-9]+";
            suffix  =  "(%|em|ex|px|rem)";
            scan    =  "-?(" + s + ")\\s+" + suffix;
         }
         if ( typeof this.reDigits  !==  "object" ) {
            this.reDigits          =  new RegExp( "^-?[0-9]+$" );
            this.reLengthSole      =  new RegExp( "^(?:-?" + s
                                                  +      ")[%a-z]+$" );
            this.reLengthSoleCorr  =  new RegExp( "^" + scan + "$" );
         }
         if ( this.reDigits.test( r ) ) {
            r  =  r + "px";
         } else {
            r  =  r.replace( this.reLengthSoleCorr, "$1$2" );
         }
         if ( ! this.reLengthSole.test( r ) ) {
            WSTM.errors.found( "cssValueInvalid",
                               false,
                               about + ": " + r );
         }
         if ( typeof this.reLengthZero  !==  "object" ) {
            s                      =  "-?0*\\.?0+[%a-z]*";
            this.reLengthZero      =  new RegExp( "^" + s + "$" );
         }
         if ( this.reLengthZero.test( r ) ) {
            r  =  "0";
         }
      }
      return  r;
   };   // .w.css.field()



   WSTM.w.css.first  =  function ( at ) {
      // Initialize CSS analysis
      // Precondition:
      //    at   -- RegExp name
      // Postcondition:
      //    Ensures RegExp
      // Uses:
      //    this
      //     < .w.css.reAlpha
      //     < .w.css.reBadchar
      //     < .w.css.reHEX
      //     < .w.css.reName
      //     < .w.css.reQuote
      //     < .w.css.reRGBstd
      //     < .w.css.reRGB
      //     < .w.css.reURL
      // 2020-05-15 PerfektesChaos@de.wikipedia
      var s;
      if ( typeof this[ "re" + at ]  !==  "object" ) {
         switch ( at ) {
            case "Alpha":
               this.reAlpha  =  new RegExp( "^[-a-zA-Z]+$" );
               break;
            case "HEX":
               this.reHEX  =  new RegExp( "^[0-9A-F]+$" );
               break;
            case "Name":
               this.reName  =  new RegExp( "^[a-z]+$" );
               break;
            case "Numeric":
               this.reNumeric  =  new RegExp( "^-?(?:[0-9]+|"
                                                  + "[0-9]*\\.[0-9]+)" );
               break;
            case "RGB":
               s  =  " *([0-9]+%?) *";
               s  =  "rgb\\(" + s + ","
                              + s + ","
                              + s + "\\)";
               this.reRGB     =  new RegExp( "^" + s + "$" );
               this.reRGBstd  =  new RegExp( s, "gi" );
               break;
            case "URL":
               this.reBadchar  =  new RegExp( "[^-a-z_A-Z.0-9% #(,)]" );
               this.reQuote    =  new RegExp( "['\"]");
               this.reURL      =  new RegExp( "\\burl\\s*\\(", "i" );
               break;
         }   // switch at
      }
   };   // .w.css.first()



   WSTM.w.css.flat  =  function ( assign ) {
      // Normalize rgb() colour assignment
      // Precondition:
      //    assign   -- string, rgb() or not
      // Postcondition:
      //    Returns attribute value, may be refined
      // Uses:
      //    >  .w.css.reRGBstd
      //    .w.css.first()
      // 2020-05-15 PerfektesChaos@de.wikipedia
      var r;
      if ( assign.indexOf( "(" )  >  0 ) {
         this.first( "RGB" );
         r  =  assign.replace( this.reRGBstd, "rgb($1,$2,$3)");
      }
      return  r  ||  assign;
   };   // .w.css.flat()



   WSTM.w.css.four  =  function ( assign, ask, about ) {
      // Standardize list of up to 4 items
      // Precondition:
      //    assign   -- string, multiple items permitted
      //    ask      -- string, "color" or "length"
      //    about    -- string, CSS attribute name
      // Postcondition:
      //    Returns attribute value, may be refined
      // Uses:
      //    .w.css.flat()
      //    .errors.found()
      //    .w.css.favourite()
      //    .w.css.field()
      // 2020-05-15 PerfektesChaos@de.wikipedia
      var i, n, r, s, tokens;
      if ( ask === "color" ) {
         s  =  this.flat( assign );
      } else {
         s  =  assign;
      }
      tokens  =  s.split( " " );
      n       =  tokens.length;
      if ( n > 4 ) {
         WSTM.errors.found( "cssValueInvalid",
                            false,
                            about + ": " + assign );
      } else {
         for ( i = 0;  i < n;  i++ ) {
            s  =  tokens[ i ];
            switch ( ask ) {
               case "color":
                  s  =  this.favourite( s, about );
                  break;
               case "length":
                  s  =  this.field( s, about );
                  break;
            }   // switch s.length
            if ( r ) {
               r  =  r + " " + s;
            } else {
               r  =  s;
            }
         }   // for i
         if ( n > 1 ) {
            r  =  " " + r;
         }
      }
      return  r  ||  assign;
   };   // .w.css.four()



};   // .bb.css()
mw.libs.WikiSyntaxTextMod.bb.css(mw.libs.WikiSyntaxTextMod);
delete mw.libs.WikiSyntaxTextMod.bb.css;



//-----------------------------------------------------------------------



( function ( WSTM ) {
   "use strict";
   var sub      =  "X",
       self     =  WSTM.w.tags.self,
       version  =  WSTM.w.tags.vsn,
       rls;
   if ( typeof WSTM.main  ===  "object"
        &&     WSTM.main   &&
        typeof WSTM.main.wait  ===  "function" ) {
      // Start on import: callback to waiting ...
      WSTM.main.wait( sub, version );
   } else if ( typeof mw.loader  ===  "object"   &&
               typeof mw.hook  !==  "undefined" ) {
      rls = { };
      rls[ self ] = "ready";
      mw.loader.state( rls );
      mw.hook( "WikiSyntaxTextMod/" + sub + ".ready" )
        .fire( [ sub, version ] );
   }
} ( mw.libs.WikiSyntaxTextMod ) );



// Emacs
// Local Variables:
// coding: iso-8859-1-dos
// fill-column: 80
// End:

/// EOF </nowiki>   WikiSyntaxTextMod/dX.js