User:PerfektesChaos/js/menuSwitcher/d.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/menuSwitcher/d.js
/// 2020-10-20 PerfektesChaos@de.wikipedia
/// Fingerprint: #0#0#
/// <nowiki>
/* global window: false, JSON:false, jQuery: false, mediaWiki: false   */
/* jshint forin: false,
          bitwise:true, curly:true, eqeqeq:true, latedef:true,
          laxbreak:true,
          nocomma:true, strict:true, undef:true, unused:true           */



( function ( mw, $ ) {
   /// Gadget for configurable Edittools
   "use strict";
   var Version    = -1.94,
       Sign       = "menuSwitcher",
       Signature  = "ext.gadget." + Sign,
       Support    = "w:en:User:PerfektesChaos/js/" + Sign,
       CONFIG     = { maxItems: 99 },
       EDIT       = { },
       GUI        = { css: { "background-color": "#FFFFFF",
                             "clear":            "both",
                             "color":            "#000000",
 //                          "font-size":        "1rem",
                             "font-style":       "normal",
                             "font-weight":      "normal",
                             "line-height":      "1.2rem" } },
       REMIND     = { };



   function fire() {
      // Intialize application
      // Uses:
      //    >  Signature
      //    mw.loader.getState()
      //    mw.loader.state()
      //    CONFIG.first()
      //    mw.hook()
      //    (CONFIG.fired)
      //    (CONFIG.forward)
      //    (GUI.fire)
      // 2018-11-12 PerfektesChaos@de.wikipedia
      var rls;
      if ( mw.loader.getState( Signature )  !==  "ready" ) {
         rls = { };
         rls[ Signature ] = "ready";
         mw.loader.state( rls );
         CONFIG.first();
         mw.hook( Signature + ".config" ).add( CONFIG.fired );
         mw.hook( Signature + ".help" ).add( CONFIG.forward );
         $( document ).ready( GUI.fire );
      }
   }   // fire()



   CONFIG.facility = function ( access, assign ) {
      // Configure auxilary buttons
      // Precondition:
      //    access  -- "help" or "hide"
      //    assign  -- object, with config, or string, or false
      // Uses:
      //    REMIND.fetch()
      //    GUI.fade()
      //    REMIND.feed()
      //    GUI.facility()
      // 2018-11-30 PerfektesChaos@de.wikipedia
      var cnf, config, def;
      switch ( access ) {
         case "help":
            def = { "background-color": "#008000",
                    "show":             "?",
                    "start":            false,
                    "suite":            "$helpers",
                    "support":          "Help" };
            break;
         case "hide":
            def = { "background-color": "#FF0000",
                    "show":             "X",
                    "start":            "fade",
                    "suite":            "$hiders",
                    "support":          "Hide" };
            break;
      }   // switch access
      if ( def ) {
         switch ( typeof assign ) {
            case "boolean":
               cnf = { mode: ( assign ? 1 : 0 ) };
               break;
            case "object":
               cnf = assign  ||  { };
               break;
            case "string":
               if ( access === "help" ) {
                  cnf = { mode:    ( assign ? 1 : 0 ),
                          service: ( assign ? assign : false ) };
               } else {
                  cnf = { };
               }
               break;
         }   // switch typeof assign
         if ( typeof CONFIG[ access ]  !==  "object" ) {
            CONFIG[ access ] = { service: false,
                                 start:   def.start,
                                 suite:   def.suite };
         }
         config = CONFIG[ access ];
         if ( typeof cnf[ "class" ]  ===  "string"
              &&     cnf[ "class" ] ) {
            config[ "class" ] = cnf[ "class" ];
         }
         if ( typeof cnf.css  ===  "object"
              &&     cnf.css ) {
            config.css = cnf.css;
         } else {
            config.css = { "background-color": def[ "background-color" ],
                           "border-color":     "#808080",
                           "border-radius":    "4px",
                           "border-style":     "solid",
                           "border-width":     "1px",
                           "color":            "#FFFFFF",
                           "display":          "inline-block",
                           "font-size":        "0.8rem",
                           "font-weight":      "bold",
                           "margin":           "0.5em",
                           "padding":          "2px" };
         }
         switch ( access ) {
            case "help":
               if ( typeof cnf.service  ===  "string" ) {
                  config.service = cnf.service;
                  config.mode    = 1;
               }
               break;
            case "hide":
               if ( typeof cnf.less  ===  "boolean" ) {
                  config.less = cnf.less;
               } else if ( typeof config.less  !==  "boolean" ) {
                  config.less = false;
               }
               if ( config.less   &&
                    typeof REMIND.fetch( "less" )  !==  "boolean" ) {
                  if ( CONFIG.live && GUI.live ) {
                     GUI.fade();
                  } else {
                     REMIND.feed( "less", true );
                  }
               }
               break;
         }   // switch access
         if ( typeof cnf.mode  ===  "number" ) {
            config.mode = cnf.mode;
         } else {
            config.mode = 1;
         }
         if ( typeof cnf.show  ===  "string"
              &&     cnf.show ) {
            config.show = cnf.show;
         } else {
            config.show = def.show;
         }
         if ( typeof cnf.support  ===  "string"
              &&     cnf.support ) {
            config.support = cnf.support;
         } else {
            config.support = def.support;
         }
         if ( CONFIG.live  &&  GUI.live ) {
            GUI.facility( access );
         }
      }
   };   // CONFIG.facility()



   CONFIG.feed = function ( apply ) {
      // Register defs
      // Precondition:
      //    apply  -- object, with config
      // Uses:
      //    CONFIG.fit()
      //    GUI.feed_***()
      // 2018-11-12 PerfektesChaos@de.wikipedia
      var last, suitable;
      if ( typeof apply.create  ===  "object"
           &&     apply.create   &&
           typeof apply.system  ===  "string" ) {
         suitable = "feed_" + apply.system;
         if ( typeof CONFIG[ suitable ]  ===  "function"   &&
              CONFIG.fit( apply ) ) {
            if ( typeof apply.last  ===  "boolean" ) {
               last = apply.last;
            }
            CONFIG[ suitable ]( apply.create, last );
         }
      } else if ( typeof apply.top  ===  "object"
                  &&     apply.top   &&
                  typeof apply.top.length  ===  "number" ) {
         CONFIG.feed_existing( apply.top );
      }
   };   // CONFIG.feed()



   CONFIG.feed_builtin = function ( apply, after ) {
      // Register object request
      // Precondition:
      //    apply  -- object, with spec
      //    after  -- boolean, with end position
      // Uses:
      //    CONFIG.feeder()
      //    GUI.fresh()
      // 2017-10-01 PerfektesChaos@de.wikipedia
      var e, i, s;
      if ( typeof apply.length  ===  "number" ) {
         for ( i = 0;  i < apply.length;  i++ ) {
            e = apply[ i ];
            if ( typeof  e ===  "object"
                 &&      e ) {
               if ( typeof e.selector  ===  "string"
                    &&     e.selector ) {
                  s = e.selector;
               } else {
                  s = false;
               }
               CONFIG.feeder( s, "builtin", e, after );
            }
         }   // for i
         GUI.fresh( true );
      }
   };   // CONFIG.feed_builtin()



   CONFIG.feed_charinsert = function ( apply ) {
      // Register <charinsert> request
      // Precondition:
      //    apply     -- object, with spec
      // Uses:
      //    GUI.flip()
      // 2017-10-04 PerfektesChaos@de.wikipedia
      if ( CONFIG.learn   &&   typeof apply.selector  ===  "string" ) {
         CONFIG.exist = apply;
         GUI.flip();
      }
   };   // CONFIG.feed_charinsert()



   CONFIG.feed_existing = function ( apply ) {
      // Modify panel sequence
      // Precondition:
      //    apply  -- Array, with order
      // Uses:
      //    CONFIG.follower()
      //    CONFIG.follow()
      //    GUI.fresh()
      // 2018-11-08 PerfektesChaos@de.wikipedia
      var i, live, s;
      for ( i = 0;  i < apply.length;  i++ ) {
         s = apply[ i ];
         if ( typeof  s ===  "string"
              &&      s ) {
            s = CONFIG.follower( s );
            if ( typeof CONFIG.groups.panels[ s ]  ===  "object" ) {
               CONFIG.follow( s, CONFIG.groups.panels[ s ], false );
               live = true;
            }
         }
      }   // for i
      if ( live ) {
         GUI.fresh( true );
      }
   };   // CONFIG.feed_existing()



   CONFIG.feed_stringArrayObject = function ( apply, after ) {
      // Register request as of dewiki 2010
      // NOTE: Definition by object, sequence is not ensured.
      // Precondition:
      //    apply  -- object, with spec
      //    after  -- boolean, with end position
      // Uses:
      //    CONFIG.feeder()
      //    GUI.fresh()
      // 2017-10-01 PerfektesChaos@de.wikipedia
      var e, s;
      for ( s in apply ) {
         e = apply[ s ];
         if ( typeof e  ===  "object"
              &&     e   &&
              typeof e.length  ===  "number" ) {
            CONFIG.feeder( s, "stringArray", e, after );
         }
      }   // for s in apply
      GUI.fresh( true );
   };   // CONFIG.feed_stringArrayObject()



   CONFIG.feed_stringArrays = function ( apply, after ) {
      // Register request as of dewiki, but by Arrays
      // Precondition:
      //    apply  -- Array, with spec
      //    after  -- boolean, with end position
      // Uses:
      //    CONFIG.feeder()
      //    GUI.fresh()
      // 2017-10-01 PerfektesChaos@de.wikipedia
      var e, i, s;
      if ( typeof apply.length  ===  "number" ) {
         for ( i = 0;  i < apply.length;  i++ ) {
            e = apply[ i ];
            if ( typeof e  ===  "object"
                 &&     e   &&
                 typeof e.length  ===  "number" ) {
               s = e[ 0 ];
               e = e[ 1 ];
               if ( typeof s  ===  "string"
                    &&     s   &&
                    typeof e  ===  "object"
                    &&     e   &&
                    typeof e.length  ===  "number" ) {
                  CONFIG.feeder( s, "stringArray", e, after );
               }
            }
         }   // for i
         GUI.fresh( true );
      }
   };   // CONFIG.feed_stringArrays()



   CONFIG.feeder = function ( assign, arranged, apply, after ) {
      // Register group panel
      // Precondition:
      //    assign    -- string, with selector
      //    arranged  -- string, with format keyword
      //    apply     -- object, with panel spec
      //    after     -- boolean, with end position
      // Uses:
      //    CONFIG.follow()
      // 2017-10-01 PerfektesChaos@de.wikipedia
      var panel = { contentmodel: true,
                    system:       arranged,
                    $panel:       false },
          s;
      if ( arranged === "builtin" ) {
         for ( s in apply ) {
            panel[ s ] = apply[ s ];
         }   // for s in apply
      } else {
         panel.def = apply;
      }
      if ( CONFIG.fit( panel ) ) {
         panel.selector = assign;
         CONFIG.follow( assign, panel, after );
      }
   };   // CONFIG.feeder()



   CONFIG.fired = function ( apply ) {
      // .config hook fired
      // Precondition:
      //    apply  -- object or boolean, with config
      // Uses:
      //    GUI.fresh()
      //    CONFIG.furnish()
      //    GUI.furnish()
      //    CONFIG.facility()
      //    CONFIG.feed()
      //    CONFIG.feed_existing()
      //    REMIND.feed()
      // 2018-11-12 PerfektesChaos@de.wikipedia
      var live;
      switch ( typeof apply ) {
         case "boolean":
            CONFIG.live = apply;
            GUI.fresh();
            break;
         case "object":
            if ( apply ) {
               if ( typeof apply.live  ===  "boolean" ) {
                  CONFIG.live = apply.live;
               }
               if ( typeof apply.position  ===  "object"
                    &&     apply.position   &&
                    typeof apply.position.length  ===  "number" ) {
                  CONFIG.furnish( apply.position );
               }
               if ( typeof apply.client  ===  "object"
                    &&     apply.client ) {
                  EDIT.client = apply.client;
               }
               if ( typeof apply.css  ===  "object"
                    &&     apply.css ) {
                  GUI.furnish( apply.css );
               }
               if ( typeof apply.hide  ===  "object"
                    &&     apply.hide    ||
                    typeof apply.hide  ===  "boolean" ) {
                  CONFIG.facility( "hide", apply.hide );
               }
               if ( typeof apply.help  ===  "object"
                    &&     apply.help    ||
                    typeof apply.help  ===  "string"    ||
                    typeof apply.help  ===  "boolean" ) {
                  CONFIG.facility( "help", apply.help );
               }
               if ( typeof apply.defs  ===  "object"
                    &&     apply.defs ) {
                  CONFIG.feed( apply.defs );
               }
               if ( typeof apply.top  ===  "object"
                    &&     apply.top   &&
                    typeof apply.top.length  ===  "number" ) {
                  CONFIG.feed_existing( apply.top );
               }
               if ( typeof apply.select  ===  "string"
                    &&     apply.select ) {
                  live = true;
                  REMIND.feed( "select", apply.select );
               }
               if ( live   ||   typeof apply.live  ===  "boolean" ) {
                  GUI.fresh( live );
               }
            }
            break;
      }   // switch typeof apply
   };   // CONFIG.fired()



   CONFIG.first = function () {
      // Initialize all
      // Uses:
      //    mw.config.get()
      //     < CONFIG.live
      //     < GUI.live
      // 2018-11-12 PerfektesChaos@de.wikipedia
      var env = mw.config.get( [ "wgAction",
                                 "wgUserName" ] );
      CONFIG.css    = false;
      CONFIG.defs   = false;
      CONFIG.exist  = false;
      CONFIG.groups = false;
      CONFIG.pos    = false;
      CONFIG.items  = 0;
      CONFIG.nsn    = env.wgNamespaceNumber;
      CONFIG.last   = false;
      CONFIG.learn  = ( env.wgAction !== "view"   ||
                        CONFIG.nsn < 0 );
      CONFIG.live   = true;
      GUI.live      = false;
      GUI.$wrappers = false;
   };   // CONFIG.first()



   CONFIG.fit = function ( ask ) {
      // Check whether content model is appropriate
      // Precondition:
      //    ask   -- object, with spec
      // Postcondition:
      //    returns true, if appropriate
      // 2017-10-01 PerfektesChaos@de.wikipedia
      var i, r, source;
      switch ( typeof ask.contentmodel ) {
         case "boolean":   // fall through
         case "string":
            r = ask.contentmodel;
            break;
         case "object":
            if ( ask.contentmodel    &&
                 typeof ask.contentmode.length  ===  "number" ) {
               r = ask.contentmodel;
            }   // fall through
         default:
            r = false;
      }   // switch typeof ask.contentmodel
      if ( typeof r  !==  "boolean" ) {
         if ( typeof CONFIG.nsn  !==  "number" ) {
            CONFIG.nsn = mw.config.get( "wgNamespaceNumber" );
         }
         switch ( CONFIG.nsn ) {
            case -1:
               source = "wikitext";
               break;
            default:
               if ( typeof CONFIG.source  !==  "string" ) {
                  CONFIG.source = mw.config.get( "wgPageContentModel" );
               }
               source = CONFIG.source;
         }   // switch wgNamespaceNumber
         if ( typeof r  ===  "object" ) {
            for ( i = r.length - 1;  i >= 0;  i-- ) {
               if ( r[ i ] === source ) {
                  r = true;
                  break;
               } else if ( ! i ) {
                  r = false;
               }
            }   // for i--
         } else {
            r = ( r === source );
         }
      }
      return r;
   };   // CONFIG.fit()



   CONFIG.follow = function ( assign, apply, after ) {
      // Put group panel into double chained list
      // Precondition:
      //    assign  -- string, with selector
      //    apply   -- object, with panel spec
      //    after   -- boolean, with end position
      // Postcondition:
      //    returns integer, with item number
      // 2018-11-08 PerfektesChaos@de.wikipedia
      var s      = CONFIG.follower( assign ),
          panels = CONFIG.groups.panels,
          old, other;
      apply.sel = s;
      if ( typeof panels[ s ]  ===  "object" ) {
         old = panels[ s ];
         if ( typeof after  ===  "boolean" ) {
            if ( old.before ) {
               other = panels[ old.before ];
               other.behind = old.behind;
               if ( ! old.behind ) {
                  CONFIG.groups.stop = other.sel;
               }
            }
            if ( old.behind ) {
               other = panels[ old.behind ];
               other.before = old.before;
               if ( ! old.before ) {
                  CONFIG.groups.start = other.sel;
               }
            }
            if ( after ) {
               if ( CONFIG.groups.stop ) {
                  other = panels[ CONFIG.groups.stop ];
                  other.behind = s;
               }
               apply.before = CONFIG.groups.stop;
               apply.behind = null;
               CONFIG.groups.stop = s;
            } else {
               if ( CONFIG.groups.start ) {
                  other = panels[ CONFIG.groups.start ];
                  other.before = s;
               }
               apply.behind = CONFIG.groups.start;
               apply.before = null;
               CONFIG.groups.start = s;
            }
         } else {
            apply.before = old.before;
            apply.behind = old.behind;
         }
      } else if ( CONFIG.items < CONFIG.maxItems ) {
         CONFIG.items++;
         apply.item = CONFIG.items;
         if ( CONFIG.groups.start ) {
            if ( after ) {
               old = panels[ CONFIG.groups.stop ];
               old.behind = s;
               CONFIG.groups.stop = s;
               apply.before = old.sel;
               apply.behind = null;
            } else {
               old = panels[ CONFIG.groups.start ];
               old.before = s;
               CONFIG.groups.start = s;
               apply.before = null;
               apply.behind = old.sel;
            }
         } else {
            CONFIG.groups.start = s;
            CONFIG.groups.stop  = s;
            apply.before = null;
            apply.behind = null;
         }
      }
      panels[ s ] = apply;
      return apply.item;
   };   // CONFIG.follow()



   CONFIG.follower = function ( assign ) {
      // Prepare group panel list manipulation
      // Precondition:
      //    assign  -- string, with selector
      // Postcondition:
      //    returns string, with standardized selector
      // 2018-11-08 PerfektesChaos@de.wikipedia
      var r;
      if ( ! CONFIG.groups ) {
         CONFIG.groups = { panels: { },
                           start:  null,
                           stop:   null };
      }
      if ( typeof assign  ===  "string" ) {
         r = assign.replace( /(\S)\s*$/, "$1" )
                   .replace( /^\s*(\S)/, "$1" );
      }
      if ( ! r ) {
         r = "UNKNOWN-"  +  ( CONFIG.items + 1 );
      }
      return r;
   };   // CONFIG.follower()



   CONFIG.forward = function ( auxilary ) {
      // Create help button
      // Precondition:
      //    auxilary  --  string, with URL, or false
      // Uses:
      //    CONFIG.facility()
      // 2018-11-12 PerfektesChaos@de.wikipedia
      CONFIG.facility( "help", auxilary );
   };   // CONFIG.forward()



   CONFIG.furnish = function ( apply ) {
      // Configure position
      // Precondition:
      //    apply  -- object, with panel spec
      // Uses:
      //    GUI.furnish()
      // 2017-11-20 PerfektesChaos@de.wikipedia
      var e, i, v;
      for ( i = apply.length - 1;  i >= 0;  i-- ) {
         e = apply[ i ];
         if ( e ) {
            v = false;
            switch ( typeof e ) {
               case "object":
                  if ( typeof e.selector  ===  "string"
                       &&     e.selector ) {
                     v = { $parents: false,
                           sel:      e.selector };
                  } else if ( typeof e.jQuery  ===  "object"
                              &&     e.jQuery    &&
                              typeof e.jQuery.jQuery  ===  "string" ) {
                     v = { $parents: e.jQuery };
                  }
                  if ( v ) {
                     if ( typeof e.lead  ===  "boolean" ) {
                        v.lead = e.lead;
                     } else {
                        v.lead = false;
                     }
                  }
                  break;
               case "string":
                  v = { lead: false,
                        sel:  e };
                  break;
            }   // switch typeof e
            if ( v ) {
               CONFIG.pos = CONFIG.pos  ||  [ ];
               if ( typeof e.last  ===  "boolean"
                    &&     e.last ) {
                  CONFIG.pos.push( v );
               } else {
                  CONFIG.pos.pop( v );
               }
            }
         }
      }   // for i--
      if ( typeof CONFIG.pos  ===  "object" ) {
         GUI.furnish();
      }
   };   // CONFIG.furnish()



   EDIT.fasten = function ( around, arglist ) {
      // Trim selection
      // Precondition:
      //    around   -- selected text
      //    arglist  -- parameters for jQuery.textSelection
      // Postcondition:
      //    Returns trimmed selected text and extends arglist
      //    >< EDIT.reWSbeg
      //     < EDIT.reWSend
      // 2018-11-29 PerfektesChaos@de.wikipedia
      var r = around,
          got/*, k, luxury*/;
      if ( r ) {
/*
         k = mw.user.options.get( "usecodemirror" );
         luxury = ( k  &&  k > 0 );
         if ( ! luxury ) {
            k = mw.user.options.get( "usecodeeditor" );
            luxury = ( k  &&  k > 0 );
         }
         if ( ! luxury ) {
*/
            if ( typeof this.reWSbeg  !==  "object" ) {
               this.reWSbeg = new RegExp( "^\\s+" );
               this.reWSend = new RegExp( "\\S(\\s+)$" );
            }
            got = this.reWSbeg.exec( r );
            if ( got ) {
               if ( typeof arglist.pre  ===  "string" ) {
                  arglist.pre = got[ 0 ] + arglist.pre;
               } else {
                  arglist.pre = got[ 0 ];
               }
               r = r.substr( got[ 0 ].length );
            }
            got = this.reWSend.exec( r );
            if ( got ) {
               if ( typeof arglist.post  ===  "string" ) {
                  arglist.post = arglist.post + got[ 1 ];
               } else {
                  arglist.post = got[ 1 ];
               }
               r = r.substr( 0,  r.length - got[ 1 ].length );
            }
/*
         }
*/
      }
      return r;
   };   // EDIT.fasten()



   EDIT.fiat = function ( $area, action, arglist ) {
      // Source text action
      // Precondition:
      //    $area    -- text $object
      //    action   -- string, with jQuery.textSelection action
      //    arglist  -- object, with jQuery.textSelection parameters
      // 2018-06-15 PerfektesChaos@de.wikipedia
      if ( typeof EDIT.client  ===  "object"   &&
           typeof EDIT.client.lfDoubled  ===  "boolean"
           &&     EDIT.client.lfDoubled ) {
         this.fossile( $area, action, arglist );
      } else {
         $area.textSelection( action, arglist );
      }
   };   // EDIT.fiat()



   EDIT.fossile = function ( $area, action, arglist ) {
      // Support ancient CRLF
      // Precondition:
      //    $area    -- text $object
      //    action   -- string, with jQuery.textSelection action
      //    arglist  -- object, with jQuery.textSelection parameters
      // Postcondition:
      //    Returns request
      // Uses:
      //    >< EDIT.reCRLF
      //    EDIT.fasten()
      // 2018-06-15 PerfektesChaos@de.wikipedia
      var textarea = $area.get( 0 ),
          iBeg     = textarea.selectionStart  ||  0,
          iEnd     = textarea.selectionEnd    ||  iBeg,
          story    = $area.val(),
          r, sel, sub, suffix;
      if ( typeof this.reCRLF  !==  "object" ) {
         this.reCRLF = new RegExp( "\r?\n", "g" );
      }
      if ( action === "encapsulateSelection" ) {
         story  = story.replace( this.reCRLF, "\r\n" );
         sub    = story.slice( 0, iEnd )
                       .replace( this.reCRLF, "\n" );
         iBeg   = story.slice( 0, iBeg )
                       .replace( this.reCRLF, "\n" ).length;
         suffix = story.slice( iEnd );
         story  = sub.slice( 0, iBeg );
         if ( ! arglist.replace ) {
            sel = sub.slice( iBeg );
            sel = this.fasten( sel, arglist );
         }
         if ( typeof arglist.pre  ===  "string" ) {
            story = story + arglist.pre;
         }
         if ( arglist.replace ) {
            if ( typeof arglist.peri  ===  "string" ) {
               story = story + arglist.peri;
            }
         } else {
            story = story + sel;
         }
         if ( typeof arglist.post  ===  "string" ) {
            story = story + arglist.post;
         }
         iEnd  = story.replace( this.reCRLF, "\r\n" ).length;
         story = story + suffix;
         $area.val( story );
         textarea.selectionEnd   = iEnd;
         textarea.selectionStart = iBeg;
         $area.focus();
         textarea.selectionEnd   = iEnd;
         textarea.selectionStart = iEnd;
      }
      return r;
   };   // EDIT.fossile()



   GUI.facet = function ( $area, assign ) {
      // Selectors for panel
      // Precondition:
      //    $area   -- panel $object
      //    assign  -- string, with selector
      // 2017-10-01 PerfektesChaos@de.wikipedia
      $area.addClass( Sign + "-panel " +
                      Sign + "-panel-" + assign );
   };   // GUI.facet()



   GUI.facility = function ( access ) {
      // Create auxilary buttons
      // Precondition:
      //    access  -- "help" or "hide"
      // Uses:
      //    REMIND.feed()
      // 2018-11-30 PerfektesChaos@de.wikipedia
      var config = CONFIG[ access ],
          i, live, $btn, $collection;
      if ( typeof config.$btn  !==  "object"   &&
           config.mode > 0 ) {
         config.$btn = $( "<a>" );
         config.$btn.addClass( Sign + "-" + access + "-button" )
                    .attr( { "href":  "#" + Sign + "-0",
                             "title": config.support } )
                    .css( config.css )
                    .css( { "text-decoration": "none" } )
                    .text( config.show );
         if ( config[ "class" ]  ===  "string" ) {
            config.$btn.addClass( config[ "class" ] );
         }
         if ( config.support  ===  "string" ) {
            config.$btn.attr( { "title": config.support } );
         }
         if ( config.service ) {
            config.$btn.attr( { "href":   config.service,
                                "target": "_blank" } );
         }
      }
      if ( GUI.$wrappers && GUI.$wrappers.length ) {
         $collection = GUI[ config.suite ];
         $collection.empty();
         live = ( config.mode > 0 );
         if ( live  &&  access === "hide" ) {
            live = ( REMIND.feed( "less" )  !==  true );
         }
         if ( live ) {
            $btn = config.$btn.clone();
            if ( config.start ) {
               $btn.click( GUI[ config.start ] );
            }
            $collection.eq( 0 ).append( $btn );
            for ( i = 1;  i < $collection.length;  i++ ) {
               $btn = config.$btn.clone();
               if ( config.start ) {
                  $btn.click( GUI[ config.start ] );
               }
               $collection.eq( i ).append( $btn );
            }   // for i
         }
      }
   };   // GUI.facility()



   GUI.factory_builtin = function ( assigned ) {
      // Create panel from object
      // Precondition:
      //    assigned  -- object, with panel spec
      // Postcondition:
      //    returns panel $object
      // 2018-11-08 PerfektesChaos@de.wikipedia
      var $r = $( "<div>" ),
          def, e, i, label, link, low, s, space, src, $e, $img;
      if ( typeof assigned[ "class" ]  ===  "string" ) {
         $r.addClass( assigned[ "class" ] );
      }
      if ( typeof assigned.style  ===  "string" ) {
         $r.attr( { "style": assigned.style } );
      }
      if ( typeof assigned.ltr  ===  "boolean" ) {
         $r.attr( { "dir":  ( assigned.ltr ? "ltr" : "rtl" ) } );
      }
      if ( typeof assigned.lang  ===  "string" ) {
         $r.attr( { "lang": assigned.lang } );
      }
      if ( typeof assigned.support  ===  "string" ) {
         $r.attr( { "title": assigned.support } );
      }
      if ( typeof assigned.def  ===  "object"
           &&     assigned.def   &&
           typeof assigned.def.length  ===  "number" ) {
         def = assigned.def;
         for ( i = 0;  i < def.length;  i++ ) {
            e = def[ i ];
            s = false;
            if ( typeof e  ===  "object"
                 &&     e ) {
               if ( typeof e.fun  ===  "function" ) {
                  e.id = i;
                  link = true;
               } else {
                  if ( typeof e.sample  ===  "string"
                       &&     e.sample ) {
                     s = e.sample;
                  }
                  if ( typeof e.start  ===  "string"
                       &&     e.start ) {
                     s = e.start;
                     if ( typeof e.suffix  ===  "string"
                          &&     e.suffix ) {
                        s = s + e.suffix;
                     }
                  } else if ( typeof e.suffix  ===  "string"
                              &&     e.suffix ) {
                     s = e.suffix;
                  }
                  link = ( s ? true : false );
               }
               if ( typeof e.show  ===  "string"
                    &&     e.show ) {
                  s   = e.show;
                  low = false;
               } else {
                  low = true;
               }
               if ( typeof e.src  ===  "string"
                    &&     e.src ) {
                  s = s || true;
               }
               switch ( typeof e.contentmodel ) {
                  case "boolean":
                  case "object":
                  case "string":
                     if ( ! CONFIG.fit( e ) ) {
                        s = false;
                     }
                     break;
               }   // switch typeof e.contentmodel
            }
            if ( s ) {
               if ( link ) {
                  if ( ! CONFIG.defs ) {
                     CONFIG.defs = [ ];
                  }
                  $e = $( "<a>" );
                  $e.attr( { "data-id": CONFIG.defs.length,
                             "href":    "#" } )
//                  .data( "id", CONFIG.defs.length )
                    .click( GUI.fiat );
                  CONFIG.defs.push( e );
               } else {
                  $e = $( "<span>" );
               }
               if ( typeof e.src  ===  "string" ) {
                  if ( e.src.charCodeAt( 0 ) === 47   &&
                       e.src.charCodeAt( 0 ) !== 47 ) {   // "/path"
                     src = e.src;
                  } else {
                     if ( typeof CONFIG.reURL  !==  "object" ) {
                        CONFIG.reURL = new RegExp( "^(?:https?:)?"
                                                   + "//[^/]*\\."
                                                   + "(?:mediawiki"
                                                   +   "|wik"
                                                   +       "(?:i"
                                                   +         "(?:books"
                                                   +           "|data"
                                                   +           "|media"
                                                   +           "|news"
                                                   +           "|pedia"
                                                   +           "|quote"
                                                   +           "|source"
                                                   +           "|species"
                                                   +           "|tech"
                                                   +           "|versity"
                                                   +           "|voyage)"
                                                   +         "|tionary))"
                                                   + "\\.org/" );
                     }
                     if ( CONFIG.reURL.test( e.src ) ) {
                        src = e.src;
                     } else {
                        src = false;
                     }
                  }
                  if ( src ) {
                     $img = $( "<img>" );
                     $img.attr( { "src": src } );
                     $e.prepend( $img );
                     label = true;
                  }
               }
               if ( typeof s  ===  "string" ) {
                  if ( low ) {
                     $e.text( s );
                     label = true;
                  } else {
                     $e.html( s );
                     label = $e.text();
                  }
               }
               if ( label ) {
                  switch ( typeof e.style ) {
                     case "string":
                        $e.attr( { "style": e.style } );
                        break;
                     case "object":
                        $e.css( e.style );
                        break;
                  }   // switch typeof e.style
                  if ( typeof e[ "class" ]  ===  "string" ) {
                     $e.addClass( e[ "class" ] );
                  }
                  if ( typeof e.support  ===  "string" ) {
                     $e.attr( { "title": e.support } );
                  }
                  if ( link ) {
                     $e.css( { "text-decoration": "none",
                               "white-space":     "nowrap" } );
                  }
                  if ( $r ) {
                     switch ( typeof e.space ) {
                        case "string":
                           space = e.space;
                           break;
                        case "number":
                           String.fromCharCode( e.space );
                           break;
                        default:
                           space = " ";
                     }   // switch typeof e.space
                  } else {
                     space = false;
                  }
                  $r = ( $r  ||  $( "<div>" ) );
                  if ( GUI.ltr ) {
                     if ( space && link ) {
                        $r.append( space );
                     }
                     $r.append( $e );
                  } else {
                     if ( space && link ) {
                        $r.prepend( space );
                     }
                     $r.prepend( $e );
                  }
               }
            }
         }   // for i
      }
      return $r;
   };   // GUI.factory_builtin()



   GUI.factory_stringArray = function ( assigned ) {
      // Create panel from stringArray
      // Precondition:
      //    assigned  -- object, with panel spec
      // Postcondition:
      //    returns panel $object
      // 2018-11-08 PerfektesChaos@de.wikipedia
      var elem, elt, i, j, lead, panel, unit, $r;
      if ( typeof assigned.def  ===  "object"
           &&     assigned.def   &&
           typeof assigned.def.length  ===  "number" ) {
         panel = { def: [ ] };
         for ( i = 0;  i < assigned.def.length;  i++ ) {
            if ( i  &&  ! lead ) {
               lead = false;
               panel.def.push(  { show:  "&#160;&#160;&#8226;&#160; ",
                                  style: { "font-weight": "bold" } }  );
            }
            unit = assigned.def[ i ];
            if ( typeof unit  ===  "object"
                 &&     unit ) {
               if ( typeof unit.length  ===  "number" ) {
                  for ( j = 0;  j < unit.length;  j++ ) {
                     elem = unit[ j ];
                     switch ( typeof elem ) {
                        case "string":
                           panel.def.push(  { start: elem }  );
                           break;
                        case "object":
                           if ( elem    &&
                                typeof elem.length  ===  "number" ) {
                              elt = { };
                              if ( typeof elem[ 0 ]  ===  "string"
                                   &&     elem[ 0 ] ) {
                                 elt.start = elem[ 0 ];
                              }
                              if ( typeof elem[ 1 ]  ===  "string"
                                   &&     elem[ 1 ] ) {
                                 elt.suffix = elem[ 1 ];
                              }
                              if ( typeof elem[ 2 ]  ===  "string"
                                   &&     elem[ 2 ] ) {
                                 elt.sample = elem[ 2 ];
                              }
                              if ( typeof elem[ 3 ]  ===  "string"
                                   &&     elem[ 3 ] ) {
                                 elt.support = elem[ 3 ];
                              }
                              if ( typeof elem[ 4 ]  ===  "string"
                                   &&     elem[ 4 ] ) {
                                 elt.show = elem[ 4 ];
                              }
                              panel.def.push( elt );
                           }
                           break;
                     }   // switch typeof elem
                  }   // for j
               } else if ( ! i ) {
                  lead = true;
                  if ( typeof unit[ "class" ]  ===  "string"
                       &&     unit[ "class" ] ) {
                     panel[ "class" ] = unit[ "class" ];
                  }
                  if ( typeof unit[ "font-size" ]  ===  "string"
                       &&     unit[ "font-size" ] ) {
                     /*
                     panel.style = { "font-size":
                                     unit[ "font-size" ] };
                     */
                     panel.style = "font-size:" + unit[ "font-size" ];
                  }
                  if ( typeof unit.lang  ===  "string"
                       &&     unit.lang ) {
                     panel.lang = unit.lang;
                  }
                  if ( typeof unit.ltr  ===  "boolean" ) {
                     panel.ltr = unit.ltr;
                  }
                  // unit.direction
               }
            }   // for i
         }
         if ( panel.def.length ) {
            $r = GUI.factory_builtin( panel );
         }
      }
      return $r;
   };   // GUI.factory_stringArray()



   GUI.faculty = function () {
      // Create or update panel selection element
      // Uses:
      //    GUI.facility()
      //    REMIND.fetch()
      //    (GUI.fold)
      // 2018-11-30 PerfektesChaos@de.wikipedia
      var e, i, s, $o;
      if ( GUI.$poly ) {
         GUI.$poly.empty();
      } else if ( CONFIG.groups ) {
         GUI.$poly = $( "<select>" );
         GUI.$poly.css( { "display":         "inline",
                          "float":           ( GUI.ltr ? "left" :
                                                         "right" ),
                          "margin-bottom":   "0.5em",
                          "vertical-align":  "middle" } );
         if ( GUI.ltr ) {
            GUI.$poly.css( { "float":        "left",
                             "margin-right": "0.5em" } );
         } else {
            GUI.$poly.css( { "float":        "right",
                             "margin-left":  "0.5em" } );
         }
         GUI.$wrappers.eq( 0 ).prepend( GUI.$poly );
         for ( i = 1;  i < GUI.$wrappers.length;  i++ ) {
            GUI.$wrappers.eq( i ).prepend( GUI.$poly.clone() );
         }   // for i
         GUI.$poly = GUI.$wrappers.children( "select" );
         if ( typeof CONFIG.help  ===  "object" ) {
            GUI.facility( "help" );
         }
         if ( typeof CONFIG.hide  ===  "object" ) {
            GUI.facility( "hide" );
         }
         GUI.$poly.change( GUI.fold )
                  .click( GUI.fold );
      }
      if ( CONFIG.groups ) {
         s = CONFIG.groups.start;
         do  {
            e = CONFIG.groups.panels[ s ];
            if ( e    &&
                 ( CONFIG.learn   ||
                   typeof e.low !==  "boolean"
                   ||     e.low ) ) {
               $o = $( "<option>" );
               $o.attr( "data-item", e.item )
//               .data( "item", e.item )
                 .text( e.sel );
               GUI.$poly.eq( 0 ).append( $o );
               for ( i = 1;  i < GUI.$poly.length;  i++ ) {
                  GUI.$poly.eq( i ).append( $o.clone() );
               }   // for i
               s = e.behind;
            }
         } while ( e && s );   // do until ! e && s
         if ( CONFIG.learn ) {
            s = REMIND.fetch( "select" );
            if ( s ) {
               GUI.select = s;
               GUI.$poly.prop( "value", s );
            }
         }
         if ( !  REMIND.fetch( "less" ) ) {
            GUI.$poly.trigger( "click" );
         }
      }
   };   // GUI.faculty()



   GUI.fade = function ( action ) {
      // On hide buttons
      // Precondition:
      //    action  -- object with event, or not
      // Uses:
      //    >  GUI.$wrappers
      //    >  Sign
      //    REMIND.feed()
      // 2018-11-29 PerfektesChaos@de.wikipedia
      var $btn, $parent;
      if ( action ) {
         $btn    = $( action.target ).parent();
         $parent = $btn.parent();
         if ( CONFIG.hide.mode > 1 ) {
            $parent.hide();
         } else {
            $parent.find( "div" ).hide();
         }
      } else if ( GUI.$wrappers && GUI.$wrappers.length ) {
         GUI.$wrappers.find( "." + Sign + "-panel " ).hide();
         if ( GUI.$hiders ) {
            GUI.$hiders.empty();
         }
      }
      REMIND.feed( "less", true );
   };   // GUI.fade()



   GUI.fetch = function () {
      // Text element blurred
      // Uses:
      //    >< GUI.$texts
      //    (GUI.fetch)
      //    (GUI.focus)
      // 2020-10-20 PerfektesChaos@de.wikipedia
      if ( GUI.$texts ) {
         GUI.$texts.off( "blur", GUI.fetch );
         $( window.document ).off( "focus",
                                   "textarea,input:text",
                                   GUI.focus );
      }
      GUI.$texts = $( "textarea,input:text" ).not( "*:disabled" )
                                             .not( '*[type="hidden"]' )
                                             .not( "#wpAntispam" );
                                             // readonly=""
      if ( GUI.$texts.length ) {
         $( window.document ).on( "focus",
                                  "textarea,input:text",
                                  GUI.focus );
         GUI.$texts.on( "blur", GUI.fetch );
      }
   };   // GUI.fetch()



   GUI.fiat = function ( event ) {
      // Action link clicked
      // Precondition:
      //    event  -- object, with event
      // Uses:
      //    >  GUI.received
      //    EDIT.fasten()
      //    EDIT.fiat()
      // 2018-11-29 PerfektesChaos@de.wikipedia
      var $item = $( event.target ),
          item  = parseInt( $item.data( "id" ),  10 ),
          def   = CONFIG.defs[ item ],
          params, sel, suffix, veFrag, veSurface, veSModel, $elt;
      if ( def ) {
         if ( typeof window.ve  ===  "object"
              &&     window.ve   &&
              typeof window.ve.init  ===  "object"
              &&     window.ve.init   &&
              typeof window.ve.init.target  ===  "object"
              &&     window.ve.init.target
              &&     window.ve.init.target.active ) {
            veSurface = window.ve.init.target.getSurface();
            veSModel  = veSurface.getModel();
            veFrag    = veSModel.getFragment();
            if ( ! veFrag.isNull() ) {
               if ( typeof def.low  ===  "boolean"
                    &&     def.low ) {
               } else if ( typeof def.fun  ===  "function" ) {
                  sel = def.fun( def, event, false, veSModel );
                  if ( typeof sel  !==  "string" ) {
                     sel = false;
                  }
               } else {
                  if ( typeof def.start  ===  "string" ) {
                     sel = def.start;
                  }
                  if ( typeof def.suffix  ===  "string" ) {
                     suffix = def.suffix;
                  }
               }
               if ( event.ctrlKey ) {
                  veFrag.remove();
               }
               if ( typeof def.leave  ===  "boolean"
                    &&   ! def.leave       &&
                    typeof def.sample  ===  "string" ) {
                  sel = def.sample;
                  veFrag.remove();
                  suffix = false;
               }
               if ( sel ) {
                  veFrag.insertContent( sel );
               }
               if ( suffix ) {
                  veFrag.collapseToEnd().insertContent( suffix );
               }
            }
         } else {
            if ( GUI.received ) {
               $elt = $( GUI.received );
            } else {
               $elt = GUI.$texts.eq( 0 );
            }
            if ( $elt.length ) {
               if ( typeof def.fun  ===  "function" ) {
                  params = def.fun( def, event, $elt );
                  switch ( typeof params ) {
                     case "object":
                        break;
                     case "string":
                        params = { peri:    params,
                                   replace: true };
                        break;
                     default:
                        params = false;
                  }   // switch typeof params
               } else if ( typeof def.leave  ===  "boolean"
                    &&   ! def.leave ) {
                  if ( typeof def.sample  ===  "string" ) {
                     params = { peri:    def.sample,
                                replace: true };
                  }
               } else {
                  params = { replace: ( event.ctrlKey ? true
                                                      : false ) };
                  if ( typeof def.start  ===  "string" ) {
                     params.pre = def.start;
                  }
                  if ( typeof def.suffix  ===  "string" ) {
                     params.post = def.suffix;
                  }
                  if ( typeof def.sample  ===  "string" ) {
                     sel = $elt.textSelection( "getSelection" );
                  } else {
                     sel = ! params.replace;
                  }
                  if ( sel ) {
                     if ( typeof sel  !==  "string" ) {
                        sel = $elt.textSelection( "getSelection" );
                     }
                     params.peri    = EDIT.fasten( sel, params );
                     params.replace = true;
                  } else {
                     params.peri = def.sample;
                  }
                  if ( typeof def.lonely  ===  "boolean" ) {
                     params.ownline = true;
                  }
               }
               if ( params ) {
                  EDIT.fiat( $elt, "encapsulateSelection", params );
               }
            }
         }
      }
      if ( typeof event.preventDefault  ===  "function" ) {
         event.preventDefault();
      }
      if ( typeof event.stopPropagation  ===  "function" ) {
         event.stopPropagation();
      }
   };   // GUI.fiat()



   GUI.finished = function ( about ) {
      // GUI initialization completed
      // Precondition:
      //    about  -- string, with state info
      // Uses:
      //    >  Support
      //    >  Signature
      //    >  Version
      //    mw.hook()
      // 2018-11-07 PerfektesChaos@de.wikipedia
      mw.hook( Signature + ".ready" ).fire( { doc:   "[[" +
                                                     Support + "]]",
                                              state: about,
                                              type:  Signature,
                                              vsn:   Version,
                                              fire:  CONFIG.fired } );
   };   // GUI.finished()



   GUI.fire = function () {
      // DOM is ready
      // Uses:
      //    >  CONFIG.live
      //     < GUI.$texts
      //     < GUI.received
      //     < GUI.live
      //    GUI.fetch()
      //    mw.loader.using()
      //    GUI.fired()
      //    (GUI.focus)
      // 2020-10-20 PerfektesChaos@de.wikipedia
      if ( CONFIG.live ) {
         if ( typeof GUI.live  ===  "boolean"
              &&   ! GUI.live ) {
            GUI.$texts = false;
            GUI.fetch();
            if ( GUI.$texts.length ) {
               GUI.live      = true;
               GUI.ltr       = ( $( "html" ).attr( "dir" )  !==  "rtl" );
               GUI.received  = false;
               GUI.select    = false;
               GUI.$poly     = false;
               GUI.$wrappers = false;
               GUI.flip();
               mw.loader.using( [ "user",
                                  "user.options",
                                  "mediawiki.user",
                                  "jquery.textSelection" ],
                                GUI.fired );
            }
         }
      } else if ( typeof GUI.live  !==  "boolean"
                  ||   ! GUI.live ) {
         GUI.fired();
      }
   };   // GUI.fire()



   GUI.fired = function () {
      // All modules ready
      // Uses:
      //    >  CONFIG.live
      //    GUI.fresh()
      //    GUI.finished()
      // 2017-11-14 PerfektesChaos@de.wikipedia
      var say;
      if ( typeof GUI.live  !==  "boolean" ) {
         GUI.live = false;
      }
      if ( CONFIG.live ) {
         say = "built";
      } else {
         say = "biocked";
      }
      GUI.fresh( true );
      GUI.finished( say );
   };   // GUI.fired()



   GUI.flip = function () {
      // Move an existing toolset (<charinsert>)
      // Uses:
      //    GUI.furnish()
      //    CONFIG.follow()
      //    GUI.facet()
      //    GUI.features()
      //    GUI.fresh()
      // 2017-11-17 PerfektesChaos@de.wikipedia
      var i, k, s, $e, $groups, $previous;
      if ( GUI.live && CONFIG.exist && CONFIG.pos && CONFIG.live ) {
         $previous = $( CONFIG.exist.selector );
         if ( $previous.length === 1 ) {
            $previous.hide();
            GUI.furnish();
            if ( GUI.$wrappers ) {
               if ( typeof CONFIG.exist.segments  ===  "string"
                    &&     CONFIG.exist.segments ) {
                  //   for in  $previous  .css( style )
                  s = $previous.attr( "title" );
                  if ( s ) {
                     GUI.$wrappers.attr( "title", s );
                  }
                  $groups = $previous.find( CONFIG.exist.segments );
                  for ( i = 0;  i < $groups.length;  i++ ) {
                     $e = $groups.eq( i );
                     $e.hide();
                     k = CONFIG.follow( $e.attr( "title" )  ||
                                        $e.attr( "id" ),
                                        { $panels: [ $e ] },
                                        true );
                     GUI.facet( $e, k );
                     GUI.$wrappers.append( $e );
                  }   // for i
                  $previous.empty();
               }
            } else {
               $previous.show();
            }
         }
         GUI.fresh( true );
         CONFIG.exist = false;
      }
   };   // GUI.flip()



   GUI.focus = function ( event ) {
      // Text element got focus
      // Precondition:
      //    event  -- object, with event
      // Uses:
      //     < GUI.received
      // 2017-10-01 PerfektesChaos@de.wikipedia
      GUI.received = event.target;
   };   // GUI.focus()



   GUI.fold = function ( event ) {
      // Panel selection item clicked or triggered
      // Precondition:
      //    event  -- object, with event
      // Uses:
      //    REMIND.feed()
      //    GUI.factory_***()
      //    GUI.facet()
      // 2018-11-30 PerfektesChaos@de.wikipedia
      var $poly   = $( event.target ),
          sel     = $poly.prop( "value" ),
          $item   = $poly.find( ":selected" ),
          index   = $item.data( "item" ),
          sign    = "." + Sign + "-panel",
          signX   = sign + "-" + index,
          $parent = $poly.parent(),
          $panels = $parent.children( sign ),
          $panel  = $parent.find( signX ),
          panel, shift;
      if ( CONFIG.learn   &&
           GUI.select     &&
           typeof CONFIG.groups.panels[ GUI.select ]  ===  "object" ) {
         GUI.select = sel;
         REMIND.feed( "select", sel );
      }
      $panels.not( signX ).hide();
      if ( $panel.length ) {
         $panel.show();
         $parent.find( "." + Sign + "-hide" ).show();
      } else {
         panel = CONFIG.groups.panels[ sel ];
         if ( typeof panel  ===  "object" ) {
            if ( panel.$panel ) {
               $panel = panel.$panel.clone().show();
            } else {
               shift = "factory_" + panel.system;
               if ( typeof GUI[ shift ]  ===  "function" ) {
                  $panel = GUI[ shift ]( panel );
                  if ( $panel ) {
                     GUI.facet( $panel, index );
                     panel.$panel = $panel;
                  }
               }
            }
            if ( $panel ) {
               $parent.append( $panel );
            }
         }
      }
      if ( typeof REMIND.fetch( "less" )  ===  "boolean" ) {
         REMIND.feed( "less", false );
      }
   };   // GUI.fold()



   GUI.fresh = function ( apply ) {
      // Create or update GUI
      // Precondition:
      //    apply  -- boolean, to influence panel selection element
      // Uses:
      //    GUI.fire()
      //    GUI.furnish()
      //    GUI.faculty()
      // 2017-10-01 PerfektesChaos@de.wikipedia
      GUI.fire();
      GUI.furnish();
      if ( GUI.$wrappers ) {
         if ( CONFIG.live ) {
            if ( apply ) {
               GUI.faculty();
            }
            GUI.$wrappers.show();
         } else {
            GUI.$wrappers.hide();
         }
      }
   };   // GUI.fresh()



   GUI.furnish = function ( appearance ) {
      // Create $wrapper in page
      // Precondition:
      //    appearance  -- object, with CSS, or not
      // Uses:
      //    >  Sign
      //    >  Signature
      //    mw.hook()
      // 2019-01-17 PerfektesChaos@de.wikipedia
      var e, i, j, k, m, seq, $wrap;
      if ( GUI.live  &&  CONFIG.live  &&  CONFIG.pos  &&
           ! GUI.$wrappers ) {
         for ( i = 0;  i < CONFIG.pos.length;  i++ ) {
            e = CONFIG.pos[ i ];
            if ( ! e.$parents ) {
               e.$parents = $( e.sel );   // [type="hidden"]
            }
            m = e.$parents.length;
            if ( m ) {
               GUI.$wrappers = $( "<div>" );
               GUI.$wrappers.addClass( Sign )
                            .css( GUI.css );
               GUI.$helpers = $( "<div>" );
               GUI.$helpers.addClass( Sign + "-help" )
                           .attr( { "id":  Sign + "-0" } )
                           .css( { "float": ( GUI.ltr ? "right" :
                                                        "left" ) } );
               GUI.$hiders = $( "<div>" );
               GUI.$hiders.addClass( Sign + "-hide" )
                          .attr( { "id":  Sign + "-1" } )
                          .css( { "float": ( GUI.ltr ? "right" :
                                                       "left" ) } );
               seq = ( e.lead ? "before" : "after" );
               e.$parents.eq( 0 )[ seq ]( GUI.$wrappers );
               for ( k = 1;  k < m;  k++ ) {
                  $wrap = GUI.$wrappers.clone();
                  j     = k + k;
                  $wrap.append( GUI.$helpers.clone() )
                       .attr( { "id":  Sign + "-" + j } );
                  j++;
                  $wrap.append( GUI.$hiders.clone() )
                       .attr( { "id":  Sign + "-" + j } );
                  e.$parents.eq( k )[ seq ]( $wrap );
               }   // for k
               GUI.$wrappers.append( GUI.$hiders );
               GUI.$wrappers.append( GUI.$helpers );
               if ( m > 1 ) {
                  GUI.$wrappers = $( "." + Sign );
                  GUI.$helpers  = $( "." + Sign + "-help" );
                  GUI.$hiders   = $( "." + Sign + "-hide" );
               }
               mw.hook( Signature + ".created" ).fire( GUI.$wrappers );
               break;   // for i
            }
         }   // for i
      }
      if ( appearance ) {
         CONFIG.css = appearance;
      }
      if ( CONFIG.css  &&  GUI.$wrappers ) {
         GUI.$wrappers.css( CONFIG.css );
      }
   };   // GUI.furnish()



   REMIND.feed = function ( sign, val ) {
      // Store value at sign
      // Precondition:
      //    sign   -- string, with group ID
      //    val    -- any value
      // Uses:
      //    >< REMIND.o
      //    REMIND.fetch()
      // 2017-10-01 PerfektesChaos@de.wikipedia
      var webSs;
      if ( typeof REMIND.o  !==  "object" ) {
         REMIND.fetch( "" );
      }
      REMIND.o[ sign ] = val;
      if ( typeof window.sessionStorage  ===  "object" ) {
         webSs = window.sessionStorage;
         if ( webSs   &&   typeof webSs.setItem  ===  "function" ) {
            try {
               if ( typeof REMIND.w  !==  "object" ) {
                  REMIND.w = { };
               }
               REMIND.w[ REMIND.fragment() ] = REMIND.o;
               webSs.setItem( REMIND.full(),
                              JSON.stringify( REMIND.w ) );
            } catch (e) {
            }
         }
      }
   };   // REMIND.feed()



   REMIND.fetch = function ( sign ) {
      // Retrieve value at sign
      // Precondition:
      //    sign   -- string, with group ID
      // Uses:
      //    >  REMIND.sub
      //     < REMIND.w
      //     < REMIND.o
      //    REMIND.full()
      //    REMIND.fragment()
      // 2017-10-01 PerfektesChaos@de.wikipedia
      var got, r, webSs;
      if ( typeof REMIND.o  !==  "object"   &&
           typeof window.sessionStorage  ===  "object" ) {
         webSs = window.sessionStorage;
         if ( webSs   &&   typeof webSs.getItem  ===  "function" ) {
            try {
               got = JSON.parse( webSs.getItem( REMIND.full() ) );
               if ( typeof got  ===  "object"
                    &&     got ) {
                  REMIND.w = got;
                  if ( typeof got[ REMIND.fragment() ]  ===  "object" ) {
                     REMIND.o = got[ REMIND.sub ];
                  }
               }
            } catch (e) {
            }
         }
      }
      if ( typeof REMIND.o  !==  "object" ) {
         REMIND.o = { };
      }
      if ( typeof REMIND.o[ sign ]  !==  "undefined" ) {
         r = REMIND.o[ sign ];
      }
      return r;
   };   // REMIND.fetch()



   REMIND.fragment = function () {
      // Provide page selector
      // Uses:
      //    >< REMIND.sub
      //    mw.config.get()
      // 2017-10-01 PerfektesChaos@de.wikipedia
      if ( typeof REMIND.sub  !==  "string" ) {
         REMIND.sub = mw.config.get( "wgRevisionId" );
         if ( ! REMIND.sub  ||  REMIND.sub <= 0 ) {
            REMIND.sub = mw.config.get( "wgTitle" );
         }
      }
      return REMIND.sub;
   };   // REMIND.fragment()



   REMIND.full = function () {
      // Provide project selector
      // Uses:
      //    >  Sign
      //    >< REMIND.sign
      //    mw.config.get()
      // 2017-10-01 PerfektesChaos@de.wikipedia
      if ( typeof REMIND.sign  !==  "string" ) {
         REMIND.sign = Sign + "." + mw.config.get( "wgDBname" );
      }
      return REMIND.sign;
   };   // REMIND.full()



   fire();
}( mediaWiki, jQuery ) );



/// EOF </nowiki>   menuSwitcher/d.js