User:PerfektesChaos/js/lintHint/d.js

This is an old revision of this page, as edited by PerfektesChaos (talk | contribs) at 19:36, 9 February 2018 (-2.15). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
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.
/// User:PerfektesChaos/js/lintHint/d.js
//  Show LintErrors analysis live
/// 2018-02-08 PerfektesChaos@de.wikipedia
//  ResourceLoader:  compatible;
//    dependencies: user, mw.API
/// Fingerprint: #0#0#
/// @license GPL [//www.mediawiki.org/w/COPYING] (+GFDL, LGPL, CC-BY-SA)
/// <nowiki>
/* global window: false                                                */
/* jshint forin: false,
          bitwise:true, curly:true, eqeqeq:true, latedef:true,
          laxbreak:true,
          nocomma:true, strict:true, undef:true, unused:true           */



( function ( mw, $ ) {
   "use strict";
   var Version   = -2.15,
       Signature = "lintHint",
       HINT      = { cmodels:   { "wikitext":        true,
                                  "proofread-index": true,
                                  "proofread-page":  true },
                     doc:       "en:User:PerfektesChaos/js/" + Signature,
                     errors:    [ "bogus-image-options",
                                  "deletable-table-tag",
                                  "fostered",
                                  "html5-misnesting",
                                  "ignored-table-attr",
                                  "misc-tidy-replacement-issues",
                                  "misnested-tag",
                                  "missing-end-tag",
                                  "missing-start-tag",
                                  "mixed-content",
                                  "multi-colon-escape",
                                  "multiline-html-table-in-list",
                                  "multiple-unclosed-formatting-tags",
                                  "obsolete-tag",
                                  "pwrap-bug-workaround",
                                  "self-closed-tag",
                                  "stripped-tag",
                                  "tidy-font-bug",
                                  "tidy-whitespace-bug",
                                  "unclosed-quotes-in-heading" ],
                     idRev:     0,
                     last:      true,
                     later:     false,
                     launch:    false,
                     launched:  false,
                     layer:     false,
                     lazy:      false,
                     live:      false,
                     ltr:       true,
                     source:    false,
                     using:     [ "mediawiki.api",
                                  "mediawiki.api.messages",
                                  "mediawiki.util" ],
                     $body:     false,
                     $page:     false,
                     $textarea: false },
       API       = { Api:     false,
                     errors:  false,
                     scream:  false,
                     service: "transform/wikitext/to/lint" },
       BOX       = { bgc:        "FFFF00",
                     bgcErr:     "FFE4E1",
                     bgcOk:      "ADFF2F",
                     bgcRun:     "C0C0C0",
                     boc:        "808080",
                     fgc:        "000000",
                     fgcRun:     "A0A0A0",
                     swift:      false,
                     $box:       false,
                     $collapsed: false,
                     $failure:   false,
                     $null:      false,
                     $other:     false,
                     $pagename:  false,
                     $swift:     false,
                     $tbody:     false,
                     $table:     false,
                     $top:       false },
       EDIT      = { listen:  false,
                     live:    false,
                     $source: false },
       GUIDER    = { last:   false,
                     live:   false,
                     reTrim: false,
                     using:  [ "jquery.textSelection",
                               "mediawiki.ui.button",
                               "mediawiki.ui.input" ],
                     $pagename: false },
       LINTER    = { },
       PREGO     = { app:       false,
                     signature: "preferencesGadgetOptions" },
       TEACH     = { };



   HINT.texts = {
      // 2017-10-06 PerfektesChaos@de.wikipedia
      "desc":   {"en": "Show LintErrors analysis live.",
                 "de": "Zeige LintErrors-Analyse live."},
      "___domain": {"en": "en.wikipedia.org",
                 "de": "de.wikipedia.org"},
      "howTo":  {"en": "Fill balanced wikitext into first input area"
                       + " and press adjacent submit button,"
                       + " or enter page name into second input field.",
                 "de": "Füge ausgeglichenen Wikitext"
                       + " in das obere Eingabefeld ein,"
                       + " oder einen Seitennamen in das untere,"
                       + " und betätige die jeweilige Schaltfläche."},
      "mark":   {"en": "select problem in source text",
                 "de": "Problem im Quelltext selektieren"},
      "noPage": {"en": "Wikitext page not found",
                 "de": "Wikitext-Seite nicht gefunden"},
      "other":  {"en": "Future problems detected.",
                 "de": "Zukünftige Probleme detektiert."}
   };   // HINT.texts



   function face() {
      // Page orientation
      // Precondition:
      //    DOM ready
      // Uses:
      //    >< HINT.$body
      //     < HINT.ltr
      // 2017-08-19 PerfektesChaos@de.wikipedia
      if ( ! HINT.$body ) {
         HINT.$body = $( "body" );
         HINT.ltr   = ( $( "html" ).attr( "dir" )  !==  "rtl" );
      }
   }   // face()



   function fair( action ) {
      // Adapt to special conditions (mobile)
      // Precondition:
      //    action  -- function to be executed, or not
      // Uses:
      //    >< HINT.using
      //    mw.loader.using()
      // 2017-08-07 PerfektesChaos@de.wikipedia
      if ( mw.config.get( "skin" ) !== "minerva" ) {   // T49858
         if ( action ) {
            mw.loader.using( "jquery.tablesorter",
                             action );
         } else {
            HINT.using.push( "jquery.tablesorter" );
         }
      }
   }   // fair()



   function features( apply ) {
      // Config hook has been fired
      // Precondition:
      //    apply  -- hook payload
      // Uses:
      //    >  HINT.nsn
      //    >  HINT.last
      //    >  HINT.launched
      //    >< HINT.launch
      //    >< HINT.layer
      //    >< HINT.live
      //     < HINT.later
      //     < HINT.lazy
      //    mw.loader.using()
      //    BOX.flat()
      //    (API.feed)
      //    (BOX.feed)
      // 2017-11-11 PerfektesChaos@de.wikipedia
      var i, live;
      if ( typeof apply  ===  "object"
           &&     apply ) {
         if ( typeof apply.rooms  ===  "object"
              &&     apply.rooms   &&
              typeof apply.rooms.length  ===  "number" ) {
            live = false;
            for ( i = 0;  i < apply.rooms.length;  i++ ) {
               if ( apply.rooms[ i ] === HINT.nsn ) {
                  live = true;
                  break;   // for i
               }
            }   // for i
         } else if ( typeof apply.rooms  ===  "string"
                     &&     apply.rooms === "*" ) {
            live = true;
         } else {
            live = false;
         }
         if ( typeof apply.later  ===  "boolean" ) {
            HINT.later = apply.later;
         }
         if ( typeof apply.launch  ===  "boolean" ) {
            HINT.launch = apply.launch;
         }
         if ( typeof apply.layer  ===  "boolean" ) {
            HINT.layer = apply.layer;
         }
         if ( typeof apply.lazy  ===  "boolean" ) {
            HINT.lazy = apply.lazy;
            if ( HINT.lazy ) {
               BOX.flat();
            }
         }
         if ( live  &&  ! HINT.last ) {
            live = false;
            if ( typeof apply.oldid  ===  "boolean"
                 &&     apply.oldid ) {
               live = true;
            }
         }
         if ( live  &&  ! HINT.live ) {
            HINT.live = true;
            if ( HINT.launch  &&  ! HINT.launched ) {
               mw.loader.using( HINT.using, API.feed );
            } else {
               mw.loader.using( HINT.using, BOX.feed );
            }
         } else if ( HINT.live  &&  ! live ) {
            BOX.flat();
         }
      }
   }   // features()



   function first() {
      // Autorun on loading
      // Uses:
      //    >  Signature
      //    >  LINTER.first
      //    >  HINT.cmodels
      //    >  HINT.doc
      //    >  Version
      //    >< HINT.using
      //     < HINT.signature
      //     < HINT.nsn
      //     < HINT.source
      //     < HINT.idRev
      //     < HINT.last
      //     < HINT.live
      //     < EDIT.live
      //     < HINT.pub
      //    mw.loader.getState()
      //    mw.loader.state()
      //    mw.config.get()
      //    TEACH.fetch()
      //    GUIDER.first()
      //    fair()
      //    mw.loader.using()
      //    mw.hook()
      //    PREGO.feed()
      //    (features)
      //    (BOX.feed)
      // 2018-02-08 PerfektesChaos@de.wikipedia
      var listen, live, re, s;
      HINT.signature = "ext.gadget." + Signature;
      if ( mw.loader.getState( HINT.signature )  !==  "ready" ) {
         mw.loader.state( HINT.signature, "ready" );
         switch ( mw.config.get( "wgAction" ) ) {
            case "view":
               HINT.nsn = mw.config.get( "wgNamespaceNumber" );
               switch ( HINT.nsn ) {
                  case -1:
                     s = mw.config.get( "wgCanonicalSpecialPageName" );
                     switch ( s ) {
                        case "Blankpage":
                           s = mw.config.get( "wgTitle" );
                           if ( s.indexOf( "/" + Signature )  >  0 ) {
                              TEACH.fetch();
                              GUIDER.first();
                           }
                           listen = true;
                           break;
                        case "LintErrors":
                           fair( LINTER.first );
                           break;
                     }   // switch wgCanonicalSpecialPageName
                     break;
                  case 102:
                  case 104:
                  case 106:
                  case 108:
                  case 110:
                  case 112:
                     // might be Wikisource
                     s = mw.config.get( "wgPageContentModel" );
                     if ( typeof HINT.cmodels[ s ]  ===  "boolean" ) {
                        HINT.source = s;
                     }
                     // fall through
                  default:
                     HINT.idRev = mw.config.get( "wgRevisionId" );
                     s          = window.___location.search;
                     if ( HINT.idRev <= 0 ) {
                        live = false;
                     } else if ( s ) {
                        re     = "\\b(diff|history|printable)=";
                        re     = new RegExp( re );
                        live = ! re.test( s );
                        if ( live ) {
                           if ( s.indexOf( "&oldid=" )  >  0 ) {
                              if ( mw.config.get( "wgCurRevisionId" ) !==
                                                           HINT.idRev ) {
                                 HINT.last = false;
                                 HINT.live = false;
                              }
                           }
                        }
                     } else {
                        live = true;
                     }
               }   // switch wgNamespaceNumber
               break;
            case "edit":
            case "submit":
            case "parsermigration-edit":
               EDIT.live = true;
               HINT.nsn  = mw.config.get( "wgNamespaceNumber" );
               HINT.using.push( "jquery.textSelection" );
               live = true;
               if ( HINT.nsn >= 100 ) {
                  s = mw.config.get( "wgPageContentModel" );
                  if ( s === "proofread-page" ) {
                     HINT.source = s;
                  }
               }
               break;
         }   // switch wgAction
         if ( live ) {
            if ( ! HINT.source ) {
               HINT.source = mw.config.get( "wgPageContentModel" );
               live        = ( HINT.source === "wikitext" );
            }
            listen = live;
         }
         if ( listen ) {
            if ( HINT.nsn === 0 ) {
               HINT.live = true;
            }
            mw.hook( Signature + ".config" ).add( features );
         }
         if ( live ) {
            PREGO.feed();
            fair();
            TEACH.fetch();
            if ( HINT.live ) {
               mw.loader.using( HINT.using, BOX.feed );
            }
         }
         HINT.pub = { doc:  "[[" + HINT.doc + "]]",
                      type: Signature,
                      vsn:  Version };
         mw.hook( Signature + ".ready" ).fire( HINT.pub );
      }
   }   // first()



   API.fault = function ( jqXHR, textStatus, errorThrown ) {
      // API failure
      // Precondition:
      //    Common failure call
      // Uses:
      //    >  Signature
      //     < API.scream
      //     < API.errors
      //    (BOX.fault)
      // 2017-08-03 PerfektesChaos@de.wikipedia
      if ( textStatus ) {
         switch ( typeof textStatus ) {
            case "object":
               if ( typeof textStatus.textStatus  ===  "string" ) {
                  API.scream = textStatus.textStatus;
               } else {
                  API.scream = "";
               }
               if ( typeof textStatus.exception  ===  "string"
                    &&     textStatus.exception ) {
                  API.scream = API.scream + " ("
                               + textStatus.exception + ")";
               }
               break;
            case "string":
               API.scream = textStatus;
               break;
         }   // switch
      }
      if ( errorThrown ) {
         if ( API.scream ) {
            API.scream = API.scream + "  -- Error: ";
         }
         API.scream = API.scream + errorThrown;
      }
      if ( ! API.scream ) {
         API.scream = "???";
      }
      if ( typeof window.console  ===  "object"   &&
           typeof window.console.log  ===  "function" ) {
         window.console.log( Signature + " * " + API.scream );
         if ( typeof textStatus  ===  "object"
              &&     textStatus   &&
              typeof window.console.dir  ===  "function" ) {
            window.console.dir( textStatus );
         }
      }
      API.errors = false;
      mw.hook( "wikipage.content" ).add( BOX.fault );
   };   // API.fault()



   API.feed = function ( access ) {
      // Intermediate retrieval of wikitext
      // Precondition:
      //    access  -- string, with title of particular page, or not
      //    mediawiki.api available
      // Uses:
      //    >  HINT.nsn
      //    >< API.Api
      //    >< HINT.idRev
      //     < API.single
      //     < HINT.launched
      //    mw.config.get()
      //    (API.feeder)
      //    (API.fault)
      // 2017-08-03 PerfektesChaos@de.wikipedia
      var w = { action: "query",
                prop:   "revisions" };
      if ( typeof access  ===  "string" ) {
         API.single = access;
      }
      if ( HINT.nsn < 0 ) {
         w.rvprop = "content|contentmodel";
      } else {
         w.rvprop = "content";
         if ( ! HINT.idRev ) {
            HINT.idRev = mw.config.get( "wgRevisionId" );
         }
         HINT.launched = true;
      }
      if ( HINT.idRev ) {
         w.revids = HINT.idRev;
      } else if ( API.single ) {
         w.titles = API.single;
      } else {
         w = false;
      }
      if ( w ) {
         if ( ! API.Api ) {
            API.Api = new mw.Api();
         }
         API.Api.get( w ).done( API.feeder )
                         .fail( API.fault );
      }
   };   // API.feed()



   API.feeder = function ( arrived ) {
      // Intermediate expansion of wikitext
      // Precondition:
      //    arrived  -- JSON result of ajax content query
      //    mediawiki.api available
      // Uses:
      //    >  HINT.cmodels
      //    >  API.single
      //    >  API.Api
      //    >  HINT.idRev
      //    >  PREGO.app
      //    >  HINT.texts.noPage
      //    API.fire()
      //    API.fault()
      //    (API.fed)
      //    (API.fault)
      // 2018-02-07 PerfektesChaos@de.wikipedia
      var id, q, s, w;
      if ( typeof arrived  ===  "object"   &&
           typeof arrived.query  ===  "object"   &&
           typeof arrived.query.pages  ===  "object" ) {
         q = arrived.query.pages;
         for ( id in q ) {
            q = q[ id ];
            if ( q && q.revisions ) {
               q = q.revisions[ 0 ];
               if ( typeof q.contentmodel  !==  "string"   ||
                    typeof HINT.cmodels[ q.contentmodel ]  ===  "boolean"
                  ) {
                  s = q[ "*" ];
                  if ( /\{\{/.test( s ) ) {
                     w = { action: "expandtemplates",
                           prop:   "wikitext|volatile",
                           text:   s };
                     if ( API.single ) {
                        w.title = API.single;
                     }
                     if ( HINT.idRev ) {
                        w.revid = HINT.idRev;
                     }
                     if ( w ) {
                        API.Api.post( w ).done( API.fed )
                                         .fail( API.fault );
                     }
                  } else {
                     API.fire( s );
                  }
               }
            }
            break;   // for id
         }   // for id in q
      }
      if ( ! s ) {
         if ( PREGO.app ) {
             s = PREGO.app.translation( HINT.texts.noPage );
         } else {
             s = HINT.texts.noPage.en;
         }
         if ( API.single ) {
            s = s + " * " + API.single;
         }
         API.fault( null, "Missing", s );
      }
   };   // API.feeder()



   API.fed  =  function ( arrived ) {
      // Postprocess page content after ajax expandtemplates request
      // Precondition:
      //    arrived  -- JSON result of ajax expandtemplates query
      // Uses:
      //    API.fire()
      // 2017-08-01 PerfektesChaos@de.wikipedia
      if ( typeof arrived  ===  "object"   &&
           typeof arrived.expandtemplates  ===  "object"   &&
           typeof arrived.expandtemplates.wikitext  ===  "string" ) {
         API.fire( arrived.expandtemplates.wikitext );
      }
   };   // API.fed()



   API.fine = function ( arrived ) {
      // Answer on LINT arrived
      // Precondition:
      //    arrived  -- JSON result of ajax lint query
      // Uses:
      //     < API.errors
      //     < API.scream
      //    (BOX.fill)
      //    (BOX.flat)
      // 2017-08-01 PerfektesChaos@de.wikipedia
      var start;
      if ( typeof arrived  ===  "object"
           &&     arrived   &&
           typeof arrived.length  ===  "number"
           &&     arrived.length ) {
         API.errors = arrived;
         start      = "fill";
      } else {
         API.errors = false;
         start      = "flat";
      }
      API.scream = false;
      mw.hook( "wikipage.content" ).add( BOX[ start ] );
   };   // API.fine()



   API.fire = function ( ask ) {
      // Request POST
      // Precondition:
      //    ask  -- wikitext string, or not (current wikitext page)
      //    mediawiki.api available
      // Uses:
      //    >< API.site
      //    >< API.query
      //    (API.fine)
      //    (API.fault)
      // 2017-08-01 PerfektesChaos@de.wikipedia
      var local = ( typeof ask  ===  "string" );
               /* , f; */
      if ( typeof API.query  !==  "object" ) {
         /*
         f = function ( jqXHR ) {
                            jqXHR.setRequestHeader( "Content-Type",
                                                    "application/json" );
             };
         */
         API.query = { //beforeSend: f,
                       dataType:   "json"   // No "Intelligent Guess"
                     };
         API.site  = window.___location.protocol + "//" +
                     window.___location.hostname + "/";
         if ( local ) {
//          API.site = API.site + "v3/" + API.service;
            API.site       = API.site + "api/rest_v1/" + API.service;
            API.query.type = "POST";
            API.query.url  = API.site;
         }
      }
      if ( local ) {
         API.query.data = { wikitext: ask };
      }
      $.ajax( API.query ).done( API.fine )
                         .fail( API.fault );
   };   // API.fire()



   BOX.factory = function ( $area ) {
      // Create and equip large box, if necessary
      // Precondition:
      //    $area  -- mw-content-text
      // Uses:
      //    >  HINT.live
      //    >  Signature
      //    >  HINT.ltr
      //    >  BOX.bgc
      //    >  BOX.boc
      //    >  BOX.fgc
      //    >< BOX.$box
      //     < HINT.$page
      //    face()
      //    BOX.focus()
      //    BOX.flat()
      //    (BOX.flip)
      // 2017-08-08 PerfektesChaos@de.wikipedia
      var $a, $e;
      if ( HINT.live ) {
         HINT.$page = $area;
         if ( BOX.$box ) {
            if ( BOX.$failure ) {
               BOX.$failure.hide();
            }
            BOX.$box.show();
         } else {
            face();
            BOX.$box = $( "<div>" );
            $e = $( "<div>" );
            if ( HINT.nsn < 0 ) {
               $a = $( "<span>" );
            } else {
               $a = $( "<a>" );
               $a.attr( { href:   "/wiki/Special:Blankpage/" + Signature,
                          target: Signature } );
            }
            $a.css( { "font-weight": "bold",
                      "font-size":  "larger" } )
              .text( Signature + "@PerfektesChaos" );
            $e.append( $a )
              .css( { "float": ( HINT.ltr ? "left": "right" ) } );
            BOX.$box.append( $e )
                    .attr( { id:  Signature } )
                    .css( { "background-color":  "#" + BOX.bgc,
                            "border-color":      "#" + BOX.boc,
                            "border-style":      "solid",
                            "border-width":      "1px",
                            "color":             "#" + BOX.fgc,
                            "margin-bottom":     "1em",
                            "padding":           "0.5em" } );
            $e = $( "<button>" );
            $e.click( BOX.flip )
              .css( { "color":        "#FF0000",
                      "float":        ( HINT.ltr ? "right": "left" ),
                      "font-weight":  "bolder" } )
              .css( "margin-" + ( HINT.ltr ? "right": "left" ),
                    "6px" )
              .text( "X" );
            BOX.$box.append( $e );
            BOX.focus( BOX.$box );
         }
      } else {
         BOX.flat();
      }
   };   // BOX.factory()



   BOX.fault = function ( $area ) {
      // API error arrived
      // Precondition:
      //    $area  -- mw-content-text
      //    DOM ready
      // Uses:
      //    >  BOX.$box
      //    >  BOX.$table
      //    >  GUIDER.$pagename
      //    >< BOX.$failure
      //     < API.scream
      //    BOX.flat()
      //    BOX.factory()
      // 2017-08-04 PerfektesChaos@de.wikipedia
      BOX.flat();
      BOX.factory( $area );
      if ( API.scream && BOX.$box ) {
         if ( BOX.$table ) {
            BOX.$table.hide();
         }
         if ( ! BOX.$failure ) {
            BOX.$failure = $( "<div>" );
            BOX.$failure.css( { "clear":       "both",
                                "color":       "#FF0000",
                                "font-weight": "bold" } );
            BOX.$box.append( BOX.$failure );
         }
         BOX.$failure.text( API.scream )
                     .show();
      }
      if ( GUIDER.$pagename ) {
         GUIDER.$pagename.hide();
      }
   };   // BOX.fault()



   BOX.feed = function () {
      // Shrink box initiated
      // Uses:
      //    >  HINT.launch
      //    >  HINT.launched
      //    API.feed()
      //    mw.hook()
      //    (BOX.flip)
      // 2017-08-03 PerfektesChaos@de.wikipedia
      if ( HINT.launch  &&  ! HINT.launched ) {
         API.feed();
      } else {
         mw.hook( "wikipage.content" ).add( BOX.flip );
      }
   };   // BOX.feed()



   BOX.fill = function ( $area ) {
      // Table content arrived
      // Precondition:
      //    $area  -- mw-content-text
      //    mediawiki.api.messages available
      // Uses:
      //    >  BOX.$collapsed
      //    >  BOX.$null
      //    >  BOX.$box
      //    >  HINT.$textarea
      //    >  GUIDER.last
      //    >  HINT.errors
      //    >  HINT.nsn
      //    >  PREGO.signature
      //    >< BOX.$table
      //    >< API.Api
      //    >< BOX.$pagename
      //     < BOX.swift
      //     < BOX.$tbody
      //    BOX.factory()
      //    mw.hook()
      //    BOX.filler()
      //    mw.Api.loadMessagesIfMissing()
      //    GUIDER.from()
      //    (BOX.flag)
      //    (BOX.filler)
      //    (API.fault)
      // 2017-10-10 PerfektesChaos@de.wikipedia
      var i, req, $th, $thead, $tr;
      BOX.factory( $area );
      if ( BOX.$collapsed ) {
         BOX.$collapsed.hide();
      }
      if ( BOX.$null ) {
         BOX.$null.hide();
      }
      if ( BOX.$box ) {
         if ( BOX.$table ) {
            if ( HINT.$textarea ) {
               if ( GUIDER.last ) {
                  BOX.$swift.hide();
               } else {
                  BOX.$swift.show();
               }
            }
            BOX.$tbody.empty();
            BOX.filler();
         } else {
            BOX.$table = $( "<table>" );
            $thead = $( "<thead>" );
            if ( HINT.nsn < 0 ) {
               BOX.$pagename = $( "<caption>" );
               BOX.$pagename.css( { "font-weight": "normal",
                                    "white-space": "nowrap" } );
               BOX.$table.append( BOX.$pagename );
            }
            $tr = $( "<tr>" );
            $th = $( "<th>" );
            $th.text( "lint" );
            $tr.append( $th );
            $th = $( "<th>" );
            $th.text( "+" );
            $tr.append( $th );
            if ( HINT.$textarea ) {
               BOX.$swift = $( "<th>" );
               BOX.$swift.data( "sort-type", "number" )
                         .text( String.fromCharCode( 8659 ) );
               mw.hook( PREGO.signature + ".ready" ).add( BOX.flag );
               if ( GUIDER.last ) {
                  BOX.$swift.hide();
               }
               $tr.append( BOX.$swift );
            }
            $thead.append( $tr );
            BOX.$tbody = $( "<tbody>" );
            BOX.$table.addClass( "wikitable" )
                      .attr( { id:  Signature + "-table" } )
                      .append( $thead, BOX.$tbody )
                      .css( { "clear": "both" } );
            if ( HINT.errors.length > 1  ||  HINT.nsn < 0 ) {
               BOX.$table.addClass( "sortable" );
            }
            BOX.$box.append( BOX.$table );
            req = [ ];
            for ( i = 0;  i < HINT.errors.length;  i++ ) {
               req.push( "linter-category-" + HINT.errors[ i ] );
            }   // for i
            if ( ! API.Api ) {
               API.Api = new mw.Api();
            }
            API.Api.loadMessagesIfMissing( req ).done( BOX.filler )
                                                .fail( API.fault );
         }
         if ( BOX.$pagename ) {
            GUIDER.from( BOX.$pagename );
         }
      }
   };   // BOX.fill()



   BOX.filler = function () {
      // Table body rows
      // Precondition:
      //    api.messages available
      // Uses:
      //    >  API.errors
      //    >  mw.messages
      //    >  HINT.later
      //    >  BOX.bgcErr
      //    >  HINT.$textarea
      //    >  GUIDER.last
      //    >  BOX.swift
      //    >  BOX.$tbody
      //    >  BOX.$table
      //    >  BOX.boc
      //    >  PREGO.app
      //    >  PREGO.signature
      //    >< BOX.$other
      //    mw.message()
      //    TEACH.feed()
      //    BOX.future()
      //    (BOX.find)
      //    (BOX.future)
      // 2018-02-07 PerfektesChaos@de.wikipedia
      var n = 0,
          e, i, k, par, s, $e, $e2, $e3, $td, $tr;
      for ( i = 0;  i < API.errors.length;  i++ ) {
         e = API.errors[ i ];
         s = "linter-category-" + e.type;
         if ( mw.messages.exists( s ) ) {
            s = mw.message( s ).text();
         } else {
            TEACH.feed( e.type );
            if ( HINT.later ) {
               s = e.type;
            } else {
               s = false;
            }
         }
         if ( s ) {
            $tr = $( "<tr>" );
            $td = $( "<td>" );
            $td.css( { "background-color":  "#" + BOX.bgcErr } );
            $td.text( s );
            $tr.append( $td );
            $td = $( "<td>" );
            $td.css( { "background-color":  "#FFFFFF" } );
            if ( typeof e.params  ===  "object" ) {
               par = e.params;
if ( Version < 0 ) {
   for ( s in par ) {
      if ( s !== "child"  &&
           s !== "items"  &&
           s !== "name"  &&
           s !== "root" ) {
         console.log(s,par)
      }
   }   // for s in par
}
               if ( typeof par.name  ===  "string" ) {
                  $td.text( par.name );
               } else if ( typeof par.root  ===  "string"   &&
                           typeof par.child  ===  "string" ) {
                  $e = $( "<code>" );
                  $e.text( par.root );
                  $e2 = $( "<span>" );
                  $e2.css( { "padding-left":   "1em",
                             "padding-right":  "1em" } )
                     .html( "&gt;" );
                  $e3 = $( "<code>" );
                  $e3.text( par.child );
                  $td.append( $e, $e2, $e3 )
                     .css( { "white-space":  "nowrap" } );
               } else if ( typeof par.items  ===  "object"  &&
                           typeof par.items.length  ===  "number" ) {
                  for ( k = 0;  k < par.items.length;  k++ ) {
                     $e = $( "<code>" );
                     $e.css( { "margin-right": "6px",
                               "white-space":  "nowrap" } )
                       .text( par.items[ k ] );
                     $td.append( $e );
                  }   // for k
               }
            }
            $tr.append( $td );
            if ( HINT.$textarea   &&
                 ! GUIDER.last   &&
                 typeof e.dsr  ===  "object"
                 &&     e.dsr   &&
                 typeof e.dsr[ 0 ]  ===  "number"   &&
                 typeof e.dsr[ 1 ]  ===  "number" ) {
               $td = $( "<td>" );
               $td.click( BOX.find )
                  .data( "range", e.dsr )
                  .data( "sort-value", i )
                  .text( String.fromCharCode( 160, 8595, 160 ) );
               if ( typeof BOX.swift  ===  "string" ) {
                  $td.attr( { title: BOX.swift } );
               }
               $tr.append( $td );
            }
            BOX.$tbody.append( $tr );
            n++;
         }
      }   // for i
      if ( n ) {
         if ( BOX.$other ) {
            BOX.$other.hide();
         }
         if ( n > 1   &&
              typeof BOX.$table.tablesorter  ===  "function" ) {
            BOX.$table.tablesorter();
         }
         BOX.$table.show();
      } else {
         BOX.$table.hide();
         if ( BOX.$other ) {
            BOX.$other.show();
         } else {
            if ( PREGO.app ) {
               BOX.future();
            } else {
               mw.hook( PREGO.signature + ".ready" ).add( BOX.future );
            }
         }
      }
   };   // BOX.filler()



   BOX.find = function ( event ) {
      // Marker link has been clicked
      // Precondition:
      //    event  -- object, with event
      // Uses:
      //    >  HINT.$textarea
      // 2017-10-06 PerfektesChaos@de.wikipedia
      var $item = $( event.target ),
          range = $item.data( "range" );
      HINT.$textarea.focus()
                    .textSelection( "setSelection",
                                    { start: range[ 0 ],
                                      end:   range[ 1 ] } );
   };   // BOX.find()



   BOX.flag = function ( application ) {
      // Tooltip on selection ranges requested
      // Precondition:
      //    application  -- PREGO object
      // Uses:
      //    >  HINT.texts.mark
      //    >  BOX.$swift
      //     < BOX.swift
      //    PREGO.app.translation()
      // 2017-10-06 PerfektesChaos@de.wikipedia
      if ( application ) {
         PREGO.app = application;
      }
      BOX.swift = PREGO.app.translation( HINT.texts.mark );
      BOX.$swift.attr( { title: BOX.swift } );
   };   // BOX.flag()



   BOX.flat = function ( $area, alive ) {
      // Hide boxes, if necessary
      // Precondition:
      //    $area  -- mw-content-text, or nil
      //    alive  -- leave BOX.$collapsed
      // Uses:
      //    >  HINT.live
      //    >  BOX.$box
      //    >  BOX.$collapsed
      //    >  EDIT.live
      //    >  BOX.$null
      //    >  API.errors
      //    >  API.scream
      //    >  HINT.lazy
      //    >  API.single
      //    >  HINT.launched
      //    >  Signature
      //    >  BOX.bgcOk
      //    >  BOX.fgc
      //    >  GUIDER.live
      //    >  Version
      //    >  HINT.ltr
      //    >  GUIDER.$pagename
      //    >< HINT.$page
      //    >< BOX.$null
      //    BOX.flip()
      //    face()
      //    GUIDER.from()
      //    BOX.focus()
      // 2017-08-08 PerfektesChaos@de.wikipedia
      if ( $area  &&  ! HINT.$page ) {
         HINT.$page = $area;
      }
      if ( BOX.$box ) {
         BOX.$box.hide();
      }
      if ( BOX.$collapsed  &&  ! alive  &&  ! EDIT.live ) {
         BOX.$collapsed.hide();
      }
      if ( EDIT.live ) {
         if ( ! alive ) {
            BOX.flip();
         }
      } else if ( ! API.errors  &&  ! API.scream  &&  HINT.live ) {
         if ( API.single  &&  GUIDER.$pagename ) {
            if ( BOX.$null ) {
               BOX.$null.hide();
            }
            GUIDER.from( GUIDER.$pagename );
         } else if ( BOX.$null ) {
            if ( HINT.lazy ) {
               BOX.$null.hide();
            } else {
               BOX.$null.show();
            }
         } else if ( ! HINT.lazy  &&
                     HINT.launched  &&
                     HINT.$page ) {
            face();
            BOX.$null = $( "<div>" );
            BOX.$null.attr( { id:  Signature + "-null" } )
                     .css( { "background-color":  "#" + BOX.bgcOk,
                             "clear":             "both",
                             "color":             "#" + BOX.fgc,
                             "float":     ( HINT.ltr ? "right": "left" ),
                             "font-size":         "smaller",
                             "padding":           "3px" } )
                     .text( Signature );
            if ( ! GUIDER.live ) {
               BOX.$null.attr( { title:  Signature + "@PerfektesChaos "
                                         + Version } );
            }
            BOX.focus( BOX.$null );
         }
      } else if ( BOX.$null ) {
         BOX.$null.hide();
      }
   };   // BOX.flat()



   BOX.flip = function ( $area ) {
      // Shrink box requested
      // Precondition:
      //    $area  -- mw-content-text, or nil
      // Uses:
      //    >  Signature
      //    >  HINT.ltr
      //    >  GUIDER.live
      //    >  BOX.bgc
      //    >  BOX.fgc
      //    >  Version
      //    >  EDIT.live
      //    >  API.errors
      //    >  GUIDER.$pagename
      //    >< HINT.$page
      //    >< BOX.$collapsed
      //    face()
      //    BOX.flat()
      //    BOX.focus()
      //    EDIT.fine()
      //    (BOX.full)
      // 2017-08-08 PerfektesChaos@de.wikipedia
      if ( $area  &&  ! HINT.$page ) {
         HINT.$page = $area;
      }
      face();
      BOX.flat( $area, true );
      if ( BOX.$collapsed ) {
         BOX.$collapsed.attr( { disabled: false } )
                       .show();
      } else {
         BOX.$collapsed = $( "<button>" );
         BOX.$collapsed.attr( { id:  Signature + "-collapsed" } )
                       .click( BOX.full )
                       .css( { "clear": ( HINT.ltr ? "right": "left" ),
                               "float": ( HINT.ltr ? "right": "left" ),
                               "margin-bottom":     "3px",
                               "padding":           "2px" } )
                       .text( Signature );
         if ( ! GUIDER.live ) {
            BOX.$collapsed.attr( { title: Version } );
         }
         BOX.focus( BOX.$collapsed );
      }
      BOX.$collapsed.css( { "background-color":  "#" + BOX.bgc,
                            "color":             "#" + BOX.fgc } );
      if ( EDIT.live  &&  ! API.errors ) {
         EDIT.fine();
      }
      if ( GUIDER.$pagename ) {
         GUIDER.$pagename.hide();
      }
   };   // BOX.flip()



   BOX.focus = function ( $apply ) {
      // Insertion in page top region
      // Precondition:
      //    $apply  -- jQuery object
      // Uses:
      //    >  Signature
      //    >  HINT.$page
      //    >< BOX.$top
      // 2017-08-08 PerfektesChaos@de.wikipedia
      var $e;
      if ( ! BOX.$top ) {
         BOX.$top = $( "<div>" );
         BOX.$top.attr( { id:  Signature + "-top" } )
                 .css( { "clear": "both",
                         "width": "100%" } );
         $e = $( "<div>" );
         $e.css( { "clear": "both" } );
         HINT.$page.prepend( BOX.$top, $e );
      }
      BOX.$top.prepend( $apply );
   };   // BOX.focus()



   BOX.full = function () {
      // Analysis or expanded box requested
      // Uses:
      //    >  HINT.live
      //    >  BOX.$box
      //    >  BOX.$collapsed
      //    >  BOX.bgcRun
      //    >  BOX.fgcRun
      //    >  GUIDER.live
      //    >  HINT.source
      //    >  HINT.$page
      //    >< API.errors
      //    >< API.single
      //    >< EDIT.live
      //    >< EDIT.$source
      //     < EDIT.listen
      //     < HINT.launch
      //     < HINT.$textarea
      //    API.feed()
      // 2018-01-21 PerfektesChaos@de.wikipedia
      var source;
      if ( HINT.live ) {
         if ( BOX.$box ) {
            if ( EDIT.live ) {
               API.errors = false;
            } else {
               BOX.$collapsed.hide();
            }
            if ( API.errors ) {
               BOX.$box.show();
            } else {
               BOX.$box.hide();
            }
         }
         if ( ! API.errors ) {
            BOX.$collapsed.attr( { disabled: true } )
                          .css( { "background-color":  "#" + BOX.bgcRun,
                                  "color":             "#" + BOX.fgcRun }
                              );
         }
         if ( ! API.single  &&  ! GUIDER.live ) {
            API.single = mw.config.get( "wgTitle" );
         }
         if ( EDIT.live ) {
            if ( ! EDIT.$source ) {
               switch ( HINT.source ) {
                  case "wikitext":
                  case "proofread-page":
                     source = "#wpTextbox1";
                     break;
               }   // switch HINT.source
               if ( source ) {
                  EDIT.$source = HINT.$page.find( source );
                  if ( ! EDIT.$source.length ) {
                     BOX.$collapsed.hide();
                     EDIT.live = false;
                  }
               } else {
                  EDIT.live = false;
               }
            }
            if ( EDIT.live ) {
               EDIT.listen = false;
               API.fire( EDIT.$source.val() );
               HINT.$textarea = EDIT.$source;
            }
         } else {
            HINT.launch = true;
            API.feed( API.single );
         }
      } else {
         BOX.$collapsed.hide();
      }
   };   // BOX.full()



   BOX.future = function ( application ) {
      // Remark on uncategorized features requested
      // Precondition:
      //    application  -- PREGO object
      // Uses:
      //    >  HINT.texts.other
      //    >  Signature
      //    >  BOX.$box
      //    >< PREGO.app
      //     < BOX.$other
      //    PREGO.app.translation()
      // 2017-08-08 PerfektesChaos@de.wikipedia
      var $e;
      if ( application ) {
         PREGO.app = application;
      }
      if ( PREGO.app ) {
         $e = $( "<span>" );
         $e.css( { "border-color":  "#" + BOX.boc,
                   "border-style":  "solid",
                   "border-width":  "1px",
                   "padding":       "0.4em" } )
           .html( PREGO.app.translation( HINT.texts.other ) );
         BOX.$other = $( "<div>" );
         BOX.$other.attr( { id:  Signature + "-future" } )
                   .css( { "clear":          "both",
                           "padding-bottom": "1em",
                           "padding-top":    "1em" } )
                   .append( $e );
         BOX.$box.append( BOX.$other );
      }
   };   // BOX.future()



   EDIT.fine = function () {
      // Source evaluation without errors
      // Uses:
      //    >  EDIT.$source
      //    >  BOX.bgcOk
      //    >  BOX.$collapsed
      //     < EDIT.listen
      //    (EDIT.focus)
      // 2017-08-08 PerfektesChaos@de.wikipedia
      if ( EDIT.$source ) {
         EDIT.listen = true;
         EDIT.$source.focusin( EDIT.focus );
         BOX.$collapsed.css( { "background-color":  "#" + BOX.bgcOk } );
      }
   };   // EDIT.fine()



   EDIT.focus = function () {
      // Source area has been touched
      // Uses:
      //    >  BOX.bgc
      //    >  BOX.$collapsed
      //    >< EDIT.listen
      // 2017-08-08 PerfektesChaos@de.wikipedia
      if ( EDIT.listen ) {
         BOX.$collapsed.css( { "background-color":  "#" + BOX.bgc } );
         EDIT.listen = false;
      }
   };   // EDIT.focus()



   LINTER.fire = function ( $area ) {
      // LintErrors page has been loaded
      // Precondition:
      //    $area  -- mw-content-text
      // Uses:
      //    >  HINT.layer
      //     < LINTER.reEdit
      //    (LINTER.further)
      // 2017-11-11 PerfektesChaos@de.wikipedia
      var $table = $area.find( ".TablePager" );
      if ( $table.length ) {
         if ( typeof $table.tablesorter  ===  "function" ) {
            $table.tablesorter();
         }
         if ( HINT.layer ) {
            LINTER.reEdit  = new RegExp( "([?&]action=)" +
                                         "edit" +
                                         "(&.+)?$" );
            $table.find( "a" ).each( LINTER.further );
         }
      }
   };   // LINTER.fire()



   LINTER.first = function () {
      // LintErrors page loading
      // Precondition:
      //    jquery.tablesorter available
      // Uses:
      //    mw.config.get()
      //    mw.hook()
      //    (LINTER.fire)
      // 2017-08-03 PerfektesChaos@de.wikipedia
      if ( mw.config.get( "wgTitle" ).indexOf( "/" )  >  0 ) {
         mw.hook( "wikipage.content" ).add( LINTER.fire );
      }
   };   // LINTER.first()



   LINTER.further = function ( any, a ) {
      // Divert LintErrors page link
      // Precondition:
      //    any  -- number of link in table
      //    a    -- DOM object of <a>
      // Uses:
      //    >  LINTER.reEdit
      // 2017-11-11 PerfektesChaos@de.wikipedia
      var $a = $( a ),
          s  = $a.attr( "href" );
      if ( s.indexOf( "action=edit" )  >  0 ) {
         $a.attr( "href",
                  s.replace( LINTER.reEdit,
                             "$1parsermigration-edit$2" ) );
      }
   };   // LINTER.further()



   GUIDER.find = function () {
      // Page name submit button has been clicked
      // Uses:
      //    >  GUIDER.$input
      //    >  GUIDER.reTrim
      //     < GUIDER.last
      //     < API.single
      //    GUIDER.fired()
      //    API.feed()
      // 2017-10-06 PerfektesChaos@de.wikipedia
      var s = GUIDER.$input.val();
      GUIDER.fired();
      GUIDER.last = true;
      if ( ! GUIDER.reTrim.test( s ) ) {
         API.single = s;
         API.feed( API.single );
      }
   };   // GUIDER.find()



   GUIDER.finish = function ( application ) {
      // Add instructions to special page
      // Precondition:
      //    application  -- PREGO object
      // Uses:
      //    >  HINT.texts.desc
      //    >  HINT.texts.howTo
      //    >  GUIDER.$desc
      //    >  HINT.$page
      //    >  HINT.texts.___domain
      //    >  Signature
      //    >  GUIDER.$doc
      //     < PREGO.app
      //    PREGO.app.translation()
      // 2017-08-01 PerfektesChaos@de.wikipedia
      var $e = $( "<div>" );
      PREGO.app = application;
      GUIDER.$desc.html( PREGO.app.translation( HINT.texts.desc ) );
      $e.css( { "clear":      "both",
                "margin-top": "8em" } )
        .html( PREGO.app.translation( HINT.texts.howTo ) );
      HINT.$page.append( $e );
      $e = $( "<a>" );
      $e.attr( { href:   "https://"
                         + PREGO.app.translation( HINT.texts.___domain )
                         + "/wiki/"
                         + "User:PerfektesChaos/js/"
                         + Signature,
                 target: Signature } )
        .text( GUIDER.$doc.text() );
      GUIDER.$doc.text( "" )
                 .append( $e );
   };   // GUIDER.finish()



   GUIDER.fire = function () {
      // Textarea submit button has been clicked
      // Uses:
      //    >  GUIDER.$textarea
      //    >  GUIDER.reTrim
      //     < GUIDER.last
      //     < API.single
      //     < HINT.launched
      //    GUIDER.fired()
      //    API.fire()
      // 2017-10-06 PerfektesChaos@de.wikipedia
      var s = GUIDER.$textarea.val();
      GUIDER.fired();
      GUIDER.last = false;
      if ( ! GUIDER.reTrim.test( s ) ) {
         API.single = false;
         API.fire( s );
         HINT.launched = true;
      }
   };   // GUIDER.fire()



   GUIDER.fired = function () {
      // Submit button has been clicked
      // Uses:
      // GUIDER.flat()
      // 2017-08-04 PerfektesChaos@de.wikipedia
      GUIDER.flat();
      if ( ! GUIDER.reTrim ) {
         GUIDER.reTrim   = new RegExp( "^\\s*$" );
      }
   };   // GUIDER.fired()



   GUIDER.first = function () {
      // Prepare special page for equipping
      // Uses:
      //    >  GUIDER.using
      //    >< HINT.using
      //     < HINT.live
      //     < GUIDER.live
      //    PREGO.feed()
      //    fair()
      //    mw.loader.load()
      //    mw.hook()
      //    (GUIDER.furnish)
      // 2017-08-08 PerfektesChaos@de.wikipedia
      var i;
      PREGO.feed();
      for ( i = 0;  i < GUIDER.using.length;  i++ ) {
         HINT.using.push( GUIDER.using[ i ] );
      }   // for i
      fair();
      mw.loader.load( HINT.using );
      HINT.live   = true;
      GUIDER.live = true;
      mw.hook( "wikipage.content" ).add( GUIDER.furnish );
   };   // GUIDER.first()



   GUIDER.flat = function () {
      // Hide boxes, since any button has been clicked
      // Uses:
      //    >  BOX.$box
      //    >  BOX.$collapsed
      //    >  BOX.$null
      //    >  GUIDER.$pagename
      // 2017-08-05 PerfektesChaos@de.wikipedia
      if ( BOX.$box ) {
         BOX.$box.hide();
      }
      if ( BOX.$collapsed ) {
         BOX.$collapsed.hide();
      }
      if ( BOX.$null ) {
         BOX.$null.hide();
      }
      if ( GUIDER.$pagename ) {
         GUIDER.$pagename.hide();
      }
   };   // GUIDER.flat()



   GUIDER.foreign = function () {
      // Request messages
      // Precondition:
      //    mediawiki.api.messages available
      // Uses:
      //    >< API.Api
      //    mw.Api.loadMessagesIfMissing()
      //    (GUIDER.form)
      //    (API.fault)
      // 2017-08-04 PerfektesChaos@de.wikipedia
      var req = [ "general-form-reset",
                  "go" ],
          i;
      if ( ! API.Api ) {
         API.Api = new mw.Api();
      }
      for ( i = 0;  i < HINT.errors.length;  i++ ) {
         req.push( "linter-category-" + HINT.errors[ i ] );
      }   // for i
      API.Api.loadMessagesIfMissing( req ).done( GUIDER.form )
                                          .fail( API.fault );
   };   // GUIDER.foreign()



   GUIDER.form = function () {
      // Equip page with buttons
      // Precondition:
      //    answer  -- messages
      //    api.messages available
      // Uses:
      //    >  GUIDER.$formText
      //    >  GUIDER.$formPage
      //    >  HINT.ltr
      //    >  PREGO.signature
      //    mw.hook()
      //    (GUIDER.fire)
      //    (GUIDER.find)
      //    (GUIDER.finish)
      // 2017-08-05 PerfektesChaos@de.wikipedia
      var submit = mw.message( "go" ).text(),
          $b     = $( "<span>" ),
          $div   = $( "<div>" ),
          $x     = $( "<span>" );
      $x.css( { "color":        "#FF0000",
                "font-weight":  "bolder" } )
        .text( "X" );
      $b.addClass( "mw-ui-button mw-ui-progressive" )
        .click( GUIDER.fire )
        .css( { "color": "#FFFFFF" } )
        .text( submit );
      GUIDER.$formText.append( $b );
      $b = $( "<input>" );
      $b.addClass( "mw-ui-button" )
        .append( $x )
        .attr( { type: "reset" } )
        .click( GUIDER.flat )
        .css( { "float": ( HINT.ltr ? "right": "left" ) } );
      GUIDER.$formText.append( $b );
      $b = $( "<span>" );
      $b.addClass( "mw-ui-button mw-ui-progressive" )
        .click( GUIDER.find )
        .css( { "color": "#FFFFFF" },
              { "float": ( HINT.ltr ? "right": "left" ) } )
        .text( submit );
      $div.append( $b );
      $b = $( "<input>" );
      $b.addClass( "mw-ui-button" )
        .append( $x.clone() )
        .attr( { type: "reset" } )
        .click( GUIDER.flat )
        .css( { "float": ( HINT.ltr ? "right": "left" ) } );
      $div.append( $b )
          .css( { "float": ( HINT.ltr ? "right": "left" ) } );
      GUIDER.$formPage.append( $div );
      mw.hook( PREGO.signature + ".ready" ).add( GUIDER.finish );
   };   // GUIDER.form()



   GUIDER.from = function ( $at ) {
      // Show or clear page name fields
      // Precondition:
      //    $at  -- container
      //    mediawiki.util available
      // Uses:
      //    >  API.single
      //    mw.util.getUrl()
      // 2017-08-04 PerfektesChaos@de.wikipedia
      var $e;
      if ( API.single ) {
         $e = $at.children();
         if ( ! $e.length ) {
            $e = $( "<a>" );
            $e.attr( { target: "_blank" } );
            $at.append( $e );
         }
         $e.attr( { href: mw.util.getUrl( API.single ) } )
           .text( API.single );
         $at.show();
      } else {
         $at.hide();
      }
   };   // GUIDER.from()



   GUIDER.furnish = function ( $area ) {
      // Equip page with docpage and intro
      // Precondition:
      //    $area  -- mw-content-text
      //    DOM ready
      // Uses:
      //    >  Signature
      //    >  HINT.$body
      //    >  HINT.ltr
      //    >  BOX.bgcOk
      //    >  HINT.using
      //     < HINT.$page
      //     < GUIDER.$doc
      //     < GUIDER.$desc
      //     < GUIDER.$formText
      //     < GUIDER.$textarea
      //     < GUIDER.$formPage
      //     < GUIDER.$input
      //     < HINT.$textarea
      //    face()
      //    PREGO.foreign()
      //    mw.loader.using()
      //    (GUIDER.foreign)
      // 2017-10-06 PerfektesChaos@de.wikipedia
      var $v = $( "head" ),
          $e = $v.find( "title" );
      $e.remove();
      $e = $( "<title>" );
      $e.text( Signature );
      $v.prepend( $e );
      HINT.$page = $area;
      HINT.$page.empty();
      face();
      $v = HINT.$body.find( "#firstHeading,#section_0" );
      if ( ! $v.length ) {
         $v = $( "h1" );
      }
      $v.eq( 0 ).text( Signature );
      $v = $( "<div>" );
      $v.css( { "clear":  "both" } );
      GUIDER.$doc = $( "<span>" );
      GUIDER.$doc.text( Signature + "@PerfektesChaos" );
      $e = $( "<span>" );
      $e.css( { "font-size": "smaller" } )
        .css( "margin-" + ( HINT.ltr ? "left": "right" ),
              "2em" )
        .text( Version );
      $v.append( GUIDER.$doc, $e );
      GUIDER.$desc = $( "<div>" );
      GUIDER.$desc.css( { "font-size": "111%" } )
                  .text( String.fromCharCode( 160 ) );
      $v.append( $v, GUIDER.$desc );
      HINT.$page.append( $v );
      GUIDER.$formText = $( "<form>" );
      GUIDER.$textarea = $( "<textarea>" );
      GUIDER.$textarea.addClass( "mw-ui-input" )
                      .attr( { name: "wikitext" } )
                      .css( { "margin-top": "2em",
                              "max-width":  "100%",
                              "width":      "100%" } );
      GUIDER.$formText.append( GUIDER.$textarea );
      GUIDER.$formPage = $( "<form>" );
      GUIDER.$formPage.css( { "clear":      "both",
                              "margin-top": "3em" } );
      GUIDER.$input = $( "<input>" );
      GUIDER.$input.addClass( "mw-ui-input" )
                   .attr( { maxlength: 255,
                            name:      "pagename",
                            size:      50,
                            type:      "text" } )
                   .css( { "float":  ( HINT.ltr ? "left": "right" ),
                           "width":      "auto",
                           "max-width":  "auto" } );
      GUIDER.$formPage.append( GUIDER.$input );
      HINT.$page.append( GUIDER.$formText, GUIDER.$formPage );
      GUIDER.$pagename = $( "<div>" );
      GUIDER.$pagename.attr( { id: Signature + "-pagename" } )
                      .css( { "background-color":  "#" + BOX.bgcOk,
                              "float":    ( HINT.ltr ? "left": "right" ),
                              "margin-bottom":     "1em",
                              "padding":           "4px" } )
                      .hide();
      HINT.$page.prepend( GUIDER.$pagename );
      HINT.$textarea = GUIDER.$textarea;
      mw.loader.using( HINT.using,
                       GUIDER.foreign );
   };   // GUIDER.furnish()



   PREGO.feed = function () {
      // Provide PREGO
      // Uses:
      //    >  PREGO.signature
      //    mw.loader.getState()
      //    mw.loader.load()
      // 2017-08-08 PerfektesChaos@de.wikipedia
      var s = "ext.gadget." + PREGO.signature;
      if ( mw.loader.getState( s )  !==  "ready" ) {
         mw.loader.load( "https://en.wikipedia.org"
                         + "/w/index.php?title="
                         + "User:PerfektesChaos/js/"
                         + PREGO.signature + "/r.js"
                         + "&bcache=1&maxage=604812"
                         + "&action=raw"
                         + "&ctype=text/javascript" );
      }
   };   // PREGO.feed()



   TEACH.feed = function ( apply ) {
      // Memorize unknown category
      // Uses:
      //    >< TEACH.o
      //    TEACH.flush()
      // 2018-02-08 PerfektesChaos@de.wikipedia
      if ( typeof TEACH.o  !==  "object" ) {
         TEACH.o = [ ];
      }
      TEACH.o.push( apply );
      TEACH.flush();
   };   // TEACH.feed()



   TEACH.fetch = function () {
      // Consider memorized categories
      // Uses:
      //    >  Signature
      //    >< HINT.errors
      //     < TEACH.o
      //    TEACH.flush()
      // 2018-02-08 PerfektesChaos@de.wikipedia
      var got, i, k, leave, parsed, s, webLs;
      if ( typeof window.localStorage  ===  "object" ) {
         webLs = window.localStorage;
         if ( webLs   &&   typeof webLs.getItem  ===  "function" ) {
            try {
               got = webLs.getItem( Signature );
               if ( got ) {
                  parsed = JSON.parse( got );
                  if ( typeof parsed  ===  "object"
                       &&     parsed    &&
                       typeof parsed.length  ===  "number"
                       &&     parsed.length ) {
                     TEACH.o = parsed;
                     for ( i = 0;  i < TEACH.o.length;  i++ ) {
                        s = TEACH.o[ i ];
                        if ( typeof s  ===  "string"
                             &&     s ) {
                           k = $.inArray( s, HINT.errors );
                           if ( k < 0 ) {
                              HINT.errors.push( s );
                           } else {
                              s = false;
                           }
                        } else {
                           s = false;
                        }
                        if ( ! s ) {
                           TEACH.o.splice( i, 1 );
                           leave = true;
                        }
                     }   // for i
                  }
               }
               if ( typeof TEACH.o  !==  "object" ) {
                  TEACH.o = [ ];
               }
               if ( got   &&   ( leave  ||  ! TEACH.o.length ) ) {
                  TEACH.flush();
               }
            } catch (e) {
            }
         }
      }
   };   // TEACH.fetch()



   TEACH.flush = function () {
      // Update unknown categories memory
      // Uses:
      //    >  Signature
      //    >  TEACH.o
      // 2018-02-08 PerfektesChaos@de.wikipedia
      var webLs;
      if ( typeof window.localStorage  ===  "object" ) {
         webLs = window.localStorage;
         if ( webLs   &&
              typeof webLs.removeItem  ===  "function"   &&
              typeof webLs.setItem  ===  "function" ) {
            try {
               if ( TEACH.o.length ) {
                  webLs.setItem( Signature,
                                 JSON.stringify( TEACH.o ) );
               } else {
                  webLs.removeItem( Signature );
               }
            } catch (e) {
            }
         }
      }
   };   // TEACH.flush()



   first();
}( window.mediaWiki, window.jQuery ) );



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

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