User:PerfektesChaos/js/editToolStrIns/debug.js

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
/// editToolStrIns
/// Edit tool to insert characters and strings -- especially for WMF
/// 2018-08-24 PerfektesChaos@de.wikipedia
// ResourceLoader:  compatible;
//    dependencies: user, mediawiki.util, jquery.textSelection
/// Fingerprint: #0#0#
/* jshint bitwise:false, forin:false                                   */
/* global window:false                                                 */
/* jshint curly:true, eqeqeq:true, futurehostile:true, latedef:true,
          laxbreak:true,
          nocomma:true, strict:true, undef:true, unused:true           */



( function ( mw, $ ) {
   "use strict";
   var Version   = -1.27,
       Sign      = "editToolStrIns",
       Signature = "ext.gadget." + Sign,
       ETSI;
   if ( typeof mw.libs[ Sign ]  !==  "object"
        ||   ! mw.libs[ Sign ] ) {
      mw.libs[ Sign ]  =  { };
   }
   ETSI            = mw.libs[ Sign ];
   ETSI.type       = Sign;
   ETSI.vsn        = Version;
   ETSI.signature  = Signature;
   ETSI.doc        = "[[mw:User:PerfektesChaos/js/" + ETSI.type + "]]";
   if ( ETSI.vsn < 0  &&  typeof ETSI.debugging !== "object" ) {
      ETSI.debugging = { loud: true,
                         say:  "ETSI" };
   }


// Uses:
//    MediaWiki  1.18 (mw.libs, jQuery.textSelection)
//    jQuery     core; $.focus(), .isArray()
//    JavaScript 1.3
//    DOM        Level 3

/*
  Based upon previous work of:
     mw:User:Alex Smotrov              2008
     w:de:User:Revolus                 2008/2009
     w:de:User:WIKImaniac              2009
     w:de:MediaWiki:Onlyifediting.js   2011-08-11
*/
/// @license GPL [//www.mediawiki.org/w/COPYING] (+GFDL, LGPL, CC-BY-SA)
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program;
 * if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 * http://www.gnu.org/copyleft/gpl.html
 */
/// About: [[mw:User:PerfektesChaos/js/editToolStrIns]] <nowiki>



   if ( typeof ETSI.debugging !== "object" ) {
      ETSI.debugging = false;
   }
   if ( typeof ETSI.l10n !== "object" ) {
      ETSI.l10n = { };
   }
   ETSI.attr   = { names: { "class":       false,
                            "lang":        false,
                            "dir":         false,
                            "font-family": true,
                            "font-size":   true }
                 };
   ETSI.defs   = { global:     null,
                   looser:     false };
   ETSI.gui    = { builder:    false,
                   container:  ".mw-editTools",
                   self:       "edit-tool-SI",
                   $container: false,
                   $wrapper:   false };
   ETSI.listen = false;
   ETSI.loaded = false;
   ETSI.menu   = { };
   ETSI.nowiki = "nowiki";
   ETSI.util   = { };



// No customization recommended above this point.
// Start adption and localization here:

   ETSI.gui.old =   "#editpage-specialchars,"
                  + "#mw-edittools-charinsert,"
                  + "#specialchars";   // 2014-01-05
   ETSI.menu.separator = " •";
   ETSI.menu.divide    = { "display":      "inline-block",
                           "font-weight":  "bold",
                           "margin-left":  "0.8em",
                           "margin-right": "0.45em",
                           "white-space":  "nowrap" };
   ETSI.menu.stick     = "…";
   ETSI.l10n.dewiki = {   // example for introduction period
      "list": [
         "0",      "Standard",
         "[[]]",   "WikiSyntax",
         ":6",     "Datei:",
         ":10",    "Vorlage:",
         "IPA",    "IPA-Lautschrift",
         "Latin",  "Lateinisch",
         "AHD",    "AHD-Lautschrift",
         "grc",    "Altgriechisch",
         "ar",     "Arabisch",
         "DMG",    "DMG-Umschrift",
         "eo",     "Esperanto",
         "et",     "Estnisch",
         "fr",     "Französisch",
         "gl",     "Galicisch",
         "el",     "Griechisch",
         "haw",    "Hawaiisch",
         "iw",     "Hebräisch",
         "is",     "Isländisch",
         "it",     "Italienisch",
         "hbs",    "Kroatisch/Serbisch/Bosnisch",
         "Cyril",  "Kyrillisch",
         "Latin",  "Lateinisch",
         "lv",     "Lettisch",
         "lt",     "Litauisch",
         "mt",     "Maltesisch",
         "pl",     "Polnisch",
         "pt",     "Portugiesisch",
         "Pinyin", "Pinyin",
         "roa",    "Romanisch",
         "ro",     "Rumänisch",
         "Scand",  "Skandinavisch",
         "wen",    "Sorbisch",
         "es",     "Spanisch",
         "cz",     "Tschechisch",
         "tr",     "Türkisch",
         "hu",     "Ungarisch",
         "vi",     "Vietnamesisch" ],
      "defs": {
         "AHD": { "class": "Unicode" },
         "ar":  { "class": "spanAr", "font-size": "1.25em" },
         "grc": { "class": "polytonic" },
         "haw": { "font-family":
                  "Arial Unicode MS, Lucida Sans Unicode, MS Mincho, "
                  + "Arial, sans-serif;" } }
   };   // .l10n.dewiki.list 2011-11-01
   ETSI.l10n.enwiki = { "defs": {   // example (introduction period)
      "0":         [ [ "–",
                       "—",
                       [ "‘", "’" ],
                       [ "“", "”" ] ],
                     false,
                     [ 1, "°″′≈≠≤≥±−×÷√←→·§" ],
                     [ 0, "<b>Sign your posts on talk pages:</b>" ],
                     [ "~~~~" ],
                     [ 0, "<b>Cite your sources:</b>" ],
                     [ [ "<ref>", "</ref>" ] ] ],
      "[[]]":      [ [ 0, "<b>Insert:</b>" ],
                     [ "–",
                       "—",
                       [ "‘", "’" ],
                       [ "“", "”" ] ],
                     false,
                     [ 1, "°″′≈≠≤≥±−×÷√←→·§" ],
                     false,
                     [ "~~~~",
                       [ "<ref>", "</ref>" ] ],
                     [ 0, "<b>Wiki markup:</b>" ],
                     [ [ "{{", "}}" ],
                       [ "{{{", "}}}" ],
                       "|",
                       [ "[", "]" ],
                       [ "[[", "]]" ],
                       [ "[[Category:", "]]" ],
                       [ "#REDIRECT [[", "]]" ],
                       "&nbsp;",
                       [ "<s>", "</s>" ],
                       [ "<sup>", "</sup>" ],
                       [ "<sub>", "</sub>" ],
                       [ "<code>", "</code>" ],
                       [ "<pre>", "</pre>" ],
                       [ "<blockquote>", "</blockquote>" ],
                       [ "<ref name=\"", "\"/>" ],
                       [ "{{#tag:ref|", "|group=\"nb\"}}" ],
                       "{{Reflist}}",
                       "<references/>",
                       [ "<includeonly>", "</includeonly>" ],
                       [ "<noinclude>", "</noinclude>" ],
                       [ "{{DEFAULTSORT:", "}}" ],
                       [ "<" + ETSI.nowiki + ">",
                         "</" + ETSI.nowiki + ">" ],
                       [ "<!-- ", " -->" ],
                       [ "<span class=\"plainlinks\">", "</span>" ] ] ],
      "Arabic":    [ { "dir": "rtl", "font-size": "120%" },
                     [ 0, "<b>Transcription:</b>" ],
                     [ 1, "ʾṯḥḫẖḏšṣḍṭẓʿġẗ",
                          "اﺁبتثجحخدذرزسشصضطظعغفقكلمنهةويىءأإؤئ" ] ],
      "Cyrillic":  [ [ 1, "АаБбВвГг",
                          "ҐґЃѓДдЂђ",
                          "ЕеЁёЄєЖж",
                          "ЗзЅѕИиІі",
                          "ЇїЙйЈјКк",
                          "ЌќЛлЉљМм",
                          "НнЊњОоПп",
                          "РрСсТтЋћ",
                          "УуЎўФфХх",
                          "ЦцЧчЏџШш",
                          "ЩщЪъЫыЬь",
                          "ЭэЮюЯя",
                          "ӘәӨөҒғҖҗ",
                          "ҚқҜҝҢңҮү",
                          "ҰұҲҳҸҹҺһ",
                          "ҔҕӢӣӮӯҘҙ",
                          "ҠҡҤҥҪҫӐӑ",
                          "ӒӓӔӕӖӗӰӱ",
                          "ӲӳӸӹӀ",
                          "ҞҟҦҧҨҩҬҭ",
                          "ҴҵҶҷҼҽҾҿ",
                          "ӁӂӃӄӇӈӋӌ",
                          "ӚӛӜӝӞӟӠӡ",
                          "ӤӥӦӧӪӫӴӵ" ] ],
      "Greek":     [ [ 1, "ΆάΈέΉήΊίΌόΎύΏώ",
                          "ΑαΒβΓγΔδ",
                          "ΕεΖζΗηΘθ",
                          "ΙιΚκΛλΜμ",
                          "ΝνΞξΟοΠπ",
                          "ΡρΣσςΤτΥυ",
                          "ΦφΧχΨψΩω",
                          "ᾼᾳᾴᾺὰᾲᾶᾷἈἀᾈᾀἉἁᾉᾁἌἄᾌᾄἊἂᾊᾂἎἆᾎᾆἍἅᾍᾅἋἃᾋᾃἏἇᾏᾇ",
                          "ῈὲἘἐἙἑἜἔἚἒἝἕἛἓ",
                          "ῌῃῄῊὴῂῆῇἨἠᾘᾐἩἡᾙᾑἬἤᾜᾔἪἢᾚᾒἮἦᾞᾖἭἥᾝᾕἫἣᾛᾓἯἧᾟᾗ",
                          "ῚὶῖἸἰἹἱἼἴἺἲἾἶἽἵἻἳἿἷ",
                          "ῸὸὈὀὉὁὌὄὊὂὍὅὋὃ",
                          "ῤῬῥ",
                          "ῪὺῦὐὙὑὔὒὖὝὕὛὓὟὗ",
                          "ῼῳῴῺὼῲῶῷὨὠᾨᾠὩὡᾩᾡὬὤᾬᾤὪὢᾪᾢὮὦᾮᾦὭὥᾭᾥὫὣᾫᾣὯὧᾯᾧ" ],
                     [ [ "{{Polytonic|", "}}" ] ] ],
      "Hebrew":    [ { "dir": "rtl", "font-size": "120%" },
                     [ 2, 0x05D0, 0x05EA,
                          0x05F3, 0x05F4,
                          0x05F0, 0x05F2 ] ],
      "IPA_en":    [ { "class": "IPA" },
                     [ -32, "ˈ ˌ ŋ ɡ tʃ dʒ ʃ ʒ θ ð ʔ",
                            "iː ɪ uː ʊ ʌ ɜr eɪ ɛ æ oʊ ɒ ɔː ɔɪ ɔr ɑː "
                            + "ɑr aɪ aʊ",
                            "ə ər ɨ ɵ ʉ" ],
                     [ [ "{{IPA-en|", "}}" ],
                       [ "{{IPA|/", "/}}" ],
                       [ "‹", "›" ] ] ],
      "Latin":     [ [ 1, "AaÁáÀàÂâÄäǍǎĂăĀāÃãÅåĄąÆæǢǣ",
                          "Bb",
                          "CcĆćĊċĈĉČčÇç",
                          "DdĎďĐđḌḍÐð",
                          "EeÉéÈèĖėÊêËëĚěĔĕĒēẼẽĘęƐɛƏə",
                          "Ff",
                          "GgĠġĜĝĞğĢģ",
                          "HhĤĥĦħḤḥ",
                          "IiİıÍíÌìÎîÏïǏǐĬĭĪīĨĩĮį",
                          "JjĴĵ",
                          "KkĶķ",
                          "LlĹĺĿŀĽľĻļŁłḶḷḸḹ",
                          "MmṂṃ","NnŃńŇňÑñŅņṆṇŊŋ",
                          "OoÓóÒòÔôÖöǑǒŎŏŌōÕõǪǫŐőØøŒœ",
                          "Ɔɔ",
                          "Pp",
                          "Qq",
                          "RrŔŕŘřŖŗṚṛṜṝ",
                          "SsŚśŜŝŠšŞşṢṣß",
                          "TtŤťŢţṬṭÞþ",
                          "UuÚúÙùÛûÜüǓǔŬŭŪūŨũŮůŲųŰűǗǘǛǜǙǚǕǖ",
                          "Vv",
                          "WwŴŵ",
                          "Xx",
                          "YyÝýŶŷŸÿỸỹȲȳ",
                          "ZzŹźŻżŽž",
                          "ßÐðÞþŊŋƏə" ],
                     [ [ "{{Unicode|", "}}" ] ] ],
      "MathLogic": [ [ 1, "−×÷⋅°∗∘±∓≤≥≠≡≅≜≝≐≃≈⊕⊗⇐⇔⇒∞←↔→≪≫∝√∤≀◅▻⋉⋊⋈∴∵↦¬∧"
                          + "∨⊻∀∃∈∉∋⊆⊈⊊⊂⊄⊇⊉⊋⊃⊅∪∩∑∏∐′∫∬∭∮∇∂∆∅ℂℍℕℙℚℝℤℵ⌊⌋⌈"
                          + "⌉⊤⊥⊢⊣⊧□∠⟨⟩" ],
                     false,
                     [ [ "{{frac|", "|}}" ],
                       "&nbsp;",
                       "&minus;",
                       [ "<math>", "</math>" ],
                       [ "{{math|", "}}" ] ] ]
   } };   // .l10n.enwiki 2011-11-01
   ETSI.l10n.de = {
      hintList: "Zeichensatz auswählen",
      hintMenu: "Element auswählen" };
   ETSI.l10n.de.defs = {
      "0":    [ null,
                [ 1, "ÄäÖößÜü" ],
                [ "’",
                  [ "„", "“" ],
                  [ "‚", "‘" ],
                  [ "»", "«" ],
                  [ "›", "‹" ],
                  [ "“", "”" ],
                  [ "‘", "’" ],
                  [ "«", "»" ],
                  [ "‹", "›" ],
                  [ "–", "", "", "Bisstrich/Gedankenstrich" ] ],
                [ "+",
                  [ "−", "", "", "mathematisches Minus" ],
                  [ "·", "", "", "mathematisches Mal" ] ],
                false,
                [ 1, "×÷≈≠±≤≥²³½*†⚭#*‰§€¢£¥$¿¡∞‣•" ],
                [ "…", "→", "↔" ],
                [ [ "&nbsp;", "", "", "Geschütztes Leerzeichen" ],
                  [ "[[", "]]", "", "Wikilink" ],
                  "|",
                  [ "{{", "}}", "", "Vorlageneinbindung" ],
                  [ "~~~~", "", "", "Signatur" ] ],
                [ [ "°", "", "", "Grad" ],
                  [ "′", "", "", "Bogenminute, Fuß" ],
                  [ "″", "", "", "Bogensekunde, Zoll" ] ] ],
      "[[]]": [ null,
                [ [ "[[Kategorie:", "]]" ],
                  [ "[[Datei:", "]]" ],
                  [ "{{SEITENTITEL:", "}}" ],
                  [ "{{SORTIERUNG:", "}}" ],
                  [ "#WEITERLEITUNG [[", "]]" ] ],
                [ "{{Begriffsklärung}}",
                  "{{Begriffsklärungshinweis}}",
                  [ "{{Dieser Artikel|", "}}" ] ],
                [ [ "<ref>", "</ref>" ],
                  [ "<ref name=\"", "\"></ref>" ],
                  [ "<ref name=\"", "\" />" ],
                  "<references />" ],
                [ [ "<" + ETSI.nowiki + ">",
                    "</" + ETSI.nowiki + ">" ],
                  [ "<code>", "</code>" ],
                  [ "<syntaxhighlight lang=\"",
                    "\"></syntaxhighlight>" ],
                  [ "<noinclude>", "</noinclude>" ],
                  [ "<includeonly>", "</includeonly>" ],
                  [ "<onlyinclude>", "</onlyinclude>" ],
                  [ "<math>", "</math>" ] ] ],
      ":6":   [ null,
                [ [ "{{Information\n"
                    + "|Beschreibung     = \n"
                    + "|Quelle           = \n"
                    + "|Urheber          = \n"
                    + "|Datum            = \n"
                    + "|Genehmigung      = \n"
                    + "|Andere Versionen = }}",
                    "", "", "", "{{Information}}" ],
                  "{{Bild-by}}",
                  "{{Bild-frei}}",
                  "{{Bild-LogoSH}}",
                  "{{Bild-PD-Schöpfungshöhe}}" ] ],
      "----":  [ null,
                 [ 0, "<em>Keine sinnvolle Auswahl</em>" ] ]
   };   // .l10n.de.defs 2018-07-09
   ETSI.l10n.de.list = [
      "0",      "Standard",
      "[[]]",   "WikiSyntax",
      ":6",     "Datei:",
      ":10",    "Vorlage:",
      "IPA",    "IPA-Lautschrift",
      "Latin",  "Lateinisch",
      "el",     "Griechisch",
      "Cyril",  "Kyrillisch"
   ];   // .l10n.de.list 2011-11-28
   // Keep English as fallback position:
   ETSI.l10n.en = {
      hintList: "Choose character subset",
      hintMenu: "Click on the character or tag "
                + "to insert it into the most recent field" };
   ETSI.l10n.en.list = [
      "0",         "Insert",
      "[[]]",      "Wiki markup",
      ":6",        "File:",
      ":10",       "Template:",
      "Symbols",   "Symbols",
      "Latin",     "Latin",
      "Greek",     "Greek",
      "Cyrillic",  "Cyrillic",
      "Hebrew",    "Hebrew",
      "Arabic",    "Arabic",
      "IPA_en",    "IPA (English)",
      "IPA_T",     "IPA",
      "MathLogic", "Math and logic"
   ];   // .l10n.en.list 2011-11-23
   ETSI.l10n.en.defs = {
      ":6":         [ null,
                      [ [ "{{Information\n"
                          + "|Description=\n"
                          + "|Source={{own}}\n"
                          + "|Author=\n"
                          + "|Permission=\n"
                          + "|other_versions=}}",
                          "", "", "", "{{Information}}" ] ] ],
      "Symbols":    [ null,
                      [ 1, "~|", "¡¿†‡↔↑↓•¶", "#", "½⅓⅔¼¾⅛⅜⅝⅞∞" ],
                      [ [ "‘", "’" ],
                        [ "“", "”" ],
                        [ "‹", "›" ],
                        [ "«", "»" ],
                        [ "⟨", "⟩" ] ],
                      [ 1, "¤₳฿₵¢₡₢$₫₯€₠₣ƒ₴₭₤ℳ₥₦№₧₰£៛₨₪৳₮₩¥", "♠♣♥♦" ],
                      [ -32, "m² m³" ],
                      [ 1,   "♭♯♮", "©®™", "◌" ],
                      [ [ "{{Unicode|", "}}" ] ] ],
      "----":       [ null,
                      [ 0, "<em>no valid selection</em>" ] ]
   };   // .l10n.en.defs 2011-11-01
   ETSI.l10n.it = { };
   ETSI.l10n.it.defs = {
      "0":    [ null,
                [ [ "{{", "}}" ],
                  [ "[[", "]]" ],
                  [ "[", "]" ] ],
                false,
                [ "’",
                  [ "«", "»" ],
                  [ "“", "”" ],
                  [ "‘", "’" ] ],
                false,
                [ [ "<!-- ", " -->" ] ],
                [ 1, "…→•·←–ºª" ],
                [ [ "[[Categoria:", "]]" ],
                  [ "File:", "]]" ],
                  [ "Media:", "]]" ],
                  [ "#RINVIA[[", "]]" ],
                  "__TOC__",
                  "__NOTOC__",
                  "__NOINDEX__",
                  [ "<del>", "</del>" ],
                  [ "<gallery>", "</gallery>" ],
                  [ "<math>", "</math>" ],
                  [ "<" + ETSI.nowiki + ">",
                    "</" + ETSI.nowiki + ">" ],
                  [ "<ref>", "</ref>" ],
                  "<references/>",
                  [ "<small>", "</small>" ],
                  [ "{{formatnum:", "}}" ] ],
                [ 0, "<br />Sezioni:" ],
                [ [ "==", "==" ],
                  [ "===", "===" ],
                  [ "====", "====" ],
                  "==Note==",
                  "==Bibliografia==",
                  "==Voci correlate==",
                  "==Altri progetti==",
                  "==Collegamenti esterni==" ],
                [ 0, "<br />Firme:" ],
                [ "--~~~",
                  "--~~~~",
                  "--~~~~~" ],
                [ 0, "<br />Tabelle:" ],
                [ "{|",
                  "|-",
                  "||",
                  "|}",
                  "–",
                  "|" ],
                [ 0, "<br />Avvisi:" ],
                [ "{{S||}}",
                  "{{F||}}",
                  "{{W||}}",
                  "{{A|||}}",
                  "{{C|||}}",
                  "{{E|||}}",
                  "{{P|||}}" ],
                [ 0, "<br />Template:" ],
                [ "{{ping|}}" ] ]
   };   // .l10n.it.defs 2016-10-13
   // Repository for world-wide definitions; items shoud not be deleted.
   // May be unused by L10N, but referenced by user customization.
   ETSI.defs.global = {
      "0":    [ null,
                [ "’",
                  "–",
                  [ "“", "”" ],
                  [ "‘", "’" ] ],
                [ 1, "·×÷−≈≠±≤≥²³½†#*‰§€¢£¥$¿¡∞‣•…→↔" ],
                [ "&nbsp;",
                  [ "[[", "]]" ],
                  "|",
                  [ "{{", "}}" ],
                  "~~~~" ] ],
      "[[]]": [ null,
                [ "~~~~",
                  [ "{{", "}}" ],
                  [ "{{{", "}}}" ],
                  "|",
                  [ "[", "]" ],
                  [ "[[", "]]" ] ] ],
      "<>":   [ null,
                [ "<br />",
                  [ "<code>", "</code>" ],
                  [ "<s>", "</s>" ],
                  [ "<small>", "</small>" ],
                  [ "<sub>", "</sub>" ],
                  [ "<sup>", "</sup>" ],
                  [ "<!-- ", " -->" ] ],
                [ "<" + ETSI.nowiki + " />",
                  [ "<" + ETSI.nowiki + ">",
                    "</" + ETSI.nowiki + ">" ] ],
                [ [ "<math>", "</math>" ],
                  [ "<syntaxhighlight lang=\"\">", "</syntaxhighlight>" ]
                  ],
                [ [ "<ref>", "</ref>" ],
                  [ "<ref name=\"", "\" />" ],
                  [ "<ref name=\"", "\"></ref>" ],
                  "<references />" ],
                [ [ "<includeonly>", "</includeonly>" ],
                  [ "<noinclude>", "</noinclude>" ],
                  [ "<onlyinclude>", "</onlyinclude>" ] ] ],
      ":10":  [ { "font-family": "monospace"  },
                [ [ "{{", "}}" ],
                  [ "{{{", "|}}}" ],
                  "|",
                  [ "{{#if:", "||}}",             "", "", "if" ],
                  [ "{{#ifeq:", "|||}}",          "", "", "ifeq" ],
                  [ "{{#ifexist:", "||}}",        "", "", "ifexist" ],
                  [ "{{#expr:", "}}",             "", "", "expr" ],
                  [ "{{#ifexpr:", "||}}",         "", "", "ifexpr" ],
                  [ "{{#iferror:", "||}}",        "", "", "iferror" ],
                  [ "{{#switch:", "|| #default=}}","","", "switch" ],
                  [ "{{#tag:", "|}}",             "", "", "tag" ],
                  [ "{{formatnum:", "}}",         "", "", "formatnum" ],
                  [ "{{formatdate:", "}}",        "", "", "formatdate" ],
                  [ "{{lc:", "}}",                "", "", "lc" ],
                  [ "{{uc:", "}}",                "", "", "uc" ],
                  [ "{{subst:", "}}",             "", "", "subst" ] ] ],
      // ISO 639
      "ang": [ { "lang": "ang" },
               [ 1, "ĀāÆæǢǣǼǽĊċÐðĒēĠġĪīŌōŪūǷƿȲȳÞþȜȝ" ] ],
      "ar":  [ { "lang": "ar", "dir": "rtl" },
               [ 1, "؛؟ءآأؤإئابةتثجحخدذرزسشصضطظعغفقكلمنهوىي،",
                    "پچژگڭ"] ],
      "bn":  [ { "lang": "bn" },
               [ 2, 0x0981, 0x0983,
                    0x0985, 0x098C,
                    0x098F, 0x0990,
                    0x0993, 0x09A8,
                    0x09AA, 0x09B0,
                    0x09B2, 0x09B2,
                    0x09B6, 0x09B9,
                    0x09BC, 0x09C4,
                    0x09C7, 0x09C8,
                    0x09CB, 0x09CE,
                    0x09D7, 0x09D7,
                    0x09DC, 0x09DD,
                    0x09DF, 0x09E3,
                    0x09E6, 0x09FB ] ],
      "cz":  [ { "lang": "cz" },
               [ 1, "ÁáČčĎďÉéĚěÍíŇňÓóŘřŠšŤťÚúŮůÝýŽž" ] ],
      "de":  [ { "lang": "de" },
               [ 1, "ÄäÖößÜü" ],
               [ [ "„", "“" ],
                 [ "‚", "‘" ],
                 [ "»", "«" ],
                 [ "›", "‹" ] ] ],
      "el":  [ { "lang": "el" },
               [ 1, "ΑΆΒΓΔΕΈΖΗΉΘΙΊΚΛΜΝΞΟΌΠΡΣΤΥΎΦΧΨΩΏ",
                    "αάβγδεέζηήθιίκλμνξοόπρσςτυύφχψωώ" ] ],
      "eo":  [ { "lang": "eo" },
               [ 1, "ĈĉĜĝĤĥĴĵŜŝŬŭ" ] ],
      "es":  [ { "lang": "es" },
               [ 1, "ÁáÉéÍíÑñÓóÚúÜü¡¿" ] ],
      "et":  [ { "lang": "et" },
               [ 1, "Č芚ŽžÕõÄäÖöÜü" ] ],
      "fr":  [ { "lang": "fr" },
               [ 1, "ÀàÂâÇçÉéÈèÊêËëÎîÏïÔôŒœÙùÛûÜüŸÿ" ],
               [ [ "«", "»" ],
                 [ "‹", "›" ] ] ],
      "gl":  [ { "lang": "gl" },
               [ 1, "ÁáÀàÂâÄäÉéÈèÊêËëÌìÎîÏïÓóÒòÔôÖöÙùÛû"
                    + "ẀẁŴŵẄẅÝýỲỳŶŷŸÿ" ] ],
      "grc": [ { "lang": "grc" },
               [ 1, "ΑαΆάΒβΓγΔδΕεΈέΖζΗηΉήΘθΙιΊίΪϊΐΚκΛλΜμΝνΞξΟοΌόΠπΡρΣσς"
                    + "ΤτΥυΫϋΎύΰΦφΧχΨψΩωΏώ;·ἀἁὰᾶἂἃἄἅἆἇᾳᾀᾁᾴᾲᾷᾄᾅᾂᾃᾆᾇἐἑὲἔἕἒ"
                    + "ἓἠἡὴῆἤἢἣἥἦἧῃῄῂῇᾐᾑᾔᾒᾕᾓᾖᾗἰἱὶῖἴἲἵἳἶἷὸὀὁὄὅὂὃῤῥὐὑὺῦὔὕὒ"
                    + "ὓὖὗὠὡὼῶὤὢὥὣὦὧῳῴῲῷᾠᾡᾤᾢᾥᾣᾦᾧ`᾿῾῍῎῏῟῞῝῍῎ϜϝϘϙϠϡ" ] ],
      "gu":  [ { "lang": "gu" },
               [ 2, 0x0A81, 0x0A83,
                    0x0A85, 0x0A8D,
                    0x0A8F, 0x0A91,
                    0x0A93, 0x0AA8,
                    0x0AAA, 0x0AB0,
                    0x0AB2, 0x0AB3,
                    0x0AB5, 0x0AB9,
                    0x0ABC, 0x0AC5,
                    0x0AC7, 0x0AC9,
                    0x0ACB, 0x0ACD,
                    0x0AD0, 0x0AD0,
                    0x0AE0, 0x0AE3 ],
               [ 2, 0x0AE6, 0x0AEF,
                    0x0AF1, 0x0AF1 ] ],
      "haw": [ { "lang": "haw" },
               [ 1, "ĀāĒēĪīŌōŪūʻ" ] ],
      "hbs": [ { "lang": "hbs" },
               [ -32, "Č č Ć ć Dž dž Đ đ Š š Ž ž" ] ],
      "hu":  [ { "lang": "hu" },
               [ 1, "áéíŐöóőŰúüű" ] ],
      "is":  [ { "lang": "is" },
               [ 1, "ÁáÐðÉéÍíÓóÚúÝýÞþÆæÖöǫ" ] ],
      "it":  [ { "lang": "it" },
               [ 1, "ÁáÀàÉéÈèÍíÌìÓóÒòÚúÙù" ] ],
      "iw":  [ { "lang": "yi", "dir": "rtl" },
               [ 3, 0x05D0, false,
                    0x05D0, 0x05B7, false,
                    0x05D0, 0x05B8, false,
                    0x05D1, false,
                    0x05D1, 0x05BF, false,
                    0x05D2, false,
                    0x05D3, false,
                    0x05D4, false,
                    0x05D5, false,
                    0x05D5, 0x05BC, 0x05F0, false,
                    0x05F1, false,
                    0x05D6, false,
                    0x05D6, 0x05E9, false,
                    0x05D7, false,
                    0x05D8, false,
                    0x05D9, false,
                    0x05D9, 0x05B4, false,
                    0x05F2, false,
                    0x05F2, 0x05B7, false,
                    0x05DB, false,
                    0x05DA, false,
                    0x05DB, 0x05BC, 0x05DC, false,
                    0x05DE, false,
                    0x05DD, false,
                    0x05E0, false,
                    0x05DF, false,
                    0x05E1, false,
                    0x05E2, false,
                    0x05E4, false,
                    0x05E4, 0x05BC, false,
                    0x05E4, 0x05BF, false,
                    0x05E3, false,
                    0x05E6, false,
                    0x05E5, false,
                    0x05E7, false,
                    0x05E8, false,
                    0x05E9, false,
                    0x05E9, 0x05C2, false,
                    0x05EA, 0x05BC, false,
                    0x05EA, false,
                    0x05F3, false,
                    0x05F4, false,
                    0x05BE ] ],
      "lo":  [ { "lang": "lo" },
               [ 2, 0x0E81, 0x0E82,
                    0x0E84, 0x0E84,
                    0x0E87, 0x0E88,
                    0x0E8A, 0x0E8A,
                    0x0E8D, 0x0E8D,
                    0x0E94, 0x0E97,
                    0x0E99, 0x0E9F,
                    0x0EA1, 0x0EA3,
                    0x0EA5, 0x0EA5,
                    0x0EA7, 0x0EA7,
                    0x0EAA, 0x0EAB,
                    0x0EAD, 0x0EB9,
                    0x0EC0, 0x0EC4,
                    0x0EC6, 0x0EC6,
                    0x0EC8, 0x0ECD,
                    0x0ED0, 0x0ED9,
                    0x0EDC, 0x0EDD ] ],
      "lv":  [ { "lang": "lv" },
               [ 1, "ĀČĒĢĪĶĻŅŠŪŽ", "āčēģīķļņšūž" ] ],
      "lt":  [ { "lang": "lt" },
               [ 1, "ĄČĘĖĮŠŲŪŽ", "ąčęėįšųūž" ] ],
      "mt":  [ { "lang": "mt" },
               [ 1, "ĊċĠġĦħŻż" ] ],
      "pl":  [ { "lang": "pl" },
               [ 1, "ąĄćĆęĘłŁńŃóÓśŚźŹżŻ" ] ],
      "pt":  [ { "lang": "pt" },
               [ 1, "ÁáÀàÂâÃãÇçÉéÊêÍíÓóÔôÕõÚúÜü" ] ],
      "ro":  [ { "lang": "ro" },
               [ 1, "ĂăÂâÎîȘșȚț" ] ],
      "roa": [ { "lang": "roa" },
               [ 1, "ĀāĒēĪīŌōŪū" ] ],
      "si":  [ { "lang": "si" },
               [ 2, 0x0D82, 0x0D83,
                    0x0D85, 0x0D96,
                    0x0D9A, 0x0DB1,
                    0x0DB3, 0x0DBB,
                    0x0DBD, 0x0DBD,
                    0x0DC0, 0x0DC6,
                    0x0DCA, 0x0DCA,
                    0x0DCF, 0x0DD4,
                    0x0DD6, 0x0DD6,
                    0x0DD8, 0x0DDF,
                    0x0DF2, 0x0DF4 ] ],
      "sk":  [ { "lang": "sk" },
               [ 1, "ÁáČčĎďÉéÍíĽľŇňÓóÔôŔ੹ŤťÚúÝýŽž" ] ],
      "te":  [ { "lang": "te" },
               [ 2, 0x0C01, 0x0C03,
                    0x0C05, 0x0C0C,
                    0x0C0E, 0x0C10,
                    0x0C12, 0x0C28,
                    0x0C2A, 0x0C33,
                    0x0C35, 0x0C39,
                    0x0C3D, 0x0C44,
                    0x0C46, 0x0C48,
                    0x0C4A, 0x0C4D,
                    0x0C55, 0x0C56,
                    0x0C58, 0x0C59,
                    0x0C60, 0x0C63,
                    0x0C66, 0x0C6F,
                    0x0C78, 0x0C7F ] ],
      "th":  [ { "lang": "th" },
               [ 2, 0x0E01, 0x0E3A ],
               [ 2, 0x0E3F, 0x0E5B ] ],
      "tr":  [ { "lang": "tr" },
               [ -32, "Â Ə Ç Ğ Gʻ Î İ Ñ Ň Oʻ Ş Û Ý Ž",
                      "â ə ç ğ gʻ î ı ñ ň oʻ ş û ý ž" ] ],
      "vi":  [ { "lang": "vi" },
               [ 1, "ÀàẢảÁáẠạÃãĂăẰằẲẳẴẵẮắẶặÂâẦầẨẩẪẫẤấẬậ",
                    "Đđ",
                    "ÈèẺẻẼẽÉéẸẹÊêỀềỂểỄễẾếỆệ",
                    "ỈỉĨĩÍíỊịÌì",
                    "ỎỏÓóỌọÒòÕõÔôỒồỔổỖỗỐốỘộƠơỜờỞởỠỡỚớỢợ",
                    "ÙùỦủŨũÚúỤụƯưỪừỬửỮữỨứỰự",
                    "ỲỳỶỷỸỹỴỵÝý" ] ],
      "wen": [ { "lang": "wen" },
               [ 1, "ČčĆć죳ńóř੹ŚśŽžŹź" ] ],
      // ISO 15924
      "Khmr": [ null,   // Khmer
                [ 2, 0x1780, 0x17DD ],
                [ 2, 0x17E0, 0x17E9 ],
                [ 2, 0x17F0, 0x17F9 ] ],
      "Phli": [ { "dir": "rtl",   // Pahlavi
                  "font-family": "ZH Mono" },
                [ 2, 0x10B60, 0x10B72 ],
                [ 2, 0x10B78, 0x10B7F ] ],
      "Prti": [ { "dir": "rtl",   // Parthian
                  "font-family": "ZH Mono" },
                [ 2, 0x10B40, 0x10B55 ],
                [ 2, 0x10B58, 0x10B5F ] ],
      "Xsux": [ { "font-family":   // Cuneiform
                     "Akkadian, CuneiformComposite, Free Idg Serif" },
                [ 2, 0x12000, 0x1236F ],
                [ 2, 0x12400, 0x12462 ],
                [ 2, 0x12470, 0x12473 ] ],
      // Others
      "AHD":    [ null,
                  [ 1, "āăäâēĕīĭîōŏôŭ" ],
                  false,
                  [ [ "o͞o", "", "", "food" ],
                    [ "o͝o", "", "", "foot" ] ] ],
      "Cyril":  [ null,
                  [ 1,
                    "АӘБВГҐЃҒДЂЕЄЁЖЗЅИІЇİЙӢЈКЌҚЛЉМНЊҢОӨПРСТЋУЎӮ"
                    + "ҰҮФХҲҺЦЧҶЏШЩЪЫЬЭЮЯ",
                    "аәбвгґѓғдђеєёжзѕиіїйӣјкќқлљмнњңоөпрстћуўӯ"
                    + "ұүфхҳһцчҷџшщъыьэюя" ] ],
      "DMG":    [ null,
                  [ 1, "ʾʿĀāČčḌḍḎḏǦǧĠġḤḥḪḫĪīḷŋṢṣS̱s̱ŠšṬṭṮṯŪūẒẓẔẕŽžŻż" ] ],
      "Finance":[ null,
                  [ 1, "‰", "₳฿₵¢₡₢$₫₯€₠₣ƒ₴₭₤ℳ₥₦№₧₰£៛₨₪৳₮₩¥" ],
                  [ [ "¤", "", "", "unspecified currency" ] ],
                  [ 1, "©®™", "§" ] ],
      "IPA":    [ { "class": "IPA" },
                  [ -32, "p t̪ t ʈ c k q ʡ ʔ",
                         "b d̪ d ɖ ɟ ɡ ɢ",
                         "ɓ ɗ ʄ ɠ ʛ",
                         "t͡s t͡ʃ t͡ɕ d͡z d͡ʒ d͡ʑ",
                         "ɸ f θ s ʃ ʅ ʆ ʂ ɕ ç ɧ x χ ħ ʜ h",
                         "β v ʍ ð z ʒ ʓ ʐ ʑ ʝ ɣ ʁ ʕ ʖ ʢ ɦ",
                         "ɬ ɮ",
                         "m m̩ ɱ ɱ̩ ɱ̍ n̪ n̪̍ n n̩ ɳ ɳ̩ ɲ ɲ̩ ŋ ŋ̍ ŋ̩ ɴ ",
                         "ɴ̩ ʙ ʙ̩ r r̩ ʀ ʀ̩",
                         "ɾ ɽ ɿ ɺ",
                         "l̪ l̪̩ l l̩ ɫ ɫ̩ ɭ ɭ̩ ʎ ʎ̩ ʟ ʟ̩",
                         "w ɥ ʋ ɹ ɻ j ɰ",
                         "ʘ ǂ ǀ ǃ ǁ",
                         "ʰ ʱ ʷ ʸ ʲ ʳ ⁿ ˡ ʴ ʵ ˢ ˣ ˠ ʶ ˤ ˁ ˀ ʼ",
                         "i i̯ ĩ y y̯ ỹ ɪ ɪ̯ ɪ̃ ʏ ʏ̯ ʏ̃ ɨ ɨ̯ ɨ̃ ʉ ʉ̯ ʉ̃ "
                         + "ɯ ɯ̯ ɯ̃ u u̯ ũ ʊ ʊ̯ ʊ̃",
                         "e e̯ ẽ ø ø̯ ø̃ ɘ ɘ̯ ɘ̃ ɵ ɵ̯ ɵ̃ ɤ ɤ̯ ɤ̃ o o̯ õ",
                         "ɛ ɛ̯ ɛ̃ œ œ̯ œ̃ ɜ ɜ̯ ɜ̃ ə ə̯ ə̃ ɞ ɞ̯ ɞ̃ ʌ ʌ̯ "
                         + "ʌ̃ ɔ ɔ̯ ɔ̃",
                         "æ æ̯ æ̃ ɶ ɶ̯ ɶ̃ a a̯ ã "
                         + "ɐ ɐ̯ ɐ̃ ɑ ɑ̯ ɑ̃ ɒ ɒ̯ ɒ̃",
                         "ˈ ˌ ː ˑ ˘ . ‿ | ‖" ] ],
      "KhmrSy": [ null,   // Khmer lunatics
                  [ 2, 0x19E0, 0x19FF ] ],
      "Latin":  [ null,
                  [ -32, "Á á Ć ć É é Í í Ó ó Ś ś Ú ú Ý ý Ǿ ǿ",
                         "À à È è Ì ì Ò ò Ù ù",
                         "Â â Ĉ ĉ Ê ê Ĝ ĝ Ĥ ĥ Î î Ĵ ĵ Ô ô ŝ Ŝ Û û",
                         "Ä ä Ë ë Ï ï Ö ö Ü ü ÿ",
                         "Ã ã Ñ ñ Õ õ",
                         "Å å",
                         "Ç ç",
                         "Č č Š š ŭ",
                         "Ł ł",
                         "Ő ő Ű ű",
                         "Ø ø",
                         "Ā ā Ē ē Ī ī Ō ō Ū ū Ȳ ȳ",
                         "Ă ă Ĕ ĕ Ğ ğ Ĭ ĭ Ŏ ŏ Ŭ ŭ Y̆ y̆" ,
                         "ß",
                         "Æ æ Œ œ",
                         "Ð ð Þ þ |" ] ],
      "Pinyin": [ null,
                  [ 1, "ÁáÀàǍǎĀāÉéÈèĚěĒēÍíÌìǏǐĪī"
                       + "ÓóÒòǑǒŌōÚúÙùÜüǓǔŪūǗǘǛǜǙǚǕǖ" ] ],
      "Scand":  [ null,
                  [ 1, "ÀàÉéÅåÆæÄäØøÖö", "ÐðÍíÓóÚúÝýÞþǫ" ] ],
      "TeX":    [ null,
                  [ [ "<math>", "</math>" ],
                    [ "{,}",        "",      "", "comma {,}","," ],
                    "\\",
                    [ "{", "}" ],
                    "^",
                    [ "\\cdot",     "",      "", "cdot",     "·" ],
                    [ "\\times",    "",      "", "times",    "×" ],
                    [ "\\pm",       "",      "", "pm",       "±" ],
                    [ "\\mp",       "",      "", "mp",       "∓" ],
                    [ "\\sum{",     "}",     "", "sum{}",    "Σ" ],
                    [ "\\frac{",    "}{}",   "", "frac{}{}", "—" ],
                    [ "\\sqrt{",    "}",     "", "sqrt{}",   "√" ],
                    [ "\\sqrt[n]{", "}",     "", "sqrt[n]{}","ⁿ√" ],
                    [ "\\leq",      "",      "", "leq",      "≤" ],
                    [ "\\geq",      "",      "", "geq",      "≥" ],
                    [ "\\approx",   "",      "", "approx",   "≈" ],
                    [ "\\ne",       "",      "", "ne",       "≠" ],
                    [ "\\circ",     "",      "", "circ",     "°" ],
                    [ "\\pi",       "",      "", "",         "π" ],
                    [ "\\infty",    "",      "", "infty",    "∞" ],
                    [ "\\cup",      "",      "", "cup",      "∪" ],
                    [ "\\cap",      "",      "", "cap",      "∩" ],
                    [ "\\angle",    "",      "", "angle",    "∠" ],
                    [ "\\underline","",      "", "underline","_" ],
                    [ "\\overline", "",      "", "overline", "¯" ],
                    [ "\\begin",    "\\end", "", "",       "begin…end" ],
                    [ "\\!\\,",     "",      "", "space\\!\\,","SPC" ],
                    [ "\\{",        "",      "", "",         "{" ],
                    [ "\\}",        "",      "", "",         "}" ] ] ],
      "TeX_ar": [ null,
                  [ [ "\\leftarrow",        "","","leftarrow",     "←" ],
                    [ "\\leftrightarrow",   "","","leftrightarrow","↔" ],
                    [ "\\rightarrow",       "","","rightarrow",    "→" ],
                    [ "\\Leftarrow",        "","","Leftarrow",     "⇐" ],
                    [ "\\Leftrightarrow",   "","","Leftrightarrow","⇔" ],
                    [ "\\Rightarrow",       "","","Rightarrow",    "⇒" ],
                    [ "\\uparrow",          "","","uparrow",       "↑" ],
                    [ "\\updownarrow",      "","","updownarrow",   "↕" ],
                    [ "\\downarrow",        "","","downarrow",     "↓" ],
                    [ "\\Uparrow",          "","","Downarrow",     "⇑" ],
                    [ "\\Updownarrow",      "","","Updownarrow",   "⇕" ],
                    [ "\\Downarrow",        "","","Downarrow",     "⇓" ],
                    [ "\\nearrow",          "","","nearrow",       "↗" ],
                    [ "\\searrow",          "","","searrow",       "↘" ],
                    [ "\\swarrow",          "","","swarrow",       "↙" ],
                    [ "\\nwarrow",          "","","nwarrow",       "↖" ],
                    ["\\leftrightarrows",  "","","leftrightarrows","⇆" ],
                    ["\\updownarrow ",     "","","updownarrow ",   "⇅" ],
                    ["\\rightleftarrows",  "","","rightleftarrows","⇄"]],
                  [["\\leftrightharpoons","","","leftrightharpoons","⇋"],
                   ["\\rightleftharpoons","","","rightleftharpoons","⇌"],
                    ["\\leftharpoondown", "","","leftharpoondown", "↽"],
                    ["\\rightharpoondown","","","rightharpoondown","⇁"],
                    ["\\leftharpoonup",   "","","leftharpoonup",   "↼"],
                    ["\\rightharpoonup",  "","","rightharpoonup",  "⇀"],
                    ["\\upharpoonleft",   "","","upharpoonleft",   "↿"],
                    ["\\upharpoonright",  "","","upharpoonright",  "↾"],
                    ["\\downharpoonleft", "","","downharpoonleft", "⇃"],
                    ["\\downharpoonright","","","downharpoonright","⇂"]],
                  [ ["\\circlearrowleft", "","","circlearrowleft", "↺"],
                    ["\\circlearrowright","","","circlearrowright","↻"],
                    ["\\curvearrowleft",  "","","curvearrowleft",  "↶"],
                    ["\\curvearrowright", "","","curvearrowright", "↷"],
                    ["\\hookleftarrow",   "","","hookleftarrow",   "↩"],
                    ["\\hookrightarrow",  "","","hookrightarrow",  "↪"],
                    ["\\looparrowleft",   "","","looparrowleft",   "↫"],
                    ["\\looparrowright",  "","","looparrowright",  "↬"],
              ["\\leftrightsquigarrow","","","leftrightsquigarrow","↭"]],
                  [ [ "\\rightmapsto",    "", "","rightmapsto",  "↦" ],
                    [ "\\upmapsto",       "", "","upmapsto",     "↥" ],
                    [ "\\leftmapsto",     "", "","leftmapsto",   "↤" ],
                    [ "\\downmapsto",     "", "","downmapsto",   "↧" ] ],
                  [ [ "\\Lsh",            "", "", "Lsh",         "↰" ],
                    [ "\\Rsh",            "", "", "Rsh",         "↱" ],
                    [ "\\dlsh",           "", "", "dlsh",        "↲" ],
                    [ "\\drsh",           "", "", "drsh",        "↳" ] ],
                  [ [ "\\nleftrightarrow","","","nleftrightarrow","↮" ],
                    [ "\\nleftarrow",     "","","nleftarrow",     "↚" ],
                    [ "\\nrightarrow",    "","","nrightarrow",    "↛" ],
                    [ "\\nLeftrightarrow","","","nLeftrightarrow","⇎" ],
                    [ "\\nLeftarrow",     "","","nLeftarrow",     "⇍" ],
                    [ "\\nRightarrow",    "","","nRightarrow",    "⇏"]]],
      "TeX_bi": [ null,
                  [ [ "\\leq",         "", "", "leq",          "≤" ],
                    [ "\\geq",         "", "", "geq",          "≥" ],
                    [ "\\propto",      "", "", "propto",       "∝" ],
                    [ "\\neq",         "", "", "neq",          "≠" ],
                    [ "\\equiv",       "", "", "equiv",        "≡" ],
                    [ "\\ll",          "", "", "ll",           "≪" ],
                    [ "\\gg",          "", "", "gg",           "≫" ],
                    [ "\\simeq ",      "", "", "simeq ",       "≃" ],
                    [ "\\cong",        "", "", "cong",         "≅" ],
                    [ "\\approx",      "", "", "approx",       "≈" ],
                    [ "\\triangleq",   "", "", "triangleq",    "≜" ],
                    [ "\\doteq",       "", "", "doteq",        "≐" ],
                    [ "\\stackrel{\\mathrm{def}}","=def","","","≝" ] ],
                  [ [ "\\neg",         "", "", "neg",          "↦" ],
                    [ "\\wedge",       "", "", "wedge",        "∧" ],
                    [ "\\vee",         "", "", "vee",          "∨" ],
                    [ "\\veebar",      "", "", "veebar",       "⊻" ],
                    [ "\\therefore",   "", "", "therefore",    "∴" ],
                    [ "\\because",     "", "", "because",      "∵" ],
                    [ "\\forall",      "", "", "forall",       "∀" ],
                    [ "\\exists",      "", "", "exists",       "∃" ] ],
                  [ [ "\\in",          "", "", "in",           "∈" ],
                    [ "\\nowns",       "", "", "nowns",        "∉" ],
                    [ "\\ni",          "", "", "ni",           "∋" ],
                    [ "\\emptyset",    "", "", "emptyset",     "∅" ],
                    [ "\\cup",         "", "", "cup",          "∪" ],
                    [ "\\cap",         "", "", "cap",          "∩" ],
                    [ "\\subset",      "", "", "subset",       "⊂" ],
                    [ "\\nsubset",     "", "", "nsubset",      "⊄" ],
                    [ "\\subseteq",    "", "", "subseteq",     "⊆" ],
                    [ "\\nsubseteq",   "", "", "nsubseteq",    "⊈" ],
                    [ "\\subsetneq",   "", "", "subsetneq",    "⊊" ],
                    [ "\\supset",      "", "", "supset",       "⊃" ],
                    [ "\\nsupset",     "", "", "nsupset",      "⊅" ],
                    [ "\\subseteq",    "", "", "subseteq",     "⊇" ],
                    [ "\\nsupseteq",   "", "", "nsupseteq",    "⊉" ],
                    [ "\\supsetneq",   "", "", "supsetneq",    "⊋" ] ],
                  [ [ "\\centerdot",   "", "", "centerdot",    "⋅" ],
                    [ "\\ast",         "", "", "ast",          "∗" ],
                    [ "\\circ",        "", "", "circ",         "∘" ],
                    [ "\\oplus",       "", "", "oplus",        "⊕" ],
                    [ "\\otimes",      "", "", "otimes",       "⊗" ],
                    [ "\\square",      "", "", "square",       "□" ],
                    [ "\\nmid",        "", "", "nmid",         "∤" ],
                    [ "\\rightmapsto", "", "", "rightmapsto",  "↦" ],
                    [ "\\wr",          "", "", "wr",           "≀" ],
                    [ "\\triangleleft","", "", "triangleleft", "◅" ],
                    [ "\\triangleright","","", "triangleright","▻" ],
                    [ "\\ltimes",      "", "", "ltimes",       "⋉" ],
                    [ "\\rtimes",      "", "", "rtimes",       "⋊" ],
                    [ "\\bowtie",      "", "", "bowtie",       "⋈" ] ],
                  [ [ "\\vdash",       "", "", "vdash",        "⊢" ],
                    [ "\\dashv",       "", "", "dashv",        "⊣" ],
                    [ "\\intercal",    "", "", "intercal",     "⊤" ],
                    [ "\\perp",        "", "", "perp",         "⊥" ],
                    [ "\\models",      "", "", "models",       "⊧" ] ] ],
      "TeX_di": [ null,
                  [ [ "\\sum_{i=0}^N",  "", "", "sum_{i=0}^N", "∑" ],
                    [ "\\prod_{i=0}^N", "", "", "prod_{i=0}^N","∏" ],
                    [ "\\coprod",       "", "", "coprod",      "∐" ] ],
                  [ [ "\\lfloor",       "", "", "lfloor",      "⌊" ],
                    [ "\\rfloor",       "", "", "rfloor",      "⌋" ],
                    [ "\\lceil",        "", "", "lceil",       "⌈" ],
                    [ "\\rceil",        "", "", "rceil",       "⌉" ] ],
                  [ [ "\\prime",        "", "", "prime",       "′" ],
                    [ "\\int_{-N}^N",   "", "", "int",         "∫" ],
                    [ "\\iint",         "", "", "iint",        "∬" ],
                    [ "\\iiint",        "", "", "iiint",       "∭" ],
                    [ "\\oint_c",       "", "", "oint_c",      "∮" ],
                    [ "\\partial",      "", "", "partial",     "∂" ],
                    [ "\\Delta",        "", "", "Delta",       "∆" ],
                    [ "\\nabla",        "", "", "nabla",       "∇" ] ],
                  [ [ "\\Complex",      "", "", "Complex",     "ℂ" ],
                    [ "\\mathbb{H}",    "", "", "mathbb{H}",   "ℍ" ],
                    [ "\\Natural",      "", "", "Natural",     "ℕ" ],
                    [ "\\mathbb{P}",    "", "", "mathbb{P}",   "ℙ" ],
                    [ "\\Rational",     "", "", "Rational",    "ℚ" ],
                    [ "\\Real",         "", "", "Real",        "ℝ" ],
                    [ "\\Integer",      "", "", "Integer",     "ℤ" ],
                    [ "\\aleph",        "", "", "aleph",       "ℵ" ] ] ],
      "TeX_gr": [ null,
                  [ [ "\\alpha",   "", "", "", "α" ],
                    [ "\\beta",    "", "", "", "β" ],
                    [ "\\gamma",   "", "", "", "γ" ],
                    [ "\\delta",   "", "", "", "δ" ],
                    [ "\\epsilon", "", "", "", "ε" ],
                    [ "\\zeta",    "", "", "", "ζ" ],
                    [ "\\eta",     "", "", "", "η" ],
                    [ "\\theta",   "", "", "", "θ" ],
                    [ "\\iota",    "", "", "", "ι" ],
                    [ "\\kappa",   "", "", "", "κ" ],
                    [ "\\lambda",  "", "", "", "λ" ],
                    [ "\\mu",      "", "", "", "μ" ],
                    [ "\\nu",      "", "", "", "ν" ],
                    [ "\\xi",      "", "", "", "ξ" ],
                    [ "\\omicron", "", "", "", "ο" ],
                    [ "\\pi",      "", "", "", "π" ],
                    [ "\\rho",     "", "", "", "ρ" ],
                    [ "\\sigma",   "", "", "", "σ" ],
                    [ "\\tau",     "", "", "", "ς" ],
                    [ "\\upsilon", "", "", "", "τ" ],
                    [ "\\phi",     "", "", "", "υ" ],
                    [ "\\chi",     "", "", "", "φ" ],
                    [ "\\psi",     "", "", "", "χ" ],
                    [ "\\omega",   "", "", "", "ψ" ] ],
                  [ [ "\\Alpha",   "", "", "", "Α" ],
                    [ "\\Beta",    "", "", "", "Β" ],
                    [ "\\Gamma",   "", "", "", "Γ" ],
                    [ "\\Delta",   "", "", "", "Δ" ],
                    [ "\\Epsilon", "", "", "", "Ε" ],
                    [ "\\Zeta",    "", "", "", "Ζ" ],
                    [ "\\Eta",     "", "", "", "Η" ],
                    [ "\\Theta",   "", "", "", "Θ" ],
                    [ "\\Iota",    "", "", "", "Ι" ],
                    [ "\\Kappa",   "", "", "", "Κ" ],
                    [ "\\Lambda",  "", "", "", "Λ" ],
                    [ "\\Mu",      "", "", "", "Μ" ],
                    [ "\\Nu",      "", "", "", "Ν" ],
                    [ "\\Xi",      "", "", "", "Ξ" ],
                    [ "\\Omicron", "", "", "", "Ο" ],
                    [ "\\Pi",      "", "", "", "Π" ],
                    [ "\\Rho",     "", "", "", "Ρ" ],
                    [ "\\Sigma",   "", "", "", "Σ" ],
                    [ "\\Tau",     "", "", "", "Τ" ],
                    [ "\\Upsilon", "", "", "", "Υ" ],
                    [ "\\Phi",     "", "", "", "Φ" ],
                    [ "\\Chi",     "", "", "", "Χ" ],
                    [ "\\Psi",     "", "", "", "Ψ" ],
                    [ "\\Omega",   "", "", "", "Ω" ] ],
                  [ 0, "<br />var: " ],
                  [ [ "\\varepsilon", "", "", "", "ε" ],
                    [ "\\vartheta",   "", "", "", "θ" ],
                    [ "\\varkappa",   "", "", "", "κ" ],
                    [ "\\varpi",      "", "", "", "π" ],
                    [ "\\varrho",     "", "", "", "ρ" ],
                    [ "\\varsigma",   "", "", "", "σ" ],
                    [ "\\varphi",     "", "", "", "υ" ] ] ],
      "TeX_tx": [ null,
                  [ [ "\\mbox",         "",  "", "", "mbox" ],
                    [ "\\text",         "",  "", "", "text" ],
                    [ "\\displaystyle", "",  "", "", "displaystyle" ],
                    [ "\\textstyle",    "",  "", "", "textstyle" ],
                    [ "\\boldsymbol{",  "}", "", "","boldsymbol" ],
                    [ "\\mathit{",      "}", "", "italic", "mathit" ],
                    [ "\\mathrm{",      "}", "", "roman", "mathrm" ],
                    [ "\\mathsf{",      "}", "", "sans serif","mathsf" ],
                    [ "\\color{",       "}", "", "", "color" ] ] ]
   };   // .defs.global
   ETSI.defs.global.IPA_T =
               ETSI.defs.global.IPA.concat( [ [ [ "{{IPA|", "}}" ] ] ] );



// No customization recommended beyond this point.



   function fiat() {
      // Perform update; furnish entire list and model once again
      // Precondition:
      //    GUI environment available
      //    document ready
      // Postcondition:
      //    Gadget equipped
      // Uses:
      //    >  .gui.builder
      //    >  .defs.opts
      //    >  .vsn
      //    >  .gui.self
      //    >  .gui.hintList
      //    >  .gui.hintMenu
      //    >< .gui.$container
      //     < .gui.$wrapper
      //     < .gui.$gadget
      //     < .gui.$menu
      //    .gui.fiat()
      //    .factory()
      //    .gui.favour()
      //    .gui.focus()
      //    .gui.facet()
      // 2017-06-01 PerfektesChaos@de.wikipedia
      var later = ( ETSI.gui.$container ? true : false ),
          i,
          multi,
          n,
          $opt,
          $sep;
      if ( ETSI.gui.builder ) {
         ETSI.gui.fiat();
      }
      ETSI.gui.$container = $( ETSI.gui.container );
      multi               = ETSI.gui.$container.length;
      if ( multi ) {
         ETSI.gui.$container.remove( "." + ETSI.gui.self );// each
         ETSI.factory();
         ETSI.gui.favour();
         if ( ETSI.defs.opts ) {
            n    = ETSI.defs.opts.length;
            $sep = $( "<span> </span>" );
            if ( ! later ) {
               ETSI.gui.focus();
            }
            ETSI.gui.$wrapper = $( "<div />" );
            ETSI.gui.$wrapper.attr( "class", ETSI.gui.self );
            ETSI.gui.$gadget = $( "<select>" );
            ETSI.gui.$gadget.attr( "class",  ETSI.gui.self + "-gadget" );
            if ( ETSI.gui.hintList ) {
               ETSI.gui.$gadget.attr( "title",
                                      ETSI.gui.hintList /** + x **/ );
            }
            ETSI.gui.$gadget.change( ETSI.gui.facet )
                            .keyup( ETSI.gui.facet );
            for ( i = 0;  i < n;  i++ ) {
               $opt = $( "<option>" );
               $opt.attr( "value", i )
                   .text( ETSI.defs.opts[ i ][ 3 ] );
               ETSI.gui.$gadget.append( $opt );
            }   // for i
            ETSI.gui.$wrapper.append( ETSI.gui.$gadget )
                             .append( $sep );
            ETSI.gui.$menu = $( "<div>" );
            ETSI.gui.$menu.attr( "class",  ETSI.gui.self + "-menu" )
                          .css( "display", "inline" );
            if ( ETSI.gui.hintMenu ) {
               ETSI.gui.$menu.attr( "title", ETSI.gui.hintMenu );
            }
            ETSI.gui.$wrapper.append( ETSI.gui.$menu );
            ETSI.gui.facet( false );
            for ( i = 1;  i < multi;  i++ ) {
               ETSI.gui.$container.eq( i )
                                   .prepend( ETSI.gui.$wrapper.clone() );
            }   // for i
            ETSI.gui.$container.first().prepend( ETSI.gui.$wrapper );
            ETSI.gui.$container.show();
         }
      }
   }   // fiat()



   function fire() {
      // Initialize on load of document, or update
      // Precondition:
      //    document ready
      // Uses:
      //     < .listen
      //    fiat()
      // 2017-06-06 PerfektesChaos@de.wikipedia
      ETSI.listen = true;
      fiat();
   }   // fire()



   function fired() {
      // Initialize on load of codes, or update
      // Uses:
      //    >  .listen
      //     < .loaded
      //    fiat()
      //    (fire)
      // 2017-06-06 PerfektesChaos@de.wikipedia
      if ( ETSI.listen ) {
         fiat();
      } else {
         $( fire );
      }
      ETSI.loaded = true;
   }   // fired()



   ETSI.attr.fetch = function ( access ) {
      // Retrieve attribute value from definition and user customization
      // Precondition:
      //    access  -- definition item
      // Uses:
      //    >< .attr.current
      // 2011-10-27 PerfektesChaos@de.wikipedia
      var d = access[ 0 ],
          s,
          v;
      if ( d ) {
         for ( v in this.current ) {
            if ( ! this.current[ v ] ) {
               s = d[ v ];
               if ( typeof s === "string" ) {
                  this.current[ v ] = s;
               }
            }
         }   // for v in .current
      }
   };   // .attr.fetch()



   ETSI.attr.fit = function ( attempt ) {
      // Does definition element match requirements for a valid attr?
      // Precondition:
      //    attempt  -- item
      // Postcondition:
      //    Returns true if is valid attr
      // Uses:
      //    >  .attr.names
      // 2011-10-27 PerfektesChaos@de.wikipedia
      var r = false,
          v;
      if ( attempt ) {
         for ( v in this.names ) {
            if ( typeof attempt[ v ] === "string" ) {
               r = true;
               break;   // for v in .names
            }
         }   // for v in .names
      } else {
         r = true;
      }
      return r;
   };   // .attr.fit()



   ETSI.attr.furnish = function ( assign, acquire, applied ) {
      // Equip menu with attributes
      // Precondition:
      //    assign   -- jQuery menu to be extended
      //    acquire  -- ID of requested content definition
      //    applied  -- definition element which provided menu content
      // Postcondition:
      //    Menu attributed by cascading properties, if any.
      // Uses:
      //    >  .attr.names
      //    >  .defs.current
      //     < .attr.current
      //    .attr.fetch()
      // 2011-11-26 PerfektesChaos@de.wikipedia
      var n = ETSI.defs.current.length,
          d,
          i,
          q,
          v;
      this.current = { };
      for ( v in this.names ) {
         this.current[ v ] = false;
      }   // for v in attr.names
      this.current.dir = "ltr";
      for ( i = 0;  i < n;  i++ ) {
         q = ETSI.defs.current[ i ];
         d = q[ 1 ].defs;
         if ( typeof d === "object" ) {
            d = d[ acquire ];
            if ( typeof d === "object" ) {
               this.fetch( d );
            }
         }
         if ( q[ 0 ]  ===  applied ) {
            break;   // for i
         }
      }   // for i
      for ( v in this.current ) {
         d = this.current[ v ];
         if ( d ) {
            if ( this.names[ v ] ) {
               assign.css( v, d );
            } else {
               assign.attr( v, d );
            }
         }
      }   // for v in attr.current
   };   // .attr.furnish()



   ETSI.defs.factory = function () {
      // Build data model from project and user spec
      // Postcondition:
      //    .defs.current has been built in current environment
      // Uses:
      //    >  .user
      //    >  .user.lang
      //    >  .project
      //    >  .l10n
      //    >  .lang
      //     < .defs.current
      //     < .defs.lead
      //    .defs.found()
      //    mw.config.get()
      //    .defs.fluent()
      //    .defs.features()
      // 2011-11-26 PerfektesChaos@de.wikipedia
      var scope = false,
          shift = false,
          slang = false,
          o,
          p;
      this.current = [ ];
      if ( typeof ETSI.user === "object" ) {
         o = this.found( "user", ETSI.user );
         if ( o ) {
            p = o.lang;
            if ( typeof p === "string" ) {
               if ( p.length ) {
                  shift = p;
               }
            }
            if ( typeof o.custom === "object" ) {
               this.lead = true;
            }
         }
      }
      if ( typeof ETSI.project === "string" ) {
         if ( ETSI.project.length ) {
            scope = ETSI.project;
         }
      }
      if ( ! scope ) {
         scope = mw.config.get( "wgDBname" );
      }
      this.found( "db", scope );
      p = scope.search( /wik[it].+$/ );
      if ( p > 0 ) {
         this.found( "project",  scope.substr( p ) );
      }
      if ( typeof ETSI.lang === "string" ) {
         if ( ETSI.lang.length ) {
            slang = ETSI.lang;
         }
      }
      if ( typeof slang !== "string" ) {
         slang = mw.config.get( "wgContentLanguage" );
      }
      p = this.fluent( slang, "projlang", "projsub", false );
      if ( typeof shift !== "string" ) {
         shift = mw.config.get( "wgUserLanguage" ).toLowerCase();
      }
      p = this.fluent( shift, "language", "dialect", p );
      this.features();
      this.current.push( [ "global",  { "defs": this.global } ] );
      this.fluent( "en", "fallback", false, p );
   };   // .defs.factory()



   ETSI.defs.fade = function ( access ) {
      // Remove an an option definition from standard options
      // Precondition:
      //    access  -- ID of definition
      // Postcondition:
      //    .defs.opts is updated
      // Uses:
      //    >< .defs.opts
      // 2011-11-23 PerfektesChaos@de.wikipedia
      var d,
          i,
          n;
      if ( access ) {
         n = this.opts.length;
         for ( i = 0;  i < n;  i++ ) {
            d = this.opts[ i ];
            if ( d[ 0 ]  ===  access ) {
               this.opts.splice( i, 1 );
               break;   // for i
            }
         }   // for i
      }
   };   // .defs.fade()



   ETSI.defs.fair = function () {
      // Check standard list, reduce to valid items and build options
      // Uses:
      //    >< .defs.tmp
      //    >< .defs.opts
      //    .defs.finder()
      // 2011-11-23 PerfektesChaos@de.wikipedia
      var n    = this.tmp.length / 2,
          d,
          i,
          j,
          say,
          seek;
      for ( i = 0;  i < n;  i++ ) {
         j    = i + i;
         seek = this.tmp[ j ];
         say  = this.tmp[ j + 1 ];
         if ( typeof say === "string"  &&
              typeof seek === "string" ) {
            if ( say.length ) {
               d = this.finder( seek );
               if ( d ) {
                  d = d.concat( [ say, false ] );
                  if ( this.opts ) {
                     this.opts.push( d );
                  } else {
                     this.opts = [ d ];
                  }
               }
            }
         }
      }   // for i
      delete this.tmp;
   };   // .defs.fair()



   ETSI.defs.features = function () {
      // Assign project and user settings
      // Precondition:
      //    defs.current is filled with user and l10n objects
      // Postcondition:
      //    Cascading settings performed
      // Uses:
      //    >  .defs.current
      //    .set()
      // 2011-11-26 PerfektesChaos@de.wikipedia
      var n = this.current.length - 1,
          c,
          i,
          p;
      for ( i = n;  i >= 0;  i-- ) {
         c = this.current[ i ][ 1 ].config;
         if ( typeof c === "object" ) {
            for ( p in c ) {
               ETSI.set( p,  c[ p ] );
            }   // for p in c
         }
      }   // for i--
   };   // .defs.features()



   ETSI.defs.filter = function () {
      // Remove situation dependent list items
      // Postcondition:
      //    Standard list has been reduced if appropriate
      // Uses:
      //    >< .defs.opts
      //    >< .defs.reNS
      // 2011-11-23 PerfektesChaos@de.wikipedia
      var n = this.opts.length,
          i,
          s;
      for ( i = n - 1;  i >= 0;  i-- ) {
         s = this.opts[ i ][ 0 ];
         if ( typeof s === "string" ) {
            switch ( s.charCodeAt( 0 ) ) {
               case 47 :   // '/' project type
                  // TODO
                  break;
               case 58 :   // ':' namespace
                  if ( ! this.reNS ) {
                     this.reNS = "^:"
                                   + mw.config.get( "wgNamespaceNumber" )
                                   + "(_.*)?$";
                     this.reNS = new RegExp( this.reNS, "" );
                  }
                  if ( ! this.reNS.test( s ) ) {
                     this.opts.splice( i, 1 );
                     n--;
                  }
                  break;
            }   // switch charCodeAt
         }
      }   // for i--
      if ( ! n ) {
         this.opts = false;
      }
   };   // .defs.filter()



   ETSI.defs.find = function ( access, alike ) {
      // Find property within objects in current environment
      // Precondition:
      //    access  -- name of property
      //    alike   -- type of property
      // Postcondition:
      //    Returns not-empty value,  or false if not found
      // Uses:
      //    >  .defs.current
      // 2011-11-23 PerfektesChaos@de.wikipedia
      var n = this.current.length,
          r = false,
          i,
          p;
      for ( i = 0;  i < n;  i++ ) {
         p = this.current[ i ][ 1 ][ access ];
         if ( typeof p  ===  alike ) {
            if ( p ) {
               r = p;
               break;   // for i
            }
         }
      }   // for i
      return r;
   };   // .defs.find()



   ETSI.defs.finder = function ( acquire ) {
      // Find content definition within current environment
      // Precondition:
      //    acquire  -- ID of requested content definition
      // Postcondition:
      //    Returns false if not found, or
      //            Array(3):  [0] ID,  [1] definition,  [2] origin
      // Uses:
      //    >  .defs.current
      // 2011-11-23 PerfektesChaos@de.wikipedia
      var n = this.current.length,
          d,
          i,
          g,
          p,
          r = false;
      for ( i = 0;  i < n;  i++ ) {
         g = this.current[ i ];
         p = g[ 1 ].defs;
         if ( typeof p === "object" ) {
            d = p[ acquire ];
            if ( typeof d === "object" ) {
               if ( d.length > 1 ) {
                  r = [ acquire,  d,  g[ 0 ] ];
                  break;   // for i
               }
            }
         }
      }   // for i
      return r;
   };   // .defs.finder()



   ETSI.defs.fluent = function ( assign, appoint, another, already ) {
      // Build data model with respect to language
      // Precondition:
      //    assign   -- string: code of language (ISO 639)
      //    appoint  -- string: id of language in current data model
      //    another  -- string: id of dialect in data model
      //    already  -- Array(2) of known items, or false if not yet set
      // Postcondition:
      //    Returns Array(2) of items, or false if not set
      // Uses:
      //    .defs.found()
      // 2011-10-27 PerfektesChaos@de.wikipedia
      var k     = assign.indexOf( "-" ),
          r     = ( already  ?  already  :  [ false, false ] ),
          slang = assign.toLowerCase(),
          s,
          sub;
      if ( k > 1 ) {
         s   = slang.substr( 0,  k - 1 );
         sub = s + "_"   +   slang.substr( 0,  k + 1 );
         if ( already ) {
            if ( already[0] === s ) {
               s = false;
            }
            if ( already[1] === sub ) {
               sub = false;
            }
         }
         if ( s ) {
            this.found( appoint, s );
         }
         if ( sub ) {
            this.found( another, sub );
         }
         r = [ s, sub ];
      } else {
         if ( already ) {
            if ( already[ 0 ]  ===  slang ) {
               slang = false;
            }
         }
         if ( slang ) {
            this.found( appoint, slang );
            r = [ slang, false ];
         }
      }
      return r;
   };   // .defs.fluent()



   ETSI.defs.format = function () {
      // Adjust all definitions in focus as canonical form definition
      // Postcondition:
      //    All definitions available in canonical form
      // Uses:
      //    this
      //    >  .defs.current
      //    .attr.fit()
      // 2011-11-23 PerfektesChaos@de.wikipedia
      var n = this.current.length,
          c,
          d,
          e,
          g,
          i,
          o,
          p;
      for ( i = 0;  i < n;  i++ ) {
         o = this.current[ i ][ 1 ];
         c = o.defs;
         if ( typeof c === "object" ) {
            if ( c ) {
               for ( e in c ) {
                  d = c[ e ];
                  if ( typeof d === "object" ) {
                     if ( ETSI.attr.fit( d ) ) {
                        c[ e ] = [ d ];
                     } else {
                        if ( $.isArray( d ) ) {
                           if ( ! ETSI.attr.fit( d[0] ) ) {
                              d.unshift( [ null ] );
                           }
                        } else {
                           p = d.atributes;
                           g = d.groups;
                           if ( p || g ) {
                              if ( ! p ) {
                                 p = null;
                              }
                              if ( g ) {
                                 c[ e ] = [ p,  { "groups": g } ];
                              } else {
                                 c[ e ] = [ p ];
                              }
                           } else {
                              d = false;
                           }
                        }
                     }
                  } else {
                     d = false;
                  }
                  if ( ! d ) {
                     delete c[ e ];
                  }
               }   // for e in c
            }
         } else {
            c = false;
         }
         if ( ! c ) {
            delete o.defs;
         }
      }   // for i
   };   // .defs.format()



   ETSI.defs.found = function ( appoint, assign ) {
      // Append data model item to current model, if valid
      // Precondition:
      //    appoint  -- string: id in current data model
      //    assign   -- string: id in .l10n.   object (direct access)
      // Postcondition:
      //    Returns object reference in data model
      // Uses:
      //    >  .l10n
      //     < .defs.current
      // 2011-11-23 PerfektesChaos@de.wikipedia
      var o = false,
          r = false;
      switch ( typeof assign ) {
         case "object" :
            o = assign;
            break;
         case "string" :
            o = ETSI.l10n[ assign ];
            break;
      }   // switch typeof assign
      if ( typeof o === "object" ) {
         if ( o ) {
            this.current.push( [ appoint, o ] );
            r = o;
         }
      }
      return r;
   };   // .defs.found()



   ETSI.defs.friend = function ( access ) {
      // Find option title within standard list
      // Precondition:
      //    access  -- ID of option
      // Postcondition:
      //    Returns false if not found, or title string
      // Uses:
      //    >  .defs.opts
      // 2011-11-23 PerfektesChaos@de.wikipedia
      var n = this.opts.length,
          i,
          o,
          r = false;
      for ( i = 0;  i < n;  i++ ) {
         o = this.opts[ i ];
         if ( o[ 0 ]  ===  access ) {
            r = o[ 3 ];
            break;
         }
      }   // for i
      return r;
   };   // .defs.friend()



   ETSI.defs.furnish = function () {
      // Customize standard list by heading elements and removing items
      // Precondition:
      //    Customization entry available
      //    Standard list in preprocessed form
      // Postcondition:
      //    Standard list has been updated
      // Uses:
      //    >  .user.custom
      //    >< .defs.opts
      //    .defs.finder()
      //    .defs.friend()
      //    .defs.fade()
      //    jQuery.isArray()
      //    .util.trimRight()
      // 2015-06-25 PerfektesChaos@de.wikipedia
      var i,
          j,
          n,
          opt,
          say,
          seek,
          temp;
      if ( typeof ETSI.user.custom === "object" ) {
         if ( $.isArray( ETSI.user.custom ) ) {
            n = ETSI.user.custom.length / 2;
            if ( n ) {
               temp = [ ];
               for ( i = 0;  i < n;  i++ ) {
                  j    = i + i;
                  seek = ETSI.user.custom[ j ];
                  if ( typeof seek === "string" ) {
                     if ( seek.length ) {
                        j++;
                        say = ETSI.user.custom[ j ];
                        if ( say ) {
                           opt = false;
                           if ( typeof say === "string" ) {
                              say = ETSI.util.trimRight( say );
                              if ( ! say.length ) {
                                 say = false;
                              }
                           } else {
                              say = this.friend( seek );
                              if ( typeof say !== "string" ) {
                                 say = "<" + seek + ">";
                              }
                           }
                           if ( say ) {
                              opt = this.finder( seek );
                              if ( opt ) {
                                 opt = opt.concat( [ say, false ] );
                                 temp.push( opt );
                              }
                           }
                        }
                        if ( seek !== "----" ) {
                           this.fade( seek );
                        }
                     }
                  }
               }   // for i
               if ( temp.length ) {
                  this.opts = temp.concat( this.opts );
               }
            }   // user.custom not empty
         }   // user.custom isArray
      }   // user.custom
   };   // .defs.furnish()



   ETSI.gui.facet = function ( action ) {
      // Display menu: initial selection or handle GUI event
      // Precondition:
      //    action  -- false:  initialization after setup
      //               object: GUI event
      // Uses:
      //    >  .gui.$gadget
      //    >  .gui.selection
      //    >  .gui.cookie
      //    >  .gui.$menu
      //    >  .defs.opts
      //    .gui.find()
      //    .menu.factory()
      // Remark: May be used as event handler -- 'this' is not accessed
      // 2017-05-31 PerfektesChaos@de.wikipedia
      var learn = ( typeof ETSI.gui.cookie === "string" ),
          k,
          s;
      if ( action ) {
         k = ETSI.gui.$gadget.prop( "value" );  // .attr -> prop
      } else {
         if ( typeof ETSI.gui.selection  ===  "string" ) {
            k = ETSI.gui.find( ETSI.gui.selection );
         } else {
            k = -1;
         }
         if ( k < 0 ) {
            if ( learn ) {
               if ( typeof window.sessionStorage  ===  "object" ) {
                  s = window.sessionStorage.getItem( ETSI.gui.cookie );
                  k = ETSI.gui.find( s );
               }
            }
         }
         ETSI.gui.$gadget.prop( "value", k );  // .attr -> prop
      }
      k = ( k < 0  ?  0  :  k );
      if ( ! ETSI.defs.opts[ k ][ 4 ] ) {
         ETSI.defs.opts[ k ][ 4 ]
                              = ETSI.menu.factory( ETSI.defs.opts[ k ] );
      }
      ETSI.gui.$menu.children().detach();
      ETSI.gui.$menu.append( ETSI.defs.opts[ k ][ 4 ] );
      if ( learn ) {
         if ( typeof window.sessionStorage  ===  "object" ) {
            try {
               window.sessionStorage.setItem( ETSI.gui.cookie,
                                              ETSI.defs.opts[ k ][ 0 ] );

            } catch ( e ) {
            }
         }
      }
   };   // .gui.facet()



   ETSI.gui.fasten = function ( around, arglist ) {
      // Trim selection
      // Precondition:
      //    around   -- selected text
      //    arglist  -- parameters for jQuery.textSelection
      // Postcondition:
      //    Returns trimmed selected text and extends arglist
      //    >< .gui.reWSbeg
      //     < .gui.reWSend
      // 2018-02-15 PerfektesChaos@de.wikipedia
      var r = around,
          got;
      if ( r ) {
         if ( typeof this.reWSbeg  !==  "object" ) {
            this.reWSbeg = new RegExp( "^\\s+" );
            this.reWSend = new RegExp( "\\S(\\s+)$" );
         }
         got = this.reWSbeg.exec( r );
         if ( got ) {
            if ( typeof arglist.pre  ===  "string" ) {
               arglist.pre = got[ 0 ] + arglist.pre;
            } else {
               arglist.pre = got[ 0 ];
            }
            r = r.substr( got[ 0 ].length );
         }
         got = this.reWSend.exec( r );
         if ( got ) {
            if ( typeof arglist.post  ===  "string" ) {
               arglist.post = arglist.post + got[ 1 ];
            } else {
               arglist.post = got[ 1 ];
            }
            r = r.substr( 0,  r.length - got[ 1 ].length );
         }
      }
      return r;
   };   // .gui.fasten()



   ETSI.gui.favour = function () {
      // Kick out competitors
      // Uses:
      //    this
      //    >  .gui.old
      //    mw.util.addCSS()
      // 2014-11-28 PerfektesChaos@de.wikipedia
      if ( typeof this.old === "string" ) {
         ETSI.gui.$container.empty();
         mw.util.addCSS( this.old + "{display:none}" );   // if later
      }
   };   // .gui.favour()



   ETSI.gui.fiat = function () {
      // Assign or create target container
      // Uses:
      //    >< .gui.builder
      //     < .gui.container
      // 2017-06-01 PerfektesChaos@de.wikipedia
      var f,
          i,
          lone,
          n,
          rule,
          s,
          sel,
          selectors,
          $container,
          $div,
          $related;
      for ( sel in this.builder ) {
         if ( /^[.#][^,.#= ]+$/.test( sel ) ) {
            $container = $( sel );
            if ( ! $container.length ) {
               rule = this.builder[ sel ];
               if ( typeof rule  ===  "object"
                    &&     rule   &&
                    typeof rule.fiat  ===  "string"
                    &&     rule.fiat   &&
                    typeof rule.start  ===  "string"
                    &&     rule.start ) {
                  $related = $( rule.start );
                  f        = rule.fiat;
                  n        = $related.length;
                  if ( n   &&
                       typeof $related[ f ]  ===  "function" ) {
                     lone = ( sel.substr( 0, 1 )  ===  "#" );
                     if ( lone  &&  n !== 1 ) {
                        n = 0;
                     }
                     if ( n ) {
                        s = sel.substr( 1 );
                        for ( i = 0;  i < n;  i++ ) {
                           $div = $( "<div>" );
                           if ( lone ) {
                              $div.attr( "id", s );
                           } else {
                              $div.addClass( s );
                           }
                           $related.eq( i )[ f ]( $div );
                        }   // for i
                        $container = $( sel );
                     }
                  }
               }
            }
            if ( $container.length ) {
               if ( selectors ) {
                  selectors = selectors + "," + sel;
               } else {
                  selectors = sel;
               }
            }
         }
      }   // for sel in this.builder
      if ( selectors ) {
         this.container = selectors;
      } else {
         this.container = "#";
      }
      this.builder = false;
   };   // .gui.fiat()



   ETSI.gui.fill = function ( arglist, additional ) {
      // Perform insertion
      // Precondition:
      //    arglist     -- parameters for jQuery.textSelection
      //    additional  -- event.ctrlKey code
      // Uses:
      //    >  .gui.$textarea
      //    >  .defs.looser
      //    >< .gui.wikEd::
      //        >  .wikEd.focus
      //        >< .wikEd.active
      //    >< .gui.$current
      //    .gui.flip()
      //    >  wikEd::
      //          >  .useWikEd
      //    .gui.fossil()
      //    jQuery.textSelection()
      // 2018-02-15 PerfektesChaos@de.wikipedia
      var launch, pars;
      if ( this.$current.length ) {
         launch = true;
         if ( this.wikEd ) {
            if ( window.wikEd.useWikEd !== true ) {
               this.wikEd.active = false;
            }
            if ( this.wikEd.active ) {
               if ( this.wikEd.focus ) {
                  if ( arglist.post  ||
                       arglist.peri  ||
                       arglist.replace ) {
                     // jQuery.textSelection() (2011-11) does not support
                     // DOM composition within iframe
                     launch = this.flip( arglist );
                  }
                  if ( window.wikEd.frameBody ) {
                     window.wikEd.UpdateTextarea( null );
                  }
                  this.$current = this.$textarea;
               }
            } else {
               this.wikEd.focus = false;
            }
         }
         if ( launch ) {
            pars = arglist;
            if ( ETSI.defs.looser ) {
               if ( arglist.post    === undefined  &&
                    arglist.replace === undefined ) {
                  pars.replace = true;
                  if ( arglist.peri === undefined ) {
                     pars.peri = "";
                  }
               }
            }
            if ( additional  &&  ! pars.replace ) {
               pars = { peri:    arglist.peri,
                        pre:     arglist.pre,
                        post:    arglist.post,
                        replace: true };
            }
            if ( typeof ETSI.user  ===  "object"
                 &&     ETSI.user   &&
                 typeof ETSI.user.client  ===  "string"
                 &&     ETSI.user.client  ===  "LFdoubled" ) {
               this.fossil( "encapsulateSelection", pars );
            } else {
               this.$current.textSelection( "encapsulateSelection",
                                            pars );
            }
         }
      }
   };   // .gui.fill()



   ETSI.gui.find = function ( adjust ) {
      // Retrieve number of item in gadget for a certain identifier
      // Precondition:
      //    adjust  -- identifier
      // Postcondition:
      //    Returns number,  < 0 if not found
      // Uses:
      //    >  .defs.opts
      // 2011-11-23 PerfektesChaos@de.wikipedia
      var r = -1,
          i,
          n;
      n = ETSI.defs.opts.length;
      for ( i = 0;  i < n;  i++ ) {
         if ( ETSI.defs.opts[ i ][ 0 ]  ===  adjust ) {
            r = i;
            break;   // for i
         }
      }   // for i
      return r;
   };   // .gui.find()



   ETSI.gui.fit = function ( arglist, additional ) {
      // Perform RegExp replacement
      // Precondition:
      //    arglist  -- Array(6)
      //                [0] to be inserted before caret / selection
      //                    string or empty
      //                [1] to be inserted after caret / selection
      //                    string or empty
      //                [2] string with replacement expression
      //                [5] string with RegExp to process selection
      //    additional  -- event.ctrlKey code
      // Uses:
      //    >  .gui.$current
      //    jQuery.textSelection()
      //    .gui.fill()
      // 2017-05-01 PerfektesChaos@de.wikipedia
      var pars,
          range,
          re,
          sel;
      if ( this.$current.length ) {
         pars  = { };
         range = this.$current.textSelection( "getCaretPosition",
                                              { "startAndEnd":
                                                true } );
         if ( arglist[0] ) {
            pars.pre = arglist[0];
         }
         if ( arglist[1] ) {
            pars.post = arglist[1];
         }
         if ( range[0] < range[1] ) {
            if ( typeof arglist[ 2 ]  ===  "string"  &&
                 typeof arglist[ 5 ]  ===  "string" ) {
               re  = new RegExp( arglist[ 5 ], "" );
               sel = this.$current.textSelection( "getSelection" );
               pars.peri    = sel.replace( re, arglist[2] );
               pars.replace = true;
            }
         }
         this.fill( pars, additional );
      }
   };   // .gui.fit()



   ETSI.gui.flip = function ( arglist ) {
      // Strip whitespace from current selection, insert in special cases
      //    (mainly for wikEd)
      // Precondition:
      //    arglist  -- encapsulateSelection object
      //                >  .pre
      //                >  .peri
      //                >  .post
      //                >  .replace
      //    Browser supports wikEd, wikEd is active
      // Postcondition:
      //    Returns false, if insertion has been performed
      // Uses:
      //    >  .gui.self
      //    >< .gui.wikEd
      //           < .encapsulateSelection
      //    .gui.flipper()
      //    >  wikEd::
      //          .GetSelection()
      //          .EditButton()
      //    .util.trimLeft()
      //    .util.trimRight()
      // 2015-06-25 PerfektesChaos@de.wikipedia
      var r     = true,
          range = window.wikEd.GetSelection(),
          sel   = range.toString(),
          n     = sel.length;
      if ( n ) {
         if ( n  !==  ETSI.util.trimLeft( sel ).length   ||
              n  !==  ETSI.util.trimRight( sel ).length ) {
            this.wikEd.encapsulateSelection = arglist;
            window.wikEd.EditButton( null,
                                     this.self,
                                     null,
                                     this.flipper );
            r = false;
         }   // heading or trailing whitespace
      }   // not empty
      return r;
   };   // .gui.flip()



   ETSI.gui.flipper = function ( about ) {
      // Handler for change per wikEd with whitespace around selection
      // Precondition:
      //    about  -- wikEd action object
      // Uses:
      //    >  .gui.wikEd
      //          < .encapsulateSelection
      //               >  .pre
      //               >  .peri
      //               >  .post
      //               >  .replace
      //    >  wikEd::
      //          .GetText()
      //          .EditButton()
      //    >< .gui.reWSbeg
      //     < .gui.reWSend
      // Remark: Used as event handler -- 'this' is not ETSI
      // 2018-02-15 PerfektesChaos@de.wikipedia
      var encapsulate = ETSI.gui.wikEd.encapsulateSelection,
          got,
          select,
          start,
          sample,
          suffix;
      // select the appropriate text change target
      // (whole, selection, cursor,
      //  focusWord, focusLine, selectionWord, or selectionLine)
      // focus... is the text under the cursor;
      // ...Word and ...Line extend the target
      //                     to the start/end of the word or line
      window.wikEd.GetText( about, "selection" );
      about.changed = about.selection;
      select        = about.changed.plain;
      start         = encapsulate.pre;
      suffix        = encapsulate.post;
      if ( typeof start === "string" ) {
         start = start.replace( /&/g, "&amp;" )
                      .replace( /</g, "&lt;" )
                      .replace( />/g, "&gt;" );
      } else {
         start = "";
      }
      if ( typeof suffix === "string" ) {
         suffix = suffix.replace( /&/g, "&amp;" )
                        .replace( /</g, "&lt;" )
                        .replace( />/g, "&gt;" );
      } else {
         suffix = "";
      }
      if ( typeof ETSI.gui.reWSbeg  !==  "object" ) {
         ETSI.gui.reWSbeg = new RegExp( "^\\s+" );
         ETSI.gui.reWSend = new RegExp( "\\S(\\s+)$" );
      }
      got = ETSI.gui.reWSbeg.exec( select );
      if ( got ) {
         start  = got[0] + start;
         select = select.substr( got[0].length );
      }
      got = ETSI.gui.reWSend.exec( select );
      if ( got ) {
         suffix = suffix + got[1];
         select = select.substr( 0,  select.length - got[1].length );
      }
      if ( encapsulate.replace ) {
         select = "";
      }
      sample = encapsulate.peri;
      if ( typeof sample === "string" ) {
         if ( ! select.length ) {
            sample = sample.replace( /&/g, "&amp;" )
                           .replace( /</g, "&lt;" )
                           .replace( />/g, "&gt;" );
         }
      } else {
         sample = select;
      }
      about.changed.plain = start + sample + suffix;
      // keep the changed text selected
      about.changed.keepSel = true;
      return;
   };   // .gui.flipper()



   ETSI.gui.focus = function () {
      // Initialize focussing
      // Precondition:
      //    document ready
      // Postcondition:
      //    Binding is established
      // Uses:
      //    this
      //     < .gui.$textarea
      //     < .gui.$current
      //     < .gui.wikEd
      //    >  wikEd::
      //          >  .disabled
      //          >  .useWikEd
      //          >  .frameDocument
      //          .Setup()
      //    jQuery().focus()
      //    (.gui.frames)
      // 2015-03-09 PerfektesChaos@de.wikipedia
      var $ins  =  $( "textarea, input:text" );
      this.$textarea  =  $( "#wpTextbox1" );
      this.wikEd      =  false;
      $ins.focus( function() { ETSI.gui.$current = $( this );
                               if ( ETSI.gui.wikEd ) {
                                  ETSI.gui.wikEd.focus = false;
                               }
                             } );
      if ( this.$textarea.length ) {
         this.$current = this.$textarea;
      } else {
         this.$current = $( "textarea, input:text" ).first();
      }
      if ( typeof window.wikEd === "object" ) {
         if ( window.wikEd  &&  this.$textarea.length ) {
            if ( typeof window.wikEd.Setup === "function" ) {
               // not just wikEdDiff?
               if ( typeof window.wikEd.disabled !== "boolean"
                    // asynchronous overrun
                    ||  ! window.wikEd.disabled ) {
                  window.wikEd.Setup();
               }
               if ( typeof window.wikEd.disabled === "boolean" ) {
                  this.wikEd = ! window.wikEd.disabled;
               }
            }
            if ( this.wikEd ) {
               this.wikEd = { active: window.wikEd.useWikEd,
                              focus:  true };
               window.wikEd.frameDocument.addEventListener( "click",
                                                            this.frames,
                                                            false );
               window.wikEd.frameDocument.addEventListener( "dblclick",
                                                            this.frames,
                                                            false );
               window.wikEd.frameDocument.addEventListener( "keypress",
                                                            this.frames,
                                                            false );
               /* wikEd uses an iframe
                  which cannot receive focus under <HTML5 conditions.  */
            }   // useWikEd
         }   // wikEd
      }   // wikEd object
   };   // .gui.focus()



   ETSI.gui.fossil = function ( action, arglist ) {
      // Support ancient CRLF
      // Precondition:
      //    action   -- jQuery.textSelection command
      //    arglist  -- parameters for jQuery.textSelection
      // Postcondition:
      //    Returns request
      // Uses:
      //    >< .gui.reCRLF
      //    .gui.fasten()
      // 2018-06-15 PerfektesChaos@de.wikipedia
      var textarea = this.$current.get( 0 ),
          iBeg     = textarea.selectionStart  ||  0,
          iEnd     = textarea.selectionEnd    ||  iBeg,
          story    = this.$current.val(),
          r, sel, sub, suffix;
      if ( typeof this.reCRLF  !==  "object" ) {
         this.reCRLF = new RegExp( "\r?\n", "g" );
      }
      if ( action === "encapsulateSelection" ) {
         story  = story.replace( this.reCRLF, "\r\n" );
         sub    = story.slice( 0, iEnd )
                       .replace( this.reCRLF, "\n" );
         iBeg   = story.slice( 0, iBeg )
                       .replace( this.reCRLF, "\n" ).length;
         suffix = story.slice( iEnd );
         story  = sub.slice( 0, iBeg );
//alert(iBeg+", "+iEnd+"  >>>"+story+"<<<  >>>"+suffix)
         if ( ! arglist.replace ) {
            sel = sub.slice( iBeg );
            sel = ETSI.gui.fasten( sel, arglist );
         }
         if ( typeof arglist.pre  ===  "string" ) {
            story = story + arglist.pre;
         }
         if ( arglist.replace ) {
            if ( typeof arglist.peri  ===  "string" ) {
               story = story + arglist.peri;
            }
         } else {
            story = story + sel;
         }
         if ( typeof arglist.post  ===  "string" ) {
            story = story + arglist.post;
         }
         iEnd  = story.replace( this.reCRLF, "\r\n" ).length;
         story = story + suffix;
         this.$current.val( story );
         textarea.selectionEnd   = iEnd;
         textarea.selectionStart = iBeg;
         this.$current.focus();
         textarea.selectionEnd   = iEnd;
         textarea.selectionStart = iEnd;
               /*
               var e, i, s;
               e = [ "pre", "peri", "post" ];
               for ( i = 0;  i < e.length;  i++ ) {
                  s = e[ i ];
                  if ( typeof pars[ s ]  ===  "string"
                       &&     pars[ s ] ) {
                     pars[ s ] = pars[ s ].replace( this.reCRLF,
                                                    "\r\n" );
                  }
               }   // for i
               */
      }
      return r;
   };   // .gui.fossil()



   ETSI.gui.frames = function ( active ) {
      // Handle iframe focussing, e.g. wikEd
      // Precondition:
      //    active  -- object: event
      // Uses:
      //    >< .gui.wikEd::
      //         < .wikEd.focus
      // 2011-11-21 PerfektesChaos@de.wikipedia
      if ( this.wikEd ) {
         this.wikEd.focus = true;
      }
   };   // .gui.frames()



   ETSI.menu.factory = function ( apply ) {
      // Build menu area
      // Precondition:
      //    apply  -- Array(5)
      //              [0] identifier
      //              [1] definition
      //              [2] origin
      //              [3] option title
      //              [4] $menu (false)
      // Postcondition:
      //    Returns jQuery object for $menu (apply[4])
      // Uses:
      //    >  .menu.separator
      //    >  .gui.self
      //    >  .menu.divide
      //    >< .menu.$sep
      //    .attr.furnish()
      //    .menu.field()
      // 2017-05-11 PerfektesChaos@de.wikipedia
      var d    = apply[ 1 ],
          lead = false,
          n    = d.length,
          $r   = $( "<div>" ),
          i,
          sel,
          $sep;
      $r.css( "display", "inline" );
      if ( typeof this.$sep !== "object" ) {
         this.$sep = false;
         if ( typeof this.separator === "string" ) {
            if ( this.separator.length ) {
               $sep = $( "<span>" );
               $sep.addClass( ETSI.gui.self + "-sep" )
                   .text( this.separator );
               if ( typeof this.divide === "object" ) {
                  $sep.css( this.divide );
               }
               this.$sep = $( "<span>" );
               this.$sep.text( " " )
                        .prepend( $sep );
            }
         }
      }
      ETSI.attr.furnish( $r,  apply[ 0 ],  apply[ 2 ] );
      sel = $r.attr( "class" );
      if ( typeof sel === "string" ) {
         sel = sel + ",";
      } else {
         sel = "";
      }
      sel = sel + ETSI.gui.self + "-menu-"  + apply[ 0 ];
      $r.attr( "class", sel );
      for ( i = 1;  i < n;  i++ ) {
         lead = this.field( $r,  d[ i ],  lead );
      }   // for i
      return $r;
   };   // .menu.factory()



   ETSI.menu.family = function ( assign, apply, align ) {
      // Process definition element of type "numeric range of single UCS"
      // Precondition:
      //    assign  -- jQuery element to be extended
      //    apply   -- definition item; Array with at least 3 elements
      //               [0] code for "numeric range"
      //               [1] UCS, first character in first pair
      //               [2] UCS, last character in first pair
      //               [4] optional: UCS, first character in second pair
      //               [5] optional: UCS, last character in second pair
      //               ... etc.
      //    align   -- true: insert group separator ahead
      // Ranges are supposed to cover less than 1024 codepoints
      // Postcondition:
      //    assign is extended
      // Uses:
      //    .menu.fence()
      //    .menu.fill()
      //    .menu.fixed()
      // 2011-11-23 PerfektesChaos@de.wikipedia
      var n = apply.length,
          i,
          j,
          k,
          m;
      this.fence( assign, align );
      for ( k = 1;  k < n;  k += 2 ) {
         i = apply[ k ];
         j = apply[ k + 1 ];
         m = j - i;
         if ( i < j ) {
            if ( m < 1024 ) {
               for(  true;  i <= j;  i++ ) {
                  this.fill( assign, i );
               }   // for i
               m = false;
            }
         } else {   // rtl
            if ( m > -1024 ) {
               for ( true;  i >= j;  i-- ) {
                  this.fill( assign, i );
               }   // for i--
               m = false;
            }
         }
         if ( m ) {
            this.fixed( assign,
                        "ERROR: too many UCS chars: " + i + "..." + j,
                        true );
         }
      }   // for k
   };   // .menu.family()



   ETSI.menu.feed = function ( assign, apply, align ) {
      // Process a definition element of type "separated compressed"
      // Precondition:
      //    assign  -- jQuery element to be extended
      //    apply   -- definition item; Array with at least 2 elements
      //               [0] number < 0, -[0]: code of separator
      //               [1] and further: string, separated by -[0]
      //    align   -- true: insert group separator ahead
      // Postcondition:
      //    assign is extended
      // Uses:
      //    .menu.fence()
      //    .menu.fill()
      // 2011-10-27 PerfektesChaos@de.wikipedia
      var lead   = align,
          more   = apply.length,
          sep    = String.fromCharCode( -apply[ 0 ] ),
          i,
          m,
          n,
          subs,
          stream;
      for ( i = 1;  i < more;  i++ ) {
         stream = apply[ i ];
         if ( typeof stream === "string" ) {
            subs = stream.split( sep );
            n    = subs.length;
            this.fence( assign,  n && lead );
            for ( m = 0;  m < n;  m++ ) {
               this.fill( assign, subs[ m ] );
            }   // for m
         }
         lead = true;
      }   // for i
   };   // .menu.feed()



   ETSI.menu.fence = function ( assign, align ) {
      // Insert group separator conditionally
      // Precondition:
      //    assign  -- jQuery element to be extended
      //    align   -- true: insert group separator ahead, else nothing
      // Postcondition:
      //    group separator has been appended to assign, if align
      // Uses:
      //    >  .menu.$sep
      // 2011-11-23 PerfektesChaos@de.wikipedia
      if ( align ) {
         if ( this.$sep ) {
            assign.append( this.$sep.clone() );
         }
      }
   };   // .menu.fence()



   ETSI.menu.field = function ( assign, apply, align ) {
   // Process a group (one item in definition array)
   // Precondition:
   //    assign  -- jQuery element to be extended
   //    apply   -- definition element
   //               Array:   with specifications
   //               boolean: false  -- no group separator
   //               number:  0      -- no group separator
   //    align   -- true: insert group separator ahead
   // Postcondition:
   //    Returns necessity for separator before next group
   // Uses:
   //    .menu.flush()
   //    .menu.family()
   //    .menu.figures()
   //    .menu.feed()
   //    .menu.fixed()
   //    .menu.fence()
   //    .menu.fill()
   // 2011-11-28 PerfektesChaos@de.wikipedia
      var light = true,
          r     = true,
          begin,
          i,
          n;
      if ( apply ) {
         begin = apply[0];
         light = ( typeof begin === "number" );
         if ( light ) {
            if ( begin === 1 ) {
               this.flush( assign, apply, align );
            } else if ( begin === 2 ) {
               this.family( assign, apply, align );
            } else if ( begin === 3 ) {
               this.figures( assign, apply, align );
            } else if ( begin < -31 ) {
               this.feed( assign, apply, align );
            } else if ( ! begin ) {
               if ( apply[1] ) {
                  this.fixed( assign, apply[1], align );
               }
               r = false;
            } else if ( begin > 126 ) {
               light = false;
            }
         }
      } else {
         r = false;
      }   // apply
      if ( ! light ) {
         n = apply.length;
         this.fence( assign, align );
         for ( i = 0;  i < n;  i++ ) {
            this.fill( assign, apply[i] );
         }   // for i
      }
      return r;
   };   // .menu.field()



   ETSI.menu.figures = function ( assign, apply, align ) {
      // Process a definition element of type "numeric UCS sequences"
      // Precondition:
      //    assign  -- jQuery element to be extended
      //    apply   -- definition item; Array with at least 3 elements
      //               [0] code for "numeric sequences"
      //               [1] UCS of first character in first token
      //               [2] UCS of next character in first token,
      //                   or false / 0 to separate from next token
      //               [...] UCS of first character in second token
      //               ... etc.
      //    align   -- true: insert group separator ahead
      // Ranges are supposed to cover less than 1024 codepoints
      // Postcondition:
      //    assign is extended
      // Uses:
      //    .menu.fence()
      //    .menu.fromCharCode()
      //    .menu.fill()
      // 2011-11-28 PerfektesChaos@de.wikipedia
      var n = apply.length,
          s = "",
          i,
          k;
      this.fence( assign, align );
      for ( k = 1;  k < n;  k++ ) {
         i = apply[ k ];
         if ( i ) {
            s = s + this.fromCharCode( i );
         } else {
            this.fill( assign, s );
            s = "";
         }
      }   // for k
   };   // .menu.figures()



   ETSI.menu.fill = function ( assign, apply ) {
      // Create a single token
      // Precondition:
      //    assign  -- jQuery element to be extended
      //    apply   -- specification
      //               string: insert ahead
      //               number: insert UCS ahead
      //               Array(1...)    [0]...[4]: string or empty
      //               [0] to be inserted before cursor pos / selection
      //               [1] to be inserted after cursor pos / selection
      //               [2] to be inserted if there is no selection range
      //               [3] tooltip
      //               [4] explicit label for token
      //               [5] advanced
      //                   true:     Replace current selection, if any.
      //                   function: to be executed with apply
      //                   string:   RegExp for selection, apply to [2]
      //               [6] double advanced
      //                   true:     Replace current selection, if any.
      //                   function: to be executed with apply
      //               [...] any other value that is currently ignored
      // Uses:
      //    >  .menu.stick
      //    >  .gui.self
      //    .menu.fromCharCode()
      //    (.gui.fill)
      //    (.menu.fun)
      //    (.gui.fit)
      // 2017-05-22 PerfektesChaos@de.wikipedia
      var exec   = false,
          label  = false,
          light  = false,
          loose  = false,
          pars   = false,
          say    = "",
          story  = false,
          n,
          sample,
          start,
          suffix,
          $space,
          $span,
          $token;
      switch ( typeof apply ) {
         case "number" :
            if ( apply > 0 ) {
               say   = this.fromCharCode( apply );
               light = true;
            }
            break;
         case "string" :
            say   = apply;
            light = true;
            break;
         case "object" :
            if ( apply ) {
               loose  = false;
               n      = apply.length;  // undefined  en.WP
               sample = "";
               start  = ( apply[0] ? apply[0] : "" );
               suffix = "";
               if ( typeof start === "number" ) {
                  start = this.fromCharCode( start );
               }
               say = start;
            } else {
               n = 0;
            }
            if ( n > 1 ) {
               if ( apply[1] ) {
                  suffix = apply[1];
                  if ( typeof suffix  ===  "number" ) {
                     suffix = this.fromCharCode( suffix );
                  }
                  say   = start + suffix;
                  story = start
                     + ( this.stick ? this.stick : "" )
                          + suffix;
               }
               if ( n > 2 ) {
                  if ( apply[2] ) {
                     sample = apply[2];
                     story  = say + sample + suffix;
                  }
                  if ( n > 3 ) {
                     if ( apply[3] ) {
                        story = apply[3];
                     }
                     if ( n > 4 ) {
                        label = ( typeof apply[4]  ===  "string"
                                  &&     apply[4] );
                        if ( label ) {
                           say = apply[4];
                        }
                        if ( n > 5 ) {
                           switch ( typeof apply[5] ) {
                              case "boolean" :
                                 loose  = apply[5];
                                 break;
                              case "function" :
                                 exec = function( event ) {
                                           this.fun( apply,
                                                     event.ctrlKey );
                                           return false;
                                        };
                                 break;
                              case "string" :
                                 exec = function( event ) {
                                           ETSI.gui.fit( apply,
                                                         event.ctrlKey );
                                           return false;
                                        };
                                 break;
                           }   // switch typeof apply[5]
                           if ( n > 6 ) {
                              switch ( typeof apply[6] ) {
                                 case "boolean" :
                                    loose  = apply[6];
                                    break;
                              }   // switch typeof apply[6]
                           }
                        }
                     }
                  }
               }
            }
            if ( ! exec   &&
                 ( start || suffix || sample || loose ) ) {
               pars = { peri:    sample,
                        pre:     start,
                        post:    suffix,
                        replace: loose };
            }
            break;
      }   // switch typeof apply
      n = say.length;
      if ( n ) {
         if ( light ) {
            pars  = { pre: say };
         }
         if ( pars ) {
            if ( ! exec ) {
               exec = function( event ) {
                         ETSI.gui.fill( pars, event.ctrlKey );
                         return false;
                      };
            }
         }
         if ( exec ) {
            $space = $( "<span>" );
            $space.text( " " );
            $span = $( "<span>" );
            $span.css( { "display":     "inline-block",
                         "white-space": "nowrap" } );
            if ( label   &&
                 say.charCodeAt( 0 ) === 60   &&       // <
                 say.charCodeAt( n - 1 ) === 62 ) {    // >
               $span.html( say );
            } else {
               $span.text( say );
            }
            $token = $( "<a>" );
            $token.attr( { "class":  ETSI.gui.self + "-token",
                           "href":   "#" } );
            if ( story ) {
               $token.attr( "title", story );
            }
            $token.append( $span )
                  .click( exec );
            assign.append( $space )
                  .append( $token );
         }
      }
   };   // .menu.fill()



   ETSI.menu.fixed = function ( assign, apply, align ) {
      // Process a definition element of type "fixed text"
      // Precondition:
      //    assign  -- jQuery element to be extended
      //    apply   -- (HTML) string to be inserted
      //    align   -- true: insert separating spaces ahead
      // Postcondition:
      //    apply has been appended to assign
      // 2011-10-27 PerfektesChaos@de.wikipedia
      var s = "<span>"
              + ( align ? " " : "" )
              + apply + "</span>";
      assign.append( s );
   };   // .menu.fixed()



   ETSI.menu.flush = function ( assign, apply, align ) {
      // Process a definition element of type "packed characters"
      // Precondition:
      //    assign  -- jQuery element to be extended
      //    apply   -- definition item; Array with at least 2 elements
      //               [0] === 1
      //               [1] and further: string, character sequence group
      //    align   -- true: insert group separator ahead
      // Postcondition:
      //    assign is extended
      // Uses:
      //    .menu.fence()
      //    .menu.fill()
      // 2011-10-27 PerfektesChaos@de.wikipedia
      var lead   = align,
          more   = apply.length,
          i,
          m,
          n,
          stream;
      for ( i = 1;  i < more;  i++ ) {
         stream = apply[i];
         if ( typeof stream === "string" ) {
            n = stream.length;
            this.fence( assign,  n && lead );
            for ( m = 0;  m < n;  m++ ) {
               this.fill( assign,  stream.substr( m, 1 ) );
            }   // for m
         }
         lead = true;
      }   // for i
   };   // .menu.flush()



   ETSI.menu.fromCharCode = function ( address ) {
      // Extended fromCharCode for UCS > 0xFFFF (4 bytes/char)
      // Precondition:
      //    address  -- number, UCS
      // Postcondition:
      //    Returns a single character,
      //       which might have a string length of 2 instead of 1
      // Requires: JavaScript 1.3 String.fromCharCode() 2 byte chars only
      // 2011-10-27 PerfektesChaos@de.wikipedia
      var c,
          r;
      if ( address > 0xFFFF ) {
         c = address - 0x10000;
         r = String.fromCharCode( 0xD800  +  ( c >> 10 ),
                                  0xDC00  +  ( c & 0x3FF ) );
      } else {
         r = String.fromCharCode( address );
      }
      return r;
   };   // .menu.fromCharCode()



   ETSI.menu.fun = function ( apply, additional ) {
      // Evaluate user defined function
      // Precondition:
      //    apply       -- specification array; apply[5] is the UDF
      //                   If apply[5]() returns
      //                   an encapsulateSelection object,
      //                   insertion will be performed.
      //    additional  -- event.ctrlKey code
      // Uses:
      //    >  .gui.$current
      //    .gui.fill()
      // 2017-05-22 PerfektesChaos@de.wikipedia
      var got = apply[5]( apply,
                          ETSI.gui.$current.textSelection(
                                                      "getSelection" ) );
      if ( typeof got === "object" ) {
         ETSI.gui.fill( got, additional );
      }
   };   // .menu.fun()



   ETSI.util.trimLeft = function ( adjust ) {
      // Trim string left
      // Precondition:
      //    adjust  -- string
      // Postcondition:
      //    Returns trimmed string
      // 2015-06-25 PerfektesChaos@de.wikipedia
      return adjust.replace( /^\s+/, "" );
   };   // .util.trimLeft()



   ETSI.util.trimRight = function ( adjust ) {
      // Trim string right
      // Precondition:
      //    adjust  -- string
      // Postcondition:
      //    Returns trimmed string
      // 2015-06-25 PerfektesChaos@de.wikipedia
      return adjust.replace( /\s+$/, "" );
   };   // .util.trimRight()



   ETSI.factory = function () {
      // (Re-)build entire data model from project and user spec
      // Postcondition:
      //    .current defs are defined
      // Uses:
      //    >< .defs.lead
      //    >< .defs.opts
      //     < .defs.tmp
      //     < .defs.reNS
      //     < .gui.hintList
      //     < .gui.hintMenu
      //    .defs.factory()
      //    .defs.format()
      //    .defs.fair()
      //    .defs.furnish()
      //    .defs.filter()
      // 2012-10-29 PerfektesChaos@de.wikipedia
      this.defs.lead = false;
      this.defs.opts = false;
      this.defs.reNS = false;
      this.defs.factory();
      this.defs.tmp     = this.defs.find( "list", "object" );
      this.gui.hintList = this.defs.find( "hintList", "string" );
      this.gui.hintMenu = this.defs.find( "hintMenu", "string" );
      this.defs.format();
      this.defs.fair();
      if ( this.defs.lead ) {
         this.defs.furnish();
      }
      if ( this.defs.opts ) {
         this.defs.filter();
      }
   };   // .factory()



   ETSI.about_defs = function ( alerting ) {
      // Show message box with all available definition identifiers (API)
      // Precondition:
      //    alerting  -- false: don't try to pop up message box
      // Postcondition:
      //    Message box is presented, if possible.
      //    Returns void(0) if message box shown,
      //            else string with definition identifiers.
      // Uses:
      //    > .defs.current
      // 2011-11-23 PerfektesChaos@de.wikipedia
      var collect = [ ],
          r       = false,
          d,
          i,
          n,
          p,
          q,
          v;
      n = this.defs.current.length;
      for ( i = 0;  i < n;  i++ ) {
         d = this.defs.current[ i ][ 1 ].defs;
         for ( q in d ) {
            v = d[ q ];
            if ( typeof v === "object" ) {
               if ( v.length > 1 ) {
                  collect = collect.concat( [ q ] );
               }
            }
         }   // for q in d
      }   // for i
      n = collect.length;
      if ( n ) {
         collect.sort();
         r = "";
         p = "";
         for ( q = 0;  q < n;  q++ ) {
            v = collect[ q ];
            if ( v !== p ) {
               r += " " + v;
               p  = v;
            }
         }   // for q
         r = r.substr( 1 );
      } else {
         r = "*-*-*-*";
      }
      if ( alerting !== false ) {
         if ( typeof window === "object" ) {
            window.alert( r );
            r = void( 0 );
         }   // online
      }
      return r;
   };   // .about_defs()



   ETSI.about_version = function () {
      // Retrieve version information
      // Postcondition:
      //    Returns string with information
      // Uses:
      //    > .gui.self
      //    > .type
      //    > .vsn
      // 2015-03-10 PerfektesChaos@de.wikipedia
      var r;
      r  = "MediaWiki User:PerfektesChaos " + this.type
           + " self='" +  this.gui.self + "' vsn=" + this.vsn;
      return r;
   };   // .about_version()



   ETSI.set = function ( action, apply ) {
      // Set project or user property (API)
      // Precondition:
      //    action  -- string: which property to be set
      //               "container":         additional selectors
      //               "cookieName":        memorize recent selection ID
      //                                    or false
      //               "ellipsis":          tooltip generation
      //                                    put between start and end tag
      //               "groupSeparator":    non-empty string
      //                                    or false
      //               "groupSeparatorCSS": object with CSS assignments
      //               "hintList":          string: tooltip for gadget
      //               "hintMenu":          string: tooltip for menus
      //               "old":               selector for other edittools
      //                                    or false
      //               "replace":           always replace instead insert
      //               "selection":         gadget shift, ID string
      //    apply   -- string or boolean
      // Uses:
      //    >  .defs.opts
      //     < .gui.builder
      //     < .gui.cookie
      //     < .menu.divide
      //     < .gui.hintList
      //     < .gui.hintMenu
      //     < .menu.separator
      //     < .menu.stick
      //     < .gui.old
      //     < .defs.looser
      //     < .gui.selection
      //    .gui.favour()
      //    .gui.facet()
      //    .util.trimLeft()
      //    .util.trimRight()
      // 2017-06-01 PerfektesChaos@de.wikipedia
      switch ( action ) {
         case "container" :
            if ( typeof apply === "object" ) {
               this.gui.builder = apply;
            }
            break;
         case "cookieName" :
            if ( typeof apply === "string" ) {
               this.gui.cookie = ETSI.util.trimLeft( apply );
               this.gui.cookie = ETSI.util.trimRight( this.gui.cookie );
               if ( ! this.gui.cookie.length ) {
                  this.gui.cookie = false;
               }
            } else {
               this.gui.cookie = false;
            }
            break;
         case "ellipsis" :
            if ( typeof apply === "string" ) {
               this.menu.stick = apply;
            }
            break;
         case "groupSeparator" :
            this.menu.separator = apply;
            break;
         case "groupSeparatorCSS" :
            if ( typeof apply === "object" ) {
               this.menu.divide = apply;
            }
            break;
         case "hintList" :
            if ( typeof apply === "string" ) {
               this.gui.hintList = apply;
            }
            break;
         case "hintMenu" :
            if ( typeof apply === "string" ) {
               this.gui.hintMenu = apply;
            }
            break;
         case "old" :
            this.gui.old = apply;
            this.gui.favour();
            break;
         case "replace" :
            this.defs.looser = apply;
            break;
         case "selection" :
            this.gui.selection = apply;
            if ( typeof this.opts === "object" ) {
               this.gui.facet();
            }
            break;
      }   // switch action
   };   // .set()



   ETSI.update = function () {
      // Furnish entire list and model once again (may be used as API)
      // Uses:
      //    >  .loaded
      //    fired()
      // Remark: Used as event handler -- 'this' is not ETSI
      // 2017-06-01 PerfektesChaos@de.wikipedia
      if ( ETSI.loaded ) {
         fired();
      }
   };   // .update()



   function first() {
      // Autorun on load (once)
      // Uses:
      //    >  Signature
      //    >  .user.config.container
      //    >  .hookAfterLoad
      //     < .gui.builder
      //    mw.loader.getState()
      //    mw.loader.state()
      //    mw.config.get()
      //    mw.hook()
      //    mw.loader.using()
      //    (fired)
      //    (ETSI.hookAfterLoad)
      // 2018-08-24 PerfektesChaos@de.wikipedia
      var launch,
          rls,
          s;
      if ( mw.loader.getState( Signature )  !==  "ready" ) {
         rls = { };
         rls[ Signature ] = "loaded";
         mw.loader.state( rls );
         switch ( mw.config.get( "wgNamespaceNumber" ) ) {
            case -1 :
               s      = mw.config.get( "wgCanonicalSpecialPageName" );
               launch = ( s === "Upload" );
               break;
            default:
               s      = mw.config.get( "wgAction" );
               launch = ( s === "edit"  ||  s === "submit" );
         }   // switch action
         if ( launch ) {
            if ( typeof ETSI.user  ===  "object"
                 &&     ETSI.user     &&
                 typeof ETSI.user.config  ===  "object"
                 &&     ETSI.user.config
                 &&     ETSI.user     &&
                 typeof ETSI.user.config.container  ===  "object"
                 &&     ETSI.user.config.container ) {
               ETSI.gui.builder = ETSI.user.config.container;
            }
            mw.hook( ETSI.type + ".ready" ).fire( ETSI );
            mw.loader.using( [ "user",
                               "mediawiki.util",
                               "jquery.textSelection" ],
                             fired );
            if ( typeof ETSI.hookAfterLoad  ===  "function" ) {
               ETSI.hookAfterLoad();
            }
         }
         rls[ Signature ] = "ready";
         mw.loader.state( rls );
      }
   }   // first()



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



/// end of editToolStrIns.js  </nowiki>