Jump to content

User:PerfektesChaos/js/WikiSyntaxTextMod/dT.js

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


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



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



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



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


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


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


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



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



mw.libs.WikiSyntaxTextMod.bb.template  =  function (WSTM) {
   // Analysis of template transclusion and variables / parser functions
   // Uses:
   //    .util.fiatObjects()
   // 2012-12-20 PerfektesChaos@de.wikipedia
   "use strict";
   WSTM.util.fiatObjects( WSTM,  "w",
                          { template:  { code: { },
                                         file: { },
                                         mod:  { },
                                         out:  { },
                                         par:  { },
                                         re:   { }
                                       }
                          } );



   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:
      //    >  .w.link.namespace.write
      //    >  .lang.translate.read
      //    >  .g.projLang
      //    >  .lang.templates.magic$.*
      //    >  .warn.template
      //    >  .warn.parserfun
      //    >  .warn.templateParamDup
      //    >< .mod.template
      //     < .w.template.space
      //     < .w.template.re.space
      //     < .w.template.sort
      //     < .w.template.show
      //     < .w.template.sisters
      //     < .w.template.re.vars
      //     < .w.template.re.funs
      //     < .w.template.re.special
      //     < .w.template.scream
      //     < .w.template.sanitize
      //     < .w.template.paramDup
      //     < .mod.luxury
      //    .lang.translate.fetch()
      //    .lang.translate.feed()
      //    .hooks.templates_sisterproj()
      //    .w.template.file.factory()
      //    .str.camelCasing()
      // 2019-08-23 PerfektesChaos@de.wikipedia
      var slang  =  WSTM.w.link.namespace.write[ "*" ].Template,
          space  =  "template",
          i, n, warn;
      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.lang.translate.fetch( "DISPLAYTITLE" );
      if ( slang ) {
         slang  =  slang.toUpperCase();
         if (this.show.indexOf( "|" + slang + "|" )  <  0) {
            this.show  =  "|" + slang + this.show;
         }
         WSTM.lang.translate.feed( this.show,
                                   "DISPLAYTITLE",
                                   "DISPLAYTITLE",
                                   WSTM.lang.translate.read,
                                   false );
      }
      this.sort  =  "|DEFAULTSORT|DEFAULTSORTKEY|DEFAULTCATEGORYSORT|";
      slang      =  WSTM.lang.translate.fetch("DEFAULTSORT");
      if ( slang ) {
         slang  =  slang.toUpperCase();
         if (this.sort.indexOf("|" + slang + "|")  <  0) {
            this.sort  =  "|" + slang + this.sort;
         }
         WSTM.lang.translate.feed( this.sort,
                                   "DEFAULTSORT",
                                   "DEFAULTSORT",
                                   WSTM.lang.translate.read,
                                   false );
      }
      this.sisters  =  WSTM.hooks.templates_sisterproj()  ||  { };
      this.re.vars  =  WSTM.lang.templates.magic$[ "*$" ];
      slang         =  WSTM.lang.templates.magic$[ 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.lang.templates.magic$["*:"];
      slang         =  WSTM.lang.templates.magic$[ 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();
      this.scream    =  false;
      this.sanitize  =  false;
      if ( WSTM.warn ) {
         warn  =  WSTM.warn.template;
         if ( warn ) {
            n = warn.length;
            if ( n ) {
               this.scream  =  "|";
               for ( i = 0;  i < n;  i++ ) {
                  this.scream  =  this.scream
                                  + WSTM.str.camelCasing( warn[ i ] )
                                  + "|";
               }   // for i
            }
         }
         warn  =  WSTM.warn.parserfun;
         if ( warn ) {
            n = warn.length;
            if ( n ) {
               this.sanitize  =  "|";
               for ( i = 0;  i < n;  i++ ) {
                  this.sanitize  =  this.sanitize + warn[i] + "|";
               }   // for i
               this.sanitize =  this.sanitize.toUpperCase();
            }
         }
      }
      if ( typeof WSTM.warn.templateParamDup  ===  "boolean" ) {
         this.paramDup  =  WSTM.warn.templateParamDup;
         if ( this.paramDup ) {
            if ( typeof WSTM.mod.template  !==  "object" ) {
               WSTM.mod.template = [ ];
            }
            WSTM.mod.luxury = true;
         }
      } else {
         this.paramDup  =  false;
      }
   };   // .w.template.factory()



   WSTM.w.template.family  =  function ( around, apply, ahead, after ) {
      // Deal with prolog and epilog strings
      // Precondition:
      //    around  -- WikiTom of template to be analyzed
      //               >< .parent
      //    apply   -- true: prolog/epilog are replacements, else match
      //    ahead   -- prolog object, or false
      //    after   -- epilog object, or false
      // Postcondition:
      //    adjust  has been modified, if apply
      //    Returns true, if apply
      // 2016-01-25 PerfektesChaos@de.wikipedia
      var r  =  false,
          brothers, i, n, post, pre;
      if ( typeof around.parent  ===  "object"
           &&     around.parent   &&
           typeof around.parent.children  ===  "object" ) {
         brothers  =  around.parent.children;
         n         =  brothers.length;
         for ( i = 0;  i < n;  i++ ) {
            if ( brothers[ i ] === around ) {
               if ( i ) {
                  pre  =  brothers[ i - 1 ];
               }
               n--;
               if ( i <  n) {
                  post  =  brothers[ n ];
               }
               break;   // for i
            }
         }   // for i
      }
      if ( ahead && pre ) {
         if ( typeof pre.source  !==  "string" ) {
            pre  =  false;
         }
      }
      if ( after && post ) {
         if ( typeof post.source  !==  "string" ) {
            post  =  false;
         }
      }
      if ( apply ) {
         if ( ahead && pre ) {
            pre.source.replace( ahead[ 0 ], ahead[ 1 ] );
            pre.fresh();
         }
         if ( after  &&  post  &&  after[ 0 ].test( post.source ) ) {
//            post.source.replace(after[0], after[1]);
            post.fresh( post.source.replace( after[ 0 ],  after[ 1 ] ) );
         }
      } else if ( ( ! ahead  ||  pre )   &&   ( ! after  ||  post) ) {
         r  =  true;
         if ( ahead  &&  ! ahead[ 0 ].test( pre.source ) ) {
            r  =  false;
         }
         if ( r  &&  after  &&  ! after[ 0 ].test( post.source ) ) {
            r  =  false;
         }
      }
      return  r;
   };   // .w.template.family()



   WSTM.w.template.feature  =  function ( adjust, assign, about ) {
      // Analyze and split template parameter and its value
      // Precondition:
      //    adjust  -- WikiTom of template to be analyzed and subdivided
      //               >< .noname
      //    assign  -- start node in adjust
      //    about   -- template name
      //    Links (wikilink pipes) and nested templates already separated
      // Postcondition:
      //    adjust  has been subdivided, if necessary
      //    Returns assignment information
      //            .br       found terminated with \n
      //            .brB      found \n between '|' and parameter name
      //            .brH      found \n between '=' and parameter value
      //            .brP      found \n between parameter name and '='
      //            .indent   number of spaces before parameter name
      //            .keep     number of chars before '='
      //            .lazy     unnamed parameter
      //            .leap     space after pipe
      //            .lined    (begin parameter assignment on new line)
      //            .location .lazy without assignment
      //            .proceed  {.i, .k, .loop}  or  false
      //            .symbol   parameter name
      //            .value
      // Uses:
      //    >  .w.template.re.featureAssign
      //    >  .w.template.re.featureEmpty
      //    >  .o.WikiTom.TmplParAssign
      //    >  .o.WikiTom.TmplParValue
      //     < .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()
      //    .w.elem.isbn.fire()
      //    .o.WikiTom()
      //    .hooks.fire()
      //    .errors.found()
      //    .str.trimL()
      // Requires: JavaScript 1.3   charCodeAt()
      // 2020-01-21 PerfektesChaos@de.wikipedia
      var j    =  1,
          r    =  { proceed: false,
                    value:   false },
          s    =  adjust.fetch( assign, 0, false ),
          got,
          i,
          k,
          n;
      s  =  s.substr( j );
      if ( s.charCodeAt( 0 ) === 10 ) {   // '\n'
         r.brB    =  true;
         r.lined  =  true;
         s        =  s.substr( 1 );
         j++;
         adjust.learnt  =  true;
      }
      got  =  this.re.featureEmpty.exec( "\f" + s );
      if ( got ) {
         s    =  got[ 1 ];
         got  =  false;
      } else {
         got  =  this.re.featureAssign.exec( "\f" + s );
      }
      if ( got ) {   // named parameter
         n  =  got[ 0 ].length - 1;
         if ( got[ 1 ] ) {
            r.leap  =  true;
         }
         r.symbol  =  got[ 2 ];
         if ( got[ 5 ] ) {
            r.brP     =  true;
            r.lined   =  true;
            r.indent  =  got[ 1 ].length;
         }
         if ( got[ 4 ] ) {
            r.keep  =  got[ 4 ].length;
         } else {
            r.keep  =  0;
         }
         /*
         OTHER BEHAVIOUR OF MEDIAWIKI
         r.lazy  =  /^[1-9][0-9]*$/.test(r.symbol);
         if (r.lazy) {
            if (parseInt(r.symbol)  ===  adjust.noname + 1) {
               adjust.noname++;
            }
         }
         */
         j  +=  n;
      } else {   // no-name parameter
         adjust.noname++;
         r.indent    =  0;
         r.lazy      =  true;
         r.location  =  true;
         r.symbol    =  WSTM.str.fromNum( adjust.noname );
         r.value     =  new WSTM.o.WikiTom( s, adjust );
      }
      if ( j ) {
         got  =  adjust.folder( 0, assign, j, assign );
      }
      if ( got ) {
         got.mode    =  WSTM.o.WikiTom.TmplParAssign;
         got.lookup  =  false;
         i           =  assign + 1;
         r.proceed   =  { i: 0,  k: i + 1 };
         got         =  this.featured( adjust, assign );
         if ( got ) {
            k               =  got.k;
            r.proceed.i     =  got.i + 1;
            r.proceed.loop  =  true;
         } else {
            got  =  adjust.find( "}}", 0, i, true, false, false );
            if ( got ) {
               s  =  adjust.fetch( r.proceed.k - 1,  0,  false );
               k  =  s.lastIndexOf( "\n" );
               if ( k >= 0 ) {
                  r.margin  =  s.length - k - 1;
               }
               k  =  got.k;
               if ( ! got.i ) {
                  r.proceed.k  =  i;
               }
            } else {
               mw.log( WSTM.debugging, ".w.template.feature() }}", 2 );
            }
         }
         if ( got ) {
            if ( ! got.i ) {
               if ( got.child ) {
                  r.value  =  got.child.o;
               } else if ( k === i ) {
                  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;
                  k++;
               }
            }
            if ( k - 1  >  i ) {
               r.value  =  adjust.fork( i,
                                        k - 1,
                                        "value",
                                        WSTM.o.WikiTom.TmplParValue,
                                        false );
               if ( typeof r.value.children  ===  "object"   &&
                    typeof r.value.children[ 0 ].source  ===  "string"
                  ) {
                  s  =  r.value.children[ 0 ].source;
                  // TODO   later 2020  .feature()
                  if ( s.charCodeAt( 0 )  ===  32 ) {
                     s  =  WSTM.str.trimL( s, true, false );
                     if ( s.charCodeAt( 0 )  ===  10 ) {
                        r.value.children[ 0 ].source  =  s;
                     } else {
                        r.value.children[ 0 ].later  =  true;
                     }
                  }
               }
               WSTM.w.elem.isbn.fire( r.value, false );
            } 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   &&
           typeof r.value.source  ===  "string"   &&
           typeof r.value.source ) {
        s  =  WSTM.str.trimL( r.value.source, false );
        if ( s.charCodeAt( 0 ) === 61   &&
             s.length > 1   &&
             ! WSTM.hooks.fire( "valEqualsign", about ) ) {
           WSTM.errors.found( "templateParStart=",
                              false,
                              "{{" + about + "}} "
                              +  s.substr( 0, 50 ) );
         }
      }
      return  r;
   };   // .w.template.feature()



   WSTM.w.template.featured  =  function ( adjust, assign ) {
      // Analyze and split template parameter with wikilink
      // Precondition:
      //    adjust  -- WikiTom of template content
      //    assign  -- start node in adjust
      // Postcondition:
      //    adjust  has been subdivided, if necessary
      //    Returns position object, { .k, .i }
      // Uses:
      //    .o.WikiTom().find()
      //    .o.WikiTom().fetch()
      //    .w.link.web.fetch()
      //    .w.link.fence()
      //    .o.WikiTom().fold()
      //    .w.link.fire()
      // 2019-12-10 PerfektesChaos@de.wikipedia
      var i     =  0,
          k     =  assign,
          open  =  true,
          close, r, seek, url;
      do {
         r  =  adjust.find( "|", i, k, true, false, false );
         if ( r ) {
            open  =  adjust.find( "[", 0, r.k, true, false, false );
            if ( open ) {
               if ( open.k === r.k  &&  open.i < r.i ) {
                  seek  =  adjust.fetch( r.k,  open.i + 1,  true );
                  if ( seek === 91 ) {
                     seek  =  "]]";
                  } else {
                     url  =  { limited:  false,
                               source:   adjust.fetch( r.k,
                                                       open.i + 1,
                                                       false ),
                               index:    0,
                               multiple: 0 };
                     url  =  WSTM.w.link.web.fetch( url );
                     if ( url && url.multiple ) {
                        seek  =  "]";
                     } else {
                        open  =  false;
                     }
                  }
                  if ( open ) {
                     close  =  adjust.find( seek,
                                            r.i + 1,
                                            r.k,
                                            true,
                                            false,
                                            false );
                     if ( close ) {
                        if ( close.k === r.k ) {
                           close  =  adjust.fold( r.k, close.i, false );
                           if ( close ) {
                              k = r.k + 1;
                              i = 0;
                              WSTM.w.link.fire( close,
                                                { k: 0, i: 0 } );
                           } else {
                              open  =  false;
                           }
                        } else {
                           open  =  false;
                        }
                     } else {
                        open  =  false;
                     }
                  }
               } else {
                  open  =  false;
               }
            }
         }
      } while ( r && open );
      return  r;
   };   // .w.template.featured()



   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
      //             < .noname  -- number of unnamed parameters
      //             < .values  -- Array;   i=0: Title
      //                               < [i].symbol
      //                               < [i].value
      // Uses:
      //    >  .o.WikiTom().mode
      //    >  .o.WikiTom.LinkFile
      //    >  .o.WikiTom.LinkWikiPipe
      //    >  .o.WikiTom.FileParam
      //    >  .o.WikiTom.Comment
      //    >  .w.template.paramDup
      //    >  .o.WikiTom.TmplBrackets
      //    >  .o.WikiTom.TmplParName
      //    >< .w.template.re.featureAssign
      //    >  .w.template.re.featureEmpty
      //     < .o.WikiTom().mode
      //     < .o.WikiTom().lookup
      //     < .mod.lazy
      //    .o.WikiTom().focus()
      //    .w.template.featured()
      //    .w.link.wiki.linked()
      //    .o.WikiTom().fetch()
      //    .str.trim()
      //    .o.WikiTom().fold()
      //    .o.WikiTom().find()
      //    .w.template.feature()
      //    .w.template.par.fetch()
      //    .hooks.fire()
      //    .errors.found()
      //    .w.template.isbn()
      //    .o.WikiTom().fresh()
      // Requires: JavaScript 1.3   charCodeAt()
      // 2020-01-21 PerfektesChaos@de.wikipedia
      var lapsus  =  false,
          lead    =  true,
          lock    =  false,
          n       =  adjust.children.length,
          s       =  false,
          tmpl    =  false,
          got,
          i,
          j,
          k,
          p,
          s1, s2,
          story;
      if ( ! this.re.featureAssign ) {
         this.re.featureAssign  =  new RegExp( "\f([ \n]*)"
                                              + "([^ \n<|=]"
                                               + "([^\n<|=]*[^ \n<|=])?)"
                                              + "( *"
                                               + "(\n)? *)=" );
         this.re.featureEmpty   =  new RegExp( "\f([ \n]*)\\|" );
      }
      adjust.noname  =  0;
      for ( k = n - 1;  k > 1;  k-- ) {
         p  =  adjust.focus( k );
         if ( p ) {
            if ( WSTM.w.link.wiki.linked( p ) ) {
               if ( adjust.fetch( k + 1,  0,  true )   ===   124 ) {
                  // '|'
                  j  =  1;
                  if ( p.mode === WSTM.o.WikiTom.LinkFile ) {
                     got  =  adjust.fetch( k + 1,  0,  false );
                     j    =  got.indexOf( "]" );
                     if ( j > 0 ) {
                        got  =  got.substr( 0, j );
                     }
                     j  =  got.lastIndexOf( "|" )  +  1;
                  }
                  got  =  adjust.fold( k + 1,  j,  false );
                  if ( got ) {
                     got.mode    =  ( j === 1
                                      ?  WSTM.o.WikiTom.LinkWikiPipe
                                      :  WSTM.o.WikiTom.FileParam );
                     got.lookup  =  false;
                  }
               }
            } else if ( typeof p.source  ===  "string"
                        &&     p.source.substr( 0, 4 )  ===  "<!--" ) {
               s  =  p.source;
               j  =  s.indexOf( "-->" );
               if ( j + 3  ===  s.length ) {
                  p.mode  =  WSTM.o.WikiTom.Comment;
               } else if ( j > 4 ) {
                  mw.log( WSTM.debugging,
                          ".w.template.feature() SPLIT",
                          2 );
               } else {
                  mw.log( WSTM.debugging,
                          ".w.template.feature() <!--",
                          2 );
               }
            }
         }
      }   // 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 );
         }
      }
      j  =  0;
      k  =  2;
      p  =  adjust.focus( 2 );
      if ( p ) {
         if ( p.mode === WSTM.o.WikiTom.Comment ) {
            k  =  3;
         } else {
             // while ... LRR   k++;
             //   Liste der Radrouten in Sachsen
             if ( p.toString().indexOf( "|" )  <  0 ) {
               p  =  adjust.focus( 3 );
               if ( p.mode === WSTM.o.WikiTom.Comment ) {
                  k  =  4;
               }
            }
         }
      }
      do {
         got  =  adjust.find( "|", j, k, true, false, false );
         if ( got ) {
            if ( lead ) {
               p  =  { joint: 0 };
               if ( got.i ) {
                  s  =  adjust.fold( got.k,  got.i,  false );
                  if (s) {
                     s        =  adjust.fetch( got.k, 0, false );
                     j        =  s.lastIndexOf( "\n" );
                     p.br     =  ( j >= 0 );
                     p.joint  =  ( p.br  ?  got.i - j - 1  :  got.i );
                     got.i    =  0;
                     got.k++;
                  }
               }
               if ( k > 2 ) {
                  if ( k === 4 ) {
                     p.commentnewline  =  true;
                  }
                  p.comment  =  adjust.focus( k - 1 );
               }
               tmpl  =  [ p ];
               lead  =  false;
            }
            j    =  got.i + 1;
            k    =  got.k;
            got  =  this.feature( adjust, k, story, got.i );
            if ( got ) {
               if ( got.symbol && got.value ) {
                  if ( got.symbol.length <= 5 ) {
                     p  =  got.symbol.toLowerCase();
                     switch ( p ) {
                        case "isbn" :
                        case "isbn2" :
                        case "isbn3" :
                        case "isbn4" :
                        case "isbn5" :
                           this.isbn( got, adjust );
                           break;
                        case "doi" :
                        case "issn" :
                        case "pmid" :
                           s  =  this.par.fetch( got );
                           if ( s ) {
                              p  =  WSTM.hooks.fire( p,
                                                     [ WSTM.str.trim(s),
                                                       false ] );
                              if ( p ) {
                                 if ( s !== WSTM.str.trimL( s ) ) {
                                    p  =  " " + p;
                                 }
                                 if ( p !== s ) {
                                    got.value.fresh( p );
                                    adjust.fresh( false );
                                 }
                              }
                           }
                           break;
                     }   // switch
                  }
               }
               if ( tmpl ) {
                  if ( this.paramDup ) {
                     for ( i = 1;  i < tmpl.length; i++ ) {
                        p  = tmpl[ i ];
                        if ( got.symbol === p.symbol ) {
                           lapsus  =  true;
                           s1      =  p.value.toString();
                           s2      =  got.value.toString();
                           s1      =  WSTM.str.trim( s1, true, true );
                           s2      =  WSTM.str.trim( s2, true, true );
                           s       =  "|" + p.symbol + "=";
                           s       =  "{{" + story + s + s1
                                                   + s + s2 + "}}";
                           lock    =  (s1 === s2);
                           if ( lock ) {
                              // remove on ===
                           } else if ( s1 === "" ) {
                              tmpl[ i ]  =  got;
                              lock     =  true;
                           }
                           WSTM.errors.found( "templateParDup",
                                              lock,
                                              s );
                        }
                        if ( p.br ) {
                           adjust.learnt  =  true;
                        }
                     }   // for i
                  }
                  if ( lock ) {
                     lock           =  false;
                     adjust.learnt  =  true;
                     WSTM.mod.lazy  =  false;
                  } else {
                     tmpl.push( got );
                  }
               } else {
                  tmpl  =  [ got ];
               }
               p  =  got.proceed;
               if ( p ) {
                  k++;
                  j  =  0;
                  p  =  p.loop;
               }
               delete got.parent;
               delete got.proceed;
               got  =  p;
            }
         }
      } while ( got );   // do
      if ( tmpl ) {
         n  =  tmpl.length;
         if ( n > 1 ) {
            tmpl[ 1 ].lined   =  ( tmpl[ 0 ].br  ?  true  :  false );
            tmpl[ 1 ].indent  =  tmpl[ 0 ].joint;
            adjust.linebreak  =  tmpl[ n - 1 ].br;
         }
         if ( story ) {
            tmpl[ 0 ].symbol  =  story;
         }
         //  .margin
      } else if ( typeof adjust.children  ===  "object" ) {
         n  =  story.lastIndexOf( "}}" );
         k  =  adjust.children.length - 1;
         if ( k >= 1  &&  n > 0 ) {
            j      =  story.length - n - 2;
            story  =  story.substr( 0, n );
            story  =  WSTM.str.trimR( story, true, true );
            if ( story ) {
               p  =  adjust.fold( k, n, true );
               if ( j ) {
                  adjust.fold( k + 1, 2, true );
               }
               p.mode  =  WSTM.o.WikiTom.TmplBrackets;
               p       =  adjust.focus( k );
               p.mode  =  WSTM.o.WikiTom.TmplParName;
               tmpl    =  [ { symbol: story } ];
               adjust.children[ k ].source  =  story;
            } else {
               lapsus  =  true;
            }
         } else {
            tmpl  =  [ { symbol: story } ];
            if ( k > 2 ) {
               p  =  adjust.focus( 2 );
               if ( p ) {
                  if ( p.mode === WSTM.o.WikiTom.Comment ) {
                     tmpl[ 0 ].comment  =  p.source;
                  } else if ( k > 3 ) {
                     p  =  adjust.focus( 3 );
                     if ( p   &&
                          p.mode === WSTM.o.WikiTom.Comment ) {
                        tmpl[ 0 ].comment  =  p.source;
                        p  =  adjust.focus( 2 );
                        if ( typeof p.source  ===  "string"
                             &&     p.source  ===  "\n" ) {
                           tmpl[ 0 ].commentnewline  =  true;
                        }
                     }
                  }
               }
            }
         }
      } else {
         lapsus  =  true;
      }
      if ( ! tmpl ) {
         tmpl  =  [ ];
         tmpl.push( false );
      }
      adjust.values  =  tmpl;
      if ( lapsus ) {
         mw.log( WSTM.debugging,
                 ".w.template.features() {{" + story + "}}",
                 2,
                 tmpl );
      } else {
         p  =  adjust.focus( 0 );
         p.mode  =  WSTM.o.WikiTom.TmplBrackets;
      }
   };   // .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 PerfektesChaos@de.wikipedia
      var re;
      if (! WSTM.mod.luxury) {
         re  =  new RegExp("\\|[ \n]*isbn[ \n]*=",  "i");
         if (WSTM.text.find([re, 0],  0,  0,  true,  false,  false)) {
            WSTM.w.encountered.isbn  =  true;
         }
      }
   };   // .w.template.findISBN()



   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()
      // 2015-03-08 PerfektesChaos@de.wikipedia
      var i     =  0,
          k     =  0,
          deep,
          got;
      if ( activate ) {
         this.factory();
      }
      do {
         got  =  all.find( "{{", i, k, true, false, false );
         if ( got ) {
            deep  =  got.child;
            if ( 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.TmplParAccess
      //    >  .o.WikiTom.TmplParValue
      //    >  .mod.luxury
      //    >  .w.encountered.indent
      //    >  .w.encountered.isbn
      //    >  .w.template.paramDup
      //    >  .o.WikiTom.Template
      //    >  .mod.wikilink
      //    >  .mod.plain
      //    >< .w.template.templates
      //    .o.WikiTom().fetch()
      //    .o.WikiTom().fold()
      //    .o.WikiTom().focus()
      //    .o.WikiTom().find()
      //    .w.template.fire()   -- recursive (indirect)
      //    .w.template.flat()
      //    .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()
      //    .w.template.mod.format()
      //    .str.substrEnd()
      //    .errors.found()
      // 2021-04-05 PerfektesChaos@de.wikipedia
      var behind  =  false,
          div     =  false,
          end     =  false,
          low     =  ( all.fetch( appoint.k,  appoint.i + 2,  true )
                       ===   123 ),   // '{'
          got     =  { i:  appoint.i,
                       k:  appoint.k },
          move    =  (low ? 3 : 2),
          node    =  got.k,
          r       =  { i:  got.i,
                       k:  got.k },
          scan    =  ( low ? "{{{" : "{{" ),
          seek    =  ( low ? "}}}" : "}}" ),
          i,
          tbeg,
          tend;
      if ( appoint.i ) {
         tbeg  =  all.fold( appoint.k, appoint.i, false, false );
         r.i   =  0;
         r.k++;
         node++;
      } else {
         if ( adjacent ) {
            end   =  { i: adjacent.i,  k: adjacent.k };
         }
         tbeg  =  all.focus( appoint.k );
      }
      if ( tbeg ) {
         do {
            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 );
            if ( behind && got ) {   // inner?
               if ( got.k < behind.k     ||
                    ( got.k === behind.k  &&  got.i < behind.i ) ) {
                  got  =  this.fold( got, behind, all );   // recursive
                  if ( got ) {
                     r  =  got;
                  } else {
                     end  =  false;
                  }
               } else {
                  end  =  behind;
                  got  =  false;
               }
            } else {
               end  =  behind;
               got  =  false;
            }
         } while ( got );   // do
         if ( end ) {
            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
            }
            if ( low ) {
               all.fork( r.k,
                         end.k,
                         "Parameter",
                         WSTM.o.WikiTom.TmplParAccess,
                         false );
            } else {
               div  =  this.format( node, end.k, all );
               if ( tend && div ) {
                  if ( node > appoint.k ) {
                     tbeg  =  all.focus( node );
                  }
                  tbeg.scope  =  div.sore;
                  tbeg.mode   =  div.mode;
                  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                    ||
                       this.paramDup ) {
                     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                  ||
                                this.paramDup ) {
                              if ( WSTM.mod.wikilink ) {
                                 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.paramDup ) {
                                 this.features( got );        // 1.
                                 this.file.featured( got );   // 2.
                                 switch ( typeof div.hook ) {
                                    case "function" :
                                       div.hook( got );
                                       break;
                                    case "object" :
                                       for ( i = 0;
                                             i < div.hook.length;
                                             i++ ) {
                                          div.hook[ i ]( got );
                                       }   // for i
                                       break;
                                 }
                                 if ( div.mod ) {
                                    this.mod.fire( got );
                                    // //////////////////////////////////
                                    // prolog epilog
                                 }
                                 if ( WSTM.mod.plain ) {
                                    this.mod.flat( got );
                                 }
                                 if ( got.learnt  &&
                                      got.children  &&
                                      got.mode ===
                                              WSTM.o.WikiTom.Template ) {
                                    this.mod.format( got );
                                 }
                              } else {
                                 this.file.full( got );
                              }
                           }
                        }
                        end.k  =  node;
                     }
                  }
               }
               if (end.k) {
                  r  =  { i:  0,
                          k:  end.k };
               } else {
                  r  =  { i:  2,
                          k:  0 };
               }
            }
         } 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);  +  " ...";
