Jump to content

User:PerfektesChaos/js/filesMetaData/lib/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.
/// User:PerfektesChaos/js/filesMetaData/lib/d.js
//  Library for: List metadata of media files
/// 2018-08-24 PerfektesChaos@de.wikipedia
/// Fingerprint: #0#0#
/// @license GPL [//www.mediawiki.org/w/COPYING] (+GFDL, LGPL, CC-BY-SA)
/// <nowiki>
/* global window: false, OO: 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   = -1.3,
       Signature = "filesMetaData",
       Sub       = "lib",
       G, MEDIA, PREGO, TEXTS;



   G = { api:        { Api:    false,
                       errors: false,
                       cl:     { },
                       cm:     { query: false },
                       dc:     { query: false },
                       fi:     { },
                       incr:   10,
                       max:    50,
                       more:   200,
                       qp:     { },
                       reNS:   false,
                       rv:     { },
                       th:     { query: false },
                       trsl:   [ "go",
                                 "sort-ascending",
                                 "sort-descending" ]
                     },
         body:       { legal: true
                     },
         cat:        { legal: true
                     },
         direct:     {
                     },
         extensions: { groups: { audio:  "flac kar midi opus spx wav"
                                         + " mp3 mpga mpa mp2"
                                         + " oga ogg ogm ogv ogx",
                               //image:
                                 paged:  "djvu pdf tiff",
                                 pixel:  "bmp gif jpeg png tiff xcf",
                                 vector: "stl svg",
                                 video:  "mp3 webm webp"
                                         + " ogg ogm ogv ogx" },
                       unique: { apng:  "png",
                                 jpg:   "jpeg",
                                 mid:   "midi",
                                 tif:   "tiff" },
                       valid:  false
                     },
         genuine:    { Category:            { clm:  "SBMTUIECD",
                                              list: false,
                                              live: true },
                       Direct :             { clm:  "UTSBMIECD",
                                              list: false,
                                              live: true },
                       Listfiles:           { clm:  "UTSBIMECD",
                                              list: true,
                                              live: false },
                       Mostimages:          { clm:  "PSBTUMIECD",
                                              list: true,
                                              live: true },
                       Newimages:           { clm:  "UTSBMIECD",
                                              list: true,
                                              live: false },
                       Uncategorizedimages: { clm:  "SBTUMIECD",
                                              list: true,
                                              live: true },
                       Unusedimages:        { clm:  "UTSBMIECD",
                                              list: true,
                                              live: true }
                     },
         head:       { columns: "^MSBUTIPECD",
                       $error:  false,
                       $wrap:   false },
         origin:     [ "Category",
                       "Listfiles",
                       "Mostimages",
                       "Newimages",
                       "Uncategorizedimages",
                       "Unusedimages",
                       "Direct" ],
         query:      { columns: { "#": { type: "n" },   // Serial
                                  "^": { type: "b" },   // mark
                                  "@": { type: "s" },   // File
                                  B:   { api:  "Fsize",
                                         type: "n" },   // Bytes
                                  C:   { api:  "Dtimestamp",
                                         type: "d" },   // Changed
                                  D:   { },             // Description
                                  E:   { api:  "Duser",
                                         type: "s" },   // Editor
                                  I:   { },             // Thumbnail
                                  L:   { },             // Localfile
                                  M:   { type: "s" },   // Mode:extension
                                  P:   { api:  false,
                                         type: "n" },   // Pages using
                                  S:   { api:  "Fsize"
                                       },               // Size px,pages
                                  T:   { api:  "Ftimestamp",
                                         type: "d" },   // Time (upload)
                                  U:   { api:  "Fuser",
                                         type: "s" }    // User (upload)
                                },
                       descr:   { value:   500,   // initial text size
                                  step:    100,
                                  min:     100,
                                  max:   10000 },
                       part:    { value:   50,    // API query chunks
                                  step:    10,
                                  min:     10,
                                  max:    500 },
                       rows:    { value:   200,    // table blocks
                                  step:     20,
                                  min:      20,
                                  max:    1000 },
                       thumb:   { value: 100,     // pixel width
                                  step:   10,
                                  min:    20,
                                  max:   500 }
                     },
         table:      { retrieve: false,
                       thumb:    { css: false,
                                   src: "5/5d/Checker-16x16.png" },
                       $wrap:    false },
         use:        { columns:    false,
                       conditions: false,
                       descr:      false,
                       directs:    false,
                       part:       false,
                       permit:     false,
                       rows:       false,
                       source:     false,
                       sub:        false,
                       target:     "_blank",
                       thumb:      false
                     },
         wikitext:   { }
      };



   TEXTS = {
      // 2018-08-05 PerfektesChaos@de.wikipedia
      "About":   {"en": "Show sortable metadata of media files.",
                  "de": "Zeige sortierbare Metadaten zu Mediendateien."},
      "Domain":  {"en": "en.wikipedia.org",
                  "de": "de.wikipedia.org"},
      "cache":   {"en": "Clear gadget cache",
                  "de": "Gadget-Cache leeren"},
      "clm.#":   {"en": "#"},
      "clm.^":   {"en": "Mark files",
                  "de": "Markieren von Dateien"},
      "clm.@":   {"en": "File"},
      "clm.B":   {"en": "Size (bytes)",
                  "de": "Größe (Bytes)"},
      "clm.C":   {"en": "Changed (description)",
                  "de": "Geändert (Beschreibung)"},
      "clm.D":   {"en": "Description",
                  "de": "Beschreibung"},
      "clm.E":   {"en": "Editor (description)",
                  "de": "Bearbeitet (Beschreibung)"},
      "clm.I":   {"en": "Thumbnail",
                  "de": "Miniatur"},
      "clm.M":   {"en": "Extension",
                  "de": "Endung"},
      "clm.P":   {"en": "Pages using",
                  "de": "Nutzende Seiten"},
      "clm.S":   {"en": "Size (pixel)",
                  "de": "Größe (Pixel)"},
      "clm.T":   {"en": "Timestamp (upload)",
                  "de": "Zeitpunkt (Hochladen)"},
      "clm.U":   {"en": "User (upload)",
                  "de": "Benutzer (Hochladen)"},
      "columns": {"en": "Columns",
                  "de": "Spalten"},
      "descr":   {"en": "Initial description text length",
                  "de": "Erste Zeichen des Beschreibungstexts"},
      "direct":  {"en": "Plain list of media identifiers",
                  "de": "Freie Auflistung von Medienbezeichnern"},
      "exports": {"en": "Export",
                  "de": "Export"},
      "exportW": {"en": "Export wikitable",
                  "de": "Exportiere wikitable"},
      "exportX": {"en": "Export file list",
                  "de": "Exportiere Dateiliste"},
      "filter":  {"en": "Filter",
                  "de": "Filter"},
      "filterB": {"en": "Identifier",
                  "de": "Bezeichner"},
      "filterBt":{"en": "Substring or RegExp",
                  "de": "Teilzeichenkette oder RegExp"},
      "filterE": {"en": "Types",
                  "de": "Dateitypen"},
      "invert":  {"en": "invert",
                  "de": "Umkehren"},
      "mark":    {"en": String.fromCharCode( 8730 ) },
      "markAll": {"en": "Mark all",
                  "de": "Alle markieren"},
      "markNone":{"en": "Mark none",
                  "de": "Nichts markieren"},
      "noCat":   {"en": "Apparently no category description.",
                  "de": "Anscheinend keine Kategoriebeschreibung."},
      "noFiles": {"en": "No matching files.",
                  "de": "Keine zutreffenden Dateien."},
      "origin":  {"en": "Origin",
                  "de": "Datenherkunft"},
      "part":    {"en": "API query chunk size",
                  "de": "Größe des Abfrageblocks zur API"},
      "plain":   {"en": "Individual list",
                  "de": "Individuelle Liste"},
      "rows":    {"en": "Number of table rows per block",
                  "de": "Anzahl der Zeilen je Tabellenblock"},
      "thumb":   {"en": "Thumbnail width",
                  "de": "Miniaturbildbreite"},
      "typesEx": "png SVG audio/* pdf"
   };



   function first() {
      // Autorun on loading
      // Uses:
      //    >  Signature
      //    >  Sub
      //    >  Version
      //     < G.vsn
      //    mw.loader.getState()
      //    mw.loader.state()
      //    mw.hook()
      // 2018-08-24 PerfektesChaos@de.wikipedia
      var rls, s;
      G.signature = Signature + "." + Sub;
      s = "ext.gadget." + G.signature;
      if ( mw.loader.getState( s )  !==  "ready" ) {
         rls = { };
         rls[ s ] = "ready";
         mw.loader.state( rls );
         G.vsn = Version;
         mw.hook( G.signature + ".ready" ).fire( G );
      }
   }   // first()



   G.fair = function ( ask ) {
      // Normalize presumable title spacers
      // Precondition:
      //    ask  -- string, with title
      // Postcondition:
      //    Returns normalized title
      // Uses:
      //    >  G.reSpc
      //    >< G.reUnder
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var set = ask;
      if ( set.indexOf( "_" ) >= 0 ) {
         if ( typeof G.reUnder  !==  "object" ) {
            G.reUnder = new RegExp( "[_ ]+", "g" );
         }
         set = set.replace( G.reUnder, " " );
      }
      return set.replace( G.reSpc, " " );
   };   // G.fair()



   G.features = function ( about ) {
      // Format size details
      // Precondition:
      //    about  -- FileInfo object
      // 2018-05-20 PerfektesChaos@de.wikipedia
      var r;
      if ( typeof about.width  ===  "number"   &&
           typeof about.height  ===  "number" ) {
         r = about.width  +  String.fromCharCode( 215 )  +  about.height;
      }
      if ( typeof about.pagecount  ===  "number" ) {
         r = ( r  ?  r + " "  : "" )   +   "(" + about.pagecount + ")";
      }
      return r;
   };   // G.features()



   G.fine = function ( ask ) {
      // Check validity of presumable title
      // Precondition:
      //    ask  -- string, with title
      // Postcondition:
      //    Returns true if suitable
      // 2018-06-03 PerfektesChaos@de.wikipedia
      return ( ask.indexOf( "<" ) < 0   &&
               ask.indexOf( "|" ) < 0   &&
               ask.indexOf( ">" ) < 0   &&
               ask.indexOf( "[" ) < 0   &&
               ask.indexOf( "]" ) < 0   &&
               ask.indexOf( "{{" ) < 0  &&
               ask.indexOf( "}}" ) < 0 );
   };   // G.fine()



   G.first = function ( app ) {
      // Start work
      // Precondition:
      //    app  -- PREGO library
      //    DOM ready
      //    Resources arrived
      // Uses:
      //     < PREGO
      //     < MEDIA
      //    G.head.first()
      //    G.api.foreign()
      // 2018-06-10 PerfektesChaos@de.wikipedia
      PREGO = app;
      G.head.first();
      MEDIA = { };
      G.api.foreign();
   };   // G.first()



   G.flat = function ( apply ) {
      // Normalize fragment identifier
      // Precondition:
      //    apply  -- string, with file title
      // Postcondition:
      //    Returns normalized identifier
      // Uses:
      //    >  G.reDot
      //    >  G.reSpc
      // 2018-05-20 PerfektesChaos@de.wikipedia
      return "_" + apply.replace( G.reDot, "_" )
                        .replace( G.reSpc, "_" );
   };   // G.flat()



   G.foreign = function () {
      // Receive system message translations
      // Uses:
      //    >  G.api.trsl
      //    >< TEXTS
      //    mw.config.get()
      //    PREGO.translation()
      //    G.head.form()
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var rooms = mw.config.get( "wgFormattedNamespaces" ),
          i, s;
      TEXTS[ "clm.@" ] = { "en": rooms[ "6" ] };
      TEXTS.Special    = rooms[ "-1" ];
      TEXTS.Category   = rooms[ "14" ];
      TEXTS.Direct     = PREGO.translation( TEXTS.direct );
      for ( i = 0;  i < G.api.trsl.length;  i++ ) {
         s = G.api.trsl[ i ];
         if ( mw.messages.exists( s ) ) {
            TEXTS[ s ] = mw.message( s ).text();
         } else {
            TEXTS[ s ] = s;
         }
      }   // for i
      G.head.form();
   };   // G.foreign()



   G.from = function ( at ) {
      // Format ISO timestamp
      // Precondition:
      //    at  -- timestamp
      // Postcondition:
      //    Returns formatted timestamp
      // Uses:
      //    >  G.extensions
      // 2018-05-20 PerfektesChaos@de.wikipedia
      return at.substr( 0, 10 )  + " "  +  at.substr( 11, 5 );
   };   // G.from()



   G.front = function ( ask, area ) {
      // Strip certain leading namespace
      // Precondition:
      //    ask   -- page name
      //    area  -- namespace number
      // Postcondition:
      //    Returns formatted timestamp
      // Uses:
      //    >  G.reSpc
      //    >< G.wgNamespaceIds
      //    mw.config.get()
      // 2018-05-20 PerfektesChaos@de.wikipedia
      var s = ask,
          k, space;
      if ( s ) {
         k = s.indexOf( ":" );
         if ( k > 0 ) {
            space = s.substr( 0, k )
                     .trim()
                     .toLowerCase()
                     .replace( G.reSpc, "_" );
            if ( typeof G.wgNamespaceIds  !==  "object" ) {
               G.wgNamespaceIds = mw.config.get( "wgNamespaceIds" );
            }
            if ( typeof G.wgNamespaceIds[ space ]  ===  "number"
                 &&     G.wgNamespaceIds[ space ]  ===  area ) {
               s = s.substr( k + 1 ).trim();
            }
         }
      }
      return s;
   };   // G.front()



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



   G.api.flop = function () {
      // Abort retrieval
      // Uses:
      //     < G.api.cm.query
      //     < G.api.fi.titles
      //     < G.api.qp.query
      //     < G.api.rv.titles
      // 2018-05-20 PerfektesChaos@de.wikipedia
      G.api.cm.query  = false;
      G.api.fi.titles = [ ];
      G.api.qp.query  = false;
      G.api.rv.titles = [ ];
   };   // G.api.flop()



   G.api.foreign = function () {
      // Retrieve system message translations
      // Uses:
      //    >  G.origin
      //    >< G.api.trsl
      //    >< G.api.Api
      //    (G.foreign)
      //    (G.api.fault)
      // 2018-05-20 PerfektesChaos@de.wikipedia
      var i;
      for ( i = 1;  i < G.origin.length - 1;  i++ ) {
         G.api.trsl.push( G.origin[ i ] );
      }   // for i
      if ( ! G.api.Api ) {
         G.api.Api = new mw.Api();
      }
      G.api.Api.loadMessagesIfMissing( G.api.trsl ).done( G.foreign )
                                                   .fail( G.api.fault );
   };   // G.api.foreign()



   G.api.cl.feed = function ( at, after ) {
      // Retrieve category basics
      // Precondition:
      //    at     -- string, category title, or false to continue
      //    after  -- function, aftermath, or false to continue
      // Uses:
      //    >  G.use.sub
      //    >  G.api.Api
      //    >< G.api.cl.query
      //    >< G.api.reNS
      //     < G.api.cl.follow
      //    (G.api.cl.fine)
      //    (G.api.fault)
      // 2018-05-20 PerfektesChaos@de.wikipedia
      if ( ! G.api.cl.query ) {
         G.api.cl.query  = { "action": "query",
                             "prop":   "categories" };
         G.api.cl.follow = after;
         if ( ! G.api.reNS ) {
            G.api.reNS = new RegExp( "^[^:]+:" );
         }
      }
      G.api.cl.query.titles = "Category:" + at;
      G.api.Api.get( G.api.cl.query ).done( G.api.cl.fine )
                                     .fail( G.api.fault );
   };   // G.api.cl.feed()



   G.api.cl.fine = function ( arrived ) {
      // Description pages result arrived
      // Precondition:
      //    arrived  -- JSON result of ajax query
      // Uses:
      //    >  G.api.reNS
      //    >  G.api.cl.follow
      //    G.table.()
      // 2018-05-20 PerfektesChaos@de.wikipedia
      var e, got, i, k, s;
      if ( typeof arrived  ===  "object"
           &&     arrived   &&
           typeof arrived.query  ===  "object"
           &&     arrived.query   &&
           typeof arrived.query.pages  ===  "object"
           &&     arrived.query.pages ) {
         for ( k in arrived.query.pages ) {
            e = arrived.query.pages[ k ];
            if ( typeof e  ===  "object"
                 &&     e   &&
                 typeof e.categories  ===  "object"
                 &&     e.categories   &&
                 typeof e.categories.length  ===  "number"
                 &&     e.categories.length ) {
               got = [ ];
               e   = e.categories;
               for ( i = 0;  i < e.length;  i++ ) {
                  if ( typeof e[ i ].title  ===  "string"
                       &&     e[ i ].title ) {
                     s = e[ i ].title.replace( G.api.reNS, "" );
                     got.push( s );
                  }
               }   // for i
               if ( typeof arrived[ "continue" ]  ===  "object"
                    &&     arrived[ "continue" ] ) {
                  got.push( false );
               }
            }
            break;   // for k in arrived.query.pages
         }   // for k in arrived.query.pages
      }
      G.api.cl.follow( got );
   };   // G.api.cl.fine()



   G.api.cm.feed = function ( alike, after, at ) {
      // Retrieve category members
      // Precondition:
      //    alike  -- boolean, true for subcats, or false for files
      //    after  -- function, aftermath, or false to continue
      //    at     -- string, category title, or false to continue
      // Uses:
      //    >  G.api.incr
      //    >  G.api.Api
      //    >< G.api.cm.follow
      //    >< G.api.cm.query
      //    >< G.api.cm.cmcontinue
      //     < G.api.cm.like
      //    G.api.cm.follow()
      //    (G.api.cm.fine)
      //    (G.api.fault)
      // 2018-06-03 PerfektesChaos@de.wikipedia
      if ( after ) {
         if ( ! G.api.cm.query ) {
            G.api.cm.query = { "action": "query",
                               "list":   "categorymembers" };
         }
         G.api.cm.follow = after;
         G.api.cm.like   = alike;
         if ( at ) {
            G.api.cm.query.cmtitle = "Category:" + at;
            G.api.cm.cmcontinue    = true;
            if ( ! G.api.reNS ) {
               G.api.reNS = new RegExp( "^[^:]+:" );
            }
         }
      }
      if ( G.api.cm.query ) {
         G.api.cm.query.cmtype  = ( alike ? "subcat" :
                                            "file" );
         G.api.cm.query.cmlimit = G.api.incr;
         if ( alike ) {
            if ( G.api.incr < 100 ) {
               G.api.cm.query.cmlimit = 100;
            }
            if ( typeof G.api.cm.query.cmcontinue  ===  "string" ) {
               delete G.api.cm.query.cmcontinue;
            }
         } else if ( typeof G.api.cm.cmcontinue  ===  "string" ) {
            G.api.cm.query.cmcontinue = G.api.cm.cmcontinue;
         }
         if ( alike || G.api.cm.cmcontinue ) {
            G.api.Api.get( G.api.cm.query ).done( G.api.cm.fine )
                                           .fail( G.api.fault );
         } else {
            G.api.cm.follow( false );
         }
      } else {
         G.api.cm.follow();
      }
   };   // G.api.cm.feed()



   G.api.cm.fine = function ( arrived ) {
      // Special page result arrived
      // Precondition:
      //    arrived  -- JSON result of ajax query
      // Uses:
      //    >  G.api.cm.query
      //    >  G.api.reNS
      //    >  G.api.cm.follow
      //    >  G.api.cm.like
      //     < G.api.cm.cmcontinue
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var cm, e, g, got, i, longer;
      if ( typeof arrived  ===  "object"
           &&     arrived ) {
         if ( typeof arrived[ "continue" ]  ===  "object"
              &&     arrived[ "continue" ]   &&
              typeof arrived[ "continue" ].cmcontinue  ===  "string"
              &&     arrived[ "continue" ].cmcontinue ) {
            longer = true;
            if ( ! G.api.cm.like ) {
               G.api.cm.cmcontinue = arrived[ "continue" ].cmcontinue;
               G.api.cm.query.cmcontinue = G.api.cm.cmcontinue;
            }
         } else {
            delete G.api.cm.cmcontinue;
         }
         if ( typeof arrived.query  ===  "object"
              &&     arrived.query   &&
              typeof arrived.query.categorymembers  ===  "object"
              &&     arrived.query.categorymembers ) {
            cm = arrived.query.categorymembers;
            if ( typeof cm  ===  "object"
                 &&     cm    &&
                 typeof cm.length  ===  "number"
                 &&     cm.length ) {
               got = [ ];
               for ( i = 0;  i < cm.length;  i++ ) {
                  G.api.cm.items++;
                  e = cm[ i ];
                  if ( typeof e.title  ===  "string"
                       &&     e.title ) {
                     g      = [ ];
                     g[ 0 ] = e.title.replace( G.api.reNS, "" );
                     got.push( g );
                  }
               }   // for i
               if ( G.api.cm.like && longer ) {
                  got.push( false );
               }
            }
         }
      }
      G.api.cm.follow( got );
   };   // G.api.cm.fine()



   G.api.dc.feed = function ( at, after ) {
      // Retrieve file description
      // Precondition:
      //    at     -- string, file title
      //    after  -- function, aftermath
      // Uses:
      //    >  G.api.Api
      //    >< G.api.dc.query
      //     < G.api.dc.follow
      //    (G.api.dc.fine)
      //    (G.api.fault)
      // 2018-05-20 PerfektesChaos@de.wikipedia
      if ( ! G.api.dc.query ) {
         G.api.dc.query  = { "action":  "query",
                             "prop":    "revisions",
                             "rvlimit": 1,
                             "rvprop":  "content" };
         G.api.dc.follow = after;
      }
      G.api.dc.query.titles = "File:" + at;
      G.api.Api.get( G.api.dc.query ).done( G.api.dc.fine )
                                     .fail( G.api.fault );
   };   // G.api.dc.feed()



   G.api.dc.fine = function ( arrived ) {
      // Description pages result arrived
      // Precondition:
      //    arrived  -- JSON result of ajax query
      // Uses:
      //    >  G.api.reNS
      //    >  G.api.dc.follow
      // 2018-05-20 PerfektesChaos@de.wikipedia
      var e, k, show, sign;
      if ( typeof arrived  ===  "object"
           &&     arrived   &&
           typeof arrived.query  ===  "object"
           &&     arrived.query   &&
           typeof arrived.query.pages  ===  "object"
           &&     arrived.query.pages ) {
         for ( k in arrived.query.pages ) {
            e = arrived.query.pages[ k ];
            if ( typeof e  ===  "object"
                 &&     e   &&
                 typeof e.title  ===  "string" ) {
               if ( typeof e.revisions  ===  "object"
                    &&     e.revisions   &&
                    typeof e.revisions.length  ===  "number"
                    &&     e.revisions.length ) {
                  show = e.revisions[ 0 ][ "*" ];
               } else {
                  show = true;
               }
               sign = e.title.replace( G.api.reNS, "" );
               G.api.dc.follow( sign, show );
            }
            break;   // for k in arrived.query.pages
         }   // for k in arrived.query.pages
      }
   };   // G.api.dc.fine()



   G.api.fi.feed = function ( ahead ) {
      // Retrieve file infos
      // Precondition:
      //    ahead  -- true, if initialization
      // Uses:
      //    >  G.api.fi.props
      //    >  G.api.fi.titles
      //    >  G.api.max
      //    >  G.api.Api
      //    >  G.api.fi.follow
      //    >< G.api.fi.query
      //    >< G.api.reNS
      //     < G.api.fi.got
      //    G.table.filling()
      //    (G.api.fi.fine)
      //    (G.api.fault)
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var n = G.api.fi.titles.length,
          i, m, s;
      if ( n ) {
         if ( ahead ) {
            G.api.fi.query = { "action":   "query",
                               "continue": "",
                               "prop":     "imageinfo",
                               "iiprop":   G.api.fi.props };
            G.api.fi.got   = { };
            if ( ! G.api.reNS ) {
               G.api.reNS = new RegExp( "^[^:]+:" );
            }
         }
         m = ( n > G.api.max  ?  n - G.api.max  :  0 );
         s = "";
         for ( i = m;  i < n;  i++ ) {
            s = s + "|File:" + G.api.fi.titles[ i ];
         }   // for i
         G.api.fi.query.titles = s.substr( 1 );
         G.api.fi.titles.splice( m,  n - m );
         G.api.Api.get( G.api.fi.query ).done( G.api.fi.fine )
                                        .fail( G.api.fault );
      } else {
         G.table.filling( G.api.fi.got, G.api.fi.follow );
      }
   };   // G.api.fi.feed()



   G.api.fi.fine = function ( arrived ) {
      // FileInfo result arrived
      // Precondition:
      //    arrived  -- JSON result of ajax query
      // Uses:
      //    >< G.api.fi.got
      //    G.features()
      //    G.from()
      //    G.api.fi.feed()
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var e, got, k, s;
      if ( typeof arrived  ===  "object"
           &&     arrived   &&
           typeof arrived.query  ===  "object"
           &&     arrived.query   &&
           typeof arrived.query.pages  ===  "object"
           &&     arrived.query.pages ) {
         for ( k in arrived.query.pages ) {
            e = arrived.query.pages[ k ];
            if ( typeof e  ===  "object"
                 &&     e   &&
                 typeof e.imageinfo  ===  "object"
                 &&     e.imageinfo   &&
                 typeof e.imageinfo.length  ===  "number"
                 &&     e.imageinfo.length   &&
                 typeof e.title  ===  "string" ) {
               got = false;
               if ( typeof e.imagerepository  ===  "string" ) {
                  switch ( e.imagerepository ) {
                     case "local":
                        got = { L: true };
                        break;
                     case "shared":
                        got = { L: false };
                        break;
                  }   //   switch e.imagerepository
               }
               s   = e.title.replace( G.api.reNS, "" );
               e   = e.imageinfo[ 0 ];
               if ( typeof e.size  ===  "number" ) {
                  got   = got || { };
                  got.B = e.size;
                  got.S = G.features( e );
               }
               if ( typeof e.timestamp  ===  "string" ) {
                  got   = got || { };
                  got.T = G.from( e.timestamp );
               }
               if ( typeof e.user  ===  "string" ) {
                  got   = got || { };
                  got.U = e.user;
               }
               if ( got ) {
                  G.api.fi.got[ s ] = got;
               }
            }
         }   // for s in arrived.query.pages
      }
      G.api.fi.feed();
   };   // G.api.fi.fine()



   G.api.qp.feed = function ( action, after ) {
      // Retrieve file names etc. like special page
      // Precondition:
      //    action  -- string, special page name, or false to continue
      //    after   -- function, aftermath, or false to continue
      // Uses:
      //    >  G.api.Api
      //    >  G.api.incr
      //    >< G.api.reNS
      //    >< G.api.qp.items
      //    >< G.api.qp.max
      //    >< G.api.qp.follow
      //    >< G.api.qp.query
      //     < G.api.qp.source
      //    (G.api.qp.fine)
      //    (G.api.fault)
      // 2018-05-20 PerfektesChaos@de.wikipedia
      if ( action ) {
         G.api.qp.items = 0;
         G.api.qp.max   = 99999999;
         if ( ! G.api.reNS ) {
            G.api.reNS = new RegExp( "^[^:]+:" );
         }
         G.api.qp.source = action;
         G.api.qp.follow = after;
         G.api.qp.query  = { "action":   "query",
                             "continue": "",
                             "list":     "querypage",
                             "qppage":   action };
      }
      if ( G.api.qp.query  &&  G.api.qp.items < G.api.qp.max ) {
         G.api.qp.query.qplimit = G.api.incr;
         G.api.Api.get( G.api.qp.query ).done( G.api.qp.fine )
                                        .fail( G.api.fault );
      } else if ( G.api.qp.follow ) {
         G.api.qp.follow( G.api.qp.query );
      }
   };   // G.api.qp.feed()



   G.api.qp.fine = function ( arrived ) {
      // Special page result arrived
      // Precondition:
      //    arrived  -- JSON result of ajax query
      // Uses:
      //    >  G.api.reNS
      //    >  G.api.qp.follow
      //    >< G.api.qp.query
      //    >< G.api.qp.items
      //     < G.api.qp.max
      //    G.from()
      // 2018-05-20 PerfektesChaos@de.wikipedia
      var e, g, got, i, qp;
      if ( typeof arrived  ===  "object"
           &&     arrived ) {
         if ( typeof arrived[ "continue" ]  ===  "object"
              &&     arrived[ "continue" ]   &&
              typeof arrived[ "continue" ].qpoffset  ===  "number" ) {
            G.api.qp.query.qpoffset = arrived[ "continue" ].qpoffset;
         } else {
            G.api.qp.query = false;
         }
         if ( typeof arrived.query  ===  "object"
              &&     arrived.query   &&
              typeof arrived.query.querypage  ===  "object"
              &&     arrived.query.querypage ) {
            qp = arrived.query.querypage;
            if ( typeof qp.maxresults  ===  "number" ) {
               G.api.qp.max = qp.maxresults;
            }
            if ( typeof qp.results  ===  "object"
                 &&     qp.results    &&
                 typeof qp.results.length  ===  "number"
                 &&     qp.results.length ) {
               got = [ ];
               for ( i = 0;  i < qp.results.length;  i++ ) {
                  G.api.qp.items++;
                  e = qp.results[ i ];
                  if ( typeof e.title  ===  "string"
                       &&     e.title ) {
                     g      = [ ];
                     g[ 0 ] = e.title.replace( G.api.reNS, "" );
                     switch ( G.api.qp.source ) {
                        case "Mostimages":
                           if ( typeof e.value  ===  "string" ) {
                              g[ 1 ] = { P: parseInt( e.value, 10 ) };
                           }
                           break;
                        case "Uncategorizedimages":
                           // e.value ->P  ???
                           break;
                        case "Unusedimages":
                           if ( typeof e.timestamp  ===  "string" ) {
                              g[ 1 ] = { T: G.from( e.timestamp ) };
                           }
                           break;
                     }   // switch assign
                     got.push( g );
                  }
               }   // for i
            }
         }
      }
      G.api.qp.follow( got );
   };   // G.api.qp.fine()



   G.api.rv.feed = function ( ahead ) {
      // Retrieve file description pages metadata
      // Precondition:
      //    ahead  -- true, if initialization
      // Uses:
      //    >  G.api.rv.props
      //    >  G.api.rv.titles
      //    >  G.api.max
      //    >  G.api.Api
      //    >< G.api.rv.follow
      //    >< G.api.rv.query
      //    >< G.api.reNS
      //     < G.api.rv.got
      //    G.table.filling()
      //    (G.api.rv.fine)
      //    (G.api.fault)
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var n = G.api.rv.titles.length,
          i, m, s;
      if ( n ) {
         if ( ahead ) {
            G.api.rv.query = { "action":   "query",
                               "continue": "",
                               "prop":     "revisions",
                               "rvprop":   G.api.rv.props };
            G.api.rv.got   = { };
         }
         m = ( n > G.api.max  ?  n - G.api.max  :  0 );
         s = "";
         for ( i = m;  i < n;  i++ ) {
            s = s + "|File:" + G.api.rv.titles[ i ];
         }   // for i
         G.api.rv.query.titles = s.substr( 1 );
         G.api.rv.titles.splice( m,  n - m );
         G.api.Api.post( G.api.rv.query ).done( G.api.rv.fine )
                                         .fail( G.api.fault );
      } else {
         G.table.filling( G.api.rv.got, G.api.rv.follow );
      }
   };   // G.api.rv.feed()



   G.api.rv.fine = function ( arrived ) {
      // Description pages result arrived
      // Precondition:
      //    arrived  -- JSON result of ajax query
      // Uses:
      //    >  G.api.reNS
      //    >< G.api.rv.got
      //    G.features()
      //    G.from()
      //    G.api.rv.feed()
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var e, got, k, s;
      if ( typeof arrived  ===  "object"
           &&     arrived   &&
           typeof arrived.query  ===  "object"
           &&     arrived.query   &&
           typeof arrived.query.pages  ===  "object"
           &&     arrived.query.pages ) {
         for ( k in arrived.query.pages ) {
            e = arrived.query.pages[ k ];
            if ( typeof e  ===  "object"
                 &&     e   &&
                 typeof e.revisions  ===  "object"
                 &&     e.revisions   &&
                 typeof e.revisions.length  ===  "number"
                 &&     e.revisions.length   &&
                 typeof e.title  ===  "string" ) {
               got = { L: true };
               s   = e.title.replace( G.api.reNS, "" );
               e   = e.revisions[ 0 ];
               if ( typeof e.timestamp  ===  "string" ) {
                  got.C = G.from( e.timestamp );
               }
               if ( typeof e.user  ===  "string" ) {
                  got   = got || { };
                  got.E = e.user;
               }
            } else {
               got = { L: false };
            }
            G.api.rv.got[ s ] = got;
         }   // for k in arrived.query.pages
      }
      G.api.rv.feed();
   };   // G.api.rv.fine()



   G.api.th.feed = function ( at ) {
      // Retrieve miniature specification
      // Precondition:
      //    at  -- string, file title
      // Uses:
      //    >  G.api.Api
      //    >  G.use.thumb
      //    >< G.api.th.query
      //    (G.api.th.fine)
      //    (G.api.fault)
      // 2018-05-20 PerfektesChaos@de.wikipedia
      if ( ! G.api.th.query ) {
         G.api.th.query = { "action":   "query",
                            "prop":     "imageinfo",
                            "iiprop":   "url" };
      }
      G.api.th.query.titles = "File:" + at;
      G.api.th.query.iiurlwidth = G.use.thumb;
      G.api.Api.get( G.api.th.query ).done( G.api.th.fine )
                                     .fail( G.api.fault );
   };   // G.api.th.feed()



   G.api.th.fine = function ( arrived ) {
      // Miniature specification result arrived
      // Precondition:
      //    arrived  -- JSON result of ajax query
      // Uses:
      //    >  G.api.reNS
      //    G.table.filed()
      // 2018-06-10 PerfektesChaos@de.wikipedia
      var e, got, k, s;
      if ( typeof arrived  ===  "object"
           &&     arrived   &&
           typeof arrived.query  ===  "object"
           &&     arrived.query   &&
           typeof arrived.query.pages  ===  "object"
           &&     arrived.query.pages ) {
         for ( k in arrived.query.pages ) {
            e = arrived.query.pages[ k ];
            if ( typeof e  ===  "object"
                 &&     e   &&
                 typeof e.title  ===  "string" ) {
               s = e.title.replace( G.api.reNS, "" );
               if ( typeof e.imageinfo  ===  "object"
                    &&     e.imageinfo   &&
                    typeof e.imageinfo.length  ===  "number"
                    &&     e.imageinfo.length ) {
                  e   = e.imageinfo[ 0 ];
                  got = { u: e.thumburl,
                          h: e.thumbheight,
                          w: e.thumbwidth };
                  G.table.filed( s, got );
               }
            }
            break;   // for k in arrived.query.pages
         }   // for k in arrived.query.pages
         if ( s  &&  ! got ) {
            G.table.filed( s, false );
         }
      }
   };   // G.api.th.fine()



   G.body.fairly = function () {
      // Query current validity
      // Postcondition:
      //    Returns true if suitable
      // Uses:
      //    >  G.body.legal
      // 2018-06-03 PerfektesChaos@de.wikipedia
      return G.body.legal;
   };   // G.body.fairly()



   G.body.filter = function ( allow ) {
      // Check title filter condition
      // Precondition:
      //    allow  --  string with title body
      // Postcondition:
      //    Returns true if suitable
      // Uses:
      //    >  G.use.conditions.body
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var body, r;
      if ( G.use.conditions   &&
           typeof G.use.conditions.body  ===  "object"   &&
           typeof G.use.conditions.body.less    ===  "boolean"   &&
           ( typeof G.use.conditions.body.re  ===  "object"    ||
             typeof G.use.conditions.body.sub  ===  "string" ) ) {
         body = G.use.conditions.body;
         if ( typeof body.re  ===  "object" ) {
            r = body.re.test( allow );
         } else {
            r = ( allow.indexOf( body.sub )  >=  0 );
         }
         r = ( body.less  ?  ! r  :  r );
      } else {
         r = true;
      }
      return r;
   };   // G.body.filter()



   G.body.fired = function () {
      // Filter input for title stem
      // Uses:
      //    >  G.wish.body
      //    >< G.body.reRegExp
      //    >< G.body.legal
      //     < G.use.conditions.ext
      //    G.fair()
      //    G.fine()
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var set = G.wish.body.text.getValue(),
          got, re;
      G.body.legal = true;
      if ( set ) {
         set = G.fair( set );
         if ( set.indexOf( "/" ) > 0 ) {
            if ( typeof G.body.reRegExp  !==  "object" ) {
               G.body.reRegExp = new RegExp( "^/([^/]+)/(i?)$" );
            }
            set = set.trim();
            got = G.body.reRegExp.exec( set );
            if ( got ) {
               try {
                  re = new RegExp( got[ 1 ], got[ 2 ] );
                  G.wish.body.text.setValue( set );
               } catch ( e ) {
                  set = false;
               }
            }
         }
         if ( ! re   &&
              ( ! G.fine( set )  ||
                set.indexOf( "/" ) > 0 ) ) {
            set = false;
         }
         if ( set ) {
            if ( typeof G.use.conditions  !==  "object" ) {
               G.use.conditions = { };
            }
            if ( typeof G.use.conditions.body  !==  "object" ) {
               G.use.conditions.body = { less: false };
            }
            if ( re ) {
               G.use.conditions.body.re  = re;
               G.use.conditions.body.sub = false;
            } else {
               G.use.conditions.body.re  = false;
               G.use.conditions.body.sub = set;
            }
            G.wish.body.check.setDisabled( false );
         } else {
            G.body.legal = false;
            if ( typeof G.use.conditions  ===  "object"   &&
                 typeof G.use.conditions.body  ===  "object" ) {
               if ( G.use.conditions.body.less ) {
                  G.use.conditions.body.re  = false;
                  G.use.conditions.body.sub = false;
               } else {
                  G.use.conditions.body = false;
               }
            }
         }
      } else {
         G.wish.body.check.setSelected( false );
         G.wish.body.check.setDisabled( true );
         if ( typeof G.use.conditions  ===  "object"   &&
              typeof G.use.conditions.body  ===  "object" ) {
            G.use.conditions.body = false;
         }
      }
   };   // G.body.fired()



   G.body.flip = function () {
      // Fired invert checkbox
      // Uses:
      //    >  G.wish.body.check
      //     < G.use.conditions.body.less
      // 2018-06-03 PerfektesChaos@de.wikipedia
      G.use.conditions.body.less = G.wish.body.check.isSelected();
   };   // G.body.flip()



   G.cat.fairly = function () {
      // Query category validity
      // Postcondition:
      //    Returns true if suitable
      // Uses:
      //    >  G.cat.legal
      // 2018-06-03 PerfektesChaos@de.wikipedia
      return G.cat.legal;
   };   // G.cat.fairly()



   G.cat.finish = function () {
      // Category input completed
      // Uses:
      //    >  G.wish.category
      //    >  G.wish.run
      //     < G.use.sub
      //    G.front()
      //    G.fine()
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var s = G.wish.category.getValue().trim();
      G.use.sub = false;
      if ( s ) {
         s = G.front( s, 14 );
         s = s.substr( 0, 1 ).toUpperCase()  +
             s.substr( 1 );
         if ( G.fine( s ) ) {
            G.use.sub = s;
         }
         G.wish.category.setValue( s );
      }
      G.wish.run.setDisabled( ( G.use.sub ? false : true ) );
   };   // G.cat.finish()



   G.cat.fired = function () {
      // Category input
      // Uses:
      //    >  G.wish.category
      //    >< G.reColonLead
      //     < G.cat.legal
      //    G.fair()
      //    G.fine()
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var s = G.wish.category.getValue(),
          k;
      if ( s ) {
         k = s.indexOf( "#" );
         if ( k >= 0 ) {
            s = s.substr( 0, k );
         }
         s = G.fair( s );
         if ( s.substr( 0, 1 ) ===  " " ) {
            s = s.substr( 1 );
         }
         if ( s.indexOf( ":" ) >= 0 ) {
            if ( typeof G.reColonLead  !==  "object" ) {
               G.reColonLead = new RegExp( "^[: ]+", "g" );
            }
            s = s.replace( G.reColonLead, "" );
         }
         G.wish.category.setValue( s );
      }
      G.cat.legal = ( s  &&  G.fine( s ) );
   };   // G.cat.fired()



   G.cat.foreign = function ( assign ) {
      // Category input hook
      // Precondition:
      //    assign  -- string with category title
      //    >  G.wish.category
      //    G.cat.fired()
      //    G.head.form()
      // 2018-08-05 PerfektesChaos@de.wikipedia
      var s;
      if ( typeof assign  ===  "string" ) {
         s = assign.trim();
         if ( s ) {
            G.wish.category.setValue( s );
            G.cat.fired();
            G.head.form();
         }
      }
   };   // G.cat.foreign()



   G.direct.files = function ( apply ) {
      // Bracketed items found
      // Precondition:
      //    apply  -- string with wikitext
      // Uses:
      //    >< G.direct.reBrackOpen
      //    >< G.direct.reBrackTerm
      //    >< G.direct.reBrackPipe
      //    G.front()
      //    G.fine()
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var s = apply,
          g, i, q, s2;
      if ( typeof G.direct.reBrackOpen  !==  "object" ) {
         G.direct.reBrackOpen = new RegExp( "\\[\\[", "g" );
         G.direct.reBrackTerm = new RegExp( "\\]\\]", "g" );
         G.direct.reBrackPipe = new RegExp( "^\\[\\[:?([^|]+:[^|]+)"
                                                   + "(:?\\|.*)?"
                                                   + "\\]\\]$" );
      }
      s = s.replace( G.direct.reBrackTerm, "]]\n" )
           .replace( G.direct.reBrackOpen, "\n[[" );
      q = s.split( "\n" );
      for ( i = q.length - 1;  i >= 0;  i-- ) {
         s = q[ i ].trim();
         if ( s.indexOf( "." ) > 0 ) {
            if ( s.indexOf( "]]" ) > 0 ) {
               g = G.direct.reBrackPipe.exec( s );
               if ( g ) {
                  s2 = g[ 1 ].trim();
                  s  = G.front( s2, 6 );
                  if ( s === s2  ||
                       ! G.fine( s ) ) {
                     s = false;
                  }
               } else {
                  s = false;
               }
            }
         } else {
            s = false;
         }
         if ( s ) {
            q[ i ] = s;
         } else {
            q.splice( i, 1 );
         }
      }   // for i--
      return q.join( "\n" );
   };   // G.direct.files()



   G.direct.finish = function () {
      // Wikitext input completed
      // Uses:
      //    >  G.wish.direct
      //    >  G.extensions.valid
      //    >  G.wish.run
      //    >< G.direct.reTag
      //    >< G.direct.rePipe
      //    >< G.reColonLead
      //     < G.use.directs
      //    G.extensions.factory()
      //    G.fair()
      //    G.fine()
      //    G.extensions.flat()
      //    G.front()
      // 2018-08-05 PerfektesChaos@de.wikipedia
      var s = G.wish.direct.getValue().trim(),
          g, i, k, q, sub;
      G.use.directs = false;
      if ( s ) {
         if ( s.indexOf( ">" ) > 0 ) {
            if ( typeof G.direct.reTag  !==  "object" ) {
               G.direct.reTag = new RegExp( "<[a-z/A-Z][^<>]*>", "g" );
            }
            s = s.replace( G.direct.reTag, "\n" );
         }
         if ( s.indexOf( "]]" ) > 0 ) {
            s = G.direct.files( s );
         }
         if ( s.indexOf( "|" ) >= 0 ) {
            if ( typeof G.direct.rePipe  !==  "object" ) {
               G.direct.rePipe = new RegExp( "\\|", "g" );
            }
            s = s.replace( G.direct.rePipe, "\n" );
         }
         G.extensions.factory();
         q = s.split( "\n" );
         for ( i = q.length - 1;  i >= 0;  i-- ) {
            s = G.fair( q[ i ].trim() );
            k = s.lastIndexOf( "." );
            if ( k > 0  &&
                 s.indexOf( "/" ) <= 0  &&
                 s.indexOf( "#" ) <= 0  &&
                 G.fine( s ) ) {
               sub = s.substr( k + 1 ).toLowerCase();
               sub = G.extensions.flat(  sub );
               if ( typeof G.extensions.valid[ sub ]  ===  "boolean" ) {
                  if ( s.indexOf( ":" ) >= 0 ) {
                     if ( typeof G.reColonLead  !==  "object" ) {
                        G.reColonLead = new RegExp( "^[: ]+", "g" );
                     }
                     s = s.replace( G.reColonLead, "" );
                     s = G.front( s, 6 );
                  }
                  s = s.substr( 0, 1 ).toUpperCase()  +
                      s.substr( 1 );
               } else {
                  s = false;
               }
            } else {
               s = false;
            }
            if ( s ) {
               q[ i ] = s;
            } else {
               q.splice( i, 1 );
            }
         }   // for i--
         g = { };
         for ( i = q.length - 1;  i >= 0;  i-- ) {
            s = q[ i ];
            if ( typeof g[ s ]  ===  "boolean" ) {
               q.splice( i, 1 );
            } else {
               g[ s ] = true;
            }
         }   // for i--
         if ( q.length ) {
            G.use.directs = q;
            s = q.join( "\n" );
         } else {
            s = "";
         }
      }
      G.wish.direct.setValue( s );
      G.wish.run.setDisabled( ( G.use.directs ? false : true ) );
   };   // G.direct.finish()



   G.direct.foreign = function ( assign ) {
      // Category input hook
      // Precondition:
      //    assign  -- string with
      //    >  G.wish.direct
      //    >  G.direct.$textarea
      //    G.direct.finish()
      //    G.head.form()
      // 2018-08-05 PerfektesChaos@de.wikipedia
      var s;
      if ( typeof assign  ===  "string" ) {
         s = assign.trim();
         if ( s ) {
            G.direct.$textarea.show();
            G.wish.direct.setValue( s );
            G.direct.finish();
            G.head.form();
         }
      }
   };   // G.direct.foreign()



   G.extensions.factory = function () {
      // Ensure validation for extensions
      // Uses:
      //    >  G.extensions.groups
      //    >< G.extensions.valid
      //     < G.extensions.groups.image
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var ext = G.extensions,
          g, i, s;
      if ( ! ext.valid ) {
         ext.valid = { };
         for ( s in ext.groups ) {
            g = ext.groups[ s ].split( " " );
            for ( i = 0;  i < g.length;  i++ ) {
               ext.valid[ g[ i ] ] = true;
            }   // for i
         }   // for s in ext.groups
         ext.groups.image = ext.groups.pixel + " " +
                            ext.groups.vector;
      }
   };   // G.extensions.factory()



   G.extensions.filter = function ( allow ) {
      // Check extension filter condition
      // Precondition:
      //    allow  --  string with suffix
      // Postcondition:
      //    Returns true if suitable
      // Uses:
      //    >  G.use.conditions.ext
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var ext, r;
      if ( G.use.conditions   &&
           typeof G.use.conditions.ext  ===  "object"   &&
           typeof G.use.conditions.ext.less    ===  "boolean"   &&
           typeof G.use.conditions.ext.permit  ===  "object" ) {
         ext = G.use.conditions.ext;
         r   = ( typeof ext.permit[ allow ]  ===  "boolean" );
         r   = ( ext.less  ?  ! r  :  r );
      } else {
         r = true;
      }
      return r;
   };   // G.extensions.filter()



   G.extensions.finder = function () {
      // Rebuild permitted extensions from string to object
      // Uses:
      //    >  G.extensions.groups
      //    >< G.use.conditions.ext
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var permit = G.use.conditions.ext.suffix.split( " " ),
          g, i, k, s;
      G.use.conditions.ext.permit = { };
      for ( i = 0;  i < permit.length;  i++ ) {
         s = permit[ i ];
         k = s.indexOf( "/*" );
         if ( k < 0 ) {
            G.use.conditions.ext.permit[ s ] = true;
         } else {
            g = G.extensions.groups[ s.substr( 0, k ) ].split( " " );
            for ( k = 0;  k < g.length;  k++ ) {
               G.use.conditions.ext.permit[ g[ k ] ] = true;
            }   // for k
         }
      }   // for i
   };   // G.extensions.finder()



   G.extensions.fired = function () {
      // Filter input for extensions
      // Uses:
      //    >  G.reSpc
      //    >  G.wish.extensions
      //    >  G.extensions.valid
      //    >  G.extensions.groups
      //     < G.use.conditions.ext
      //    G.extensions.factory()
      //    G.extensions.flat()
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var ext = G.extensions,
          set = G.wish.extensions.text.getValue().trim(),
          g, got, i, k, s;
      if ( set ) {
         G.extensions.factory();
         set = set.replace( G.reSpc, " " )
                  .toLowerCase();
         g   = set.split( " " );
         set = "";
         got = { };
         for ( i = 0;  i < g.length;  i++ ) {
            s = ext.flat( g[ i ] );
            if ( typeof ext.valid[ s ]  !==  "boolean" ) {
               k = s.length - 2;
               if ( k < 4   ||
                    s.substr( k ) !== "/*"   ||
                    typeof ext.groups[ s.substr( 0, k ) ]
                                                        !==  "string" ) {
                  s = false;
               }
            }
            if ( s ) {
               if ( typeof got[ s ]  !==  "boolean" ) {
                  set      = set  +  ( set ? " " : "" )  +  s;
                  got[ s ] = true;
               }
            }
         }   // for i
      }
      G.wish.extensions.text.setValue( set );
      if ( set ) {
         if ( typeof G.use.conditions  !==  "object" ) {
            G.use.conditions = { };
         }
         if ( typeof G.use.conditions.ext  !==  "object" ) {
            G.use.conditions.ext = { less: false };
         }
         G.use.conditions.ext.suffix = set;
         G.wish.extensions.check.setDisabled( false );
      } else {
         G.wish.extensions.check.setSelected( false );
         G.wish.extensions.check.setDisabled( true );
         if ( typeof G.use.conditions  ===  "object"   &&
              typeof G.use.conditions.ext  ===  "object" ) {
            G.use.conditions.ext = false;
         }
      }
   };   // G.extensions.fired()



   G.extensions.flat = function ( after ) {
      // Standard extension
      // Precondition:
      //    after  -- lowercase extension
      // Postcondition:
      //    Returns unified extension
      // Uses:
      //    >  G.extensions.unique
      // 2018-05-20 PerfektesChaos@de.wikipedia
      var r;
      if ( typeof G.extensions.unique[ after ]  ===  "string" ) {
         r = G.extensions.unique[ after ];
      } else {
         r = after;
      }
      return r;
   };   // G.extensions.flat()



   G.extensions.flip = function () {
      // Fired invert checkbox
      // Uses:
      //    >  G.wish.extensions.check
      //     < G.use.conditions.ext.less
      // 2018-06-03 PerfektesChaos@de.wikipedia
      G.use.conditions.ext.less = G.wish.extensions.check.isSelected();
   };   // G.extensions.flip()



   G.head.fault = function ( alert ) {
      // API problem
      // Precondition:
      //    alert  -- string with message, or false to hide
      //    >< G.head.$error
      // 2018-05-20 PerfektesChaos@de.wikipedia
      if ( G.head.$error ) {
         G.head.$error.empty();
         if ( alert ) {
            G.head.$error.text( alert )
                         .show();
         } else {
            G.head.$error.hide();
         }
      }
   };   // G.head.fault()



   G.head.feeder = function ( assigned ) {
      // Origin field changed
      // Precondition:
      //    assigned  -- OO object of RadioOptionWidget
      // Uses:
      //    >  G.wish.category
      //    >  G.direct.$textarea
      //    >  G.wish.run
      //    >  G.use.sub
      //     < G.use.source
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var lock;
      if ( assigned ) {
         lock = ( assigned.data !== "Category" );
         G.use.source = assigned.data;
         G.wish.category.setDisabled( lock );
         if ( assigned.data === "Direct" ) {
            G.direct.$textarea.show();
         } else {
            G.direct.$textarea.hide();
         }
      }
      G.wish.run.setDisabled( ! ( lock || G.use.sub ) );
   };   // G.head.feeder()



   G.head.figure = function ( assign, assigned ) {
      // Create numeric input field
      // Precondition:
      //    assign    -- string with ID of figure
      //    assigned  -- string with value, or not if to be created
      // Uses:
      //    >  G.query
      //    >  TEXTS
      //    >  G.head.$options
      //    >< G.wish
      //    >< G.use
      //     < G.api.incr
      //     < G.api.more
      //    OO.ui.NumberInputWidget()
      //    PREGO.translation()
      //    G.table.fiat()
      //    (G.head.figure)
      // 2018-05-20 PerfektesChaos@de.wikipedia
      var n, o, w, $e, $i, $t;
      if ( typeof assigned  ===  "string" ) {
         n = parseInt( assigned, 10 );
         if ( ! n  ||  isNaN( n ) ) {
            // NaN should never happen since validated
            n = G.use[ assign ];
         } else {
            o = G.query[ assign ];
            if ( n < o.min ) {
               n = o.min;
            } else if ( n > o.max ) {
               n = o.max;
            }
         }
         w = G.wish[ assign ];
         w.setValue( n + "" );
      } else {
         o  = G.query[ assign ];
         n  = o.value;
         w  = new OO.ui.NumberInputWidget( { allowInteger: true,
                                             maxLength:    5,
                                             title:        "≤" + o.max,
                                             input:        { value: n },
                                             min:          o.min,
                                             max:          o.max,
                                             step:         o.step } );
         G.use[ assign ] = o.value;
         w.on( "change", G.head.figure, [ assign ] );
         G.wish[ assign ] = w;
         $e = w.$element;
         $e.css( { "float": ( G.ltr ? "left" : "right" ),
                   "margin-bottom": "1em",
                   "width": "11em" } );
         $t = $( "<div>" );
         $t.css( { "float":  ( G.ltr ? "left" : "right" ),
                   "margin": "0 1em" } )
           .text( PREGO.translation( TEXTS[ assign ] ) );
         $i = $( "<div>" );
         $i.css( { "clear": "both" } )
           .append( $e, $t );
         G.head.$options.append( $i );
      }
      G.use[ assign ] = n;
      switch ( assign ) {
         case "descr":
            break;
         case "part":
            G.api.incr = n;
            break;
         case "rows":
            G.api.more = n;
            G.table.fiat();
            break;
         case "thumb":
            break;
      }   // switch assign
   };   // G.head.figure()



   G.head.filter = function ( assign, about, abbr ) {
      // Create filter group input elements
      // Precondition:
      //    assign  -- string, with component
      //    about   -- string, with tooltip, or not
      //    abbr    -- boolean, abbreviated
      // Uses:
      //    >  G.head.$request
      //    >< G.wish
      //    PREGO.translation()
      //    (G.body.fairly)
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var $d    = $( "<div>" ),
          $i    = $( "<div>" ),
          $w    = $( "<div>" ),
          start = ( G.ltr ? "left" : "right" ),
          w     = new OO.ui.TextInputWidget( { type: "text" } ),
          sign  = assign.substr( 0, 1 ).toUpperCase(),
          $c, $e;
      $d.css( { "float":  start,
                "margin": "1em" } )
        .text( PREGO.translation( TEXTS[ "filter" + sign ] ) );
      if ( typeof about  ===  "string" ) {
         w.setTitle( about );
      }
      $e = w.$element;
      $e.css( { "float":  start,
                "margin": "0.5em 1em 0.5em 1em",
                "width":  ( abbr ? "15em" : "25em" ) } );
      if ( sign === "B" ) {
         w.on( "change", G.body.fired );
         w.setValidation( G.body.fairly );
      } else if ( sign === "E" ) {
         $e.find( "input" ).blur( G[ assign ].fired );
      }
      G.wish[ assign ].text = w;
      w = new OO.ui.CheckboxInputWidget( { disabled: true } );
      w.on( "change", G[ assign ].flip );
      $c = w.$element;
      $c.css( { "float":  start,
                "margin": "1em 0.5em 0em 0.5em" } );
      $i.css( { "float":      start,
                "margin-top": "1em" } )
        .text( PREGO.translation( TEXTS.invert ) );
      G.wish[ assign ].check = w;
      $w.css( { "clear":      "both",
                "margin-top": "0.5em" } )
        .append( $d, $e, $c, $i );
      G.head.$request.append( $w );
   };   // G.head.filter()



   G.head.fire = function () {
      // Start button fired
      // Uses:
      //    >  G.wish.columns
      //    >  G.use.source
      //    >  G.genuine
      //    >  G.use.sub
      //    >  G.wish.cache
      //    G.table.first()
      // 2018-08-05 PerfektesChaos@de.wikipedia
      var checkbox, checked, columns, i, s, suitable, suite;
      G.head.flip();
      checked = G.wish.columns.findSelectedItems();
      if ( checked  &&  typeof checked  ===  "object"
                    &&  typeof checked.length  ===  "number"
                        &&     checked.length ) {
         columns = { };
         suite   = "";
         for ( i = 0;  i < checked.length;  i++ ) {
            checkbox = checked[ i ];
            columns[ checkbox.data ] = true;
         }   // for i
         suitable = "^" + G.genuine[ G.use.source ].clm;
         for ( i = 0;  i < suitable.length;  i++ ) {
            s = suitable.substr( i, 1 );
            if ( typeof columns[ s ]  ===  "boolean" ) {
               suite = suite + s;
            }
         }   // for i
      }
      G.wish.cache.setDisabled( false );
      G.table.first( G.use.source, suite );
   };   // G.head.fire()



   G.head.first = function () {
      // Initialize head region
      // Uses:
      //    >  G.head.$doc
      //    >  TEXTS.Domain
      //    >  TEXTS.About
      //    >  G.$page
      //    PREGO.translation()
      // 2018-05-20 PerfektesChaos@de.wikipedia
      var $e;
      G.head.$doc.attr( { href:   "https://"
                                  + PREGO.translation( TEXTS.Domain )
                                  + "/wiki/"
                                  + "User:PerfektesChaos/js/"
                                  + Signature,
                          target: Signature } );
      $e = $( "<div>" );
      $e.css( { "font-size": "111%" } )
        .html( PREGO.translation( TEXTS.About ) );
      G.$page.append( $e );
      $e = $( "<hr>" );
      $e.css( { "margin":      "1em 0",
                "padding-top": "0.5em" } );
      G.$page.append( $e );
   };   // G.head.first()



   G.head.flat = function () {
      // Clear cache
      // Uses:
      //    >  G.wish.cache
      //     < MEDIA
      // 2018-06-10 PerfektesChaos@de.wikipedia
      G.wish.cache.setDisabled( true );
      MEDIA = { };
   };   // G.head.flat()



   G.head.flip = function () {
      // Hide form in head region
      // Uses:
      //    >  G.head.$error
      //    >  G.head.$show
      //    >  G.head.$request
      //    >  G.head.$run
      // 2018-05-20 PerfektesChaos@de.wikipedia
      G.head.$error.hide();
      G.head.$show.show();
      G.head.$request.hide();
      G.head.$run.hide();
   };   // G.head.flip()



   G.head.focus = function () {
      // Set category input and focus
      // Uses:
      //    >  G.wish.origin
      //    >  G.wish.category
      //    >  G.use.sub
      //    G.head.feeder()
      //    G.head.form()
      // 2018-06-03 PerfektesChaos@de.wikipedia
      G.wish.origin.selectItemByData( "Category" );
      G.wish.category.setDisabled( false );
      G.wish.category.setValue( G.use.sub );
      G.head.feeder();
      G.head.form();
      G.wish.origin.focus();
   };   // G.head.focus()



   G.head.form = function () {
      // Initialize or show form in head region
      // Uses:
      //    >  G.ltr
      //    >  TEXTS
      //    >  G.origin
      //    >  G.genuine
      //    >  G.$page
      //    >  Signature
      //    >< G.head.$wrap
      //    >< G.head.$error
      //    >< G.head.$show
      //    >< G.head.$hide
      //    >< G.head.$run
      //    >< G.head.$cache
      //    >< G.head.$request
      //    >< G.head.$options
      //     < G.wish
      //     < G.direct.$textarea
      //    PREGO.translation()
      //    OO.ui.ButtonWidget()
      //    OO.ui.TextInputWidget()
      //    OO.ui.RadioOptionWidget()
      //    OO.ui.RadioSelectWidget()
      //    OO.ui.MultilineTextInputWidget()
      //    OO.ui.CheckboxMultioptionWidget()
      //    OO.ui.CheckboxMultiselectWidget()
      //    G.head.filter()
      //    G.head.figure()
      //    mw.hook()
      //    (G.head.form)
      //    (G.cat.fired)
      //    (G.cat.fairly)
      //    (G.head.feeder)
      //    (G.cat.finish)
      //    (G.direct.finish)
      //    (G.head.fire)
      //    (G.head.flat)
      //    (G.cat.foreign)
      //    (G.direct.foreign)
      // 2018-08-05 PerfektesChaos@de.wikipedia
      var gen, i, s, see, w, $e;
      if ( G.head.$wrap ) {
         G.head.$error.hide();
         G.head.$show.hide();
         G.head.$hide.show();
         G.head.$request.show();
         G.head.$run.show();
         G.head.$cache.show();
      } else {
         G.head.$wrap = $( "<div>" );
         G.wish = { body:       { },
                    clms:       [ ],
                    extensions: { },
                    origins:    [ ] };
         G.head.$request = $( "<div>" );
         w = new OO.ui.ButtonWidget( { icon:      "expand",
                                       iconTitle: "expand" } );
         w.on( "click", G.head.form );
         G.head.$show = w.$element;
         G.head.$show.css( { "margin-bottom": "1em" } )
                     .hide();
         w = new OO.ui.ButtonWidget( { icon:      "collapse",
                                       iconTitle: "collapse" } );
         w.on( "click", G.head.flip );
         G.head.$hide = w.$element;
         G.head.$hide.css( { "margin-bottom": "1em" } )
                     .hide();
         $e = $( "<div>" );
         $e.css( { "clear": "both" } );
         G.head.$request.append( G.head.$show, G.head.$hide, $e );
         w = new OO.ui.TextInputWidget( { disabled: true,
                                          required: true,
                                          type:     "text"
                                        } );
         w.on( "change", G.cat.fired );
         w.setValidation( G.cat.fairly );
         G.wish.category = w;
         for ( i = 0;  i < G.origin.length;  i++ ) {
            s   = G.origin[ i ];
            see = TEXTS[ s ];
            gen = G.genuine[ s ];
            if ( gen.list ) {
               see = TEXTS.Special + ": " + see;
            }
            w = new OO.ui.RadioOptionWidget( { data:     s,
                                               disabled: ! gen.live,
                                               label:    see } );
            G.wish.origins.push( w );
         }   // for i
         s = PREGO.translation( TEXTS.origin );
         w = new OO.ui.RadioSelectWidget( { items: G.wish.origins,
                                            text:  s } );
         w.on( "choose", G.head.feeder );
         G.wish.origin = w;
         w.$element.css( { "max-width": "35%" } );
         G.head.$request.append( w.$element );
         $e = G.wish.category.$element;
         $e.css( { "display":    "inline-block",
                   "margin-top": "2em",
                   "float":      ( G.ltr ? "right" : "left" ),
                   "width":      "60%" } );
         $e.find( "input" ).blur( G.cat.finish );
         G.wish.origin.$element.before( $e );
         w = new OO.ui.MultilineTextInputWidget( { required: true,
                                                   rows:     10,
                                                   type:     "text"
                                                 } );
         G.direct.$textarea = w.$element;
         G.direct.$textarea.hide();
         G.direct.$textarea.find( "textarea" ).blur( G.direct.finish );
         G.wish.direct = w;
         G.wish.origin.$element.after( G.direct.$textarea );
         for ( i = 0;  i < G.head.columns.length;  i++ ) {
            s   = G.head.columns.substr( i, 1 );
            see = PREGO.translation( TEXTS[ "clm." + s ] );
            w   = new OO.ui.CheckboxMultioptionWidget( { data:  s,
                                                         label: see } );
            G.wish.clms.push( w );
         }   // for i
         s = PREGO.translation( TEXTS.columns );
         w = new OO.ui.CheckboxMultiselectWidget( { items: G.wish.clms,
                                                    text:  s } );
         G.wish.columns = w;
         $e = w.$element;
         $e.css( { "margin-top": "1em" } );
         G.head.$request.append( $e );
         $e = $( "<div>" );
         $e.css( { "margin-top": "2em" } )
           .text( PREGO.translation( TEXTS.filter ) );
         G.head.$request.append( $e );
         G.head.filter( "body", PREGO.translation( TEXTS.filterBt ) );
         G.head.filter( "extensions", TEXTS.typesEx, true );
         G.head.$options = $( "<div>" );
         G.head.$options.css( { "clear":       "both",
                                "padding-top": "2em" } );
         G.head.figure( "rows" );
         G.head.figure( "part" );
         G.head.figure( "thumb" );
         G.head.figure( "descr" );
         w = new OO.ui.ButtonWidget( { disabled: true,
                                       flags:    [ "primary",
                                                   "progressive" ],
                                       label:    TEXTS.go } );
         w.on( "click", G.head.fire );
         G.wish.run = w;
         G.head.$run = $( "<div>" );
         G.head.$run.css( { "clear": "both" } )
                    .append( w.$element );
         s = PREGO.translation( TEXTS.cache );
         w = new OO.ui.ButtonWidget( { flags: [ "primary",
                                                "destructive" ],
                                       label: s } );
         w.on( "click", G.head.flat );
         G.wish.cache = w;
         G.head.$cache = $( "<div>" );
         G.head.$cache.css( { "float": ( G.ltr ? "right" : "left" ) } )
                      .hide()
                      .append( w.$element );
         G.head.$run.append( G.head.$cache );
         G.head.$error = $( "<div>" );
         G.head.$error.addClass( "error" )
                      .css( { "background-color": "#FFFF00",
                              "border":           "#FF0000 2px solid",
                              "clear":            "both",
                              "color":            "#FF0000",
                              "margin":           "2em 0",
                              "padding":          "0.5em"
                            } )
                      .hide();
         G.head.$wrap.append( G.head.$show,
                              G.head.$request,
                              G.head.$options,
                              G.head.$run,
                              G.head.$error );
         G.$page.append( G.head.$wrap );
         mw.hook( Signature + ".category" ).add( G.cat.foreign );
         mw.hook( Signature + ".files" ).add( G.direct.foreign );
      }
   };   // G.head.form()



   G.table.feature = function ( active ) {
      // Trigger description retrieval
      //    active  -- object, with DOM button
      // Uses:
      //    >  MEDIA
      //    G.table.featured()
      //    G.api.dc.feed()
      //    (G.table.featured)
      // 2018-05-20 PerfektesChaos@de.wikipedia
      var sign, $btn;
      if ( typeof active.target  ===  "object" ) {
         $btn = $( active.target );
         sign = $btn.data( "file" );
         if ( typeof MEDIA[ sign ]  ===  "object"   &&
              typeof MEDIA[ sign ].D  ===  "string"
              &&     MEDIA[ sign ].D ) {
            G.table.featured( sign, MEDIA[ sign ].D );
         } else {
            G.api.dc.feed( sign, G.table.featured );
         }
   }
   };   // G.table.feature()



   G.table.featured = function ( at, about ) {
      // Show file
      // Precondition:
      //    at     -- string, with file title
      //    about  -- string, with description, or true on commons
      // Uses:
      //    >  G.table.suite
      //    >  G.ltr
      //    >  G.use.descr
      //    G.flat()
      //    G.table.features()
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var j, $btn, $span, $td, $tr;
      if ( about ) {
         MEDIA[ at ].D = about;
         j   = G.table.suite.indexOf( "D" );
         $tr = G.table.$table.find( "#" + G.flat( at ) );
         if ( $tr.length  &&  j > 1 ) {
            $td = $tr.children().eq( j );
            $td.empty();
            if ( about === true ) {
               $td.text( String.fromCharCode( 8212 ) );
            } else {
               $td.css( { "text-align":     ( G.ltr ? "left" : "right" ),
                          "vertical-align": "top" } );
               j = about.length - G.use.descr;
               if ( j < 20 ) {
                  $td.text( about );
               } else {
                  $span = $( "<span>" );
                  $span.text( about.substr( 0, G.use.descr )
                              + String.fromCharCode( 32, 8230, 32 ) );
                  $btn = $( "<button>" );
                  $btn.attr( { "data-file": at } )
                      .click( G.table.features )
                      .text( "+" + j );
                  $td.append( $span, $btn );
               }
            }
         }
      }
   };   // G.table.featured()



   G.table.features = function ( active ) {
      // Trigger description completion
      //    active  -- object, with DOM button
      // Uses:
      //    >  MEDIA
      // 2018-05-20 PerfektesChaos@de.wikipedia
      var sign, $btn, $td;
      if ( typeof active.target  ===  "object" ) {
         $btn = $( active.target );
         sign = $btn.data( "file" );
         $td  = $btn.parent();
         $td.empty()
            .text( MEDIA[ sign ].D );
      }
   };   // G.table.features()



   G.table.fed = function ( arrived ) {
      // File entries arrived
      // Precondition:
      //    arrived  -- Array, with file entries, or not
      //                each element Array with length 1 or 2
      //                [0] file page title, [1] object with additionals
      //                false if no more results available
      //                omitted if chunk ready
      // Uses:
      //    >  G.table.reBodyExt
      //    >  G.table.suite
      //    >  G.query.columns
      //    >  G.use.target
      //    >  G.ltr
      //    >  G.table.$tbody
      //    >  G.table.$retrieve
      //    >  G.table.rows
      //    >  G.table.progress
      //    >  G.table.list
      //    >  G.use.source
      //    >< G.table.max
      //    >< G.table.query
      //    >< MEDIA
      //    G.extensions.flat()
      //    G.body.filter()
      //    G.extensions.filter()
      //    G.flat()
      //    G.api.qp.feed()
      //    G.api.cm.feed()
      //    G.table.finish()
      //    G.table.further()
      //    G.table.friends()
      //    (G.table.friends)
      //    (G.table.flip)
      // 2018-08-05 PerfektesChaos@de.wikipedia
      var c, d, e, g, i, k, s, src, st, stem, suffix, $a, $cb, $td, $tr;
      G.table.max--;
      if ( G.table.max && arrived ) {
         for ( i = 0;  i < arrived.length;  i++ ) {
            e = arrived[ i ];
            if ( ! e ) {
               arrived = false;
               if ( G.table.$retrieve ) {
                  G.table.$retrieve.hide();
               }
               break;
            }
            src = e[ 0 ];
            if ( typeof MEDIA[ src ]  ===  "object" ) {
               d = MEDIA[ src ];
            } else {
               d = { };
            }
            g = G.table.reBodyExt.exec( src );
            if ( g ) {
               stem   = g[ 1 ];
               suffix = G.extensions.flat( g[ 2 ].toLowerCase() );
            } else {
               stem   = "???";
               suffix = "???";
            }
            if ( G.body.filter( stem )  &&
                 G.extensions.filter( suffix ) ) {
               if ( typeof d.M  !==  "string" ) {
                  d.M = suffix;
               }
               G.table.items++;
               $tr = $( "<tr>" );
               $tr.attr( { id: G.flat( src ) } );
               if ( e.length > 1 ) {
                  g = e[ 1 ];
                  for ( s in g ) {
                     d[ s ] = g[ s ];
                  }   // for s in g
               }
               g = { "#":   G.table.items,
                     "^":   "",
                     "@":   src,
                     "$tr": $tr };
               for ( k = 0;  k < G.table.suite.length;  k++ ) {
                  s = G.table.suite.substr( k, 1 );
                  if ( typeof d[ s ]  ===  "string" ) {
                     g[ s ] = d[ s ];
                  }
               }   // for k
               for ( k = 0;  k < G.table.suite.length;  k++ ) {
                  s   = G.table.suite.substr( k, 1 );
                  $td = $( "<td>" );
                  c   = G.query.columns[ s ];
                  if ( typeof c.type  ===  "string"
                       &&     c.type === "n" ) {
                     $td.css( { "text-align":
                                        ( G.ltr ? "right" : "left" ) } );
                  }
                  st = typeof g[ s ];
                  if ( st === "string"  ||
                       st === "number" ) {
                     switch ( s ) {
                        case "^":
                           $cb = $( "<input>" );
                           $cb.addClass( "markfile" )
                              .attr( { "type": "checkbox" } )
                              .change( G.table.flip );
                           $td.append( $cb )
                              .attr( { "data-sort-value": "-" } );
                           break;
                        case "@":
                           s  = g[ s ];
                           $a = $( "<a>" );
                           $a.attr( { href:   mw.util.getUrl( "File:"
                                                              + s ),
                                      target: G.use.target } )
                             .text( s );
                           $td.append( $a );
                           break;
                        default:
                           $td.text( g[ s ] );
                     }   // switch s
                  } else {
                     g[ s ] = null;
                  }
                  $tr.append( $td );
               }   // for k
               G.table.query.push( g );
               G.table.$tbody.append( $tr );
            }
            MEDIA[ src ] = d;
         }   // for i
      } else if ( arrived === false  &&  G.table.$retrieve ) {
         G.table.$retrieve.hide();
      }
      if ( G.table.max  &&
           arrived  &&
           G.table.query.length < G.table.rows ) {
         i = 5  +  45 * G.table.query.length / G.table.rows;
         G.table.progress.setProgress( i );
         if ( G.table.list ) {
            G.api.qp.feed();
         } else if ( G.use.source === "Category" ) {
            G.api.cm.feed();
         } else {
            G.table.further();
         }
      } else {
         G.table.progress.setProgress( 50 );
         G.table.further();
         if ( ! G.table.list ) {
            if ( G.use.source === "Category" ) {
               G.api.cm.feed( true, G.table.friends );
            }
         }
      }
   };   // G.table.fed()



   G.table.fiat = function () {
      // Create or update [more] button
      // Uses:
      //    >  G.table.retrieve
      //    >  G.api.more
      // 2018-05-20 PerfektesChaos@de.wikipedia
      if ( G.table.retrieve ) {
         G.table.retrieve.setLabel( "+" + G.api.more );
      }
   };   // G.table.fiat()



   G.table.file = function ( active ) {
      // Trigger miniature image
      //    active  -- object, with DOM button
      // Uses:
      //    >  MEDIA
      //    G.table.filed()
      //    G.api.th.feed()
      // 2018-05-20 PerfektesChaos@de.wikipedia
      var sign, $btn;
      if ( typeof active.target  ===  "object" ) {
         $btn = $( active.target );
         sign = $btn.data( "file" );
         if ( typeof MEDIA[ sign ]  ===  "object"   &&
              typeof MEDIA[ sign ].I  ===  "object"
              &&     MEDIA[ sign ].I ) {
            G.table.filed( sign, MEDIA[ sign ].I );
         } else {
            G.api.th.feed( sign );
         }
      }
   };   // G.table.file()



   G.table.filed = function ( at, about ) {
      // Show miniature image
      // Precondition:
      //    at     -- string, with file title
      //    about  -- object, with details, or not
      // Uses:
      //    >  G.table.suite
      //    >  G.table.$table
      //    >< G.table.thumb.css
      //    G.flat()
      // 2018-06-10 PerfektesChaos@de.wikipedia
      var j   = G.table.suite.indexOf( "I" ),
          $tr = G.table.$table.find( "#" + G.flat( at ) ),
          $img, $td;
      MEDIA[ at ].I = about;
      if ( $tr.length  &&  j > 1 ) {
         $td = $tr.children().eq( j );
         $td.empty();
         if ( about ) {
            if ( ! G.table.thumb.css ) {
               G.table.thumb.css =
                        { "background": "transparent repeat scroll 0% 0%"
                                        + " url('//upload.wikimedia.org/"
                                              + "wikipedia/commons/"
                                              + G.table.thumb.src
                                              + "')" };
            }
            $img = $( "<img>" );
            $img.attr( { src:    about.u,
                         height: about.h,
                         width:  about.w } );
            $td = $tr.children().eq( j );
            $td.css( G.table.thumb.css )
               .append( $img );
         }
      }
   };   // G.table.filed()



   G.table.fill = function () {
      // All details arrived
      // Uses:
      //    >  G.table.suite
      //    >  MEDIA
      //    >< G.table.query
      //    G.table.furnish()
      //    G.table.finish()
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var i, j, g, q, s, sign, $td, $tr;
      G.table.progress.setProgress( 70 );
      for ( i = 0;  i < G.table.query.length;  i++ ) {
         q = G.table.query[ i ];
         if ( q ) {
            sign = q[ "@" ];
            if ( typeof MEDIA[ sign ]  ===  "object" ) {
               g = MEDIA[ sign ];
               for ( s in q ) {
                  if ( q[ s ] === null   &&
                       typeof g[ s ]  !==  "undefined" ) {
                     j    = G.table.suite.indexOf( s );
                     $tr  = q.$tr;
                     $td  = $tr.children().eq( j );
                     $td.text( g[ s ] );
                  }
               }   // for s in q
               j = 70  +  20 * i / G.table.query.length;
               G.table.progress.setProgress( j );
            }
         }   // for i
      }
      G.table.furnish( "D" );
      G.table.furnish( "I" );
      delete G.table.query;
      G.table.progress.setProgress( 90 );
      G.table.finish();
   };   // G.table.fill()



   G.table.filling = function ( apply, after ) {
      // Details arrived
      // Precondition:
      //    apply  -- object, with details
      //    after  -- function, to proceed
      // Uses:
      //    >  G.table.progress
      //    >< MEDIA
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var e, g, s, sub;
      G.table.progress.setProgress( 60 );
      for ( s in apply ) {
         g = apply[ s ];
         if ( typeof MEDIA[ s ]  ===  "object" ) {
            e = MEDIA[ s ];
            for ( sub in g ) {
               e[ sub ] = g[ sub ];
            }   // for sub in g
         } else {
            MEDIA[ s ] = g;
         }
      }   // for s in apply
      after( true );
   };   // G.table.filling()



   G.table.finish = function () {
      // All entries arrived
      // Uses:
      //    >  G.table.$abort
      //    >  G.table.items
      //    >  G.table.$table
      //    >  G.table.$progress
      //    >  G.table.retrieve
      //    >  G.table.source
      //    >  TEXTS.noFiles
      //    >  G.table.$wrap
      //    >< G.table.$files
      //    G.wikitext.first()
      //    PREGO.translation()
      // 2018-08-05 PerfektesChaos@de.wikipedia
      if ( G.table.items ) {
         G.table.$abort.hide();
         if ( G.table.items > 1    &&
              typeof G.table.$table.tablesorter  ===  "function" ) {
            G.table.$table.find( "thead" ).remove();
            G.table.$table.prepend( G.table.$thead.clone() );
            G.table.$table.addClass( "sortable" )
                          .tablesorter();
         }
         G.table.$progress.hide();
         if ( G.table.retrieve ) {
            G.table.retrieve.setDisabled( false );
         }
         G.wikitext.first();
      } else {
         G.table.$files.remove();
         G.table.$files = $( "<div>" );
         G.table.$files.css( { "font-size": "1.2em"} )
                       .text( PREGO.translation( TEXTS.noFiles ) );
         G.table.$wrap.append( G.table.$files );
      }
   };   // G.table.finish()



   G.table.fire = function () {
      // Retrieve more entries
      // Uses:
      //    >  G.api.incr
      //    >  G.use.rows
      //    >  G.table.retrieve
      //    >  G.table.progress
      //    >  G.table.$progress
      //    >  G.table.$abort
      //    >  G.table.items
      //    >  G.table.list
      //     < G.table.max
      //     < G.table.rows
      //     < G.table.query
      //    G.api.qp.feed()
      //    G.api.cm.feed()
      // 2018-06-03 PerfektesChaos@de.wikipedia
      G.table.max  = G.api.incr;
      G.table.rows = G.use.rows;
      if ( G.table.retrieve ) {
         G.table.retrieve.setDisabled( true );
      }
      G.table.progress.setProgress( 5 );
      G.table.progress.setDisabled( false );
      G.table.$progress.show();
      G.table.$abort.show();
      G.table.query = [ ];
      if ( G.table.list ) {
         G.api.qp.feed();
      } else {
         G.api.cm.feed( false, G.table.fed );
      }
   };   // G.table.fire()



   G.table.first = function ( assign, apply ) {
      // Initialize table region
      // Precondition:
      //    assign  -- string with ID of collection
      //    apply   -- string, with column codes, or not
      // Uses:
      //    >  G.$page
      //    >  G.use.rows
      //    >  TEXTS
      //    >  G.use.target
      //    >  G.ltr
      //    >  G.use.sub
      //    >  G.api.incr
      //    >  G.use.directs
      //    >< G.table.$wrap
      //     < G.table.list
      //     < G.table.rows
      //     < G.table.$files
      //     < G.table.progress
      //     < G.table.$abort
      //     < G.table.retrieve
      //     < G.table.$retrieve
      //     < G.table.items
      //     < G.table.query
      //     < G.table.reBodyExt
      //     < G.reDot
      //     < G.reSpc
      //     < G.table.$cats
      //     < G.table.max
      //    PREGO.translation()
      //    mw.util.getUrl()
      //    OO.ui.ProgressBarWidget()
      //    OO.ui.ButtonWidget()
      //    G.extensions.finder()
      //    G.table.frame()
      //    G.api.qp.feed()
      //    G.api.cm.feed()
      //    G.api.cl.feed()
      //    G.table.fed()
      //    (G.table.fire)
      //    (G.table.flop)
      //    (G.table.fed)
      // 2018-08-05 PerfektesChaos@de.wikipedia
      var i, show, src, w, $a, $e;
      if ( G.table.$wrap ) {
         G.table.$wrap.empty();
      } else {
         G.table.$wrap = $( "<div>" );
         G.$page.append( G.table.$wrap );
      }
      G.table.rows = G.use.rows;
      G.table.list = G.genuine[ assign ].list;
      if ( G.table.list ) {
         show = TEXTS[ assign ];
         src  = "Special:" + assign;
      } else if ( assign === "Category" ) {
         show = TEXTS.Category + ":" + G.use.sub;
         src  = "Category:" + G.use.sub;
      } else if ( assign === "Direct" )  {
         show = PREGO.translation( TEXTS.plain );
      } else {
         show = "????????";
      }
      if ( src ) {
         $a = $( "<a>" );
         $a.attr( { href:   mw.util.getUrl( src ),
                    target: G.use.target } );
      } else {
         $a = $( "<span>" );
      }
      $a.text( show );
      $e = $( "<h2>" );
      $e.css( { "clear":      "both",
                "margin-top": "4em" } )
        .append( $a );
      G.table.$wrap.append( $e );
      G.table.$files = $( "<div>" );
      G.table.progress = new OO.ui.ProgressBarWidget( { progress: 5 } );
      G.table.$progress = G.table.progress.$element;
      G.table.$progress.css( { "margin-bottom": "1em" } );
      G.table.$files.append( G.table.$progress );
      w = new OO.ui.ButtonWidget( { flags:     [ "primary",
                                                 "destructive" ],
                                    icon:      "clear",
                                    iconTitle: "abort" } );
      w.on( "click", G.table.flop );
      G.table.$abort = $( "<div>" );
      G.table.$abort.css( { "clear":  "both",
                            "float":  ( G.ltr ? "right" : "left" ) } )
                    .hide()
                    .append( w.$element );
      G.table.$files.append( G.table.$abort );
      if ( G.table.list || src ) {
         w = new OO.ui.ButtonWidget( { disabled: true,
                                       flags:    [ "primary",
                                                   "progressive" ],
                                       label:    "+" + G.api.more } );
         w.on( "click", G.table.fire );
         G.table.retrieve  = w;
         G.table.$retrieve = w.$element;
         G.table.$files.append( G.table.$retrieve );
      } else {
         G.table.retrieve  = false;
         G.table.$retrieve = false;
      }
      G.table.frame( assign, apply );
      G.table.$wrap.append( G.table.$files );
      G.table.items = 0;
      G.table.query = [ ];
      if ( ! G.table.reBodyExt ) {
         G.table.reBodyExt = new RegExp( "^(.+)\\.([a-zA-Z0-9]+)$" );
         G.reDot           = new RegExp( "\\.", "g" );
         G.reSpc           = new RegExp( "\\s+", "g" );
      }
      if ( G.use.conditions    &&
           typeof G.use.conditions.ext  ===  "object" ) {
         G.extensions.finder();
      }
      G.table.max = G.api.incr;
      if ( G.table.list ) {
         G.api.qp.feed( assign, G.table.fed );
      } else if ( src ) {
         G.table.$cats = false;
         G.api.cm.feed( false, G.table.fed, G.use.sub );
      } else {
         w = [ ];
         for ( i = 0;  i < G.use.directs.length;  i++ ) {
            w.push( [ G.use.directs[ i ] ] );
         }   // for i
         G.table.rows = G.use.directs.length;
         G.table.fed( w );
      }
   };   // G.table.first()



   G.table.flip = function () {
      // Handler on mark change
      // 2018-08-05 PerfektesChaos@de.wikipedia
      var $cb = $( this ),
          $td = $cb.parent();
      $td.attr( { "data-sort-value": ( $cb.prop( "checked" ) ? "+"
                                                             : "-" ) } );
   };   // G.table.flip()



   G.table.flop = function () {
      // Abort retrieving
      // Uses:
      //    >  G.table.progress
      //    >  G.table.$abort
      //    G.api.flop()
      // 2018-05-20 PerfektesChaos@de.wikipedia
      G.table.progress.setDisabled( true );
      G.table.$abort.hide();
      G.api.flop();
   };   // G.table.flop()



   G.table.frame = function ( assign, apply ) {
      // Create table
      // Precondition:
      //    assign  -- string with ID of collection
      //    apply   -- string, with column codes, or not
      // Uses:
      //    >  TEXTS
      //    >  G.query.columns
      //    >  G.table.$files
      //     < G.table.source
      //     < G.table.learn
      //     < G.table.suite
      //     < G.table.$table
      //     < G.table.$thead
      //     < G.table.$tbody
      //    PREGO.translation()
      // 2018-08-05 PerfektesChaos@de.wikipedia
      var c, i, s, show, sort, $th, $tr;
      G.table.source = assign;
      G.table.learn  = false;
      if ( apply ) {
         if ( apply.substr( 0, 1 ) === "^" ) {
            G.table.learn = true;
            G.table.suite = "#^@" + apply.substr( 1 );
         } else {
            G.table.suite = "#@" + apply;
         }
      } else {
         G.table.suite = "#@";
      }
      G.table.$table = $( "<table>" );
      G.table.$table.addClass( "wikitable" )
                    .css( { "margin-top": "2em" } );
      G.table.$thead = $( "<thead>" );
      $tr = $( "<tr>" );
      for ( i = 0;  i < G.table.suite.length;  i++ ) {
         s   = G.table.suite.substr( i, 1 );
         $th = $( "<th>" );
         if ( s === "^" ) {
            show = "mark";
         } else {
            show = "clm." + s;
         }
         $th.text( PREGO.translation( TEXTS[ show ] ) );
         c = G.query.columns[ s ];
         if ( typeof c.type  ===  "string" ) {
            switch ( c.type ) {
               case "n":
                  sort = "number";
                  break;
               default:
                  sort = "text";
            }   // switch assign
            $th.attr( { "data-sort-type": sort } );
         } else {
            $th.addClass( "unsortable" );
         }
         $tr.append( $th );
      }   // for i
      G.table.$thead.append( $tr );
      G.table.$tbody = $( "<tbody>" );
      G.table.$table.append( G.table.$thead.clone(),
                             G.table.$tbody );
      G.table.$files.append( G.table.$table );
   };   // G.table.frame()



   G.table.friendly = function ( adult, arrived ) {
      // Precondition:
      //    adult    -- false for subcat, true for parent
      //    arrived  -- Array, with categories
      // Uses:
      //    >  G.table.$cats
      //    >  TEXTS.noCat
      //    G.table.$cat.text()
      //    (G.table.friendship)
      // 2018-05-20 PerfektesChaos@de.wikipedia
      var i, s, $btn, $div, $e;
      if ( arrived && arrived.length ) {
         $div = $( "<div>" );
         $div.css( { "margin-top": "3em" } );
         G.table.$cats.append( $div );
         $btn = $( "<button>" );
         $btn.text( String.fromCharCode( ( adult ? 8593
                                                 : 8595 ) ) );
         for ( i = 0;  i < arrived.length;  i++ ) {
            s    = arrived[ i ];
            $div = $( "<div>" );
            if ( s ) {
               $e = $( "<span>" );
               $e.css( { "margin": "0 1em" } )
                 .text( s );
               $div.css( { "margin-top": "0.5em" } )
                   .append( $btn.clone()
                                .attr( { "data-cat": s } )
                                .click( G.table.friendship ),
                            $e );
            } else {
               $div.text( String.fromCharCode( 8230, 32, 8230 ) );
            }
            G.table.$cats.append( $div );
         }   // for i
      }
      if ( adult  &&  ! G.table.$cats.children().length ) {
         G.table.$cats.text( PREGO.translation( TEXTS.noCat ) );
      }
   };   // G.table.friendly()



   G.table.friends = function ( arrived ) {
      // Apply category navigation
      // Precondition:
      //    arrived  -- Array, with category entries, or not
      // Uses:
      //    >  G.table.$wrap
      //    >  G.G.use.sub
      //    >< G.table.$cats
      //    G.table.friendly()
      //    G.api.cl.feed()
      // 2018-05-20 PerfektesChaos@de.wikipedia
      if ( G.table.$cats ) {
         G.table.friendly( true, arrived );
      } else {
         G.table.$cats = $( "<div>" );
         G.table.friendly( false, arrived );
         G.table.$wrap.append( G.table.$cats );
         G.api.cl.feed( G.use.sub, G.table.friends );
      }
   };   // G.table.friends()



   G.table.friendship = function ( active ) {
      // Trigger category navigation click
      //    active  -- object, with DOM button
      // Uses:
      //     < G.use.sub
      //    G.head.focus()
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var $btn;
      if ( typeof active.target  ===  "object" ) {
         $btn      = $( active.target );
         G.use.sub = $btn.data( "cat" );
         G.head.focus();
      }
   };   // G.table.friendship()



   G.table.furnish = function ( ask ) {
      // Equip columns with request capabilities for additional items
      // Precondition:
      //    ask  -- string with ID letter of capability
      // Uses:
      //    >  G.table.suite
      //    >  MEDIA
      //    >< G.table.query
      //    (G.table.file)
      //    (G.table.feature)
      // 2018-06-03 PerfektesChaos@de.wikipedia
      var j = G.table.suite.indexOf( ask ),
          i, q, s, $btn, $td, $tr;
      if ( j > 1 ) {
         for ( i = 0;  i < G.table.query.length;  i++ ) {
            q = G.table.query[ i ];
            s = q[ "@" ];
            if ( ask !== "D"   ||
                 typeof MEDIA[ s ].L  !==  "boolean"
                 ||     MEDIA[ s ].L ) {
               if ( typeof q[ ask ]  !==  "string" ) {
                  q[ ask ] = false;
               }
               $tr  = q.$tr;
               $td  = $tr.children().eq( j );
               $btn = $( "<button>" );
               $btn.attr( { "data-file": s } )
                   .click( ( ask === "I"  ?  G.table.file
                                          :  G.table.feature ) )
                   .text( "+" );
               $td.css( { "text-align":     "center",
                          "vertical-align": "middle" } )
                  .append( $btn );
            }
         }   // for i
      }
   };   // G.table.furnish()



   G.table.further = function () {
      // Request more details
      // Uses:
      //    >  G.query.columns
      //    >  G.table.progress
      //    >< G.table.query
      //     < G.api.fi.titles
      //     < G.api.rv.titles
      //     < G.api.rv.follow
      //     < G.api.fi.follow
      //    G.api.fi.feed()
      //    G.api.rv.feed()
      //    G.table.fill()
      //    (G.api.rv.feed)
      //    (G.table.fill)
      //    (G.table.filling)
      // 2018-05-20 PerfektesChaos@de.wikipedia
      var props = { },
          follow, get, i, q, s, suck;
      G.api.fi.titles = [ ];
      G.api.rv.titles = [ ];
      for ( i = G.table.query.length - 1;  i >= 0;  i-- ) {
         q   = G.table.query[ i ];
         get = { F: false, D: false };
         for ( s in q ) {
            if ( q[ s ] === null ) {
               suck = G.query.columns[ s ].api;
               if ( suck ) {
                  props[ suck ]              = true;
                  get[ suck.substr( 0, 1 ) ] = true;
               }
            }
         }   // for s in q
         if ( get.F || get.D ) {
            if ( get.F ) {
               G.api.fi.titles.push( q[ "@" ] );
            }
            if ( get.D ) {
               G.api.rv.titles.push( q[ "@" ] );
            }
         }
      }   // for i--
      G.table.progress.setProgress( 55 );
      if ( G.api.rv.titles.length ) {
         follow = G.api.rv.feed;
         suck   = "";
         for ( s in props ) {
            if ( s.substr( 0, 1 )  ===  "D" ) {
               suck = suck + "|" + s.substr( 1 );
            }
         }   // for s in props
         G.api.rv.props  = suck.substr( 1 );
         G.api.rv.follow = G.table.fill;
      } else {
         follow = G.table.fill;
      }
      if ( G.api.fi.titles.length ) {
         suck = "";
         for ( s in props ) {
            if ( s.substr( 0, 1 )  ===  "F" ) {
               suck = suck + "|" + s.substr( 1 );
            }
         }   // for s in props
         G.api.fi.props  = suck.substr( 1 );
         G.api.fi.follow = follow;
         G.api.fi.feed( G.table.filling );
      } else {
         follow( true );
      }
      G.table.progress.setProgress( 60 );
   };   // G.table.further()



   G.wikitext.fetch = function ( ask ) {
      // Export selected information
      // Uses:
      //    >  G.table.suite
      //    >  G.table.$tbody
      //    >  TEXTS
      //    >  MEDIA
      //    >  G.table.$wrap
      //    >< G.wikitext.reI
      //    >< G.wikitext.rePipe
      //    >< G.wikitext.reLT
      //    >< G.wikitext.$textarea
      //    >< G.wikitext.textarea
      //    PREGO.translation()
      //    OO.ui.MultilineTextInputWidget()
      // 2018-08-05 PerfektesChaos@de.wikipedia
      var k     = G.table.suite.indexOf( "@" ),
          $rows = G.table.$tbody.children(),
          i, j, s, stuff, story, suite, o, w, $tr;
      if ( ask ) {
         story = "{| class=\"wikitable\"\n" +
                 "|-\n" +
                 "! ";
         suite = G.table.suite.substr( k );
         if ( typeof G.wikitext.reI  !==  "object" ) {
            G.wikitext.reI    = new RegExp( "I" );
            G.wikitext.rePipe = new RegExp( "|", "g" );
            G.wikitext.reLT   = new RegExp( "<", "g" );
         }
         suite = suite.replace( G.wikitext.reI, "" );
         for ( j = 0;  j < suite.length;  j++ ) {
            s = suite.substr( j, 1 );
            if ( j ) {
               story = story + " !! ";
            }
            story = story  +  PREGO.translation( TEXTS[ "clm." + s ] );
         }   // for j
         story = story + "\n";
      } else {
         story = "";
      }
      for ( i = 0;  i < $rows.length;  i++ ) {
         $tr = $rows.eq( i );
         if ( G.table.learn  &&
              ! $tr.find( ".markfile" ).prop( "checked" ) ) {
            $tr = false;
         }
         if ( $tr ) {
            s = $tr.children().eq( k ).text();
            if ( ask ) {
               story = story + "|-\n| [[" +  TEXTS[ "clm.@" ].en + ":"
                             + s + "|" + s + "]]\n";
               if ( typeof MEDIA[ s ]  ===  "object" ) {
                  o = MEDIA[ s ];
                  for ( j = 1;  j < suite.length;  j++ ) {
                     s     = suite.substr( j, 1 );
                     story = story + "| ";
                     stuff = o[ s ]  ||  "";
                     if ( s === "D" ) {
                        story = story + stuff.replace( G.wikitext.rePipe,
                                                       "{{!}}" )
                                             .replace( G.wikitext.reLT,
                                                       "&lt;" );
                     } else {
                        story = story + stuff;
                     }
                     story = story + "\n";
                  }   // for j
               }
            } else {
               story = story + s + "\n";
            }
         }
      }   // for i
      if ( ask ) {
         story = story + "|}";
      }
      if ( typeof G.wikitext.$textarea  ===  "object" ) {
         if ( ! story ) {
            G.wikitext.$textarea.hide();
         }
      } else if ( story ) {
         w = new OO.ui.MultilineTextInputWidget( { rows:     10,
                                                   type:     "text"
                                                 } );
         G.wikitext.textarea  = w;
         G.wikitext.$textarea = w.$element;
         G.wikitext.$textarea.css( { "clear":       "both",
                                     "padding-top": "1em" } );
         G.table.$wrap.append( G.wikitext.$textarea );
      }
      if ( story ) {
         G.wikitext.textarea.setValue( story );
         G.wikitext.$textarea.show();
      }
   };   // G.wikitext.fetch()



   G.wikitext.files = function () {
      // Create list of files
      // Uses:
      //    G.wikitext.fetch()
      // 2018-08-05 PerfektesChaos@de.wikipedia
      G.wikitext.fetch( false );
   };   // G.wikitext.files()



   G.wikitext.fill = function ( apply ) {
      // Change marks
      // Precondition:
      //    apply  -- true or false
      // Uses:
      //    >  G.table.$table
      // 2018-08-05 PerfektesChaos@de.wikipedia
      var $c = G.table.$table.find( ".markfile" );
      $c.prop( "checked", apply );
   };   // G.wikitext.fill()



   G.wikitext.first = function () {
      // Append export facility
      // Uses:
      //    >  TEXTS
      //    >  G.table.learn
      //    (G.wikitext.flag)
      //    (G.wikitext.flat)
      //    (G.wikitext.full)
      //    (G.wikitext.files)
      // 2018-08-05 PerfektesChaos@de.wikipedia
      var side   = ( G.ltr ? "left" : "right" ),
          $block = $( "<div>" ),
          $h3    = $( "<h3>" ),
          s, w, $div;
      $h3.text( PREGO.translation( TEXTS.exports ) );
      G.table.$wrap.append( $h3 );
      if ( G.table.learn ) {
         s = PREGO.translation( TEXTS.markAll );
         w = new OO.ui.ButtonWidget( { flags: [ "progressive" ],
                                       label: s } );
         w.on( "click", G.wikitext.flag );
         $div = $( "<div>" );
         $div.append( w.$element )
             .css( { "float": side } );
         $block.append( $div );
         s = PREGO.translation( TEXTS.markNone );
         w = new OO.ui.ButtonWidget( { flags: [ "progressive" ],
                                       label: s } );
         w.on( "click", G.wikitext.flat );
         $div = $( "<div>" );
         $div.append( w.$element )
             .css( "margin-" + side, "3em" )
             .css( { "float": side } );
         $block.append( $div )
               .css( { "padding-top":    "1em",
                       "padding-bottom": "2em" } );
         G.table.$wrap.append( $block );
         $block = $( "<div>" );
      }
      $block.css( { "padding-top": "1em" } );
      s = PREGO.translation( TEXTS.exportW );
      w = new OO.ui.ButtonWidget( { flags: [ "primary",
                                             "progressive" ],
                                    label: s } );
      w.on( "click", G.wikitext.full );
      $div = $( "<div>" );
      $div.append( w.$element )
          .css( { "float": side } );
      $block.append( $div );
      s = PREGO.translation( TEXTS.exportX );
      w = new OO.ui.ButtonWidget( { flags: [ "primary",
                                             "progressive" ],
                                    label: s } );
      w.on( "click", G.wikitext.files );
      $div = $( "<div>" );
      $div.append( w.$element )
          .css( "margin-" + side, "3em" )
          .css( { "float": side } );
      $block.append( $div )
            .css( { "clear": "both" } );
      G.table.$wrap.append( $block );
   };   // G.wikitext.first()



   G.wikitext.flag = function () {
      // Mark all
      // Uses:
      //    G.wikitext.fill()
      // 2018-08-05 PerfektesChaos@de.wikipedia
      G.wikitext.fill( true );
   };   // G.wikitext.flag()



   G.wikitext.flat = function () {
      // Mark none
      // Uses:
      //    G.wikitext.fill()
      // 2018-08-05 PerfektesChaos@de.wikipedia
      G.wikitext.fill( false );
   };   // G.wikitext.flat()



   G.wikitext.full = function () {
      // Create wikitable
      // Uses:
      //    G.wikitext.fetch()
      // 2018-08-05 PerfektesChaos@de.wikipedia
      G.wikitext.fetch( true );
   };   // G.wikitext.full()



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



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

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