Revision 137931 of "User:PerfektesChaos/js/WikiSyntaxTextMod/dN.js" on testwiki

/// PerfektesChaos/js/WikisyntaxTextMod/?W.js
/// 2012-06-18 [email protected]
/// Fingerprint: #0#0#
/// <nowiki>
// WikiSyntaxTextMod:  Wiki syntax specific code
/* jshint curly:true, latedef:true, laxbreak:true,
          trailing:true, undef:true, white:false  */
/* global mw: true, mediaWiki: false                                   */
/*jslint plusplus: true, regexp: true, sloppy: true, unparam: true,
           vars: true, white: true, maxerr: 50 */
/*globals mw: true, mediaWiki: false                                   */


if (typeof(mediaWiki) !== "object") {   // disconnected
   mw  =  { config: false,
            libs:   { WikiSyntaxTextMod:  {debugging: false}
                    },
            log:    function () {}
          };
}
if (typeof(mw.libs.WikiSyntaxTextMod) !== "object") {   // isolated
   mw.libs.WikiSyntaxTextMod  =  { debugging: false };
}
if (typeof(mw.libs.WikiSyntaxTextMod.w) !== "object") {
   mw.libs.WikiSyntaxTextMod.w  =  { };
}
mw.libs.WikiSyntaxTextMod.w.vsn  =  -4.86;
if (typeof(mw.libs.WikiSyntaxTextMod.bb) !== "object") {
   mw.libs.WikiSyntaxTextMod.bb  =  { };
}



/*
Requires: JavaScript 1.3
          (String.charCodeAt String.fromCharCode String.replace)
          JavaScript 1.5  RegExp non-capturing parenthese
 */
// mw.log(WSTM.debugging,"",0);



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



mw.libs.WikiSyntaxTextMod.bb.bbW  =  function (WSTM) {
   // Building block and run environment support
   // 2012-05-18 [email protected]
   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 [email protected]
         var elt;
         var obj;
         var s;
         if (typeof( adult[activate] )  !==  "object") {
            adult[activate]  =  (assign  ?  assign  :  { } );
         }
         if (assign) {
            obj  =  adult[activate];
            for (s in assign) {
               if (assign.hasOwnProperty(s)) {
                  elt  =  assign[s];
                  if (typeof(elt)  ===  "object") {
                     WSTM.util.fiatObjects(obj, s, elt);
                  }
               }
            }  //  for s in obj
         }
      };   // .util.fiatObjects()
   }


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


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



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