*/
               }
               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 item 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.sanitize
      //    >  .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.sisters
      //    >  .mod.plain
      //    >  .o.WikiTom.Comment
      //    >  .o.WikiTom.MagicWord
      //    >  .w.template.scream
      //    >  .mod.luxury
      //    >  .w.encountered.isbn
      //    >  .mod.wikilink
      //    >  .mod.template
      //    >  .o.WikiTom.LinkTemplate
      //    >  .o.WikiTom.Sortkey
      //    >< .w.template.re.value
      //     < .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()
      //    .warn.found()
      //    .errors.found()
      //    .str.trim()
      //    .o.WikiTom().focus()
      //    .w.link.wiki.decode()
      //    .str.camelCasing()
      //    .util.code.doi()
      //    .util.code.issn()
      //    .util.code.pmid()
      //    .util.code.viaf()
      //    .hooks.fire()
      //    .o.WikiTom().fresh()
      //    .w.template.mod.find()
      //    .w.link.replace.flipper()
      //    .o.WikiTom().fold()
      //    .o.WikiTom().focus()
      //    (.w.template.sister)
      // 2019-10-26 PerfektesChaos@de.wikipedia
      var immune  =  0,
          later   =  false,   //   line break to be inserted behind
          lead    =  false,   //   line break ahead to be inserted
          leap    =  false,   //   string changed
          learn   =  false,   //   update element
          leave   =  false,   //   discard element
          lock    =  false,   //   no lookup
          low     =  false,   //   variable or parser function
          lone    =  false,   //   single line
