/// Gadget-importUtility/utl.js
//  Shared utilities for any kind of page
/// 2018-08-24 [email protected]
//  ResourceLoader: compatible;
//    dependencies: user, mediawiki.util
//  Namespaces:     *
//  Build:          .utl .batch .cnf .known
//  Documentation:  ]
/// Fingerprint:    #0#0#
/// @license GPL  (+GFDL, LGPL, CC-BY-SA)
/// <nowiki>
/* global window: false                                                */
/* jshint forin: false,
          bitwise:true, curly:true, eqeqeq:true, latedef:true,
          laxbreak:true,
          nocomma:true, strict:true, undef:true, unused:true           */



( function ( mw, $ ) {
   "use strict";
   var Version    =  0.903,
       IUTIL      =  "importUtility",
       Self       =  "utl",
       SIG        =  "ext.gadget." + IUTIL,
       SIGNATURE  =  SIG + "." + Self;
   if ( typeof mw.libs  !==  "object"   ||
        ! mw.libs ) {
      mw.libs  =  { };
   }
   mw.libs.type  =  IUTIL;
   IUTIL                  =  mw.libs;
   if ( typeof IUTIL.vsn  ===  "string" ) {
      IUTIL.vsn  =  IUTIL.vsn + " ";
   } else {
      IUTIL.vsn  =  "";
   }
   IUTIL.vsn  =  IUTIL.vsn + Self.substr( 0, 1 ) + "=" + Version;



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



   if ( typeof IUTIL.cnf  !==  "object" ) {
      // Project independent configuration
      IUTIL.cnf  =  { };
   }


   if ( ! IUTIL.cnf.loaded ) {
      IUTIL.cnf.swift    =  IUTIL.type + "Form";
         // OBSOLETING
         // sessionStorage item ID for form data
         // Uses:
         //    >  .type
         // 2012-12-15 [email protected]
      IUTIL.cnf.spooling  =  "//upload.wikimedia.org/wikipedia/commons"
                             + "/d/de/Ajax-loader.gif";
         // throbber URL
         // 2012-12-15 [email protected]



      IUTIL.cnf.texts  =  {
         // 2014-12-30 [email protected]
         "AjaxWait":      {"en": "Contacting server",
                           "de": "Kommuniziere mit dem GROSSEN GURU"},
         "Archive":       {"en": "Resolved",
                           "de": "Erledigt"},
         "Cancel":        {"en": "Cancel",
                           "de": "Abbruch"},
         "Checking":      {"en": "Check origin page ...",
                           "de": "Prüfe Ursprungsseite ..."},
         "Completed":     {"en": "Completed",
                           "de": "Abgearbeitet"},
         "Conflict":      {"en": "Conflict",
                           "de": "Konflikt"},
         "Count":         {"en": "Number of revisions:",
                           "de": "Versionsanzahl:"},
         "Counting":      {"en": "Counting revisions ...",
                           "de": "Zähle Versionen ..."},
         "DeleteIssue":   {"en": "Delete",
                           "de": "Löschen"},
         "Done":          {"en": "(done)",
                           "de": "(erl.)"},
         "Error":         {"en": "ERROR!",
                           "de": "FEHLER!"},
         "ErrorAjax":     {"en": "ERROR!<br />Ajax transfer failed.",
                           "de": "FEHLER!<br />"
                                 + "Ajax (API) fehlgeschlagen."},
         "ErrorAlready":  {"en": "ERROR!\n"
                                 + "Page has been processed already.",
                           "de": "FEHLER!\n"
                                 + "Seite wurde bereits angepasst\n"
                                 + "{{Importartikel}} schon eingefügt."},
         "ErrorData":     {"en": "Data not recognized",
                           "de": "Daten wurden nicht erkannt"},
         "ErrorNoSource": {"en": "ERROR!\nSource page not found.",
                           "de": "FEHLER!\nQuellseite nicht gefunden."},
         "ErrorRedirect": {"en": "ERROR!\nSource page is redirect.",
                           "de": "Hinweis: Quellseite ist Weiterleitung."},
         "ErrorSignat":   {"en": "ERROR!\nSignature not recognized",
                           "de": "FEHLER!\nSignatur nicht lesbar"},
         "Export":        {"en": "Export",
                           "de": "Export"},
         "GetToken":      {"en": "Get token",
                           "de": "Token kaufen"},
         "GreetingAdd":   {"en": "Optional addendum for message,"
                                 + " terminated by greetings."
                                 + " Free pipe symbols '|'"
                                 + " not permitted.",
                           "de": "Optionale Ergänzung der Nachricht,"
                                 + " endend mit Grußformel."},
         "Hold":          {"en": "started",
                           "de": "in Arbeit"},
         "Imported":      {"en": "Import succeeded",
                           "de": "Import erfolgreich"},
         "Imported0":     {"en": "all revisions already present",
                           "de": "Alle Versionen bereits vorhanden"},
         "Imported1":     {"en": "1 revision imported",
                           "de": "1 Version importiert"},
         "ImportedN":     {"en": "revisions imported",
                           "de": "Versionen importiert"},
         "Malicious":     {"en": "Malicious data detected in field",
                           "de": "Bösartige Daten gefunden im Feld"},
         "Modifying":     {"en": "Start page adaption",
                           "de": "Beginne Seitenanpassung"},
         "Move":          {"en": "Move imported page",
                           "de": "Importierte Seite verschieben"},
         "Moved":         {"en": "Page moved",
                           "de": "Importierte Seite verschoben"},
         "MoveSpace":     {"en": "Source not user subpage",
                           "de": "Quellseite keine BNR-Unterseite"},
         "MoveToSame":    {"en": "Source and target page equal",
                           "de": "Quellseite gleich Zielseite"},
         "Moving":        {"en": "Page moving",
                           "de": "Importierte Seite wird verschoben"},
         "NoPreview":     {"en": "No Preview!",
                           "de": "Keine Vorschau!"},
         "NotFound":      {"en": "Page not found",
                           "de": "Seite wurde nicht gefunden"},
         "NoImport":      {"en": "Import failed",
                           "de": "Import gescheitert"},
         "NoToken":       {"en": "Token refused",
                           "de": "Token wurde verweigert"},
         "NoUserName":    {"en": "No user name",
                           "de": "Kein Benutzername"},
         "NoUserPg":      {"en": "Not a user subpage",
                           "de": "Keine Benutzer-Unterseite."},
         "PageAdapt":     {"en": "Adapt page text",
                           "de": "Seitentext anpassen"},
         "PageAdapted":   {"en": "Page has been adapted.",
                           "de": "Seite wurde angepasst."},
         "PageAdapting":  {"en": "Page adaption.",
                           "de": "Seite wird angepasst."},
         "PageUpdated":   {"en": "Page has been updated.",
                           "de": "Seite wurde aktualisiert."},
         "Robinson":      {"en": "No notification required",
                           "de": "Benötigt keine Benachrichtigung"},
         "SendNotifier":  {"en": "Send notification",
                           "de": "Sende Benachrichtigung"},
         "Start":         {"en": "Start import",
                           "de": "Import starten"},
         "Started":       {"en": "Import has been started.",
                           "de": "Import gestartet."},
         "Swap":          {"en": "Request at Upload",
                           "de": "Anfrage auf Upload"},
         "TempPage":      {"en": "Temporary target page:",
                           "de": "Temporäre Zielseite:"},
         "Tic":           {"en": String.fromCharCode(8730)},
         "Update":        {"en": "Update table",
                           "de": "Aktualisiere Tabelle"},
         "UserNotified":  {"en": "User has been notified.",
                           "de": "Benutzer wurde benachrichtigt."},
         "UserNotify":    {"en": "User notifícation",
                           "de": "Benutzer informieren"},
         "UserNotifying": {"en": "User notification.",
                           "de": "Benutzer wird benachrichtigt."}
      };   // .cnf.texts



      IUTIL.cnf.trans  =  {
         // 2012-11-30 [email protected]
         "de" :        "de",
         "de-at" :     "de",
         "de-ch" :     "de",
         "de-formal" : "de",
         "als" :       "de",
         "bar" :       "de",
         "dsb" :       "de",
         "frr" :       "de",
         "gsw" :       "de",
         "hsb" :       "de",
         "ksh" :       "de",
         "lb" :        "de",
         "nds" :       "de",
         "pdc" :       "de",
         "pdt" :       "de",
         "pfl" :       "de",
         "sli" :       "de",
         "stq" :       "de",
         "vmf" :       "de"
      };   // .cnf.trans



      IUTIL.cnf.favorite  =  function () {
         // Guess user language
         // Uses:
         //    this
         //    >  .cnf.trans
         //    >< .cnf.slang
         //    mw.config.get()
         // 2012-12-23 [email protected]
         var s;
         if ( ! this.slang ) {
            s           =  mw.config.get( "wgUserLanguage" );
            s           =  this.trans;
            this.slang  =  ( s ? s : "en" );
         }
      };   // .cnf.favorite()



      IUTIL.cnf.feature  =  function ( apply, adhere ) {
         // Wrap message text access for user or project language
         // Precondition:
         //    apply   -- text keyword
         //    adhere  -- true: project language;  else user language
         // Postcondition:
         //    Return text closest to user language
         // Uses:
         //    this
         //    >  .cnf.slang
         //    >  .cnf.texts
         //    >  .cnf.project.slang
         //    .cnf.favorite()
         // Remark: To be replaced
         //         if one day ResourceLoader3 gives access to
         //         gadget@translatewiki
         // 2012-12-18 [email protected]
         var e,
             r, slang;
         if ( ! this.slang ) {
            this.favorite();
         }
         e  =  this.texts;
         if ( e ) {
            slang  =  ( adhere ? this.project.slang : this.slang );
            r  =  e;
            if ( ! r ) {
               r  =  e.en;
               if ( ! r ) {
                  r  =  "???" + apply + "???";
               }
            }
         } else {
            r  =  "***" + apply + "***";
         }
         return r;
      };   // .cnf.feature()



      IUTIL.cnf.loaded  =  true;
   }   // ! .cnf.loaded



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



   if ( typeof IUTIL.batch  !==  "object" ) {
      // Utilitiy for API communication, displaying current state
      IUTIL.batch  =  { };



      IUTIL.batch.fine  =  function ( apply ) {
         // Equip page with success message
         //    apply  -- message keyword
         // Uses:
         //    this
         //    >  .$msg
         //    jQuery().empty()
         //    jQuery().css()
         //    jQuery().text()
         //    jQuery().append()
         //    .cnf.feature()
         // 2014-10-10 [email protected]
         var $msg;
         IUTIL.$msg.empty();
         IUTIL.$msg.css( { "border":  "solid 1px #00A000",
                           "color":   "#00A000",
                           "margin":  "3px",
                           "padding": "1em" } );
         switch ( typeof apply ) {
            case "function":
            case "object":
               $msg  =  apply;
               break;
            case "string":
               $msg  =  $( "<span>" );
               $msg.text( IUTIL.cnf.feature( apply, false ) );
               break;
            default:
               $msg  =  $( "<strong>" );
               $msg.text( apply );
         }   // switch typeof apply
         IUTIL.$msg.append( $msg );
      };   // .batch.fine()



      IUTIL.batch.fired  =  function ( await ) {
         // Equip page with waiting loop and throbber
         //    await   -- message keyword, or false
         // Uses:
         //    this
         //    >  .$msg
         //    jQuery().empty()
         //    jQuery().css()
         //    .batch.$flow()
         //    jQuery().append()
         //    jQuery().text()
         //    .cnf.feature()
         // 2014-10-10 [email protected]
         var $span  =  $( "<span>" );
         IUTIL.$msg.empty();
         IUTIL.$msg.css( { "border":  "solid 1px #0000FF",
                           "color":   "#0000FF",
                           "margin":  "3px",
                           "padding": "1em" } );
         IUTIL.$msg.append( this.$flow() );
         IUTIL.$msg.append( $span );
         $span  =  $( "<span>" );
         $span.css( { "margin-left": "3em" } );
         $span.text( IUTIL.cnf.feature( ( await ? await : "AjaxWait" ),
                                        false ) );
         IUTIL.$msg.append( $span );
      };   // .batch.fired()



      IUTIL.batch.$flow  =  function ( alter, adapt ) {
         // Create throbber
         // Precondition:
         //    alter  -- number of pixels other than standard, or false
         //    adapt  -- additional style, or false
         // Postcondition:
         //    Return jQuery with throbber IMG
         // Uses:
         //    >  .cnf.spooling
         //    jQuery()
         //    jQuery().attr()
         // 2014-10-10 [email protected]
         var $r  =  $( "<img />" );
         $r.attr( { "src":    IUTIL.cnf.spooling,
                    "height": ( alter ? alter : "24" )
                  } );
         if ( adapt ) {
            $r.attr( "style", adapt );
         }
         return $r;
      };   // .batch.$flow()
   }   // .batch



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



   if ( typeof IUTIL.known  !==  "object" ) {
      // Check existence of user account
      // Dependencies: mediawiki.api
      IUTIL.known  =  { };



      IUTIL.known.fault  =  function ( arrived ) {
         // Show API failure on account check
         // Precondition:
         //    arrived  -- JSON info of ajax query, or false
         // Uses:
         //    .utl.fault()
         //    mw.log()
         // Remark: Used as event handler -- 'this' is not IUTIL.known
         // 2014-10-10 [email protected]
         IUTIL.utl.fault( false );
         mw.log( {loud:true}, "IUTIL.known.fault()", 2, arrived );
      };   // .known.fault()



      IUTIL.known.fire  =  function ( account ) {
         // Check whether account is valid
         // Precondition:
         //    account  -- user name
         // Uses:
         //    >  mw.Api
         //    .utl.furnish()
         //    (.known.found)
         //    (.known.fault)
         // 2013-01-16 [email protected]
         var q   =  new mw.Api(),
             w   =  { action:  "query",
                      list:    "users",
                      ususers: account,
                      usprop:  "blockinfo" };
         IUTIL.utl.furnish();
         q.get( w ).done( this.found )
                   .fail( this.fault );
      };   // .known.fire()



      IUTIL.known.found  =  function ( arrived ) {
         // Process API aucccess on account check
         // Precondition:
         //    arrived  -- JSON info of ajax query, or false
         // Uses:
         //    >  .$div
         //    .cnf.feature()
         //    jQuery()
         //    jQuery().css()
         //    jQuery().text()
         //    jQuery().append()
         // Remark: Used as event handler -- 'this' is not IUTIL.known
         // 2014-10-10 [email protected]
         var q  =  false,
             $div;
         if ( arrived ) {
            q  =  arrived.query;
            if ( q ) {
               q  =  q.users;
               if ( q ) {
                  q  =  q;
                  if ( q ) {
                     if ( ! q.userid ) {
                        $div  =  $( "<div>" );
                        $div.css( { "border":      "solid 5px #FF0000",
                                    "color":       "#FF0000",
                                    "font-weight": "bold",
                                    "margin":      "10px",
                                    "padding":     "1em" } );
                        $div.text( IUTIL.cnf.feature( "NoUserName",
                                                      false )
                                   + ": " + q.name );
                        IUTIL.$div.append( $div );
                     }
                  }
               }
            }
         }
      };   // .known.found()
   }   // .known



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



   if ( typeof IUTIL.utl  !==  "object" ) {
      // Misc utilitiies
      // Dependencies: user, mediawiki.util
      IUTIL.utl  =  { };



      IUTIL.utl.factory   =  function ( adjust, apply ) {
         // Replace placeholders in string
         // Precondition:
         //    adjust  -- base string with possible placeholders  {{{_}}}
         //               may be empty non-string
         //    apply   -- object with key:value assignments
         // Postcondition:
         //    Returns adapted string
         // 2012-12-26 [email protected]
         var r  =  adjust,
             re, s;
         if ( r ) {
            if ( r.indexOf( "{{{" )  >=  0 ) {
               for ( s in apply ) {
                  re  =  new RegExp( "{{{" + s + "}}}",  "g" );
                  r   =  r.replace( re,  apply );
               }   // for s in apply
            }
         }
         return r;
      };   // .utl.factory()



      IUTIL.utl.fault  =  function ( apply, $assign ) {
         // Equip page with error message box
         // Precondition:
         //    apply     -- HTML error message text, jQuery, or false
         //    $assign   -- jQuery container to be reset
         //                 IUTIL.$div
         //                 IUTIL.$msg
         // Uses:
         //    >  .$msg
         //    jQuery().empty()
         //    jQuery().css()
         //    .cnf.feature()
         //    jQuery().append()
         // 2014-10-10 [email protected]
         var $container = $assign,
             $msg;
         if ( ! $container ) {
            $container  =  IUTIL.$msg;
         }
         $container.empty();
         $container.css( { "border":  "solid 2px #FF0000",
                           "color":   "#FF0000",
                           "margin":  "3px",
                           "padding": "1em" } );
         switch ( typeof apply ) {
            case "function":
            case "object":
               $msg  =  apply;
               break;
            case "string":
               $msg  =  $( "<strong>" );
               $msg.text( apply );
               break;
            default:
               $msg  =  $( "<strong>" );
               $msg.text( IUTIL.cnf.feature( "Error", false ) );
         }   // switch typeof apply
         $container.append( $msg );
      };   // .utl.fault()



      IUTIL.utl.filter  =  function ( adjust ) {
         // Escape pipe symbols in text, but maintain links or templates
         // Precondition:
         //    adjust  -- base string
         // Postcondition:
         //    Return adjust with escaped pipes
         // Uses:
         //    this
         //    >< .str.reWSpaces
         // 2013-01-21 [email protected]
         var r  =  adjust,
             s;
         if ( r.indexOf( "|" )  >=  0 ) {
            if ( ! this.reWSpaces ) {
               this.reWSpaces  =  new RegExp( "+", "g" );
            }
            if ( ! this.rePipeTemplate ) {
               s                     =  "(\\{\\{+)\\|(+\\}\\})";
               this.rePipeTemplate   =  new RegExp( s );
               this.rePipesTemplate  =  new RegExp( s, "g" );
            }
            r  =  r.replace( this.reWSpaces, " " )
                   .replace( /\]/g, "\f" )
                   .replace( /(\+)\|(+\f\f)/g, "$1\t$2" );
            do {
               s  =  r;
               r  =  r.replace( this.rePipesTemplate, "$1\t$2" );
            } while ( s !== r );
            r  =  r.replace( /\|/g, "&#124;" )
                   .replace( /\f/g, "]" )
                   .replace( /\t/g, "|" );
         }
         return r;
      };   // .utl.filter()



      IUTIL.utl.fire  =  function () {
         // Initialize module
         // Precondition:
         //    Standard user module has been loaded.
         // Uses:
         //    >  .options
         //    >< .cnf.user
         // 2014-10-10 [email protected]
         if ( typeof IUTIL.cnf.user  !==  "object" ) {
            if ( IUTIL.options   &&
                 typeof IUTIL.options  ===  "object" ) {
               IUTIL.cnf.user  =  IUTIL.options;
            } else {
               IUTIL.cnf.user  =  { };
            }
         }
      };   // .utl.fire()



      IUTIL.utl.firm  =  function () {
         // Make signature with time stamp
         // Postcondition:
         //    Return string
         // Uses:
         //    mw.config.get()
         // 2012-12-15 [email protected]
         var d  =  new Date(),
             s  =  mw.config.get( "wgUserName" ),
             r  =  "] " + d.toLocaleString();
         return r;
      };   // .utl.firm()



      IUTIL.utl.fold  =  function ( analyze ) {
         // Split page name into namespace and title
         // Precondition:
         //    analyze  -- page name
         // Postcondition:
         //    Returns Array
         //                   ns number
         //                   title
         //                   root of subpage, terminated by '/'
         // Uses:
         //    >< .cnf.reSpace
         //    >< .cnf.roomNs
         //    mw.config.get()
         // 2015-11-08 [email protected]
         var s  =  analyze.replace( /%3A/ig, ":" ),
             r  =  ,
             j  =  s.indexOf( ":" ),
             n;
         if ( j > 0 ) {
            if ( ! IUTIL.cnf.reSpace ) {
               IUTIL.cnf.reSpace  =  new RegExp( " ", "g" );
            }
            if ( ! IUTIL.cnf.roomNs ) {
               IUTIL.cnf.roomNs  =  mw.config.get( "wgNamespaceIds" );
            }
            n  =  s.substr( 0, j ).replace( IUTIL.cnf.reSpace, "_" );
            n  =  IUTIL.cnf.roomNs;
            if ( n ) {
               r  =  ;
               j  =  s.indexOf( "/",   j + 1 );
               if ( j > 0 ) {
                  r  =  s.substr( 0,  j + 1 );
               }
            }
         }
         return r;
      };   // .utl.fold()



      IUTIL.utl.format  =  function ( appoint ) {
         // Format Date object according to ISO 8601 UTC "Z"
         // Precondition:
         //    appoint  -- Date object
         // Postcondition:
         //    Return ISO 8601 string in "Z" time zone
         // 2013-01-05 [email protected]
         var r  =  appoint.getUTCFullYear() + "-",
             i  =  appoint.getUTCMonth() + 1;
         if ( i < 10 ) {
   			i	=  "0" + i;
         }
         r  =  r + i + "-";
         i  =  appoint.getUTCDate();
         if ( i < 10 ) {
   			i	=  "0" + i;
         }
         r  =  r + i + "T";
         i  =  appoint.getUTCHours();
         if ( i < 10 ) {
   			i	=  "0" + i;
         }
         r  =  r + i + ":";
         i  =  appoint.getUTCMinutes();
         if ( i < 10 ) {
   			i	=  "0" + i;
         }
         r  =  r + i + ":";
         i  =  appoint.getUTCSeconds();
         if ( i < 10 ) {
   			i	=  "0" + i;
         }
   		return  r + i + "Z";
      };   // .utl.format()



      IUTIL.utl.furnish  =  function () {
         // Insert containers on page
         // Precondition:
         //    document ready
         // Uses:
         //    >  mw.util.$content
         //    >< .$top
         //    >< .$div
         //     < .$msg
         //    mw.util.addCSS()
         //    jQuery()
         //    jQuery().attr()
         //    jQuery().before()
         //    jQuery().css()
         //    jQuery().prepend()
         // 2014-10-10 [email protected]
         mw.util.addCSS( "#siteNotice,"
                         + ".cn-fundraiser-banner,"
                         + "#fundraising"
                         + "{display: none ! important;}" );
         if ( typeof IUTIL.$div  !==  "object" ) {
            IUTIL.$div  =  $( "<div>" );
            IUTIL.$div.attr( "class", "importUtilityDiv" );
            if ( typeof IUTIL.$top  !==  "object" ) {
               IUTIL.$top  =  $( "#editform" );
               if ( IUTIL.$top.length ) {
                  IUTIL.$top.before( IUTIL.$div );
               } else {
                  IUTIL.$top  =  $( "#mw-content-text" );
                  if ( IUTIL.$top.length ) {
                     IUTIL.$top.prepend( IUTIL.$div );
                  } else {
                     IUTIL.$top  =  $( "#bodyContent" );
                     if ( ! IUTIL.$top.length ) {
                        IUTIL.$top  =  $( "#article" );
                        if ( ! IUTIL.$top.length ) {
                           IUTIL.$top  =  $( "#content" );
                           if ( ! IUTIL.$top.length ) {
                              IUTIL.$top  =  mw.util.$content;
                           }
                        }
                     }
                     IUTIL.$top.before( IUTIL.$div );
                  }
               }
            }
            IUTIL.$msg  =  $( "<div>" );
            IUTIL.$msg.attr( "id", "importUtilityMsg" );
            IUTIL.$div.prepend( IUTIL.$msg );
         }
      };   // .utl.furnish()
   }   // .utl



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



   function fire() {
      // Script unit has been loaded
      // Uses:
      //    >  SIGNATURE
      //    >  .type
      //    >  Self
      //    >  .start
      //    >  SIG
      //    mw.loader.getState()
      //    mw.loader.state()
      //    .utl.fire()
      // 2018-08-24 [email protected]
      var rls, sign;
      if ( mw.loader.getState( SIGNATURE )  !==  "ready" ) {
         rls  =  { };
         rls  =  "ready";
         mw.loader.state( rls );
         sign  =  IUTIL.type + "." + Self;
         mw.hook( sign + ".ready" ).fire( { type: sign,
                                            vsn:  Version } );
         if ( typeof IUTIL.start  ===  "string"
              &&  ( mw.loader.getState( SIG )  ===  "ready" )
              &&  typeof IUTIL  ===  "object"
              &&  IUTIL ) {
            IUTIL.utl.fire();
            IUTIL.fire();
         }
      }
   }   // fire()



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



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

/// EOF   importUtility/utl.js    </nowiki>