mw.libs.WikiSyntaxTextMod.bb.W  =  function (WSTM) {
   // Wiki specific localization
   // Uses:
   //    .util.fiatObjects()
   // 2012-05-18 [email protected]
   WSTM.util.fiatObjects(WSTM,  "g",
                         { learnt: false,
                           re:     { },
                           s:      {  re: { }  }
                         } );
   // WikiRegExp_URLfragmt       =  false;   // ??
   // WikiRegExp_URLarticle      =  false;



   if (typeof(mw.libs.WikiSyntaxTextMod.str) !== "object") {
      mw.libs.WikiSyntaxTextMod.str  =  { };
   }
   WSTM.str.locateEntities  =  false;
   WSTM.str.sort_lang       =  false;
   WSTM.str.sort_mode       =  false;



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



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



mw.libs.WikiSyntaxTextMod.bb.l10nW  =  function (WSTM) {
   // Wiki specific localization
   // Uses:
   //    .util.fiatObjects()
   // 2012-05-23 [email protected]
   WSTM.util.fiatObjects(WSTM,  "l10n",
                         { lang:      { },
                           proj:      { },
                           re:        { },
                           s:         { },
                           templates: { },
                           text:      { },
                           word:      { trslFilePar: false }
                         } );



WSTM.l10n.word.filePars  =  function () {
   // Initialize global variable for image_parameter standardization
   // Uses:
   //     < .l10n.word.trslFilePar
   //    .l10n.word.fetch()
   //    .util.translate.factory()
   // 2012-05-18 [email protected]
   var ext  =  WSTM.l10n.word.fetch("image_", 0);
   var dup  =  [ ["(\\|[a-zA-Z])\\1\\|",      "$1|",    "g"],
                 ["(\\|[a-zA-Z]\\|)(.+)\\1",  "$1$2|",  "g"] ];
   var tms  =  [ ["\\| +",                               "|",     "g"],
                 [" +\\|",                               "|",     "g"],
                 ["\\|(\\|.)",                           "$1",    "g"],
                 ["(\\|[a-zA-Z]+) +(=.*\\|)",            "$1$2",  "g"],
                 ["(\\|[a-zA-Z]+=) +(.*\\|)",            "$1$2",  "g"],
                 ["(\\|[a-zA-Z]+[ =][01]?),([0-9]*\\|)", "$1.$2", "g"],
                 ["(\\|[x0-9]+) +px\\|",                 "$1px|", "i"]
               ];
   var i;
   var n;
   var raw;
   var rep;
   var trsl;
   tms  =  tms.concat(dup);
   if (ext) {
      n  =  ext.length;
      if (n > 0) {
         trsl  =  new Array(n);
         for (i = 0;  i < n;  i++) {
            raw      =  ext[i];
            rep      =  new Array(3);
            rep[0]   =  "\\|" + raw[0] + "\\|";
            rep[1]   =  "|" + raw[1] + "|";
            rep[2]   =  "i";
            trsl[i]  =  rep;
         }   // for i
         tms  =  tms.concat(trsl, dup);
      }
   }   // localize
   WSTM.l10n.word.trslFilePar  =
                            WSTM.util.translate.factory(tms, "filePars");
};   // .l10n.word.filePars()



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



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



mw.libs.WikiSyntaxTextMod.bb.chr  =  function (WSTM) {
   // Wiki specific character handling
   // 2012-05-12 [email protected]
   if (typeof(WSTM.w.chr) !== "object") {
      WSTM.w.chr  =  { detected:  { ampersand: false,
                                    exchange: 0,
                                    nbHyphen: false,
                                    ordMasc:  false,
                                    tab:      false,
                                    tabEOL:   false,
                                    white:    false },
                       re:        { }
                     };
   }
   if (typeof(WSTM.w.chr.detected) !== "object") {
      WSTM.w.chr.detected  =  { ampersand: false,
                                exchange: 0,
                                nbHyphen: false,
                                ordMasc:  false,
                                tab:      false,
                                tabEOL:   false,
                                white:    false
                              };
   }
   if (typeof(WSTM.w.chr.re) !== "object") {
      WSTM.w.chr.re  =  { };
   }



WSTM.w.chr.fashion  =  function (adjust, address) {
   // Exchange string, replace Dingbats, fullwidth, Roman digits
   // Precondition:
   //    adjust   -- String to be manipulated
   //    address  -- last position of suspicious character within adjust
   // Postcondition:
   //    Returns modified String, exchanged undesired characters
   // Uses:
   //    >  .w.chr.detected.exchange
   //    .w.chr.format()
   //    .str.setChar()
   //    .str.setString()
   // 2012-04-06 [email protected]
   var r  =  false;
   var c;
   var i;
   var s  =  adjust;
   var x;
   for (i = address;  i >= 0;  i--) {
      c  =  s.charCodeAt(i);
      if (c >= this.detected.exchange) {
         if ((c >=  8544  &&  c <=  8575)   ||   // Roman digits
             (c >= 65281  &&  c <= 65374)) {   // fullwidth
            x  =  this.format(c, s, i);
            if (x !== c) {
               r  =  typeof(x);
               if (r === "number") {
                  s  =  WSTM.str.setChar(s, x, i);
               } else if (r === "string") {
                  s  =  WSTM.str.setString(s, i, 1, x);
               } else {
                  s  =  r;
               }
            r  =  s;
            }
         } else if (c >= 10005  &&  c <= 10015) {   // Dingbats
            switch (c) {
               case 10005 : // 2715
               case 10006 : // 2716
                  c  =   215; // times
                  break;
               case 10013 : // 271D
               case 10014 : // 271E
               case 10015 : // 271F
                  c  =  8224; // dagger
                  break;
            }   // switch c
            if (c < 10000) {
               s  =  WSTM.str.setChar(s, c, i);
               r  =  s;
            }
         }   // rare codes
      }   // .w.chr.detected.exchange
   }   // for i
   return  r;
};   // .w.chr.fashion()



WSTM.w.chr.filter  =  function (all) {
   // Improve character encoding in string, encode, trim lines
   // Precondition:
   //    all  -- root WikiTom to be manipulated
   // Postcondition:
   //    Modifies  all::
   //      >< .source  -- exchanged unreadable characters
   //                     trailing whitespace and control codes removed
   //       < .learnt  -- true: significant encoding change
   //                     false: possibly trailing whitespace cut
   // Characters which may occur in links and syntax are postponed.
   // Uses:
   //    >< .w.chr.detected.exchange
   //    >< .w.chr.whitespace
   //     < .w.encountered.indent
   //     < .w.chr.detected.ampersand
   //     < .w.chr.detected.nbHyphen
   //     < .w.chr.detected.ordMasc
   //     < .w.chr.detected.tab
   //     < .w.chr.detected.tabEOL
   //     < .w.chr.detected.white
   //    .str.setString()
   //    .str.setChar()
   //    .w.chr.form()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-06-19 [email protected]
   var c;
   var i;
   var k;
   var l  =  false;
   var s  =  all.source;
   for (i = s.length - 1;  i >= 0;  i--) {
      c  =  s.charCodeAt(i);
      if (c < 128) {   // ASCII
         if (c < 32) {   // control code
            switch (c) {
               case 10 : // newline
                  if (s.charCodeAt(k + 1)  ===  10) {
                     WSTM.w.encountered.indent  =  true;
                  }
                  for (k = i-1;  k >= 0;  k--) {
                     c  =  s.charCodeAt(k);
                     if (c > 32  ||  c === 10) {
                        if (c === 61) {   // '='
                           k++;
                           if (s.charCodeAt(k) === 9) {
                              k--;
                           }
                        }   // template?
                        break;   // for k
                     } else if (c === 9) {
                        this.detected.tabEOL  =  true;
                     }
                  }   // for k
                  if (k  <  i - 1) {   // trailing whitespace: minor mod
                     this.detected.white  =  true;
                     k++;
                     s  =  WSTM.str.setString(s,  k,  i - k,  "");
                     i  =  k;
                  }
                  break;
               case 13 : // IE inserts CR before any LF
                  break;
               case  9 : // hor tab
                  this.detected.tab  =  true;
                  break;
               case 11 : // vertical tab
               case 12 : // form feed
                  s  =  WSTM.str.setChar(s, 10, i);   // newline
                  l  =  true;
                  break;
               default : // forbidden
                  s  =  WSTM.str.setChar(s, "", i);   // discard
                  l  =  true;
                  break;
            }   // switch c
         } else  if (c === 38) {   // '&'
            this.detected.ampersand  =  true;
         }
      } else {
         if (c <= 160) {   // windows codepages and nbsp
            s  =  WSTM.str.setChar(s,  "&#" + c + ";",  i);   // show
            l  =  true;
         } else if (c > 8193  &&  c < 8289) {   // Unicode
            // make visible
            switch (c) {
               case 8194 : // enSpace  \u2002
               case 8195 : // emSpace  \u2003
                  s  =  WSTM.str.setChar(s, 32, i);   // space
                  l  =  true;
                  break;
               case 8198 : // SIX-PER-EM SPACE
               case 8201 : // thinsp
               case 8239 : // NARROW NO-BREAK SPACE
                  // 8239 richtiges Zeichen für deutsche Typografie
                  s  =  WSTM.str.setChar(s, "&thinsp;", i);
                  l  =  true;
                  break;
               case 8203 : // ZERO WIDTH SPACE used in bo:
                  s  =  WSTM.str.setChar(s, "&#x200A;", i);
                  l  =  true;
                  break;
               case 8204 : // ZERO WIDTH NON-JOINER used in fa: kn: mzn:
                  s  =  WSTM.str.setChar(s, "&zwnj;", i);
                  l  =  true;
                  break;
               case 8205 : // ZERO WIDTH JOINER      used in ml:
                  s  =  WSTM.str.setChar(s, "&zwj;", i);
                  l  =  true;
                  break;
               case 8209 : // NON-BREAKING HYPHEN  \u2011
                  this.detected.nbHyphen  =  true;
                  break;
               case 8202 : // hair space (english typography)
               case 8206 : // LEFT-TO-RIGHT MARK  \u200E
               case 8207 : // RIGHT-TO-LEFT MARK  \u200F
               case 8232 : // LINE SEPARATOR
               case 8233 : // PARAGRAPH SEPARATOR
               case 8234 : // LEFT-TO-RIGHT EMBEDDING
               case 8235 : // RIGHT-TO-LEFT EMBEDDING
               case 8236 : // POP DIRECTIONAL FORMATTING
               case 8237 : // LEFT-TO-RIGHT OVERRIDE
               case 8238 : // RIGHT-TO-LEFT OVERRIDE
               case 8288 : // WORD JOINER
                  c  =  this.form(c);
                  s  =  WSTM.str.setChar(s, c, i);
                  l  =  true;
                  break;
            }   // switch c
         } else if ((c >= 57344   &&  c <= 63743)   ||
                    (c >= 983040  &&  c <= 1114111)) { // Private Use
            s  =  WSTM.str.setChar(s,  "&#" + c + ";",  i);   // show
            l  =  true;
            // U+E000-F8FF  U+F0000-10FFFF
         } else if ((c >= 8544   &&  c <= 8575)    ||    // Roman
                    (c >= 65281  &&  c <= 65374)   ||    // fullwidth
                    (c >= 10005  &&  c <= 10015)) {      // Dingbats etc.
            if (this.detected.exchange) {
               if (this.detected.exchange > c) {
                  this.detected.exchange  =  c;
               }
            } else {
               this.detected.exchange  =  c;
            }
         } else if (c === 186) {   // masculine ordinal indicator
            this.detected.ordMasc  =  true;
         } else if (c === 847) {   // COMBINING GRAPHEME JOINER \x034F
            c  =  this.form(c);
            s  =  WSTM.str.setChar(s, c, i);
            l  =  true;
         }   // rare codes
      }   // character types
   }   // for i --
   c  =  s.charCodeAt(0);
   while (c === 10) {   // skip heading \n
      s  =  s.substr(1);
      c  =  s.charCodeAt(0);
      this.detected.white  =  true;
   }   // while ! c
   k  =  s.length - 1;
   c  =  s.charCodeAt(k);
   while (c === 10) {   // remove trailing \n
      s  =  s.substr(0, k);
      k--;
      c  =  s.charCodeAt(k);
      this.detected.white  =  true;
   }   // while ! c
   this.whitespace  =  (this.detected.tab ? " \n\t" : " \n");
   all.learnt  =  l;
   all.source  =  s;
};   // .w.chr.filter()



WSTM.w.chr.fixed  =  function (adjust) {
   // Check whether character entity should be kept escaped in wikisyntax
   // Precondition:
   //    adjust  -- character code
   // Postcondition:
   //    Returns false if replacement not recommended,  or character code
   // 2012-03-09 [email protected]
   var r  =  adjust;
   switch (r) {
      /* ML escapes */
      case   34 : // quot
      case   38 : // amp
      case   39 : // apos
      case   60 : // lt
      case   62 : // gt
      /* special chars to be kept */
      case  160 : // nbsp
      case  710 : // circ
      case  732 : // tilde
      case 8201 : // thinsp
      case 8206 : // lrm  LEFT-TO-RIGHT MARK
      case 8207 : // rlm  RIGHT-TO-LEFT MARK
      /* wikisyntax escapes */
      case   91 : // [ lsqb
      case   93 : // ] rsqb
      case  123 : // { lcub
      case  124 : // | verbar
      case  125 : // } rcub
         r  =  false;
      /* special chars to be deleted one day */
      case 8204 : // zwnj   // required in Farsi, kn:, mzn:
      case 8205 : // zwj    // required in ml:
         r  =  0;
         break;
      /* to be replaced by ASCII space */
      case 8194 : // ensp
      case 8195 : // emsp
         r  =  32;
         break;
   }   // switch r
   return  r;
};   // .w.chr.fixed()



WSTM.w.chr.fixTab  =  function (adjust) {
   // Remove tab chars from string, if any
   // Precondition:
   //    adjust  -- string to be cleaned
   // Postcondition:
   //    Returns false, if no tab char found, or modified string
   // 2012-03-12 [email protected]
   var r  =  false;
   if (adjust.indexOf("\t") >= 0) {
      r  =  adjust.replace(/\t/g, " ");
   }
   return  r;
};   // .w.chr.fixTab()



WSTM.w.chr.flat  =  function (adjust, assign) {
   // Exchange undesired entities with char or standardized entity form
   // Precondition:
   //    adjust  -- string "&named;" or "&#xHHHH;" or "&#NNN;"
   //    assign  -- true if named entity,  false if numeric
   // Postcondition:
   //    Returns false if replacement not recommended,
   //            otherwise string with (single) character
   // Uses:
   //    .str.charEntityCode()
   //    .str.charEntityHTML4()
   //    .w.chr.form()
   // Requires: JavaScript 1.3   fromCharCode()
   // 2012-06-19 [email protected]
   var r;
   if (assign) {
      r  =  WSTM.str.charEntityHTML4(adjust);
   } else {
      r  =  WSTM.str.charEntityCode(adjust);
   }   // named or numeric
   if (r) {
      switch (r) {
         // ML syntax escaped
         case   34 : // quot
         case   38 : // amp
         case   39 : // apos
         case   60 : // lt
         case   62 : // gt
         // wikisyntax escaped
         case   32 : // SPC
         case   35 : // #
         case   42 : // *
         case   58 : // :
         case   59 : // ;
         case   91 : // [
         case   93 : // ]
         case  123 : // {
         case  124 : // |
         case  125 : // }
         // invisible information kept visual
         case   96 : // grave
         case  160 : // nbsp
         case  168 : // uml
         case  175 : // macr
         case  180 : // acute
         case  184 : // cedil
         case  710 : // circ
         case  711 : // caron
         case  728 : // breve
         case  730 : // ring
         case  731 : // ogon
         case  732 : // tilde
         case  733 : // dacute
         case  173 : // soft hyphen
         case 8201 : // thinsp
         case 8202 : // hair space (english typography)
         case 8206 : // LEFT-TO-RIGHT MARK
         case 8207 : // RIGHT-TO-LEFT MARK
         case 8209 : // NON-BREAKING HYPHEN
         case 8239 : // NARROW NO-BREAK SPACE
            r  =  false;
            break;
         // replace by ASCII space
         case 8194 : // ensp
         case 8195 : // emsp
         case 8196 : // THREE-PER-EM SPACE
         case 8197 : // FOUR-PER-EM SPACE
         case 8198 : // SIX-PER-EM SPACE
            r  =  32;
            break;
         case 8204 : // ZERO WIDTH NON-JOINER
         case 8205 : // ZERO WIDTH JOINER
            r  =  false;
            break;
         // to be replaced later
         case  8232 : // LINE SEPARATOR
         case  8233 : // PARAGRAPH SEPARATOR
         // just make entities
         case   847 : // COMBINING GRAPHEME JOINER \x034F
         case  8202 : // HAIR SPACE
         case  8203 : // ZERO WIDTH SPACE
         case  8206 : // LEFT-TO-RIGHT MARK  \u200E
         case  8207 : // RIGHT-TO-LEFT MARK  \u200F
         case  8234 : // LEFT-TO-RIGHT EMBEDDING
         case  8235 : // RIGHT-TO-LEFT EMBEDDING
         case  8236 : // POP DIRECTIONAL FORMATTING
         case  8237 : // LEFT-TO-RIGHT OVERRIDE
         case  8238 : // RIGHT-TO-LEFT OVERRIDE
         case  8288 : // WORD JOINER
            r  =  this.form(r);
            break;
         default :
            if (r >= 10240) {   // Braille and extra-European
               // entity should'nt be converted
               r  =  false;
            } else if (r > 8193)  {
               r  =  this.form(r);
            } else if (r < 160)  {
               r  =  false;
            }
            break;
      }   // switch r
   }   // detected
   if (r) {
      if (typeof(r) === "number") {
         r  =  String.fromCharCode(r);
      }   // conversion  number -> string
      if (adjust === r) {
         r  =  false;
      }   // unchanged
   }   // conversion
   return  r;
};   // .w.chr.flat()



WSTM.w.chr.flip  =  function (all) {
   // Exchange and standardize undesired character entities
   // Precondition:
   //    all  -- root WikiTom to be adjusted
   // Postcondition:
   //    Modified all, if appropriate
   // Uses:
   //    > .w.chr.detected.ampersand
   //    >< .w.chr.reEntity
   //    .X.WikiTom().find()
   //    .w.chr.flipper()
   //    .X.WikiTom().flip()
   // 2012-04-14 [email protected]
   var got;
   var reC;
   var reH;
   var s;
   var shift;
   if (this.detected.ampersand) {
      if (! this.reEntity) {
         reC   =  /&#x?[0-9A-Fa-f+]+;/g;
         reH   =  "&[A-Za-z]"
                  + "[a-zAETH][a-zHO][a-zR123]?[a-zN1234]?[a-z24]?[a-z]?"
                  + ";";
         this.reEntity  =  [ reC,  new RegExp(reH, "g") ];
      }
      got  =  { i: 0,  k: 0 };
      do {
         got  =  all.find("&", got.i, got.k, true, false);
         if (got) {
            s  =  all.fetch(got.k, got.i);
            if (s) {
               shift  =  this.flipper(s);
               if (shift) {
                  all.flip(got.k, got.i, s.length, shift);
               }
            }
            got.i  =  0;
            got.k++;
         }
      } while (got);   // do
   }
};   // .w.chr.flip()



WSTM.w.chr.flipper  =  function (adjust) {
   // Exchange and standardize undesired character entity
   // Precondition:
   //    adjust  -- string to be adjusted
   // Postcondition:
   //    Returns adjusted string,  or false
   // Uses:
   //    >  .w.chr.reEntity
   //    .w.chr.flat()
   // 2012-03-14 [email protected]
   var c;
   var e;
   var f;
   var j;
   var k;
   var l;
   var m  =  false;
   var r  =  false;
   var s  =  adjust;
   for (k = 0;  k < 2;  k++) {
      l  =  (k === 1);
      r  =  this.reEntity[k];
      r.lastIndex  =  0;
      do {
         j  =  r.lastIndex;
         f  =  r.exec(s);
         if (f) {
            e  =  f[0];
            if (e !== "&nbsp;") {
               c  =  this.flat(e, l);
               if (c) {
                  m  =  true;
                  j  =  f.index;
                  s  =  s.substr(0, j)  +  c  +  s.substr(j + e.length);
                  r.lastIndex  =  j + 1;
               }   //
            }   // replace, except nbsp
         }   // found?
      } while (f);   // do
   }   // for k
   return  (m ? s : false);
};   // .w.chr.flipper()



WSTM.w.chr.flushChars  =  function (adjust) {
   // Exchange undesired characters in modifiable nodes with better ones
   // Precondition:
   //    adjust  -- WikiTom to be analyzed
   // Postcondition:
   //    Nodes are modified where suitable.
   // Uses:
   //    >  .w.chr.detected.exchange
   //    .w.chr.flushChars()  -- recursive
   //    .w.chr.fashion()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-05-19 [email protected]
   var c;
   var i;
   var n;
   var s;
   if (adjust.children) {
      n  =  adjust.children.length;
      for (i = 0;  i < n;  i++) {
         this.flushChars(adjust.children[i]);
      }   // for i
   } else if (adjust.lookup) {
      if (adjust.mode <= WSTM.o.WikiTom.TextOnly) {
         s  =  adjust.source;
         if (s) {
            n  =  false;
            for (i = s.length;  i >= 0;  i--) {
               c  =  s.charCodeAt(i);
               if (c >= WSTM.w.chr.detected.exchange) {  // Dingbats etc.
                  s  =  WSTM.w.chr.fashion(s, i);
                  n  =  true;
                  break;   // for i
               }   // suspiciuos character
            }   // for i
            if (n) {
               if (adjust.source !== s) {
                  adjust.fresh(s);
               }
            }
         }
      }
   }
};   // .w.chr.flushChars()



WSTM.w.chr.form  =  function (adjust) {
   // Is character code to be replaced by a more common code or string?
   // Precondition:
   //    adjust  -- character code
   // Postcondition:
   //    Returns original (adjust) or replacing character code or string
   // Uses:
   //    >< .w.chr.detected.exchange
   //    .str.hexcode()
   // 2012-06-19 [email protected]
   var c  =  adjust;
   switch (adjust) {
      case  8194 : // N-SPACE
      case  8195 : // M-SPACE
      case  8200 : // PUNCTUATION SPACE
         c  =  32; // SPC
         break;
      case  8206 : // LEFT-TO-RIGHT MARK  \u200E
         c  =  "&lrm;";
         break;
      case  8207 : // RIGHT-TO-LEFT MARK  \u200F
         c  =  "&rlm;";
         break;
      case   847 : // COMBINING GRAPHEME JOINER \x034F
      case  8196 : // THREE-PER-EM SPACE
      case  8197 : // FOUR-PER-EM SPACE
      case  8198 : // SIX-PER-EM SPACE
      case  8203 : // ZERO WIDTH SPACE
      case  8232 : // LINE SEPARATOR -- make visible as entity first
                          // then remove from links, remaining as '\n'
      case  8233 : // PARAGRAPH SEPARATOR
      case  8234 : // LEFT-TO-RIGHT EMBEDDING
      case  8235 : // RIGHT-TO-LEFT EMBEDDING
      case  8236 : // POP DIRECTIONAL FORMATTING
      case  8237 : // LEFT-TO-RIGHT OVERRIDE
      case  8238 : // RIGHT-TO-LEFT OVERRIDE
         c  =  "&#x" +  WSTM.str.hexcode(adjust, 4, false)  +  ";";
mw.log(WSTM.debugging,".w.chr.form() "+adjust,0);
         break;
      case  8202 : // HAIR SPACE
         c  =  "";   // hook: en=keep  de: ""
         break;
      case  8288 : // WORD JOINER
         c  =  "";
         break;
      default :
         if ((c >= 8544  &&  c <= 8575)   ||    // Roman
             (c >= 65281  &&  c <= 65374)   ||  // fullwidth
             (c >= 10005  &&  c <= 10015)) {    // Dingbats etc.
            if (this.detected.exchange) {
               if (this.detected.exchange > adjust) {
                  this.detected.exchange  =  adjust;
               }
            } else {
               this.detected.exchange  =  adjust;
            }
         }
   }   // switch adjust
   return  c;
};   // .w.chr.form()



WSTM.w.chr.format  =  function (adjust, around, address) {
   // Is character to be replaced by a more common one in this context?
   // Precondition:
   //    adjust   -- character code
   //    around   -- entire context string (modifiable)
   //                false if no context present
   //    address  -- position of adjust within around
   // Postcondition:
   //    Returns original (adjust) or replacing character code or string
   // Uses:
   //    >  .w.chr.detected.exchange
   //    .str.charEntityCode()
   //    .str.charEntityHTML4()
   //    .w.chr.fixed()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-05-31 [email protected]
   var cb  =  0;
   var cf  =  0;
   var c;
   var i;
   var n;
   var r   =  adjust;
   if (around) {
      n   =  around.length;
      if (address > 0) {
         cb  =  around.charCodeAt(address - 1);
         if (cb === 59) {   // ';'
            if (address > 4) {
               i  =  around.lastIndexOf("&",  address - 2);
               if (i >= 0) {
                  c  =  around.substr(i,  address - i);
                  if (around.charCodeAt(i + 1) === 35) {   // '#'
                     c  =  WSTM.str.charEntityCode(c);
                  } else {
                     c  =  WSTM.str.charEntityHTML4(c);
                     if (c) {
                        c  =  this.fixed(c);
                     }
                  }
                  if (c) {
                     cb  =  c;
                  }
               }   // entity
            }
         }   // entity?
      }   // ahead
      if (address  <  n - 1) {
         cf  =  around.charCodeAt(address + 1);
         if (cf === 38) {   // '&'
            if (address  <  n - 4) {
               i  =  around.indexOf(";",  address + 2);
               if (i > address) {
                  c  =  around.substr(address + 1,  i - address);
                  if (around.charCodeAt(address + 2) === 35) {  // '#'
                     c  =  WSTM.str.charEntityCode(c);
                  } else {
                     c  =  WSTM.str.charEntityHTML4(c);
                     if (c) {
                        c  =  this.fixed(c);
                     }
                  }
                  if (c) {
                     cf  =  c;
                  }
               }   // entity
            }
         }   // entity?
      }   // after
   }   // around
   if (cb !== 32   ||
       (cf !== 10  &&  cf !== 32)) {   // not in whitespace
      if (adjust >= 8544  &&  adjust <= 8575) {   // Roman digits
         if (cb < 11904  &&  cf < 11904) {   // Not CJK
            //    >  .w.chr.detected.exchange
            switch (adjust) {
               case 8544 :
                  r  =   73;  // I
                  break;
               case 8545 :
                  r  =  "II";
                  break;
               case 8546 :
                  r  =  "III";
                  break;
               case 8547 :
                  r  =  "IV";
                  break;
               case 8548 :
                  r  =   86;  // V
                  break;
               case 8549 :
                  r  =  "VI";
                  break;
               case 8550 :
                  r  =  "VII";
                  break;
               case 8551 :
                  r  =  "VIII";
                  break;
               case 8552 :
                  r  =  "IX";
                  break;
               case 8553 :
                  r  =   88;  // X
                  break;
               case 8554 :
                  r  =  "XI";
                  break;
               case 8555 :
                  r  =  "XII";
                  break;
               case 8556 :
                  r  =   76;  // L
                  break;
               case 8557 :
                  r  =   67;  // C
                  break;
               case 8558 :
                  r  =   68;  // D
                  break;
               case 8559 :
                  r  =   77;  // M
                  break;
               case 8560 :
                  r  =  105;  // i
                  break;
               case 8561 :
                  r  =  "ii";
                  break;
               case 8562 :
                  r  =  "iii";
                  break;
               case 8563 :
                  r  =  "iv";
                  break;
               case 8564 :
                  r  =  118;  // v
                  break;
               case 8565 :
                  r  =  "vi";
                  break;
               case 8566 :
                  r  =  "vii";
                  break;
               case 8567 :
                  r  =  "viii";
                  break;
               case 8568 :
                  r  =  "ix";
                  break;
               case 8569 :
                  r  =  120;  // x
                  break;
               case 8570 :
                  r  =  "xi";
                  break;
               case 8571 :
                  r  =  "xii";
                  break;
               case 8572 :
                  r  =  108;  // l
                  break;
               case 8573 :
                  r  =   99;  // c
                  break;
               case 8574 :
                  r  =  100;  // d
                  break;
               case 8575 :
                  r  =  109;  // m
                  break;
            }   // switch adjust
         }   // Roman digits permitted within CJK
      } else if (adjust >= 65281  &&  adjust <= 65374) {  // fullwidth
         // FF01=65281 ... FF5E=65374
         if ((cb < 11904  &&  cf !== 32)   ||
             (cf < 11904  &&  cb !== 32)   ||
             (cb < 11904  &&  cf < 11904  &&
              (cb !== 32  ||  cf !== 32)   &&
              cb !== 60  &&  cb !== 62  &&  cf !== 60  &&  cf !== 62)) {
            // Neighbour not CJK, not sole, not >ruby<
            r  =  adjust - 65248;   // calculate from ASCII
         }   // fullwidth forms permitted within CJK
      }   // adjust type
   }   //  not in whitespace
   return  r;
};   // .w.chr.format()



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




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



mw.libs.WikiSyntaxTextMod.bb.elem  =  function (WSTM) {
   // Particular syntax elements
   // Uses:
   //    .util.fiatObjects()
   // 2012-05-18 [email protected]
   WSTM.util.fiatObjects(WSTM.w,  "elem",
                         { isbn: { }
                         } );


WSTM.w.elem.defaultsort  =  function (adjust, assign) {
   // Check "{{DEFAULTSORT:" code and localize keyword
   // Precondition:
   //    adjust  -- entire expression like "DEFAULTSORT:sortkey}}"
   //    assign  -- keyword like "DEFAULTSORT" or localized
   // Postcondition:
   //    Returns (updated) expression
   // Uses:
   //    >  .w.template.sort
   //    >  .g.wTitle
   //    >< .w.encountered.DEFAULTSORT
   //    .errors.found()
   //    .hooks.fire()
   //    .w.elem.sortkey()
   // 2012-04-24 [email protected]
   var k       =  adjust.indexOf(":");
   var lapsus  =  true;
   var shift;
   var sorter  =  adjust.substr(k + 1);
   var symbol;
   if (typeof(WSTM.w.encountered.DEFAULTSORT) === "string") {
      WSTM.errors.found("defaultsortRepeated",  false,  "{{" + adjust);
   } else {
      if (WSTM.hooks.fire("defaultsort.strict")) {
         symbol  =  WSTM.w.template.sort;
         symbol  =  symbol.substr(1,  symbol.substr(1).indexOf("|"));
      } else {
         symbol  =  assign.toUpperCase();
      }
      sorter  =  sorter.slice(0, -2);
      if (sorter.length) {
         if (sorter.indexOf("\n") < 0) {
            shift  =  this.sortkey(sorter);
            if (shift) {
               sorter  =  shift;
            }
            if (sorter === WSTM.g.wTitle) {
               WSTM.errors.found("defaultsortSuperfluous",
                                 false,
                                 "{{" + adjust);
            } else {
               lapsus  =  false;
            }
         } else {
            WSTM.errors.found("defaultsortLineBreak",
                              false,
                              "{{" + adjust);
         }
      } else {
         WSTM.errors.found("defaultsortEmpty",  false,  "{{" + adjust);
      }
      WSTM.w.encountered.DEFAULTSORT  =  sorter;
   }
   return  (lapsus  ?  adjust  :  symbol + ":" + sorter + "}}");
};   // .w.elem.defaultsort()



WSTM.w.elem.displaytitle  =  function (adjust, assign) {
   // Check "{{DISPLAYTITLE:" code, delete if entirely redundant
   // Precondition:
   //    adjust  -- entire expression like "DISPLAYTITLE:title}}"
   //    assign  -- keyword like "DISPLAYTITLE" or localized
   //    attach  -- detected keyword
   // Postcondition:
   //    Returns false, if to be discarded,
   //            or string with possibly formatted adjust string
   // Uses:
   //    >  .w.template.show
   //    >  .g.wNsNumber
   //    >  .g.wTitle
   //    >< .w.encountered.DISPLAYTITLE
   //     < .mod.lazy
   //    .str.trimL()
   //    .errors.found()
   //    .hooks.fire()
   //    .str.substrEnd()
   //    .str.trimR()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-05-05 [email protected]
   var k       =  adjust.indexOf(":");
   var r       =  adjust;
   var show    =  WSTM.str.trimL(adjust.substr(k + 1),  false);
   var symbol;
   if (typeof(WSTM.w.encountered.DISPLAYTITLE) === "string") {
      WSTM.errors.found("displaytitleRepeated",  false,  "{{" + adjust);
   } else {
      if (WSTM.hooks.fire("displaytitle.localize")) {
         symbol  =  WSTM.w.template.sort;
         symbol  =  symbol.substr(1,  symbol.substr(1).indexOf("|"));
      } else {
         symbol  =  assign.toUpperCase();
      }
      if (WSTM.str.substrEnd(show, 2)  ===  "}}") {
//    if (show.slice(-2) === "}}") {
         show  =  WSTM.str.trimR(show.slice(0, -2),  false,  false);
         if (show.indexOf("\n") < 0) {
            if (show === WSTM.g.wTitle  &&  ! WSTM.g.wNsNumber) {
               r              =  false;
               WSTM.mod.lazy  =  false;
            }
            /*
            k  =  show.charCodeAt(0);
            if ((k >= 48  &&  k <= 57)   ||
                (k >= 65  &&  k <= 90)) {
            }   // digit or capital latin
            */
            WSTM.w.encountered.DISPLAYTITLE  =  show;
         } else {
            WSTM.errors.found("displaytitleDubios",
                              false,
                              "{{" + adjust);
         }
         show  =  show + "}}";
      } else {
         WSTM.errors.found("displaytitleDubios",  false,  "{{" + adjust);
      }
      if (r) {
         r  =  symbol + ":" + show;
      }
   }
   return  r;
};   // .w.elem.displaytitle()



WSTM.w.elem.fair  =  function (all) {
   // Isolate paragraph and headline ranges
   // Precondition:
   //    all  -- WikiTom to be analyzed and subdivided (root)
   // Postcondition:
   //    all  has been subdivided, where appropriate
   // Uses:
   //    .hooks.fire()
   //    .o.WikiTom().find()
   //    .o.WikiTom().flip()
   //    .o.WikiTom().folder()
   //    .o.WikiTom().focus()
   //    .errors.found()
   //    .str.trim()
   //    .w.elem.fragment()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-06-17 [email protected]
   var d;
   var h;
   var j;
   var k;
   var m    =  WSTM.hooks.fire("headline-spacing");
   var n;
   var p;
   var re   =  [ /\n(\n+)/, 1 ];
   var s;
   var got  =  all.find(re, 0, 0, true, false, false);
   while (got) {
      j  =  got.i;
      k  =  got.k;
      n  =  got.m.length;
      if (n > 1) {
         all.flip(k,  j,  n - 1,  "");
      }
      if (j) {
         all.folder(0,  k,  j + 1,  k);
         p  =  all.focus(k);
         if (p) {
            p.limited  =  true;
         }
         k++;
         j  =  1;
      } else {
         j  +=  n + 1;
      }
      got  =  all.find(re, j, k, false, false, false);
   }   // while got
   re   =  [ /([^=])?(=+)([^=\n].*[^=\n]|[^=\n])(=+)([^=\n]+)?\n?/,  0 ];
   got  =  all.find(re, 0, 0, true, false, false);
   while (got) {
      d  =  got.child;
      if (d) {
         j  =  0;
         k  =  got.k + 1;
         this.fair(d.o);
      } else {
         j    =  got.i;
         k    =  got.k;
         n    =  got.m.length;
         got  =  got.r;
         if (got[1]) {
            if (got[1].charCodeAt(0) === 10) {
               j++;
            } else {
               got  =  false;
               if (! j) {
                  j++;
                  n  -=  2;
               }
            }
         } else if (j || k) {
            got  =  false;
         }
         if (got) {
            s  =  got[5];
            if (s) {
               s  =  WSTM.str.trim(s);
               if (s.length) {
                  WSTM.errors.found("headlineEnd",
                                    false,
                                    got[2] + got[3] + got[4]);
                  got  =  false;
               }
            }
            if (got) {
               s  =  got[2];
               h  =  s.length;
               if (h === got[4].length) {
                  n  =  h + got[3].length + h;
                  if (j) {
                     h  =  all.folder(0, k, j, k);
                     if (h) {
                        p  =  all.focus(k);
                        if (p) {
                           p.limited  =  true;
                        }
                     }
                     k++;
                     j  =  0;
                  }
                  if (all.folder(0, k, n, k)) {
                     h  =  all.focus(k);
                     if (h) {
                        p  =  WSTM.str.trim(got[3]);
// .w.polish.strong()   still ???
                        this.fragment(p, false);
                        h.limited  =  true;
                        h.scope    =  "headline";
                        if (m) {
                           if (m > 0) {
                              s  =  s + " " + p + " " + s;
                           } else {
                              s  =  s + p + s;
                           }
                           if (s !== h.toString()) {
                              // no links nor templates defined yet
                              all.flip(k, 0, n, s);
                           }
                        }
                     }
                     k++;
                     j  =  0;
                  }
               } else {
                  WSTM.errors.found("headlineUnequal",
                                    false,
                                    got[2] + got[3] + got[4]);
               }
            }
         }
         if (j) {
            j  +=  n - 2;
         }
      }
      got  =  all.find(re, j, k, true, false, false);
   }   // while got
};   // .w.elem.fair()



WSTM.w.elem.finishing  =  function () {
   // Perform general syntax polish
   // Postcondition:
   //    RegExp was used.
   // Uses:
   //    >  .w.chr.detected.exchange
   //    >  .w.chr.detected.ampersand
   //    >  .w.chr.detected.nbHyphen
   //    >  .w.chr.detected.ordMasc
   //    >< .text
   //    .w.chr.flushEntities()
   //    .w.chr.flushChars()
   //    .hooks.fire()
   //    .util.translate.factory()
   //    .o.WikiTom().replace()
   //    .w.elem.isbn.fire()
   // 2012-06-14 [email protected]
   var c;
   var t;
   var tms  =  [ ["([0-9])&(nbsp|#(160|x0*[aA]0));%",
                  "$1 %"],
                 ["&#x202[89];",
                  "\n"],
                 ["\n\\| *(border|(col|row)span) *= *(1?[0-9]) *\\|",
                  "\n|$1=\"$3\"|"],
                 ["\\bPMID"
                  + "(?::?&nbsp;| *: *)"
                  + "([0-9]{6,10}[ /.,;)\n])",
                  "PMID $1"]
                ];
   if (WSTM.w.chr.detected.nbHyphen) {
      c    =  String.fromCharCode(8209);   // 2011 NON-BREAKING HYPHEN
      t    =  [   [c + "( |\n|<(br|div)\\b)",
                   "-$1"],
                  ["( |\n|/>)" + c,
                   "$1-"]   ];
      tms  =  tms.concat(t);
   }
   if (WSTM.w.chr.detected.ordMasc) {
      c    =  String.fromCharCode(186);   // \xBA &ordm;
      t    =  [  ["([0-9])" + c,
                  "$1°"],
                 ["( |&nbsp;)" + c
                  + "([CFR])\\b",
                  "$1°$2"]    ];
      tms  =  tms.concat(t);
   }
   if (WSTM.w.chr.detected.ampersand) {
      //    new RegExp("&[#A-Za-z]")
      WSTM.w.chr.flushEntities(WSTM.text);
   }
   if (WSTM.w.chr.detected.exchange) {
      WSTM.w.chr.flushChars(WSTM.text);
   }
   t  =  WSTM.hooks.fire("finishing");
   if (t) {
      tms  =  tms.concat(t);
   }
   tms  =  WSTM.util.translate.factory(tms, ".finishing");
   WSTM.text.replace(tms);
   this.isbn.fire(WSTM.text, false);
};   // .w.elem.finishing()



WSTM.w.elem.fixed  =  function (analyze, ahead) {
   // Isolate any indented paragraph
   // Precondition:
   //    analyze  -- WikiTom to be analyzed in detail
   //    ahead    -- true: top level of entire text
   // Postcondition:
   //    analyze  has been subdivided and locked, where appropriate
   // Uses:
   //    >  WSTM.o.WikiTom.TextOnly
   //    .w.elem.fixing()
   // 2012-04-28 [email protected]
   var e;
   var i;
   if (WSTM.text.children) {
      for (i = 0;  i < analyze.children.length;  i++) {
         e  =  analyze.children[i];
         if (e.mode <= WSTM.o.WikiTom.TextOnly) {
            i  =  this.fixing(analyze, i);
         } else if (e.mode <= WSTM.o.WikiTom.Tag) {
            //  this.fixed(e, false); ///////////////////////////////
         }
      }   // for i
   } else {
      this.fixing(analyze, 0);
   }
};   // .w.elem.fixed()



WSTM.w.elem.fixing  =  function (analyze, assign) {
   // Isolate any indented paragraph in string
   // Precondition:
   //    analyze  -- WikiTom to be analyzed partially
   //    assign   -- number of string WikiTom to be analyzed
   // Postcondition:
   //    Returns node number
   //    all  has been subdivided and locked, where appropriate
   //    RegExp was used.
   // Uses:
   //    >  WSTM.o.WikiTom.TextOnly
   //    >  WSTM.o.WikiTom.CodeBlock
   //    .o.WikiTom().find()
   //    .o.WikiTom().focus()
   //    .o.WikiTom().fold()
   //    .o.WikiTom().fork()
   //    .o.WikiTom().folder()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-05-03 [email protected]
   var beg  =  false;
   var c;
   var end  =  false;
   var got  =  0;
   var r    =  assign;
   if (! assign) {
      if (analyze.fetch(0, 0, true)  ===  32) {
         beg    =  { i: 0,  k: 0 };
      }
   }
   if (! beg) {
      got  =  analyze.find("\n ", 2, r, false, true, false);
      if (got) {
         if (analyze.focus(got.k).mode <= WSTM.o.WikiTom.TextOnly) {
            beg  =  { i: got.i,  k: got.k };
         }
      }
   }
   if (beg) {
      end  =  { i: beg.i + 1,  k: beg.k };
      do {
         got  =  analyze.find("\n",  end.i + 1,  end.k,
                              false,  true,  false);
         if (got) {
            c    =  analyze.fetch(got.k,  got.i + 1,  true);
            if (c === 32  ||  c === 10) {
               if (got.k === beg.k) {
                  end  =  { i: got.i,  k: got.k };
               } else {
                  got  =  false;
               }
            } else {
               got  =  false;
            }
            //  if   end.k > beg.k  ->   WSTM.o.WikiTom.TextOnly
         } else {
            end.i  =  analyze.fetch(end.k, 0, false).length;
            got    =  false;
         }
      } while (got);   // do
      if (end.k > beg.k) {
         if (end.i) {
            analyze.fold(end.k, end.i, false);
            end.i  =  0;
         }
         if (beg.i) {
            if (analyze.fold(beg.k, beg.i, true)) {
               beg.k++;
               beg.i  =  0;
            }
         }
         got  =  analyze.fork(beg.k, end.k, "code", false, false);
      } else if (end.i - beg.i  >  3) {
         got  =  analyze.folder(beg.i, beg.k, end.i, beg.k);
      }
      if (got) {
         got.mode    =  WSTM.o.WikiTom.CodeBlock;
         got.lookup  =  false;
      }
   }
   return  r;
};   // .w.elem.fixed()



WSTM.w.elem.fragment  =  function (anchor, alone) {
   // Precondition:
   //    anchor  -- fragment id to be added
   //    alone   -- true:  do not permit existing anchor id
   // Uses:
   //    >< .w.anchors
   //    .errors.found()
   // 2011-03-26 [email protected]
   var i;
   var l  =  false;
   var n  =  WSTM.w.anchors;
   var s  =  anchor.replace( new RegExp("(  +|_)", "g"),  " " );
   if (! alone) {
      s  =  s.replace( /<[^>]+>/, "" ).replace( /{{.+}}/, "" );
   }
   if (WSTM.w.anchors) {
      for (i = 0;  i < n;  i++) {
         l  =  (WSTM.w.anchors[i] === s);
         if (l) {
            if (alone) {
               WSTM.errors.found("anchorRepeated", false, anchor);
            }
            break;
         }
      }   // for i
      if (! l) {
         WSTM.w.anchors.push(s);
      }
   } else {
      WSTM.w.anchors  =  [ s ];
   }
};   // .w.elem.fragment()



WSTM.w.elem.galleries  =  function () {
   // Adapt all <gallery>...</gallery> blocks
   // Precondition:
   //    At least one gallery block has been detected before.
   // Postcondition:
   //    Nodes are modified where suitable.
   //    RegExp was used.
   // Uses:
   //    >  .text
   //           >  .children
   //           >  .mode
   //           >  .scope
   //    >  .WikiTom.TagBinary
   //    >< .l10n.word.file
   //    .o.WikiTom().getCount()
   //    .l10n.word.fetch()
   //    .w.elem.gallery()
   // 2012-06-05 [email protected]
   var i;
   var p;
   if (! WSTM.l10n.word.file) {
      WSTM.l10n.word.file  =  WSTM.l10n.word.fetch("File", 0);
   }
   for (i = WSTM.text.getCount() - 1;  i >= 0;  i--) {
      p  =  WSTM.text.children[i];
      if (p.mode === WSTM.o.WikiTom.TagBinary) {
         if (p.scope) {
            if (p.scope === "gallery") {
               this.gallery(p, WSTM.l10n.word.file);
            }
         }
      }
   }   // for i
};   // .w.elem.galleries()



WSTM.w.elem.gallery  =  function (adjust, area) {
   // Adapt one <gallery>...</gallery> block
   // Precondition:
   //    adjust  -- WikiTom to be analyzed (gallery parent)
   //               >  .children
   //               >< .mode
   //               >< .source
   //    area    -- namespace keyword, before ':'
   // Postcondition:
   //    Nodes are modified where suitable.
   //    RegExp was used.
   // Uses:
   //    >  .g.re.File
   //    >  .mod.luxury
   //    >  .o.WikiTom.LinkFile
   //     < .mod.lazy
   //    .o.WikiTom().fresh()
   //    .str.isBlank()
   //    .str.makeString()
   //    .str.trimL()
   //    .str.trimR()
   //    .w.link.wiki.decode()
   //    .w.link.replace.flipper()
   //    .str.setString()
   //    .o.WikiTom().folder()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-04-25 [email protected]
   var i;
   var indent   =  0;
   var j;
   var k;
   var m;
   var next;
   var q        =  adjust.children;
   var s;
   var seek;
   var shift    =  "";
   var single;
   var show;
   var swift;
   var t;
   for (k = 0;  k < q.length;  k++) {   // first run
      t  =  q[k];
      if (! t.mode) {
         s  =  t.source;
         j  =  (s.indexOf("\n\n") >= 0);
         if (j) {
            s  =  s.replace(/\n\n+/g, "\n");
         }
         if (j) {
            t.fresh( s );
         }
         s  =  "\n" + t.source + "|";
         j  =  0;
         while (j >= 0) {
            j  =  s.indexOf("\n", j);
            if (j >= 0) {
               i  =  0;
               j++;
               for (  true;  true;  j++) {
                  if (WSTM.str.isBlank(s.charCodeAt(j), false)) {
                     i++;
                     if (i > indent) {
                        indent  =  i;
                     }
                  } else {
                     break;   // for j
                  }
               }   // for j
            }   // fetch single line
         }   // while  \n
      }
   }   // for k
   if (indent) {
      shift  =  WSTM.str.makeString(32, indent);
   }   // for k
   for (k = q.length-1;  k >= 0;  k--) {   // second run
      t  =  q[k];
      if (! t.mode) {
         next    =  t.source.length;
         j       =  next;
         while (j >= 0) {
            j   =  t.source.lastIndexOf("\n", j);
            if (j < 0) {
               single  =  t.source.substring(0,  next);
            } else {
               single  =  t.source.substring(j + 1,  next);
            }
            if (single) {
               i  =  single.indexOf("|");
               if (i > 0) {
                  show  =  WSTM.str.trimL(single.substr(i + 1),  true);
                  if (show.length) {
                     show  =  "|" + show;
                  } else {
                     show  =  "";
                  }
                  swift  =  WSTM.str.trimR(single.substr(0, i),
                                           false,  false);
               } else {
                  show   =  "";
                  swift  =  single;
               }
               i      =  swift.indexOf(":");
               swift  =  WSTM.str.trimL(swift.substr(i + 1),  true);
               s      =  WSTM.w.link.wiki.decode(swift, true, false,
                                                 false, true);
               if (s) {
                  swift  =  s;
               }
               if (WSTM.mod.hyper) {
                  seek  =  area + ":" + swift;
                  s     =  WSTM.w.link.replace.flipper(seek,
                                                       false,
                                                       false,
                                                       false);
                  if (s) {
                     swift  =  s.substr(area.length + 1);
                  }
               }
if (WSTM.config) {
if (WSTM.config.xEvaluation) {
               swift  =  area + ":" + swift;
}
}
               show   =  shift + swift + show;
               if (show !== single) {
                  t.fresh( WSTM.str.setString(t.source,
                                              j + 1,
                                              next - j - 1,
                                              show) );
                  WSTM.mod.lazy  =  false;
               }
               if (WSTM.mod.luxury) {
                  i  =  j + 1 + indent;
                  m  =  adjust.folder(i,  k,  i + swift.length,  k);
                  if (m) {
                     m.mode    =  WSTM.o.WikiTom.LinkFile;
                     m.lookup  =  false;
                     t  =  q[k];
                  }
               }
            }
            next  =  j;
            j--;
         }   // while  \n
      }
   }   // for k
};   // .w.elem.gallery()



WSTM.w.elem.imagemaps  =  function () {
   // Adapt all <imagemap>...</imagemap> blocks
   // Precondition:
   //    At least one imagemap block has been detected before.
   // Postcondition:
   //    Nodes are modified where suitable.
   //    RegExp was used.
   // Uses:
   //    >  .text
   //           >  .children
   //           >  .mode
   //           >  .scope
   //    >  .WikiTom.TagBinary
   //    >< .l10n.word.file
   //    .o.WikiTom().getCount()
   //    .l10n.word.fetch()
   //    .w.elem.imagemap()
   // 2012-06-20 [email protected]
};   // .w.elem.imagemaps()



WSTM.w.elem.redirect  =  function (all) {
   // Standardize #REDIRECT statement
   // Precondition:
   //    all  -- WikiTom to be analyzed and standardized (root)
   // Postcondition:
   //    Modifies text, if appropriate
   //    RegExp was used.
   // Uses:
   //    .WikiTom().fetch()
   //    .WikiTom().flip()
   //    .WikiTom().fresh()
   //    .l10n.word.fetch()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-03-23 [email protected]
   var got;
   var re;
   var s      =  all.fetch(0, 0);
   var shift;
   var start;
   if (s.charCodeAt(0) === 35) {   // '#'
      re   =  new RegExp("("  +  WSTM.l10n.word.fetch("REDIRECT", 1)
                         +  "):? *\\[\\[ *",
                         "i");
      got  =  re.exec(s);
      if (got) {
         if (got.index === 1) {
            start  =  got[0];
            shift  =  WSTM.l10n.word.fetch("REDIRECT", 0) + ": [[";
            if (start !== shift) {
               all.flip(0, 1, start.length, shift);
               all.fresh();
            }   // non-standard
         }   // heading
      }
   }   // '#'
};   // .w.elem.redirect()



WSTM.w.elem.references  =  function (all) {
   // Adapt all <references>...</references> blocks
   // Precondition:
   //    At least one references block has been detected before.
   // Postcondition:
   //    Nodes are modified where suitable.
   //    RegExp was used.
   // Uses:
   //    >  .text
   //          >  .children
   //          >  .mode
   //          >  .scope
   //          >< .source
   //    >  .WikiTom.TagBinary
   //     < .mod.lazy
   //    .o.WikiTom().getCount()
   //    .o.WikiTom().fresh()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2011-06-05 [email protected]
   var i;
   var k;
   var lead;
   var m;
   var p;
   var q;
   var refBeg  =  /([^ \n>]) *(<\/?ref?[ \n>])/g;
   var refEnd  =  /(<\/?ref[^>\n]*>) *([^ \n>])/g;
   var s;
   var t;
   for (i = WSTM.text.getCount() - 1;  i >= 0;  i--) {
      p  =  WSTM.text.children[i];
      if (p.mode === WSTM.o.WikiTom.TagBinary) {
         if (p.scope) {
            if (p.scope === "references") {
               q     =  p.children;
               lead  =  true;
               m     =  0;
               for (k = 0;  k < q.length;  k++) {
                  t  =  q[k];
                  if (! t.mode) {
                     s  =  t.source;
                     if (lead) {
                        if (s.charCodeAt(0) !== 10) {
                           s  =  "\n" + s;
                        }
                     }
                     lead  =  false;
                     s     =  s.replace(refBeg, "$1\n$2")
                               .replace(refEnd, "$1\n$2");
                     if (s !== t.source) {
                        t.fresh(s);
                        WSTM.mod.lazy  =  false;
                     }
                     m  =  k;
                  }
               }   // for k
               t  =  q[m];
               s  =  t.source;
               if (s.charCodeAt(s.length - 1)  !==  10) {
                  t.fresh(s + "\n");
                  WSTM.mod.lazy  =  false;
               }
            }
         }
      }
   }   // for i
};   // .w.elem.references()



WSTM.w.elem.refgroups  =  function (arglist) {
   // Bookkeeping of <references group=>
   // Precondition:
   //    arglist  -- tags object
   //                >  .props
   // Postcondition:
   //    Returns refgroup ID, or "><" for global
   // Uses:
   //    >< .w.encountered.refgroups
   //    .w.tags.furnished()
   //    .str.trim()
   //    .errors.found()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-05-11 [email protected]
   var s;
   var r  =  "><";
   if (arglist.props) {
      s  =  WSTM.str.trim(WSTM.w.tags.furnished(arglist.props, "group"),
                          true);
      if (s.length) {
         r  =  s;
      }
   }
   if (WSTM.w.encountered.refgroups) {
      if (WSTM.w.encountered.refgroups[r]) {
         if (r === "><") {
            s  =  "";
         } else {
            s  =  "'" + r + "'";
         }
         WSTM.errors.found("referencesRepeated", false, s);
      } else {
         WSTM.w.encountered.refgroups[r]  =  true;
      }
   } else {
      WSTM.w.encountered.refgroups     =  { };
      WSTM.w.encountered.refgroups[r]  =  true;
   }
   return  r;
};   // .w.elem.refgroups()



WSTM.w.elem.sortkey =  function (adjust) {
   // Retrieve key for sorting (currently dewiki only)
   // Precondition:
   //    adjust  -- string to be checked or modified
   // Postcondition:
   //    Returns information about sortable string
   //            false   if nothing to do, adjust is fine
   //            string  changes against adjust
   //    RegExp is not modified
   // Uses:
   //    >  .g.wTitle
   //    .str.sortString()
   // 2012-05-03 [email protected]
   var s      =  adjust.substr(0, 1);
   var learn  =  (s === WSTM.g.wTitle);
   var shift  =  adjust;
   var sup    =  s.toUpperCase();
   var sort;
   if (s !== sup) {
      shift  =  sup + shift.substr(1);
      learn  =  true;
   }   // capitalize
   sort  =  WSTM.str.sortString(shift);
   if (sort) {
      shift  =  sort;
      s      =  shift.substr(0, 1);
      sup    =  s.toUpperCase();
      if (s !== sup) {
         shift  =  sup + shift.substr(1);
      }   // capitalize
      learn  =  true;
   }   // char changed
   return  (learn ? shift : false);
};   // .w.elem.sortkey()



WSTM.w.elem.isbn.fire  =  function (analyze, access) {
   // Find ISBN magic codes, exchange against improvements
   // Precondition:
   //    analyze  -- WikiTom to be analyzed
   //    access   -- object  { i, k }  with start position, or false
   // Postcondition:
   //    Nodes are modified where suitable.
   //    RegExp was used.
   // Uses:
   //    >  .g.re.ISBN
   //    .o.WikiTom().find()
   //    .w.elem.isbn.fire()  -- recursive
   //    .w.elem.isbn.format()
   //    .o.WikiTom().flip()
   // 2012-05-03 [email protected]
   var deep;
   var details;
   var got;
   var suggest;
   var target   =  [ WSTM.g.re.ISBN, 0 ];
   if (access) {
      got  =  access;
   } else {
      got  =  { i: 0,  k: 0 };
   }
   do {
      got  =  analyze.find(target, got.i, got.k, true, false, false);
      if (got) {
         deep  =  got.child;
         if (deep) {
            this.fire(deep.o, deep);
            got.i  =  0;
            got.k++;
         } else {
            details  =  got.r;
            suggest  =  this.format(details);
            if (suggest) {
               analyze.flip(got.k, got.i, details[0].length, suggest);
               got.i  +=  suggest.length + 6;
            } else {
               got.i  +=  6;
            }
         }
      }
   } while (got);   // do
};   // .w.elem.isbn.fire()



WSTM.w.elem.isbn.format  =  function (adjust) {
   // Check and reformat ISBN magic code
   // Precondition:
   //    adjust  -- regexp result array
   //                [0]  entire context
   //                [1]  prolog
   //                     preceding non-whitespace  ('|': template)
   //                [2]  "ISBN"
   //        6 10 14 [3]  10 | 13
   //              4 [4]  '=' assignment, if any
   //             15 [5]  I-S-B-N
   //             17 [6]  epilog
   // Postcondition:
   //    Returns  string  reformatted changed sequence (adjust[0])
   //                     (without last digit and epilog **+????***)
   //                     insert hyphens etc., spaces replaced by hyphens
   //                     x->X
   //                     hyphens inserted before language, checknumber
   //                             at ISBN-13
   //             false   adjust is invalid or unchanged
   // Uses:
   //    .util.isbn.format()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-05-23 [email protected]
   var lapsus   =  false;
   var liaison  =  (typeof(adjust[4]) === "string");
   var need     =  adjust[3];
   var r;
   var score    =  adjust[5];
   var stuff;
   if (! liaison) {
      lapsus  =  true;
   }
   if (need) {
      need  =  Number(need);
   }
   r  =  WSTM.util.isbn.format(score, need);
   if (r[0]) {
      if (r[1]) {
         lapsus  =  true;
         score   =  r[1];
      } else if (typeof(adjust[11]) === "string") {
         if (adjust[11] !== " ") {
            lapsus  =  true;
         }
      } else {
         lapsus  =  true;
      }
   } else {
      lapsus  =  false;
   }
   if (lapsus) {
      stuff   =  adjust[1];
      if (stuff.charCodeAt(0) === 124  &&  liaison) {   // "|"   template
         stuff  =  stuff + adjust[2] + adjust[4];
      } else {
         stuff  =  stuff + "ISBN ";
      }   // template ?
      stuff  =  stuff + score + adjust[6];
      if (adjust[0] === stuff) {
         r  =  false;
      } else {
         r  =  stuff;
      }
   } else {
      r  =  false;
   }   // validity
   return  r;
};   // .w.elem.isbn.format()



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



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



mw.libs.WikiSyntaxTextMod.bb.link  =  function (WSTM) {
   // Analysis of link -- web and wiki
   // Uses:
   //    .util.fiatObjects()
   // 2012-05-24 [email protected]
   WSTM.util.fiatObjects(WSTM.w,  "link",
                         { namespace: { },
                           replace:   { },
                           web:       { },
                           wiki:      { }
                         } );
   WSTM.w.link.nesting  =  50;



WSTM.w.link.fence  =  function (address, access, alone) {
   // Detect termination of any link (URL or wiki)
   // Precondition:
   //    address  -- string with link and aftermath
   //    access   -- link type   0: unknown   1: URL   2: wikilink
   //    alone    -- true: detect target only   false: keep title
   // Postcondition:
   //    Returns false       entire string appears to be link target
   //            number > 0  index of termination before string end
   // Requires: JavaScript 1.3   charCodeAt()
   // 2011-03-02 [email protected]
   var c;
   var i;
   var m;
   var r  =  false;
   var s;
   var scheme;
   if (address.length > 0) {
      m  =  access;
      s  =  address;
      if (alone) {
         if (m === 0) {
            m  =  2;
            i  =  address.indexOf("://");
            if (i > 0) {   // URL
               if (i < 6) {
                  scheme  =  address.substr(0, i);
                  if (scheme === "ftp"  ||
                      scheme === "http"  ||
                      scheme === "https") {
                     m  =  1;
                  }
               }
            }
         }   // determine link type
         i  =  address.indexOf((m === 1  ?  " "  :  "|"));
         if (i > 0) {
            r  =  i;
            s  =  address.substr(0, r);
         }
      }   // target only
      i  =  s.indexOf("\n");
      if (i > 0) {
         r  =  i;
         s  =  s.substr(0, r);
      }
      i  =  s.indexOf("]");
      if (i > 0) {
         r  =  i;
         s  =  s.substr(0, r);
      }
      i  =  s.indexOf("<");
      if (i > 0) {
         c = s.charCodeAt(i + 1);
         if (c === 47) {   // '/'
            c  =  s.charCodeAt(i + 2);
         }
         if (c > 96  &&  c < 123) {   // 'a' ... 'z'
            r  =  i;
         }
      }
   }   // content
   return  r;
};   // .w.link.fence()



WSTM.w.link.fenced  =  function (adjust, access, above, adhere) {
   // Find '[' in WikiTom, analyze and process links
   // Precondition:
   //    adjust  -- WikiTom top element
   //    access  -- location object
   //               .i  position to start searching for "["
   //               .k  sibling number
   //    above   -- top level
   //    adhere  -- true: freeze link targets
   // Uses:
   //    >< .w.link.nesting
   //    .o.WikiTom().find()
   //    .w.link.fenced()   -- recursive
   //    .adjust.focus()
   //    mw.log()
   //    .w.link.format()
   // 2012-05-24 [email protected]
   var deep;
   var lock  =  adhere;
   var open  =  access;
   do {
      open  =  adjust.find("[", open.i, open.k, true, false, false);
      if (open) {
         deep  =  open.child;
         if (deep) {
            if (WSTM.w.link.nesting > 0) {
               WSTM.w.link.nesting--;
               this.fenced(deep.o, deep, false, lock);
               open.i  =  0;
               open.k++;
               WSTM.w.link.nesting++;
            } else if (! WSTM.w.link.nesting) {
               mw.log(WSTM.debugging,
                      ".w.link.fenced()    nesting level exhausted  c="
                      + open.i,
                      2,
                      adjust.focus(open.k));
               open.i++;
            }
         } else {
            open  =  this.format(adjust, open, false, lock, false);
            if (open.target) {
               lock  =  true;
            }
         }
      }   // open
   } while (open);   // do
};   // .w.link.fenced()



WSTM.w.link.filter  =  function (adjust, all) {
   // Remove undesired chars from wikilink and URL
   // Precondition:
   //    adjust  -- string with link target
   //    all     -- true: titled wikilink or File location
   // Postcondition:
   //    Returns  false   if nothing to do,
   //             string  adjusted identifier
   //    RegExp was used.
   // Uses:
   //    .str.trimL()
   // Requires: JavaScript 1.3   fromCharCode()
   // 2011-07-20 [email protected]
   var r;
   var re;
   var scan  =  WSTM.str.trimL(adjust, true);
   var shy   =  String.fromCharCode(173);   // &shy;
   if (scan.indexOf(shy) >= 0) {
      re  =  new RegExp(shy, "g");
      if (re.test(scan)) {
         scan  =  adjust.replace(re, "");
      }   // remove shy
   }   // shy
   if (scan.indexOf("&") >= 0) {
      if (scan.indexOf("&#x") >= 0) {
         re  =  new RegExp("&#x(AD|2028);", "g");   // shy EOL
         if (re.test(scan)) {
            scan  =  scan.replace(re, "");
         }   // remove
/*
            if (scan.indexOf("&#x200") >= 0) {
               var got;
               re   =  new RegExp("&#x(200[ABC]);", "g");
               got  =  re.exec(scan);
               // 200A   8203  ZERO WIDTH SPACE  used in bo:
               // 200B   8204  ZERO WIDTH NON-JOINER  used in Farsi, kn:
               // 200C   8205  ZERO WIDTH JOINER      used in ml:
               if (got !== null) {
                  scan  =  scan.replace(re,
                              String.fromCharCode(parseInt(got[1], 16)));
               }   // replace
            }   // &#x200
*/
      }   // &#x
      if (all) {
         if (scan.indexOf("&nbsp;") >= 0) {
            re  =  new RegExp("&nbsp;", "g");
            if (re.test(scan)) {
               scan  =  scan.replace(re, " ");
            }   // remove
         }   // &nbsp;
      }   // titled wikilink or File location
   }   // &
   r  =  (scan === adjust  ?  false  :  scan);
   return  r;
};   // .w.link.filter()



WSTM.w.link.fire  =  function (adjust, above, adhere, arg) {
   // Format and process any internal and external link
   // Precondition:
   //    adjust  -- WikiTom top element
   //    above   -- top level
   //    adhere  -- true: freeze link targets in this context
   //    arg     -- template parameter
   // Postcondition:
   //    Nodes are modified where suitable.
   //    RegExp was used.
   // Uses:
   //    >< .w.link.reHead
   //    >< .w.link.web.re
   //    >< .o.Wikilink.instance
   //    .w.link.fenced()
   //    .w.link.web.free()
   // Requires: JavaScript 1.5   RegExp non-capturing parenthese
   // 2012-05-18 [email protected]
   if (! this.reHead) {
      this.reHead  =  new RegExp("^( +)?"
                                 + "(?:(\\[)"
                                    + "|"
                                    + "((?:(?:ht|f)tps?:)?//))",
                                 "i");
      this.web.re  =  new RegExp("((^|[^:])(\\b(?:https?|ftp):)?)//",
                                 "i");
   }
   if (! WSTM.o.Wikilink.instance) {
      WSTM.o.Wikilink.instance  =  new WSTM.o.Wikilink();
   }
   this.fenced(adjust,
               { i: 0,  k: 0 },
               above,
               adhere);   // '['
   this.web.free(adjust,
                 { i: 0,  k: 0 },
                 true,
                 adhere,
                 arg);   // "http://"
};   // .w.link.fire()



WSTM.w.link.linked  =  function (about) {
   // Check whether WikiTom is some link target
   // Precondition:
   //    about  -- WikiTom element
   // Postcondition:
   //    Returns true if about is wikilink
   // Uses:
   //    >  .o.WikiTom().mode
   //    >  .o.WikiTom.LinkWiki
   //    >  .o.WikiTom.LinkWeb
   // 2012-04-22 [email protected]
   return  (about.mode >= WSTM.o.WikiTom.LinkWiki  &&
            about.mode <= WSTM.o.WikiTom.LinkWeb);
};   // .w.link.linked()



WSTM.w.link.project  =  function (affiliate, assign) {
   // Is the current wiki project matched, or abbreviated
   // Precondition:
   //    affiliate  -- project name, also abbreviated
   //    assign     -- return also reformatted namespace
   // Postcondition:
   //    Returns false     unknown project or language or space
   //            array[2]  project identified
   //                      [0]  mode
   //                           1      affiliate is already abbreviation
   //                           2      full name, abbreviated
   //                           3      commons  meta  mediawiki
   //                           false  namespace if assign
   //                      [1]  false   if current wiki project matches
   //                           string  abbreviated name or
   //                                   re-formatted namespace if assign
   // Uses:
   //    >  .g.projType
   // 2011-10-06 [email protected]
   var r       =  false;
   var m       =  -99;
   var scope;
   var sister  =  affiliate.toLowerCase();
   if (sister === WSTM.g.projType) {
      sister  =  false;
      m       =  2;
   } else if (sister.length < 8) {   // abbreviated
      scope  =  false;
      if (sister.length === 1) {
         sister  =  affiliate;
         // ":sv:S:t Eriksplan (tunnelbanestation)"
      }
      switch (sister) {
         case "commons" :
            scope  =  "commons";
            m      =  3;
            break;
         case "b" :
            scope  =  "wikibooks";
            break;
         case "n" :
            scope  =  "wikinews";
            break;
         case "m" :
            scope   =  "meta";   // meta.wikimedia.org
            sister  =  "meta";
            m       =  3;
            break;
         case "mw" :
            scope  =  "mediawiki";   // mediawiki.org
            m      =  3;
            break;
         case "q" :
            scope  =  "wikiquote";
            break;
         case "s" :
            scope  =  "wikisource";
            break;
         case "v" :
            scope  =  "wikiversity";
            break;
         case "w" :
            scope  =  "wikipedia";
            break;
         case "wikt" :
            scope  =  "wiktionary";
            break;
      }   // switch sister
      if (scope  &&  m < 0) {
         m  =  1;
      }
      if (scope === WSTM.g.projType) {
         sister  =  false;
      } else if (sister === WSTM.g.projType) {
         sister  =  false;
         m       =  2;
      }
   }
   if (sister) {
      if (m < 0) {
         m  =  2;
         switch (sister) {
            case "wikipedia" :
               sister  =  "w";
               break;
            case "wikibooks" :
            case "wikinews" :
            case "wikiquote" :
            case "wikisource" :
            case "wikiversity" :
               sister  =  sister.substr(4, 1);
               break;
            case "wiktionary" :
               sister  =  "wikt";
               break;
            case "meta" :
               sister  =  "meta";
               m       =  3;
               break;
            default:
               m  =  -1;
               break;
         }   // switch sister
      }   // find abbreviation
      if (m > 0) {
         r  =  [m, sister];
      }   // identified
   } else {
      r  =  [m, false];
      if (assign) {   // namespace reformatting?
         if (m === 2) {
            if (affiliate.toLowerCase() === WSTM.g.projType) {
               r  =  false;
            } else {   // reformatting
               r  =  [ false, WSTM.g.projType ];
            }   // space
         }
      }
   }
   return  r;
};   // .w.link.project()



WSTM.w.link.namespace.fetch  =  function (assigned, at) {
   // Retrieve assigned appropriate namespace keyword
   // Precondition:
   //    assigned  -- keyword code (number)
   //                 1  File etc.
   //                 2  Category etc.
   //                 3  Special etc.
   //                 4  Page etc.
   //    at        -- project identifier, if any; lower case only
   //                 false or ""  -- same project, same language
   //                 "commons:"   -- shift to "File:"
   //                 "s:it:"      -- keep local
   //                 ":en:"       -- shift to "File:"
   //                 etc.
   // Postcondition:
   //    Returns  adjcent keyword  or  false
   //             string according to assigned and at
   //                    English standard for: commons en simple
   //                            "File" if detected
   //                            "Category" if detected
   //                    localized keyword, else English
   //             false  if project not recognized
   // Uses:
   //    >  .g.trslKw[]
   //    >  .g.projType
   //    .str.substrEnd()
   // 2011-12-31 [email protected]
   var m;   // 0: local   1: en   2: project, keep
   var n;
   var q;
   var r  =  false;
   if (assigned > 0) {
      n  =  2;
      if (WSTM.g.projType === "wikisource") {
          n++;
      } else if (at) {
         if (at.substr(0, 2) === "s:") {
            n++;
         }
      }
      if (assigned <= n) {
         m  =  0;
         switch (at) {
            case false :
               break;   // switch at
            case "commons:" :
            case "commons" :
            case "en" :
            case ":en:" :
            case ":simple:" :
            case "simple" :
               m  =  1;
               break;   // switch at
            default:
               if (WSTM.str.substrEnd(at, 4)  ===  ":en:") {
//             if (at.slice(-4) === ":en:") {

                  m  =  1;
               } else if (WSTM.str.substrEnd(at, 8)  ===  ":simple:") {
//             } else if (at.slice(-8) === ":simple:") {
                  m  =  1;
               } else {
                  m  =  2;
               }
               break;   // switch at
         }   // switch at
         switch (m) {
            case 0 :   // local
               q  =  WSTM.g.trslKw[assigned - 1];
               r  =  q[1];
               break;   // switch m
            case 1 :   // en
               switch (assigned) {
                  case 1 :
                     r  =  "File";
                     break;   // switch adjust
                  case 2 :
                     r  =  "Category";
                     break;   // switch adjust
                  case 3 :
                     r  =  "Special";
                     break;   // switch adjust
                  case 4 :
                     r  =  "Page";
                     break;   // switch adjust
               }   // switch adjust
               break;   // switch m
         }   // switch m
      }   // assigned in range
   }   // assigned valid
   return  r;
};   // .w.link.namespace.fetch()



WSTM.w.link.namespace.furnish  =  function (ahead) {
   // Retrieve keyword code if "File" or "Category" or localized
   // Precondition:
   //    ahead  -- string  keyword only, no ":"
   // Postcondition:
   //    Returns  code   1=File 2=Category
   //             false, if not detected
   // Uses:
   //    >  WSTM.g.trslKw[]
   // 2011-12-31 [email protected]
   var i;
   var q;
   var r  =  false;
   var s  =  "|" + ahead.toLowerCase() + "|";
   for (i = 0;  i < 3;  i++) {
      q  =  WSTM.g.trslKw[i];
      if (q[0].indexOf(s) >= 0) {
         r  =  i + 1;
         break;   // for i
      }
   }   // for i
   return  r;
};   // .w.link.namespace.furnish()



WSTM.w.link.replace.factory  =  function (apply) {
   // Validate user defined link replacement request
   // Precondition:
   //    apply  -- .raw   array with user defined link replacements
   //                     Each element is an array with two elements
   //                     Both elements are either
   //                     string  with
   //                             [0] link full regexp
   //                             [1] replacement
   //                     array  with 3/4 elements,
   //                             each pairwise scan/replace
   //                            [0] prolog regexp string / replacement
   //                                or  false / false
   //                            [1] link full regexp / replacement
   //                            [2] epilog regexp / replacement
   //                                or  false / false
   //                            [3] true: search case sensitive
   //                                (apply[][0] only)
   //              .name  name of user defined request variable
   // Postcondition:
   //    Returns  apply.parsed
   //     < apply.parsed  array with validated elements.
   //                     Both elements are arrays of length 3.
   // Uses:
   //    .util.isArray()
   //    .main.fault()
   // TODO:
   //    Split by recognized namespace
   // 2012-05-26 [email protected]
   var a;
   var e;
   var f;
   var i;
   var j;
   var m;
   var r  =  [ ];
   var t;
   var u  =  apply.raw;
   var n  =  u.length;
   for (i = 0;  i < n;  i++) {
      a  =  u[i];
      if (typeof(a) !== "object") {
         a  =  false;
      }
      if ( ! WSTM.util.isArray(a)) {
         WSTM.main.fault("Invalid Syntax in user definition element #"
                         + i,
                         apply.name);
         a  =  [false, false];
      }
      f  =  a[0];
      t  =  a[1];
      m  =  typeof(t);
      if (typeof(f) === "string"   &&
          (m === "string"  ||  m === "function")) {
         f  =  [false, f, false, false];
         t  =  [false, t, false];
      } else if (WSTM.util.isArray(f) && WSTM.util.isArray(t)) {
         m  =  f.length;
         if ((m === 3  ||  m === 4)   &&   t.length === 3) {
            if (m === 3) {
               f  =  [f[0], f[1], f[2], false];
            }
            for (j = 0;  j < 3;  j++) {
               e  =  f[j];
               if (typeof(e) === "string") {
                  if (e.length === 0  &&  j === 1) {
                     f  =  false;
                     break;   // for j
                  }
               } else if (e) {   // invalid type
                  f  =  false;
                  break;   // for j
               } else if (j === 1) {   // link regexp false
                  f  =  false;
                  break;   // for j
               }
            }   // for j
            for (j = 0;  j < 3;  j++) {
               e  =  t[j];
               if (e) {
                  m  =  typeof(e);
                  if (m !== "string"  &&  m !== "function") {
                     f  =  false;
                     WSTM.main.fault("Invalid user definition element #"
                                     + i,
                                     apply.name);
                  }
               }
            }   // for j
         } else {
            f  =  false;
         }
      } else {   // invalid format
         f  =  false;
      }   // string or array
      if (f) {
         m  =  (f[3] ? "i" : "");
         for (j = 0;  j < 3;  j++) {
            e  =  f[j];
            if (typeof(e) === "string") {
               switch (j) {
               case 0:   // prolog
                  e  =  e + "\f";
                  break;
               case 1:   // link
                  e  =  "^" + e + "$";
                  break;
               case 2:   // epilog
                  e  =  "\f" + e;
                  break;
               }   // j
               try {
                  f[j]  =  new RegExp(e, m);
               } catch (err) {
                  WSTM.main.fault("Invalid user definition element #" + i
                                  + "\nUser link RegExp\n" + err
                                  + "\n>>>" + e + "<<<\n" + f,
                                  apply.name);
                  f  =  false;
               }
            }
         }   // for j
         if (f) {
            r.push([ [f[0], f[1], f[2], f[3]],
                     [t[0], t[1], t[2]] ]);
         }
      }   // valid
   }   // for i
   r             =  (r.length ? r : false);
   apply.parsed  =  (r.length ? r : false);
   return  r;
};   // .w.link.replace.factory()



WSTM.w.link.replace.flip  =
   function (apply, adjust, ahead, after, about) {
   // Perform user defined link replacement
   // Precondition:
   //    apply   -- array with user defined link replacements
   //               Each element is an array with two elements
   //               Both elements are
   //               array  with 3 elements, each pairwise scan / replace
   //                      [0] prolog regexp string / replacement
   //                          or  false / false
   //                      [1] link full regexp / replacement
   //                      [2] epilog regexp / replacement
   //                          or  false / false
   //               Array is validated
   //    adjust  -- current link target
   //    ahead   -- prolog, may be false
   //    after   -- epilog, may be false
   //    about   -- informative hint for user defined functions
   // Postcondition:
   //    Returns  false     if not changed,
   //             string    adjusted link specification only
   //             array[3]  prolog and/or epilog modified also
   // Uses:
   //     < .mod.lazy
   //    .str.trimL()
   //    .w.link.fence()
   // 2012-05-30 [email protected]
   var r  =  false;
   var a;
   var e;
   var f;
   var i;
   var n  =  apply.length;
   var q  =  [(ahead  ?  ahead + "\f"  :  "\f"),
              adjust,
              (after  ?  "\f" + after  :  "\f")];
   var t;
   for (i = 0;  i < n;  i++) {
      a  =  apply[i];
      f  =  a[0];
      e  =  f[1];
      r  =  e.test(q[1]);
      if (r) {   // target match
         e  =  f[0];
         if (e) {   // prolog present
            r  =  e.test(q[0]);   //   e.test(ahead);
         }
         if (r) {   // target and prolog match
            e  =  f[2];
            if (e) {   // epilog present
               r  =  e.test(q[2]);   //   e.test(after);
            }
         }
      }
      if (r) {   // every request matching
         t  =  a[1];
         e  =  typeof(t[1]);
         if (e === "string") {
            q[1]  =  q[1].replace(f[1], t[1]);
         } else if (e === "function") {
            q[1]  =  q[1].replace(f[1],
                                  t[1](about, i, 0, q[1]));
         }
         if (q[0] && f[0]) {
            e  =  typeof(t[0]);
            if (e === "string") {
               q[0]  =  q[0].replace(f[0],  t[0] + "\f");
            } else if (e === "function") {
               q[0]  =  q[0].replace(f[0],
                                     t[0](about, i, -1, q[0]) + "\f");
            }
         }
         if (q[2]  &&  f[2]) {
            if (typeof(t[2]) === "string") {
               q[2]  =  q[2].replace(f[2],  "\f" + t[2]);
            } else if (e === "function") {
               q[2]  =  q[2].replace(f[2],
                                     "\f" + t[2](about, i, 1, q[2]));
            }
         }
         r  =  q[1].lastIndexOf("[") + 1;
         if (r > 0) {
            e     =  q[1].substr(0, r)  +  "\f";
            q[1]  =  q[1].substr(r);
            if (q[0]) {
               q[0]  =  q[0].substr(0,  q[0].length - 1)   +   e;
            } else {
               q[0]  =  e;
            }
         }
         r  =  WSTM.w.link.fence(q[1], 0, true);
         if (r) {
            e     =  "\f"  +  WSTM.str.trimL(q[1].substr(r), false);
            q[1]  =  q[1].substr(0, r);
            if (q[2]) {
               q[2]  =  e + q[2].substr(1);
            } else {
               q[2]  =  e;
            }
         }
         r  =  false;
      }   // match
   }   // for i
   if (q[0]  ===  (ahead  ?  ahead + "\f"  :  "\f")) {
      q[0]  =  false;
   }
   if (q[2]  ===  (after  ?  "\f" + after  :  "\f")) {
      q[2]  =  false;
   }
   if (q[0] || q[2]) {
      if (q[0]) {
         q[0]  =  q[0].substr(0,  q[0].length - 1);
      }
      if (q[2]) {
         q[2]  =  q[2].substr(1);
      }
      r  =  q;
   } else if (q[1] !== adjust) {
      r  =  q[1];
   }
   if (r) {
      WSTM.mod.lazy  =  false;
   }
   return  r;
};   // .w.link.replace.flip()



WSTM.w.link.replace.flipper  =  function (adjust, ahead, after, area) {
   // Perform user defined link replacement request (WSTM.4 type)
   // Precondition:
   //    adjust  -- current link target
   //    ahead   -- prolog, may be false
   //    after   -- epilog, may be false
   //    area    -- canonical namespace name, may be false
   //               "File", "Template", "Category"
   //    Replacement Array is parsed and validated
   // Postcondition:
   //    Returns  false     if not changed,
   //             string    adjusted link specification only
   //             array[3]  prolog and/or epilog modified also
   // Uses:
   //    >  .mod.hyper
   //    .w.link.replace.flip()
   //    .l10n.word.fetch()
   // 2012-05-30 [email protected]
   var r  =  WSTM.w.link.replace.flip(WSTM.mod.hyper,
                                      adjust,
                                      ahead,
                                      after,
                                      "link.4");
   var s;
   if (! r  &&  area) {
      s  =  WSTM.l10n.word.fetch(area, 0)  +  ":";
      if (! adjust.indexOf(s)) {
         r  =  WSTM.w.link.replace.flip(WSTM.mod.hyper,
                                        s + adjust,
                                        ahead,
                                        after,
                                        "link:" + area + ".4");
      }
      if (! r  &&  ! ahead  &&  area === "Template") {
         r  =  WSTM.w.link.replace.flip(WSTM.mod.hyper,
                                        adjust,
                                        "{{",
                                        after,
                                        "template.4");
      }
   }
   return  r;
};   // .w.link.replace.flipper()



WSTM.w.link.web.fenced  =  function (adjust, address) {
   // Escape URL parts in [brackets]
   //    TYPO3:   tx_ttnews[tt_news]=
   //    &q1=[1009]&cat1=
   // Precondition:
   //    adjust   -- entire string, without line break
   //    address  -- start of URL in adjust
   // Postcondition:
   //    Returns  false   if nothing to do
   //             string  adjusted (escaped)
   // Uses:
   //     < .mod.lazy
   //    .errors.found()
   // 2012-01-27 [email protected]
   var r  =  false;
   var re;
   var res  =  "\\[([-A-Za-z_0-9%]{1,30})\\]";
   var s    =  adjust.substr(address);
   var n    =  s.indexOf(" ");
   var s2   =  adjust.substr(address);
   if (n > 0) {
      s  =  s.substr(0, n);
   }
   re  =  new RegExp(res + "([[&%/=]|\\.\\w|$)",  "g");
   s2  =  s.replace(re, "&#91;$1&#93;$2");
   s2  =  s2.replace(re, "&#91;$1&#93;$2");
   re  =  new RegExp("=" + res,  "g");
   s2  =  s2.replace(re, "=&#91;$1&#93;");
   if (s2.length - s.length) {
      WSTM.mod.lazy  =  false;
      WSTM.errors.found("bracketsInURL", true, s);
      if (address) {
         s2  =  adjust.substr(0, address)  +  s2;
      }
      if (n > 0) {
         s2  =  s2  +  adjust.substr(address + n);
      }
      r  =  s2;
   }
   return  r;
};   // .w.link.web.fenced()



WSTM.w.link.web.format  =  function (adjust, about, adhere, arg, assign){
   // Format a link to something on the web (http, https, ftp, ...)
   // Precondition:
   //    adjust  -- WikiTom element
   //    about   -- location object
   //               .i  start of http://, https://, ftp:// or // in .k
   //               .j  start of interesting region in .k
   //               .k  sibling number of adjust
   //    adhere  -- true: length of URL required
   //    arg     -- template parameter on unbracket link
   //    assign  -- user defined link replacements, or false
   // Postcondition:
   //    Returns  false     if nothing to do
   //             array[5]  [0] adjusted address (or false)
   //                       [1] address of URL termination, if adhere
   //                       [2] adjusted string
   //                           false   if nothing to replace
   //                       [3] true iff user defined link replacement
   //                       [4] link type:
   //                           .o.WikiTom.LinkWeb
   //                           .o.WikiTom.LinkWiki
   //                           0  if no link any longer
   // Uses:
   //    >  .o.WikiTom.LinkWiki
   //    >  .o.WikiTom.LinkWeb
   //     < .mod.lazy
   //    .str.isBlank()
   //    .w.link.fence()
   //    .o.WikiTom().focus()
   //    .o.WikiTom().fetch()
   //    .errors.found()
   //    .str.trimL()
   //    .w.link.filter()
   //    .w.link.wiki.url()
   //    .w.link.replace.flip()
   //    .w.link.wiki.fore()
   // Requires: JavaScript 1.3   charCodeAt()   fromCharCode()
   // 2012-05-28 [email protected]
   var r  =  false;
   var c;
   var d;                         // domain
   var e  =  adjust.fetch(about.k, about.j, false);   // entire
   var f;                         // find
   var i;
   var j  =  about.i;             // start of unreplaced aftermath
   var k  =  about.i;             // position of "http://" / after prolog
   var l  =  false;               // learn
   var m  =  0;                   // leading bracket count
   var n  =  e.indexOf("\n", about.i);   // number of char of URL
   var p  =  false;               // path
   var s  =  e;
   var t  =  false;               // title
   var u  =  false;               // URL
   var x  =  false;               // user defined link replacement
   for (i = about.i - 1;   i > 0;   i--) {
      f  =  e.charCodeAt(i);
      if (!  WSTM.str.isBlank(f, true)) {
         if (f === 91) {   // '['
            k  =  i + 1;
            l  =  (k !== about.i);
         }
         break;   // for i
      }
   }   // for i
   if (arg) {
      i  =  e.indexOf("|", about.i);
      if (i > 0) {
         if (n > 0) {
            n  =  (i < n  ?  i  :  n);
         } else {
            n  =  i;
         }
      }
   } else if (k > 0) {
      if (e.charCodeAt(k - 1)  ===  91) {   // '['
         m  =  1;   // opening bracket
         if (k > 1) {   // doubled opening bracket
            if (e.charCodeAt(k - 2)  ===  91) {   // '['
               m  =  2;
               k--;
               l  =  true;
            }
         }
      }
   }
   if (n > 0) {
      s  =  e.substr(0, n);
      j  =  n;
   }
   f  =  s.indexOf("</ref>", about.i);
   if (f > 0) {
      s  =  e.substr(0, f);
      n  =  f;
      j  =  f;
   }
   if (s.indexOf("[", about.i) > 0) {   // suspicious brackets
      f  =  WSTM.w.link.web.fenced(s, about.i);
      if (f) {
         if (n > 0) {
            e  =  f + e.substr(n);
            j  =  f.length;
         } else {
            e  =  f;
         }
         s  =  f;
         n  =  s.length;
         l  =  true;
      }
   }
   if (m > 0) {   // opening bracket
      f  =  s.indexOf("]", about.i);
      if (f > 0) {   // closing bracket
         n  =  f;
         j  =  n;
         s  =  e.substr(0, n);
      } else if (j === about.i) {   // no ] in string, check next nodes
         c  =  adjust.focus(about.k + 1);
         if (c) {
            if (c.mode > WSTM.o.WikiTom.TextOnly) {
               c  =  adjust.focus(about.k + 2);
               if (c) {
                  if (c.mode <= WSTM.o.WikiTom.TextOnly) {
                     c  =  adjust.fetch(about.k + 2,  0,  false);
                     if (/[^<\n]*\]/.test(c)) {
                        f  =  1234567;
                     }
                  }
               }
            }
         }
      }
      if (f <= 0) {    // closing bracket missing
         i  =  m;
         m  =  0;
         f  =  e.indexOf("]", about.i);
         if (f > 0) {   // wide search, skipping \n
            c  =  e.slice(n, f);
            if (c.indexOf("[") < 0) {
               var maxd  =  50;   // // // // // // //   Global config
               if (f - n  <  maxd) {   // replace \n
                  WSTM.mod.lazy  =  false;
                  s  =  s   +   " "   +   e.slice(n + 1,  f);
                  n  =  f;
                  j  =  n;
                  l  =  true;
                  m  =  i;
               }
            }
         } else {   // opening bracket within link title - inner link?
            f  =  e.indexOf("[", about.i);
            if (f > 0) {   //  opening bracket within link title
               c  =  e.length - 1;   // last pos
               if (f  >=  c - 1) {   // inner link?
                  if (e.charCodeAt(c) === 91) {   // '['
                     m  =  0;
                     j  =  f;
                     s  =  s.substr(0, j);
                     f  =  WSTM.w.link.fence(s.substr(about.i), 1, true);
                     if (f) {
                        j  =  about.i + f;
                        s  =  s.substr(0, j);
                     } else {
                        f  =  -3;
                     }
                  }
               } else {
                  f  =  -2;
               }
            }
            if (f < 0) {
               WSTM.errors.found("weblinkBracketRight",
                                 false,
                                 "["  +  s.substr(about.i, 100));
            }
         }
      }
      if (m === 2) {   // doubled opening bracket
         if (e.charCodeAt(n + 1)  ===  93) {   // ']'
            j  =  n + 1;
            m  =  6;
            f  =  s.indexOf("|", about.i);
            if (f > 0) {   // mixing wikilink and weblink
               s  =  s.substr(0, f)  +  " "  +  s.substr(f + 1);
            }
         }
      }   // doubled opening bracket
   }   // opening bracket
   u  =  s.substr(about.i);
   if (m > 0) {   // brackets
      f  =  s.indexOf(" ", about.i);
      if (f > 0) {
         t  =  s.substr(f + 1);
         u  =  s.slice(about.i, f);
         if (WSTM.str.isBlank(t.charCodeAt(0), false)) {
            t  =  WSTM.str.trimL(t, false);
            l  =  true;
         }
      }
   } else {   // plain
      f  =  WSTM.w.link.fence(s.substr(about.i), 1, true);
      if (f) {
         u  =  s.substr(about.i, f);
         j  =  about.i + f;
      } else if (j === about.i) {
         j  =  s.length;
      }
   }
   f  =  WSTM.w.link.filter(u, false);
   if (f) {
      u  =  f;
   }
   if (u.charCodeAt(0) === 47) {   // '/'
      f  =  u.indexOf("/", 6);
   } else {
      f  =  u.indexOf("/",  u.indexOf("://") + 4);
   }
   if (f > 0) {
      d  =  u.substr(0, f);
      p  =  u.substr(f + 1);
   } else {
      d  =  u;
      l  =  true;
   }
   f  =  d.indexOf("?");
   if (f > 0) {
      c  =  d.substr(f);
      d  =  d.substr(0, f);
      p  =  (p  ?  p + c  :  c);
   } else if (! p) {
      f  =  u.charCodeAt(u.length - 1);
      if (f !== 47) {   // ! '/'
         p  =  "/";
         if ((f >= 65  &&  f <=  90)  ||
             (f >= 97  &&  f <= 122)) {   // A-Za-z   (TLD)
            u  =  u + "/";
            n  =  u.length;
            l  =  true;
         } else if (d !== d.toLowerCase()) {
            d  =  d.toLowerCase();
            l  =  true;
         }
      }
   }
   f  =  d.toLowerCase();
   if (f !== d) {
      c  =  u.charCodeAt(d.length);
      d  =  f;
      u  =  d;
      if (c === 47  ||  c === 63) {   //   '/'  '?'
         if (p !== "/") {
            u  =  u + String.fromCharCode(c);
         }
      }
      if (p) {
         u  =  u + p;
      }
      l  =  true;
   }
   c  =  false;
   if (u.substr(0, 4)  ===  "http") {
      if (d.charCodeAt(4) === 115) {
         c  =  8;
      } else {
         c  =  7;
      }
   } else if (u.substr(0, 2)  ===  "//") {
      if (m) {
         c  =  2;
      }
   }
   if (c) {
      c  =  WSTM.w.link.wiki.url(c, d, p, t);
      if (typeof(c) === "string") {
         u  =  c;
         l  =  true;
         c  =  false;
      }
   }
   if (c) {   // wikilink
      r  =  c[0] + c[1];
      x  =  WSTM.w.link.replace.flip(assign,
                                     r,
                                     "\\[\\[",
                                     (t ? t : "")  +  "\\]\\]",
                                     "[wiki");
      if (x) {
         r  =  x;
      }
      s  =  e.substr(0, k);
      if (m === 0) {
         r   =  "[[" + r;
         k  +=  2;
      } else {
         r  =  "[" + r;
         k++;
      }
      r  =  s + r;
      n  =  k + c[0].length + c[1].length;
      if (c[2]) {
         t  =  c[2];
      }
      if (t) {
         if (c[0] !== ""  ||  c[1] !== t) {
            r  =  r + "|" + t;
         }
      } else if (c[0] !== "") {
         r  =  r + "|" + c[1];
      }
      f  =  0;
      if (m > 0) {   // ']'
         f  =  WSTM.w.link.wiki.fore(e, j);
         if (f) {   // aftermath
            j++;
            r   =  r  +  e.substr(j, f)  +  "]";
            j  +=  f;
            // title updated   ->  identical with target?
         }
         f  =  1;
      }
      if (f === 0) {
         r  =  r + "]";
      }
      if (m < 2) {
         r  =  r + "]";
      }
      r  =  r  +  e.substr(j);
      l  =  true;
      u  =  WSTM.o.WikiTom.LinkWiki;
   } else {   // URL
      s  =  e.substr(0, k);
      if (assign) {   // .mod.url   (= .mod.url + .mod.hyper)
         x  =  (t  ?  " " + t  :  "")   +  e.substr(j);
         x  =  WSTM.w.link.replace.flip(assign, u, s, x, "url");
         if (x) {
            if (typeof(x) === "object") {
               if (x[0]) {
                  s  =  x[0];
                  f  =  s.length;
                  n  =  n - k + f;
                  k  =  f;
               }
               if (x[1]) {
                  u  =  x[1];
                  n  =  u.indexOf("://");
                  if (n < 3  ||  n > 10) {
                     n  =  false;
                  } else if (u.indexOf("//") === 0) {
                     n  =  false;
                  } else {
                     n  =  true;
                  }
                  if (n) {
                     n  =  k + u.length;
                  } else {
                     s     =  s
                              +  u
                              +  (x[2] ? x[2] : e.substr(j));
                     t     =  false;
                     u     =  false;
                     x[2]  =  false;
                  }
               }
               if (x[2]) {
                  j  =  false;
                  t  =  x[2];
               }
            } else {
               u  =  x;
               n  =  k + u.length;
            }
            l  =  true;
         } else {
            n  =  k + u.length;
         }
      } else if (l) {
         n  =  k + u.length;
      }
      if (l) {
         r  =  s;
         if (u) {
            r  =  r + u;
         }
         if (u && t) {
            if (t) {
               r  =  r   +   (t.charCodeAt(0) === 32  ?  t  :  " " + t);
            } else {
               r  =  r + " ";
            }
         }
         if (n && j) {
            r  =  r + e.substr(j);
         }
      }
      if (u) {
         u  =  WSTM.o.WikiTom.LinkWeb;
      } else {
         u  =  0;
      }
   }
   if (l) {
      r  =  [k, n, r, x, u];
   } else if (n > 0  &&  adhere) {
      r  =  [k, n, false, false, WSTM.o.WikiTom.LinkWeb];

   }
   return  r;
};   // .w.link.web.format()



WSTM.w.link.web.free  =  function (adjust, access, above, adhere, arg) {
   // Format and process any unbracketed URL, protocol required
   // Precondition:
   //    adjust  -- WikiTom top element
   //    access  -- location object
   //               .i  position to start searching for "["
   //               .k  sibling number
   //    above   -- top level
   //    adhere  -- true: freeze link targets in this context
   //    arg     -- template parameter
   // Postcondition:
   //    Nodes are modified where suitable.
   //    RegExp was used.
   // Uses:
   //    >  .w.link.web.re
   //    >  .mod.hyper
   //     < .mod.lazy
   //    .o.WikiTom().find()
   //    .w.link.web.free()  -- recursive
   //    .o.WikiTom().fetch()
   //    .w.link.web.format()
   //    .o.WikiTom().folder()
   // 2012-05-19 [email protected]
   var beg;
   var deep;
   var got  =  access;
   var i;
   var j;
///var m;
   var n;
   var pos;
   var s;
   var tp;
   var url;
   do {
      got  =  adjust.find("://", got.i, got.k, true, false, false);
      if (got) {
         deep  =  got.child;
         if (deep) {
            this.free(deep.o, deep, true, adhere, arg);
            got.i   =  0;
            got.k++;
         } else if (got.i < 3) {
            got.i  +=  6;
         } else {
            n    =  6;
            i    =  (got.i > 6  ?  got.i - 6  :  0);
            s    =  adjust.fetch(got.k, i, false);
            beg  =  this.re.exec(s.substr(0, 9));
            if (beg) {
               if (beg[2] !== "[") {
                  if (beg[1]) {
                     j  =  beg[1].length - beg[3].length;
                  } else {
                     j  =  0;
                  }
                  j    +=  beg.index;
                  pos   =  { i: j,  j: i,  k: got.k };
                   //  .i  start of http://, https://, ftp:// or // in .k
                   //  .j  start of interesting region in .k
                   //  .k  sibling number of adjust
                  tp    =  this.format(adjust,
                                       pos,
                                       adhere,
                                       WSTM.mod.hyper,
                                       arg,
                                       false);
                  if (tp) {
//mw.log(WSTM.debugging,".w.link.web.free() beg",0,beg);
//mw.log(WSTM.debugging,".w.link.web.free() tp",0,tp);
                 //  [0] adjusted address (or false)
                 //  [1] address of URL termination, if adhere
                 //  [2] adjusted string
                 //      false   if nothing to replace
                 //  [3] true iff user defined link replacement
                 //  [4] link type
                     if (tp[0]) {
                        n  =  tp[0];
                     }
                     if (tp[1]) {
                        j     =  tp[1];
                        url   =  false;
                        n    +=  j;
                        if (tp[2]) {
                           adjust.flip(got.k, i, s.length, tp[2]);
                        }
                        if (adhere) {
                           url  =  adjust.folder(i + tp[0],
                                                 got.k,
                                                 i + j,
                                                 got.k);
                           if (url) {
                              url.mode    =  tp[4];
                              url.lookup  =  (! url.mode);
                           }
                        }
/*
                        if (tp[2]) {
                           adjust.flip(got.k,  i + m,  s.length,  tp[2]);
                        }
                        if (adhere) {
                           url  =  adjust.folder(i + m + 2,
                                                 got.k,
                                                 i + j,
                                                 got.k);
*/
                     }
                     if (tp[3]) {
                        WSTM.mod.lazy  =  false;
                     }
                     //   [4] false iff converted into wikilink
                  }
               }
            }
            got.i  +=  n;
         }
      }
   } while (got);
};   // .w.link.web.free()



WSTM.w.link.wiki.context  =  function (adjust) {
   // Retrieve context title for [[fool:bar (Abc)|]]
   // Precondition:
   //    adjust  -- string with link target
   // Postcondition:
   //    Returns link title
   //    RegExp was used.
   // Requires: JavaScript 1.3   fromCharCode()
   // 2011-01-18 [email protected]
   var got;
   var sB  =  "(" + String.fromCharCode(65288);
   var sE  =  ")" + String.fromCharCode(65289);
                    // FF08 FF09  FULLWIDTH PARENTHESIS
   var re  =  sB + sE;
   re   =  "([^" + re + "]*[^ " + re + "]) *"
           + "[" + sB + "].+[" + sE + "]";
   re   =  new RegExp(re, "");
   got  =  re.exec(adjust);
   return  (got === null ?  adjust  :  got[1]);
};   // .w.link.wiki.context()



WSTM.w.link.wiki.decode  =  function (adjust, article, after, alone, assume) {
   // Standardize wiki identifier part, decode URL
   // Precondition:
   //    adjust   -- string with identifier (article or anchor)
   //    article  -- true if identifier is article, not anchor
   //    after    -- false if trailing space not permitted and to remove
   //    alone    -- true if entire link -- false if titled
   //    assume   -- true: space for underscore -- false: underscore kept
   // Postcondition:
   //    Returns  false   if nothing to do,
   //             string  adjusted identifier
   //    RegExp was used.
   // Uses:
   //    .str.setString()
   //    .str.setChar()
   //    .str.trimL()
   //    .str.trimR()
   //    .str.substrEnd()
   //    .str.decodeOctet()
   //    .str.charEntityCode()
   // Requires: JavaScript 1.3   charCodeAt()   fromCharCode(Unicode)
   // 2012-03-22 [email protected]
   var c       =  false;
   var i;
   var k1, k2, k3;
   var learnt  =  false;
   var match   =  0;
   var n;
   var qc, qn;
   var s;
   var stuff   =  adjust;
   var suffix  =  false;
   if (! alone) {   // titled link
      i  =  stuff.indexOf("&nbsp;");
      while (i >= 0) {
         stuff  =  WSTM.str.setString(stuff, i, 6, " ");
         i      =  stuff.indexOf("&nbsp;");
      }   // while
   }   // ! alone
   if (assume) {
      for (i = stuff.length - 1;  i >= 0;  i--) {
         if (stuff.charCodeAt(i) === 95) {   // '_'
            stuff   =  WSTM.str.setChar(stuff, 32, i);   // ' '
            learnt  =  true;
         }   // replace underscore
      }   // for i
   }
   n      =  stuff.length;
   stuff  =  WSTM.str.trimL(stuff, true);
   if (stuff.length < n) {
      learnt  =  true;
      n       =  stuff.length;
   }   // ltrim
   stuff  =  WSTM.str.trimR(stuff, true);
   if (stuff.length < n) {
      learnt  =  true;
      if (after) {
         suffix  =  " ";
         n       =  n - stuff.length - 1;
         while (n) {
            suffix  +=  " ";
            n--;
         }   // while n
      }
   }   // rtrim
   i  =  stuff.indexOf("  ");
   while (i >= 0) {
      stuff   =  WSTM.str.setString(stuff, i, 2, " ");
      i       =  stuff.indexOf("  ");
      learnt  =  true;
   }   // while
   if (stuff.charCodeAt(0) === 38) {    // &
      if (stuff.substr(3, 2) === "m;") {
         s  =  stuff.substr(1, 2);
         if (s === "rl"  ||  s === "lr") {
            stuff   =  stuff.substr(5);
            learnt  =  true;
         }   // heading superfluous char
      }   // m;
   }   // &
   if (WSTM.str.substrEnd(stuff, 2)  ===  "m;") {
// if (stuff.slice(-2) === "m;") {
         s  =  WSTM.str.substrEnd(stuff, 5, 3);
//       s  =  stuff.slice(-5, -2);
      if (s === "&rl"  ||  s === "&lr") {
         stuff   =  stuff.substr(0,  stuff.length - 5);
         learnt  =  true;
      }   // trailing superfluous char
   }   // m;
   if (suffix) {
      stuff  =  stuff + suffix;
   }   // ! after
   if (article) {
      qc  =  "%";
      qn  =  37;
   } else {
      qc  =  ".";
      qn  =  46;
   }
   match  =  stuff.indexOf(qc, match);
   while (match >= 0) {
      n   =  3;
      k1  =  WSTM.str.decodeOctet(stuff,  match + 1);
      if (k1 < 32) {   // invalid
      } else if (k1 <  48) {   // single ASCII
         c  =  k1;
      } else if (k1 <  58) {   // invalid
      } else if (k1 <  65) {   // single ASCII
         c  =  k1;
      } else if (k1 <  91) {   // invalid
      } else if (k1 <  97) {   // single ASCII
         c  =  k1;
      } else if (k1 < 123) {   // invalid
      } else if (k1 < 128) {   // single ASCII
         c  =  k1;
      } else if (k1 < 192) {   // invalid
      } else if (k1 < 240) {   // UTF-8
         k2  =  (stuff.charCodeAt(match + 3)  ===  qn);
         if (k2) {
            k2  =  WSTM.str.decodeOctet(stuff,  match + 4);
         }
         if (k2) {
            n  =  6;
            if (k1 < 224) {   // byte pair
               if (k2 > 127  &&  k2 < 192) {
                  c  =  (k1 - 192)  *  64   +   k2   -   128;
               }   // k2 valid
            } else {   // byte triplet
               k3  =  (stuff.charCodeAt(match + 6)  ===  qn);
               if (k3) {
                  k3  =  WSTM.str.decodeOctet(stuff,  match + 7);
               }
               if (k3) {
                  n  =  9;
                  if (k3 > 127  &&  k3 < 192) {
                     c  =  (((k1 - 224)  *  64   +   k2   -   128)
                            *    64)
                           +     k3    -    128;
                  }   // k3 valid
               }   // URL-encoded byte #3
            }
         }   // URL-encoded byte #2
      }   // first byte
      switch (c) {   // required escapes
         case  32 : // ' '
            if (! article) {   // in anchors
               c  =  false;   // ".20" not to be replaced, '_' used
            }
            break;
         case  35 : // #
            if (article) {
               break;
            }
         case  38 : // &
         case  91 : // [
         case  93 : // ]
         case 124 : // |
            c  =  false;
      }   // switch c
      if (c) {
         c       =  String.fromCharCode(c);
         stuff   =  WSTM.str.setString(stuff, match, n, c);
         learnt  =  true;
         n       =  1;
         c       =  false;
      }   // decode
      match  =  stuff.indexOf(qc,  match + 1);
   }   // while URL-encoded char
   return  (learnt  ?  stuff  :  false);
};   // .w.link.wiki.decode()



WSTM.w.link.wiki.file  =  function (adjust) {
   // Standardize presumable file link
   // Precondition:
   //    Text has been read until end
   // Uses:
   //    >< .l10n.word.file
   //    >< .l10n.re.fileBeg
   //    .w.link.wiki.decode()
   //    .l10n.word.fetch()
   // 2012-05-21 [email protected]
   var k;
   var r  =  WSTM.w.link.wiki.decode(adjust, true, false, true, true);
   if (! r) {
      r  =  adjust;
   }
   k  =  r.indexOf(":");
   if (k > 1) {   // .w.link.wiki.file()
      if (! WSTM.l10n.word.file) {
         WSTM.l10n.word.file  =  WSTM.l10n.word.fetch("File", 0);
      }
      if (! WSTM.l10n.re.fileBeg) {
         WSTM.l10n.re.fileBeg  =  "^("
                                  +  WSTM.l10n.word.fetch("File", 1)
                                  +  "|"
                                  +  WSTM.l10n.word.fetch("Image", 1)
                                  +  "):";
         WSTM.l10n.re.fileBeg  =  new RegExp(WSTM.l10n.re.fileBeg,  "i");
      }
      if (WSTM.l10n.re.fileBeg.test(r)) {
         r  =  WSTM.l10n.word.file + r.substr(k);
      }
   }
   return  r;
};   // .w.link.wiki.file()



WSTM.w.link.wiki.finalize  =  function () {
   // Finalize category and interwiki link structure
   // Precondition:
   //    Text has been read until end
   // Uses:
   //    >< .w.encountered.cats
   //    >< .w.encountered.iwiki
   //    .errors.found()
   // 2012-04-27 [email protected]
   var r    =  false;
   var got;
   var i;
   var n;
   var say  =  false;
   switch (r) {
      case WSTM.o.WikiTom.LinkCategory :
         got  =  WSTM.w.encountered.cats;
         break;
      case WSTM.o.WikiTom.LinkInterWiki :
         got  =  WSTM.w.encountered.iwiki;
         break;
   }   // switch mode
   if (say) {
      if (got) {
         n  =  got.length;
         for (i = 1;  i < n;  i++) {
            if (got[i] === r.source) {
               WSTM.errors.found("???.w.link.wiki.finalize()",
                                 false,
                                 r.source);
            }
         }   // for i
      }
   }
};   // .w.link.wiki.finalize()



WSTM.w.link.wiki.flush  =  function (apply) {
   // Remove any wikilink from WikiTom
   // Precondition:
   //    apply  -- WikiTom, might contain wikilinks as children
   // Postcondition:
   //    Returns  false  if nothing to do,  else true if modified
   // Uses:
   //    >  .o.WikiTom.LinkWikiPipe
   //    >  .o.WikiTom.TextOnly
   //    .w.link.linked()
   //    .o.WikiTom().fetch()
   //    .str.substrEnd()
   //    .o.WikiTom().find()
   //    .o.WikiTom().focus()
   //    .o.WikiTom().fresh()
   //    .o.WikiTom().flush()
   // 2012-06-18 [email protected]
   var e  =  apply.children;
   var i;
   var p;
   var q;
   var n;
   var r  =  false;
   var s;
   var t;
   if (e) {
      n  =  e.length;
      if (n > 1) {
         for (i = n - 2;  i >= 0;  i--) {
            if (this.linked(e[i])) {
               p  =  apply.fetch(i - 1);
               if (WSTM.str.substrEnd(p, 2)  ===  "[[") {
//             if (p.slice(-2) === "[[") {
                  r  =  true;
                  q  =  e[i + 1];
                  if (q.mode === WSTM.o.WikiTom.LinkWikiPipe) {
                     t  =  apply.find("]]",
                                      0,
                                      i + 2,
                                      true,
                                      false,
                                      false);
                     if (t) {
                        s  =  apply.fetch(t.k);
                        s  =  s.substr(0, t.i)  +  s.substr(t.i + 2);
                        t  =  apply.focus(t.k).fresh(s);
                        apply.flush(i + 1);
                     }
                  } else {
                     s  =  q.toString();
                     if (s.substr(0, 2)  ===  "]]") {
                        s  =  e[i].toString()  +  s.substr(2);
                        q.fresh(s);
                     }
                  }
                  apply.flush(i);
               }
               i--;
               s  =  p.toString();
               n  =  s.length - 2;
               if (n) {
                  e[i].fresh(s.substr(0, n));
               } else {
                  apply.flush(i);
               }

            }
         }   // for i
      }
   }
   if (e.length === 1) {
      p  =  e[0];
      if (p.mode <= WSTM.o.WikiTom.TextOnly) {
         if (! p.children) {
            s           =  p.source;
            apply.mode  =  p.mode;
            delete apply.children;
            apply.fresh(s);
         }
      }
   }
   return  r;
};   // .w.link.wiki.flush()



WSTM.w.link.wiki.fore  =  function (aftermath, align) {
   // Find length of titled wikilink aftermath, if any
   // Precondition:
   //    aftermath  -- string with follower of a titled wikilink
   //    align      -- first character in aftermath to consider
   // Postcondition:
   //    Returns  false   if nothing to do,
   //             number  of characters to join with wikilink title
   //                     (terminated by interpunction etc.)
   // Uses:
   //    .str.isLetter()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2011-04-27 [email protected]
   var r;
   var i;
   var n  =  aftermath.length;
   for (i = align;  i < n;  i++) {
      if (! WSTM.str.isLetter(aftermath.charCodeAt(i))) {
         break;   // for i
      }
   }   // for i
   r  =  (i > align   ?   i - align   :   false);
   return  r;
};   // .w.link.wiki.fore()



WSTM.w.link.wiki.further  =  function (about) {
   // Handle special category or interwiki link
   // Precondition:
   //    about  -- link information
   //              >  .mode
   //              >  .source
   // Postcondition:
   //    Returns true iff first occurence of this type
   // Uses:
   //    >  .o.WikiTom.LinkCategory
   //    >  .o.WikiTom.LinkInterWiki
   //    >< .w.encountered.cats
   //    >< .w.encountered.iwiki
   // 2012-04-26 [email protected]
   var r  =  false;
   var s;
   switch (about.mode) {
      case WSTM.o.WikiTom.LinkCategory :
         s  =  "cats";
         break;
      case WSTM.o.WikiTom.LinkInterWiki :
         s  =  "iwiki";
         break;
   }   // switch mode
   if (s) {
      if (WSTM.w.encountered[s]) {
         WSTM.w.encountered[s].push(about.source);
      } else {
         WSTM.w.encountered[s]  =  [ about.source ];
         r  =  true;
      }
   }
   return  r;
};   // .w.link.wiki.further()



WSTM.w.link.wiki.iwMap  =  function (adjust, align) {
   // Check possible interwiki whether it is mapped to URL
   //    [[meta:Interwiki map]]
   // Precondition:
   //    adjust  -- possible mapped interwiki, leading spaces permitted
   //    align   -- length of adjust
   // Postcondition:
   //    Returns adjusted string, if mapped, or false
   //    RegExp was used.
   // Uses:
   //    >  .g.s.re.interwURL
   //    >  .g.s.re.interwMap
   //    >< .g.re.iwikiMap
   // 2010-12-31 [email protected]
   var r    =  false;
   var re;
   var got;
   if ( ! WSTM.g.re.iwikiMap) {
      re  =  " *("
             + WSTM.g.s.re.interwURL.substr(1)
             + WSTM.g.s.re.interwMap
             + ":";
      WSTM.g.re.iwikiMap  =  new RegExp(re, "i");
   }
   got  =  WSTM.g.re.iwikiMap.exec(adjust);
   if (got) {
      re   =  new RegExp("\\|(" + got[1] + ")[|)]",  "i");
      got  =  re.exec(WSTM.g.s.re.interwMap);
      r    =  got[1];
   }   // interwiki map
   return  r;
};   // .w.link.wiki.iwMap()



WSTM.w.link.wiki.linked  =  function (about) {
   // Check whether WikiTom is wikilink target
   // Precondition:
   //    about  -- WikiTom element
   // Postcondition:
   //    Returns true if about is wikilink
   // Uses:
   //    >  .o.WikiTom().mode
   //    >  .o.WikiTom.LinkWiki
   //    >  .o.WikiTom.LinkExtWiki
   // 2012-04-18 [email protected]
   return  (about.mode >= WSTM.o.WikiTom.LinkWiki  &&
            about.mode <= WSTM.o.WikiTom.LinkExtWiki);
};   // .w.link.wiki.linked()



WSTM.w.link.wiki.target  =  function (adjust, alone) {
   // Standardize target identifier in the wiki world
   // Precondition:
   //    adjust  -- string with link specification
   //    alone   -- true if entire link -- false if titled
   // Postcondition:
   //    Returns  false   if nothing to do,
   //             string  adjusted link specification
   //    RegExp was used.
   // Uses:
   //    .hooks.fire()
   //    .w.link.wiki.decode()
   // 2011-12-26 [email protected]
   var r  =  false;
   var joint   =  adjust.indexOf("#");
   var stuff   =  adjust;
   var sub     =  false;
   var swap;
   if (joint >= 0) {   // fragment
      sub  =  stuff.substr(joint+1);
      if (joint === 0) {
         stuff  =  "";
      } else {
         stuff  =  stuff.substr(0, joint);
      }
      if (sub.indexOf(":") > 0) {   // anchor template?
         swap  =  WSTM.hooks.fire("fragment", sub);
         if (swap) {
            sub  =  swap;
            r    =  true;
         }
      }
      swap  =  WSTM.w.link.wiki.decode(sub, false, false, alone, true);
      if (swap) {
         if (swap === "") {
            sub  =  false;
         } else {
            sub  =  swap;
         }
         r  =  true;
      } else if (sub === "") {
         sub  =  false;
         r    =  true;
      }
   }   // anchor
   swap  =  WSTM.w.link.wiki.decode(stuff, true, sub, alone, true);
   if (swap) {
      stuff  =  swap;
      r      =  true;
   }
   if (sub) {
      stuff  =  stuff + "#" + sub;
   }
   r  =  (r ? stuff : false);
   return  r;
};   // .w.link.wiki.target()



WSTM.w.link.wiki.upload  =  function (achieve, about) {
   // Reformat any http link to a wiki upload as a wikilink
   // Precondition:
   //    achieve  -- path, following '//upload.wikimedia.org/'
   //    about    -- linktitle, following ' '  --  or false
   // Postcondition:
   //    Returns  false     if not to be formatted as wikilink
   //             array[3]  [0] ""  or  prefix string terminated with ":"
   //                       [1] target of wikilink
   //                       [2] title of wikilink
   //    RegExp was used.
   // Uses:
   //    >  .g.projSpace
   //    >  .g.projLang
   //    >  .g.s.re.Filetypes
   //    >< .g.projUploadPath
   //    >< .g.re.stripFileExt
   //    .w.link.project()
   //    .w.link.wiki.target()
   //    .l10n.word.fetch()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-03-27 [email protected]
   var got;
   var n;
   var r      =  false;
   var re;
   var swift  =  false;
   var space  =  false;
   if (achieve.substr(0, 18)  ===  "wikipedia/commons/") {
      swift  =  achieve.substr(18);
   } else {
      if (typeof(WSTM.g.projUploadPath) !== "string") {
         WSTM.g.projUploadPath  =  WSTM.g.projSpace + "/" +
                                   WSTM.g.projLang + "/";
      }
      n  =  WSTM.g.projUploadPath.length;
      if (achieve.substr(0, n)  ===  WSTM.g.projUploadPath) {
         swift  =  achieve.substr(n);
      } else {
         re   =  /^(([a-z]+)\/([a-z]+)\/)(.+)$/;
         got  =  re.exec(achieve);
         if (got) {
            space  =  WSTM.w.link.project(got[2], false);
            if (space) {
               space  =  space[1];
               if (! space) {
                  space  =  "";
               }
               space  =  space + ":" + got[3] + ":File:";
               swift  =  got[4];
            }
         }
      }
   }
   if (swift) {
      if (swift.charCodeAt(1) === 47  &&   // '/'
          swift.charCodeAt(4) === 47  &&   // '/'
          swift.charCodeAt(0) === swift.charCodeAt(2)) {
         swift  =  swift.substr(5);
         r  =  WSTM.w.link.wiki.target(swift);
         if (r) {
            swift  =  r;
         }
         if (! space) {
            space  =  ":"  +  WSTM.l10n.word.fetch("File", 0)  +  ":";
         }
         r  =  new Array(3);
         r[0]  =  space;
         r[1]  =  swift;
         if (about) {
            r[2]  =  about;
         } else {
            if (typeof(WSTM.g.re.stripFileExt) !== "object") {
               re  =  " *\\." + WSTM.g.s.re.Filetypes + "$";
               WSTM.g.re.stripFileExt  =  new RegExp(re);
            }
            r[2]  =  swift.replace(WSTM.g.re.stripFileExt, "");
         }
      }
   }
   return  r;
};   // .w.link.wiki.upload()



WSTM.w.link.wiki.url  =  function (access, address, achieve, about) {
   // Reformat any http link to a wiki project as a wikilink or else
   // Precondition:
   //    access   -- length of protocol part   2: relative
   //                                          7: http
   //                                          8: https
   //    address  -- domain and subdomains, maybe any wiki project
   //                downcased
   //    achieve  -- path, if any, following '/'  --  or false
   //    about    -- linktext, following ' '  --  or false
   // Postcondition:
   //    Returns  false     if not to be formatted as wikilink
   //             array[3]  [0] ""  or  prefix string terminated with ":"
   //                       [1] target of wikilink
   //                       [2] title of wikilink
   //             string    reformatted URL
   //    RegExp was used.
   // Uses:
   //    >  .g.re.wikiSECURE
   //    >  .g.re.wikiDOMAIN
   //    >  .g.projLang
   //    >  .g.s.re.ProtocolSecure
   //    >  .g.s.re.ProtocolRelative
   //     < .mod.lazy
   //    .str.substrEnd()
   //    .g.factoryURL()
   //    .w.link.wiki.upload()
   //    .w.link.wiki.target()
   //    .w.link.project()
   //    .w.link.namespace.furnish()
   //    .str.trimL()
   //    .w.link.namespace.fetch()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-05-16 [email protected]
   var domain;
   var got;
   var j;
   var key;
   var layer;
   var learn;
   var life    =  true;
   var mode;
   var n;
   var pars;
   var r       =  false;
   var re;
   var s;
   var scope;
   var show;
   var sister;
   var slang;
   var stuff;
   if (WSTM.str.substrEnd(address, 4)  ===  ".org") {
// if (address.slice(-4) === ".org") {
      domain  =  address.substr(access);
      layer   =  false;
      if (access === 8) {   // https
         layer  =  (domain === "secure.wikimedia.org");
         if (layer) {
            r  =  [false, false, false];
            if (achieve) {
               if (! WSTM.g.re.wikiSECURE) {
                  WSTM.g.factoryURL(true);
               }
               got  =  WSTM.g.re.wikiSECURE.exec(achieve.toLowerCase());
               if (got === null) {
                  r  =  false;
               } else {
                  if (got[4] === "commons") {
                     r[0]  =  "commons";
                     r[1]  =  "";
                  } else {
                     r[0]  =  got[1];   // reSite
                     r[1]  =  got[4];   // reProj
                  }
                  if ( achieve.charCodeAt(0) === 119) {   // 'w'
                     r[2]  =  achieve.substr(got[0].length);
                  } else {
                     r[2]  =  achieve;
                  }
                  r[2]  =  achieve.substr(got[0].length);
               }
            } else {
               r[0]  =  "wikimedia";
               r[1]  =  WSTM.g.projLang;
            }
         }   // https://secure.wikimedia.org until summer 2011
      }   // https
      if (! layer) {   // protocol relative / http or https 2011-10...
         if (! WSTM.g.re.wikiDOMAIN) {
            WSTM.g.factoryURL(false);
         }
         domain  =  WSTM.g.re.wikiDOMAIN.exec(domain);
         if (domain) {
            r  =  [domain[2], domain[1], false];
            if (achieve) {
               r[2]  =  achieve;
               if (r[0] === "wikimedia") {
                  if (r[1].length < 4) {
                     r  =  false;
                  } else if (achieve.charCodeAt(0) === 119) {   // 'w'
                     if (r[1] === "commons") {  /* meta*/
                        r[0]  =  "commons";
                        r[1]  =  "";
                     } else if (r[1] === "upload") {
                        mode  =  WSTM.w.link.wiki.upload(achieve, about);
                        if (mode) {
                           r     =  mode;
                           life  =  false;
                        }
                     }
                  }
               } else if (r[0] === "mediawiki") {
                  r[1]  =  "";
               }
            }   // path
         }
      }
   }   // .org
   if (r && life) {   // It's a wiki.
      learn  =  false;
      if (r[2]) {
         stuff  =  r[2];
         life   =  (stuff.charCodeAt(1) === 47);   // '/' ("w/")
         if (life) {
            learn  =  (stuff.substr(2, 11)  ===  "wiki.phtml?");
            if (learn) {   // ~2004
               stuff   =  stuff.substr(13);
               r[2]    =  "w/index.php" + stuff;
            } else if (stuff.substr(2, 10)  ===  "index.php?") {
               stuff  =  stuff.substr(12);
            } else {
               life  =  false;
            }
         }
         if (life) {
            s  =  stuff.substr(0, 6);
            if ("=title=oldid=".indexOf("=" + s)  >=  0) {
               pars  =  { };
               re    =  /^&((title|oldid)=([^&]+)&)/;
               s     =  "&" + stuff + "&";
               got   =  re.exec(s);
               if (got) {
                  pars[ got[2] ]  =  got[3];
                  s               =  s.substr(got[1].length);
               }
               got   =  re.exec(s);
               if (got) {
                  pars[ got[2] ]  =  got[3];
                  s               =  s.substr(got[1].length);
               }
               if (s === "&") {
                  learn  =  true;
                  life   =  false;
                  if (pars.oldid) {
                     r[2]  =  "Special:PermanentLink/" + pars.oldid;
                     if (pars.title) {
                        r[2]  =  r[2]  + "?title=" + pars.title;
                     }
                  } else {
                     r[2]  =  pars.title;
                  }
               }
            } else {
               life  =  false;///////////////// ++
            }
            if (! learn  &&  access !== 2) {
               learn  =  true;
            }
         }
         if (! life) {
            if (stuff.substr(0, 5)  ===  "wiki/") {
               r[2]   =  stuff.substr(5);
               learn  =  true;
            }
            if (! r[2]) {   // on every project in any language
               r[2]  =  "Main Page";   // default
            }
         }
      }
      if (life) {
         s  =  ".org/";
         if (r[2]) {
            s  =  s + r[2];
         }
         if (r[1] === "") {
            if (r[0] === "wikimedia") {
               r  =  r[0] + ".wikimedia" + s;
            } else if (r[0] === "mediawiki") {
               r  =  "www.mediawiki" + s;
            } else {
               r  =  false;
            }
         } else {
            r  =  r[1] + "." + r[0] + s;
         }
         if (r) {
            r  =  "//" + r;
         }
     } else if (r) {
         mode  =  access;
         if (r[0] === "wikimedia") {
            s  =  "|" + r[1] + "|";
            if (WSTM.g.s.re.ProtocolSecure.indexOf(s) >= 0) {
               if (mode === 8) {
                  r  =  false;
               } else {
                  s  =  r[2];
                  r  =  "https://" + r[1] + ".wikimedia.org";
                  if (s) {
                     r  =  r + "/" + s;
                  }
               }
               mode  =  false;
            }
         } else if (r[0] === "mediawiki") {
            mode  =  false;
            r[0]  =  "mw";
         } else if (r[1] === "meta") {
            mode  =  false;
         }
         if (mode === 2) {
            r  =  false;
         } else if (mode) {
            if (r[0] === "wikimedia") {
               s  =  "|" + r[1] + "|";
               if (WSTM.g.s.re.ProtocolRelative.indexOf(s)  >=  0) {
                  s  =  r[2];
                  r  =  "//" + r[1] + ".wikimedia.org";
                  if (s) {
                     r  =  r + "/" + s;
                  }
               }
            }
         }
         if (typeof(r) === "object") {
            s  =  WSTM.w.link.wiki.target(r[2], true);
            if (s) {
               r[2]  =  s;
            }   // decoded
         }
      }
      if (typeof(r) === "object") {
         show    =  about;
         sister  =  false;
         slang   =  false;
         stuff  =  r[2];
         j      =  stuff.indexOf(":");
         if (r[0] !== "") {
            sister  =  r[0];
            s       =  WSTM.w.link.project(sister, false);
            if (s) {
               if (s[0] !== 1) {
                  slang  =  ":en:";
               }
               sister =  s[1];
               if (sister) {
                  r[0]  =  sister + ":";
               } else {
                  r[0]  =  "";
               }   // prefix required
            }   // project identified
         }   // sister
         if (r[1] !== "") {
            slang  =  r[1];
            if (slang === WSTM.g.projLang) {
               slang  =  false;
            } else if (sister) {
               r[0]  =  r[0] + slang + ":";
            } else {
               r[0]  =  ":" + slang + ":";
            }
         }
         n  =  stuff.indexOf(":");
         if (n > 2) {   // maybe File:
            scope  =  stuff.substr(0, n);
            key    =  WSTM.w.link.namespace.furnish(scope);
            if (key) {
               stuff  =  WSTM.str.trimL(stuff.substr(n + 1),  true);
               if (! show) {
                  show  =  stuff;
               }
               s  =  stuff.substr(0, 1).toUpperCase();
               if (s  !==  stuff.substr(0, 1)) {
                  stuff  =  s + stuff.substr(1);
               }
               s  =  WSTM.w.link.namespace.fetch(key, slang);
               if (s) {
                  scope  =  s;
               }
               stuff  =  scope + ":" + stuff;
               if (r[0] === "") {
                  stuff  =  ":" + stuff;
               }   // own DB itself
            }
         }
         r[1]  =  stuff;
         n     =  stuff.indexOf("|");
         if (show) {
            s  =  WSTM.str.trimL(show,  true);
         } else {
            WSTM.mod.lazy  =  false;
         }
         if (n < 0) {
            r[2]  =  (show  ?  s  :  stuff);
         } else {
            WSTM.mod.lazy  =  false;
            r[1]           =  stuff.substr(0, n);
            stuff          =  WSTM.str.trimL(stuff.substr(n + 1),  true);
            if (show) {
               if (stuff.length > 0) {
                  stuff  =  stuff + " " + s;
               } else {
                  stuff  =  s;
               }
            }
            r[2]  =  stuff;
         }
         n  =  r[2].indexOf("?title=");
         if (n > 0) {
            r[2]  =  r[2].substr(n + 7);
         }
      }   // replace target by wikilink
   }   // replace
   return  r;
};   // .w.link.wiki.url()



function wikisyntax_link_remove(adjust) {   // "L":wikisyntax_dewiki_PD()
   return  mw.libs.WikiSyntaxTextMod.w.link.wiki.remove(adjust);
}   // wikisyntax_link_remove()
WSTM.w.link.wiki.remove  =  function (adjust) {
   // Remove any wikilink from content string
   // Precondition:
   //    adjust  -- string, might contain wikilinks
   // Postcondition:
   //    Returns  false   if nothing to do
   //             string  with removed wikilinks
   //    RegExp was used.
   // Uses:
   //    .w.link.wiki.target()
   //    .str.trimL()
   // Requires: JavaScript 1.3   charCodeAt()
   // Remark:   Unused but neat
   // 2011-01-26 [email protected]
   var fa;
   var i     =  adjust.indexOf("[[");
   var j;
   var n;
   var r     =  false;
   var re;
   var s;
   var scan;
   var show;
   if (i >= 0) {
      scan  =  adjust;
      r  =  "";
      while (i >= 0) {
         r     =  r + scan.substr(0, i);
         scan  =  scan.substr(i + 2);
         n     =  scan.indexOf("\n");
         if (n > 0) {
            s  =  scan.substr(0, n);
         } else {
            s  =  scan;
         }
         n  =  s.indexOf("]]");
         if (n > 0) {
            s  =  s.substr(0, n);
            j  =  s.indexOf("|");
            if (j < 0) {
               show  =  WSTM.w.link.wiki.target(s, true);
               r     =  r  +  (show ? show : s);
            } else {
               s  =  WSTM.str.trimL(s.substr(j + 1),  false);
               if (s.charCodeAt(0) === 124) {   // '|'
                  re  =  new RegExp("^(:?[a-zA-Z]+:)?" +
                                     "([^|(,]+).*\\|",
                                    "");
                  fa  =  re.exec(scan);
                  if (fa !== null) {
                     show  =  WSTM.w.link.wiki.target(fa[2], true);
                     s     =  (show ? show : fa[2]);
                  }
               }
               r  =  r + s;
            }
            scan  =  scan.substr(n+2);
         } else {
            r     =  r + "[[";
         }
         i  =  scan.indexOf("[[");
      }   // while i
      r  =  r + scan;
   }   // something to do
   return  r;
};   // .w.link.wiki.remove()



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



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



mw.libs.WikiSyntaxTextMod.bb.tags  =  function (WSTM) {
   // Analyzing and formatting of tags <x>...</x>
   // Uses:
   //    .util.fiatObjects()
   // 2012-05-25 [email protected]
   WSTM.util.fiatObjects(WSTM.w,  "tags",  { });



   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|code|dfn|gallery"
                                     + "|hiddentext|hiero"
                                     + "|imagemap|includeonly|inputbox"
                                     + "|kbd|noinclude"
                                     + "|onlyinclude|poem|pre"
                                     + "|ruby|rb|rbc|rp|rt|rtc|samp",
                         blockEnd:   "gallery|imagemap|inputbox|pre"
                                     + "|references",
                         codeBlock:  "pre",
                         codeData:   "hiero|imagemap|inputbox|math|poem"
                                     + "|timeline",
                         codedFix:   "syntaxhighlight|source",
                         codeInline: "code|dfn|kbd|poem|samp",
                         comment:    "hiddentext",
                         direct:     "bdi|br|ref|hiddentext"
                                     + "|ruby|rb|rbc|rp|rt|rtc",
                         enclose:    "b|big|blockquote|center|i|em"
                                     + "|s|span|strong|u",
                         marker:     "gallery"
                         //          + "|imagemap"
                                     + "|includeonly|onlyinclude"
                                     + "|references",
                         parNone:    "hiddentext"
                                     + "|imagemap|includeonly|inputbox"
                                     + "|noinclude|nowiki|onlyinclude"
                                     + "|rb|rbc|rp|rt|rtc|ruby"
                                     + "|timeline",
                         parWith:    "bdi|br|code|dfn|div|gallery|hiero"
                                     + "|kbd|math|pages|poem|pre"
                                     + "|ref|references"
                                     + "|samp|small|source|span|sub|sup"
                                     + "|syntaxhighlight|tt",
                         unary:      "br|hr"
                       };   // 2012-06-05
   WSTM.w.tags.pars  =  { gallery:    "caption=|class=|heights=|perrow="
                                      + "|showfilename|style=|widths=",
                          ref:        "!|name=|group=|follow=",
                          references: "group="
                        };   // 2012-06-18



WSTM.w.tags.feature  =  function (arglist, access, adjust, assign) {
   // 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
   // Postcondition:
   //    Returns attribute value, or false if not available yet
   // 2012-03-30 [email protected]
   var r  =  false;
   var e  =  arglist.props;
   var i  =  0;
   var n  =  0;
   var p;
   if (e) {
      n  =  e.length;
      for (i = 0;  i < n;  i++) {
         p  =  e[i];
			if (p[1] === access) {
            r  =  p[2];
            if (adjust) {
               r  =  r.toLowerCase();
            }
            if (assign) {
               if (typeof(assign) === "string") {
                  p[2]  =  assign;
               } else if (n === 1  &&  ! i) {
                  arglist.props  =  false;
               } else {
                  arglist.props  =  e.splice(i, 1);
               }
            }
            i  =  -1;
				break;   // for i
			}
      }   // for i
   }
   if (assign) {
      if (typeof(assign) === "string") {
         if (i === n) {
            p  =  [ " ", access, assign ];
            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)
   // Uses:
   //    >  .w.tags.reTagAttrQ
   //    >  .w.tags.reTagAttrX
   //    >  .w.tags.reTagAttrS
   //    >  .w.tags.reTagAttrE
   //    >  .w.tags.reTagAttrU
   //     < .mod.lazy
   //    .errors.found()
   //    .str.trim()
   // 2012-06-15 [email protected]
   var got   =  true;
   var p;
   var r     =  false;
   var set   =  false;
   var sign;
   var spc;
   var sub   =  " " + assign;
   var sum   =  "|";
   while (got) {
      sign  =  false;
      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("tagAttrValueEmpty",
                              false,
                              "<" + about + " " + got[2] + "=\"\">");
            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;
         } else {
            set  =  false;
            got  =  this.reTagAttrS.exec(sub + "/");
            if (got) {
               sign  =  sub;
               got   =  this.reTagAttrE.exec(sub);
               if (got) {
                  sign  =  got[1];
                  WSTM.errors.found("tagAttrValueEmpty",
                                    false,
                                    "<" + about + " " + sign + "=>");
               } else {
               }
               spc  =  " ";
               set  =  "???";
               sub  =  " ";
               got  =  false;
            } else {
               got  =  this.reTagAttrU.exec(sub + "/");
               if (got) {
                  WSTM.errors.found("tagAttrInvalid",
                                    false,
                                    "<" + about + " " + assign);
                  set  =  sub;
               } else {
                  spc   =  " ";
                  sign  =  sub;
                  sub   =  " ";
               }
            }
         }
      }
      if (got) {
         spc  =  got[1];
         p    =  spc.indexOf("\n");
         if (p < 0) {
            spc  =  " ";
         } else {
            spc  =  spc.substr(p);
         }
         sign  =  got[2].toLowerCase();
         if (set) {
            set  =  WSTM.str.trim(set, true);
         }
         sub  =  sub.substr(got[0].length);
         if (sum.indexOf("|" + sign + "|")  <  0) {
            sum   =  sum + sign + "|";
         } else {
            got  =  "<" + about + " "
                    +  assign.substr(0,  assign.length - sub.length);
            WSTM.errors.found("tagAttrRepeated", false, got);
            got   =  false;
            sign  =  "";
         }
      }
      sign  =  WSTM.str.trim(sign, true);
      if (sign.length) {
         p  =  [ spc, sign, set ];
         if (r) {
            r.push(p);
         } else {
            r  =  [ p ];
         }
      }
   }   // while got
   sub  =  WSTM.str.trim(sub, true);
   if (sub.length) {
      WSTM.errors.found("tagAttrInvalid",
                        false,
                        "<" + about + " " + assign);
   }
   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()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-06-20 [email protected]
   var lbb  =  false;
   var lbe  =  false;
   var leb  =  false;
   var lee  =  false;
   var i;
   var j;
   var k;
   var m;
   var n;
   var r;
   var s;
   var re    =  this.reEndTags[arglist.scope];
   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.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);
      }
      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
   // 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.suckNowiki
   //    .errors.found()
   //    .w.chr.fixTab()
   //    .str.trim()
   //    .w.tags.features()
   //    .w.tags.focus()
   //    .w.tags.format()
   // 2012-06-18 [email protected]
   //    >  .w.tags.pars
   var got;
   var i;
   var m;
   var n;
   var sub;
   arglist.n  =  arglist.source.indexOf(">", arglist.move)  +  1;
   if (arglist.n) {
      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.n     =  0;
         arglist.move  =  (i > arglist.move  ?  i - 1  :  m);
      } else if (i > arglist.move) {
         arglist.move  =  i - 1;
         i             =  (i > 100  ?  100  :  i);
         WSTM.errors.found("tagFormReOpen",
                           false,
                           "<"  +  arglist.source.substr(0, i));
         arglist.n  =  0;
      } else {
         sub           =  arglist.source.substr(arglist.move);
         arglist.move  =  m;
      }
      if (arglist.n) {
         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 (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;
            }
         }
         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.comment
   //    >  .w.tags.elt.direct
   //    >  .w.tags.elt.marker
   //    >  .w.tags.elt.parNone
   //    >  .w.tags.elt.unary
   //    >  .w.tags.elt.enclose
   //    >  .w.chr.detected.tab
   //     < .w.tags.blocks
   //     < .w.tags.reCommentBeg
   //     < .w.tags.reEndTags
   //     < .w.tags.reTagAttrE
   //     < .w.tags.reTagAttrQ
   //     < .w.tags.reTagAttrS
   //     < .w.tags.reTagAttrU
   //     < .w.tags.reTagAttrX
   //     < .w.tags.reTagBeg
   //     < .w.tags.reTagEnd
   //     < .w.tags.sealed
   //     < .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
   //    .o.WikiTom().find()
   //    .str.uniques()
   //    .o.WikiTom().fetch()
   //    .o.WikiTom().flip()
   //    .o.WikiTom().fresh()
   //    .o.WikiTom().frame()
   //    .w.tags.fold()
   //    .w.tags.frame()
   //    .errors.found()
   //    .o.WikiTom().fixTab()
   // Requires: JavaScript 1.3   fromCharCode()
   // 2012-06-15 [email protected]
   var got   =  all.find("<", 0, 0, true, false);
   var j;
   var k;
   var s     =  "([" + WSTM.w.chr.whitespace + "]+)?";
   var sqd   =  String.fromCharCode(34,8220,8221,8222);
   var sqs   =  String.fromCharCode(39,8216,8217,8218);
   var tag;
   var open  =  [ ];
   this.blocks        =  false;
   this.reCommentBeg  =  new RegExp("^" + s + "!--");
   this.reEndTags     =  { };
   this.reTagAttrE    =  new RegExp("\\b([^ =\n]+)[ \n]*=[ \n]*$");
   this.reTagAttrQ    =  new RegExp("^" + "( *\n *| +)"
                                        + "([a-z_A-Z:0-9]+)"
                                        + " *\n? *= *\n? *"
                                        + "(?:'([^'\n]*)'"
                                          + "|\"([^\"\n]*)\""
                                        + ")");
   this.reTagAttrS    =  new RegExp("^" + "( *\n *| +)"
                                        + "([a-z_A-Z:0-9]+)"
                                        + "(?: *\n? *"
                                           + "([^= ]"
                                              + "(?:.|\n)*))$");
   this.reTagAttrU    =  new RegExp("^" + "( *\n *| +)"
                                        + "([a-z_A-Z:0-9]+)"
                                        + "(?: *\n? *= *)"
                                           + "((.|\n)*)$");
   this.reTagAttrX    =  new RegExp("^" + "( *\n *| +)"
                                        + "([a-z_A-Z:0-9]+)"
                                        + " *\n? *= *\n? *"
                                        + "(?:[" + sqs + "]" +
                                          "([^" + sqs + "]*)" +
                                          "[" + sqs + "]"
                                        + "|[" + sqd + "]" +
                                          "([^" + sqd + "]*)" +
                                          "[" + sqd + "]"
                                        + "|([^ \n]+)\\b"
                                        + ")");
   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.single        =  "|" + this.elt.parNone + "|";
   this.slice         =  "|" + this.elt.marker + "|ref|";
   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) {
         if (this.elt.hasOwnProperty(s)) {
            this.suitable  =  this.suitable + "|" + this.elt[s];
         }
      }   // for s in elt
     this.suitable  =  "|"
                       +  WSTM.str.uniques(this.suitable, "|")
                       +  "|";
   }
var ddeebbuugg=10000;
   while (got                                             &&ddeebbuugg) {
      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);
            }
            tag.join  =  got.i;
            tag.node  =  k;
            this.frame(all, tag, open);
            j  =  tag.join  +  tag.move;
            k  =  tag.node;
         }
      }
      got  =  all.find("<", j, k, true, false);