//        lost    =  false,   //   pipe directly after template name
          mode    =  WSTM.o.WikiTom.Template,
          r       =  { joint: advance,
                       scope: "template" },
          scope   =  r.scope,
          slice   =  "",
          space   =  "",
          store   =  all.fetch( at, 2, false ),
          stuff   =  false,   //   really template
          suffix  =  false,
          shift   =  WSTM.str.trimL( store, false ),
          i       =  shift.indexOf( ":" ),
          moved   =  store.length - shift.length,
          got, indent, k, scan, sub, symbol;
      low  =  ( shift.charCodeAt( 0 ) === 35 );   // '#'
      if ( low ) {
         r.mode  =  WSTM.o.WikiTom.ParserFun;
         r.sore  =  shift.substr( 0, i ).toUpperCase();
         if ( this.sanitize  &&  i > 0 ) {
            scan  =  "|" + r.sore + "|";
            if ( this.sanitize.indexOf( scan ) >= 0 ) {
               WSTM.warn.found( "function",
                                "{{" + sub.toLowerCase() + "}}" );
            }
         }
      } else {
         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";
                           mode    =  WSTM.o.WikiTom.Sortkey;
                           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;
                        }
                     }
                  }
                  if ( this.sanitize ) {
                     scan  =  "|" + sub.toUpperCase() + "|";
                     if ( this.sanitize.indexOf( scan ) >= 0 ) {
                        WSTM.warn.found( "function",
                                         "{{"
                                         + sub.toLowerCase() + ":}}" );
                     }
                  }
               } 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;
               }
            } else {
               shift  =  WSTM.str.trim( shift, false, false );
               if ( shift.length ) {
                  got  =  all.focus( at + 1 );
                  if (got) {
                     if ( got.mode === WSTM.o.WikiTom.Comment ) {
                        stuff  =  shift;
                     }
                  }
               }
               shift  =  "{{" + shift;
            }
         }
      }
      if ( low ) {
         if ( r.mode === WSTM.o.WikiTom.Template ) {
            r.mode  =  WSTM.o.WikiTom.MagicWord;
         }
         mode     =  r.mode;
         r.scope  =  "magicword";
         r.joint  =  advance;
         if ( shift ) {
            shift  =  "{{" + shift;
         }
         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 ( this.scream ) {
            if (low) {
               scan  =  symbol.toLowerCase();
            } else {
               scan  =  WSTM.str.camelCasing( symbol );
            }
            if ( this.scream.indexOf( "|" + scan + "|" )  >=  0 ) {
               WSTM.warn.found( "template",  "{{" + symbol + "}}" );
            }
         }
         if ( WSTM.g.wNsNumber !== 10 ) {   //   g.nsTemplate
            sub   =  symbol.toLowerCase();
            scan  =  "|" + sub + "|";
            if ( suffix ) {
               if ( "|doi|issn|pmid|viaf|".indexOf( scan )  >=  0 ) {
                  if ( ! this.re.value ) {
                     this.re.value  =  "^ *([^|}\n]+) *(\\||\\}\\})$";
                     this.re.value  =  new RegExp(this.re.value);
                  }
                  got  =  this.re.value.exec( suffix );
                  if (got) {
                     scan  =  WSTM.util.code[sub]( got[ 1 ],  true );
                     if ( scan ) {
                        switch ( typeof scan ) {
                           case "string" :
                              suffix  =  scan + got[ 2 ];
                              learn   =  true;
                              break;
                           case "object" :
                              WSTM.errors.found( "templateParInvalid",
                                                 false,
                                                 "{{" + symbol + "}} "
                                                 + scan[ 1 ] + "\n"
                                                 + got[ 1 ] );
                              break;
                        }   // switch typeof sub
                     }
                  }
               }
            }
            sub  =  sub.substr( 0, 1 ).toUpperCase()  +
                    sub.substr( 1 );
            if ( typeof this.sisters[ sub ]  ===  "object" ) {
               space  =  "";
               k      =  "*{{}}";
               if ( at  &&
                    typeof this.sisters[ sub ][ k ]  ===  "boolean"
                    &&   ! this.sisters[ sub ][ k ] ) {
                  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 );
                           }
                        }
                     }
                  }
               }
               r.hook  =  this.sister;
               lone    =  true;
            }
         }
         got  =  WSTM.hooks.fire( "template",
                                  [ symbol, at, advance, all ] );
         if ( got ) {
            if ( symbol !== got[ 0 ] ) {
               if ( symbol.substr( 2 )  !==  got[ 0 ].substr( 2 ) ) {
                  WSTM.mod.lazy  =  false;
               } else if (symbol.substr( 0, 1 ).toLowerCase()  !==
                          got[ 0 ].substr( 0, 1 ).toLowerCase()) {
                  WSTM.mod.lazy  =  false;
               }
            }
            symbol  =  got[ 0 ];
            lone    =  ( lone  ||  got[ 1 ] );
            if ( got[ 2 ] ) {
               switch ( typeof r.hook ) {
                  case "function" :
                     r.hook  =  [ r.hook ];   // fall through
                  case "object" :
                     r.hook.push( got[ 2 ] );
                     break;
                  default:
                     r.hook  =  got[ 2 ];
               }   // switch typeof r.hook
            }
         }
         if ( suffix ) {
            if ( suffix === "}}" ) {
               shift  =  symbol + "}}";
            } else {
               shift  =  symbol + slice + space + "|" + suffix;
            }
         } else if ( at === advance ) {
            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 || later );
      }
      learn  =  ( learn || lead || leave );
      if ( !  ( immune || low ) ) {
         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 {
                     got  =  all.focus(at);
                     if ( got ) {
                        if ( shift.substr( 0, 2 )  !==  "{{" ) {
                           shift  =  "{{" + shift;
                        }
                        got.fresh( shift );
                     }
                  }
                  all.fresh( false );
               } else if ( lead || later ) {
                  if (lead && at) {
                     i  =  all.fetch( at - 1, -1, true );
                     if ( i  &&  i !== 10 ) {
                        got  =  all.focus(at - 1);
                        if (got) {
                           shift  =  all.fetch( at - 1 );
                           got.fresh( shift + "\n" );
                        }
                     }
                  }
                  if ( later && advance ) {
                     i  =  all.fetch( advance + 1,  0,  true );
                     if (i  &&  i !== 10) {
                        got  =  all.focus( advance + 1 );
                        if (got) {
                           shift  =  all.fetch( advance + 1 );
                           shift  =  WSTM.str.trimL( shift, false );
                           i      =  shift.charCodeAt(0);
                           if (i === 35  ||
                               i === 42  ||
                               i === 58  ||
                               i === 59) {
                              shift  =  "<nowiki /> " + shift;
                           }
                           got.fresh( "\n" + shift );
                           WSTM.mod.lazy  =  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.wikilink ) {
                        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 )  ===  "}}" ) {
                  i  =  got.length - 2;
                  if ( i ) {
                     got  =  all.fold( advance, i, false );
                     if ( got ) {
                        r.joint++;
                     }
                  }
               }
            }
         }
         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++;
                  }
                  moved  =  0;
               }
            }
         }
         if ( indent + moved ) {
            if ( indent ) {
//             got  =  all.fold( at,  indent + moved,  true );// BEFORE
               got  =  all.fold( at,  indent,  true );
            } else {
               got  =  all.focus( at );
            }
            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.isbn  =  function (assigned, adjust) {
      // Format value of an ISBN= template parameter
      // Precondition:
      //    assigned  -- parameter object of ISBN=
      //    adjust    -- WikiTom of template to analyze and subdivide
      // Uses:
      //    .w.template.par.fetch()
      //    .str.trim()
      //    .util.code.isbn()
      //    .str.trimL()
      //    .str.trimR()
      //    .o.WikiTom().fresh()
      // 2013-10-12 PerfektesChaos@de.wikipedia
      var k,
          n,
          p,
          s,
          story,
          shift;
      story  =  this.par.fetch( assigned );
      if ( typeof story  ===  "string" ) {
         shift  =  WSTM.str.trim( story, true, true );
         if ( shift.length > 8 ) {
            p  =  WSTM.util.code.isbn(shift);
            if ( p[0] && p[1] ) {
               n  =  story.length;
               s  =  WSTM.str.trimL( story, true, true );
               if (s.length < n) {
                  p[1]  =  " " + p[1];
               }
               if ( shift.length > p[0] ) {
                  p[1]  =  p[1]  +  shift.substr(p[0]);
               }
               s  =  WSTM.str.trimR( story, true, true );
               k  =  s.length;
               if ( k < n ) {
                  p[1]  =  p[1] + story.substr(k);
               }
               assigned.value.fresh(p[1]);
               adjust.fresh(false);
            }
         }
      }
   };   // .w.template.isbn()



   WSTM.w.template.sister  =  function ( adjust ) {
      // Protect sister project link in standard template (.hook)
      // Precondition:
      //    adjust  -- WikiTom sequence (forked element)
      // Uses:
      //    >  .w.template.sisters
      //    >  .g.projLang
      //    >  .mod.wikilink
      //    >  .w.link.namespace.nsCategory
      //    >  .o.WikiTom.LinkExtWiki
      //    >  .o.WikiTom.
      //    .str.camelCasing()
      //    .w.template.par.find()
      //    .w.link.wiki.decode()
      //    .str.trimL()
      //    .errors.found()
      //    .str.trim()
      //    .util.code.lang()
      //    .w.template.mod.flush()
      //    .w.link.namespace.furnish()
      //    .w.template.par.fiat()
      //    .w.template.mod.furnish()
      //    .hooks.fire()
      //    .o.WikiTom().fresh()
      // Remark: May be used as event handler -- 'this' is not accessed
      // 2020-02-07 PerfektesChaos@de.wikipedia
      var configs  =  WSTM.w.template.sisters,
          stamp    =  WSTM.str.camelCasing( adjust.values[ 0 ].symbol ),
          config   =  configs[ stamp ],
          e, elang, got, low, ns, re, s, store, slang, slot, spc;
      for ( s in config ) {
         spc  =  config[ s ];
         if ( spc === "page"  ||
              spc === "pageCase" ) {
            e  =  WSTM.w.template.par.find( adjust, s );
            if ( e ) {
               if ( typeof e.value  ===  "object"
                    &&     e.value   &&
                    ! e.mode   &&
                    typeof e.value.source  ===  "string" ) {
                  store  =  e.value.source;
                  got    =  WSTM.w.link.wiki.decode( store,
                                                     true,
                                                     false,
                                                     true,
                                                     true );
                  if ( got ) {
                     store  =  got;
                  }
                  e.value.lookup  =  false;
                  s               =  stamp + ":cat";
                  if ( store.substr( 1, 8 ) ===  "ategory:"   &&
                       ( store.substr( 0, 1 ) === "C"  ||
                         store.substr( 0, 1 ) === "c" )   &&
                       typeof configs[ s ]  ===  "string" ) {
                     store   =  WSTM.str.camelCasing(
                                       WSTM.str.trimL( store.substr( 9 ),
                                                       true ) );
                     stamp   =  configs[ s ];
                     config  =  configs[ stamp ];
                  } else {
                     low  =  ( spc === "pageCase" );
                  }
               } else {
                  WSTM.errors.found( "templateParDubious",
                                     false,
                                     "{{" + stamp + "|" + s + "=}}" );
                  e  =  false;
               }
            }
            break;   // for s in config
         }
      }   // for s in config
      adjust.values[ 0 ].symbol  =  stamp;
      for ( s in config ) {
         if ( config[ s ]  ===  "lang"   ||
              config[ s ]  ===  "projLang" ) {
            slot   =  s;
            elang  =  WSTM.w.template.par.find( adjust, slot );
            if ( elang ) {
               if ( typeof elang.value  ===  "object"
                    &&     elang.value   &&
                    ! elang.mode   &&
                    typeof elang.value.source  ===  "string" ) {
                  slang  =  WSTM.str.trim( elang.value.source,
                                           true,
                                           true );
                  slang  =  slang.toLowerCase();
                  if ( config[ slot ]  ===  "lang" ) {
                     got  =  WSTM.util.code.lang( slang );
                     switch ( typeof got ) {
                        case "string" :
                           slang  =  got;   // fall through
                        case "boolean" :
                           if ( slang === WSTM.g.projLang ) {
                              re  =  new RegExp( "^" + slot + "$" );
                              WSTM.w.template.mod.flush( adjust,
                                                         [ [ re,
                                                             true ] ] );
                           }
                           break;
                        case "object" :
                           WSTM.errors.found( "templateParInvalid",
                                              false,
                                              "{{" + stamp +
                                              "|" + slot + "=" +
                                              slang + "}}"
                                              + got[ 1 ] );
                           slang  =  false;
                           break;
                     }   // switch typeof got
                  } else {   // "projLang"
                     re  =  new RegExp( "^[a-z]+[_-]?[a-z]+$" );
                     if ( ! re.test( slang ) ) {
                        WSTM.errors.found( "templateParInvalid",
                                           false,
                                           "{{" + stamp +
                                           "|" + slot + "=" +
                                           slang + "}}" );
                        slang  =  false;
                     }
                  }
               } else {
                  WSTM.errors.found( "templateParDubious",
                                     false,
                                     "{{" + stamp + "|" + slot + "=}}" );
                  elang  =  false;
               }
            }
            break;   // for s in config
         }
      }   // for s in config
      if ( store ) {
         ns  =  store.indexOf( ":" );
         if ( ns > 0 ) {   // ':'
            spc  =  store.substr( 0, ns );
            if ( spc === spc.toLowerCase() ) {
               got  =  WSTM.util.code.lang( spc );
               if ( ! got ) {
                  got  =  spc;
               }
               if ( typeof got  ===  "string" ) {
                  slang  =  got;
                  store  =  WSTM.str.trimL( store.substr( ns + 1 ),
                                            true );
               }
            // ns     =  store.indexOf( ":" );
            }
         }
/*
         var m
         if ( ns > 0 ) {   // ':'
            spc  =  store.substr( 0, ns );
            m    =  WSTM.w.link.namespace.furnish( spc, slang, false );
         }   // ':'
*/
         if ( ! low ) {
            store  =  WSTM.str.camelCasing( store );
         }
         if ( slang   &&
              slang !== WSTM.g.projLang ) {
            if ( slot   &&
                 config[ slot ]  ===  "lang" ) {
               WSTM.w.template.par.fiat( adjust, slot, slang );
               elang  =  false;
            } else {
               store  =  slang + ":" + store;
            }
         }
         e.value.source  =  store;
         e.mode          =  WSTM.o.WikiTom.LinkExtWiki;
      }
      if ( elang && slang ) {
         elang.value.source  =  slang;
         elang.mode          =  WSTM.o.WikiTom.TmplParValue;
      }
      WSTM.w.template.mod.furnish( adjust,  { indent:    0,
                                              margin:    0,
                                              linebreak: false,
                                              lost:      true,
                                              leap:      false,
                                              leave:     false,
                                              later:     false,
                                              lastline:  false } );
      WSTM.hooks.fire( "sistertemplate",  [ stamp, adjust ] );
      adjust.fresh( false );
   };   // .w.template.sister()



   WSTM.w.template.split  =  function ( adjust ) {
      // Split list of template parameters
      // Precondition:
      //    adjust  -- parameter sequence, pipe separated, no heading '|'
      //               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 PerfektesChaos@de.wikipedia
      var r  =  false,
          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.code.fold  =  function (about, adjust) {
      // Check and format coded parameter value
      // Precondition:
      //    about   -- keyword (lowercase)
      //    adjust  -- WikiTom of template to be modified or protected
      //               >< .values  Array;   i=0: Title
      //                                    >  [i].symbol
      //                                    >< [i].value
      //                < .learnt
      // Uses:
      //    .str.trimL()
      //    .str.trimR()
      //    .util.code.*()
      //    .o.WikiTom().fresh()
      // 2013-01-06 PerfektesChaos@de.wikipedia
      var b;
      var e;
      var i;
      var m;
      var n;
      var s;
      var t;
      var v  =  adjust.values;
      if (v) {
         n  =  v.length;
         for (i = 1;  i < n;  i++) {
            e  =  v[i];
            if (e.symbol.toLowerCase() === about) {
               v  =  e.value;
               if (v) {
                  t  =  typeof(v);
                  if (t === "string") {
                     s  =  v;
                  } else if (t === "object") {
                     s  =  v.source;
                  }
                  if (s) {
                     m  =  s.length;
                     s  =  WSTM.str.trimL(s, true, true);
                     m  =  (s.length === m);
                     v  =  WSTM.str.trimR(s, true, true);
                     b  =  s.substr(v.length);
                     if (v) {
                        v  =  WSTM.util.code[about](v);
                        if (v) {
                           if (typeof(v) === "string") {
                              s  =  (m ? "" : " ")  +  v  +  b;
                              e.value.fresh(s);
                              adjust.fresh(false);
                           } else {
                              // .error
                           }
                        }
                     }
                  }
               }
               break;   // for i
            }
         }   // for i
      }
   };   // .w.template.code.fold()
*/



   WSTM.w.template.file.factory  =  function () {
      // Create template configuration data
      // Uses:
      //    >  .str.spaces
      //    >  .w.link.mediatypes
      //    >< .w.template.file.re
      // 2019-06-15 PerfektesChaos@de.wikipedia
      var s;
      if ( ! this.re ) {
         this.re  =  new Array( 2 );
         s  =  "^|/#{}\n";
         s  =  "^"
               + "([ " + WSTM.str.spaces + "]*)"
               + "(&lrm;|&rlm;)?"
               + "([" + s + "]*[" + s + " ]\\."
                 + WSTM.w.link.mediatypes + ")"
               + "(&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 and URL as parameter value
      // Precondition:
      //    adjust  -- WikiTom of template to be modified or protected
      //               >< .values  Array
      //                < .learnt
      // Uses:
      //    >  .w.template.file.re
      //    >  .o.WikiTom.LinkFile
      //    >  .o.WikiTom.LinkWeb
      //    >  .mod.file
      //    >  .mod.wikilink
      //    >  .mod.luxury
      //    .str.makeString()
      //    .w.link.wiki.file()
      //    .w.link.replace.flipper()
      //    .o.WikiTom().flip()
      //    .o.WikiTom().fresh()
      //    .o.WikiTom().folder()
      // 2020-01-25 PerfektesChaos@de.wikipedia
      var re      =  this.re[ 0 ],
          v       =  adjust.values,
          n       =  v.length,
          d,
          e,
          got,
          i,
          j,
          k,
          leap,
          m,
          mode,
          p,
          s,
          story;
      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 ) {
               if ( ! d.mode ) {   // no URL
                  s  =  d.source;
               }
            }
         }
         if ( s ) {
            got  =  re.exec( s );
            if ( got ) {
               leap  =  false;
               mode  =  ( got[ 3 ].indexOf( "/" )  <  0
                                             ?  WSTM.o.WikiTom.LinkFile
                                             :  WSTM.o.WikiTom.LinkWeb );
               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 );
               }
               if ( mode === WSTM.o.WikiTom.LinkFile ) {
                  story  =  WSTM.w.link.wiki.file( got [ 3 ] );
                  if ( got[ 3 ] !== story ) {
                     leap  =  true;
                  }
               } else {
                  story  =  got[ 3 ];
               }
               if ( WSTM.mod.wikilink ) {
                  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 ] );
               }   // replace value
               if ( WSTM.mod.luxury ) {
                  got  =  p.folder( j,
                                    m,
                                    j + story.length,
                                    m );
                  if ( got ) {
                     got.mode       =  mode;
                     got.lookup     =  false;
                     adjust.learnt  =  true;
                     if ( j ) {
                        // TODO   later 2020  .file.featured()
                        p.children[ 0 ].later  =  true;
                     }
                  }
               }   // 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.wikilink       .wikilink
      //    >  .mod.luxury
      //    .o.WikiTom().find()
      //    .str.makeString()
      //    .w.link.replace.flipper()
      //    .o.WikiTom().flip()
      //    .o.WikiTom().folder()
      // 2014-09-09 PerfektesChaos@de.wikipedia
      var get     =  [ this.re[1], 0 ],
          i       =  0,
          k       =  0,
          got,
          j,
          n,
          leap,
          s,
          start,
          suffix;
      do {
         got  =  adjust.find( get, i, k, true, false, false );
         if (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) {
                     leap   =  true;
                  }   // exotic
               }   // got[1]
            }   // string
            if ( got[2] ) { // &lrm;
               leap  =  (got[2].length === 5);
            } else {
               leap  =  false;
            }
            if ( WSTM.mod.wikilink ) {
               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) {
                     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 ) {
                     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()
      // Requires: JavaScript 1.3   charCodeAt()
      // 2012-11-15 PerfektesChaos@de.wikipedia
      var r  =  false,
          d,
          e,
          i,
          j,
          k,
          n,
          p,
          s,
          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 );
                     k  =  s.length;
                     if ( k ) {
                        if ( s.charCodeAt( 0 ) === 94 ) {   // '^'
                           s  =  s.substr( 1 );
                           k--;
                        }
                     }
                     if ( k ) {
                        if (s.charCodeAt(n - 1)  ===  36) {   // '$'
                           k--;
                           s  =  s.substr(0, n);
                        }
                     }
                     if (k) {
                        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++) {
                              k  =  WSTM.util.translate.fiat(
                                            d.params[j],
                                            "",
                                            "mod.template.detect.params["
                                            + j + "]");
                              if (k) {
                                 e.params.push(k);
                              }
                           }   // for j
                           if (! e.params.length) {
                              e.params  =  false;
                           }
                        }
                        d  =  u.rename;
                        if ( typeof d  ===  "object"   &&   d ) {
                           p.rename  =  { };
                           e         =  p.rename;
                           e.title   =  WSTM.util.translate.fiat(
                                            d.title,
                                            "",
                                            "mod.template.rename.title");
                           if (WSTM.util.isArray(d.params)) {
                              e.params  =  [ ];
                              for (j = 0;  j < d.params.length;  j++) {
                                 k  =  WSTM.util.translate.fiat(
                                            d.params[j],
                                            "",
                                            "mod.template.rename.params["
                                            + j + "]");
                                 if (k) {
                                    e.params.push(k);
                                 }
                              }   // for j
                              if (! e.params.length) {
                                 e.params  =  false;
                              }
                           }
                        }
                        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++) {
                              k  =  WSTM.util.regexp.fiat(
                                                    d[j][0],
                                                    "",
                                                    "mod.template.clear["
                                                    + j + "]");
                                 if (k) {
                                    p.clear.push( [ k, d[j][1] ]);
                                 }
                           }   // for j
                           if (! p.clear.length) {
                              p.clear  =  false;
                           }
                        }
                        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 ) {
                              p.format.style  =  d.style;
                           }
                        }
                     }
