Revision 139855 of "User:PerfektesChaos/js/WikiSyntaxTextMod/dO.js" on testwiki

/// PerfektesChaos/js/WikisyntaxTextMod/?O.js
// WikisyntaxTextMod:  Objects for wiki syntax specific code
/// 2012-07-22 [email protected]
/// Fingerprint: #0#0#
/// <nowiki>
/* 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  =  { libs:   { WikiSyntaxTextMod:  { }
                    },
            log:    function () {}
          };
}
if (typeof(mw.libs.WikiSyntaxTextMod) !== "object") {   // isolated
   mw.libs.WikiSyntaxTextMod  =  { };
}
if (typeof(mw.libs.WikiSyntaxTextMod.o) !== "object") {
   mw.libs.WikiSyntaxTextMod.o  =  { };
}
mw.libs.WikiSyntaxTextMod.o.vsn  =  -5.06;
if (typeof(mw.libs.WikiSyntaxTextMod.bb) !== "object") {
   mw.libs.WikiSyntaxTextMod.bb  =  { };
}
if (typeof(mw.libs.WikiSyntaxTextMod.debugging) !== "object") {
   mw.libs.WikiSyntaxTextMod.debugging  =  { debugging: false };
}




// Provides:
//    .o.Wikilink
//    .o.WikiTom
/*
Requires: JavaScript 1.3
          (String.charCodeAt String.fromCharCode String.replace)
 */



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