ddeebbuugg--;
   }   // 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
   //                >  .props
   //                >  .scope
   //                >  .source
   //                 < .limited
   //                 < .shift
   // Postcondition:
   //    Returns true, if to be folded as limited, or false
   // Uses:
   //    .w.tags.feature()
   //    .str.substrEnd()
   //    .w.tags.format()
   // 2012-05-28 [email protected]
   var got;
   var r      =  false;
   var re;
   var s;
   var set    =  false;
   var style;
   if ("|br|div|".indexOf(arglist.scan) >= 0) {
      s  =  this.feature(arglist, "clear", true, false);
      if (s) {
         arglist.scope  =  "div";
         if ("|both|left|right|none|all|".indexOf("|" + s + "|")  <  0) {
            WSTM.errors.found("tagAttrValue",
                              false,
                              "<" + arglist.tags.format() + ">");
         } else {
            this.feature(arglist, "clear", true, true);
            set  =  s;
            r    =  true;
         }
      }
      style  =  this.feature(arglist, "style", false, false);
      if (style) {
         re   =  /\bclear *: *([^ ;\n]+) *;/i;
         s    =  style;
         if (WSTM.str.substrEnd(s, 1)  !==  ";") {
//       if (s.slice(-1) !== ";") {
            s  =  s + ";";
         }
         got  =  re.exec(s);
         if (got) {
            set    =  got[1].toLowerCase();
            style  =  s.replace(re, "");
         }
      } else {
         style  =  "";
      }
      if (set) {
         arglist.scope    =  "div";
         arglist.limited  =  true;
         arglist.scan     =  "|div|";
         if (set === "all") {
            set  =  "both";
         }
         style  =  "clear:" + set + ";" + style;
         this.feature(arglist, "style", false, style);
         r  =  true;
      }
      s              =  this.format(arglist);
      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
   //                >  .mode
   //                >  .move
   //                >< .join
   // Postcondition:
   //    tag object and WikiTom updated
   // Uses:
   //    >  .w.tags.references
   //    >  .o.WikiTom.TagBegin
   //    >  .o.WikiTom.TagEnd
   //    .o.WikiTom().focus()
   //    .str.isBlank()
   //    .w.tags.flip()
   //    .w.tags.free()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-05-27 [email protected]
   var c;
   var i;
   var j;
   var later    =  false;
   var liaison  =  true;
   var lonely   =  false;
   var s;
   if (arglist.lone) {
      later  =  (arglist.scope === "br");
   } else {
      later  =  (arglist.mode === WSTM.o.WikiTom.TagEnd);
      if (arglist.scope === "ref") {
         liaison  =  (! this.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.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)
   //    arglist  -- tag object
   //                >  .scope
   //                >  .lone
   //                 < .props
   // Postcondition:
   //    Array .props has been assigned
   // Uses:
   //    .errors.found()
   //    >  .w.tags.pars
   // 2012-06-18 [email protected]
   var i;
   var p;
   var s;
   var support  =  this.pars[ arglist.scope ];
   if (support) {
      support  =  "|" + support + "|";
      for (i = 0;  i < apply.length;  i++) {
         p  =  apply[i];
         s  =  "|" +  p[1]  +  (p[2] ? "=|" : "|");
         if (support.indexOf(s) < 0) {
            WSTM.errors.found("tagAttrUnknown",
                              false,
                              "<" + arglist.scope + " " + p[1]
                              + (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 found 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
   //    >  .vsn
   //    >  .w.tags.replaceComment
   //    >  .o.WikiTom.TextOnly
   //    >  .w.tags.reTagBeg
   //    >  .w.tags.suitable
   //    >  .o.WikiTom.Tag
   //    >< .w.tags.reCommentVsn
   //    .errors.found()
   //    .hooks.fire()
   //    .str.substrEnd()
   //    .w.tags.fetch()
   // 2012-05-30 [email protected]
   var got    =  this.reCommentBeg.exec(adjust);
   var j;
   var n;
   var r      =  false;
   var s;
   var seek;
   var 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: false };
         n  =  adjust.indexOf("-->", 3);
         if (n > 0) {
            s       =  adjust.substr(3,  n - 3);
            r.move  =  n + 4;
            if (adjust.indexOf("__Version__") > 0) {
               if (! this.reCommentVsn) {
                  swift  =  "^ *__WikiSyntaxTextMod__Version__ *$";
                  this.reCommentVsn  =  new RegExp(swift, "i");
               }
               if (this.reCommentVsn.test(s)) {
                  // identify release in cache
                  r.shift  =  "!-- WikiSyntaxTextMod " + WSTM.vsn
                              + " -->";
                  r.move--;
                  n  =  0;
               }
            }
            swift  =  WSTM.hooks.fire("comment", s);
            if (swift) {
               if (typeof(swift) === "string") {
                  r.shift  =  "!--" + swift + "-->";
                  n        =  swift.length + 3;
               } else {
                  r.shift  =  "";
                  r.move--;
                  r.join  =  -1;
                  r.mode  =  0;
                  n       =  0;
               }
            }
            if (n  &&  this.replaceComment) {
               swift  =  "<!--" + s + "-->";
               for (j = 0;  j < this.replaceComment.length;  j++) {
                  swift  =  swift.replace(this.replaceComment[j][0],
                                          this.replaceComment[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:  (typeof(got[3]) === "string"),
                    move:    got[1].length,
                    scan:    seek,
                    scope:   s,
                    source:  adjust };
mw.log(WSTM.debugging,".w.tags.fold() r.leader 1"+r.leader,1,r);
            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()
   //    .errors.found()
   // 2012-05-03 [email protected]
   var i;
   var p;
   var r  =  (arglist.leader ? "/" : "")
             +  WSTM.str.trim(arglist.scope, true);
   if (arglist.props) {
      for (i = 0;  i < arglist.props.length;  i++) {
         p  =  arglist.props[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);
               arglist.n  =  0;
            }
         }
      }   // for i
   }
   if (arglist.lone) {
      r  =  r + " /";
   }
   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
   //                 < .limited
   //                 < .lookup
   //    arglist  -- tag information provided by .tags.fetch()
   //                >  .scan
   //                >  .stop
   //                >  .scope
   //                >  .lone
   //                >  .props
   //                >  .leader
   //                >  .source
   //                >< .mode
   //                >< .join
   //                >< .node
   //                >< .move
   //                 < .limited
   //                 < .lookup
   //    ago      -- Array with pending opening tags
   //                >< may pop or push
   // Postcondition:
   //    all  has been subdivided or merged, if necessary
   // Uses:
   //    >  .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.sources
   //    >  .w.tags.stack
   //    >  .w.tags.shift
   //    >  .w.tags.spacing
   //    >  .w.tags.slice
   //     < .w.tags.references
   //     < .w.encountered.include
   //    .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()
   // 2012-05-27 [email protected]
   var l       =  false;
   var lapsus  =  false;
   var m       =  0;
   var p       =  false;
   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) {
   } else if (arglist.scope === "nowiki") {
      l  =  arglist.lone;
      if (l) {
         arglist.mode    =  WSTM.o.WikiTom.Nowiki;
         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 (this.sources.indexOf(arglist.scan) >= 0) {
         m  =  WSTM.o.WikiTom.CodedBlock;
      } else {
         m  =  WSTM.o.WikiTom.Code;
      }
      if (arglist.lone) {
         WSTM.errors.found("tagUnaryIllegal",
                           false,
                           "<" + arglist.scope + " />");
      } else if (arglist.leader) {
         p  =  all.fetch(arglist.node,
                         arglist.join + arglist.move + 2,
                         false);
         p  =  WSTM.str.trim(p);
         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 === WSTM.o.WikiTom.CodedBlock) {
            if (arglist.props) {
               if (this.feature(arglist, "lang", false, false)) {
                  p  =  this.feature(arglist, "enclose", true, false);
                  if (p === "none") {
                     m  =  WSTM.o.WikiTom.CodedInline;
                  } else {
                     arglist.limited  =  true;
                     p                =  true;
                  }
               }
            }
            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 (arglist.leader) {
         p  =  ago.length;
         if (p) {
            p  =  ago[p-1];
            if (p.scope === arglist.scope) {
               if (p.node === arglist.node) {
                  if (this.friend(all, p, arglist)) {
                     all.flip(arglist.node,
                              p.join + 1,
                              arglist.move,
                              p.shift);
                     arglist.join    =  p.join;
                     arglist.move    =  p.shift.length;
                     arglist.lone    =  true;
                     arglist.leader  =  false;
                  }
               }
               m  =  p.node;
               ago.pop();
            } 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);
            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.story  =  ;  // context
         ago.push(arglist);
         if (this.stack.indexOf(arglist.scan) >= 0) {
            this.future(arglist.scope, true);
         }
      }
   }
   if (arglist.lone) {
      if ("|br|div|".indexOf(arglist.scan) >= 0) {
         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 (! l) {
      arglist.move  +=  2;
   }
   if (arglist.limited) {
      this.free(all, arglist);
      if (arglist.scope === "references") {   // imagemap
         if (arglist.lone  ||  ! arglist.leader) {
            if (this.references) {
               WSTM.errors.found("tagNestingSelf",
                                 false,
                                 "<" + arglist.scope + ">");
            } else if (! arglist.lone) {
               this.references  =  WSTM.w.elem.refgroups(arglist);
            }
         } else {
            this.references  =  false;
         }
      }
   }
   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.node++;
            arglist.join  =  0;
         }
         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()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-05-10 [email protected]
   var late  =  false;
   var lead  =  false;
   var j     =  (arglist.join > 0  ?  arglist.join - 1  :  0);
   var k;
   var m;
   var n;
   var s     =  all.fetch(arglist.node, j, false);
   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  -- tag object of begin; merged with arglist if unary
   //                 >  .join
   //                 >  .node
   //                 >  .scan
   //                 >  .scope
   //                  < .lone
   //                  < .move
   //                  < .n
   //                  < .shift
   //    arglist   -- tag object of end
   //                 >  .join
   //                 >  .move
   //    ancestor and arglist need to be the identical string node in all
   // Postcondition:
   //    Returns true, if strings to be merged, or false
   // Uses:
   //    .o.WikiTom().fetch()
   //    .str.trim()
   //    .errors.found()
   //    .w.tags.format()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-06-05 [email protected]
   var r  =  false;
   var j  =  arglist.join - ancestor.join;
   var k  =  0;
   var m  =  j - ancestor.move;
   var s  =  all.fetch(ancestor.node, ancestor.join, false);
   if (s.charCodeAt(0) === 60) {   // '<'
      k  =  s.indexOf(">");
   }
   m  =  j - ancestor.move;
   if (m > 0) {
      s  =  s.substr(k + 1,  m);
      s  =  WSTM.str.trim(s, true, true);
      m  =  s.length;
   }
   if (! m) {
      if (this.storing.indexOf(arglist.scan) < 0) {
         ancestor.lone    =  true;
         ancestor.leader  =  false;
         ancestor.shift   =  this.format(ancestor);
         ancestor.move    =  ancestor.shift.length;
         arglist.move     =  j + arglist.move;
         r                =  true;
      } else {
         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 two or three 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.replaceComment
   //    .util.isArray()
   //    .errors.found()
   //    .str.substrEnd()
   // 2012-05-10 [email protected]
   var a;
   var d;
   var f;
   var i;
   var l;
   var m;
   var n;
   var p  =  WSTM.mod.comment;
   var r;
   var s;
   var t;
   var 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.replaceComment  =  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 [email protected]
   var e;
   var i;
   var n;
   var r  =  false;
   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:
   //    >< .w.tags.blocks
   // 2012-03-19 [email protected]
   var i;
   var r  =  false;
   if (this.blocks) {
      for (i = 0;  i < this.blocks.length;  i++) {
         if (this.blocks[i] === assigned) {
            r  =  true;
            break;   // for i
         }
      }   // for i
      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.template  =  function (WSTM) {
   // Analysis of template transclusion and variables / parser functions
   // Uses:
   //    .util.fiatObjects()
   // 2012-05-28 [email protected]
   WSTM.util.fiatObjects( WSTM.w,  "template",
                          { file: { },
                            mod:  { },
                            out:  { },
                            par:  { },
                            re:   {  Variables: { }
                                  }
                          } );



WSTM.w.template.factory  =  function () {
   // Create template configuration data
   // Precondition:
   //    all  -- WikiTom to be analyzed and subdivided (root)
   // Postcondition:
   //    all  has been subdivided, if necessary
   // Uses:
   //    >  .g.s.re.Variables.$
   //    >  .g.s.re.Variables.*
   //    >  .g.projLang
   //    >  .l10n.s.re.Variables.*
   //     < .w.template.space
   //     < .w.template.re.space
   //     < .w.template.sort
   //     < .w.template.show
   //     < .w.template.sibling
   //     < .w.template.re.vars
   //     < .w.template.re.funs
   //     < .w.template.re.special
   //    .l10n.word.fetch()
   //    .w.template.file.factory()
   // 2012-04-25 [email protected]
   var slang  =  WSTM.l10n.word.fetch("Template", 0);
   var space  =  "template";
   if (slang) {
      this.space  =  slang;
      slang  =  slang.toLowerCase();
      if (slang !== space) {
         space  =  slang + "|" + space;
      }
   }
   this.re.space  =  new RegExp("^(" + space + "):.*",  "i");
   this.show      =  "|DISPLAYTITLE|";
   slang          =  WSTM.l10n.word.fetch("DISPLAYTITLE", 0);
   if (slang) {
      slang  =  slang.toUpperCase();
      if (this.show.indexOf("|" + slang + "|")  <  0) {
         this.show  =  "|" + slang + this.show;
      }
   }
   this.sort  =  "|DEFAULTSORT|DEFAULTSORTKEY|DEFAULTCATEGORYSORT|";
   slang      =  WSTM.l10n.word.fetch("DEFAULTSORT", 0);
   if (slang) {
      slang  =  slang.toUpperCase();
      if (this.sort.indexOf("|" + slang + "|")  <  0) {
         this.sort  =  "|" + slang + this.sort;
      }
   }
   this.sibling  =  "|COMMONS|COMMONS CAT|COMMONSCAT" +
                    "|WIKIMEDIA" +
                    "|WIKIBOOKS|WIKINEWS|WIKIPEDIA|WIKIQUOTE" +
                    "|WIKISOURCE|WIKIVERSITY|WIKTIONARY|";
   this.re.vars  =  WSTM.g.s.re.Variables.$;
   slang         =  WSTM.l10n.s.re.Variables[WSTM.g.projLang];
   if (typeof(slang) === "string") {
      this.re.vars  =  this.re.vars + "|" + slang;
   }
   this.re.vars  =  new RegExp("^(" + this.re.vars + ")$",  "i");
   this.re.funs  =  WSTM.g.s.re.Variables[":"];
   slang         =  WSTM.l10n.s.re.Variables[ WSTM.g.projLang + ":" ];
   if (typeof(slang) === "string") {
      this.re.funs  =  this.re.funs + "|" + slang;
   }
   this.re.funs     =  new RegExp("^(" + this.re.funs + ")$",  "i");
   this.re.special  =  new RegExp(" /.-%|");
   this.file.factory();
};   // .w.template.factory()



WSTM.w.template.feature  =  function (adjust, assign, align, arg, about) {
   // Analyze and split template parameter and its value
   // Precondition:
   //    adjust  -- WikiTom of template to be analyzed and subdivided
   //    assign  -- start node in adjust
   //    align   -- position of assignment separation '|' in assign
   //    arg     -- number of argument in template
   //    about   -- template name
   //    Links (wikilink pipes) and nested templates already separated
   // Postcondition:
   //    adjust  has been subdivided, if necessary
   //    Returns assignment information
   //            .br      terminated with \n
   //            .brB     \n
   //            .brP     \n
   //            .indent  number of spaces before parameter name
   //            .keep    number of chars before '='
   //            .pre
   //            .proceed {.i, .k, .loop}  or  false
   //            .symbol  parameter name
   //            .value
   // Uses:
   //    >  .w.template.re.feature
   //    >  .o.WikiTom.TmplParam
   //     < .o.WikiTom().mode
   //     < .o.WikiTom().lookup
   //    .o.WikiTom().fetch()
   //    .str.fromNum()
   //    .o.WikiTom().folder()
   //    .o.WikiTom().find()
   //    mw.log()
   //    .o.WikiTom().focus()
   //    .o.WikiTom().fold()
   //    .o.WikiTom().fork()
   //    .o.WikiTom()
   //    .hooks.fire()
   //    .errors.found()
   //    .str.trimL()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-06-16 [email protected]
   var kids  =  false;
   var got;
   var i;
   var j     =  align + 1;
   var k;
   var n;
   var r     =  { pre:     0,
                  proceed: false,
                  value:   false };
   var s     =  adjust.fetch(assign, 0, false);
   if (align) {
      for (i = align - 1;  i >= 0;  i--) {
         switch (s.charCodeAt(i)) {
            case 32 :   // ' '
               r.pre++;
               break;
            case 10 :   // '\n'
               r.br  =  true;
            default :
               i  =  -1;
         }   // switch charCodeAt
      }   // for i
   }
   s  =  s.substr(j);
   if (s.charCodeAt(0) === 10) {   // '\n'
      r.brB  =  true;
      j++;
      s  =  s.substr(1);
   }
//  "^( *)([^ |=]+)( *(\n)? *)="
//mw.log(WSTM.debugging,".w.template.feature() ##"+s+"##",0);
   got  =  this.re.feature.exec(s);
//mw.log(WSTM.debugging,".w.template.feature() s="+s,0);
   if (got) {   // named parameter
      n         =  got[0].length;
      r.indent  =  got[1].length;
      r.symbol  =  got[2];
//    r.value   =  new WSTM.o.WikiTom(s.substr(n), adjust);
      if (got[4]) {
         r.brP  =  true;
      }
      if (got[3]) {
         r.keep  =  got[3].length;
      } else {
         r.keep  =  0;
      }
      j  +=  n;
//mw.log(WSTM.debugging,".w.template.feature() got[0]="+got[0],0);
   } else {   // no-name parameter
      r.indent  =  0;
      r.symbol  =  WSTM.str.fromNum(arg);
      r.value   =  new WSTM.o.WikiTom(s, adjust);
//mw.log(WSTM.debugging,".w.template.feature() no-name  s="+s,0,r.value);
   }
   if (j > align) {
      got  =  adjust.folder(align, assign, j, assign);
//mw.log(WSTM.debugging,".w.template.feature() j-align="+(j-align),0);
   }
   if (got) {
      got.mode    =  WSTM.o.WikiTom.TmplParam;
      got.lookup  =  false;
      got         =  adjust.find("|", 0, assign, true, false, false);
      i           =  assign   +   (assign > 2  ?  1  :  2);
      r.proceed   =  { i: 0,  k: i + 1 };
      if (got) {
         k               =  got.k;
         r.proceed.i     =  got.i + 1;
         r.proceed.loop  =  true;
      } else {
         got  =  adjust.find("}}", 0, i, true, false, false);
//mw.log(WSTM.debugging,".w.template.feature() }}",0,got);
         if (got) {
            k   =  got.k;
            if (! got.i) {
//             k--;    //////////////////// ??????????????????????
               i            =  (assign > 2  ?  i  :  --i);
               r.proceed.k  =  i;
            }
         } else {
            mw.log(WSTM.debugging, ".w.template.feature() }}", 2);
         }
      }
      if (got) {
         if (! got.i) {
            if (got.child) {
mw.log(WSTM.debugging,".w.template.feature() got.child",0);
               r.value  =  got.child.o;
            } else if (k === i) {
//mw.log(WSTM.debugging,".w.template.feature() k="+k+"  i="+i,0,r.value);
//               if (typeof(r.value) !== "object") {
               r.value  =  new WSTM.o.WikiTom("", adjust);
//               }
            } else if (k - 1  ===  i) {
               r.value  =  adjust.focus(got.k - 1);
            }
         } else {
            got  =  adjust.fold(k, got.i, false);
            if (got) {
               r.value  =  got;
//mw.log(WSTM.debugging,".w.template.feature() .fold="+s+"\n"+got,0);
               k++;///////////////////////////
            }
         }
         if (k - 1  >  i) {
            r.value  =  adjust.fork(i,
                                    k - 1,
                                    "value",
                                    WSTM.o.WikiTom.TmplValue,
                                    false);
//mw.log(WSTM.debugging,".w.template.feature() fork="+r.value,0);
         } else if (got.source) {
            r.value  =  new WSTM.o.WikiTom(got.source, adjust);
         }
         // r.br   terminated
      }
   }
   if (r.value === false) {
      r.value  =  new WSTM.o.WikiTom("", adjust);
   }
   if (r.value) {
      s  =  r.value.source;
      if (s) {
         s  =  WSTM.str.trimL(s, false);
         if (s.charCodeAt(0) === 61) {
            if (! WSTM.hooks.fire("valEqualsign", about)) {
               WSTM.errors.found("templateParStart=",
                                 false,
                                 s.substr(0, 50));
            }
         }
      }
   }
   return  r;
};   // .w.template.feature()



WSTM.w.template.features  =  function (adjust) {
   // Analyze and split template parameters and their values
   // Precondition:
   //    adjust  -- WikiTom of template to be analyzed and subdivided
   // Postcondition:
   //    adjust  has been subdivided, if necessary
   //        < .values  -- ArrayM   i=0: Title
   //                          < [i].symbol
   //                          < [i].value
   // Uses:
   //    >  .o.WikiTom().mode
   //    >  .o.WikiTom.LinkWeb
   //    >< .w.template.re.feature
   //     < .o.WikiTom().mode
   //     < .o.WikiTom().lookup
   //    .o.WikiTom().focus()
   //    .w.link.wiki.linked()
   //    .o.WikiTom().fetch()
   //    .str.trim()
   //    .o.WikiTom().fold()
   //    .o.WikiTom().find()
   //    .w.template.feature()
   //    .w.template.par.fetch()
   //    .hooks.fire()
   //    .util.isbn.format()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-06-16 [email protected]
   var got;
   var j;
   var k;
   var n      =  adjust.children.length;
   var p;
   var s      =  false;
   var story;
   var tmpl   =  false;
   if (! this.re.feature) {
      this.re.feature  =  new RegExp("^( *)([^ |=]+)( *(\n)? *)=");
   }
WSTM.o.WikiTom.Level=0;
   for (k = n - 1;  k > 1;  k--) {
      p  =  adjust.focus(k);
      if (p) {
         if (p.mode === WSTM.o.WikiTom.LinkWeb) {
            j  =  p.source.indexOf("|");
            if (j > 0) {
               got  =  adjust.fold(k, j, true);
            }
         } else if (WSTM.w.link.wiki.linked(p)) {
            if (adjust.fetch(k + 1,  0,  true)   ===   124) {   // '|'
               got  =  adjust.fold(k + 1,  1,  false);
               if (got) {
                  got.mode    =  WSTM.o.WikiTom.LinkWikiPipe;
                  got.lookup  =  false;
               }
            }
         }
      }
   }   // for k
   if (n > 1) {
      story  =  adjust.fetch(1, 0, false);
   } else {
      p  =  adjust.children[0];
      if (p) {
         s  =  p.source.substr(2);
         p  =  s.indexOf("|");
         if (p < 0) {
            p  =  s.length - 2;
         }
         story  =  s.substr(0, p);
      }
   }
   k  =  2;
   j  =  0;
   do {
      got  =  adjust.find("|", j, k, true, false, false);
      if (got) {
         j  =  got.i + 1;
         k  =  got.k;
         if (k === 2) {
            p  =  { };
            if (got.i) {
               s      =  adjust.fetch(2, 0, false);
               p.br   =  (s.charCodeAt(0) === 10);   // '\n'
               p.pre  =  (p.br  ?  got.i - 1  :  got.i);
            }
            tmpl  =  [ p ];
         }
         got  =  this.feature(adjust, k, got.i, tmpl.length, story);
         if (got) {
            if (got.symbol && got.value) {
               if (got.symbol.length === 4) {
                  p  =  got.symbol.toLowerCase();
                  if (p === "isbn") {
                     s  =  this.par.fetch(got);
                     if (s) {
                        s  =  WSTM.str.trim(s, true, true);
                        if (s.length) {
                           p  =  WSTM.util.isbn.format(s, false);
                           if (p[1]) {
                              got.value  =  p[1];
                           }
                        }
                     }
                  } else if (p === "issn") {
mw.log(WSTM.debugging,".w.template.features()  issn="+got.value,0);
                     s  =  this.par.fetch(got);
                     if (s) {
                        got.value.source  =  WSTM.hooks.fire("issn",
                                                             [ s,
                                                               false ]);
                     }
                  }
               }
            }
            if (tmpl) {
               tmpl.push(got);
            } else {
               tmpl  =  [ got ];
            }
            p  =  got.proceed;
            if (p) {
               k++;
               j  =  0;
               p  =  p.loop;
            }
            delete got.proceed;
            got  =  p;
         }
      }
   } while (got);   // do
   if (story && tmpl) {
      tmpl[0].symbol  =  story;
   }
   adjust.values  =  tmpl;
//mw.log(WSTM.debugging,".w.template.features()  adjust.values",0,tmpl);
};   // .w.template.features()



WSTM.w.template.findISBN  =  function () {
   // Check whether ISBN template parameter in text
   // Postcondition:
   //    Flag is set
   // Uses:
   //    >  .mod.luxury
   //    >  .text
   //     < .w.encountered.isbn
   //    .o.WikiTom().find()
   // 2012-05-24 [email protected]
   var re;
   if (! WSTM.mod.luxury) {
      re  =  new RegExp("\\|[ \n]*isbn[ \n]*=",  "i");
      if (WSTM.text.find([re, 0],  0,  0,  true,  false,  false)) {
mw.log(WSTM.debugging,".w.template.findISBN()",0,WSTM.text.find(re, 0, 0, true, false, false));
         WSTM.w.encountered.isbn  =  true;
      }
   }
};   // .w.template.findISBN()



WSTM.w.template.fine  =  function (adjust) {   //   TODO: ÜB
   // Polish template content and layout
   // Precondition:
   //    adjust  -- .values Array:
   //               [0] template name
   //               [1] first parameter name, or false
   //                   .symbol
   //               etc.
   // Postcondition:
   //    Returns  object
   //             .arr     Array: names
   //                      [0] template name
   //                      [1] first parameter assignment
   //                      etc.
   //                      members of assign first, then others of adjust
   //             .obj     object
   //                      parameter name: value
   //             .learnt  need for reformatting
   //             .arr, .obj: objects
   //                         .d       WikiTom content
   //                         .i       sequence number
   //                         .symbol  name
   // 2012-05-31 [email protected]
   var d;
   var i;
   var n  =  adjust.length;
   var r  =  { arr:     new Array(n),
               obj:     { },
               learnt:  false };
   var s;
   var t  =  r.arr;
   var u  =  r.obj;
   for (i = 0;  i < n;  i++) {
      d  =  adjust[i];
      if (d) {
         s  =  d.symbol;
         if (u[s]) {
            u[s].d  =  d;
         } else {
            r.learnt  =  true;
            t.push(s);
            u[s]  =  { i:      t.length,
                       symbol: s };
         }
      }
   }   // for i
   n  =  t.length;
   for (i = 0;  i < n;  i++) {
      t[i]  =  u[ t[i] ];
   }   // for i
   return  r;
};   // .w.template.fine()



WSTM.w.template.fire  =  function (all, activate) {
   // Start template analysis on top level
   // Precondition:
   //    all       -- WikiTom to be analyzed and subdivided (root)
   //    activate  -- initialize
   // Postcondition:
   //    all  has been subdivided, if necessary
   // Uses:
   //    .w.template.factory()
   //    .o.WikiTom().find()
   //    .w.template.fire()  -- recursive
   //    .w.template.fold()
   // 2012-05-07 [email protected]
   var deep;
   var got;
   var i     =  0;
   var k     =  0;
   if (activate) {
      this.factory();
   }
   do {
      got  =  all.find("{{", i, k, true, false, false);
      if (got) {
         deep  =  got.child;
         if (deep) {
//mw.log(WSTM.debugging,".w.template.fire deep",0,deep);
            i  =  0;
            k  =  got.k + 1;
            this.fire(deep.o, false);
         } else {
            got  =  this.fold(got, false, all);
            i    =  got.i;
            k    =  got.k;
         }
      }
   } while (got);   // do
};   // .w.template.fire()



WSTM.w.template.fold  =  function (appoint, adjacent, all) {
   // Start template analysis on relative top level
   // Precondition:
   //    appoint   -- location object of begin
   //                 .i  position of beginning "{{"
   //                 .k  sibling number
   //    adjacent  -- location object of end, or false
   //                 .i  position of beginning "}}"
   //                 .k  sibling number
   //    all       -- WikiTom to be analyzed and subdivided
   //                 (root or higher level template or tag construct)
   // Postcondition:
   //    Returns  object with updated appoint
   //             .i  position of ending "}}"
   //             .k  sibling number
   //    all  has been subdivided, if necessary
   // Uses:
   //    >  .o.WikiTom.TmplParam
   //    >  .mod.luxury
   //    >  .w.encountered.indent
   //    >  .w.encountered.isbn
   //    >  .o.WikiTom.Template
   //    >  .mod.hyper
   //    >  .mod.plain
   //    >< .w.template.templates
   //    .o.WikiTom().fetch()
   //    .o.WikiTom().fold()
   //    .o.WikiTom().focus()
   //    .o.WikiTom().find()
   //    .w.template.fire()   -- recursive (indirect)
   //    .w.template.fold()   -- recursive
   //    .o.WikiTom().folder()
   //    .w.template.format()
   //    .o.WikiTom().fork()
   //    .w.template.mod.former()
   //    .w.link.fire()
   //    .w.template.features()
   //    .w.template.file.featured()
   //    .w.template.file.full()
   //    .w.template.mod.fire()
   //    .str.substrEnd()
   //    .errors.found()
   // 2012-06-16 [email protected]
   var behind  =  false;
   var div     =  false;
   var end     =  false;
   var low     =  (all.fetch(appoint.k,  appoint.i + 2,  true)
                   ===   123);   // '{'
   var got     =  { i:  appoint.i,
                    k:  appoint.k };
   var move    =  (low ? 3 : 2);
   var node    =  got.k;
   var r       =  { i:  got.i,
                    k:  got.k };
   var scan    =  (low ? "{{{" : "{{");
   var seek    =  (low ? "}}}" : "}}");
   var tbeg;
   var tend;
   if (appoint.i) {
      tbeg  =  all.fold(appoint.k, appoint.i, false);
      r.i   =  0;
      r.k++;
      node++;
   } else {
      if (adjacent) {
         end   =  { i: adjacent.i,  k: adjacent.k };
      }
      tbeg  =  all.focus(appoint.k);
   }
   if (tbeg) {
var ddeebbuugg=0;
      do {
ddeebbuugg++;////////////////////////////////////
         r.i     +=  move;
         behind   =  all.find(seek, r.i, r.k, true, false, false);
         got      =  all.find(scan, r.i, r.k, true,  false,  false);
//mw.log(WSTM.debugging,".w.template.fold() "+ddeebbuugg+"   r.k="+r.k+"   r.i="+r.i+"       got.k="+got.k+"   got.i="+got.i,0);
         if (behind && got) {   // inner?
            if (got.k < behind.k     ||
                (got.k === behind.k  &&  got.i < behind.i)) {// recursive
//mw.log(WSTM.debugging,".w.template.fold() .fold",0);
               got  =  this.fold(got, behind, all);
               if (got) {
                  r  =  got;
               } else {
                  end  =  false;
               }
            } else {
               end  =  behind;
               got  =  false;
            }
         } else {
            end  =  behind;
            got  =  false;
         }
      } while (got);   // do
if (ddeebbuugg>1) {
//mw.log(WSTM.debugging,".w.template.fold()  ddeebbuugg ddeebbuugg   "+ddeebbuugg,0);
}
      if (end) {
         if (! low) {
            if (end) {//   end.i
               tend  =  all.folder(0,  end.k,  end.i + move,  end.k);
            } else {
               tend  =  tbeg;
            }
            // end.k    zu groß; hat forks innerhalb nicht mitbekommen
            div  =  this.format(node, end.k, all);
            if (tend && div) {
               if (node > appoint.k) {
                  tbeg  =  all.focus(node);
               }
               if (low) {
                  tbeg.scope  =  "templateParameter";
                  tbeg.mode   =  WSTM.o.WikiTom.TmplParam;
               } else {
                  tbeg.scope  =  div.sore;
               }
               tend.scope  =  tbeg.scope;
               tend.mode   =  tbeg.mode;
               if (div.joint > node           ||
                   WSTM.mod.luxury            ||
                   WSTM.w.encountered.indent  ||
                   WSTM.w.encountered.isbn    ||
                   div.hook                   ||
                   div.mod) {
                  got  =  all.fork(node,
                                   div.joint,
                                   div.scope,
                                   tbeg.mode,
                                   false);
                  if (got) {
                     got.mode  =  div.mode;
                     if (got.mode === WSTM.o.WikiTom.Template) {
                        if (WSTM.mod.luxury          ||
                            WSTM.w.encountered.isbn  ||
                            div.hook                 ||
                            div.mod) {
                           if (WSTM.mod.hyper) {
                              this.mod.former(got);
                           }
                           WSTM.w.link.fire(got, false, true, true);
                           if (WSTM.mod.plain           ||
                               WSTM.w.encountered.isbn  ||
                               div.hook                 ||
                               div.mod) {
                              this.features(got);
                              this.file.featured(got);
                              if (typeof(div.hook) === "function") {
                                 div.hook(got);
                              }
                              if (div.mod) {
                                 this.mod.fire(got);
                                 /////////////////////////
                                 // prolog epilog
                              }
                           } else {
                              this.file.full(got);
                           }
                        }
                     }
                     end.k  =  node;
                  }
               }
            }
            r  =  { i:  0,
                    k:  end.k + 1 };
         }
      } else {
         got  =  all.focus(node);
         if (got) {
            if (got.mode !== WSTM.o.WikiTom.Template) {
               got  =  false;
            }
         }
         if (got) {
            got  =  all.fetch(node, appoint.i, false);
            if (got) {
               got  =  "... "  +  got.substr(0, 50);
            } else if (node !== appoint.k) {
               got  =  all.fetch(node, 0, false);
               if (got) {
                  got  =  "... "  +  got.substr(0, 50);
               }
            } else {
               got  =  all.fetch(appoint.k + 1,  0,  false);
               got  =  WSTM.str.substrEnd(got, 50)  +  " ...";
//             got  =  got.slice(-50) + " ...";
/*
            } else if (appoint.i) {
               got  =  all.fetch(appoint.k, 0, false);
               got  =   "... "  +  got.substr(0, 50);
            } else if (appoint.k) {
               got  =  all.fetch(appoint.k - 1,  0,  false)
               got  =  WSTM.str.substrEnd(got, 50);  +  " ...";
*/
            }
            ///////////////////////   Name in Fehlermeldung    tbeg
mw.log(WSTM.debugging,".w.template.fold() .errors.found "+low,2,got);
            WSTM.errors.found( (low ? "templateParStart"
                                    : "templateStart"),
                               false,
                               got);
         }
      }
   }
   return  r;
};   // .w.template.fold()



WSTM.w.template.format  =  function (at, advance, all) {
   // Format a template or parser function transclusion
   // Precondition:
   //    at       -- first node in all, starting at beginning of "{{"
   //    advance  -- last node in all, terminated with "}}"
   //    all      -- WikiTom to be analyzed and subdivided
   // Postcondition:
   //    Returns  object
   //             .joint  node number of termination, or advance
   //             .hook   callback function (forked element as parameter)
   //                     or false
   //             .mod    may be subject to modification
   //             .scope  kind of node
   //             .sore   variable or function ID
   //    May insert more nodes
   // Uses:
   //    >  .o.WikiTom.Template
   //    >  .w.template.re.space
   //    >  .w.template.space
   //    >  .w.template.re.funs
   //    >  .w.template.sort
   //    >  .w.template.show
   //    >  .w.template.re.vars
   //    >  .w.template.re.special
   //    >  .w.template.sibling
   //    >  .o.WikiTom.MagicWord
   //    >  .mod.luxury
   //    >  .w.encountered.isbn
   //    >  .mod.hyper
   //    >  .mod.template
   //    >  .mod.text
   //    >  .mod.plain
   //    >  .o.WikiTom.LinkTemplate
   //     < .o.WikiTom().mode
   //     < .o.WikiTom().lookup
   //     < .o.WikiTom().scope
   //     < .mod.lazy
   //    .o.WikiTom().fetch()
   //    .str.trimL()
   //    .str.trimR()
   //    .str.substrEnd()
   //    .str.makeString()
   //    .w.elem.defaultsort()
   //    .w.elem.displaytitle()
   //    .errors.found()
   //    .w.link.wiki.decode()
   //    .l10n.templates.issn.format()
   //    .w.template.sister()
   //    .o.WikiTom().focus()
   //    .hooks.fire()
   //    .o.WikiTom().fresh()
   //    .w.template.mod.find()
   //    .w.link.replace.flipper()
   //    .o.WikiTom().fold()
   //    .o.WikiTom().focus()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-06-17 [email protected]
   var got;
   var i;
   var k;
   var immune  =  0;
   var indent;
   var later   =  false;   //   line break to be inserted behind
   var lead    =  false;   //   line break ahead to be inserted
   var leap    =  false;   //   string changed
   var learn   =  false;   //   update element
   var leave   =  false;   //   discard element
   var lock    =  false;   //   no lookup
   var low     =  false;   //   variable or parser function
   var lone    =  false;   //   single line
   var mode    =  WSTM.o.WikiTom.Template;
   var r       =  { joint: advance,
                    scope: "template" };
   var scan;
   var scope   =  r.scope;
   var shift;
   var slice   =  "";
   var space   =  "";
   var store   =  all.fetch(at, 2, false);
   var stuff   =  false;   //   really template
   var sub;
   var suffix  =  false;
   var symbol;
   shift  =  WSTM.str.trimL(store, false);
   low    =  (shift.charCodeAt(0) === 35);   // '#'
   if (! low) {
      i  =  shift.indexOf(":");
      if (i > 0) {
         got  =  this.re.space.exec(shift);
         if (got) {
            shift  =  WSTM.str.trimL(shift.substr(i + 1),  false);
            if (shift.charCodeAt(0) === 47) {   // '/'
               shift  =  this.space + ":" + shift;
            }
            stuff  =  shift;
         } else {
            sub  =  WSTM.str.trimR(shift.substr(0, i),  false,  false);
            got  =  this.re.funs.exec(sub);
            if (got) {
               low    =  true;
               sub    =  got[1];
               shift  =  sub  +  ":"  +  shift.substr(i + 1);
               if (sub === sub.toUpperCase()) {
                  scan  =  "|" + sub + "|";
                  if (this.sort.indexOf(scan) >= 0) {
                     if (at === advance) {
                        shift   =  "{{"
                                   + WSTM.w.elem.defaultsort(shift, sub);
                        lock    =  true;
                        lone    =  true;
                        r.sore  =  "DEFAULTSORT";
                        low     =  true;
                        indent  =  0;
                        immune  =  shift.length + 2;
                     } else {
                        WSTM.errors.found("defaultsortValue",
                                          false,
                                          store.substr(0, 50));
                     }
                  } else if (this.show.indexOf(scan) >= 0) {
                     shift  =  WSTM.w.elem.displaytitle(shift, sub);
                     if (shift) {
                        lone    =  true;
                        r.sore  =  "DISPLAYTITLE";
                     } else {
                        leave  =  true;
                     }
                  }
               }
            } else {
               stuff  =  shift;
            }
         }
      } else if (this.re.special.test(WSTM.str.trimR(shift,
                                                     false, false))) {
         stuff  =  shift;
      }
   }
   if (!  (stuff || low)) {
      i  =  shift.indexOf("|");
      if (i > 0) {
         stuff  =  shift;
      } else {
         if (WSTM.str.substrEnd(shift, 2)  ===  "}}") {
//       if (shift.slice(-2) === "}}") {
            shift  =  WSTM.str.trimR(shift.slice(0, -2),  false,  false);
            got    =  this.re.vars.exec(shift);
            if (got) {
               low    =  true;
               shift  =  got[1] + "}}";
            } else {
               stuff  =  shift;
            }
         }
      }
   }
   if (low) {
      mode     =  WSTM.o.WikiTom.MagicWord;
      r.scope  =  "magicword";
      stuff    =  false;
   }
   if (stuff) {
      if (! stuff.length) {
         stuff  =  false;
      }
   }
   if (stuff) {
      i  =  stuff.indexOf("|");
      if (i > 0) {
         suffix  =  stuff.substr(i + 1);
         stuff   =  WSTM.str.trimR(stuff.substr(0, i),  false,  false);
         if (stuff.length < i) {
            space  =  WSTM.str.makeString(32,  i - stuff.length);
         }
         symbol  =  stuff;
      } else if (WSTM.str.substrEnd(shift, 2)  ===  "}}") {
//    } else if (shift.slice(-2) === "}}") {
         symbol  =  WSTM.str.trimR(stuff.slice(0, -2),  false,  false);
      } else {
         symbol  =  stuff;
      }
      if (WSTM.str.substrEnd(symbol, 1)  ===  "\n") {
//    if (symbol.slice(-21) === "\n") {
         slice   =  "\n";
         stuff   =  stuff.slice(0, -1);
         symbol  =  WSTM.str.trimR(stuff, false, false);
      }
      sub  =  WSTM.w.link.wiki.decode(symbol, true, true, true, true);
      if (sub) {
         symbol  =  sub;
      }
      if (WSTM.g.wNsNumber !== 10) {   //   g.nsTemplate
         scan  =  "|" + symbol.toUpperCase() + "|";
         if (suffix) {
            if (scan === "|ISSN|") {
               sub  =  WSTM.l10n.templates.issn.format(suffix);
               if (sub) {
                  suffix  =  sub;
                  learn   =  true;
               }
            }
         }
         if (! WSTM.g.wNsNumber) {
            if (this.sibling.indexOf(scan) >= 0) {
               got  =  this.sister(symbol, suffix);
               if (got) {
                  symbol  =  got[0];
                  suffix  =  got[1];
               }
               space  =  "";
               if (at) {
                  // spin off this, if repeated
                  got  =  at - 1;
                  sub  =  all.fetch(got, 0, false);
                  if (sub) {
                     sub  =  WSTM.str.trimR(sub, true);
                     i    =  sub.length;
                     if (i) {
                        if (sub.charCodeAt(i - 1)  ===  42) {   // '*'
                           i--;
                           if (i < 0) {
                              k  =  0;
                           } else if (sub.charCodeAt(i - 1)  ===  10) {
                              k  =  0;
                           }
                           if (! k) {
                              sub  =  sub.substr(0, i);
                              got  =  all.focus(got);
                              got.fresh(sub);
                           }
                        }
                     }
                  }
               }
               lone  =  true;
            }
         }
      }
      got  =  WSTM.hooks.fire("Template",  [symbol, at, advance, all]);
      if (got) {
         WSTM.mod.lazy  =  false;
          symbol        =  got[0];
         lone           =  (lone || got[1]);
         r.hook         =  got[2];
      }
      if (suffix) {
         if (suffix === "}}") {
            shift  =  symbol + "}}";
         } else {
            shift  =  symbol + slice + space + "|" + suffix;
         }
      } else {
         shift  =  symbol + "}}";
      }
   }
   if (lone) {
      if (at) {
         got   =  all.fetch(at - 1,  -1,  true);
         lead  =  (got !== 10);
      }
      got    =  all.fetch(advance + 1,  0,  true);
      later  =  (got !== 10);
      learn  =  (learn || lead || later);
   }
   learn  =  (learn || lead || leave);
   if (! immune) {
      got  =  all.focus(advance);
      if (got) {
         got.mode  =  mode;
         if (lock) {
            got.lookup  =  false;
         }
         if (scope) {
            got.scope  =  scope;
         }
         leap  =  (shift !== store);
         if (learn || scope || leap) {
            if (leap || leave) {
               if (leave) {
                  WSTM.mod.lazy  =  false;
               }
               if (at === advance) {
                  if (leave) {
                     if (later) {
                        i  =  all.focus(advance + 1);
                        if (i) {
                           shift  =  all.fetch(advance + 1,  0,  false);
                           i.fresh(shift.substr(1));
                        }
                     } else if (lead) {
                        i  =  all.focus(at);
                        if (i) {
                           shift  =  all.fetch(at, 0, false);
                           i.fresh(shift.slice(0, -1));
                        }
                     }
                     shift  =  "";
                  } else {
                     shift  =  "{{" + shift;
                     if (lead) {
                        shift  =  "\n" + shift;
                     }
                     if (later) {
                        shift  =  shift + "\n";
                     }
                  }
                  got.fresh(shift);
               } else {
                  // at ... advance
               }
               all.fresh(false);
            }
            if (symbol) {
               shift  =  false;
               r.mod  =  this.mod.find(symbol);
               if (WSTM.mod.luxury          ||
                   r.hook                   ||
                   r.mod                    ||
                   WSTM.w.encountered.isbn) {
                  indent  =  2;
                  immune  =  symbol.length;
                  lock    =  true;
                  if (WSTM.mod.hyper || WSTM.mod.template) {
                     got  =  WSTM.w.link.replace.flipper(symbol,
                                                         false,
                                                         false,
                                                         "Template");
                     if (got) {
                        symbol  =  got;
                        shift   =  symbol;
                     }
                  }
               }
               r.mode  =  WSTM.o.WikiTom.Template;
               mode    =  WSTM.o.WikiTom.LinkTemplate;
            }
         }
      }
   }
   if (immune) {
      if (! low) {
         got  =  all.fetch(advance);
         if (got) {
            if (WSTM.str.substrEnd(got, 2)  ===  "}}") {
//          if (got.slice(-2) === "}}") {
               i  =  got.length - 2;
               if (i) {
                  got  =  all.fold(advance, i, false);
                  if (got) {
                     r.joint++;
//mw.log(WSTM.debugging,".w.template.format()  r="+got,0,r);
                  }
               }
            }
         }
      }
//mw.log(WSTM.debugging,".w.template.format()  immune="+immune+"  at="+at+"  advance="+advance+"  indent="+indent+"    r.joint="+r.joint+"    "+low+"    "+symbol,0);
      if (immune) {
         got  =  false;
         if (at < r.joint) {
            sub  =  all.fetch(at);
            if (sub) {
               i  =  indent + immune;
               if (sub.length > i) {
                  got  =  all.fold(at, i, false);
                  if (got) {
                     r.joint++;
                  }
               }
            }
         }
         if (indent) {
            got  =  all.fold(at, indent, true);
            if (got) {
               r.joint++;
            }
         } else if (! got) {
            got  =  all.focus(at);
         }
      } else {
         got  =  all.focus(at);
      }
      if (got) {
         got.mode  =  mode;
         if (shift) {
            got.fresh(shift);
            all.fresh();
         }
         if (lock) {
            got.lookup  =  false;
         }
         if (scope) {
            got.scope  =  scope;
         }
      }
   }
   return  r;
};   // .w.template.format()



WSTM.w.template.sister  =  function (about, after) {
   // Format standard templates to sister projects
   // Precondition:
   //    about  -- detected keyword
   //    after  -- detected parameter sequence, or false
   // Postcondition:
   //    Returns string with formatted template content
   //    RegExp was used.
   // Uses:
   //    >  .g.wTitle
   //    >  .g.wNsNumber
   //    >  .g.projType
   //    >  .mod.hyper
   //     < .mod.lazy
   //    .str.trim()
   //    .hooks.fire()
   //    .w.template.split()
   //    .str.trimL()
   //    .w.link.wiki.decode()
   //    .w.link.replace.flipper()
   //    .w.link.namespace.furnish()
   //    .w.link.namespace.fetch()
   //    .l10n.lang.fix()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-05-11 [email protected]
   var stamp   =  about.substr(0, 1).toUpperCase()  +
                  about.substr(1).toLowerCase();
   var got;
   var large   =  (stamp.substr(0, 7)  ===  "Commons");
   var m;
   var ns;
   var pars;
   var re;
   var s;
   var second  =  false;
   var show    =  false;
   var slang   =  false;
   var space;
   var story   =  (after  ?  WSTM.str.trim(after, false)  :  false);
   var suffix  =  after;
   if (large) {
      if (stamp.length > 7) {
         got  =  WSTM.hooks.fire("commonscat", stamp);
         if (got) {
            if (got.toLowerCase !== stamp.toLowerCase) {
               stamp  =  got;
            }
         }
      }
   }
   if (story) {
      story  =  story.slice(0, -2);
      pars   =  this.split(story);
      m      =  pars.length;
      if (m) {
         second  =  WSTM.str.trim(pars[0]);
         if (second.length) {
            while (second.charCodeAt(0) === 58) {   // ':'
               second  =  second.substr(1);
            }
            if (! second.length) {
               second  =  false;
            }
         } else {
            second  =  false;
         }
         second  =  (second.length ? second : false);
         if (m > 1) {
            show  =  WSTM.str.trim(pars[1]);
            show  =  (show.length ? show : false);
            if (m > 2) {
               slang  =  WSTM.str.trim(pars[2]);
               slang  =  (slang.length ? slang : false);
            }
         }
      }
   }
   if (second) {
      s  =  WSTM.w.link.wiki.decode(second, true, false, true, true);
      if (s) {
         second  =  s;
      }
      if (WSTM.mod.hyper) {
         s  =  WSTM.w.link.replace.flipper(second, false, false, false);
         if (s) {
            if (typeof(s) === "string") {
               second  =  s;
            } else {
               second  =  s[1];
            }
         }   // changed
      }
      m      =  false;   // "File:", "Category:", "Page:"
      ns     =  second.indexOf(":");
      space  =  (large ?  "commons:" : false);
      if (ns > 0) {   // ':'
         s  =  second.substr(0, ns);
         m  =  WSTM.w.link.namespace.furnish(s);
         if (m === 2) {   // Category:
            second  =  WSTM.str.trimL(second.substr(ns + 1),  true);
            if (large) {
               if (stamp.length === 7) {
                  s  =  WSTM.hooks.fire("commonscat", false);
                  if (s) {
                     stamp  =  s;
                  }
               }
            } else {
               if (! slang) {
                  s  =  WSTM.w.link.namespace.fetch(2, space);
               }
               second  =  s + ":" + second;
            }
            m  =  false;
         }
      }   // ':'
      if (slang) {
         re   =  new RegExp(" *lang *= *([A-Za-z]{2,3})");
         got  =  re.exec(slang);
         if (got) {
            s  =  "lang=" + WSTM.l10n.lang.fix(got[1]);
            if (s !== slang) {
               slang  =  s;
            }
         }
      } else {
         if (! WSTM.g.wNsNumber) {
            if (! show  && (second === WSTM.g.wTitle  ||
                            second === "{{PAGENAME}}")) {
               second  =  false;
            }
         }
         if (m === 3) {   // Page:
            if (stamp !== "Wikisource") {
               m  =  false;
            }
         }
         if (m) {   // "File:", or perhaps "Page:"
            // already covered Commons|Category:
            second  =  second.substr(second.indexOf(":"));
            second  =  WSTM.str.trimL(second, true);
            if (stamp !== "Wiktionary") {
               s  =  second.substr(0, 1).toUpperCase();
               if (s  !==  second.substr(0, 1)) {
                  second  =  s + second.substr(1);
               }
            }   // wiktionary: keep case
            second  =  WSTM.w.link.namespace.fetch(m, slang) + ":"
                       + second;
         }
      }   // no 3rd parameter
      if (second) {
         s  =  second.substr(0, 1).toUpperCase();
         if (s  !==  second.substr(0, 1)) {
            if (second.indexOf("=") > 0  ||
                second.indexOf(":") > 0) {   // lang=
               s  =  false;
            } else if (second.length < 4) {   // ISO 639 ?
               if (stamp === WSTM.g.projType) {
                  if (second.toLowerCase() === second) {
                     s  =  false;
                  }
               }
            }
            if (s  &&  stamp !== "Wiktionary") {
               second  =  s + second.substr(1);
            }
         }
      }
      suffix  =  (second  ?  "|" + second  :  "")   +
                 (show    ?  "|" + show    :  "")   +
                 (slang   ?  "|" + slang   :  "")   +   "}}";
      if (suffix.charCodeAt(0) === 124) {   // '|'
         suffix  =  suffix.substr(1);
      }
   }
   if (stamp !== about  ||  suffix !== after) {
      got  =  [ stamp, suffix ];
   } else {
      got  =  false;
   }
   return  got;
};   // .w.template.sister()



WSTM.w.template.split  =  function (adjust) {
   // Split list of template parameters
   // Precondition:
   //    adjust  -- parameter sequence, pipe separated, no pipe in front
   //               leading and trailing whitespace kept
   //               may be terminated by "}}"
   //               evaluated as far as string goes
   // Postcondition:
   //    Returns array with parameters (strings)
   // Uses:
   //    .str.substrEnd()
   // 2012-04-10 [email protected]
   var r  =  false;
   var s;
   if (typeof(adjust) === "string") {
      if (WSTM.str.substrEnd(adjust) === "}}") {
//    if (adjust.slice(-2) === "}}") {
         s  =  adjust.slice(0, -2);
      } else {
         s  =  adjust;
      }
      r  =  s.split("|");
   }
   return  r;
};   // .w.template.split()



WSTM.w.template.file.factory  =  function () {
   // Create template configuration data
   // Uses:
   //    >  .str.spaces
   //    >  .g.s.re.Filetypes
   //    >< .w.template.file.re
   // 2012-06-16 [email protected]
   var s;
   if (! this.re) {
      this.re  =  new Array(2);
      s  =    "([ " + WSTM.str.spaces + "]*)"
            + "(&lrm;|&rlm;)?"
            + "([^|{}\n]+\\." + WSTM.g.s.re.Filetypes + ")"
            + "(&lrm;|&rlm;)?"
            + "([ " + WSTM.str.spaces + "]*)"
            + "(\n?)"
            + "([ " + WSTM.str.spaces + "]*)$";
      this.re[0]  =  new RegExp(s, "i");
      s  =  "\\| *\n? *[^|{}=\n ]+ *=" + s + "(\\}\\}|\\|)";
      this.re[1]  =  new RegExp(s, "i");
   }
};   // .w.template.file.factory()



WSTM.w.template.file.featured  =  function (adjust) {
   // Protect presumptive file names as template parameter value
   // Precondition:
   //    adjust  -- WikiTom of template to be modified or protected
   //               .values.template  Array
   // Uses:
   //    >  .w.template.file.re
   //    >  .mod.file
   //    >  .mod.hyper
   //    >  .mod.luxury
   //    >  .o.WikiTom.LinkFile
   //    .str.makeString()
   //    .w.link.wiki.file()
   //    .w.link.replace.flipper()
   //    .o.WikiTom().flip()
   //    .o.WikiTom().fresh()
   //    .o.WikiTom().folder()
   // 2012-06-16 [email protected]
   var d;
   var e;
   var got;
   var i;
   var j;
   var k;
   var leap;
   var m;
   var p;
   var re      =  this.re[0];
   var s;
   var story;
   var v       =  adjust.values;
   var n       =  v.length;
   for (i = 1;  i < n;  i++) {
      s  =  false;
      p  =  v[i].value;
      if (p) {
         d  =  false;
         e  =  p.children;
         if (e) {
            e  =  p.children;
            if (e.length === 2) {
               d  =  e[1];
               m  =  1;
            }
         } else {
            d  =  p;
            m  =  0;
         }
         if (d) {
            s  =  d.source;
         }
      }
      if (s) {
         got  =  re.exec(s);
         if (got) {
            if (/^(?:https?|ftp):\/\/[a-z0-9]+\.[a-z0-9]+/i.exec(s)) {
               got  =  false;
            }
         }
         if (got) {
            leap  =  false;
            s     =  got[1];
            j     =  0;
            if (typeof(s) === "string") {
               j  =  s.length;
               if (j > 0) {
                  s  =  WSTM.str.makeString(32, j);
                  if (got[1] !== s) {
                     got[1]  =  s;
                     leap    =  true;
                  }   // exotic
               }   // got[1]
            }   // string
            if (got[2]) {   // &lrm;
               leap  =  (leap  ||  got[2].length === 5);
            }
            story  =  WSTM.w.link.wiki.file(got[3]);
            if (got[3] !== story) {
               leap  =  true;
            }
            if (WSTM.mod.file || WSTM.mod.hyper) {
               s  =  WSTM.w.link.replace.flipper(story,
                                                 false,
                                                 false,
                                                 "File");
               if (s) {
                  if (typeof(s) === "string") {
                     story  =  s;
                  } else {
                     story  =  s[1];
                  }
                  leap  =  true;
               }   // changed
            }   // replace target
            if (got[4]) { // &lrm;
               if (got[4].length === 5) {
                  leap  =  true;
               }
            }   // &lrm;
            s  =  got[5];
            if (typeof(s) === "string") {
               s  =  s.length;
               if (s > 0) {
                  s  =  WSTM.str.makeString(32, s);
                  if (got[5] !== s) {
                     got[5]  =  s;
                     leap    =  true;
                  }   // exotic
               }   // got[5]
            } else {
               got[5]  =  "";
            }   // string
            if (got[7] === "\n") {
               got[6]  =  "";
            } else {
               got[7]  =  "";
            }   // string
            s  =  got[8];
            if (typeof(s) === "string") {
               k  =  s.length;
               if (k > 0) {
                  s  =  WSTM.str.makeString(32, k);
                  if (got[8] !== s) {
                     got[8]  =  s;
                     leap    =  true;
                  }   // exotic
               }   // got[8]
            } else {
               got[8]  =  "";
            }   // string
            if (leap) {
               d.fresh(got[1] + story + got[6] + got[7] + got[8]);
mw.log(WSTM.debugging,".w.template.file.featured() .fresh "+WSTM.text.learnt,0);
            }   // replace value
            if (WSTM.mod.luxury) {
               got  =  p.folder(j,
                                m,
                                j + story.length,
                                m);
               if (got) {
                  got.mode    =  WSTM.o.WikiTom.LinkFile;
                  got.lookup  =  false;
               }
            }   // protect link
         }
      }
   }   // for i
};   // .w.template.file.featured()



WSTM.w.template.file.full  =  function (adjust) {
   // Protect presumptive file names as template parameter in string
   // Precondition:
   //    adjust  -- WikiTom of template to be modified or protected
   // Uses:
   //    >  .w.template.file.re
   //    >  .mod.file
   //    >  .mod.hyper
   //    >  .mod.luxury
   //    .o.WikiTom().find()
   //    .str.makeString()
   //    .w.link.replace.flipper()
   //    .o.WikiTom().flip()
   //    .o.WikiTom().folder()
   // 2012-04-19 [email protected]
   var get     =  [ this.re[1], 0 ];
   var got;
   var i       =  0;
   var j;
   var k       =  0;
   var n;
   var leap;
   var s;
   var start;
   var suffix;
mw.log(WSTM.debugging,".w.template.file.full()",0,adjust);
   do {
      got  =  adjust.find(get, i, k, true, false, false);
      if (got) {
mw.log(WSTM.debugging,".w.template.file.full()  got",0,got);
         i       =  got.i;
         k       =  got.k;
         got     =  got.r;
         start   =  got[0];
         start   =  start.substring(0, start.indexOf("="));
         suffix  =  got[9];
         s       =  got[1];
         if (typeof(s) === "string") {
            j  =  s.length;
            if (j > 0) {
               s      =  WSTM.str.makeString(32, j);
               start  =  start + s;
               if (got[1] !== s) {
mw.log(WSTM.debugging,".w.template.file.full() [1] exotic");
                  leap   =  true;
               }   // exotic
            }   // got[1]
         }   // string
         if (got[2]) { // &lrm;
            leap  =  (got[2].length === 5);
         } else {
            leap  =  false;
         }
         if (WSTM.mod.file || WSTM.mod.hyper) {
            s  =  WSTM.w.link.replace.flipper(got[3],
                                              start,
                                              false,
                                              "File");
            if (! s) {
               s  =  WSTM.w.link.replace.flipper(got[3],
                                                 false,
                                                 false,
                                                 "File");
            }
            if (s) {
               if (typeof(s) === "string") {
                  got[3]  =  s;
               } else {
                  start   =  s[0];
                  got[3]  =  s[1];
               }
               leap  =  true;
            }   // changed
         }   // replace target
         if (got[4]) { // &lrm;
            if (got[4].length === 5) {
               leap  =  true;
            }
         }   // &lrm;
         s  =  got[5];
         if (typeof(s) === "string") {
            s  =  s.length;
            if (s > 0) {
               s  =  WSTM.str.makeString(32, s);
               if (got[5] !== s) {
mw.log(WSTM.debugging,".w.template.file.full() [5] exotic");
                  got[5]  =  s;
                  leap    =  true;
               }   // exotic
            }   // got[5]
         } else {
            got[5]  =  "";
         }   // string
         if (got[6] === "\n") {
            got[5]  =  "";
         } else {
            got[6]  =  "";
         }   // string
         s  =  got[8];
         if (typeof(s) === "string") {
            j  =  s.length;
            if (j > 0) {
               s  =  WSTM.str.makeString(32, j);
               if (got[8] !== s) {
mw.log(WSTM.debugging,".w.template.file.full() [8] exotic");
                  got[8]  =  s;
                  leap    =  true;
               }   // exotic
            }   // got[8]
         } else {
            got[8]  =  "";
         }   // string
         if (leap) {
            s  =  start + got[3] + got[5] + got[6] + got[8] + suffix;
            adjust.flip(k, i, got[0].length, s);
         }   // replace node
         if (WSTM.mod.luxury) {
            n    =  i + start.length;
            got  =  adjust.folder(n,  k,  n + got[3].length,  k);
         }   // protect link
         i++;
      }
   } while (got);   // do
};   // .w.template.file.full()



WSTM.w.template.mod.factory  =  function (apply) {
   // Create user defined modification data for templates
   // Precondition:
   //    apply  -- user defined array of modification objects
   // Postcondition:
   //    Returns array with tested modification objects, if any
   // Uses:
   //    .util.isArray()
   //    .str.trim()
   //    .util.regexp.fiat()
   //    .util.translate.fiat()
   // 2012-05-27 [email protected]
   var d;
   var e;
   var i;
   var j;
   var n;
   var p;
   var r  =  false;
   var s;
   var u;
   if (WSTM.util.isArray(apply)) {
      n  =  apply.length;
      for (i = 0;  i < n;  i++) {
         u  =  apply[i];
         if (typeof(u) === "object"  &&  u) {
            d  =  u.detect;
            if (typeof(d) === "object"  &&  d) {
               s  =  d.title;
               if (typeof(s) === "string") {
                  s  =  WSTM.str.trim(s, false);
                  if (s.length) {
                     p  =  { detect: { },
                             rename: false,
                             change: false,
                             format: false,
                             params: false
                           };
                     p.detect.title  =  WSTM.util.regexp.fiat(
                                            "^(?:" + s + ")$",
                                            "",
                                            "mod.template.detect.title");
                     if (r) {
                        r.push(p);
                     } else {
                        r  =  [ p ];
                     }
                     e  =  p.detect;
                     if (typeof(d.prolog) === "string") {
                        e.prolog  =  WSTM.util.regexp.fiat(
                                           d.prolog + "\f",
                                           "",
                                           "mod.template.detect.prolog");
                     }
                     if (typeof(d.epilog) === "string") {
                        e.epilog  =  WSTM.util.regexp.fiat(
                                           "\f" + d.epilog,
                                           "",
                                           "mod.template.detect.epilog");
                     }
                     if (WSTM.util.isArray(d.params)) {
                        e.params  =  [ ];
                        for (j = 0;  j < d.params.length;  j++) {
                           e.params.push(WSTM.util.regexp.fiat(
                                            d.params[j],
                                            "",
                                            "mod.template.detect.params["
                                            + j + "]"));
                        }   // for j
                     }
                     d  =  u.rename;
                     if (typeof(d) === "object"  &&  d) {
                        p.rename  =  { };
                        e         =  p.rename;
                        e.title   =  WSTM.util.regexp.fiat(
                                            d.title,
                                            "",
                                            "mod.template.rename.title");
                        if (WSTM.util.isArray(d.params)) {
                           e.params  =  [ ];
                           for (j = 0;  j < d.params.length;  j++) {
                              e.params.push(WSTM.util.translate.fiat(
                                            d.params[j],
                                            "",
                                            "mod.template.rename.params["
                                            + j + "]"));
                           }   // for j
                        }
                     }
                     d  =  u.change;
                     if (typeof(d) === "object"  &&  d) {
                        p.change  =  { };
                        e         =  p.change;
                        if (typeof(d.prolog) === "object") {
                           e.prolog  =  WSTM.util.translate.fiat(
                                           d.prolog,
                                           "",
                                           "mod.template.change.prolog");
                        }
                        if (typeof(d.epilog) === "object") {
                           e.epilog  =  WSTM.util.translate.fiat(
                                           d.epilog,
                                           "",
                                           "mod.template.change.epilog");
                        }
                     }
                     if (WSTM.util.isArray(u.clear)) {
                        d        =  u.clear;
                        p.clear  =  [ ];
                        for (j = 0;  j < d.length;  j++) {
                           p.clear.push([ WSTM.util.regexp.fiat(
                                                    d[j][0],
                                                    "",
                                                    "mod.template.clear["
                                                    + j + "]"),
                                          d[j][1] ]);
                        }   // for j
                     }
                     d  =  u.format;
                     if (typeof(d) === "object"  &&  d) {
                        p.format  =  { };
                        if (WSTM.util.isArray(d.order)) {
                           p.format.order  =  d.order;
                        }
                        if (typeof(d.style) === "object"  &&  d.style) {
                           // .fashion
                        }
                     }
                  }
            /*
mod.template   detect   prolog
                        title
                        params   [ [name, value|false],    ]
                        epilog
               rename   title    new      [regexp, replace, flag=i]
                        params   [ [name, new, value|false],   ]
               change   prolog   [regexp, replace]
                        epilog   [regexp, replace]
               clear    [ [regexp,mode],  [regexp,mode],  ]
               format   order    [ name, name,  ]    [ [*,n], [*,n],  ]
                        style    style-object general
                                 { indent:    0,
                                   later:     false,
                                   lastline:  false,
                                   leap:      false,
                                   leave      space before '='
                                   linebreak: true,
                                   lineup:    false
                                 }
               params   Array
                           format   {{{*}}}
                           style    style-object particular
                           values   [ [name, regexp, replace|false],   ]
               hook     function(WikiTom.values)
            */
               }
            }
         }
      }   // for i
   }
   return  r;
};   // .w.template.mod.factory()



WSTM.w.template.mod.find  =  function (about) {
   // Check whether template name occurs in user defined modifications
   // Precondition:
   //    about  -- detected template name
   // Postcondition:
   //    Returns true iff about is subject to modification
   // Uses:
   //    >  .mod.template.*
   // 2012-05-25 [email protected]
   var i;
   var n;
   var p  =  WSTM.mod.template;
   var r  =  false;
   if (p) {
      n  =  p.length;
      for (i = 0;  i < n;  i++) {
         if (p[i].detect.title.test(about)) {
            r  =  true;
            break;   // for i
         }
      }   // for i
   }
   return  r;
};   // .w.template.mod.find()



WSTM.w.template.mod.fire  =  function (adjust) {
   // Perform user defined template modifications
   // Precondition:
   //    adjust   -- WikiTom of entire template
   // Postcondition:
   //    WikiTom elements modified, if appropriate
   // Uses:
   //    >  .mod.template.*
   //    .util.isArray()
   //    .w.template.par.fix()
   //    .w.template.mod.flush()
   //    .w.template.par.fixed()
   //    .w.template.par.format()
   // 2012-06-18 [email protected]
   var e;
   var i;
   var n;
   var p  =  false;
   var s;
   var t;
   var v  =  adjust.values;
   if (v) {
      if (WSTM.util.isArray(v)) {
         if (typeof(v[0].symbol) === "string") {
            s  =  v[0].symbol;
            p  =  WSTM.mod.template;
         }
      }
   }
   if (p) {
      n  =  p.length;
      for (i = 0;  i < n;  i++) {
         t  =  p[i];
         if (t.detect.title.test(s)) {
            if (t.rename) {
               if (t.rename.title) {
                  e  =  t.rename.title[1];
                  if (typeof(e) === "string") {
                     v.source.replace(t.rename.title[0], e);
                  } else if (e === "function") {
                     v.source.replace(t.rename.title[0],
                                      e("template", i, "title", s,
                                        adjust.values));
                  }
               }
               if (t.rename.params) {
                  WSTM.w.template.par.fix(t.rename.params, adjust);
               }
            }
            if (t.change) {
//             WSTM.w.template.mod.(t.change, adjust);
            }
            if (t.clear) {
               WSTM.w.template.mod.flush(adjust, t.clear);
            }
            if (t.format) {
               if (t.format.order) {
                  WSTM.w.template.par.fixed(t.format.order, adjust);
               }
               if (t.format.style) {
               }
            }
            if (adjust.learnt) {
               WSTM.w.template.mod.format(adjust);
            }
         }
      }   // for i
   }
};   // .w.template.mod.fire()



WSTM.w.template.mod.flush  =  function (adjust, apply) {
   // Remove template parameters
   // Precondition:
   //    adjust  -- adjust
   //                  .values Array:
   //                          [0] .symbol  template name
   //                          [1] first parameter assignment
   //                              .symbol  name
   //                              .value   WikiTom content
   //                          etc.
   //    apply   -- array of arrays with parameter names to be deleted
   //               every element is an array of [name, mode]
   //               mode  -- false: keep if not empty;   true: always
   // Postcondition:
   //    < adjust.learnt  -- true if modified
   // Uses:
   //    .str.trim()
   // 2012-05-31 [email protected]
   var v  =  adjust.values;
   var i;
   var k;
   var m  =  v.length;
   var n  =  apply.length;
   var p;
   var q;
   var r;
   var s;
   var x;
   for (i = 0;  i < n;  i++) {
      p  =  apply[i];
      r  =  p[0];
      for (k = 1;  k < m;  k++) {
         q  =  v[k];
         if (r.test(q.symbol)) {
            x  =  false;
            if (p[1]) {
               x  =  true;
            } else {
               q  =  q.value;
               if (q) {
                  s  =  typeof(q);
                  if (s === "string") {
                     s  =  q;
                  } else if (s === "object") {
                     if (q.children) {
                        s  =  false;
                     } else {
                        q  =  q.source;
                        if (typeof(q) === "string") {
                           s  =  q;
                        } else {
                           s  =  false;
                        }
                     }
                  } else {
                     s  =  false;
                  }
                  if (typeof(s) === "string") {
                     if (!  WSTM.str.trim(s, true, true)) {
                        x  =  true;
                     }
                  }
               }
            }
            if (x) {
               adjust.values.splice(k, 1);
               adjust.learnt  =  true;
               m--;
               k--;
            }
         }
      }   // for k
   }   // for i
};   // .w.template.mod.flush()



WSTM.w.template.mod.format  =  function (adjust) {
   // Rewrite template WikiTom children
   //    adjust  -- WikiTom of entire template
   //               >  .values
   //               >< .children
   //                < .learnt
   //                < .source
   // Postcondition:
   //    adjust was re-built
   // Uses:
   //    .str.makeString()
   //    .o.WikiTom()
   //    .o.WikiTom().fresh()
   // 2012-05-30 [email protected]
   var v  =  adjust.values;
   var i;
   var n  =  v.length;
   var p;
   var s;
   adjust.learnt              =  true;
   adjust.source              =  false;
   adjust.children[1].parent  =  null;
   adjust.children            =  [ new WSTM.o.WikiTom("{{", null),
                                   adjust.children[1] ];
   if (n && adjust.linebreak) {
      if (v.indent) {
         s  =  "\n"  +  WSTM.str.makeString(32, v.indent);
      } else {
         s  =  "\n";
      }
      adjust.children.push(new WSTM.o.WikiTom(s, null));
   }
   for (i = 1;  i < n;  i++) {
      p  =  v[i];
      adjust.children.push(WSTM.w.template.par.format(p, null));
      if (p.value) {
         p.value.parent  =  null;
         adjust.children.push(p.value);
      } else {
         adjust.children.push(new WSTM.o.WikiTom("", null));
      }
   }   // for i
   adjust.children.push(new WSTM.o.WikiTom("}}", null));
   n  =  adjust.children.length;
   for (i = 0;  i < n;  i++) {
      adjust.children[i].parent  =  adjust;
   }   // for i
   adjust.fresh(false);
};   // .w.template.mod.format()



WSTM.w.template.mod.former  =  function (adjust, ahead, after) {
   // Modify template inclusion according to WSTM.4 .mod.hyper
   // Precondition:
   //    adjust  -- WikiTom of template to be modified
   //    ahead   -- context before "{{"  -- WikiTom, may be false
   //    after   -- context after "}}"   -- WikiTom, may be false
   // Postcondition:
   //    adjust  has been modified, if necessary
   // Uses:
   //    >  .o.WikiTom().children
   //    .w.link.replace.flipper()
   //    .o.WikiTom().fresh()
   // TODO: TEST ////////////////////////////////////////////////////////
   // 2012-04-17 [email protected]
   var block   =  adjust.children;
   var i;
   var serve   =  block[1].toString();
   var start   =  (ahead  ?  ahead + "{{"  :  "{{");
   var suffix  =  (block[2]  ?  block[2].toString()  :  false);
   var swap    =  WSTM.w.link.replace.flipper(serve,
                                              start,
                                              suffix,
                                              "Template");
   if (swap) {
//mw.log(WSTM.debugging,".w.template.mod.former()  modified",0,swap);
      if (typeof(swap) === "string") {
         block[1].fresh(swap);
      } else {
         for (i = 0;  i < 3;  i++) {
            if (swap[i]) {
               block[i].fresh(swap[i]);
            }
         }   // for i
      }
      adjust.fresh(false);
   }   // changed
};   // .w.template.mod.former()



WSTM.w.template.mod.furnish  =  function (adjust, apply) {
   // Build formatted template content and layout
   // Precondition:
   //    adjust  -- WikiTom
   //                 .values Array:
   //                    [0] template name
   //                    [1] first parameter
   //                        >  .value  -- WikiTom with value string
   //                           >  .children
   //                           >  .source
   //                    etc.
   //    apply   -- layout information
   //               .indent     -- number of spaces before pipe
   //               .later      -- space after '='
   //               .lastline   -- ignore linebreak on lastline
   //               .leap       -- space after pipe
   //               .leave      -- space before '='
   //               .linebreak  -- one line per parameter
   //               .lineup     -- all '=' at same position
   // Postcondition:
   //    < adjust.learnt     -- true if modified
   //    < adjust.indent     -- true if indented
   //    < adjust.linebreak  -- true if linebreak after template name
   // Uses:
   //    >  this.source
   //    >  this.children
   //    .str.trimR()
   //    .str.makeString()
   //    this.fresh()
   // 2012-05-30 [email protected]
   var v  =  adjust.values;
   var b  =  "";
   var e;
   var i;
   var j;
   var m  =  0;
   var n  =  v.length;
   var p;
   var q;
   var s;
//mw.log(WSTM.debugging,".w.template.mod.furnish()  adjust",0,adjust);
   if (n && apply.indent) {
      b              =  WSTM.str.makeString(32, apply.indent);
      adjust.indent  =  true;
   }
   if (apply.lineup) {
      for (i = 1;  i < n;  i++) {
         q  =  v[i].symbol;
         if (s) {
            j  =  s.length;
            if (j > m) {
               m  =  j;
            }
         }
      }   // for i
      adjust.lineup  =  m;
   }
   if (apply.leave) {
      m++;
   }
   if (apply.linebreak) {
      s  =  v[0].symbol;
      if (s) {
         s  =  WSTM.str.trimR(s, true, true);
      }
      adjust.learnt     =  true;
      adjust.linebreak  =  true;
   }
   for (i = 1;  i < n;  i++) {
      q  =  v[i];
      e  =  q.value;
//mw.log(WSTM.debugging,".w.template.mod.furnish()  q.value",0,e);
      q  =  q.symbol;
      s  =  false;
      if (e.children) {
         p  =  e.children[e.children.length - 1];
         if (p.source) {
            s  =  p.source;
         }
      } else if (e.source) {
        s  =  e.source;
      }
      if (typeof(s) !== "string") {
         s  =  "";
      }
      j  =  s;
      s  =  WSTM.str.trimR(s, true, true);
      if (apply.linebreak) {
         if (! apply.lastline   ||   i  !==  n - 1) {
            s  =  s + "\n" + b;
         }
      }
      if (s !== j) {
//mw.log(WSTM.debugging,".w.template.mod.furnish()  e="+s,0,e);
         if (e.children) {
            p.fresh(s);
         } else {
            e.fresh(s);
         }
         adjust.learnt  =  true;
      }
   }   // for i
};   // .w.template.mod.furnish()



WSTM.w.template.mod.trim  =  function (adjust) {
   // Trim all template values
   // Precondition:
   //    adjust  -- WikiTom
   //                 .values Array:
   //                      [0] template name
   //                      [1] first parameter
   //                          >  .value  -- WikiTom with value string
   //                             >  .children
   //                             >  .source
   //                      etc.
   // Postcondition:
   //    < adjust.learnt  -- true if modified
   // Uses:
   //    .o.WikiTom().trimL()
   //    .o.WikiTom().trimR()
   //    .o.WikiTom()
   // 2012-05-30 [email protected]
   var i;
   var q;
   var v  =  adjust.values;
   var n  =  v.length;
   for (i = 1;  i < n;  i++) {
      q  =  v[i].value;
      if (typeof(q) === "object") {
         if (q.trimL(true)) {
            adjust.learnt  =  true;
         }
         if (q.trimR(true, true, true)) {
            adjust.learnt  =  true;
         }
      } else {
         adjust.values[i].value  =  new WSTM.o.WikiTom("", null);
         adjust.learnt           =  true;
      }
   }   // for i
};   // .w.template.mod.trim()



WSTM.w.template.par.fiat  =  function (adjust, access, assign) {
   // Set parameter value; create new assignment if not yet present
   // Precondition:
   //    adjust  -- WikiTom().values
   //               [0] template name
   //               [1] first parameter assignment
   //                   .symbol
   //    access  -- parameter name
   //    assign  -- parameter value; string or WikiTom
   // Postcondition:
   //    Return updated object, or false if failed
   // Uses:
   //    .o.WikiTom()
   // 2012-05-31 [email protected]
   var i;
   var n;
   var r  =  false;
   var v  =  adjust.values;
   if (v) {
      n  =  v.length;
      for (i = 1;  i < n;  i++) {
         if (v[i].symbol === access) {
            r  =  v[i];
            break;   // for i
         }
      }   // for i
      if (! r) {
         r  =  new WSTM.o.WikiTom("|" + access + "=",  adjust);
         r.symbol  =  access;
//       r.scope   =  "value";
         adjust.values.push(r);
      }
      v  =  typeof(assign);
      if (v === "string") {
         v  =  new WSTM.o.WikiTom(assign, adjust);
      } else if (v === "object") {
         v         =  assign;
         v.parent  =  adjust;
      }
      r.value        =  v;
      adjust.learnt  =  true;
   }
   return  r;
};   // .w.template.mod.fiat()



WSTM.w.template.par.find  =  function (adjust, access) {
   // Ensure parameter sequence
   // Precondition:
   //    adjust  -- WikiTom().values
   //               [0] template name
   //               [1] first parameter assignment
   //                   .symbol
   //    access  -- parameter name
   // Postcondition:
   //    Return value object, or false
   // 2012-05-31 [email protected]
   var i;
   var n;
   var r  =  false;
   var v  =  adjust.values;
   if (v) {
      n  =  v.length;
      for (i = 1;  i < n;  i++) {
         if (v[i].symbol === access) {
            r  =  v[i];
            break;   // for i
         }
      }   // for i
   }
   return  r;
};   // .w.template.par.find()



WSTM.w.template.par.fetch  =  function (assigned) {
   // Retrieve plain string from assignment
   // Precondition:
   //    assigned  -- assignment with .value
   // Postcondition:
   //    Return string, or false if failed
   // 2012-05-31 [email protected]
   var r  =  false;
   var t;
   var v  =  assigned.value;
   if (v) {
      t  =  typeof(v);
      if (t === "string") {
         r  =  v;
      } else if (t === "object") {
         r  =  v.source;
      }
   }
   return  r;
};   // .w.template.par.fetch()



WSTM.w.template.par.fix  =  function (apply, adjust) {
   // Adapt parameter names
   // Precondition:
   //    apply   -- array with arrays [RE, rp]
   //    adjust  -- WikiTom()
   //               .values
   //                  [0] template name
   //                  [1] first parameter name, or false
   //                      .symbol
   // Postcondition:
   //    modified adjust iff any reason,  or false
   //     < .learnt      true
   //    >< [i].symbol   adjusted
   // 2012-05-30 [email protected]
   var e;
   var i;
   var j;
   var k;
   var m;
   var n;
   var r  =  false;
   var s;
   var v  =  adjust.values;
   if (apply && v) {
      m  =  apply.length;
      n  =  v.length;
      for (j = 0;  j < m;  j++) {
         e  =  apply[j];
         for (i = 1;  i < n;  i++) {
            s  =  v[i].symbol;
            if (e[0].test(s)) {
               if (s !== e[1]) {
                  s  =  e[1];
                  for (k = 1;  k < n;  k++) {
                     if (v[k].symbol === s) {
                        s  =  false;
                        break;   // for k
                     }
                  }   // for k
                  if (s) {
                     v[i].symbol  =  s;
                     r            =  true;
                  }
               }
            }
         }   // for i
      }   // for j
   }
   if (r) {
      adjust.learnt  =  true;
      r              =  adjust;
   }
   return  r;
};   // .w.template.par.fix()



WSTM.w.template.par.fixed  =  function (apply, adjust) {
   // Ensure parameter sequence
   // Precondition:
   //    apply   -- array with name strings or arrays [*, name, require]
   //               [0] template name
   //               [1] first parameter
   //               element is either  string with name
   //                          or      Array  [*, name, (require)]
   //                                         require: create empty value
   //    adjust  -- WikiTom().values
   //               [0] template name
   //               [1] first parameter name, or false
   //                   .symbol
   // Postcondition:
   //    Return true iff any modification
   //     < .learnt      true
   //    >< [i].symbol   adjusted
   // Uses:
   //    .util.isArray()
   // 2012-05-31 [email protected]
   var i;
   var j;
   var k;
   var l;
   var m;
   var n;
   var p;
   var r  =  false;
   var s;
   var v  =  adjust.values;
   if (apply && v) {
      m  =  1;
      k  =  apply.length;
      n  =  v.length;
      k  =  (n < k  ?  n  :  k);
      for (i = 1;  i < k;  i++) {
         l  =  false;
         s  =  apply[m];
         if (typeof(s) !== "string") {
            if (WSTM.util.isArray(s)) {
               if (s[2]) {
                  l  =  true;
               }
               s  =  s[1];
            }
         }
         m++;
         if (typeof(s) === "string") {
            if (s !== v[i].symbol) {
               p  =  true;
               for (j = i + 1;  j < n;  j++) {
                  p  =  v[j];
                  if (p.symbol === s) {
                     adjust.values.splice(j, 1);
                     adjust.values.splice(i,  0,  p);
                     r  =  true;
                     p  =  false;
                     break;   // for j
                  }
               }   // for j
               if (p && l) {
                  p         =  new WSTM.o.WikiTom("", adjust);
                  p.symbol  =  s;
                  adjust.values.splice(i,
                                       0,
                                       { symbol: s,
                                         value:  p
                                       });
                  if (k < n) {
                     n++;
                  }
                  r  =  true;
               }
            }
         }
      }   // for i
   }
   if (r) {
      adjust.learnt  =  true;
      r              =  adjust;
   }
   return  r;
};   // .w.template.par.fixed()



WSTM.w.template.par.format  =  function (apply, assign) {
   // Format parameter assignment
   // Precondition:
   //    apply   -- WikiTom().values[i]
   //               >  .leap
   //               >  .symbol
   //               >  .lineup
   //               >  .leave
   //               >  .later
   //                < .lookup
   //                < .parent
   //    assign  -- parent
   // Postcondition:
   //    Return new WikiTom()
   // Uses:
   //    >  .o.WikiTom.TmplParam
   //    .str.makeString()
   //    .o.WikiTom()
   // 2012-05-28 [email protected]
   var s  =  "|";
   var r;
   if (apply.leap) {
      s  =  s  +  " ";
   }
   if (apply.symbol) {
      s  =  s  +  apply.symbol;
      if (apply.lineup) {
         r  =  apply.symbol.length - apply.lineup;
         if (r) {
            s  =  s  +  WSTM.str.makeString(32, r);
         }
      }
      if (apply.leave) {
         s  =  s  +  " ";
      }
      s  =  s  +  "=";
      if (apply.later) {
         s  =  s  +  " ";
      }
   }
   r         =  new WSTM.o.WikiTom(s, assign);
   r.lookup  =  false;
   r.mode    =  WSTM.o.WikiTom.TmplParam;
   return  r;
};   // .w.template.par.format()



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



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



mw.libs.WikiSyntaxTextMod.bb.apiW  =  function (WSTM) {
   // Detected syntax error handling
   // 2012-04-30 [email protected]
   if (typeof(WSTM.api) !== "object") {
      WSTM.api  =  { };
   }



// .api.textMod()



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



// Start on import: callback to waiting ...
if (typeof(mw.libs.WikiSyntaxTextMod.main) !== "object") {
   mw.libs.WikiSyntaxTextMod.main  =  { };
}
if (typeof(mw.libs.WikiSyntaxTextMod.main.wait) === "function") {
   mw.libs.WikiSyntaxTextMod.main.wait("N",
                                       mw.libs.WikiSyntaxTextMod.w.vsn);
}
delete mw.libs.WikiSyntaxTextMod.w.vsn;



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

/// EOF </nowiki>   WikiSyntaxTextMod/?W.js