/*
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,
                                    lone:      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 PerfektesChaos@de.wikipedia
      var p  =  WSTM.mod.template,
          r  =  false,
          i,
          n;
      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
      //    .w.template.mod.format() ís postponed
      // Uses:
      //    >  .mod.template.*
      //    .util.isArray()
      //    .w.template.par.fix()
      //    .w.template.mod.flush()
      //    .w.template.mod.furnish()
      //    .w.template.par.fixed()
      //    .w.template.par.format()
      // 2013-07-21 PerfektesChaos@de.wikipedia
      var n  =  -1,
          p  =  false,
          v  =  adjust.values,
          e,
          i,
          s,
          t;
      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 ( e === "function" ) {
                        e  =  e( "template",
                                 i,
                                 "{title}",
                                 s,
                                 adjust.values );
                     }
                     if ( typeof e  ===  "string" ) {
                        s  =  s.replace( t.rename.title[ 0 ],  e );
                     }
                     if ( s !== v[ 0 ].symbol ) {
                        adjust.values[ 0 ].symbol  =  s;
                        adjust.children[ 1 ].fresh( s );
                     }
                  }
                  if ( t.rename.params ) {
                     WSTM.w.template.par.fix( t.rename.params, adjust );
                  }
               }
               if ( t.change && false ) {
                  WSTM.w.template.mod.xxxxxxxxx( t.change, adjust );
               }
               if ( t.clear ) {
                  WSTM.w.template.mod.flush( adjust, t.clear );
               }
               if ( t.format ) {
                  if ( t.format.style ) {
                     WSTM.w.template.mod.furnish( adjust,
                                                  t.format.style );
                  }
                  if ( t.format.order ) {
                     WSTM.w.template.par.fixed( t.format.order, adjust );
                  }
               }
            }
         }   // for i
      }
   };   // .w.template.mod.fire()



   WSTM.w.template.mod.flat  =  function (adjust) {
      // Perform user defined plain text template parameters modification
      // Precondition:
      //    adjust   -- WikiTom of entire template
      //                >  .values
      //                 < .learnt
      // Uses:
      //    >  .mod.plain
      //    >  .mod.plain.stm
      //    .o.WikiTom().replace()
      // 2019-08-01 PerfektesChaos@de.wikipedia
      var v  =  adjust.values,
          i, n, q;
      if ( v ) {
         n  =  v.length;
         for ( i = 1;  i < n;  i++ ) {
            q  =  v[ i ].value;
            if ( typeof q  ===  "object"   &&   q.lookup ) {
               q.replace( WSTM.mod.plain.stm, false );
            }
         }   // for i
      }
   };   // .w.template.mod.flat()



   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 [nameRE, mode]
      //               nameRE  -- RegExp string
      //               mode    -- false: keep if not empty;  true: always
      // Postcondition:
      //    < adjust.learnt  -- true if modified
      // Uses:
      //    .str.trim()
      // 2015-01-18 PerfektesChaos@de.wikipedia
      var v  =  adjust.values,
          m  =  v.length,
          n  =  apply.length,
          i,
          k,
          p,
          q,
          r,
          s,
          x;
      for ( i = 0;  i < n;  i++ ) {
         p  =  apply[ i ];
         r  =  p[ 0 ];
         switch ( typeof r ) {
            case "string" :
               r  =  new RegExp( p[ 0 ] );
               break;
            case "object" :
               break;
            default:
               m = 0;
         }   // switch typeof r
         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
      //               >  .lastline  -- ignore linebreak on lastline
      //               >  .lost      -- pipe directly after template name
      //               >< .children
      //                < .learnt
      //                < .source
      // Postcondition:
      //    adjust was re-built
      // Uses:
      //    .str.makeString()
      //    .o.WikiTom()
      //    .o.WikiTom().fresh()
      // 2019-11-17 PerfektesChaos@de.wikipedia
      var lost  =  adjust.lost,
          v     =  adjust.values,
          i, n, p, s;
      if ( v ) {
         n                            =  v.length;
         adjust.learnt                =  true;
         adjust.source                =  false;
         adjust.children[ 1 ].parent  =  null;
         adjust.children[ 1 ].source  =  v[ 0 ].symbol;
         adjust.children              =  [ new WSTM.o.WikiTom( "{{",
                                                               null ),
                                           adjust.children[ 1 ] ];
         adjust.label                 =  false;
         if ( v[ 0 ].joint ) {
            s  =  WSTM.str.makeString( 32, adjust.joint );
            adjust.children.push( new WSTM.o.WikiTom( s, null ) );
         }
         if ( v[ 0 ].comment ) {
            if ( v[ 0 ].commentnewline ) {
               adjust.children.push( new WSTM.o.WikiTom( "\n", null ) );
            }
            adjust.children.push( v[ 0 ].comment );
         }
         for ( i = 1;  i < n;  i++ ) {
            p  =  v[ i ];
            adjust.children.push( WSTM.w.template.par.format( p,
                                                              adjust,
                                                              lost ) );
            lost  =  false;
            if ( p.value ) {
               p.value.parent  =  null;
               adjust.children.push( p.value );
            } else {
               adjust.children.push( new WSTM.o.WikiTom( "", null ) );
            }
         }   // for i
         if ( typeof adjust.linebreak  !==  "boolean" ) {
            adjust.linebreak  =  false;
         }
         if ( typeof adjust.lastline  !==  "boolean" ) {
            adjust.lastline  =  false;
         }
         if ( n  &&  adjust.linebreak  &&  adjust.lastline ) {
            i  =  0;
            if ( typeof adjust.margin  ===  "number" ) {
               i  =  adjust.margin;
            } else if ( typeof adjust.indent  ===  "number" ) {
               i  =  adjust.indent;
            }
            if ( i ) {
               s  =  "\n"  +  WSTM.str.makeString( 32, i )  +  "}}";
            } else {
               s  =  "\n}}";
            }
         } else {
            s  =  "}}";
         }
         adjust.children.push( new WSTM.o.WikiTom( s, 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.wikilink
      // 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()
      // 2012-04-17 PerfektesChaos@de.wikipedia
      var block   =  adjust.children,
          serve   =  block[1].toString(),
          start   =  ( ahead  ?  ahead + "{{"  :  "{{" ),
          suffix  =  ( block[2]  ?  block[2].toString()  :  false ),
          swap    =  WSTM.w.link.replace.flipper( serve,
                                                  start,
                                                  suffix,
                                                  "Template" ),
          i;
      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
      //                           >  .leap
      //                           >  .source
      //                         < .lined linebreak before pipe
      //                    etc.
      //                 >  .linebreak
      //    apply   -- layout information
      //               .indent     -- number of spaces before pipe
      //               .margin     -- number of spaces before '}}'
      //               .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
      //               .lone       -- space after '=' even if no value
      //               .lost       -- pipe directly after template name
      // Postcondition:
      //    < adjust.learnt     -- true if modified
      //    < adjust.margin     -- number of spaces before '}}'
      //    < adjust.indent     -- true if indented
      //    < adjust.lastline   -- linebreak on lastline
      //    < adjust.leap       -- true if space after pipe
      //    < adjust.linebreak  -- true if linebreak after template name
      //    < adjust.lineup     -- true if all '=' aligned
      //    < adjust.lost       -- true if pipe directly after template name
      // Uses:
      //    >  this.source
      //    >  this.children
      //    .str.trimR()
      //    .str.makeString()
      //    .o.WikiTom().trimR()
      //    .o.WikiTom().fresh()
      //    .w.template.mod.trim()
      // 2019-11-14 PerfektesChaos@de.wikipedia
      var v   =  adjust.values,
          ch  =  [ ],
          ck  =  [ "margin", "indent",
                   "later", "leap", "leave", "lone" ],
          lb  =  ( typeof apply.linebreak  ===  "boolean" ),
          m   =  0,
          n   =  v.length,
          e,
          i,
          j,
          p,
          q,
          s;
      ch[ 0 ]  =  ( typeof apply.margin  ===  "number" );
      ch[ 1 ]  =  ( typeof apply.indent  ===  "number" );
      for ( j = 2;  j < ck.length;  j++ ) {
         ch[ j ]  =  ( typeof apply[ ck[ j ] ]  ===  "boolean" );
      }   // for j
      if ( ch[ 0 ] ) {
         ch[ 0 ]  =  ( apply.margin >= 0 );
         if ( ch[ 0 ]  &&  n ) {
            adjust.margin  =  apply.margin;
         }
      }
      if ( ch[ 1 ] ) {
         ch[ 1 ]  =  ( apply.indent >= 0 );
         if ( ch[ 1 ]  &&  n  &&  apply.indent ) {
            adjust.indent  =  true;
         }
      }
      if ( typeof apply.lastline  ===  "boolean" ) {
         adjust.lastline  =  apply.lastline;
      }
      if ( typeof apply.leap  ===  "boolean"   &&   apply.leap ) {
         adjust.leap  =  true;
      }
      if ( typeof apply.lineup  ===  "boolean"   &&   apply.lineup ) {
         for ( i = 1;  i < n;  i++ ) {
            s  =  v[ i ].symbol;
            if ( s ) {
               j  =  s.length;
               if ( j > m ) {
                  m  =  j;
               }
            }
         }   // for i
         adjust.lineup  =  m;
      }
      if ( typeof apply.leave  ===  "boolean" ) {
         if ( typeof adjust.leave  !==  "boolean" ) {
            adjust.leave  =  false;
         }
         if ( apply.leave ) {
            m++;
            adjust.learnt  =  ( adjust.leave ? adjust.learnt : true );
            adjust.leave   =  true;
         } else {
            adjust.learnt  =  ( adjust.leave ? true : adjust.learnt );
            adjust.leave   =  false;
         }
      }
      if ( typeof apply.later  ===  "boolean" ) {
         if ( typeof adjust.later  !==  "boolean" ) {
            adjust.later  =  false;
         }
         if ( apply.later ) {
            adjust.learnt  =  ( adjust.later ? adjust.learnt : true );
            adjust.later   =  true;
         } else {
            adjust.learnt  =  ( adjust.later ? true : adjust.learnt );
            adjust.later   =  false;
         }
      }
      if ( lb ) {
         if ( typeof adjust.linebreak  !==  "boolean" ) {
            adjust.linebreak  =  false;
         }
         if ( apply.linebreak !== adjust.linebreak ) {
            adjust.linebreak  =  apply.linebreak;
            adjust.learnt     =  true;
         }
         if ( apply.linebreak ) {
            s  =  v[ 0 ].symbol;
            if (s) {
               s  =  WSTM.str.trimR( s, true, true );
               if ( s  !==  v[ 0 ].symbol ) {
                  v[ 0 ].symbol    =  s;
                  adjust.learnt    =  true;
               }
            }
         }
      }
      if ( typeof apply.lost  ===  "boolean" ) {
         adjust.lost  =  apply.lost;
      }
      for ( i = 1;  i < n;  i++ ) {
         q  =  v[ i ];
         e  =  q.value;
         if ( lb ) {
            if ( apply.linebreak !== q.lined ) {
               q.lined        =  apply.linebreak;
               adjust.learnt  =  true;
            }
            if ( apply.linebreak ) {
               if ( typeof e  ===  "object" ) {
                  if ( e.trimR( true, true, true ) ) {
                     adjust.learnt  =  true;
                  }
               }
            }
         }
         for ( j = 1;  j < ch.length;  j++ ) {
            if ( ch[ j ] ) {
               s  =  ck[ j ];
               if ( apply[ s ] !== q[ s ] ) {
                  q[ s ]         =  apply[ s ];
                  adjust.learnt  =  true;
               }
            }
         }   // for j
         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, false, true );
         if ( s !== j ) {
            if ( e.children ) {
               p.fresh( s );
            } else {
               e.fresh( s );
            }
            adjust.learnt  =  true;
         }
      }   // for i
      this.trim( adjust, apply );
   };   // .w.template.mod.furnish()



   WSTM.w.template.mod.trim  =  function ( adjust, apply ) {
      // Trim all template values
      // Precondition:
      //    adjust  -- WikiTom
      //                 .values Array:
      //                      [0] template name
      //                      [1] first parameter
      //                          >  .value  -- WikiTom with value string
      //                             >  .children
      //                             >  .source
      //                      etc.
      //    apply   -- layout information, or false
      //               .later  -- space after '='
      //               .lone   -- space after '=' even if no value
      // Postcondition:
      //    < adjust.learnt  -- true if modified
      // Uses:
      //    .o.WikiTom().trimL()
      //    .o.WikiTom().trimR()
      //    .o.WikiTom()
      // 2012-11-20 PerfektesChaos@de.wikipedia
      var v  =  adjust.values,
          n  =  v.length,
          i,
          q;
      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;
            }
            if ( apply ) {
               if ( apply.lone && apply.later ) {
                  if ( ! q.children ) {
                     if ( ! q.source ) {
                        q.source       =  " ";
                        adjust.learnt  =  true;
                     }
                  }
               }
            }
         } else {   // ?????? ever?
            adjust.values[i].value  =  new WSTM.o.WikiTom( ( apply.later
                                                                  ? " "
                                                                  : "" ),
                                                           null );
            adjust.learnt           =  true;
         }
      }   // for i
   };   // .w.template.mod.trim()



   WSTM.w.template.par.fetch  =  function ( assigned ) {
      // Retrieve plain string from assignment
      // Precondition:
      //    assigned  -- assignment with .value
      // Postcondition:
      //    Return string, or false if failed
      // 2016-01-13 PerfektesChaos@de.wikipedia
      var r  =  false,
          v  =  assigned.value,
          t;
      if ( v ) {
         t  =  typeof v;
         if ( t === "string" ) {
            r  =  v;
         } else if ( t === "object" ) {
            r  =  v.source;
            if ( ! r ) {
               r  =  v.toString();
            }
         }
      }
      return  r;
   };   // .w.template.par.fetch()



   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()
      // 2019-09-14 PerfektesChaos@de.wikipedia
      var r  =  false,
          v  =  adjust.values,
          i,
          n;
      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 );
         }
         switch ( typeof assign ) {
            case "string" :
               v  =  new WSTM.o.WikiTom( assign, adjust );
               break;
            case "object" :
               v         =  assign;
               v.parent  =  adjust;
               break;
            default:
               v         =  null;
         }
         r.value        =  v;
         adjust.learnt  =  true;
      }
      return  r;
   };   // .w.template.par.fiat()



   WSTM.w.template.par.find  =  function ( adjust, access ) {
      // Find parameter in sequence
      // Precondition:
      //    adjust  -- WikiTom().values
      //               [0] template name
      //               [1] first parameter assignment
      //                   .symbol
      //    access  -- parameter name
      // Postcondition:
      //    Return value object, or false
      // 2019-11-14 PerfektesChaos@de.wikipedia
      var r  =  false,
          v  =  adjust.values,
          i,
          n;
      if ( v ) {
         n  =  v.length;
         for ( i = 1;  i < n;  i++ ) {
            if ( v[ i ].symbol  ===  access ) {
               r  =  v[ i ];
               if ( typeof r.flat  !==  "function" ) {
                  r.WSTM  =  WSTM;
                  r.flat  =  function () {
                     var rf  =  false;
                     if ( typeof this.value  ===  "object"
                          &&     this.value   &&
                          typeof this.value.source  ===  "string" ) {
                        rf  =  this.WSTM.str.trim( this.value.source,
                                                   false,
                                                   true );
                     }
                     return  rf;
                  };
               }
               break;   // for i
            }
         }   // for i
      }
      return  r;
   };   // .w.template.par.find()



   WSTM.w.template.par.fit  =  function ( adjust, assign, access ) {
      // Identify setting per parameter or per template
      // Precondition:
      //    adjust  -- single value object
      //    assign  -- parent object (entire template)
      //    access  -- property name
      // Postcondition:
      //    Return true, if requested
      // 2013-04-29 PerfektesChaos@de.wikipedia
      var g  =  adjust[ access ],
          s  =  typeof g,
          r  =  false;
      if ( s === "boolean"  ||  s === "number" ) {
         r  =  g;
      } else {
         g  =  assign[ access ];
         s  =  typeof g;
         if ( s === "boolean"  ||  s === "number" ) {
            r  =  g;
         }
      }
      return  r;
   };   // .w.template.par.fit()



   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].lazy     adjusted
      //    >< [i].symbol   adjusted
      // 2017-07-24 PerfektesChaos@de.wikipedia
      var r  =  false,
          v  =  adjust.values,
          e,
          i,
          j,
          k,
          m,
          n,
          s;
      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 ].lazy    =  false;
                        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 false iff no modification
      //    adjust
      //        < .learnt      true  if modified
      //       >< [i].symbol   adjusted
      // Uses:
      //    .util.isArray()
      //    .o.WikiTom().trimR()
      // 2019-02-10 PerfektesChaos@de.wikipedia
      var b  =  false,
          r  =  false,
          v  =  adjust.values,
          i,    // apply[i]
          j,    // values[j]
          k,    // apply.length
          l,    // insert new par
          m,    // last
          n,    // values.length
          p,    // par not found
          s,
          x;    // ignore
      if ( apply && v ) {
         k  =  apply.length;
         n  =  v.length;
         m  =  1;
         if ( n > 1 ) {
            p  =  v[ 1 ];
            if ( p.lined ) {
               b  =  true;
               delete p.lined;
            }
            if ( ! adjust.linebreak ) {
               /* last   + .br */
            }
         }
         for ( i = 0;  i < k;  i++ ) {
            l  =  false;
            x  =  false;
            s  =  apply[ i ];
            if ( typeof s  !==  "string" ) {
               if ( WSTM.util.isArray( s ) ) {
                  if ( s[ 2 ] ) {
                     l  =  true;
                  } else if ( s[ 3 ] ) {
                     x  =  true;
                  }
                  s  =  s[ 1 ];
               }
            }
            if ( typeof s  ===  "string" ) {
               p  =  true;
               for ( j = m;  j < n;  j++ ) {
                  p  =  v[ j ];
                  if ( s === p.symbol ) {
                     if ( j > m ) {
                        adjust.values.splice( j, 1 );
                        adjust.values.splice( m,  0,  p );
                        r  =  true;
                     }
                     p  =  false;
                     m++;
                     break;   // for j
                  } else if ( x ) {
                     break;   // for j
                  }
               }   // for j
               if ( p && l ) {
                  p  =  new WSTM.o.WikiTom( "", adjust );
                  adjust.values.splice( m,
                                        0,
                                        { symbol: s,
                                          value:  p } );
                  p.symbol  =  s;
                  m++;
                  n++;
                  r  =  true;
               }
            }
         }   // for i
      }
      if ( b ) {
         v[ 1 ].lined  =  true;
         if ( v[ 0 ].joint ) {
            v[ 1 ].indent  =  v[ 0 ].joint;
         }
      }
      if ( n > 1 ) {
         v  =  adjust.values[ n - 1 ].value;
         if ( typeof v  ===  "object"   &&
              v.trimR( true, true, true ) ) {
            r  =  true;
         }
      }
      if ( r ) {
         adjust.learnt  =  true;
         r              =  adjust;
      }
      return  r;
   };   // .w.template.par.fixed()



   WSTM.w.template.par.flip  =  function ( adjust ) {
      // Perform standardized parameter modifications
      // Precondition:
      //    adjust  -- WikiTom sequence (forked element)
      // Postcondition:
      //    adjust was changed if necessary
      // Uses:
      //    >   .lang.p.*.parShift
      //    .w.template.par.flipper()
      //    .str.fromNum()
      //    .w.template.par.fixed()
      // Remark: May be used as event handler -- 'this' is not accessed
      // 2019-12-27 PerfektesChaos@de.wikipedia
      var s  =  adjust.values[ 0 ].symbol,
          d, i;
      if ( typeof WSTM.lang.p[ WSTM.g.wDBname ]  ===  "object" ) {
         d  =  WSTM.lang.p[ WSTM.g.wDBname ];
         if ( typeof d.template  ===  "object"   &&
              typeof d.template.parShift  ===  "object"   &&
              typeof d.template.parShift[ s ]  ===  "object" ) {
            d  =  d.template.parShift[ s ];
            if ( typeof d.length  ===  "number" ) {
               for ( i = 0;  i < d.length;  i++ ) {
                  if ( typeof d[ i ]  ===  "object"
                       &&     d[ i ] ) {
                     WSTM.w.template.par.flipper( adjust, d[ i ] );
                  }
               }   // for i
            } else {
               WSTM.w.template.par.flipper( adjust, d );
            }
         }
         if ( typeof adjust.nameless  ===  "number" ) {
            d  =  [ false ];
            for ( i = 1;  i <= adjust.nameless;  i++ ) {
               d.push( WSTM.str.fromNum( i ) );
            }   // for i
            WSTM.w.template.par.fixed( d, adjust );
            WSTM.w.template.mod.format( adjust );
            delete adjust.nameless;
            adjust.fresh( false );
         }
      }
   };   // .w.template.par.flip()



   WSTM.w.template.par.flipper  =  function ( adjust, apply ) {
      // Execute a standardized parameter modification
      // Precondition:
      //    adjust  -- WikiTom sequence (forked element)
      //    apply   -- modification object
      //               .p        -- pattern, string or Array of strings
      //               .d        -- true, delete this or these parameters
      //               .s        -- string, with new name
      //               .boole    -- Array, with default rule
      //               .isoDate  -- true, format date as ISO
      //               .lock     -- true, protect this value
      // Postcondition:
      //    adjust was changed if necessary
      // Uses:
      //    .w.template.par.find()
      //    .o.WikiTom().fresh()
      //    .util.date.fetch()
      //    .util.date.format()
      //    .w.template.mod.flush()
      // 2021-05-11 PerfektesChaos@de.wikipedia
      var e, i, o, s;
      switch ( typeof apply.p ) {
         case "string" :
            e  =  WSTM.w.template.par.find( adjust, apply.p );
            break;
         case "object" :
            for ( i = 0;  i < apply.p.length;  i++ ) {
               e  =  WSTM.w.template.par.find( adjust, apply.p[ i ] );
               if ( e ) {
                  break;   // for i
               }
            }   // for i
            break;
         case "boolean" :
            if ( apply.p ) {
               e  =  WSTM.w.template.par.find( adjust, apply.s );
            }
            break;
      }   // switch typeof  apply.p
      if ( typeof apply.s  ===  "string" ) {
         if ( e ) {
            if ( apply.s ) {
               if ( typeof e.location  ===  "boolean"
                    &&     e.location ) {
                  if ( typeof this.reNum  !==  "object" ) {
                     this.reNum  =  new RegExp( "^[1-9][0-9]*$" );
                  }
                  if ( this.reNum.test( e.symbol )   &&
                       ! this.reNum.test( apply.s ) ) {
                     e.location  =  false;
                  }
               }
               e.symbol = apply.s;
               adjust.fresh( false );
            }
         }
      }
      if ( e ) {
         if ( typeof apply.boole  ===  "object"
              &&     apply.boole   &&
              typeof apply.boole.length  ===  "number"   &&
              typeof e.value.source  ===  "string" ) {
            s  =  WSTM.str.trim( e.value.source, true, true );
            if ( s === "" ) {
               if ( apply.boole.length === 0 ) {
                  s  =  "^" + e.symbol + "$";
                  WSTM.w.template.mod.flush( adjust,
                                             [ [ s, true ] ] );
               } else if ( typeof apply.boole[ 0 ]  ===  "boolean" ) {
                  i  =  ( apply.boole[ 0 ]  ?  1  :  0 );
               }
            } else {
               s  =  s.toLowerCase();
               if ( s === "-"       ||
                    s === "false"   ||
                    s === "n"       ||
                    s === "no"      ||
                    s === "off" ) {
                  i  =  0;
               } else if ( s === "true"   ||
                           s === "y"      ||
                           s === "yes"    ||
                           s === "on" ) {
                  i  =  1;
               } else {
                  o  =  WSTM.hooks.fire( "yes_pattern" );
                  if ( o  &&  o.test( s ) ) {
                     i  =  1;
                  } else {
                     o  =  WSTM.hooks.fire( "no_pattern" );
                     if ( o  &&  o.test( s ) ) {
                        i  =  0;
                     }
                  }
               }
            }
            if ( typeof i  ===  "number" ) {
               e.value.source  =  ( i + "" );
               adjust.fresh( false );
            }
         }
         if ( typeof apply.isoDate  ===  "boolean"
              &&     apply.isoDate   &&
              typeof e.value.source  ===  "string" ) {
            s  =  WSTM.util.date.fetch( e.value.source,
                                        true,
                                        WSTM.g.wPageLang );
            if ( s ) {
               e.value.source  =  WSTM.util.date.format( s, 3 );
            }
            adjust.fresh( false );
         }
         if ( typeof apply.lock  ===  "boolean"
              &&     apply.lock ) {
            e.value.lookup  =  false;
         }
         if ( typeof this.reNum  !==  "object" ) {
            this.reNum  =  new RegExp( "^[1-9][0-9]*$" );
         }
         if ( this.reNum.test( apply.s ) ) {
            if ( typeof e.value.source  ===  "string"   &&
                 e.value.source.indexOf( "=" )  <  0 ) {
               e.lazy      =  true;
               e.location  =  true;
            }
            i  =  parseInt( apply.s, 10 );
            if ( typeof adjust.nameless  ===  "number" ) {
               if ( i > adjust.nameless ) {
                  adjust.nameless  =  i;
               }
            } else {
               adjust.nameless  =  i;
            }
         }
         if ( typeof apply.d  ===  "boolean"
              &&     apply.d ) {
            switch ( typeof apply.p ) {
               case "string" :
                  e  =  "^" + apply.p + "$";
                  WSTM.w.template.mod.flush( adjust,  [ [ e, true ] ] );
                  break;
               case "object" :
                  o  =  [ ];
                  for ( i = 0;  i < apply.p.length;  i++ ) {
                     e  =  new RegExp( "^" + apply.p[ i ] + "$" );
                     o.push( [ e, true ] );
                  }   // for i
                  WSTM.w.template.mod.flush( adjust, o );
                  break;
            }   // switch typeof  apply.p
         }
      }
   };   // .w.template.par.flipper()



   WSTM.w.template.par.flush  =  function ( adjust, avoid, already ) {
      // Remove parameter assignment
      // Precondition:
      //    adjust   -- WikiTom()
      //                >< .values[]
      //                 < .learnt
      //    avoid    -- parameter number in .values[]
      //    already  -- true: even if value present
      //    .str.trim()
      // 2019-11-12 PerfektesChaos@de.wikipedia
      var e  =  adjust.values[ avoid ].value;
      if ( e ) {
         if ( already ) {
            e  =  false;
         } else if ( typeof e.source  ===  "string"   &&
                     WSTM.str.trim( e.source, true, true ) === "" ) {
            e  =  false;
         }
      }
      if ( ! e ) {
         adjust.values.splice( avoid, 1 );
         adjust.values.learnt  =  true;
      }
   };   // .w.template.par.flush()



   WSTM.w.template.par.format  =  function ( adjust, assign, alone ) {
      // Format parameter assignment
      // Precondition:
      //    adjust  -- WikiTom().values[i]
      //                         >  .lined
      //                         >  .indent
      //                         >  .symbol
      //                         >  .lazy
      //                         >  .location
      //                         >  .keep
      //                         >  .value
      //    assign  -- parent
      //               >  .lineup
      //               >  .leap
      //               >  .leave
      //               >  .later
      //               >  .values
      //               >< .label
      //               >< .legal
      //    alone   -- pipe after template name
      // Postcondition:
      //    Return new WikiTom()
      // Uses:
      //    >  .o.WikiTom.TmplParAssign
      //    .w.template.par.fit()
      //    .str.makeString()
      //    .hooks.fire()
      //    .o.WikiTom()
      //    .o.WikiTom().trimL()
      // .o.WikiTom().flush()
      // 2020-01-25 PerfektesChaos@de.wikipedia
      var l      =  assign.label,
          s      =  "|",
          later,
          n,
          o,
          r;
      if ( this.fit( adjust, assign, "leap" ) ) {
         s  =  "| ";
      }
      if ( typeof adjust.lined  ===  "boolean" ) {
         if ( adjust.indent ) {
            s  =  WSTM.str.makeString( 32, adjust.indent )  +  s;
         }
         if ( adjust.lined ) {
            if ( alone ) {
               s  =  "|\n  ";
            } else {
               s  =  "\n" + s;
            }
         }
      }
      if ( adjust.symbol ) {
         if ( ! l ) {
            if ( ! adjust.lazy  &&  ! assign.legal ) {
               if ( WSTM.hooks.fire( "paramSeqMix",
                                     assign.values[ 0 ].symbol ) ) {
                  assign.legal  =  true;
               } else {
                  assign.label  =  true;
                  l             =  true;
               }
            }
         }
         if ( l   ||
              typeof adjust.location  !==  "boolean"
              ||   ! adjust.location ) {
            s  =  s  +  adjust.symbol;
            l  =  true;
         }
         if ( assign.lineup ) {
            n  =  assign.lineup - adjust.symbol.length;
            if ( n > 0 ) {
               s  =  s  +  WSTM.str.makeString( 32, n );
            }
         } else if ( adjust.keep  &&
                     assign.leave !== false  &&
                     adjust.leave !== false ) {
            s  =  s  +  WSTM.str.makeString( 32, adjust.keep );
         }
         if ( this.fit( adjust, assign, "leave" ) ) {
            s  =  s + " ";
         }
         if ( l ) {
            s  =  s + "=";
            if ( this.fit( adjust, assign, "later" ) ) {
               s      =  s + " ";
               later  =  true;
            }
            if ( typeof adjust.value  ===  "object"   &&
                 typeof adjust.value.children  ===  "object"   &&
                 typeof adjust.value.children.length ) {
               o  =  adjust.value.children[ 0 ];
               if ( typeof o.source  ===  "string"
                    &&     o.source ) {
                  // TODO 2020
                  if ( typeof o.later  ===  "boolean"
                       &&     o.later
                       &&     ! later ) {
                     s  =  s + " ";
                  }
                  o.trimL( true );
                  if ( ! o.source ) {
                     adjust.value.flush( 0 );
                  }
               }
            }
         }
      }
      r         =  new WSTM.o.WikiTom( s, null );
      r.lookup  =  false;
      r.mode    =  WSTM.o.WikiTom.TmplParAssign;
      return  r;
   };   // .w.template.par.format()



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



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



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



// Emacs
// Local Variables:
// coding: utf-8-dos
// fill-column: 80
// End:

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