mw.libs.WikiSyntaxTextMod.bb.Wikilink  =  function (WSTM) {
   // Administration of wikilinks
   // 2012-05-17 [email protected]
   // Class:
   //    Public:
   //       getChange()
   //       getError()
   //       getIncrement()
   //       getRemoveFrom()
   //       getRemoveTo()
   //       getSortkey()
   //       getTargetLength()
   //       getTextReplace()
   //       getType()
   //       getUserModified()
   //       set()
   //       setTarget()
   //    Private:
   //       adjust()
   //       analyze()
   //       capitalize()
   //       category()
   //       closingBracket()
   //       extend()
   //       file()
   //       language()
   //       lineFeedAhead()
   //       magic()
   //       magic_ISBN()
   //       namespace()
   //       newline()
   //       old2New()
   //       pipeSymbols()
   //       project()
   //       specials()  //  -> special()
   //       target()
   //       title()
   //       unlink()
   //       url()
   //       init()
   // .lapsus   true: syntax error detected
   // .lead     true: target starts with ":"
   // .leader   true: first item in category or interlanguage sequence
   // .leap     true: leading whitespace
   // .learn    true: link modified by user replacement
   // .lfAhead  true: line feed present before link
   // .limited  true: enclosed in brackets (single bracket termination)
   // .lock     true: freeze wikilink targets
   // .loose    true: (single  "[" heading //unused)
   // .index    number: position of "[[" in .source
   // .inPipe   number: of chars in analyze until pipe symbol, or false
   // .inTerm   number: of chars in analyze until terminating bracket
   // .join     number: relative position of "[["
   // .justify  number: default lang for project link
   // .keySort  number: of chars to be unconditionally locked as sort key
   // .mode     number: interwiki, category, media (file) etc.
   // .move     number: incrementation on global search
   // .newFrom  number: of chars in .source for replacement region start
   // .newTo    number: of chars in .source for replacement region end
   // .next     number: of chars in .suffix to be added, or all
   // .nucleus  number: of target chars to be locked
   // .off      WikiTom with <includeonly> spans, or false
   // .old2new  user defined link replacements, or false
   // .onto     current WikiTom node
   // .score    wikilink target
   // .sister   'project:', if any
   // .shift    replacement string (total)
   // .show     non-empty title string
   // .slang    'language:', if any
   // .source   wikitext including "[[" at .index
   // .special  category or interwiki content    // -> schedule
   // .start    replacement string (preceeding)
   // .subcase  downcased wgTitle
   // .suffix   aftermath
   var WikiLK;



   WSTM.o.Wikilink  =  function () {
      // .constructor for new
      // Postcondition:
      //    Returns .o.Wikilink object
      // Uses:
      //    >  .g.wTitle
      //     < .o.Wikilink.subcase
      //    .o.Wikilink.init()
      //    .str.deCapitalize()
      // 2012-05-17 [email protected]
      var p;
      this.init();
      this.index    =  false;
      this.lock     =  false;
      this.move     =  false;
      this.newFrom  =  false;
      this.off      =  false;
      this.old2new  =  false;
      this.onto     =  false;
      this.source   =  false;
   // this.lfAhead  =  false;
      this.subcase  =  WSTM.str.deCapitalize(WSTM.g.wTitle);
      for (p in WSTM.o.Wikilink) {
         if (WSTM.o.Wikilink.hasOwnProperty(p)) {
            this[ p ]  =  WSTM.o.Wikilink[ p ];
         }
      }   // for p in
      return this;
   };   // .o.Wikilink() .constructor
   WikiLK  =  WSTM.o.Wikilink;



   // Definition of constants
   // 2012-05-24 [email protected]
   WikiLK.ModeWeb   =  1;
   WikiLK.ModeWiki  =  2;
   WikiLK.ModeFile  =  3;
   WikiLK.ModeCat   =  4;
   WikiLK.ModeIw    =  5;
   //                  6   special interwikilink ([[bugzilla:...]] etc.)
   //                  7   page
   //                  9   special weblink ([[DOI:...]] etc.)



   WikiLK.prototype.init  =  function () {
      // Initialize existing wikilink object
      // Postcondition:
      //    .o.wikilink object has been reset
      // Uses:
      //    >  .o.Wikilink::
      //       >  .***
      // 2012-04-26 [email protected]
      this.lapsus   =  false;
      this.lead     =  false;
      this.leader   =  false;
      this.leap     =  false;
      this.learn    =  false;
      this.limited  =  false;
      this.lock     =  false;
      this.inPipe   =  false;
      this.inTerm   =  false;
      this.join     =  false;
      this.justify  =  false;
      this.keySort  =  false;
      this.mode     =  false;
      this.move     =  false;
      this.newFrom  =  false;
      this.newTo    =  false;
      this.next     =  false;
      this.nucleus  =  false;
      this.off      =  false;
      this.onto     =  false;
      this.score    =  false;
      this.shift    =  false;
      this.show     =  false;
      this.sister   =  false;
      this.slang    =  false;
      this.special  =  false;
      this.start    =  false;
      this.suffix   =  false;
   };   // .o.Wikilink.init()



WikiLK.prototype.adjust  =  function (analyze) {
   // Analyze entire link syntax, divide into major parts
   // Precondition:
   //    analyze  -- string with link content beginning with '[['
   // Uses:
   //    >  .g.re.File
   //    >  .o.Wikilink::
   //       >  .ModeFile
   //       >  .show
   //        < .mode
   //        < .limited
   //        < .join
   //        < .inTerm
   //        < .inPipe
   //        < .lapsus
   //        < .move
   //        < .leap
   //        < .suffix
   //        < .score
   //       .extend()
   //       .newline()
   //       .url()
   //       .closingBracket()
   //       .pipeSymbols()
   //       .analyze()
   //     < .mod.lazy
   //    .w.link.wiki.iwMap()
   //    .str.isBlank()
   //    .errors.found()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-07-22 [email protected]
   var s       =  analyze.substr(2);
   var c;
   var inside  =  2;
   var join    =  s.indexOf("\n\n");
   var newl;
   var mid;
   var start;
   var swap;
   if (join > 0) {
      s  =  s.substr(0, join);
   }   // paragraph found
   join  =  s.indexOf(":");
   if (join > 1) {
      if (s.search(WSTM.g.re.File) === 0) {
         this.mode  =  this.ModeFile;   // (not Media:)
         join  =  s.indexOf("\n");
         if (join > 0) {
            s  =  s.substr(0, join);
         }   // EOL -- image description might contain strange things
      } else {
         start  =  s.substr(0, join);
         swap   =  WSTM.w.link.wiki.iwMap(start, join);
         if (swap) {
            this.mode  =  9;
            if (swap !== start) {
               s  =  swap  +  s.substr(join);
               this.extend(1);
            }   // adjust
         }   // interwiki mapping
      }
   }   // may be prefixed
   join          =  s.indexOf("]") + 2;
   this.limited  =  (join > 1);
   if (this.limited) {   // first terminating bracket found
      inside  =  s.indexOf("[") + 2;
      if (inside > 1) {
         if (inside < join) {
            if (inside === 2) {   // triple bracket, or even more
               c  =  s.charCodeAt(0);
               this.join  =  0;
               this.extend(32);
               while (WSTM.str.isBlank(c, false)  ||  c === 91) {   // [
                  s  =  s.substr(1);
                  c  =  s.charCodeAt(0);
                  this.join++;
                  this.newTo++;
                  join--;
               }   // while
               WSTM.mod.lazy  =  false;
               WSTM.errors.found("tooManyLeftBrackets",
                                 true,
                                 analyze.substr(0, 100));
            } else {   // got opening bracket inside, could be Media:
               join          =  inside;
               s             =  s.substr(0,  join - 2);
               this.limited  =  false;
            }
         }
      } else {
         inside  =  2;
      }
      this.inTerm  =  join;
   }
   newl  =  s.indexOf("\n") + 2;
   mid   =  s.indexOf("|") + 2;
   if (! this.limited) {
      if (this.mode === this.ModeFile) {
         join  =  s.length;   // "]]"
      } else {
         this.extend(-1);
         if (newl > 1) {
            s  =  s.substr(0,  newl - 1);
         }
         if (mid > 1) {
            s  =  s.substr(0, mid);
         }
         if (s.length  &&  mid < 1) {   // not folded
            WSTM.errors.found("wikilinkBracketsAhead",
                              false,
                              mid +
                              "[[" + s.substr(0, 100));
         }
         s  =  false;
      }
   }
   if (s) {
      if (mid > 1) {
         if (mid < join) {
            this.inPipe  =  mid;
         }
      }
      if (newl > 1) {
         if (this.limited) {
            if (newl < this.inTerm) {
               s     =  this.newline(s, newl);
               newl  =  false;
            }   // newline within bracket pair
         }
         if (newl) {
            s  =  s.substr(0,  newl - 2);
            if (mid > newl) {
               this.inPipe  =  false;
            }
         }
      }
   } else {
      this.move  =  inside;
   }
   if (s) {
      while (WSTM.str.isBlank(s.charCodeAt(0), false)) {
         s  =  s.substr(1);
         join--;
         if (this.inPipe) {
            mid--;
         }
         this.extend(1);
         this.leap  =  true;
      }   // while ltrim
      if (join === 2) {   // "[[\n"
         WSTM.errors.found("linkTargetMissing",
                           true,
                           analyze.substr(0, 100));
         this.extend(-1);
         s  =  false;
      } else if (s.charCodeAt(0) === 93) {   // ']'   // [[]
         this.extend(-1);
         s  =  false;
      } else if (this.limited) {   // at least single brackets
         if (s.length >= join) {
            this.suffix  =  s.substr(join - 1);
            s            =  s.substr(0,  join - 2);
         }
         if (this.url(s)) {
            s  =  false;
         }
      }   // not empty
   }
   if (s) {   // neither URL nor empty
      this.closingBracket(s);
      if (this.score) {
         if (this.inPipe) {
            this.pipeSymbols(mid - 2);
         }
         if (this.score || this.show) {
            this.analyze();
         } else if (this.score) {
            this.extend(-1);
         }
      }   // local
   }
};   // .o.Wikilink.adjust()



WikiLK.prototype.analyze  =  function () {
   // Analyze bracket content fractions and aftermath
   // Precondition:
   //    Fractions .score, .show, .suffix are defined.
   // Uses:
   //    >  .o.Wikilink::
   //       >  .mode
   //       >  .lead
   //       >  .inPipe
   //       >  .newFrom
   //       >  .newTo
   //       >  .start
   //       >  .index
   //       >  .ModeWiki
   //       >  .next
   //       >< .score
   //       >< .show
   //       >< .suffix
   //       >< .nucleus
   //       >< .leap
   //        < .lock
   //        < .shift
   //        < .move
   //       .target()
   //       .title()
   //       .unlink()
   //       .magic()
   //       .extend()
   //       .lineFeedAhead()
   //    .w.link.wiki.context()
   //    .str.substrEnd()
   //    .w.link.wiki.fore()
   //    .str.isLetter()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-07-22 [email protected]
   var c;
   var linking;
   var n;
   var s;
   if (this.score) {
      if (this.mode !== 9) {   // not Interwiki mapping
         this.target();
      }
      if (! this.mode) {   // not Category:
         if (! this.lead) {
            this.unlink();
         }
         if (this.inPipe  &&  ! this.show) {
            this.show  =  WSTM.w.link.wiki.context(this.score);
            this.extend(2);
         }   // context style   [[title (Abc)|]]
      }
   }
   if (! this.mode) {   // magic?
      this.magic();
      if (this.show) {
         this.title();
      }
   }
   if (this.lock) {
      if (this.newFrom === 2  &&  ! this.nucleus) {
         n  =  this.score.length;
         if (n > 0) {
            this.nucleus  =  n;
         }
      }
   }
   if (this.leap) {
      if (this.start) {
         c  =  WSTM.str.substrEnd(this.start, 1);
      } else if (this.index > 0) {
         c  =  this.source.substr(this.index - 1,  1);
      } else {
         c  =  false;
         n  =  10;
      }
      if (c) {
         n  =  c.charCodeAt(0);
      }
      if (n === 10  ||  n === 32) {
         this.leap  =  false;
      } else {
         this.extend(32);
         this.move++;
      }
   }
   if (! this.mode) {
      if (this.show) {   // titled
         if (WSTM.str.isLetter(WSTM.str.substrEnd(this.show, 1))) {
            // c'td?
            n  =  WSTM.w.link.wiki.fore(this.suffix, 0);
            if (n) {
               this.show  =  this.show  +  this.suffix.substr(0, n);
               this.extend(16, n);
               if (n > this.suffix.length) {
                  this.suffix  =  this.suffix.substr(n);
               } else {
                  this.suffix  =  false;
               }
            }
         }   // isLetter
         if (typeof(this.newTo) === "number") {
            if (this.newTo >= this.inTerm) {
               if (typeof(this.score) === "string") {
                  this.score  =  this.score + "|" + this.show;
                  this.show   =  false;
               }
            }
         }
      }   // titled
      if (this.newFrom === 2) {
         this.mode  =  this.ModeWiki;
      }
   }
   this.lineFeedAhead();
   if (typeof(this.newTo) === "number") {
      this.join  =  (typeof(this.join) === "number"  ?  this.join
                                                     :  0);
      if (this.newTo > this.join) {
         if (typeof(this.shift) === "boolean") {
            this.shift  =  (this.score ? this.score : "");
         }
      }
      if (this.newFrom <= 0) {
         linking  =  (typeof(this.score) === "string")
                     &&  this.newTo > this.join;
         if (linking) {
            if (typeof(this.start) === "string") {
               if (WSTM.str.substrEnd(this.start, 2) === "[[") {
                  linking  =  false;
               }
            }
         }
         this.shift  =  (this.leap ? " " : "")
                        +  (linking ? "[[" : "")
                        +  (this.shift ? this.shift : "");
      }
      if (this.start  &&  this.newFrom < 0) {
         this.shift  =  this.start  +  (this.shift ? this.shift : "");
      }
      if (this.newTo  >=  this.join + this.inTerm + 2) {
         if (this.score  &&  this.mode !== this.ModeFile) {
            this.shift  =  (this.shift ? this.shift : "")  +  "]]";
         }
         if (this.suffix && this.next) {
            s  =  this.suffix;
            if (typeof(this.next) === "number") {
               s  =  s.substr(0, this.next);
            }
            this.shift  =  (this.shift ? this.shift : "")  +  s;
         }   // suffix
      }   // newTo
   }
   if (this.score) {
      n  =  this.score.length;
      if (n > this.move) {
         this.move  =  n;
      }
   }
};   // .o.Wikilink.analyze()



WikiLK.prototype.capitalize  =  function () {
   // Capitalize wikilink if appropriate
   // Precondition:
   //    address  -- string with link target
   // Uses:
   //    >  .o.Wikilink::
   //       >  .sister
   //       >  .show
   //       >< .score
   //       .extend()
   //    .hooks.fire()
   // 2012-05-17 [email protected]
   var low2up;
   var s;
   var start   =  this.score.substr(0, 1);
   var swap    =  start.toUpperCase();
   if (start !== swap) {   // 1st letter downcased
      low2up  =  true;
      if (this.sister) {
         s  =  this.sister.substr(0, 5) + ":";
         low2up  =  (s.substr(0, 5)  !==  "wikt:");
      }   // no upcasing in Wiktionary
      if (low2up) {
         low2up  =  WSTM.hooks.fire("wikilink-lower1",
                                    [ this.score, this.show ]);
      }   // upcasing appropriate
      if (low2up) {
         this.score  =  swap + this.score.substr(1);
         this.extend(1);
      }   // upcase
   }   // 1st letter downcased
};   // .o.Wikilink.capitalize()



WikiLK.prototype.category  =  function () {
   // Handle category of page
   // Uses:
   //    >  .w.encountered.DEFAULTSORT
   //    >  .g.wTitle
   //    >  .g.wNsNumber
   //    >  .o.WikiTom.LinkCategory
   //    >  .o.Wikilink::
   //       >  .sister
   //       >  .ModeCat
   //       >< .score
   //       >< .show
   //       >< .inPipe
   //        < .lock
   //        < .keySort
   //        < .mode
   //        < .special  //  -> schedule
   //        < .leader
   //       .extend()
   //    .w.elem.sortkey()
   //    .w.link.wiki.context()
   //    .w.link.wiki.further()
   // 2012-05-17 [email protected]
   var s  =  this.score.substr(0, 1);
   if (s.toUpperCase() !== s) {
      this.score  =  s.toUpperCase() + this.score.substr(1);
      this.extend(1);
   }
   if (! this.sister) {   // [[Category:  ]]
      if (this.inPipe) {   // [[Category:  |   ]]
         if (this.show) {
            s  =  WSTM.w.elem.sortkey(this.show);
            if (typeof(s) === "string") {
               if (! s.length) {
                  this.show  =  false;
               } else {
                  this.show  =  s;
               }
               this.extend(2);
            }
            if (this.show !== WSTM.w.link.wiki.context(this.score)) {
               if (WSTM.w.encountered.DEFAULTSORT) {
                  if (this.show === WSTM.w.encountered.DEFAULTSORT) {
                     this.show  =  false;
                     this.extend(2);
                  }
               }
               if (this.show === WSTM.g.wTitle) {
                  if (WSTM.g.wNsNumber === 0) {
                     if (! WSTM.w.encountered.DEFAULTSORT) {
                        this.show  =  false;
                        this.extend(2);
                     }
                  }
               }
            }   // not possibly erroneous "|]]"
         }   // non-empty sortkey
         if (this.show) {   // non-empty sortkey
            if (this.lock) {
               this.keySort  =  this.show.length;
            }
            this.score  =  this.score + "|" + this.show;
            this.show   =  false;
            this.extend(2);
            this.inPipe  =  false;
         } else {   // empty/emptied sortkey
            this.extend(1);
         }   // sortkey
      }   // pipe symbol
      this.mode     =  this.ModeCat;
      this.special  =  this.score;
      this.leader   =  WSTM.w.link.wiki.further(
                                   { mode:   WSTM.o.WikiTom.LinkCategory,
                                             source: this.score } );
   }   // ! sister
};   // .o.Wikilink.category()



WikiLK.prototype.closingBracket  =  function (adjust) {
   // Check or complete link content for second closing bracket
   // Precondition:
   //    adjust  -- string with link inner content
   //    Neither URL nor empty
   // Postcondition:
   //    this.score defined if appropriate
   // Uses:
   //    >  .o.Wikilink::
   //       >  .ModeFile
   //       >< .suffix
   //       >< .mode
   //       >< .lapsus
   //        < .score
   //       .extend()
   //    .errors.found()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-04-04 [email protected]
   var less  =  true;
   if (this.suffix) {
      if (this.suffix.charCodeAt(0) === 93) {   // ']'
         this.score  =  adjust;
         if (this.suffix.length < 2) {
            this.suffix  =  false;
         } else {
            this.suffix  =  this.suffix.substr(1);
         }
         less  =  false;
      }
   }
   if (less) {
      if (this.mode === this.ModeFile) {
         this.score  =  adjust;
      } else {
         WSTM.errors.found("secondClosingBracket", true, adjust);
         if (this.lapsus) {
            this.extend(-1);
         } else {   // append ']'
            this.score  =  adjust + "]]";
            this.extend(9);
            this.lapsus  =  true;
         }
      }
   }
};   // .o.Wikilink.closingBracket()



WikiLK.prototype.extend  =  function (assign, around) {
   // Extend replacement region
   // Precondition:
   //    assign  -- kind of extension
   //               -1  -- no extension
   //                1  -- target region (beginning at 2)
   //                2  -- title region
   //                3  -- end of both target and title
   //                4  -- begin at 0, not at 2
   //                8  -- end after first terminating bracket
   //                9  -- second terminating bracket appended
   //               16  -- append afterward characters
   //               32  -- begin and terminate at least at 0
   //    around  -- position extending outside brackets
   //               assign=16   after second bracket
   //               assign=32   before first bracket
   // Uses:
   //    >  .o.Wikilink::
   //       >  .inPipe
   //       >  .inTerm
   //       >< .newFrom
   //       >< .newTo
   // 2011-04-08 [email protected]
   var n;
   switch (assign) {
      case -1 :
         this.newFrom  =  2;
         this.newTo    =  false;
         break;
      case  1 :
      case  2 :
      case  3 :
      case  8 :
      case  9 :
      case 16 :
         switch (assign) {
            case  1 :
               n  =  (this.inPipe ? this.inPipe : this.inTerm);
               break;
            case  2 :
            case  3 :
               n  =  this.inTerm;
               break;
            case  8 :
            case  9 :
               n  =  this.inTerm + 1;
               break;
            case 16 :
               n  =  this.inTerm + 2;
               if (around) {
                  n  +=  around;
               }
               break;
         }   // switch assign
         if (typeof(this.newTo) === "number") {
            if (n > this.newTo) {
               this.newTo  =  n;
            }
         } else {
            this.newTo  =  n;
         }
         break;
      case  4 :
         this.newFrom  =  0;
         break;
      case 32 :
         this.newFrom  =  0;
         if (typeof(this.newTo) !== "number") {
            this.newTo  =  0;
         }
         if (around) {
            this.newFrom  -=  around;
         }
         break;
   }   // switch assign
};   // .o.Wikilink.extend()



WikiLK.prototype.file  =  function () {
   // Analyze wikilink as Media embedding in File: namespace
   // Uses:
   //    >  .l10n.word.trslFilePar
   //    >  .o.Wikilink::
   //       >  .sister
   //       >  .limited
   //       >  .newTo
   //       >  .ModeFile
   //       >< .show
   //       >< .score
   //        < .inPipe
   //        < .mode
   //       .extend()
   //    .l10n.word.filePars()
   //    .util.translate.flip()
   //    .str.substrEnd()
   // 2012-05-27 [email protected]
   var last;
   var scan;
   var s;
   if (! this.sister  &&  this.show) {   // Media
      /* next generation: DOM */
      scan  =  "|" + this.show + "|";
      if (! WSTM.l10n.word.trslFilePar) {
         WSTM.l10n.word.filePars();
         // parameters are enclosed in "|"
      }
      s  =  WSTM.util.translate.flip(scan, WSTM.l10n.word.trslFilePar);
      if (s !== scan) {
         last  =  (! this.limited);
         if (last) {
            last  =  (WSTM.str.substrEnd(this.show, 1)  ===  " ");
         }
         this.show  =  s.substr(1,  s.length - 2);
         if (last) {
            this.show  =  this.show + " ";
         }
         this.extend(3);
      }
      if (typeof(this.newTo) === "number") {
         if (this.newTo > this.inPipe) {
            this.score  =  this.score + "|" + this.show;
            this.show    =  false;
            this.inPipe  =  false;
         }
      }
      this.mode  =  this.ModeFile;
   }
};   // .o.Wikilink.file()



WikiLK.prototype.language  =  function (ahead) {
   // Analyze wikilink beginning whether it starts with language
   // Check language identification, remove wgContentLanguage
   // Precondition:
   //    ahead     -- position of ':' in this.score (>0)
   //    .justify  -- behaviour if no explicit "lang" identified
   //                 1           adjust with wgContentLanguage
   //                 2           adjust with "en"
   //                 false (else)
   //                             do nothing than trimming and downcasing
   // Postcondition:
   //    Returns true iff language stripped off from this.score
   //    RegExp was used.
   // Uses:
   //    >  .g.projLang
   //    >  .o.Wikilink::
   //       >< .justify
   //       >< .score
   //        < .lead
   //        < .slang
   //       .extend()
   //    .str.trimL()
   //    .l10n.lang.flop()
   //    .str.trimR()
   // 2012-06-27 [email protected]
   var learnt  =  false;
   var left    =  false;
   var r       =  false;
   var s       =  this.score.substr(0, ahead);
   var slang   =  false;   // language specification
   var story;              // heading part of article title
   s  =  WSTM.str.trimL(s, false);
   if (s.length < ahead) {
      learnt  =  true;
   }   // trimmed
   story  =  WSTM.l10n.lang.flop(s);
   if (! story) {
      slang  =  WSTM.str.trimR(s, false).toLowerCase();
      if (slang !== s) {
         learnt  =  true;
      }
   }   // matching lang?
   if (! slang) {
      if (this.justify) {
         switch (this.justify) {
            case  1 :
               slang   =  false;
               learnt  =  story;
               break;
            case  2 :
               slang   =  "en";
               learnt  =  true;
               break;
         }   // switch this.justify
         left  =  true;
      }
   }
   if (slang === WSTM.g.projLang) {
      slang   =  false;
      learnt  =  true;
   }
   if (learnt || slang || story) {   // language or similar identified
      this.score  =  this.score.substr(ahead + 1);
      if (story) {
         this.score  =  story + ":" + this.score;
         slang       =  false;
      } else {
         this.score  =  WSTM.str.trimL(this.score, false);
         if (left) {
            this.score  =  s + ":" + this.score;
         }
      }
      if (slang) {
         this.slang  =  slang + ":";
         r           =  true;
      }
      this.extend(1);
      this.justify  =  false;
   } else {
      if (this.justify) {
         if (this.lead) {
            this.lead  =  false;
            this.extend(1);
         }
      }
   }
   return r;
};   // .o.Wikilink.language()



WikiLK.prototype.lineFeedAhead  =  function () {
   // Ensure that a category or interlanguage starts on a new line
   // Uses:
   //    >  .o.Wikilink::
   //       >  .mode
   //       >  .ModeIw
   //       >  .ModeWiki
   //       >  .ModeCat
   //       >  .slang
   //       >  .show
   //       >  .source
   //       >  .index
   //       >< .start
   //       >< .move
   //       .extend()
   //    .errors.found()
   //    .str.isBlank()
   //    .util.isO_639_1()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-07-22 [email protected]
   var c;
   var k;
   var s;
   var m;
   if (this.mode === this.ModeIw) {
      if (this.slang.length === 3) {   // like "bd:"
         if (!  WSTM.util.isO_639_1(this.slang.substr(0, 2))) {
            this.mode  =  this.ModeWiki;   // downgrade   "bd"/"wd"
         }   // not a language code
      }   // A2 language code
      if (this.mode === this.ModeIw) {   // still interlanguage
         if (this.show) {
            WSTM.errors.found("interlanguageTitled",
                              false,
                              this.score + "|" + this.show);
            this.show  =  false;
         }   // titled
      }
   }   // interlanguage supposed
   if (this.mode === this.ModeCat  ||  this.mode === this.ModeIw) {
      if (this.start) {
         s  =  this.start;
         k  =  s.length - 3;
         c  =  s.charCodeAt(k);
      } else {
         if (this.index > 0) {
            s  =  this.source;
            k  =  this.index - 1;
            c  =  s.charCodeAt(k);
         } else {
            c  =  false;
         }
      }
      if (c) {
         if (c !== 10) {
            m  =  0;
            while (WSTM.str.isBlank(c, true)) {
               m++;
               if (! k) {
                  break;   // while
               }
               k--;
               c  =  s.charCodeAt(k);
            }
            if (c === 10) {
               if (this.start) {
                  this.start  =  s.substr(0,  k - 2);
               } else {
                  this.start  =  "";
               }
               this.extend(32, m);
               this.move  -=  m + 2;
            } else {
               if (this.start) {
                  k  =  this.start.length - 2;
                  this.start  =  this.start.substr(0, k)  +  "\n";
               } else {
                  this.start  =  "\n";
               }
               this.extend(32);
               this.move++;
            }
         }   // no break
      }   // prolog
   }   // category or interlanguage
};   // .o.Wikilink.lineFeedAhead()



WikiLK.prototype.magic  =  function () {
   // Analyze wikilink whether it is actually a magic word
   // Precondition:
   //    Neither File nor Category
   // Uses:
   //    >  .o.Wikilink::
   //       >  .show
   //       >  .score
   //       .magic_ISBN()
   // 2010-10-01 [email protected]
   var s  =  (this.show  ?  this.score + "|" + this.show  :  this.score);
   if (s.indexOf("ISBN") >= 0) {
      this.magic_ISBN();
   }
   /*
      PMID Nummer   min.6
           Richtig: PMID 4957203
           Falsch:  PMID:4957203
           Falsch:  PubMed 4957203
      RFC ISSN DOI gleichrangig Linkziele schützen
   */
};   // .o.Wikilink.magic()



WikiLK.prototype.magic_ISBN  =  function () {
   // Analyze wikilink and context whether it is actually magic word ISBN
   // Precondition:
   //    Wikilink contains magic word "ISBN" insome way
   // Uses:
   //    >  .g.re.ISBN
   //    >  .o.Wikilink::
   //       >  .suffix
   //       >< .show
   //       >< .score
   //        < .inPipe
   //        < .mode
   //        < .shift
   //      .extend()
   //    .w.elem.isbn.format()
   //    .str.substrEnd()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-07-11 [email protected]
   var found  =  false;
   var k;
   var later;
   var n;
   var narrow;
   var swap;
   if (this.show) {
      narrow  =  this.show.length;
      swap    =  ">"  +  this.show;
      if (narrow > 7) {
         if (narrow >= 14) {
            swap  =  swap  +  this.suffix;
         } else {
            swap  =  false;
         }
      }
      if (swap) {
         swap   =  swap + "\t";
         found  =  WSTM.g.re.ISBN.exec(swap);
      }
      if (swap) {
         if (found) {
            if (found.index !== 0) {
               found  =  false;
            }
         }
      }
      if (found) {
         k     =  0;
         n     =  swap.length;
         swap  =  WSTM.w.elem.isbn.format(found);
         if (! swap) {
            swap  =  found[0];
         }   // unchanged
         if (WSTM.str.substrEnd(swap, 1) === "\t") {
            swap  =  swap.substr(0,  n - 1);
            if (narrow <= 7) {
               k--;
            }
         }   // end of source
         this.shift   =  swap.substr(1);
         if (narrow <= 7) {
            k  +=  found[0].length - 5;
         } else {
            k  +=  2;
         }
         this.extend(16, k);
      }   // |ISBN]] + number
   }
   if (!  (found || this.show)) {
      later  =  (this.score === "ISBN");
      if (later) {
         swap  =  "ISBN " + this.suffix;
      } else {
         swap  =  this.score;
      }
      swap   =  ">" + swap + "\t";
      found  =  WSTM.g.re.ISBN.exec(swap);
      if (found) {
         if (found.index !== 0) {
            found  =  false;
         }
      }
      if (found) {
         k  =  (later  ?  found[0].length - 5  :  0);
         swap  =  WSTM.w.elem.isbn.format(found);
         if (! swap) {
            swap  =  found[0];
         }   // unchanged
         n  =  swap.length - 1;
         if (swap.charCodeAt(n) === 9) {   //  \t
            swap  =  swap.substr(0, n);
            if (later) {
               k--;
            }
         }
         this.extend(16, k);
         this.shift  =  swap.substr(1);
      }   // [[ISBN + number
   }
   if (found) {
      this.extend(4);
      this.show    =  false;
      this.score   =  false;
      this.inPipe  =  false;
      this.mode    =  -1;
   }
};   // .o.Wikilink.magic_ISBN()



WikiLK.prototype.namespace  =  function (ahead) {
   // Analyze wikilink beginning whether it starts with namespace
   // Precondition:
   //    ahead  -- position of ':' in this.score (>0)
   // Uses:
   //    >  .o.Wikilink::
   //       >  .sister
   //       >  .slang
   //       >  .lead
   //       >  .inPipe
   //       >< .score
   //       >< .show
   //        < .nucleus
   //        < .lock
   //       .extend()
   //       .file()
   //       .category()
   //       .specials()
   //       .capitalize()
   //    .w.link.namespace.furnish()
   //    .w.link.namespace.fetch()
   //    .w.link.wiki.decode()
   // 2011-10-15 [email protected]
   var space  =  this.score.substr(0, ahead);
   var key    =  WSTM.w.link.namespace.furnish(space);
   var s;
   var swap;
   if (key) {   // relevant namespace?
      s     =  (this.sister ? this.sister : this.slang);
      swap  =  WSTM.w.link.namespace.fetch(key, s);
      if (swap) {
         if (space !== swap) {
            this.extend(1);
         }
         space  =  swap;
      }
      if (this.lead  &&  ! this.sister) {   // :File:  or  :Category:
         this.sister  =  ":";
         this.extend(1);
      }
      this.score  =  this.score.substr(ahead + 1);
      s           =  WSTM.w.link.wiki.decode(this.score,
                                             true, false, true, true);
      if (s) {
         this.score  =  s;
         this.extend(1);
      }
      if (this.lock  &&  ! this.sister  &&  this.show) {
         this.nucleus  =  space.length + 1 + this.score.length;
         if (this.nucleus + 2  !==  this.inPipe) {
            this.extend(1);
         }
      }
      switch (key) {
         case 1 :   // File
            this.file();
            break;
         case 2 :   // Category
            this.category();
            break;
         case 3 :   // Special
            this.specials();
            break;
      }   // switch key
      if (this.score) {
         this.capitalize();
         this.score  =  space + ":" + this.score;
      }
   }   // key
};   // .o.Wikilink.namespace()



WikiLK.prototype.newline  =  function (analyze, address) {
   // Repair line break within wikilink, if appropriate
   // Precondition:
   //    analyze  -- string with link inner content
   //    address  -- position of '\n' in environment (>1)
   // Postcondition:
   //    Returns repaired analyzed string, or false
   // Uses:
   //    >  .o.Wikilink::
   //       >  .inTerm
   //       >  .inPipe
   //       >  .join
   //       >< .score
   //        < .lapsus
   //       .extend()
   //     < .mod.lazy
   //    .str.setChar()
   // 2012-05-09 [email protected]
   var maxd  =  50;
   var newl;
   var r     =  analyze;
   var leak  =  (address < maxd   ||   this.inTerm - address  <  maxd);
   if (leak) {
      this.extend(3);
   } else if (this.inPipe) {
      if (address < maxd) {   // left of pipe
         leak  =  (this.inPipe - address  <  maxd);
         this.extend(1);
      } else {   // right of pipe
         leak  =  (address - this.inPipe  <  maxd);
         this.extend(2);
      }
   }
   // TODO   maybe  [[File:
   if (leak) {   // error detected and repairing
      r     =  WSTM.str.setChar(analyze,  32,  address - 2);   // ' '
      newl  =  r.indexOf("\n") + 2;
      if (newl > 1  &&  newl < this.join) {   // newline(s) left
         this.extend(-1);
         r  =  false;
      }
      this.lapsus     =  true;
      WSTM.mod.lazy   =  false;
   } else {
      this.extend(-1);
      r  =  false;
   }
   return r;
};   // .o.Wikilink.newline()



WikiLK.prototype.old2New  =  function () {
   // Perform user defined replacements
   // Precondition:
   //    .old2new is defined.
   // Uses:
   //    >  .o.Wikilink::
   //       >  .source
   //       >  .index
   //       >< .show
   //       >< .suffix
   //       >< .old2new
   //       >< .score
   //       >< .learn
   //       >< .mode
   //        < .next
   //       .extend()
   //    .w.link.replace.flip()
   //    .str.trimR()
   //    .str.substrEnd()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-05-30 [email protected]
   var i;
   var j;
   var n;
   var s;
   var sB  =  this.source.substr(0,  this.index + 2);
   var sE  =  (this.show ? this.show : "")  +  "]]"  +
              (this.suffix ? this.suffix : "");
   var sO;
   var x   =  WSTM.w.link.replace.flip(this.old2new, this.score, sB, sE,
                                       "[[");
   if (x) {
      this.learn  =  true;
      this.extend(1);
      if (typeof(x) === "string") {
         this.score  =  x;
      } else {
         if (x[0]) {
            if (x[0] !== sB) {
               for (j = 0;  j < sB.length;  j++) {
                  if (x[0].charCodeAt(j) !== sB.charCodeAt(j)) {
                     break;   // for j
                  }
               }   // for j
            }
         }
         if (this.score !== x[1]) {
            this.score  =  x[1];
            this.extend(3);
         }
         if (x[0]) {
            sO  =  x[0];
            n   =  sB.length;
            for (j = 0;  j < n;  j++) {
               if (sO.charCodeAt(j) !== sB.charCodeAt(j)) {
                  break;   // for j
               }
            }   // for j
            if (j > 0) {
               this.start  =  sO.substr(j);
            }
            j   =  n - j - 2;
            sB  =  WSTM.str.substrEnd(this.start, 2);
            if (sB !== "[[") {   // unlink
               this.extend(4);
               this.shift  =  this.start + this.score;
               this.mode   =  -1;
            }
            if (j > 0) {
               this.extend(32, j);
            }
         }
         if (x[2] === sE) {
            x[2]  =  false;
         }
         if (x[2]) {
            sO  =  x[2];
            if ( ! this.mode) {
               this.mode  =  0;
            }

            j  =  sO.indexOf("]]");
            if (this.mode <= 0  ||  ! j) {
               if (j) {
                  n  =  this.suffix.length;
                  for (i = sO.length;  i && n;  i--, n--) {
                     if (this.suffix.charCodeAt(n)
                         !== sO.charCodeAt(i)) {
                        break;   // for i
                     }
                  }   // for i
                  if (i || n) {
                     this.extend(16, n);
                     this.next  =  i;
                  }
                  this.show    =  sO.substr(0, j);
                  this.suffix  =  sO.substr(j+2);
               } else {
                  sO  =  sO.substr(2);
               }
               j  =  -1;
               if (x[0]) {
                  this.extend(3);
               }
            } else {
               this.show  =  false;
            }
            if (j > 0) {
               s  =  sO.substr(0, j);
               if (s.indexOf("[") < 0) {
                  this.show   =  WSTM.str.trimR(s, true);
                  j          +=  2;
               } else {
                  j  =  -2;
               }
            } else if (j === 0) {
               j  =  2;
            }
            if (j > 0) {
               if (sO.length > j) {
                  sO  =  sO.substr(j);
               } else {
                  sO  =  false;
               }
            }
            if (this.suffix) {
               n  =  this.suffix.length;
            } else {
               n  =  0;
            }
            this.extend(2);
         }
         if (this.mode < 0) {
            this.start   =  false;
            this.show    =  false;
            this.score   =  false;
            this.inPipe  =  false;
         }
      }   // modified
   }   // user defined replacements
};   // .o.Wikilink.old2New()



WikiLK.prototype.pipeSymbols  =  function (align) {
   // Analyze pipe symbol(s) within wikilink
   // Precondition:
   //    align  -- position of '|' in this.score  (>=0)
   // Uses:
   //    >  .o.Wikilink::
   //       >  .ModeFile
   //       >< .score
   //       >< .mode
   //        < .lapsus
   //        < .show
   //       .extend()
   //    .str.trimL()
   //    .errors.found()
   // 2012-04-10 [email protected]
   var less;
   var mid;
   var n;
   var s;
   var shine  =  this.score.substr(align + 1);
   if (align > 0) {
      this.score  =  this.score.substr(0, align);
   } else {
      this.score  =  false;
   }
   s  =  WSTM.str.trimL(shine, false);
   n  =  s.length;
   if (n < shine.length) {
      this.extend(2);
   }   // ltrim
   if (n === 0) {
      if (! this.score) {   // [[|]]
         WSTM.errors.found("meaninglessLinkTarget", true, "");
         this.extend(-1);
         shine  =  false;
      }
   }
   if (shine) {
      mid  =  s.indexOf("|");
      if (mid < 0) {
         this.show  =  shine;
      } else {   // second pipe
         if (mid === 0) {   // directly following
            s    =  s.substr(1);
            mid  =  s.indexOf("|");
            this.extend(2);
            this.lapsus  =  true;
            if (mid < 0) {
               s  =  WSTM.str.trimL(s, false);
               if (! s.length) {
                  s  =  false;
               }
            }
         } else {
            less  =  true;
            if (this.score) {
               less  =  (this.mode !== this.ModeFile);
            }
            if (less && this.show) {
               if (this.show.substr(0, mid).indexOf("{{")  <  0) {
                  WSTM.errors.found("multiplePipeSymbols",
                                    false,
                                    this.score);
                  if (this.lapsus) {
                     this.extend(-1);
                     s  =  false;
                  } else {
                     this.lapsus  =  true;
                  }
               }
            }   // less
         }
         this.show  =  s;
      }   // second pipe
   }
};   // .o.Wikilink.pipeSymbols()



WikiLK.prototype.project  =  function (ahead) {
   // Analyze wikilink beginning whether it starts with project
   // Precondition:
   //    ahead  -- position of ':' in this.score (>0)
   // Postcondition:
   //    Returns true iff project stripped off from this.score
   //    RegExp was used.
   // Uses:
   //    >  .o.Wikilink::
   //       >< .score
   //        < .lead
   //        < .sister
   //        < .justify
   //       .extend()
   //    >< .l10n.word.file
   //    .str.trimL()
   //    .w.link.project()
   //    .l10n.word.fetch()
   // 2012-07-12 [email protected]
   var kind;
   var swap;
   var r  =  false;
   var s  =  this.score.substr(0, ahead);
   if (ahead === 1) {
      if (s === s.toUpperCase()) {
         s  =  false;
         // ":sv:S:t Eriksplan (tunnelbanestation)"
      }
   }
   if (s) {
      r  =  WSTM.w.link.project(s, true);
   }
   if (r) {   // project identified
      kind  =  r[0];
      swap  =  r[1];
      this.score  =  WSTM.str.trimL(this.score.substr(ahead + 1),
                                    false);
      if (this.score.length  <  ahead + 1) {
         this.extend(1);
      }   // trimmed
      if (kind === 3) {
         if (swap === "commons") {
            if (this.score.charCodeAt(4) === 58  ||
                this.score.charCodeAt(5) === 58) {   // ':'
               if (/^(File|Image):/i.test(this.score)) {
                  if (! WSTM.l10n.word.file) {
                     WSTM.l10n.word.file  =  WSTM.l10n.word.fetch("File",
                                                                  0);
                  }
                  kind        =  this.score.indexOf(":") + 1;
                  swap        =  WSTM.l10n.word.file;
                  this.score  =  WSTM.str.trimL(this.score.substr(kind),
                                                false);
                  this.lead   =  true;
                  kind        =  false;
               }
            }
         }
      }
      if (kind) {
         if (this.lead) {   // superfluous heading ':'
            this.extend(1);
         }
         this.lead  =  true;
         if (swap) {
            this.sister   =  swap + ":";
            this.justify  =  kind;
            if (swap !== s) {
               this.extend(1);
            }
         } else {   // itself
            this.justify  =  2;
            this.extend(1);
         }
      } else {   // project major namespace
         this.score  =  swap + ":" + this.score;
         this.extend(1);
      }   // mode
   }   // affiliated project
   return r;
};   // .o.Wikilink.project()



WikiLK.prototype.specials  =  function () {
   // Handle link into special namespace
   // Precondition:
   //    .score is defined, special namespace already stripped off.
   // Uses:
   //    >  .o.Wikilink::
   //       >< .score
   //        < .inPipe
   //        < .show
   //        < .shift
   //        < .mode
   //       .extend()
   //    .hooks.fire()
   //    .util.isbn.format()
   // 2011-10-15 [email protected]
   var got;
   var re   =  "^([^/]+)"
              + "(/([-0-9]{9,}[0-9xX]|[-0-9]{13,}))$";
   var s    =  this.score.substr(0, 1);
   if (s.toUpperCase() !== s) {
      this.score  =  s.toUpperCase() + this.score.substr(1);
      this.extend(1);
   }
   re   =  new RegExp(re, "");
   got  =  re.exec(this.score);
   if (got) {
      if (WSTM.hooks.fire("booksources", got[1])) {
         s    =  got[3];
         got  =  WSTM.util.isbn.format(s, false);
         if (got[0]) {
            if (got[1]) {
               s  =  got[1];
            }
         }
         this.shift   =  "ISBN " + s;
         this.inPipe  =  false;
         this.show    =  false;
         this.score   =  false;
         this.extend(4);
         this.extend(16, 0);
         this.mode  =  -1;
      }
   }
};   // .o.Wikilink.specials()


WikiLK.prototype.target  =  function () {
   // Analyze wikilink target
   // Precondition:
   //    .score is defined.
   // Uses:
   //    >  .o.Wikilink::
   //       >  .ModeFile
   //       >  .justify
   //       >  .ModeIw
   //       >< .score
   //       >< .show
   //       >< .lead
   //       >< .slang
   //       >< .sister
   //        < .mode
   //        < .leap
   //        < .special
   //        < .leader
   //       .extend()
   //       .project()
   //       .language()
   //       .namespace()
   //       .capitalize()
   //       .old2New()
   //    >  .o.WikiTom.LinkInterWiki
   //    .w.link.filter()
   //    .str.isBlank()
   //    .str.trimL()
   //    .w.link.wiki.target()
   //    .w.link.wiki.further()
   // Requires: JavaScript 1.3   charCodeAt()   fromCharCode()
   // 2012-07-07 [email protected]
   var join;
   var label;
   var lang;
   var re;
   var s     =  WSTM.w.link.filter(this.score,
                                   this.show
                                   ||  (this.mode === this.ModeFile));
   if (s) {
      this.score  =  s;
      this.extend(1);
   }   // undesired character removed
   if (WSTM.str.isBlank(this.score.charCodeAt(0), false)) {
      this.score  =  WSTM.str.trimL(this.score.substr(1), true);
      if (! this.show) {
         this.leap   =  true;
      }
   }
   while (this.score.charCodeAt(0) === 58) {   // ':'
      this.lead   =  true;
      this.score  =  WSTM.str.trimL(this.score.substr(1), true);
   }   // while leading ':'
   join  =  this.score.indexOf(":");
   if (join > 0) {
      label  =  this.project(join);
      lang   =  false;
      if (! label) {
         lang  =  this.language(join);
      }
      if (label  ||  (lang && this.lead)) {   // one already in effect
         join  =  this.score.indexOf(":");
         if (join > 0) {
            if (label) {   //   (:)project:lang:Lemma ??
               this.language(join);
            } else if (this.lead) {   //   :lang:project:Lemma ??
               this.project(join);
            }
         }   // ':'  ':'
      }
      if (! this.slang
          &&  this.justify === 2) {  // no lang, but needed
         this.slang  =  "en:";
         this.extend(1);
         this.lead  =  true;
      }
      if (this.slang) {   // lang detected
         // 200A   8203  ZERO WIDTH SPACE  used in bo:
         // 200B   8204  ZERO WIDTH NON-JOINER  used in Farsi, kn:, mzn:
         // 200C   8205  ZERO WIDTH JOINER      used in ml:
         if (":bo:".indexOf(":" + this.slang)  >=  0) {
            if (this.score.indexOf("&#x200A;") >= 0) {
               re  =  new RegExp("&#x200A;", "g");
               s   =  String.fromCharCode(8203);
               if (re.test(this.score)) {
                  this.score  =  this.score.replace(re, s);
               }
            }
         }
         if (this.score.indexOf("&zw") >= 0) {
            if (":fa:kn:mzn:".indexOf(":" + this.slang)  >=  0) {
               re  =  new RegExp("&zwnj;", "g");
               if (re.test(this.score)) {
                  s           =  String.fromCharCode(8204);
                  this.score  =  this.score.replace(re, s);
               }
            }
            if (":ml:".indexOf(":" + this.slang)  >=  0) {
               re  =  new RegExp("&zwj;", "g");
               if (re.test(this.score)) {
                  s           =  String.fromCharCode(8205);
                  this.score  =  this.score.replace(re, s);
               }
            }
         }
         if (this.sister) {
            this.sister  =  this.sister + this.slang;
            this.lead    =  true;
         } else if (this.lead) {
            this.sister  =  ":" + this.slang;
         } else {   // (! this.lead) -- interlanguage
            this.mode     =  this.ModeIw;   // .interlanguage()
            this.special  =  this.slang + this.score;
            this.sister   =  this.slang;
            s             =  this.slang.substr(0,
                                               this.slang.length - 1);
            this.leader   =  WSTM.w.link.wiki.further(
                                  { mode:   WSTM.o.WikiTom.LinkInterWiki,
                                    source: s } );
         }
      }
      join  =  this.score.indexOf(":");
   }   // ':'
   s  =  WSTM.w.link.wiki.target(this.score,  ! this.show);
   if (s) {
      this.score  =  s;
      this.extend(1);
      if (join > 0) {   // adjust
         join  =  this.score.indexOf(":");
      }
   }
   if (join > 0) {   // namespace?
      this.namespace(join);
   }   // namespace?
   if (this.show) {
      if (WSTM.str.isBlank(this.show.charCodeAt(0), false)) {
         this.show  =  WSTM.str.trimL(this.show.substr(1), true);
         this.leap  =  true;
      }
      this.capitalize();
   }   // titled?
   if (this.sister) {
      this.score  =  this.sister + this.score;
   }
   if (this.lead  &&  ! this.sister) {
      if (this.score.charCodeAt(0) !== 47) {   // '/'
         this.lead  =  false;
      }
   }
   if (this.old2new) {
      this.old2New();
   }   // user defined replacements
};   // .o.Wikilink.target()



WikiLK.prototype.title  =  function () {
   // Analyze wikilink title and representation
   // Precondition:
   //    this.show not a Category
   // Uses:
   //    >  .o.Wikilink::
   //       >< .show
   //       >< .suffix
   //        < .leap
   //       .extend()
   //    .str.trimR()
   //    .str.isBlank()
   //    .str.trimL()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2012-03-31 [email protected]
   var k;
   var leap;
   var m  =  this.show.length;
   var n;
   this.show  =  WSTM.str.trimR(this.show, false);
   n  =  this.show.length;
   if (n < m) {
      leap  =  false;
      if (this.suffix) {
         k  =  this.suffix.charCodeAt(0);
         if (k === 10) {
            leap  =  true;
         } else {
            leap  =  WSTM.str.isBlank(k, true);
         }
      }
      if (leap) {   // whitespace follows
         this.extend(2);
      } else {
         this.suffix  =  "]] ";
         this.extend(16, 0);
      }
   }   // rtrim
   if (WSTM.str.isBlank(this.show.charCodeAt(0), false)) {
      this.show  =  WSTM.str.trimL(this.show.substr(1), false);
      this.extend(32);
      this.leap  =  true;
   }   // ltrim
};   // .o.Wikilink.title()



WikiLK.prototype.unlink  =  function () {
   // Analyze link whether it can be unlinked or merged with title
   // Precondition:
   //    Wikilink without leading colon ':'
   // Uses:
   //    >  .g.wTitle
   //    >  .g.wNsNumber
   //    >  .o.Wikilink::
   //       >  .sister
   //       >  .subcase
   //       >  .off
   //       >  .onto
   //       >  .lapsus
   //       >< .score
   //       >< .show
   //       >< .suffix
   //       >< .next
   //        < .inPipe
   //        < .shift
   //        < .mode
   //       .extend()
   //    .w.link.wiki.fore()
   //    .str.deCapitalize()
   //    .str.isLetter()
   // 2012-05-14 [email protected]
   var io;
   var j;
   var n;
   var sh;
   var sw  =  WSTM.str.deCapitalize(this.score);
   if (! this.sister  &&  WSTM.g.wNsNumber === 0) {
      io  =  0;
      if (sw === this.subcase) {   // unlink
         io  =  1;
      } else if (sw.indexOf(this.subcase + "#")  ===  0) {   // intern
         io  =  2;
      }
      if (io > 0) {
         if (this.off && this.onto) {
            if (this.off.isNodeInSpan(this.onto)) {
               io  =  -1;
            }
         }
      }
      if (io === 1) {   // unlink
         this.inPipe  =  false;
         if (this.show) {
            this.shift  =  this.show;
            this.show   =  false;
         } else {
            this.shift  =  this.score;
         }
         this.score  =  false;
         this.extend(4);
         this.extend(16, 0);
         this.mode  =  -1;
      } else if (io === 2) {   // internal
         this.score  =  this.score.substr(WSTM.g.wTitle.length);
         this.extend(1);
      }
   }   // same project
   if (this.show) {
      sh  =  WSTM.str.deCapitalize(this.show);
      if (sw === sh  &&  ! this.sister) {
         this.score  =  this.show;
         this.show   =  false;
         this.extend(3);
         this.inPipe  =  false;
      } else if (! this.lapsus) {
         n  =  sw.length;
         if (sw  ===  sh.substr(0, n)   &&
             WSTM.str.isLetter(sh.substr(n, 1))) {
            j  =  WSTM.w.link.wiki.fore(sh, n);
            if (j) {
               if (j + n  ===  sh.length) {
                  this.score  =  this.show.substr(0, n);
                  this.show   =  this.show.substr(n);
                  j  =  this.show.length;
                  if (j > 0) {
                     if (this.suffix) {
                        this.suffix  =  this.show + this.suffix;
                        if (! this.next) {
                           this.next  =  j;
                        }
                     } else {
                        this.suffix  =  this.show;
                        if (! this.next) {
                           this.next  =  true;
                        }
                     }
                  }
                  this.show  =  false;
                  this.extend(16, 0);
                  this.inPipe  =  false;
               }   // link range unchanged
            }   // do not merge sophisticated link titles
         } else if (this.suffix) {
            if (sh  ===  sw.substr(0, sh.length)) {
               j  =  WSTM.w.link.wiki.fore(this.suffix, 0);
               if (j) {
                  if (sw  ===  sh + this.suffix.substr(0, j)) {
                     this.suffix  =  this.suffix.substr(j);
                     this.show  =  false;
                     this.extend(16, j);
                     this.inPipe  =  false;
                  }
               }
            }
         }
      }   // title === target, or part
   }   // titled
};   // .o.Wikilink.unlink()



WikiLK.prototype.url  =  function (adjust) {
   // Analyze bracket content whether it starts with an URL
   // Precondition:
   //    adjust  -- string with possible link target, left trimmed
   // Postcondition:
   //    Returns true iff adjust starts with an URL
   // Uses:
   //    >  .o.Wikilink::
   //       >  .suffix
   //        < .lapsus
   //        < .mode
   //        < .move
   //        < .shift
   //       .extend()
   // Requires: JavaScript 1.3   charCodeAt()
   // 2011-09-28 [email protected]
   var r   =  false;
   var re;
   var s;
   switch (adjust.charCodeAt(1)) {
      case  47 :   //  '/'
         r  =  (adjust.charCodeAt(0) === 47);
         break;
      case 116 :   //  't'
         s  =  adjust.substr(0, 4);
         r  =  (s === "http"  ||  s === "ftp:");
         break;
   }   // switch charCodeAt(1)
   if (r) {
      re  = new RegExp("((https?|ftp):)?//"
                       + "([^ ;,/*&?!#]+)+\\.[a-z]+([/:].+)?",
                       "");
      r  =  (adjust.search(re) === 0);
      if (r) {
         this.extend(3);
         this.extend(4);
         if (this.suffix) {
            if (this.suffix.charCodeAt(0) === 93) {   // ']'
               this.extend(8);   // post first bracket
            }   // terminating double brackets
         }   // follow
         this.lapsus  =  true;
         this.mode    =  1;
         this.move    =  adjust.length + 2;
         this.shift   =  "[" + adjust;
      }   // matching
   }   // heading
   return r;
};   // .o.Wikilink.url()



WikiLK.prototype.getChange  =  function () {
   // Returns true if any need for changes
   // Uses:
   //    >  .o.Wikilink::
   //       >  .shift
   //       >  .newTo
   //       >  .newFrom
   //       >  .source
   //       >  .index
   // 2012-04-12 [email protected]
   var r  =  (typeof(this.shift) === "string");
   if (r) {
      r  =  (typeof(this.newTo) === "number");
      if (r) {
         if (this.newFrom === 2) {
            r  =  (this.source.substr(this.index + 2,  this.newTo - 2)
                   !==   this.shift);
         } else {
            r  =  false;
         }
      }
   }
   return r;
};   // .o.Wikilink.getChange()


WikiLK.prototype.getError  =  function () {
   // Returns true if severe syntax error detected (repaired if change)
   // Uses:
   //    >  .o.Wikilink::
   //       >  .lapsus
   // 2010-10-01 [email protected]
   return  this.lapsus;
};   // .o.Wikilink.getError()


WikiLK.prototype.getIncrement  =  function () {
   // Returns number of chars to advance in basic text
   // Uses:
   //    >  .o.Wikilink::
   //       >  .move
   // 2010-10-01 [email protected]
   return  this.move;
};   // .o.Wikilink.getIncrement()


WikiLK.prototype.getLeader  =  function () {
   // Returns true if category or interlanguage has been first occurrence
   // Uses:
   //    >  .o.Wikilink::
   //       >  .leader
   // 2012-04-26 [email protected]
   return  this.leader;
};   // .o.Wikilink.getLeader()


WikiLK.prototype.getRemoveFrom  =  function () {
   // Returns number of target chars since which to be removed, or false
   // Uses:
   //    >  .o.Wikilink::
   //       >  .newFrom
   //       >  .newTo
   // 2011-05-03 [email protected]
   var k  =  this.newFrom;
   if (k) {
      if (typeof(this.newTo) !== "number") {
         k  =  false;
      }
   }
   return  k;
};   // .o.Wikilink.getRemoveFrom()


WikiLK.prototype.getRemoveTo  =  function () {
   // Returns number of target chars to be removed, or false
   // Uses:
   //    >  .o.Wikilink::
   //       >  .newTo
   // 2010-10-01 [email protected]
   return  this.newTo;
};   // .o.Wikilink.getRemoveTo()


WikiLK.prototype.getSortkey  =  function () {
   // Returns number of characters to be unconditionally locked, or false
   // Uses:
   //    >  .o.Wikilink::
   //       >  .keySort
   // 2010-10-01 [email protected]
   return  this.keySort;
};   // .o.Wikilink.getSortkey()


WikiLK.prototype.getSpecial  =  function () {
   // Returns category or interlanguage content
   // Uses:
   //    >  .o.Wikilink::
   //       >  .special  //  -> schedule
   // 2010-10-01 [email protected]
   return  this.special;
};   // .o.Wikilink.getSpecial()


WikiLK.prototype.getTargetLength  =  function () {
   // Returns number of target chars to be locked, or false if not adhere
   // Uses:
   //    >  .o.Wikilink::
   //       >  .lock
   //       >  .score
   //       >  .nucleus
   // 2010-10-01 [email protected]
   //    [1]
   var r  =  false;
   if (this.lock && this.score) {
      r  =  (this.nucleus ? this.nucleus : this.score.length);
   }
   return  r;
};   // .o.Wikilink.getTargetLength()


WikiLK.prototype.getTextReplace  =  function () {
   // Returns replacement string, maybe false if nothing to do
   // Uses:
   //    >  .o.Wikilink::
   //       >  .shift
   // 2010-10-01 [email protected]
   return  this.shift;
};   // .o.Wikilink.getTextReplace()


WikiLK.prototype.getType  =  function () {
   // Returns special link type, or false if not a link
   //    -1     unlinked (magic, self-reference, or replaced)
   //     1     weblink
   //     2     normal wikilink
   //     3     file (not Media:)
   //     4     category
   //     5     interlanguage
   //     6     special interwikilink ([[bugzilla:...]] etc.)
   //     7     page
   //     9     special weblink ([[DOI:...]] etc.)
   // Uses:
   //    >  .o.Wikilink::
   //       >  .mode
   // 2010-10-22 [email protected]
   return  this.mode;
};   // .o.Wikilink.getType()


WikiLK.prototype.getUserModified  =  function () {
   // Returns true if user defined modification performed
   // Uses:
   //    >  .o.Wikilink::
   //       >  .learn
   // 2010-10-01 [email protected]
   return  this.learn;
};   // .o.Wikilink.getUserModified()



WikiLK.prototype.set  =  function (anode, access, adhere, alien, assign) {
   // Initialize exisiting wikilink object with node
   // Precondition:
   //    anode    -- current node object
   //    access   -- position in node where '[[' starts
   //    adhere   -- true: freeze link targets
   //    alien    -- WikiTom with <includeonly> spans, or false
   //    assign   -- array with link replacements, or false
   // Postcondition:
   //    .o.Wikilink object was set and has been analyzed
   //    RegExp was used.
   // Uses:
   //    WikiTom().toString()
   //    >  .o.Wikilink::
   //       >  .onto
   //       >  .index
   //       >  .lock
   //       >  .off
   //       >  .old2new
   //       >  .move
   //       >  .newFrom
   //       >  .source
   //       .init()
   //       .adjust()
   // 2010-10-13 [email protected]
   this.init();
   this.onto     =  anode;
   this.index    =  access;
   this.lock     =  adhere;
   this.off      =  alien;
   this.old2new  =  assign;
   this.move     =  2;
   this.newFrom  =  2;
   this.source   =  anode.toString();
   this.adjust(this.source.substr(this.index));
};   // .o.Wikilink.set()



WikiLK.prototype.setTarget  =  function (adjust, assign) {
   // Initialize exisiting wikilink object with target string
   // Precondition:
   //    adjust   -- target string
   //    assign   -- array with link replacements, or false
   // Postcondition:
   //    .o.Wikilink object was set and has been analyzed
   //    RegExp was used.
   // Uses:
   //    WikiTom().toString()
   //    >  .o.Wikilink::
   //       >  .source
   //       >  .old2new
   //       .init()
   //       .adjust()
   // 2010-10-13 [email protected]
   this.init();
   this.source   =  adjust;
   this.old2new  =  assign;
   this.adjust(this.source);
};   // .o.Wikilink.setTarget()



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



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



mw.libs.WikiSyntaxTextMod.bb.WikiTom  =  function (WSTM) {
// Text and wikisyntax node
// 2012-07-07 [email protected]
   var WTOM;


WSTM.o.WikiTom  =  function (assign, above) {
   // .constructor for new
   // Precondition:
   //    assign  -- string
   //    above   -- parent Node   root: null
   // Postcondition:
   //    Returns new WikiTom
   // 2012-03-12 [email protected]
   this.parent    =  above;    // Object
   this.source    =  assign;   // String   basic or no change in children
   this.learnt    =  false;    // boolean  any (minor) modification
   this.lookup    =  true;     // boolean  may be searched
   this.limited   =  false;    // boolean  end of block
   this.mode      =  0;        // Number   kind of node
// this.children               // Array    of WikiTom nodes
// this.scope                  // String   group description
   return this;
};   // .o.WikiTom() .constructor
WTOM  =  WSTM.o.WikiTom;



// Definition of constants
// 2012-07-14 [email protected]
WTOM.type            =  "WikiTom";
WTOM.TextOnly        =   1;
WTOM.Nowiki          =  10;
WTOM.Inline          =  11;
WTOM.CodedBlock      =  13;
WTOM.CodedInline     =  14;
WTOM.CodeBlock       =  15;
WTOM.Code            =  16;
WTOM.Comment         =  18;
WTOM.CommentOld      =  19;
WTOM.Tag             =  20;
WTOM.TagUnary        =  21;
WTOM.TagBegin        =  22;
WTOM.TagEnd          =  23;
WTOM.TagBinary       =  29;
WTOM.LinkWiki        =  31;
WTOM.LinkFile        =  32;   // link to File: even without NS
WTOM.LinkTemplate    =  33;   // link to Template: even in {{
WTOM.LinkCategory    =  34;
WTOM.LinkExtWiki     =  35;
WTOM.LinkInterWiki   =  36;
WTOM.LinkWikiPipe    =  38;
WTOM.LinkWeb         =  39;
WTOM.Template        =  41;
WTOM.TmplBrackets    =  42;
WTOM.TmplParam       =  43;
WTOM.TmplValue       =  44;
WTOM.FileParam       =  48;
WTOM.MagicWord       =  49;



WTOM.prototype.fade  =  function () {
   // Deconstruct WikiTom node
   // Postcondition:
   //    Allocated members are destroyed.
   // Uses:
   //    >- this.children
   //    >- this.source
   //    this.children.fade()
   // 2012-03-07 [email protected]
   var i;
   if (this.source) {
      delete this.source;
   }
   if (this.children) {
      for (i = 0;  i < this.children.length;  i++) {
         this.children[i].fade();
      }   // for i
      delete this.children;
   }
};   // .o.WikiTom().fade()



WTOM.prototype.fetch  =  function (assigned, ahead, alone) {
   // Access string in WikiTom
   // Precondition:
   //    assigned  -- sibling number to be accessed
   //    ahead     -- string position to start within assigned
   //                 ahead < 0  count from end
   //    alone     -- retrieve charCodeAt only
   // Postcondition:
   //    Returns  string,  or false if assigned not found
   // Uses:
   //    >  this.children
   //    >  this.source
   //    this.children.toString()
   //    mw.log()
   // 2012-07-17 [email protected]
   var j;
   var r  =  false;
   if (this.children) {
      if (assigned < this.children.length) {
         r  =  this.children[assigned].toString();
      } else {
         mw.log(WSTM.debugging,
                ".WikiTom().fetch() node beyond length " + assigned,
                3,
                this);
         r  =  "";
      }
   } else {   // plain string
      if (assigned) {
         mw.log(WSTM.debugging,
                ".WikiTom().fetch() bad node for string " + assigned,
                3,
                this);
      } else if (this.source) {
         r  =  this.source;
      } else {   // empty page
         r  =  "";
      }
   }
   if (r && ahead) {
      if (ahead < 0) {
         j  =  r.length + ahead;
         if (j > 0) {
            r  =  r.substr(j);
         }
      } else {
         r  =  r.substr(ahead);
      }
   }
   if (r && alone) {
      r  =  r.charCodeAt(0);
   }
   return r;
};   // .o.WikiTom().fetch()



WTOM.prototype.find  =  function (achieve, already, assigned, allow, alone, attached) {
   // Find term in WikiTom
   // Precondition:
   //    achieve   -- string or regexp info to be searched
   //                 regexp info:
   //                 [0]  RegExp object
   //                 [1]  bracket number
   //    already   -- string position to start
   //    assigned  -- sibling number containing already
   //    allow     -- permit inspection of children
   //    alone     -- skip after element limitation since assigned
   //    attached  -- achieve is deeper than application request
   // Postcondition:
   //    Returns  false, if achieve not found,  or found info object
   //             .i      string position of beginning
   //             .k      sibling number
   //             .m      regexp match for bracket number, if regexp
   //             .r      regexp result array, if regexp
   //             .child  object if allow and attached
   //                     .i  string position of beginning in child
   //                     .k  child number
   //                     .o  WikiTom child itself
   //    RegExp was used.
   // Uses:
   //    >  this.lookup
   //    >  this.source
   //    >  this.children
   //    >  this.limited
   //    this.children.find()   -- recursive
   // 2012-06-16 [email protected]
   var join;
   var node;
   var e;
   var i;
   var j;
   var n;
   var s;
   var r     =  false;
   if (this.lookup) {
      join  =  (typeof(already) === "number"  ?  already  :  0);
      node  =  (typeof(assigned) === "number"  ?  assigned  :  0);
      if (typeof(this.children) === "object") {
         if (allow) {
            n  =  this.children.length;
            j  =  join;
            for (i = node;  i < n;  i++) {
               e  =  this.children[i];
                r  =  e.find(achieve, j, 0, attached, false, attached);
               if (r) {
                  if (attached) {
                     r.child  =  { i: r.i,
                                   k: r.k,
                                   o: this };
                  }
                  r.k  =  i;
                  break;   // for i
               }
               if (alone) {
                  if (e.limited) {
                     break;   // for i
                  }
               }
               j  =  0;///////////////////////////
            }   // for i
         }
      } else if (! node) {   // plain string
         s  =  this.source;
         n  =  s.length;
         if (n) {
            if (join) {
               if (n > join) {
                  s  =  s.substr(join);
               } else {
                  n  =  0;
               }
            }
            if (n) {
               if (typeof(achieve) === "string") {
                  j  =  s.indexOf(achieve);
                  if (j >= 0) {
                     r  =  { i:  join + j,
                             k:  0 };
                  }
               } else {
                  j  =  s.search(achieve[0]);
                  if (j >= 0) {
                     r  =  s.match(achieve[0]);
                     r  =  { i:  join + j,
                             k:  0,
                             m:  r[ achieve[1] ],
                             r:  r };
                  }
               }
            }
         }
      }
   }
   return r;
};   // .o.WikiTom().find()



WTOM.prototype.fixTab  =  function (adjust) {
   // Remove tab chars from WikiTom, if any
   // Precondition:
   //    adjust  -- WikiTom to be changed, if necessary
   //               >  .mode
   //               >  .children
   //               >< .source
   // Postcondition:
   //    adjust is updated
   // Uses:
   //    >  this.CodedBlock
   //    this.fixTab()   -- recursive
   //    .w.chr.fixTab()
   //    this.fresh()
   // 2012-03-23 [email protected]
   var j;
   var s;
   if (adjust.mode !== WTOM.CodedBlock) {
      if (adjust.children) {
         for (j = 0;  j < adjust.children.length;  j++) {
            this.fixTab(adjust.children[j]);
         }   // for j
      } else if (adjust.source) {
         s  =  WSTM.w.chr.fixTab(adjust.source);
         if (s) {
            adjust.fresh(s);
         }
      }
   }
};   // .o.WikiTom().fixTab()



WTOM.prototype.flip  =  function (assigned, ahead, amount, apply) {
   // Exchange string in WikiTom
   // Precondition:
   //    assigned  -- sibling number containing ahead
   //    ahead     -- string position to start exchange within assigned
   //    amount    -- number of characters to remove within assigned
   //    apply     -- string to be inserted
   // Postcondition:
   //    Returns entire node string, or false
   // Uses:
   //    >  this.children
   //    >  this.limited
   //    >  this.lookup
   //    >  this.mode
   //    >< this.source
   //    this.children.toString()
   //    this.fade()
   //    this.fresh()
   //    .str.setString()
   //    mw.log()
   // 2012-04-30 [email protected]
   var p;
   var s  =  false;
   var r  =  false;
   if (this.children) {
      if (assigned < this.children.length) {
         r  =  this.children[assigned].toString();
      } else {
         s  =  "node beyond length";
      }
   } else {   // plain string
      if (assigned) {
         s  =  "bad node for string";
      } else {
         r  =  this.source;
      }
   }
   if (s) {
      mw.log(WSTM.debugging,
             ".WikiTom().flip() " + s + " " + assigned,
             3,
             this);
   } else {
      r  =  WSTM.str.setString(r, ahead, amount, apply);
      if (this.children) {
         s  =  new WSTM.o.WikiTom(r, this);
         p  =  this.children[assigned];
         s.limited  =  p.limited;
         s.lookup   =  p.lookup;
         s.mode     =  p.mode;
         this.children[assigned]  =  s;
         p.fade();
         s.fresh(false);
      } else {
         this.fresh(r);
      }
   }
   return r;
};   // .o.WikiTom().flip()



WTOM.prototype.flush  =  function (avoid) {
   // Remove one child
   // Precondition:
   //    avoid  -- child number
   // Postcondition:
   //    this has been updated
   // Uses:
   //    >  this.source
   //    >  this.children
   //    mw.log()
   // 2012-04-23 [email protected]
   var q  =  this.children;
   if (q) {
      if (avoid < q.length) {
         q.splice(avoid, 1);
      } else {
         mw.log(WSTM.debugging,
                ".WikiTom().flush() bad node for discard; r=" + avoid
                + " / " + q.length,
                3,
                this);
      }
   } else {
      mw.log(WSTM.debugging,
             ".WikiTom().flush() no child to discard; r=" + avoid,
             3,
             this);
   }
};   // .o.WikiTom().flush()



WTOM.prototype.focus  =  function (assign) {
   // Access particular child
   // Precondition:
   //    assign  -- child number
   // Postcondition:
   //    Returns WikiTom;  or  false if failed
   // Uses:
   //    >  this.children
   // 2012-03-25 [email protected]
   var r  =  false;
   if (this.children) {
      if (assign < this.children.length) {
         r  =  this.children[assign];
      }
   } else if (assign) {
      mw.log(WSTM.debugging,
             ".WikiTom().focus()  has no children",
             3,
             this);
   } else {
      r  =  this;
   }
   return r;
};   // .o.WikiTom().focus()



WTOM.prototype.fold  =  function (assign, align, append, allow) {
   // Split child with searchable string content
   // Precondition:
   //    assign  -- child number
   //    align   -- position where to split
   //    append  -- true: insert after;  false: insert before
   //    allow   -- true: permit initial string separation
   // Postcondition:
   //    Returns inserted WikiTom, even if string is empty;
   //            or  false if failed
   // Uses:
   //    >  this.source
   //    >  this.children
   //    mw.log()
   // 2012-07-07 [email protected]
   var r  =  false;
   var s;
   if (this.children) {
      if (assign < this.children.length) {
         if (align) {
            r  =  this.children[assign];
            if (r.children) {
               r  =  false;
               mw.log(WSTM.debugging,
                      ".WikiTom().fold() no string node: " + assign,
                      3,
                      this);
            } else {
               s  =  r.source;
               if (align <= s.length) {
                  if (append) {
                     r.source  =  s.substr(0, align);
                     s         =  s.substr(align);
                  } else {
                     this.children[assign].source  =  s.substr(align);
                     s         =  s.substr(0, align);
                  }
               } else {
                  r  =  false;
                  mw.log(WSTM.debugging,
                         ".WikiTom().fold() > string end: " + align,
                         3,
                         this);
               }
            }
         } else {
            s  =  "";
         }
         if (r) {
            r  =  new WSTM.o.WikiTom(s, this);
            this.children.splice((append ? assign+1 : assign),  0,  r);
            r.learnt  =  this.learnt;
         }
      } else {
         mw.log(WSTM.debugging,
                ".WikiTom().fold() invalid child number: " + assign,
                3,
                this);
      }
   } else if (allow) {
      this.children  =  [ new WSTM.o.WikiTom(this.source, this) ];
   } else {
      mw.log(WSTM.debugging,
             ".WikiTom().fold()  has no children",
             3,
             this);
   }
   return r;
};   // .o.WikiTom().fold()



WTOM.prototype.folder  =  function (ahead, assign, after, adjacent) {
   // Subdivide separated section, even over multiple children
   // Precondition:
   //    ahead     -- begin position within assign
   //    assign    -- child number of begin
   //    after     -- end position within adjacent
   //    adjacent  -- child number of end
   // Postcondition:
   //    Returns inserted WikiTom
   // Uses:
   //    >  this.source
   //    >  this.children
   //    this.fold()
   //    mw.log()
   // 2012-03-18 [email protected]
   var beg;
   var end;
   var r      =  false;
   var i;
   var later;
   var n;
   var s;
   if (this.children) {
      if (adjacent < assign  ||  adjacent > this.children.length) {
         mw.log(WSTM.debugging,
                ".WikiTom().folder() bad nodes for string; b="
                + assign + " e=" + adjacent
                + " / " + this.children.length,
                3,
                this);
      } else {
         r  =  true;
         for (i = assign;  i <= adjacent;  i++) {
            if (this.children[i].children) {
               mw.log(WSTM.debugging,
                      ".WikiTom().folder() no string: b=" + assign,
                      3,
                      this);
               r  =  false;
               break;   // for i
            }
         }   // for i
         if (r) {
            beg  =  false;
            end  =  false;
            n    =  adjacent;
            if (after) {
               r  =  this.fold(adjacent, after, false);
               if (r) {
                  end  =  r;
                  n++;
               }
            }
         }
         if (r) {
            i  =  assign;
            if (ahead) {
               r  =  this.fold(assign, ahead, true);
               if (r) {
                  beg  =  r;
                  end  =  false;
                  i++;
                  n++;
               }
            }
         }
         if (r) {
            s  =  "";
            if (end) {
               s  =  end.source;
            }
            if (i < n) {
               for (n = n-1;  n > i;  n--) {
                  s  =  this.children[i].toString() + s;
               }   // for i
               this.children.splice(i,  n - i - 1);
            }
            if (beg) {
               s  =  beg.source + s;
            }
            this.children[i].source  =  s;
            r                        =  this.children[i];
         }
      }
   } else {
      if (assign || adjacent) {
         mw.log(WSTM.debugging,
                ".WikiTom().folder() bad nodes for string b="
                + assign + " e=" + adjacent,
                3,
                this);
      } else {
         later  =  (after < this.source.length);
         n      =  (ahead ? 2 : 1)  +  (later ? 1 : 0);
         this.children  =  new Array(n);
         i              =  0;
         if (ahead) {
            s                 =  this.source.substr(0, ahead);
            this.children[0]  =  new WSTM.o.WikiTom(s, this);
            i                 =  1;
         }
         s                 =  this.source.substr(ahead,  after - ahead);
         this.children[i]  =  new WSTM.o.WikiTom(s, this);
         r                 =  this.children[i];
         if (later) {
            i++;
            s                 =  this.source.substr(after);
            this.children[i]  =  new WSTM.o.WikiTom(s, this);
         }
         if (this.learnt) {
            for (i = 0;  i < n;  i++) {
               this.children[i].learnt  =  true;
            }   // for i
         }
      }
   }
   return r;
};   // .o.WikiTom().folder()



WTOM.prototype.fork  =  function (at, advance, ancestor, assign, attach) {
   // Introduce deeper level
   // Precondition:
   //    at        -- child number of begin
   //    advance   -- child number of end;  advance >= at
   //    ancestor  -- name of family (tag etc.)
   //    assign    -- family mode
   //    attach    -- true: 'include' tag
   // Postcondition:
   //    Nodes from at until advance (including) created at parent at.
   //    Returns parent, if succeeded, else false
   // Uses:
   //    >< this.children
   //    >< this.parent
   //     < this.mode
   //     < this.scope
   //     < this.source
   //    mw.log()
   // 2012-04-14 [email protected]
   var i;
   var r  =  false;
   if (this.children) {
      r           =  new WSTM.o.WikiTom(false, this);
      r.children  =  this.children.slice(at,  advance + 1);
      r.mode      =  assign;
      r.scope     =  ancestor;
      for (i = 0;  i < r.children.length;  i++) {
         r.children[i].parent  =  r;
         if (attach) {
            r.children[i].include  =  true;
         } else {
            r.children[i][ancestor]  =  true;
         }
      }   // for i
      this.children[at]  =  r;
      if (advance > at) {
         this.children.splice(at + 1,  advance - at);
      }
      if (at) {
         delete r.source;
      }
      r.parent  =  this;
   } else {
      mw.log(WSTM.debugging, ".WikiTom().fork() no children", 3, this);
   }
   return r;
};   // .o.WikiTom().fork()



WTOM.prototype.free  =  function () {
   // Replace parents of children by this parent
   // Uses:
   //    >  this.children
   //    >  this.parent
   // 2012-04-22 [email protected]
   var e;
   var i;
   var n;
   if (this.children) {
      n  =  this.children.length;
      for (i = 0;  i < n;  i++) {
         e  =  this.children[i];
         e.free();
         e.parent  =  this;
      }   // for i
   }
};   // .o.WikiTom().free()



WTOM.prototype.fresh  =  function (apply) {
   // Mark this and above nodes as modified
   // Precondition:
   //    apply  -- optional string to be stored
   // Postcondition:
   //    nodes are marked.
   // Uses:
   //    >  this.children
   //    >  this.parent
   //     < this.source
   //     < this.learnt
   //    this.fresh()   -- recursive
   // 2012-03-23 [email protected]
   this.learnt  =  true;
   if (this.children) {
      this.source  =  false;
   } else if (apply) {
      this.source  =  apply;
   } else if (typeof(apply) === "string") {
      this.source  =  "";
   }
   if (this.parent) {
      this.parent.fresh(false);
   }
};   // .o.WikiTom().fresh()



WTOM.prototype.getCount  =  function () {
   // How many nodes?
   // Postcondition:
   //     Return current node count.
   // Uses:
   //    >  this.children
   // 2012-03-19 [email protected]
   var r  =  0;
   if (this.children) {
      r  =  this.children.length;
   }
   return r;
};   // .o.WikiTom().getCount()



WTOM.prototype.isNodeInSpan  =  function () {
   // Is this node within <include>...</include> span?
   // Postcondition:
   //    Returns true, if anode within span, else false
   // Uses:
   //    >  .w.encountered.include
   // 2012-04-06 [email protected]
   var r  =  false;
   if (WSTM.w.encountered.include) {
      r  =  (this.include ? true : false);
   }
   return r;
};   // .o.WikiTom().isNodeInSpan()



WTOM.prototype.replace  =  function (apply, assign) {
   // Precondition:
   //    apply   -- RegExp object,  or Array of replacement pairs
   //    assign  -- single replacement,  or false if replacement pairs
   // Postcondition:
   //    Nodes are modified
   // Uses:
   //    >  this.children
   //    >  this.lookup
   //    >  this.mode
   //    >  .o.WikiTom.TextOnly
   //    >< this.source
   //    this.replace()   -- recursive
   //    .util.translate.flip()
   //    this.fresh()
   // 2012-05-27 [email protected]
   var i;
   var n;
   var s;
   if (this.children) {
      n  =  this.children.length;
      for (i = 0;  i < n;  i++) {
         this.children[i].replace(apply, assign);
      }   // for i
   } else {
      if (this.lookup) {
         if (this.mode <= WTOM.TextOnly) {
            s  =  this.source;
            if (s) {
               if (typeof(assign) === "string") {
                  n  =  s.replace(apply, assign);
               } else {
                  n  =  WSTM.util.translate.flip(s, apply);
               }
               if (n !== s) {
                  this.fresh(n);
               }
            }
         }
      }
   }
};   // .o.WikiTom().replace()



WTOM.prototype.toString  =  function () {
   // Postcondition:
   //    Returns string
   // Uses:
   //    >  this.source
   //    >  this.children
   //    >  this.learnt
   //    this.toString()
   // 2012-05-16 [email protected]
   var i;
   var n;
   var p;
   var r  =  this.source;
   if (this.children) {
      if (this.learnt  ||  ! r) {
         n  =  this.children.length;
         r  =  "";
         for (i = 0;  i < this.children.length;  i++) {
            p  =  this.children[i];
            if (p) {
//             if (p.hasOwnProperty("toString")) {   /// failed
               if (p.toString) {
                  r  =  r + p.toString();
               }
            }
         }   // for i
      }
   } else if (! r) {
      r  =  "";
   }
   return r;
};   // .o.WikiTom().toString()



WTOM.prototype.trimL  =  function (any) {
   // Trim leftmost node from heading spacing charcodes of any kind
   // Precondition:
   //    any  -- true: include zero width and direction marks
   // Postcondition:
   //    Returns true, if whitespace removed
   //    leftmost node modified, if whitespace
   // Uses:
   //    >  this.source
   //    >  this.children
   //    >  .o.WikiTom().lookup
   //    >  .o.WikiTom().mode
   //    >  .o.WikiTom.TextOnly
   //    .str.trimL()
   //    this.fresh()
   // 2012-05-28 [email protected]
   var n;
   var r  =  false;
   var s  =  false;
   if (this.children) {
      n  =  this.children[0];
      if (n.lookup) {
         if (n.mode <= WTOM.TextOnly) {
            if (n.source) {
               s  =  n.source;
            }
         }
      }
   } else if (this.source) {
      s  =  this.source;
   }
   if (s) {
      s  =  WSTM.str.trimL(s, any);
      r  =  (s.length < n);
      if (r) {
         if (this.children) {
            this.children[0].fresh(s);
         } else {
            this.fresh(s);
         }
      }
   }
   return r;
};   // .o.WikiTom().trimL()



WTOM.prototype.trimR  =  function (any, also) {
   // Trim rightmost node from trailing spacing charcodes of any kind
   // Precondition:
   //    any   -- true: include zero width and direction marks
   //    also  -- true: remove also line break
   // Postcondition:
   //    Returns true, if whitespace removed
   //    rightmost node modified, if whitespace
   // Uses:
   //    >  this.source
   //    >  this.children
   //    >  .o.WikiTom().lookup
   //    >  .o.WikiTom().mode
   //    >  .o.WikiTom.TextOnly
   //    .str.trimR()
   //    .str.substrEnd()
   //    this.fresh()
   // 2012-05-28 [email protected]
   var n;
   var p;
   var r  =  false;
   var s  =  false;
   if (this.children) {
      p  =  this.children[this.children.length - 1];
      if (p.lookup) {
         if (p.mode <= WTOM.TextOnly) {
            if (p.source) {
               s  =  p.source;
            }
         }
      }
   } else if (this.source) {
      s  =  this.source;
   }
   if (s) {
      n  =  s.length;
      s  =  WSTM.str.trimR(s, any, also);
      r  =  (s.length < n);
      if (r) {
         if (this.children) {
            p.fresh(s);
         } else {
            this.fresh(s);
         }
      }
   }
   return r;
};   // .o.WikiTom().trimR()



WTOM.prototype.DEBUGparent  =  function () {
   // Replace parent objects by brief string for debugging report
   // Uses:
   //    >  this.parent
   //    >  this.children
   //    this.toString()
   // 2012-04-22 [email protected]
   var e;
   var i;
   var n;
   if (this.parent) {
      this.parent  =  this.parent.toString().substr(0, 100);
   }
   if (this.children) {
      n  =  this.children.length;
      for (i = 0;  i < n;  i++) {
         e  =  this.children[i].DEBUGparent();
      }   // for i
   }
};   // .o.WikiTom().DEBUGparent()



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



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



// 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("O",
                                       mw.libs.WikiSyntaxTextMod.o.vsn);
}
delete mw.libs.WikiSyntaxTextMod.o.vsn;



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

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