Bearbeiten von „OS2.spielplan

Zur Navigation springen Zur Suche springen
Warnung: Du bist nicht angemeldet. Deine IP-Adresse wird bei Bearbeitungen öffentlich sichtbar. Melde dich an oder erstelle ein Benutzerkonto, damit Bearbeitungen deinem Benutzernamen zugeordnet werden. Ein eigenes Benutzerkonto hat eine ganze Reihe von Vorteilen.

Die Bearbeitung kann rückgängig gemacht werden. Bitte prüfe den Vergleich unten, um sicherzustellen, dass du dies tun möchtest, und veröffentliche dann unten deine Änderungen, um die Bearbeitung rückgängig zu machen.

Aktuelle Version Dein Text
Zeile 1: Zeile 1:
[[Kategorie:Greasemonkey]]
[[Kategorie:Greasemonkey]]
[[Kategorie:Greasemonkey WE]]
{| style="background-color:white; font-size:11px; float: right; margin:3px 3px 3px 10px; border:1px solid #999; border-color: #9C1818; border-collapse:collapse;" width=500 cellpadding=3 cellspacing=0
{| style="background-color:white; font-size:11px; float: right; margin:3px 3px 3px 10px; border:1px solid #999; border-color: #9C1818; border-collapse:collapse;" width=500 cellpadding=3 cellspacing=0
| colspan="2" style="padding:0.3em; background-color:#9C1818; font-size: 18px; color:#FFFFFF" align=center| '''OS2.spielplan'''
| colspan="2" style="padding:0.3em; background-color:#9C1818; font-size: 18px; color:#FFFFFF" align=center| '''OS2.spielplan'''
Zeile 8: Zeile 7:
|- bgcolor="#FFCC00"
|- bgcolor="#FFCC00"
| '''Version'''
| '''Version'''
| '''0.73 (WebExtensions)'''  
| '''0.70'''  
|- bgcolor="#FFCC00"
|- bgcolor="#FFCC00"
| '''Autor'''
| '''Autor'''
Zeile 20: Zeile 19:
|- bgcolor="#FFCC00"
|- bgcolor="#FFCC00"
| '''Funktionalität'''
| '''Funktionalität'''
| '''Trennstriche zwischen den Abrechnungsmonaten'''<br> '''Verkürzung von "Vorbericht(e)" und "Kommentar(e)"'''<br> '''Details zu den Spielen'''<br> '''Ergebnisse aufaddieren'''<br> '''Nachträgliche Vorschau: Bilanz'''<br> '''Benutzermenü für Optionen'''<br> '''Erweiterte Optionen auch auf der Seite'''<br> '''Link auf den jeweiligen Spieltag bzw. die jeweilige Runde'''<br> '''Interaktive Menü-Optionen'''<br> '''Gemeinsame Code- und Datenbasis'''<br> '''Gezielte "hl"-Links auf die eigenen Spiele'''
| '''Trennstriche zwischen den Abrechnungsmonaten'''<br> '''Verkürzung von "Vorbericht(e)" und "Kommentar(e)"'''<br> '''Details zu den Spielen'''<br> '''Ergebnisse aufaddieren'''<br> '''Nachträgliche Vorschau: Bilanz'''<br> '''Benutzermenü für Optionen'''<br> '''Erweiterte Optionen auch auf der Seite'''<br> '''Link auf den jeweiligen Spieltag bzw. die jeweilige Runde'''<br> '''Interaktive Menü-Optionen'''<br> '''Gemeinsame Code- und Datenbasis'''
|- bgcolor="#FFCC00"
|- bgcolor="#FFCC00"
| '''Letzte Änderung'''
| '''Letzte Änderung'''
Zeile 26: Zeile 25:
|- bgcolor="#FFCC00"
|- bgcolor="#FFCC00"
|}
|}
== [https://github.com/Eselce/OS2.scripts/blob/master/OS2.spielplan.user.js Quellcode] [https://eselce.github.io/OS2.scripts/OS2.spielplan.user.js INSTALLATION] ==
<pre>
<pre>
// ==UserScript==
// ==UserScript==
// @name        OS2.spielplan
// @name        OS2.spielplan
// @namespace    http://os.ongapo.com/
// @namespace    http://os.ongapo.com/
// @version      0.73
// @version      0.70
// @copyright    2013+
// @copyright    2013+
// @author      Sven Loges (SLC)
// @author      Sven Loges (SLC)
// @description  Spielplan-Abschnitt aus dem Master-Script fuer Online Soccer 2.0
// @description  Spielplan-Abschnitt aus dem Master-Script fuer Online Soccer 2.0
// @include      /^https?://(www\.)?(os\.ongapo\.com|online-soccer\.eu|os-zeitungen\.com)/(st|showteam)\.php\?s=6(&\w+=?[+\w]+)*(#\w+)?$/
// @include      http*://os.ongapo.com/st.php?s=*
// @grant        GM.getValue
// @include      http*://os.ongapo.com/showteam.php?s=*
// @grant        GM.setValue
// @include      http*://www.os.ongapo.com/st.php?s=*
// @grant        GM.deleteValue
// @include      http*://www.os.ongapo.com/showteam.php?s=*
// @grant        GM.registerMenuCommand
// @include      http*://online-soccer.eu/st.php?s=*
// @grant        GM.info
// @include      http*://online-soccer.eu/showteam.php?s=*
// @require     https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
// @include      http*://www.online-soccer.eu/st.php?s=*
// @include     http*://www.online-soccer.eu/showteam.php?s=*
// @grant        GM_getValue
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_setValue
Zeile 50: Zeile 48:
// ==/UserScript==
// ==/UserScript==


// ECMAScript 6:
// ECMAScript 6: Erlaubt 'const', 'let', ...
/* jshint esnext: true */
/* jshint esnext: true */
/* jshint moz: true */
/* jshint moz: true */
Zeile 144: Zeile 142:
                   'Name'      : "sepStyle",
                   'Name'      : "sepStyle",
                   'Type'      : __OPTTYPES.MC,
                   'Type'      : __OPTTYPES.MC,
                   'ValType'  : 'String',
                   'ValType'  : "String",
                   'Choice'    : [ 'solid', 'hidden', 'dotted', 'dashed', 'double', 'groove', 'ridge',
                   'Choice'    : [ "solid", "hidden", "dotted", "dashed", "double", "groove", "ridge",
                                   'inset', 'outset', 'none' ],
                                   "inset", "outset", "none" ],
                   'Action'    : __OPTACTION.NXT,
                   'Action'    : __OPTACTION.NXT,
                   'Label'    : "Stil: $",
                   'Label'    : "Stil: $",
Zeile 155: Zeile 153:
                   'Name'      : "sepColor",
                   'Name'      : "sepColor",
                   'Type'      : __OPTTYPES.MC,
                   'Type'      : __OPTTYPES.MC,
                   'ValType'  : 'String',
                   'ValType'  : "String",
                   'FreeValue' : true,
                   'FreeValue' : true,
                   'Choice'    : [ 'white', 'yellow', 'black', 'blue', 'cyan', 'gold', 'grey', 'green',
                   'Choice'    : [ "white", "yellow", "black", "blue", "cyan", "gold", "grey", "green",
                                   'lime', 'magenta', 'maroon', 'navy', 'olive', 'orange', 'purple',
                                   "lime", "magenta", "maroon", "navy", "olive", "orange", "purple",
                                   'red', 'teal', 'transparent' ],
                                   "red", "teal", "transparent" ],
                   'Action'    : __OPTACTION.NXT,
                   'Action'    : __OPTACTION.NXT,
                   'Label'    : "Farbe: $",
                   'Label'    : "Farbe: $",
Zeile 168: Zeile 166:
                   'Name'      : "sepWidth",
                   'Name'      : "sepWidth",
                   'Type'      : __OPTTYPES.MC,
                   'Type'      : __OPTTYPES.MC,
                   'ValType'  : 'String',
                   'ValType'  : "String",
                   'FreeValue' : true,
                   'FreeValue' : true,
                   'Choice'    : [ 'thin', 'medium', 'thick' ],
                   'Choice'    : [ "thin", "medium", "thick" ],
                   'Action'    : __OPTACTION.NXT,
                   'Action'    : __OPTACTION.NXT,
                   'Label'    : "Dicke: $",
                   'Label'    : "Dicke: $",
Zeile 176: Zeile 174:
                   'FormLabel' : "Dicke:|$"
                   'FormLabel' : "Dicke:|$"
               },
               },
     'saison' : {          // Angezeigte Saison
     'saison' : {          // Laufende Saison
                   'Name'      : "saison",
                   'Name'      : "saison",
                   'Type'      : __OPTTYPES.MC,
                   'Type'      : __OPTTYPES.MC,
                   'ValType'  : 'Number',
                   'ValType'  : "Number",
                   'FreeValue' : true,
                   'FreeValue' : true,
                   'SelValue'  : false,
                   'SelValue'  : false,
                   'Choice'    : [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 ],
                   'Choice'    : [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ],
                   'Default'  : 18,
                   'Default'  : 10,
                   'Action'    : __OPTACTION.NXT,
                   'Action'    : __OPTACTION.NXT,
                   'Label'    : "Saison: $",
                   'Label'    : "Saison: $",
                   'Hotkey'    : 's',
                   'Hotkey'    : 'a',
                   'FormLabel' : "Saison:|$"
                   'FormLabel' : "Saison:|$"
               },
               },
Zeile 192: Zeile 190:
                   'Name'      : "ligaSize",
                   'Name'      : "ligaSize",
                   'Type'      : __OPTTYPES.MC,
                   'Type'      : __OPTTYPES.MC,
                   'ValType'  : 'Number',
                   'ValType'  : "Number",
                   'AutoReset' : true,
                   'AutoReset' : true,
                   'Choice'    : [ 10, 18, 20 ],
                   'Choice'    : [ 10, 18, 20 ],
Zeile 206: Zeile 204:
                   'Serial'    : true,
                   'Serial'    : true,
                   'Permanent' : true,
                   'Permanent' : true,
                   'Default'  : undefined,  // new Team() // { 'Team' : undefined, 'Liga' : undefined, 'Land' : undefined, 'TmNr' : 0, 'LdNr' : 0, 'LgNr' : 0 }
                   'Default'  : undefined,  // new Team() // { 'Team' : undefined, 'Liga' : undefined, 'Land' : undefined, 'LdNr' : 0, 'LgNr' : 0 }
                   'Submit'    : undefined,
                   'Submit'    : undefined,
                   'Cols'      : 36,
                   'Cols'      : 36,
Zeile 215: Zeile 213:
               },
               },
     'reset' : {          // Optionen auf die "Werkseinstellungen" zuruecksetzen
     'reset' : {          // Optionen auf die "Werkseinstellungen" zuruecksetzen
                  'FormPrio'  : undefined,
                   'Name'      : "reset",
                   'Name'      : "reset",
                   'Type'      : __OPTTYPES.SI,
                   'Type'      : __OPTTYPES.SI,
Zeile 224: Zeile 221:
               },
               },
     'storage' : {        // Browserspeicher fuer die Klicks auf Optionen
     'storage' : {        // Browserspeicher fuer die Klicks auf Optionen
                  'FormPrio'  : undefined,
                   'Name'      : "storage",
                   'Name'      : "storage",
                   'Type'      : __OPTTYPES.MC,
                   'Type'      : __OPTTYPES.MC,
                   'ValType'  : 'String',
                   'ValType'  : "String",
                   'Choice'    : Object.keys(__OPTMEM),
                   'Choice'    : Object.keys(__OPTMEM),
                   'Action'    : __OPTACTION.NXT,
                   'Action'    : __OPTACTION.NXT,
Zeile 235: Zeile 231:
               },
               },
     'oldStorage' : {      // Vorheriger Browserspeicher fuer die Klicks auf Optionen
     'oldStorage' : {      // Vorheriger Browserspeicher fuer die Klicks auf Optionen
                  'FormPrio'  : undefined,
                   'Name'      : "oldStorage",
                   'Name'      : "oldStorage",
                   'Type'      : __OPTTYPES.SD,
                   'Type'      : __OPTTYPES.SD,
Zeile 243: Zeile 238:
               },
               },
     'showForm' : {        // Optionen auf der Webseite (true = anzeigen, false = nicht anzeigen)
     'showForm' : {        // Optionen auf der Webseite (true = anzeigen, false = nicht anzeigen)
                  'FormPrio'  : undefined,
                   'Name'      : "showForm",
                   'Name'      : "showForm",
                   'Type'      : __OPTTYPES.SW,
                   'Type'      : __OPTTYPES.SW,
Zeile 249: Zeile 243:
                   'Permanent' : true,
                   'Permanent' : true,
                   'Default'  : false,
                   'Default'  : false,
                  'Title'    : "$V Optionen",
                   'Action'    : __OPTACTION.NXT,
                   'Action'    : __OPTACTION.NXT,
                   'Label'    : "Optionen anzeigen",
                   'Label'    : "Optionen anzeigen",
                   'Hotkey'    : 'a',
                   'Hotkey'    : 'a',
                  'AltTitle'  : "$V schlie\xDFen",
                   'AltLabel'  : "Optionen verbergen",
                   'AltLabel'  : "Optionen verbergen",
                   'AltHotkey' : 'v',
                   'AltHotkey' : 'v',
Zeile 261: Zeile 253:


// ==================== Invarianter Abschnitt fuer Optionen ====================
// ==================== Invarianter Abschnitt fuer Optionen ====================
// Ein Satz von Logfunktionen, die je nach Loglevel zur Verfuegung stehen. Aufruf: __LOG[level](text)
const __LOG = {
                  'logFun'    : [
                                    console.error,  // [0] Alert
                                    console.error,  // [1] Error
                                    console.log,    // [2] Log: Release
                                    console.log,    // [3] Log: Info
                                    console.log,    // [4] Log: Debug
                                    console.log,    // [5] Log: Verbose
                                    console.log,    // [6] Log: Very verbose
                                    console.log    // [7] Log: Testing
                                ],
                  'init'      : function(win, logLevel = 1) {
                                    for (let level = 0; level < this.logFun.length; level++) {
                                        this[level] = ((level > logLevel) ? function() { } : this.logFun[level]);
                                    }
                                },
                  'stringify' : safeStringify,      // JSON.stringify
                  'changed'  : function(oldVal, newVal) {
                                    const __OLDVAL = this.stringify(oldVal);
                                    const __NEWVAL = this.stringify(newVal);
                                    return ((__OLDVAL !== __NEWVAL) ? __OLDVAL + " => " : "") + __NEWVAL;
                                }
              };
__LOG.init(window, __LOGLEVEL);


// Kompatibilitaetsfunktion zur Ermittlung des Namens einer Funktion (falle <Function>.name nicht vorhanden ist)
// Kompatibilitaetsfunktion zur Ermittlung des Namens einer Funktion (falle <Function>.name nicht vorhanden ist)
Zeile 299: Zeile 263:
}
}


// Ergaenzung fuer Strings: Links oder rechts auffuellen nach Vorlage
// Ein Satz von Logfunktionen, die je nach Loglevel zur Verfuegung stehen. Aufruf: __LOG[level](text)
// padStr: Vorlage, z.B. "00" fuer zweistellige Zahlen
const __LOG = {
// padLeft: true = rechtsbuendig, false = linksbuendig
                  'logFun'  : [
// clip: Abschneiden, falls zu lang
                                  console.error,  // [0] Alert
// return Rechts- oder linksbuendiger String, der so lang ist wie die Vorlage
                                  console.error, // [1] Error
String.prototype.pad = function(padStr, padLeft = true, clip = false) {
                                  console.log,    // [2] Log: Release
    const __LEN = ((clip || (padStr.length > this.length)) ? padStr.length : this.length);
                                  console.log,    // [3] Log: Info
                                  console.log,    // [4] Log: Debug
                                  console.log,   // [5] Log: Verbose
                                  console.log    // [6] Log: Very verbose
                              ],
                  'init'    : function(win, logLevel = 1) {
                                  for (level = 0; level < this.logFun.length; level++) {
                                      this[level] = ((level > logLevel) ? function() { } : this.logFun[level]);
                                  }
                              },
                  'changed'  : function(oldVal, newVal) {
                                  const __OLDVAL = safeStringify(oldVal);
                                  const __NEWVAL = safeStringify(newVal);


    return (padLeft ? String(padStr + this).slice(- __LEN) : String(this + padStr).slice(0, __LEN));
                                  return ((__OLDVAL !== __NEWVAL) ? __OLDVAL + " => " : "") + __NEWVAL;
};
                              }
              };


// Ersetzt in einem String {0}, {1}, ... durch die entsprechenden Parameter
__LOG.init(window, __LOGLEVEL);
// arguments: Parameter, die fuer {0}, {1}, ... eingesetzt werden sollen
// return Resultierender String
String.prototype.format = function() {
    const __ARGS = arguments;
    return this.replace(/{(\d+)}/g, function(match, argIdx) {
                                        const __ARG = __ARGS[argIdx];
                                        return ((__ARG !== undefined) ? __ARG : match);
                                    });
};


// Gibt eine Meldung in der Console aus und oeffnet ein Bestaetigungsfenster mit der Meldung
// Gibt eine Meldung in der Console aus und oeffnet ein Bestaetigungsfenster mit der Meldung
Zeile 325: Zeile 293:
// message: Der Meldungs-Text
// message: Der Meldungs-Text
// data: Ein Wert. Ist er angegeben, wird er in der Console ausgegeben
// data: Ein Wert. Ist er angegeben, wird er in der Console ausgegeben
// return Liefert die Parameter zurueck
function showAlert(label, message, data = undefined) {
function showAlert(label, message, data = undefined) {
     __LOG[0](label + ": " + message);
     __LOG[1](label + ": " + message);


     if (data !== undefined) {
     if (data !== undefined) {
Zeile 334: Zeile 301:


     alert(label + "\n\n" + message);
     alert(label + "\n\n" + message);
    return arguments;
}
// Gibt eine Meldung in der Console aus und oeffnet ein Bestaetigungsfenster
// mit der Meldung zu einer Exception oder einer Fehlermeldung
// label: Eine Ueberschrift
// ex: Exception oder sonstiges Fehlerobjekt
// return Liefert die showAlert()-Parameter zurueck
function showException(label, ex) {
    if (ex && ex.message) {  // Exception
        showAlert(label, ex.message, ex);
    } else {  // sonstiger Fehler
        showAlert(label, ex);
    }
}
// Standard-Callback-Funktion fuer onRejected, also abgefangener Fehler
// in einer Promise bei Exceptions oder Fehler bzw. Rejections
// error: Parameter von reject() im Promise-Objekt, der von Promise.catch() erhalten wurde
// return Liefert die showAlert()-Parameter zurueck
function defaultCatch(error) {
    try {
        const __LABEL = `[${error.lineNumber}] ${__DBMOD.Name}`;
        if (error && error.message) {  // Exception
            return showException(__LABEL, error.message, error);
        } else {
            return showException(__LABEL, error);
        }
    } catch (ex) {
        return showException(`[${ex.lineNumber}] ${__DBMOD.Name}`, ex.message, ex);
    }
}
}


Zeile 400: Zeile 334:


         console.assert((__BASE === null) || ((typeof __BASE) === 'function'), "No function:", __BASE);
         console.assert((__BASE === null) || ((typeof __BASE) === 'function'), "No function:", __BASE);
         console.assert((typeof initFun) === 'function', "Not a function:", initFun);
         console.assert((typeof initFun) === 'function', "No function:", initFun);


         this.init = initFun;
         this.init = initFun;
Zeile 428: Zeile 362:
             const __CREATEPROTO = ((createProto === undefined) ? true : createProto);
             const __CREATEPROTO = ((createProto === undefined) ? true : createProto);


             console.assert((typeof this) === 'function', "Not a function:", this);
             console.assert((typeof this) === 'function');
             console.assert((typeof __MEMBERS) === 'object', "Not an object:", __MEMBERS);
             console.assert((typeof __MEMBERS) === 'object');


             const __CLASS = new Class(this.name || __MEMBERS.__name, baseClass, initFun || __MEMBERS.__init);
             const __CLASS = new Class(this.name || __MEMBERS.__name, baseClass, initFun || __MEMBERS.__init);
Zeile 472: Zeile 406:
                                         return this.className;
                                         return this.className;
                                     }
                                     }
                 });
                 } );


// ==================== Ende Abschnitt fuer Klasse Class ====================
// ==================== Ende Abschnitt fuer Klasse Class ====================
Zeile 519: Zeile 453:
                                     this.home = home;
                                     this.home = home;
                                 }
                                 }
           });
           } );


// ==================== Ende Abschnitt fuer Klasse Delims ====================
// ==================== Ende Abschnitt fuer Klasse Delims ====================
Zeile 598: Zeile 532:
                                     this.node = node;
                                     this.node = node;
                                 }
                                 }
           });
           } );


// ==================== Ende Abschnitt fuer Klasse UriDelims ====================
// ==================== Ende Abschnitt fuer Klasse UriDelims ====================
Zeile 697: Zeile 631:
                                         return __DIRS.slice(1);
                                         return __DIRS.slice(1);
                                     }
                                     }
                 });
                 } );


// ==================== Ende Abschnitt fuer Klasse Path ====================
// ==================== Ende Abschnitt fuer Klasse Path ====================
Zeile 756: Zeile 690:
                                         const __NOSCHEME = this.stripSchemePrefix(path);
                                         const __NOSCHEME = this.stripSchemePrefix(path);
                                         const __INDEXHOST = (__NOSCHEME ? __NOSCHEME.indexOf(__HOSTDELIM) : -1);
                                         const __INDEXHOST = (__NOSCHEME ? __NOSCHEME.indexOf(__HOSTDELIM) : -1);
                                         const __PATH = ((~ __INDEXHOST) ? __NOSCHEME.substring(__INDEXHOST + __HOSTDELIM.length) : __NOSCHEME);
                                         const __PATH = (~ __INDEXHOST) ? __NOSCHEME.substring(__INDEXHOST + __HOSTDELIM.length) : __NOSCHEME;
                                         const __INDEXHOSTPORT = (__PATH ? __PATH.indexOf(__ROOTDELIM) : -1);
                                         const __INDEXHOSTPORT = (__PATH ? __PATH.indexOf(__ROOTDELIM) : -1);
                                         const __HOSTPORT = ((~ __INDEXHOSTPORT) ? __PATH.substring(0, __INDEXHOSTPORT) : undefined);
                                         const __HOSTPORT = (~ __INDEXHOSTPORT) ? __PATH.substring(0, __INDEXHOSTPORT) : undefined;
                                         const __INDEXPORT = (__HOSTPORT ? __HOSTPORT.indexOf(__PORTDELIM) : -1);
                                         const __INDEXPORT = (__HOSTPORT ? __HOSTPORT.indexOf(__PORTDELIM) : -1);
                                         const __HOST = ((~ __INDEXPORT) ? __HOSTPORT.substring(0, __INDEXPORT) : __HOSTPORT);
                                         const __HOST = (~ __INDEXPORT) ? __HOSTPORT.substring(0, __INDEXPORT) : __HOSTPORT;
                                         const __PORT = ((~ __INDEXPORT) ? __HOSTPORT.substring(__INDEXPORT + __PORTDELIM.length) : undefined);
                                         const __PORT = (~ __INDEXPORT) ? __HOSTPORT.substring(__INDEXPORT + __PORTDELIM.length) : undefined;


                                         return {
                                         return {
Zeile 772: Zeile 706:
                                         const __ROOTDELIM = this.delims.root + this.delims.delim;
                                         const __ROOTDELIM = this.delims.root + this.delims.delim;
                                         const __INDEXHOST = (path ? path.indexOf(__HOSTDELIM) : -1);
                                         const __INDEXHOST = (path ? path.indexOf(__HOSTDELIM) : -1);
                                         const __PATH = ((~ __INDEXHOST) ? path.substring(__INDEXHOST + __HOSTDELIM.length) : path);
                                         const __PATH = (~ __INDEXHOST) ? path.substring(__INDEXHOST + __HOSTDELIM.length) : path;
                                         const __INDEXHOSTPORT = (__PATH ? __PATH.indexOf(__ROOTDELIM) : -1);
                                         const __INDEXHOSTPORT = (__PATH ? __PATH.indexOf(__ROOTDELIM) : -1);


                                         return ((~ __INDEXHOSTPORT) ? __PATH.substring(__INDEXHOSTPORT) : __PATH);
                                         return (~ __INDEXHOSTPORT) ? __PATH.substring(__INDEXHOSTPORT) : __PATH;
                                     },
                                     },
               'getSchemePrefix'  : function(path = undefined) {
               'getSchemePrefix'  : function(path = undefined) {
Zeile 781: Zeile 715:
                                         const __INDEXSCHEME = (path ? path.indexOf(__SCHEMEDELIM) : -1);
                                         const __INDEXSCHEME = (path ? path.indexOf(__SCHEMEDELIM) : -1);


                                         return ((~ __INDEXSCHEME) ? path.substring(0, __INDEXSCHEME) : undefined);
                                         return (~ __INDEXSCHEME) ? path.substring(0, __INDEXSCHEME) : undefined;
                                     },
                                     },
               'stripSchemePrefix' : function(path = undefined) {
               'stripSchemePrefix' : function(path = undefined) {
Zeile 787: Zeile 721:
                                         const __INDEXSCHEME = (path ? path.indexOf(__SCHEMEDELIM) : -1);
                                         const __INDEXSCHEME = (path ? path.indexOf(__SCHEMEDELIM) : -1);


                                         return ((~ __INDEXSCHEME) ? path.substring(__INDEXSCHEME + __INDEXSCHEME.length) : path);
                                         return (~ __INDEXSCHEME) ? path.substring(__INDEXSCHEME + __INDEXSCHEME.length) : path;
                                     },
                                     },
               'getNodeSuffix'    : function(path = undefined) {
               'getNodeSuffix'    : function(path = undefined) {
Zeile 793: Zeile 727:
                                         const __INDEXNODE = (path ? path.lastIndexOf(__NODEDELIM) : -1);
                                         const __INDEXNODE = (path ? path.lastIndexOf(__NODEDELIM) : -1);


                                         return ((~ __INDEXNODE) ? path.substring(__INDEXNODE + __NODEDELIM.length) : undefined);
                                         return (~ __INDEXNODE) ? path.substring(__INDEXNODE + __NODEDELIM.length) : undefined;
                                     },
                                     },
               'stripNodeSuffix'  : function(path = undefined) {
               'stripNodeSuffix'  : function(path = undefined) {
Zeile 799: Zeile 733:
                                         const __INDEXNODE = (path ? path.lastIndexOf(__NODEDELIM) : -1);
                                         const __INDEXNODE = (path ? path.lastIndexOf(__NODEDELIM) : -1);


                                         return ((~ __INDEXNODE) ? path.substring(0, __INDEXNODE) : path);
                                         return (~ __INDEXNODE) ? path.substring(0, __INDEXNODE) : path;
                                     },
                                     },
               'getQueryString'    : function(path = undefined) {
               'getQueryString'    : function(path = undefined) {
Zeile 806: Zeile 740:
                                         const __INDEXQUERY = (__PATH ? __PATH.indexOf(__QUERYDELIM) : -1);
                                         const __INDEXQUERY = (__PATH ? __PATH.indexOf(__QUERYDELIM) : -1);


                                         return ((~ __INDEXQUERY) ? __PATH.substring(__INDEXQUERY + __QUERYDELIM.length) : undefined);
                                         return (~ __INDEXQUERY) ? __PATH.substring(__INDEXQUERY + __QUERYDELIM.length) : undefined;
                                     },
                                     },
               'stripQueryString'  : function(path = undefined) {
               'stripQueryString'  : function(path = undefined) {
Zeile 812: Zeile 746:
                                         const __INDEXQUERY = (path ? path.indexOf(__QUERYDELIM) : -1);
                                         const __INDEXQUERY = (path ? path.indexOf(__QUERYDELIM) : -1);


                                         return ((~ __INDEXQUERY) ? path.substring(0, __INDEXQUERY) : path);
                                         return (~ __INDEXQUERY) ? path.substring(0, __INDEXQUERY) : path;
                                     },
                                     },
               'formatParams'      : function(params, formatFun, delim = ' ', assign = '=') {
               'formatParams'      : function(params, formatFun, delim = ' ', assign = '=') {
Zeile 834: Zeile 768:
                                                 if (__PARAM) {
                                                 if (__PARAM) {
                                                     const __INDEX = __PARAM.indexOf(assign);
                                                     const __INDEX = __PARAM.indexOf(assign);
                                                     const __KEY = ((~ __INDEX) ? __PARAM.substring(0, __INDEX) : __PARAM);
                                                     const __KEY = (~ __INDEX) ? __PARAM.substring(0, __INDEX) : __PARAM;
                                                     const __VAL = ((~ __INDEX) ? parseFun(__PARAM.substring(__INDEX + assign.length)) : true);
                                                     const __VAL = (~ __INDEX) ? parseFun(__PARAM.substring(__INDEX + assign.length)) : true;


                                                     __RET[__KEY] = __VAL;
                                                     __RET[__KEY] = __VAL;
Zeile 855: Zeile 789:
                                             const __LOWER = (value ? value.toLowerCase() : undefined);
                                             const __LOWER = (value ? value.toLowerCase() : undefined);


                                             if ((__LOWER === 'true') || (__LOWER === 'false')) {
                                             if ((__LOWER === "true") || (__LOWER === "false")) {
                                                 return (value === 'true');
                                                 return (value === "true");
                                             }
                                             }
                                         }
                                         }
Zeile 908: Zeile 842:
                                         return Path.prototype.getDirs.call(this, __PATH);
                                         return Path.prototype.getDirs.call(this, __PATH);
                                     }
                                     }
           });
           } );


// ==================== Ende Abschnitt fuer Klasse URI ====================
// ==================== Ende Abschnitt fuer Klasse URI ====================
Zeile 948: Zeile 882:
                                   return this.getPath();
                                   return this.getPath();
                               }
                               }
                 });
                 } );


// ==================== Ende Abschnitt fuer Klasse Directory ====================
// ==================== Ende Abschnitt fuer Klasse Directory ====================
Zeile 976: Zeile 910:
                                     return ret;
                                     return ret;
                                 }
                                 }
                 });
                 } );


// ==================== Ende Abschnitt fuer Klasse ObjRef ====================
// ==================== Ende Abschnitt fuer Klasse ObjRef ====================
Zeile 1.021: Zeile 955:


// Gibt ein Produkt zurueck. Ist einer der Multiplikanten nicht definiert, wird ein Alternativwert geliefert
// Gibt ein Produkt zurueck. Ist einer der Multiplikanten nicht definiert, wird ein Alternativwert geliefert
// valueA: Ein Multiplikant. Ist dieser undefined, wird als Produkt defValue zurueckgeliefert
// valueA: Ein Multipliksnt. Ist dieser undefined, wird als Produkt defValue zurueckgeliefert
// valueB: Ein Multiplikant. Ist dieser undefined, wird als Produkt defValue zurueckgeliefert
// valueB: Ein Multipliksnt. Ist dieser undefined, wird als Produkt defValue zurueckgeliefert
// digits: Anzahl der Stellen nach dem Komma fuer das Produkt (Default: 0)
// digits: Anzahl der Stellen nach dem Komma fuer das Produkt (Default: 0)
// defValue: Default-Wert fuer den Fall, dass ein Multiplikant nicht gesetzt ist (Default: NaN)
// defValue: Default-Wert fuer den Fall, dass ein Multiplikant nicht gesetzt ist (Default: NaN)
Zeile 1.031: Zeile 965:
     if ((valueA !== undefined) && (valueB !== undefined)) {
     if ((valueA !== undefined) && (valueB !== undefined)) {
         product = parseFloat(valueA) * parseFloat(valueB);
         product = parseFloat(valueA) * parseFloat(valueB);
    }
    if (isNaN(product)) {
        product = defValue;
     }
     }


Zeile 1.040: Zeile 970:
}
}


// Gibt eine Ordinalzahl zur uebergebenen Zahl zurueck
// Ueberprueft, ob ein Objekt einer bestimmten Klasse angehoert (ggfs. per Vererbung)
// value: Eine ganze Zahl
// defValue: Default-Wert fuer den Fall, dass der Wert nicht gesetzt ist (Default: '*')
// return Die Ordinalzahl als String der Form "n." oder defValue, falls nicht angegeben
function getOrdinal(value, defValue = '*') {
    return getValue(value, defValue, value + '.');
}
 
// Hilfsfunktion fuer Array.sort(): Vergleich zweier Zahlen
// valueA: Erster Zahlenwert
// valueB: Zweiter Zahlenwert
// return -1 = kleiner, 0 = gleich, +1 = groesser
function compareNumber(valueA, valueB) {
    return +(valueA > valueB) || (+(valueA === valueB) - 1);
}
 
// Ueberprueft, ob ein Objekt einer bestimmten Klasse angehoert (ggfs. per Vererbung)
// obj: Ein (generisches) Objekt
// obj: Ein (generisches) Objekt
// base: Eine Objektklasse (Konstruktor-Funktion)
// base: Eine Objektklasse (Konstruktor-Funktion)
Zeile 1.062: Zeile 976:
function instanceOf(obj, base) {
function instanceOf(obj, base) {
     while (obj !== null) {
     while (obj !== null) {
         if (obj === base.prototype) {
         if (obj === base.prototype)
             return true;
             return true;
        }
         if ((typeof obj) === 'xml') {  // Sonderfall mit Selbstbezug
         if ((typeof obj) === 'xml') {  // Sonderfall mit Selbstbezug
             return (base.prototype === XML.prototype);
             return (base.prototype === XML.prototype);
Zeile 1.114: Zeile 1.027:
     let active = true;
     let active = true;


     if (inList) {
     if (inList !== undefined) {
         active = (inList[item] === true);  // gesetzt und true
         active = (inList[item] === true);  // gesetzt und true
     }
     }
     if (exList) {
     if (exList !== undefined) {
         if (exList[item] === true) {  // gesetzt und true
         if (exList[item] === true) {  // gesetzt und true
             active = false;  // NICHT anzeigen
             active = false;  // NICHT anzeigen
Zeile 1.136: Zeile 1.049:
         if (checkItem(item, addList, ignList)) {
         if (checkItem(item, addList, ignList)) {
             data[item] = addData[item];
             data[item] = addData[item];
        }
    }
    return data;
}
// Entfernt Properties in einem Objekt
// data: Objekt, deren Properties bearbeitet werden
// delList: Checkliste der zu loeschenden Items (true fuer loeschen), falls angegeben
// ignList: Checkliste der ignorierten Items (true fuer auslassen), falls angegeben
// return Das veraenderte Objekt ohne die geloeschten Properties
function delProps(data, delList = undefined, ignList = undefined) {
    for (let item in getValue(data, { })) {
        if (checkItem(item, delList, ignList)) {
            delete data[item];
         }
         }
     }
     }
Zeile 1.232: Zeile 1.130:
}
}


// Replacer fuer JSON.stringify() oder safeStringify(), der Arrays kompakter darstellt
// Speichert einen beliebiegen (strukturierten) Wert unter einem Namen ab
// key: Der uebergebene Schluessel
// name: GM_setValue-Name, unter dem die Daten gespeichert werden
// value: Der uebergebene Wert
// value: Beliebiger (strukturierter) Wert
// return Fuer Arrays eine kompakte Darstellung, sonst derselbe Wert
// return String-Darstellung des Wertes
function replaceArraySimple(key, value) {
function serialize(name, value) {
     if (Array.isArray(value)) {
     const __STREAM = (value !== undefined) ? safeStringify(value) : value;
        return "[ " + value.join(", ") + " ]";
    }
 
    return value;
}


// Replacer fuer JSON.stringify() oder safeStringify(), der Arrays kompakter darstellt
     __LOG[4](name + " >> " + __STREAM);
// key: Der uebergebene Schluessel
// value: Der uebergebene Wert
// return Fuer Arrays eine kompakte Darstellung, sonst derselbe Wert
function replaceArray(key, value) {
     if (Array.isArray(value)) {
        __RET = value.map(function(element) {
                              return safeStringify(element, replaceArray, 0);
                          });


        return __RET;
    GM_setValue(name, __STREAM);
    }


     return value;
     return __STREAM;
}
}


// Moegliche einfache Ersetzungen mit '$'...
// Holt einen beliebiegen (strukturierter) Wert unter einem Namen zurueck
let textSubst;
// name: GM_setValue-Name, unter dem die Daten gespeichert werden
// defValue: Default-Wert fuer den Fall, dass nichts gespeichert ist
// return Objekt, das unter dem Namen gespeichert war
function deserialize(name, defValue = undefined) {
    const __STREAM = GM_getValue(name, defValue);


// Substituiert '$'-Parameter in einem Text
     __LOG[4](name + " << " + __STREAM);
// text: Urspruenglicher Text mit '$'-Befehlen
// par1: Der (erste) uebergebene Parameter
// return Fuer Arrays eine kompakte Darstellung, sonst derselbe Wert
function substParam(text, par1) {
     let ret = getValue(text, "");


     if (! textSubst) {
     if ((__STREAM !== undefined) && __STREAM.length) {
         textSubst  = {
         try {
                'n' : __DBMOD.name,
            return JSON.parse(__STREAM);
                'v' : __DBMOD.version,
        } catch (ex) {
                'V' : __DBMOD.Name
            __LOG[1](name + ": " + ex.message);
            };
        }
     }
     }


     for (let ch in textSubst) {
     return undefined;
        const __SUBST = textSubst[ch];
}


         ret = ret.replace('$' + ch, __SUBST);
// Setzt eine Option dauerhaft und laedt die Seite neu
// name: Name der Option als Speicherort
// value: Zu setzender Wert
// reload: Seite mit neuem Wert neu laden
// return Gespeicherter Wert fuer setOptValue()
function setStored(name, value, reload = false, serial = false) {
    if (serial) {
        serialize(name, value);
    } else {
         GM_setValue(name, value);
     }
     }


    return ret.replace('$', par1);
     if (reload) {
}
         window.location.reload();
 
// Fuegt in die uebergebene Zahl Tausender-Trennpunkte ein
// Wandelt einen etwaig vorhandenen Dezimalpunkt in ein Komma um
// numberString: Dezimalzahl als String
// return Diese Dezimalzahl als String mit Tausender-Trennpunkten und Komma statt Dezimalpunkt
function getNumberString(numberString) {
     if (numberString.lastIndexOf('.') !== -1) {
        // Zahl enthaelt Dezimalpunkt
        const __VORKOMMA = numberString.substring(0, numberString.lastIndexOf('.'));
        const __NACHKOMMA = numberString.substring(numberString.lastIndexOf('.') + 1, numberString.length);
 
        return getNumberString(__VORKOMMA) + ',' + __NACHKOMMA;
    } else {
         // Kein Dezimalpunkt, fuege Tausender-Trennpunkte ein:
        // String umdrehen, nach jedem dritten Zeichen Punkt einfuegen, dann wieder umdrehen:
        const __TEMP = reverseString(numberString);
        let result = "";
 
        for (let i = 0; i < __TEMP.length; i++) {
            if ((i > 0) && (i % 3 === 0)) {
                result += '.';
            }
            result += __TEMP.substr(i, 1);
        }
 
        return reverseString(result);
     }
     }
}


// Dreht den uebergebenen String um
     return value;
// string: Eine Zeichenkette
// return Dieselbe Zeichenkette rueckwaerts
function reverseString(string) {
    let result = "";
 
    for (let i = string.length - 1; i >= 0; i--) {
        result += string.substr(i, 1);
    }
 
     return result;
}
}


// Speichert einen String/Integer/Boolean-Wert unter einem Namen ab
// Setzt den naechsten Wert aus einer Array-Liste als Option
// name: GM.setValue()-Name, unter dem die Daten gespeichert werden
// arr: Array-Liste mit den moeglichen Optionen
// value: Zu speichernder String/Integer/Boolean-Wert
// name: Name der Option als Speicherort
// return Promise auf ein Objekt, das 'name' und 'value' der Operation enthaelt
// value: Vorher gesetzter Wert
function storeValue(name, value) {
// reload: Seite mit neuem Wert neu laden
    __LOG[4](name + " >> " + value);
// return Gespeicherter Wert fuer setOptValue()
 
function setNextStored(arr, name, value, reload = false, serial = false) {
     return GM.setValue(name, value).then(voidValue => {
     return setStored(name, getNextValue(arr, value), reload, serial);
            __LOG[5]("OK " + name + " >> " + value);
 
            return Promise.resolve({
                    'name'  : name,
                    'value' : value
                });
        }, defaultCatch);
}
}


// Holt einen String/Integer/Boolean-Wert unter einem Namen zurueck
// Fuehrt die in einem Storage gespeicherte Operation aus
// name: GM.getValue()-Name, unter dem die Daten gespeichert wurden
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
// defValue: Default-Wert fuer den Fall, dass nichts gespeichert ist
// return Array von Objekten mit 'cmd' / 'key' / 'val' (derzeit maximal ein Kommando) oder undefined
// return Promise fuer den String/Integer/Boolean-Wert, der unter dem Namen gespeichert war
function getStoredCmds(memory = undefined) {
function summonValue(name, defValue = undefined) {
     const __STORAGE = getMemory(memory);
     return GM.getValue(name, defValue).then(value => {
    const __MEMORY = __STORAGE.Value;
            __LOG[4](name + " << " + value);
    const __RUNPREFIX = __STORAGE.Prefix;
    const __STOREDCMDS = [];


            return Promise.resolve(value);
    if (__MEMORY !== undefined) {
         }, ex => {
        const __GETITEM = function(item) {
            __LOG[0](name + ": " + ex.message);
                              return __MEMORY.getItem(__RUNPREFIX + item);
                          };
         const __DELITEM = function(item) {
                              return __MEMORY.removeItem(__RUNPREFIX + item);
                          };
        const __CMD = ((__MEMORY !== undefined) ? __GETITEM('cmd') : undefined);


             return Promise.reject(ex);
        if (__CMD !== undefined) {
        }, defaultCatch);
             const __KEY = __GETITEM('key');
}
            let value = __GETITEM('val');


// Speichert einen beliebiegen (strukturierten) Wert unter einem Namen ab
            try {
// name: GM.setValue()-Name, unter dem die Daten gespeichert werden
                value = JSON.parse(value);
// value: Beliebiger (strukturierter) Wert
            } catch (ex) {
// return Promise auf ein Objekt, das 'name' und 'value' in der String-Darstellung des Wertes enthaelt
                __LOG[1]("getStoredCmds(): " + __CMD + " '" + __KEY + "' hat illegalen Wert '" + value + "'");
function serialize(name, value) {
                // ... meist kann man den String selber aber speichern, daher kein "return"...
    const __STREAM = ((value !== undefined) ? safeStringify(value) : value);
            }


    return storeValue(name, __STREAM);
            __STOREDCMDS.push({
}
                                'cmd' : __CMD,
                                'key' : __KEY,
                                'val' : value
                            });
        }


// Holt einen beliebiegen (strukturierter) Wert unter einem Namen zurueck
        __DELITEM('cmd');
// name: GM.getValue()-Name, unter dem die Daten gespeichert wurden
        __DELITEM('key');
// defValue: Default-Wert fuer den Fall, dass nichts gespeichert ist
         __DELITEM('val');
// return Promise fuer das Objekt, das unter dem Namen gespeichert war
    }
function deserialize(name, defValue = undefined) {
    return summonValue(name).then(stream => {
            if (stream && stream.length) {
                return JSON.parse(stream);
            } else {
                return defValue;
            }
         });
}


// Setzt die Seite gemaess der Aenderungen zurueck...
     return (__STOREDCMDS.length ? __STOREDCMDS : undefined);
// reload: Seite wird ganz neu geladen
function refreshPage(reload = true) {
     if (reload) {
        __LOG[2]("Seite wird neu geladen...");
        window.location.reload();
    }
}
}


// Setzt eine Option dauerhaft und laedt die Seite neu
// Fuehrt die in einem Storage gespeicherte Operation aus
// name: Name der Option als Speicherort
// storedCmds: Array von Objekten mit 'cmd' / 'key' / 'val' (siehe getStoredCmds())
// value: Zu setzender Wert
// optSet: Set mit den Optionen
// reload: Seite mit neuem Wert neu laden
// beforeLoad: Angabe, ob nach der Speicherung noch loadOptions() aufgerufen wird
// serial: Serialization fuer komplexe Daten
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
// onFulfilled: Reaktion auf Speicherung im resolve-Fall (1. Promise.then()-Parameter)
// return Array von Operationen (wie storedCmds), die fuer die naechste Phase uebrig bleiben
// onRejected: Reaktion auf Speicherung im reject-Fall (2. Promise.then()-Parameter)
function runStoredCmds(storedCmds, optSet = undefined, beforeLoad = undefined) {
// return Gespeicherter Wert fuer setOptValue()
     const __BEFORELOAD = getValue(beforeLoad, true);
function setStored(name, value, reload = false, serial = false, onFulfilled = undefined, onRejected = undefined) {
    const __STOREDCMDS = getValue(storedCmds, []);
     (serial ? serialize(name, value)
    const __LOADEDCMDS = [];
            : storeValue(name, value))
    let invalidated = false;
                .then(onFulfilled, onRejected)
                .then(() => refreshPage(reload), defaultCatch); // Ende der Kette...


     return value;
     while (__STOREDCMDS.length) {
}
        const __STORED = __STOREDCMDS.shift();
        const __CMD = __STORED.cmd;
        const __KEY = __STORED.key;
        const __VAL = __STORED.val;


// Setzt den naechsten Wert aus einer Array-Liste als Option
        if (__BEFORELOAD) {
// arr: Array-Liste mit den moeglichen Optionen
            if (__STOREDCMDS.length) {
// name: Name der Option als Speicherort
                invalidateOpts(optSet);  // alle Optionen invalidieren
// value: Vorher gesetzter Wert
                invalidated = true;
// reload: Seite mit neuem Wert neu laden
            }
// serial: Serialization fuer komplexe Daten
            switch (__OPTACTION[__CMD]) {
// onFulfilled: Reaktion auf Speicherung im resolve-Fall (1. Promise.then()-Parameter)
            case __OPTACTION.SET : __LOG[4]("SET '" + __KEY + "' " + __VAL);
// onRejected: Reaktion auf Speicherung im reject-Fall (2. Promise.then()-Parameter)
                                  setStored(__KEY, __VAL, false, false);
// return Gespeicherter Wert fuer setOptValue()
                                  break;
function setNextStored(arr, name, value, reload = false, serial = false, onFulfilled = undefined, onRejected = undefined) {
            case __OPTACTION.NXT : __LOG[4]("SETNEXT '" + __KEY + "' " + __VAL);
    return setStored(name, getNextValue(arr, value), reload, serial, onFulfilled, onRejected);
                                  //setNextStored(__CONFIG.Choice, __KEY, __VAL, false, false);
}
                                  setStored(__KEY, __VAL, false, false);
 
                                  break;
// Fuehrt die in einem Storage gespeicherte Operation aus
            case __OPTACTION.RST : __LOG[4]("RESET (delayed)");
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
                                  __LOADEDCMDS.push(__STORED);
// return Array von Objekten mit 'cmd' / 'key' / 'val' (derzeit maximal ein Kommando) oder undefined
                                  break;
function getStoredCmds(memory = undefined) {
            default :              break;
    const __STORAGE = getMemory(memory);
            }
    const __MEMORY = __STORAGE.Value;
        } else {
    const __RUNPREFIX = __STORAGE.Prefix;
            switch (__OPTACTION[__CMD]) {
     const __STOREDCMDS = [];
            case __OPTACTION.SET :
            case __OPTACTION.NXT : __LOG[2]("SET/SETNEXT (undefined)");
                                  break;
            case __OPTACTION.RST : __LOG[4]("RESET");
                                  resetOptions(optSet, false);
                                  loadOptions(optSet); // Reset auf umbenannte Optionen anwenden!
                                  break;
            default :              break;
            }
        }
     }


     if (__MEMORY !== undefined) {
     return (__LOADEDCMDS.length ? __LOADEDCMDS : undefined);
        const __GETITEM = function(item) {
}
                              return __MEMORY.getItem(__RUNPREFIX + item);
                          };
        const __DELITEM = function(item) {
                              return __MEMORY.removeItem(__RUNPREFIX + item);
                          };
        const __CMD = ((__MEMORY !== undefined) ? __GETITEM('cmd') : undefined);


        if (__CMD !== undefined) {
// Gibt eine Option sicher zurueck
            const __KEY = __GETITEM('key');
// opt: Config und Value der Option, ggfs. undefined
            let value = __GETITEM('val');
// defOpt: Rueckgabewert, falls undefined
// return Daten zur Option (oder defOpt)
function getOpt(opt, defOpt = { }) {
    return getValue(opt, defOpt);
}


            try {
// Gibt eine Option sicher zurueck (Version mit Key)
                value = JSON.parse(value);
// optSet: Platz fuer die gesetzten Optionen (und Config)
            } catch (ex) {
// item: Key der Option
                __LOG[0]("getStoredCmds(): " + __CMD + " '" + __KEY + "' hat illegalen Wert '" + value + "'");
// defOpt: Rueckgabewert, falls nicht zu finden
                // ... meist kann man den String selber aber speichern, daher kein "return"...
// return Daten zur Option (oder defOpt)
            }
function getOptByName(optSet, item, defOpt = { }) {
 
    if ((optSet !== undefined) && (item !== undefined)) {
            __STOREDCMDS.push({
         return getOpt(optSet[item], defOpt);
                                'cmd' : __CMD,
    } else {
                                'key' : __KEY,
         return defOpt;
                                'val' : value
                            });
        }
 
        __DELITEM('cmd');
         __DELITEM('key');
         __DELITEM('val');
     }
     }
}


     return (__STOREDCMDS.length ? __STOREDCMDS : undefined);
// Gibt die Konfigurationsdaten einer Option zurueck
// opt: Config und Value der Option
// defConfig: Rueckgabewert, falls Config nicht zu finden
// return Konfigurationsdaten der Option
function getOptConfig(opt, defConfig = { }) {
     return getValue(getOpt(opt).Config, defConfig);
}
}


// Fuehrt die in einem Storage gespeicherte Operation aus
// Setzt den Namen einer Option
// storedCmds: Array von Objekten mit 'cmd' / 'key' / 'val' (siehe getStoredCmds())
// opt: Config und Value der Option
// optSet: Object mit den Optionen
// name: Zu setzender Name der Option
// beforeLoad: Angabe, ob nach der Speicherung noch loadOptions() aufgerufen wird
// reload: Seite mit neuem Wert neu laden
// onFulfilled: Reaktion auf Speicherung im resolve-Fall (1. Promise.then()-Parameter)
// return Gesetzter Name der Option
// onRejected: Reaktion auf Speicherung im reject-Fall (2. Promise.then()-Parameter)
function setOptName(opt, name) {
// return Promise auf ein Array von Operationen (wie storedCmds), die fuer die naechste Phase uebrig bleiben
     const __CONFIG = getOptConfig(opt);
async function runStoredCmds(storedCmds, optSet = undefined, beforeLoad = undefined, onFulfilled = undefined, onRejected = undefined) {
     const __NAME = getOptName(opt);
     const __BEFORELOAD = getValue(beforeLoad, true);
 
     const __STOREDCMDS = getValue(storedCmds, []);
     if (__NAME !== name) {
     const __LOADEDCMDS = [];
        __LOG[4]("RENAME " + __NAME + " => " + name);
    let invalidated = false;
 
        __CONFIG.Name = name;
    }


     while (__STOREDCMDS.length) {
     return name;
        const __STORED = __STOREDCMDS.shift();
}
        const __CMD = __STORED.cmd;
        const __KEY = __STORED.key;
        const __VAL = __STORED.val;


        if (__BEFORELOAD) {
// Gibt den Namen einer Option zurueck
            if (__STOREDCMDS.length) {
// opt: Config und Value der Option
                await invalidateOpts(optSet);  // alle Optionen invalidieren
// return Name der Option
                invalidated = true;
function getOptName(opt) {
            }
    const __CONFIG = getOptConfig(opt);
            switch (__OPTACTION[__CMD]) {
    const __NAME = __CONFIG.Name;
            case __OPTACTION.SET : __LOG[4]("SET '" + __KEY + "' " + __VAL);
 
                                  setStored(__KEY, __VAL, false, false, onFulfilled, onRejected);
    if (! __NAME) {
                                  break;
        const __SHARED = __CONFIG.Shared;
            case __OPTACTION.NXT : __LOG[4]("SETNEXT '" + __KEY + "' " + __VAL);
 
                                  //setNextStored(__CONFIG.Choice, __KEY, __VAL, false, false, onFulfilled, onRejected);
        if (__SHARED && ! opt.Loaded) {
                                  setStored(__KEY, __VAL, false, false, onFulfilled, onRejected);
             const __OBJREF = getSharedRef(__SHARED, opt.Item);
                                  break;
 
            case __OPTACTION.RST : __LOG[4]("RESET (delayed)");
             return __OBJREF.getPath();
                                  __LOADEDCMDS.push(__STORED);
                                  break;
            default :              break;
            }
        } else {
             switch (__OPTACTION[__CMD]) {
            case __OPTACTION.SET :
            case __OPTACTION.NXT : __LOG[2]("SET/SETNEXT (undefined)");
                                  break;
             case __OPTACTION.RST : __LOG[4]("RESET");
                                  await resetOptions(optSet, false);
                                  await loadOptions(optSet); // Reset auf umbenannte Optionen anwenden!
                                  break;
            default :              break;
            }
         }
         }
        showAlert("Error", "Option ohne Namen", safeStringify(__CONFIG));
     }
     }


     return (__LOADEDCMDS.length ? __LOADEDCMDS : undefined);
     return __NAME;
}
}


// Gibt eine Option sicher zurueck
// Setzt den Wert einer Option
// opt: Config und Value der Option, ggfs. undefined
// opt: Config und Value der Option
// defOpt: Rueckgabewert, falls undefined
// name: Zu setzender Wert der Option
// return Daten zur Option (oder defOpt)
// return Gesetzter Wert
function getOpt(opt, defOpt = { }) {
function setOptValue(opt, value) {
    return getValue(opt, defOpt);
    if (opt !== undefined) {
}
        if (! opt.ReadOnly) {
            __LOG[6](getOptName(opt) + ": " + __LOG.changed(opt.Value, value));


// Gibt eine Option sicher zurueck (Version mit Key)
            opt.Value = value;
// optSet: Platz fuer die gesetzten Optionen (und Config)
        }
// item: Key der Option
         return opt.Value;
// defOpt: Rueckgabewert, falls nicht zu finden
// return Daten zur Option (oder defOpt)
function getOptByName(optSet, item, defOpt = { }) {
    if ((optSet !== undefined) && (item !== undefined)) {
         return getOpt(optSet[item], defOpt);
     } else {
     } else {
         return defOpt;
         return undefined;
     }
     }
}
}


// Gibt die Konfigurationsdaten einer Option zurueck
// Gibt den Wert einer Option zurueck
// opt: Config und Value der Option
// opt: Config und Value der Option
// defConfig: Rueckgabewert, falls Config nicht zu finden
// defValue: Default-Wert fuer den Fall, dass nichts gesetzt ist
// return Konfigurationsdaten der Option
// load: Laedt die Option per loadOption(), falls noetig
function getOptConfig(opt, defConfig = { }) {
// force: Laedt auch Optionen mit 'AutoReset'-Attribut
     return getValue(getOpt(opt).Config, defConfig);
// return Gesetzter Wert
}
function getOptValue(opt, defValue = undefined, load = true, force = false) {
     let value;


// Setzt den Namen einer Option
    if (opt !== undefined) {
// opt: Config und Value der Option
        if (load && ! opt.Loaded) {
// name: Zu setzender Name der Option
            value = loadOption(opt, force);
// reload: Seite mit neuem Wert neu laden
        } else {
// return Gesetzter Name der Option
            value = opt.Value;
function setOptName(opt, name) {
         }
    const __CONFIG = getOptConfig(opt);
    const __NAME = getOptName(opt);
 
    if (__NAME !== name) {
        __LOG[4]("RENAME " + __NAME + " => " + name);
 
         __CONFIG.Name = name;
     }
     }


     return name;
     return valueOf(getValue(value, defValue));
}
}


// Gibt den Namen einer Option zurueck
// ==================== Ende Abschnitt fuer diverse Utilities ====================
// opt: Config und Value der Option
// return Name der Option
function getOptName(opt) {
    const __CONFIG = getOptConfig(opt);
    const __NAME = __CONFIG.Name;


    if (! __NAME) {
// ==================== Abschnitt fuer Speicher und die Scriptdatenbank ====================
        const __SHARED = __CONFIG.Shared;


        if (__SHARED && ! opt.Loaded) {
// Namen des Default-, Temporaer- und Null-Memories...
            const __OBJREF = getSharedRef(__SHARED, opt.Item);
const __MEMNORMAL  = 'normal';
const __MEMSESSION  = 'begrenzt';
const __MEMINAKTIVE = 'inaktiv';


            return __OBJREF.getPath();
// Definition des Default-, Dauer- und Null-Memories...
        }
const __OPTMEMNORMAL  = __OPTMEM[__MEMNORMAL];
const __OPTMEMSESSION  = __OPTMEM[__MEMSESSION];
const __OPTMEMINAKTIVE = __OPTMEM[__MEMINAKTIVE];


        showAlert("Error", "Option ohne Namen", safeStringify(__CONFIG));
// Medium fuer die Datenbank (Speicher)
    }
let myOptMem = __OPTMEMNORMAL;
let myOptMemSize;
 
// Infos ueber dieses Script-Modul
const __DBMOD = new ScriptModule();
 
// Inhaltsverzeichnis der DB-Daten (indiziert durch die Script-Namen)
const __DBTOC = { };


    return __NAME;
// Daten zu den Modulen (indiziert durch die Script-Namen)
}
const __DBDATA = { };


// Setzt den Wert einer Option
// ==================== Abschnitt fuer Speicher ====================
// opt: Config und Value der Option
// name: Zu setzender Wert der Option
// return Gesetzter Wert
function setOptValue(opt, value) {
    if (opt !== undefined) {
        if (! opt.ReadOnly) {
            __LOG[6](getOptName(opt) + ": " + __LOG.changed(opt.Value, value));


            opt.Value = value;
// Ermittelt fuer die uebergebene Speicher-Konfiguration einen Speicher
        }
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
        return opt.Value;
// defMemory: Ersatz-Wert, falls memory undefined. Soll nur memory genutzt werden, dann z.B. null uebergeben!
    } else {
// return memory, falls okay, sonst einen Defaultwert
        return undefined;
function getMemory(memory = undefined, defMemory = getValue(myOptMem, __OPTMEMNORMAL)) {
    }
    return getValue(memory, defMemory);
}
}


// Gibt den Wert einer Option zurueck
// Kompatibilitaetsfunktion: Testet, ob der uebergebene Speicher genutzt werden kann
// opt: Config und Value der Option
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
// defValue: Default-Wert fuer den Fall, dass nichts gesetzt ist
// return true, wenn der Speichertest erfolgreich war
// load: Laedt die Option per loadOption(), falls noetig
function canUseMemory(memory = undefined) {
// force: Laedt auch Optionen mit 'AutoReset'-Attribut
    const __STORAGE = getMemory(memory, { });
// return Gesetzter Wert
    const __MEMORY = __STORAGE.Value;
function getOptValue(opt, defValue = undefined, load = true, asyncLoad = false, force = false) {
    let ret = false;
    let value;
 
    if (__MEMORY !== undefined) {
        const __TESTPREFIX = 'canUseStorageTest';
        const __TESTDATA = Math.random().toString();
        const __TESTITEM = __TESTPREFIX + __TESTDATA;


    if (opt !== undefined) {
         __MEMORY.setItem(__TESTITEM, __TESTDATA);
         if (load && ! opt.Loaded) {
        ret = (__MEMORY.getItem(__TESTITEM) === __TESTDATA);
            if (! opt.Promise) {
         __MEMORY.removeItem(__TESTITEM);
                loadOption(opt, force);
            }
            if (! asyncLoad) {
                __LOG[0]("Warnung: getOptValue(" + getOptName(opt) + ") fordert zum Nachladen auf, daher nur Default-Wert!");
            }
         } else {
            value = opt.Value;
        }
     }
     }


     return valueOf(getValue(value, defValue));
     __LOG[2]("canUseStorage(" + __STORAGE.Name + ") = " + ret);
 
    return ret;
}
}


// ==================== Ende Abschnitt fuer diverse Utilities ====================
// Ermittelt die Groesse des benutzten Speichers
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
// return Groesse des genutzten Speichers in Bytes
function getMemSize(memory = undefined) {
    const __STORAGE = getMemory(memory);
    const __MEMORY = __STORAGE.Value;


// ==================== Abschnitt fuer Speicher und die Scriptdatenbank ====================
    //getMemUsage(__MEMORY);


// Namen des Default-, Temporaer- und Null-Memories...
    if (__MEMORY !== undefined) {
const __MEMNORMAL  = 'normal';
        const __SIZE = safeStringify(__MEMORY).length;
const __MEMSESSION  = 'begrenzt';
const __MEMINAKTIVE = 'inaktiv';


// Definition des Default-, Dauer- und Null-Memories...
        __LOG[2]("MEM: " + __SIZE + " bytes");
const __OPTMEMNORMAL  = __OPTMEM[__MEMNORMAL];
        return __SIZE;
const __OPTMEMSESSION  = __OPTMEM[__MEMSESSION];
    } else {
const __OPTMEMINAKTIVE = __OPTMEM[__MEMINAKTIVE];
        return 0;
    }
}


// Medium fuer die Datenbank (Speicher)
// Gibt rekursiv und detailliert die Groesse des benutzten Speichers fuer ein Objekt aus
let myOptMem = __OPTMEMNORMAL;
// value: (Enumerierbares) Objekt oder Wert, dessen Groesse gemessen wird
let myOptMemSize;
// out: Logfunktion, etwa console.log
// depth: Gewuenschte Rekursionstiefe (0 = nur dieses Objekt, -1 = alle Ebenen)
// name: Name des Objekts
function getMemUsage(value = undefined, out = undefined, depth = -1, name = '$') {
    const __OUT = (out || __LOG[4]);


// Infos ueber dieses Script-Modul
    if ((typeof value) === 'string') {
const __DBMOD = new ScriptModule();
        const __SIZE = value.length;


// Inhaltsverzeichnis der DB-Daten (indiziert durch die Script-Namen)
        __OUT("USAGE: " + name + '\t' + __SIZE + '\t' + value.substr(0, 255));
const __DBTOC = { };
    } else if ((typeof value) === 'object') {
        if (depth === 0) {
            const __SIZE = safeStringify(value).length;


// Daten zu den Modulen (indiziert durch die Script-Namen)
            __OUT("USAGE: " + name + '\t' + __SIZE);
const __DBDATA = { };
        } else {
            depth--;
            for (let sub in value) {
                getMemUsage(value[sub], __OUT, depth, name + '.' + sub);
            }
            getMemUsage(value, __OUT, 0, name);
        }
    } else {
      const __DATA = (((typeof value) === 'function') ? "" : '\t' + value);


// ==================== Abschnitt fuer Speicher ====================
        __OUT("USAGE: " + name + '\t' + (typeof value) + __DATA);
 
     }
// Ermittelt fuer die uebergebene Speicher-Konfiguration einen Speicher
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
// defMemory: Ersatz-Wert, falls memory undefined. Soll nur memory genutzt werden, dann z.B. null uebergeben!
// return memory, falls okay, sonst einen Defaultwert
function getMemory(memory = undefined, defMemory = getValue(myOptMem, __OPTMEMNORMAL)) {
     return getValue(memory, defMemory);
}
}


// Kompatibilitaetsfunktion: Testet, ob der uebergebene Speicher genutzt werden kann
// Restauriert den vorherigen Speicher (der in einer Option definiert ist)
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
// opt: Option zur Wahl des Speichers
// return true, wenn der Speichertest erfolgreich war
// return Gesuchter Speicher oder Null-Speicher ('inaktiv')
function canUseMemory(memory = undefined) {
function restoreMemoryByOpt(opt) {
     const __STORAGE = getMemory(memory, { });
    // Memory Storage fuer vorherige Speicherung...
    const __MEMORY = __STORAGE.Value;
     const __STORAGE = getOptValue(opt, __MEMNORMAL, true, true);
    let ret = false;


     if (__MEMORY !== undefined) {
     return __OPTMEM[__STORAGE];
        const __TESTPREFIX = 'canUseStorageTest';
}
        const __TESTDATA = Math.random().toString();
        const __TESTITEM = __TESTPREFIX + __TESTDATA;


        __MEMORY.setItem(__TESTITEM, __TESTDATA);
// Initialisiert den Speicher (der in einer Option definiert ist) und merkt sich diesen ggfs.
        ret = (__MEMORY.getItem(__TESTITEM) === __TESTDATA);
// opt: Option zur Wahl des Speichers
         __MEMORY.removeItem(__TESTITEM);
// saveOpt: Option zur Speicherung der Wahl des Speichers (fuer restoreMemoryByOpt)
// return Gesuchter Speicher oder Null-Speicher ('inaktiv'), falls speichern nicht moeglich ist
function startMemoryByOpt(opt, saveOpt = undefined) {
    // Memory Storage fuer naechste Speicherung...
    let storage = getOptValue(opt, __MEMNORMAL);
    let optMem = __OPTMEM[storage];
 
    if (! canUseMemory(optMem)) {
        if (storage !== __MEMINAKTIVE) {
            storage = __MEMINAKTIVE;
            optMem = __OPTMEM[storage];
         }
     }
     }


     __LOG[2]("canUseStorage(" + __STORAGE.Name + ") = " + ret);
     if (saveOpt !== undefined) {
        setOpt(saveOpt, storage, false);
    }


     return ret;
     return optMem;
}
}


// Ermittelt die Groesse des benutzten Speichers
// ==================== Ende Abschnitt fuer Speicher ====================
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
// return Groesse des genutzten Speichers in Bytes
function getMemSize(memory = undefined) {
    const __STORAGE = getMemory(memory);
    const __MEMORY = __STORAGE.Value;


    //getMemUsage(__MEMORY);
// ==================== Abschnitt fuer die Scriptdatenbank ====================


    if (__MEMORY !== undefined) {
// Initialisiert das Script-Modul und ermittelt die beschreibenden Daten
        const __SIZE = safeStringify(__MEMORY).length;
// meta: Metadaten des Scripts (Default: GM_info.script)
// return Beschreibende Daten fuer __DBMOD
function ScriptModule(meta) {
    'use strict';


        __LOG[2]("MEM: " + __SIZE + " bytes");
    const __META = getValue(meta, GM_info.script);
        return __SIZE;
     const __PROPS = {
     } else {
                'name'        : true,
        return 0;
                'version'     : true,
     }
                'namespace'  : true,
}
                'description' : true
            };
 
    const __DBMOD = { };


// Gibt rekursiv und detailliert die Groesse des benutzten Speichers fuer ein Objekt aus
    __LOG[5](__META);
// value: (Enumerierbares) Objekt oder Wert, dessen Groesse gemessen wird
// out: Logfunktion, etwa __LOG[4]
// depth: Gewuenschte Rekursionstiefe (0 = nur dieses Objekt, -1 = alle Ebenen)
// name: Name des Objekts
function getMemUsage(value = undefined, out = undefined, depth = -1, name = '$') {
    const __OUT = (out || __LOG[4]);


     if ((typeof value) === 'string') {
     // Infos zu diesem Script...
        const __SIZE = value.length;
    addProps(__DBMOD, __META, __PROPS);


        __OUT("USAGE: " + name + '\t' + __SIZE + '\t' + value.slice(0, 255));
    // Voller Name fuer die Ausgabe...
    } else if ((typeof value) === 'object') {
    Object.defineProperty(__DBMOD, 'Name', {
        if (depth === 0) {
                    get : function() {
            const __SIZE = safeStringify(value).length;
                              return this.name + " (" + this.version + ')';
                          },
                    set : undefined
                });


            __OUT("USAGE: " + name + '\t' + __SIZE);
    __LOG[2](__DBMOD);
        } else {
            depth--;
            for (let sub in value) {
                getMemUsage(value[sub], __OUT, depth, name + '.' + sub);
            }
            getMemUsage(value, __OUT, 0, name);
        }
    } else {
      const __DATA = (((typeof value) === 'function') ? "" : '\t' + value);


        __OUT("USAGE: " + name + '\t' + (typeof value) + __DATA);
    return __DBMOD;
    }
}
}


// Restauriert den vorherigen Speicher (der in einer Option definiert ist)
Class.define(ScriptModule, Object);
// opt: Option zur Wahl des Speichers
 
// return Promise auf gesuchten Speicher oder Null-Speicher ('inaktiv')
// Initialisiert die Scriptdatenbank, die einen Datenaustausch zwischen den Scripten ermoeglicht
async function restoreMemoryByOpt(opt) {
// optSet: Gesetzte Optionen (und Config)
    // Memory Storage fuer vorherige Speicherung...
function initScriptDB(optSet) {
     const __STORAGE = await getOptValue(opt, __MEMNORMAL, true, true, true);
    // Speicher fuer die DB-Daten...
     const __DBMEM = myOptMem.Value;


     return __OPTMEM[__STORAGE];
     __DBTOC.versions = getValue((__DBMEM === undefined) ? undefined : JSON.parse(__DBMEM.getItem('__DBTOC.versions')), { });
}
    __DBTOC.namespaces = getValue((__DBMEM === undefined) ? undefined : JSON.parse(__DBMEM.getItem('__DBTOC.namespaces')), { });


// Initialisiert den Speicher (der in einer Option definiert ist) und merkt sich diesen ggfs.
    // Zunaechst den alten Eintrag entfernen...
// opt: Option zur Wahl des Speichers
     delete __DBTOC.versions[__DBMOD.name];
// saveOpt: Option zur Speicherung der Wahl des Speichers (fuer restoreMemoryByOpt)
     delete __DBTOC.namespaces[__DBMOD.name];
// onFulfilled: Reaktion auf Speicherung im resolve-Fall (1. Promise.then()-Parameter)
// onRejected: Reaktion auf Speicherung im reject-Fall (2. Promise.then()-Parameter)
// return Gesuchter Speicher oder Null-Speicher ('inaktiv'), falls speichern nicht moeglich ist
function startMemoryByOpt(opt, saveOpt = undefined, onFulfilled = undefined, onRejected = undefined) {
     // Memory Storage fuer naechste Speicherung...
    let storage = getOptValue(opt, __MEMNORMAL);
     let optMem = __OPTMEM[storage];


     if (! canUseMemory(optMem)) {
     if (__DBMEM !== undefined) {
         if (storage !== __MEMINAKTIVE) {
         // ... und die Daten der Fremdscripte laden...
             storage = __MEMINAKTIVE;
        for (let module in __DBTOC.versions) {
            optMem = __OPTMEM[storage];
             scriptDB(module, getValue(JSON.parse(__DBMEM.getItem('__DBDATA.' + module)), { }));
         }
         }
     }
     }
    if (saveOpt !== undefined) {
        setOpt(saveOpt, storage, false, onFulfilled, onRejected);
    }
    return optMem;
}
}


// ==================== Ende Abschnitt fuer Speicher ====================
// Setzt die Daten dieses Scriptes in der Scriptdatenbank, die einen Datenaustausch zwischen den Scripten ermoeglicht
// optSet: Gesetzte Optionen (und Config)
function updateScriptDB(optSet) {
    // Eintrag ins Inhaltsverzeichnis...
    __DBTOC.versions[__DBMOD.name] = __DBMOD.version;
    __DBTOC.namespaces[__DBMOD.name] = __DBMOD.namespace;


// ==================== Abschnitt fuer die Scriptdatenbank ====================
    // Speicher fuer die DB-Daten...
    const __DBMEM = myOptMem.Value;


// Initialisiert das Script-Modul und ermittelt die beschreibenden Daten
    if (__DBMEM !== undefined) {
// meta: Metadaten des Scripts (Default: GM.info.script)
        // Permanente Speicherung der Eintraege...
// return Beschreibende Daten fuer __DBMOD
        __DBMEM.setItem('__DBTOC.versions', safeStringify(__DBTOC.versions));
function ScriptModule(meta) {
        __DBMEM.setItem('__DBTOC.namespaces', safeStringify(__DBTOC.namespaces));
    'use strict';
        __DBMEM.setItem('__DBDATA.' + __DBMOD.name, safeStringify(optSet));


    const __META = getValue(meta, GM.info.script);
        // Aktualisierung der Speichergroesse...
     const __PROPS = {
        myOptMemSize = getMemSize(myOptMem);
                'name'        : true,
     }
                'version'    : true,
                'namespace'  : true,
                'description' : true
            };


     const __DBMOD = { };
     // Jetzt die inzwischen gefuellten Daten *dieses* Scripts ergaenzen...
    scriptDB(__DBMOD.name, getValue(optSet, { }));


     __LOG[5](__META);
     __LOG[2](__DBDATA);
}


    // Infos zu diesem Script...
// Holt die globalen Daten zu einem Modul aus der Scriptdatenbank
     addProps(__DBMOD, __META, __PROPS);
// module: Gesetzte Optionen (und Config)
// initValue: Falls angegeben, zugewiesener Startwert
// return Daten zu diesem Modul
function scriptDB(module, initValue = undefined) {
    const __NAMESPACE = __DBTOC.namespaces[module];
     const __DBMODS = getProp(__DBDATA, __NAMESPACE, { });


     // Voller Name fuer die Ausgabe...
     if (initValue !== undefined) {
    Object.defineProperty(__DBMOD, 'Name', {
        return (__DBMODS[module] = initValue);
                    get : function() {
    } else {
                              return this.name + " (" + this.version + ')';
        return getProp(__DBMODS, module, { });
                          },
     }
                    set : undefined
                });
 
     __LOG[2](__DBMOD);
 
    return __DBMOD;
}
}


Class.define(ScriptModule, Object);
// ==================== Ende Abschnitt fuer die Scriptdatenbank ====================


// Initialisiert die Scriptdatenbank, die einen Datenaustausch zwischen den Scripten ermoeglicht
// ==================== Ende Abschnitt fuer Speicher und die Scriptdatenbank ====================
// optSet: Gesetzte Optionen (und Config)
function initScriptDB(optSet) {
    // Speicher fuer die DB-Daten...
    const __DBMEM = myOptMem.Value;


    __DBTOC.versions = getValue((__DBMEM === undefined) ? undefined : JSON.parse(__DBMEM.getItem('__DBTOC.versions')), { });
// ==================== Abschnitt fuer das Benutzermenu ====================
    __DBTOC.namespaces = getValue((__DBMEM === undefined) ? undefined : JSON.parse(__DBMEM.getItem('__DBTOC.namespaces')), { });


    // Zunaechst den alten Eintrag entfernen...
// Zeigt den Eintrag im Menu einer Option
     delete __DBTOC.versions[__DBMOD.name];
// val: Derzeitiger Wert der Option
     delete __DBTOC.namespaces[__DBMOD.name];
// menuOn: Text zum Setzen im Menu
// funOn: Funktion zum Setzen
// keyOn: Hotkey zum Setzen im Menu
// menuOff: Text zum Ausschalten im Menu
// funOff: Funktion zum Ausschalten
// keyOff: Hotkey zum Ausschalten im Menu
function registerMenuOption(val, menuOn, funOn, keyOn, menuOff, funOff, keyOff) {
     const __ON  = (val ? '*' : "");
    const __OFF = (val ? "" : '*');
 
     __LOG[3]("OPTION " + __ON + menuOn + __ON + " / " + __OFF + menuOff + __OFF);


     if (__DBMEM !== undefined) {
     if (val) {
         // ... und die Daten der Fremdscripte laden...
         GM_registerMenuCommand(menuOff, funOff, keyOff);
        for (let module in __DBTOC.versions) {
    } else {
            scriptDB(module, getValue(JSON.parse(__DBMEM.getItem('__DBDATA.' + module)), { }));
        GM_registerMenuCommand(menuOn, funOn, keyOn);
        }
     }
     }
}
}


// Setzt die Daten dieses Scriptes in der Scriptdatenbank, die einen Datenaustausch zwischen den Scripten ermoeglicht
// Zeigt den Eintrag im Menu einer Option mit Wahl des naechsten Wertes
// optSet: Gesetzte Optionen (und Config)
// val: Derzeitiger Wert der Option
function updateScriptDB(optSet) {
// arr: Array-Liste mit den moeglichen Optionen
     // Eintrag ins Inhaltsverzeichnis...
// menu: Text zum Setzen im Menu ($ wird durch gesetzten Wert ersetzt)
    __DBTOC.versions[__DBMOD.name] = __DBMOD.version;
// fun: Funktion zum Setzen des naechsten Wertes
     __DBTOC.namespaces[__DBMOD.name] = __DBMOD.namespace;
// key: Hotkey zum Setzen des naechsten Wertes im Menu
function registerNextMenuOption(val, arr, menu, fun, key) {
     const __MENU = menu.replace('$', val);
     let options = "OPTION " + __MENU;


     // Speicher fuer die DB-Daten...
     for (let value of arr) {
     const __DBMEM = myOptMem.Value;
        if (value === val) {
            options += " / *" + value + '*';
        } else {
            options += " / " + value;
        }
    }
     __LOG[3](options);


     if (__DBMEM !== undefined) {
     GM_registerMenuCommand(__MENU, fun, key);
        // Permanente Speicherung der Eintraege...
}
        __DBMEM.setItem('__DBTOC.versions', safeStringify(__DBTOC.versions));
        __DBMEM.setItem('__DBTOC.namespaces', safeStringify(__DBTOC.namespaces));
        __DBMEM.setItem('__DBDATA.' + __DBMOD.name, safeStringify(optSet));


        // Aktualisierung der Speichergroesse...
// Zeigt den Eintrag im Menu einer Option, falls nicht hidden
        myOptMemSize = getMemSize(myOptMem);
// val: Derzeitiger Wert der Option
     }
// menu: Text zum Setzen im Menu ($ wird durch gesetzten Wert ersetzt)
// fun: Funktion zum Setzen des naechsten Wertes
// key: Hotkey zum Setzen des naechsten Wertes im Menu
// hidden: Angabe, ob Menupunkt nicht sichtbar sein soll (Default: sichtbar)
// serial: Serialization fuer komplexe Daten
function registerDataOption(val, menu, fun, key, hidden = false, serial = true) {
    const __VALUE = ((serial && (val !== undefined)) ? safeStringify(val) : val);
    const __MENU = getValue(menu, "").replace('$', __VALUE);
     const __OPTIONS = (hidden ? "HIDDEN " : "") + "OPTION " + __MENU +
                      getValue(__VALUE, "", " = " + __VALUE);


     // Jetzt die inzwischen gefuellten Daten *dieses* Scripts ergaenzen...
     __LOG[hidden ? 4 : 3](__OPTIONS);
    scriptDB(__DBMOD.name, getValue(optSet, { }));


     __LOG[2](__DBDATA);
     if (! hidden) {
        GM_registerMenuCommand(__MENU, fun, key);
    }
}
}


// Holt die globalen Daten zu einem Modul aus der Scriptdatenbank
// Zeigt den Eintrag im Menu einer Option
// module: Gesetzte Optionen (und Config)
// opt: Config und Value der Option
// initValue: Falls angegeben, zugewiesener Startwert
function registerOption(opt) {
// return Daten zu diesem Modul
     const __CONFIG = getOptConfig(opt);
function scriptDB(module, initValue = undefined) {
     const __VALUE = getOptValue(opt);
     const __NAMESPACE = __DBTOC.namespaces[module];
    const __LABEL = __CONFIG.Label;
     const __DBMODS = getProp(__DBDATA, __NAMESPACE, { });
    const __ACTION = opt.Action;
    const __HOTKEY = __CONFIG.Hotkey;
    const __HIDDEN = __CONFIG.HiddenMenu;
    const __SERIAL = __CONFIG.Serial;


     if (initValue !== undefined) {
     if (! __CONFIG.HiddenMenu) {
         return (__DBMODS[module] = initValue);
         switch (__CONFIG.Type) {
        case __OPTTYPES.MC : registerNextMenuOption(__VALUE, __CONFIG.Choice, __LABEL, __ACTION, __HOTKEY);
                            break;
        case __OPTTYPES.SW : registerMenuOption(__VALUE, __LABEL, __ACTION, __HOTKEY,
                                                __CONFIG.AltLabel, __ACTION, __CONFIG.AltHotkey);
                            break;
        case __OPTTYPES.TF : registerMenuOption(__VALUE, __LABEL, __ACTION, __HOTKEY,
                                                __CONFIG.AltLabel, opt.AltAction, __CONFIG.AltHotkey);
                            break;
        case __OPTTYPES.SD : registerDataOption(__VALUE, __LABEL, __ACTION, __HOTKEY, __HIDDEN, __SERIAL);
                            break;
        case __OPTTYPES.SI : registerDataOption(__VALUE, __LABEL, __ACTION, __HOTKEY, __HIDDEN, __SERIAL);
                            break;
        default :            break;
        }
     } else {
     } else {
         return getProp(__DBMODS, module, { });
         // Nur Anzeige im Log...
        registerDataOption(__VALUE, __LABEL, __ACTION, __HOTKEY, __HIDDEN, __SERIAL);
     }
     }
}
}


// ==================== Ende Abschnitt fuer die Scriptdatenbank ====================
// ==================== Ende Abschnitt fuer das Benutzermenu ====================


// ==================== Ende Abschnitt fuer Speicher und die Scriptdatenbank ====================
// Initialisiert die gesetzten Option
// config: Konfiguration der Option
// setValue: Zu uebernehmender Default-Wert (z.B. der jetzt gesetzte)
// return Initialwert der gesetzten Option
function initOptValue(config, setValue = undefined) {
    let value = getValue(setValue, config.Default);  // Standard


// ==================== Abschnitt fuer das Benutzermenu ====================
    if (config.SharedData !== undefined) {
        value = config.SharedData;
    }


// Zeigt den Eintrag im Menu einer Option
    switch (config.Type) {
// val: Derzeitiger Wert der Option
    case __OPTTYPES.MC : if ((value === undefined) && (config.Choice !== undefined)) {
// menuOn: Text zum Setzen im Menu
                            value = config.Choice[0];
// funOn: Funktion zum Setzen
                        }
// keyOn: Hotkey zum Setzen im Menu
                        break;
// menuOff: Text zum Ausschalten im Menu
    case __OPTTYPES.SW : break;
// funOff: Funktion zum Ausschalten
    case __OPTTYPES.TF : break;
// keyOff: Hotkey zum Ausschalten im Menu
    case __OPTTYPES.SD : config.Serial = true;
// return Promise von GM.registerMenuCommand()
                        break;
function registerMenuOption(val, menuOn, funOn, keyOn, menuOff, funOff, keyOff) {
     case __OPTTYPES.SI : break;
     const __ON  = (val ? '*' : "");
     default :           break;
     const __OFF = (val ? "" : '*');
    }


     __LOG[3]("OPTION " + __ON + menuOn + __ON + " / " + __OFF + menuOff + __OFF);
     if (config.Serial || config.Hidden) {
        config.HiddenMenu = true;
    }


     if (val) {
     return value;
        return GM.registerMenuCommand(menuOff, funOff, keyOff).then(result => menuOn);
    } else {
        return GM.registerMenuCommand(menuOn, funOn, keyOn).then(result => menuOff);
    }
}
}


// Zeigt den Eintrag im Menu einer Option mit Wahl des naechsten Wertes
// Initialisiert die Menue-Funktion einer Option
// val: Derzeitiger Wert der Option
// optAction: Typ der Funktion
// arr: Array-Liste mit den moeglichen Optionen
// item: Key der Option
// menu: Text zum Setzen im Menu ($ wird durch gesetzten Wert ersetzt)
// optSet: Platz fuer die gesetzten Optionen (und Config)
// fun: Funktion zum Setzen des naechsten Wertes
// optConfig: Konfiguration der Option
// key: Hotkey zum Setzen des naechsten Wertes im Menu
// return Funktion fuer die Option
// return Promise von GM.registerMenuCommand()
function initOptAction(optAction, item = undefined, optSet = undefined, optConfig = undefined) {
function registerNextMenuOption(val, arr, menu, fun, key) {
    let fun;
    const __MENU = substParam(menu, val);
 
    let options = "OPTION " + __MENU;
    if (optAction !== undefined) {
        const __CONFIG = ((optConfig !== undefined) ? optConfig : getOptConfig(getOptByName(optSet, item)));
        const __RELOAD = getValue(getValue(__CONFIG, { }).ActionReload, true);


    for (let value of arr) {
        switch (optAction) {
         if (value === val) {
         case __OPTACTION.SET : fun = function() {
            options += " / *" + value + '*';
                                      return setOptByName(optSet, item, __CONFIG.SetValue, __RELOAD);
        } else {
                                  };
            options += " / " + value;
                              break;
        case __OPTACTION.NXT : fun = function() {
                                      return promptNextOptByName(optSet, item, __CONFIG.SetValue, __RELOAD,
                                                  __CONFIG.FreeValue, __CONFIG.SelValue, __CONFIG.MinChoice);
                                  };
                              break;
        case __OPTACTION.RST : fun = function() {
                                      return resetOptions(optSet, __RELOAD);
                                  };
                              break;
        default :              break;
         }
         }
     }
     }
    __LOG[3](options);


     return GM.registerMenuCommand(__MENU, fun, key).then(result => __MENU);
     return fun;
}
}


// Zeigt den Eintrag im Menu einer Option, falls nicht hidden
// Gibt fuer einen 'Shared'-Eintrag eine ObjRef zurueck
// val: Derzeitiger Wert der Option
// shared: Object mit den Angaben 'namespace', 'module' und ggfs. 'item'
// menu: Text zum Setzen im Menu ($ wird durch gesetzten Wert ersetzt)
// item: Key der Option
// fun: Funktion zum Setzen des naechsten Wertes
// return ObjRef, die das Ziel definiert
// key: Hotkey zum Setzen des naechsten Wertes im Menu
function getSharedRef(shared, item = undefined) {
// hidden: Angabe, ob Menupunkt nicht sichtbar sein soll (Default: sichtbar)
     if (shared === undefined) {
// serial: Serialization fuer komplexe Daten
        return undefined;
// return Promise von GM.registerMenuCommand() (oder String-Version des Wertes)
    }
function registerDataOption(val, menu, fun, key, hidden = false, serial = true) {
 
     const __VALUE = ((serial && (val !== undefined)) ? safeStringify(val) : val);
    const __OBJREF = new ObjRef(__DBDATA); // Gemeinsame Daten
     const __MENU = substParam(menu, __VALUE);
     const __PROPS = [ 'namespace', 'module', 'item' ];
     const __OPTIONS = (hidden ? "HIDDEN " : "") + "OPTION " + __MENU +
     const __DEFAULTS = [ __DBMOD.namespace, __DBMOD.name, item ];
                      getValue(__VALUE, "", " = " + __VALUE);
 
    for (let stage in __PROPS) {
        const __DEFAULT = __DEFAULTS[stage];
        const __PROP = __PROPS[stage];
        const __NAME = shared[__PROP];


    __LOG[hidden ? 4 : 3](__OPTIONS);
        if (__NAME === '$') {
            break;
        }


    if (hidden) {
         __OBJREF.chDir(getValue(__NAME, __DEFAULT));
         return Promise.resolve(__VALUE);
    } else {
        return GM.registerMenuCommand(__MENU, fun, key).then(result => __MENU);
     }
     }
    return __OBJREF;
}
}


// Zeigt den Eintrag im Menu einer Option
// Gibt diese Config oder, falls 'Shared', ein Referenz-Objekt mit gemeinsamen Daten zurueck
// opt: Config und Value der Option
// optConfig: Konfiguration der Option
// return Promise von GM.registerMenuCommand() (oder String-Version des Wertes)
// item: Key der Option
function registerOption(opt) {
// return Entweder optConfig oder gemergete Daten auf Basis des in 'Shared' angegebenen Objekts
     const __CONFIG = getOptConfig(opt);
function getSharedConfig(optConfig, item = undefined) {
     const __VALUE = getOptValue(opt);
     let config = getValue(optConfig, { });
     const __LABEL = __CONFIG.Label;
     const __SHARED = config.Shared;
    const __ACTION = opt.Action;
 
    const __HOTKEY = __CONFIG.Hotkey;
     if (__SHARED !== undefined) {
    const __HIDDEN = __CONFIG.HiddenMenu;
        const __OBJREF = getSharedRef(__SHARED, item); // Gemeinsame Daten
    const __SERIAL = __CONFIG.Serial;
 
        if (getValue(__SHARED.item, '$') !== '$') {  // __REF ist ein Item
            const __REF = valueOf(__OBJREF);


    if (! __CONFIG.HiddenMenu) {
            config = { };  // Neu aufbauen...
        switch (__CONFIG.Type) {
            addProps(config, getOptConfig(__REF));
        case __OPTTYPES.MC : return registerNextMenuOption(__VALUE, __CONFIG.Choice, __LABEL, __ACTION, __HOTKEY);
            addProps(config, optConfig);
        case __OPTTYPES.SW : return registerMenuOption(__VALUE, __LABEL, __ACTION, __HOTKEY,
            config.setConst('SharedData', getOptValue(__REF));
                                                      __CONFIG.AltLabel, __ACTION, __CONFIG.AltHotkey);
         } else {  // __REF enthaelt die Daten selbst
         case __OPTTYPES.TF : return registerMenuOption(__VALUE, __LABEL, __ACTION, __HOTKEY,
            if (! config.Name) {
                                                      __CONFIG.AltLabel, opt.AltAction, __CONFIG.AltHotkey);
                config.Name = __OBJREF.getPath();
        case __OPTTYPES.SD : return registerDataOption(__VALUE, __LABEL, __ACTION, __HOTKEY, __HIDDEN, __SERIAL);
            }
        case __OPTTYPES.SI : return registerDataOption(__VALUE, __LABEL, __ACTION, __HOTKEY, __HIDDEN, __SERIAL);
            config.setConst('SharedData', __OBJREF); // Achtung: Ggfs. zirkulaer!
        default :           return Promise.resolve(__VALUE);
         }
         }
    } else {
        // Nur Anzeige im Log...
        return registerDataOption(__VALUE, __LABEL, __ACTION, __HOTKEY, __HIDDEN, __SERIAL);
     }
     }
    return config;
}
}


// ==================== Ende Abschnitt fuer das Benutzermenu ====================
// Initialisiert die gesetzten Optionen
// optConfig: Konfiguration der Optionen
// optSet: Platz fuer die gesetzten Optionen
// preInit: Vorinitialisierung einzelner Optionen mit 'PreInit'-Attribut
// return Gefuelltes Objekt mit den gesetzten Optionen
function initOptions(optConfig, optSet = undefined, preInit = undefined) {
    let value;


// Initialisiert die gesetzten Option
     if (optSet === undefined) {
// config: Konfiguration der Option
         optSet = { };
// setValue: Zu uebernehmender Default-Wert (z.B. der jetzt gesetzte)
// return Initialwert der gesetzten Option
function initOptValue(config, setValue = undefined) {
    let value = getValue(setValue, config.Default);  // Standard
 
     if (config.SharedData !== undefined) {
         value = config.SharedData;
     }
     }


     switch (config.Type) {
     for (let opt in optConfig) {
    case __OPTTYPES.MC : if ((value === undefined) && (config.Choice !== undefined)) {
        const __OPTCONFIG = optConfig[opt];
                            value = config.Choice[0];
        const __PREINIT = getValue(__OPTCONFIG.PreInit, false, true);
                        }
        const __ISSHARED = getValue(__OPTCONFIG.Shared, false, true);
                        break;
    case __OPTTYPES.SW : break;
    case __OPTTYPES.TF : break;
    case __OPTTYPES.SD : config.Serial = true;
                        break;
    case __OPTTYPES.SI : break;
    default :            break;
    }


    if (config.Serial || config.Hidden) {
        if ((preInit === undefined) || (__PREINIT === preInit)) {
        config.HiddenMenu = true;
            const __CONFIG = getSharedConfig(__OPTCONFIG, opt);
    }
            const __ALTACTION = getValue(__CONFIG.AltAction, __CONFIG.Action);
            // Gab es vorher einen Aufruf, der einen Stub-Eintrag erzeugt hat? Wurde ggfs. bereits geaendert...
            const __USESTUB = ((preInit === false) && __PREINIT);
            const __LOADED = (__USESTUB && optSet[opt].Loaded);
            const __VALUE = (__USESTUB ? optSet[opt].Value : undefined);


    return value;
            optSet[opt] = {
}
                'Item'      : opt,
 
                'Config'    : __CONFIG,
// Initialisiert die Menue-Funktion einer Option
                'Loaded'    : (__ISSHARED || __LOADED),
// optAction: Typ der Funktion
                'Value'    : initOptValue(__CONFIG, __VALUE),
// item: Key der Option
                'SetValue'  : __CONFIG.SetValue,
// optSet: Platz fuer die gesetzten Optionen (und Config)
                'ReadOnly'  : (__ISSHARED || __CONFIG.ReadOnly),
// optConfig: Konfiguration der Option
                'Action'    : initOptAction(__CONFIG.Action, opt, optSet, __CONFIG),
// return Funktion fuer die Option
                'AltAction' : initOptAction(__ALTACTION, opt, optSet, __CONFIG)
function initOptAction(optAction, item = undefined, optSet = undefined, optConfig = undefined) {
            };
    let fun;
         } else if (preInit) { // erstmal nur Stub
 
            optSet[opt] = {
    if (optAction !== undefined) {
                'Item'      : opt,
        const __CONFIG = ((optConfig !== undefined) ? optConfig : getOptConfig(getOptByName(optSet, item)));
                'Config'    : __OPTCONFIG,
        const __RELOAD = getValue(getValue(__CONFIG, { }).ActionReload, true);
                'Loaded'    : false,
 
                'Value'    : initOptValue(__OPTCONFIG),
        switch (optAction) {
                'ReadOnly'  : (__ISSHARED || __OPTCONFIG.ReadOnly)
        case __OPTACTION.SET : fun = function() {
            };
                                      return setOptByName(optSet, item, __CONFIG.SetValue, __RELOAD).catch(defaultCatch);
                                  };
                              break;
         case __OPTACTION.NXT : fun = function() {
                                      return promptNextOptByName(optSet, item, __CONFIG.SetValue, __RELOAD,
                                                  __CONFIG.FreeValue, __CONFIG.SelValue, __CONFIG.MinChoice).catch(defaultCatch);
                                  };
                              break;
        case __OPTACTION.RST : fun = function() {
                                      return resetOptions(optSet, __RELOAD).then(
                                              result => __LOG[3]("RESETTING (" + result + ")..."),
                                              defaultCatch);
                                  };
                              break;
        default :              break;
         }
         }
     }
     }


     return fun;
     return optSet;
}
}


// Gibt fuer einen 'Shared'-Eintrag eine ObjRef zurueck
    // Abhaengigkeiten:
// shared: Object mit den Angaben 'namespace', 'module' und ggfs. 'item'
    // ================
// item: Key der Option
    // initOptions (PreInit):
// return ObjRef, die das Ziel definiert
    // restoreMemoryByOpt: PreInit oldStorage
function getSharedRef(shared, item = undefined) {
    // getStoredCmds: restoreMemoryByOpt
     if (shared === undefined) {
    // runStoredCmds (beforeLoad): getStoredCmds
        return undefined;
    // loadOptions (PreInit): PreInit
     }
    // startMemoryByOpt: storage oldStorage
    // initScriptDB: startMemoryByOpt
    // initOptions (Rest): PreInit
    // getMyTeam callback (getOptPrefix): initTeam
    // __MYTEAM (initTeam): initOptions
    // renameOptions: getOptPrefix
    // runStoredCmds (afterLoad): getStoredCmds, renameOptions
     // loadOptions (Rest): PreInit/Rest runStoredCmds
    // updateScriptDB: startMemoryByOpt
     // showOptions: startMemoryByOpt renameOptions
    // buildMenu: showOptions
    // buildForm: showOptions


    const __OBJREF = new ObjRef(__DBDATA);  // Gemeinsame Daten
// Initialisiert die gesetzten Optionen und den Speicher und laedt die Optionen zum Start
    const __PROPS = [ 'namespace', 'module', 'item' ];
// optConfig: Konfiguration der Optionen
     const __DEFAULTS = [ __DBMOD.namespace, __DBMOD.name, item ];
// optSet: Platz fuer die gesetzten Optionen
// return Gefuelltes Objekt mit den gesetzten Optionen
function startOptions(optConfig, optSet = undefined, classification = undefined) {
     optSet = initOptions(optConfig, optSet, true); // PreInit


     for (let stage in __PROPS) {
     // Memory Storage fuer vorherige Speicherung...
        const __DEFAULT = __DEFAULTS[stage];
    myOptMemSize = getMemSize(myOptMem = restoreMemoryByOpt(optSet.oldStorage));
        const __PROP = __PROPS[stage];
 
        const __NAME = shared[__PROP];
    // Zwischengespeicherte Befehle auslesen...
    const __STOREDCMDS = getStoredCmds(myOptMem);
 
    // ... ermittelte Befehle ausführen...
    const __LOADEDCMDS = runStoredCmds(__STOREDCMDS, optSet, true); // BeforeLoad


        if (__NAME === '$') {
    // Bisher noch nicht geladenene Optionen laden...
            break;
    loadOptions(optSet);
        }


        __OBJREF.chDir(getValue(__NAME, __DEFAULT));
    // Memory Storage fuer naechste Speicherung...
    }
    myOptMemSize = getMemSize(myOptMem = startMemoryByOpt(optSet.storage, optSet.oldStorage));


     return __OBJREF;
     // Globale Daten ermitteln...
}
    initScriptDB(optSet);


// Gibt diese Config oder, falls 'Shared', ein Referenz-Objekt mit gemeinsamen Daten zurueck
     optSet = initOptions(optConfig, optSet, false); // Rest
// optConfig: Konfiguration der Option
// item: Key der Option
// return Entweder optConfig oder gemergete Daten auf Basis des in 'Shared' angegebenen Objekts
function getSharedConfig(optConfig, item = undefined) {
     let config = getValue(optConfig, { });
    const __SHARED = config.Shared;


     if (__SHARED !== undefined) {
     if (classification !== undefined) {
         const __OBJREF = getSharedRef(__SHARED, item); // Gemeinsame Daten
         // Umbenennungen durchfuehren...
        classification.renameOptions();
    }


        if (getValue(__SHARED.item, '$') !== '$') { // __OBJREF ist ein Item
    // ... ermittelte Befehle ausführen...
            const __REF = valueOf(__OBJREF);
    runStoredCmds(__LOADEDCMDS, optSet, false); // Rest


            config = { };  // Neu aufbauen...
    // Als globale Daten speichern...
            addProps(config, getOptConfig(__REF));
    updateScriptDB(optSet);
            addProps(config, optConfig);
            config.setConst('SharedData', getOptValue(__REF), false);  // Wert muss schon da sein, NICHT nachladen, sonst ggfs. Promise
        } else {  // __OBJREF enthaelt die Daten selbst
            if (! config.Name) {
                config.Name = __OBJREF.getPath();
            }
            config.setConst('SharedData', __OBJREF); // Achtung: Ggfs. zirkulaer!
        }
    }


     return config;
     return optSet;
}
}


// Initialisiert die gesetzten Optionen
// Installiert die Visualisierung und Steuerung der Optionen
// optConfig: Konfiguration der Optionen
// optSet: Platz fuer die gesetzten Optionen
// optSet: Platz fuer die gesetzten Optionen
// preInit: Vorinitialisierung einzelner Optionen mit 'PreInit'-Attribut
// optParams: Eventuell notwendige Parameter zur Initialisierung
// return Gefuelltes Objekt mit den gesetzten Optionen
// 'hideMenu': Optionen werden zwar geladen und genutzt, tauchen aber nicht im Benutzermenu auf
function initOptions(optConfig, optSet = undefined, preInit = undefined) {
// 'menuAnchor': Startpunkt fuer das Optionsmenu auf der Seite
     let value;
// 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar)
// 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar)
// 'formWidth': Anzahl der Elemente pro Zeile
// 'formBreak': Elementnummer des ersten Zeilenumbruchs
function showOptions(optSet = undefined, optParams = { 'hideMenu' : false }) {
     if (! optParams.hideMenu) {
        buildMenu(optSet);
    }


     if (optSet === undefined) {
     if ((optParams.menuAnchor !== undefined) && (myOptMem !== __OPTMEMINAKTIVE)) {
         optSet = { };
         buildForm(optParams.menuAnchor, optSet, optParams);
     }
     }
}


    for (let opt in optConfig) {
// Setzt eine Option auf einen vorgegebenen Wert
        const __OPTCONFIG = optConfig[opt];
// Fuer kontrollierte Auswahl des Values siehe setNextOpt()
        const __PREINIT = getValue(__OPTCONFIG.PreInit, false, true);
// opt: Config und vorheriger Value der Option
        const __ISSHARED = getValue(__OPTCONFIG.Shared, false, true);
// value: (Bei allen Typen) Zu setzender Wert
// reload: Seite mit neuem Wert neu laden
// return Gesetzter Wert
function setOpt(opt, value, reload = false) {
    return setOptValue(opt, setStored(getOptName(opt), value, reload, getOptConfig(opt).Serial));
}


        if ((preInit === undefined) || (__PREINIT === preInit)) {
// Ermittelt die naechste moegliche Option
            const __CONFIG = getSharedConfig(__OPTCONFIG, opt);
// opt: Config und Value der Option
            const __ALTACTION = getValue(__CONFIG.AltAction, __CONFIG.Action);
// value: Ggfs. zu setzender Wert
            // Gab es vorher einen Aufruf, der einen Stub-Eintrag erzeugt hat, und wurden Daten geladen?
// return Zu setzender Wert
            const __LOADED = ((preInit === false) && optSet[opt].Loaded);
function getNextOpt(opt, value = undefined) {
            const __PROMISE = ((__LOADED || ! optSet[opt]) ? undefined : optSet[opt].Promise);
    const __CONFIG = getOptConfig(opt);
            const __VALUE = (__LOADED ? optSet[opt].Value : undefined);
    const __VALUE = getOptValue(opt, value);


            optSet[opt] = {
    switch (__CONFIG.Type) {
                'Item'      : opt,
    case __OPTTYPES.MC : return getValue(value, getNextValue(__CONFIG.Choice, __VALUE));
                'Config'    : __CONFIG,
     case __OPTTYPES.SW : return getValue(value, ! __VALUE);
                'Loaded'    : (__ISSHARED || __LOADED),
    case __OPTTYPES.TF : return getValue(value, ! __VALUE);
                'Promise'  : __PROMISE,
    case __OPTTYPES.SD : return getValue(value, __VALUE);
                'Value'     : initOptValue(__CONFIG, __VALUE),
    case __OPTTYPES.SI : break;
                'SetValue'  : __CONFIG.SetValue,
     default :           break;
                'ReadOnly'  : (__ISSHARED || __CONFIG.ReadOnly),
     }
                'Action'    : initOptAction(__CONFIG.Action, opt, optSet, __CONFIG),
                'AltAction' : initOptAction(__ALTACTION, opt, optSet, __CONFIG)
            };
        } else if (preInit) {  // erstmal nur Stub
            optSet[opt] = {
                'Item'      : opt,
                'Config'    : __OPTCONFIG,
                'Loaded'    : false,
                'Promise'  : undefined,
                'Value'     : initOptValue(__OPTCONFIG),
                'ReadOnly'  : (__ISSHARED || __OPTCONFIG.ReadOnly)
            };
        }
     }


     return optSet;
     return __VALUE;
}
}


    // Abhaengigkeiten:
// Setzt die naechste moegliche Option
    // ================
// opt: Config und Value der Option
    // initOptions (PreInit):
// value: Default fuer ggfs. zu setzenden Wert
    // restoreMemoryByOpt: PreInit oldStorage
// reload: Seite mit neuem Wert neu laden
    // getStoredCmds: restoreMemoryByOpt
// return Gesetzter Wert
    // runStoredCmds (beforeLoad): getStoredCmds
function setNextOpt(opt, value = undefined, reload = false) {
    // loadOptions (PreInit): PreInit
     return setOpt(opt, getNextOpt(opt, value), reload);
    // startMemoryByOpt: storage oldStorage
}
     // initScriptDB: startMemoryByOpt
    // initOptions (Rest): PreInit
    // getMyTeam callback (getOptPrefix): initTeam
    // __MYTEAM (initTeam): initOptions
    // renameOptions: getOptPrefix
    // runStoredCmds (afterLoad): getStoredCmds, renameOptions
    // loadOptions (Rest): PreInit/Rest runStoredCmds
    // updateScriptDB: startMemoryByOpt
    // showOptions: startMemoryByOpt renameOptions
    // buildMenu: showOptions
    // buildForm: showOptions


// Initialisiert die gesetzten Optionen und den Speicher und laedt die Optionen zum Start
// Setzt die naechste moegliche Option oder fragt ab einer gewissen Anzahl interaktiv ab
// optConfig: Konfiguration der Optionen
// opt: Config und Value der Option
// optSet: Platz fuer die gesetzten Optionen
// value: Default fuer ggfs. zu setzenden Wert
// return Promise auf gefuelltes Objekt mit den gesetzten Optionen
// reload: Seite mit neuem Wert neu laden
async function startOptions(optConfig, optSet = undefined, classification = undefined) {
// freeValue: Angabe, ob Freitext zugelassen ist (Default: false)
     optSet = initOptions(optConfig, optSet, true); // PreInit
// minChoice: Ab wievielen Auswahlmoeglichkeiten soll abgefragt werden? (Default: 3)
// return Gesetzter Wert
function promptNextOpt(opt, value = undefined, reload = false, freeValue = false, selValue = true, minChoice = 3) {
     const __CONFIG = getOptConfig(opt);
    const __CHOICE = __CONFIG.Choice;


     // Memory Storage fuer vorherige Speicherung...
     if (value || (! __CHOICE) || (__CHOICE.length < minChoice)) {
    myOptMemSize = getMemSize(myOptMem = await restoreMemoryByOpt(optSet.oldStorage));
        return setNextOpt(opt, value, reload);
    }


    // Zwischengespeicherte Befehle auslesen...
     const __VALUE = getOptValue(opt, value);
     const __STOREDCMDS = getStoredCmds(myOptMem);


     // ... ermittelte Befehle ausfuehren...
     try {
    const __LOADEDCMDS = await runStoredCmds(__STOREDCMDS, optSet, true); // BeforeLoad
        const __NEXTVAL = getNextValue(__CHOICE, __VALUE);
        let message = "";


    // Bisher noch nicht geladenene Optionen laden...
        if (selValue) {
    await loadOptions(optSet);
            for (let index = 0; index < __CHOICE.length; index++) {
                message += (index + 1) + ") " + __CHOICE[index] + '\n';
            }
            message += "\nNummer eingeben:";
        } else {
            message = __CHOICE.join(" / ") + "\n\nWert eingeben:";
        }


    // Memory Storage fuer naechste Speicherung...
        const __ANSWER = prompt(message, __NEXTVAL);
    myOptMemSize = getMemSize(myOptMem = startMemoryByOpt(optSet.storage, optSet.oldStorage));


    // Globale Daten ermitteln...
        if (__ANSWER) {
    initScriptDB(optSet);
            const __INDEX = parseInt(__ANSWER, 10) - 1;
            let nextVal = (selValue ? __CHOICE[__INDEX] : undefined);


    optSet = initOptions(optConfig, optSet, false); // Rest
            if (nextVal === undefined) {
                const __VALTYPE = getValue(__CONFIG.ValType, 'String');
                const __CASTVAL = this[__VALTYPE](__ANSWER);


    if (classification !== undefined) {
                if (freeValue || (~ __CHOICE.indexOf(__CASTVAL))) {
        // Umbenennungen durchfuehren...
                    nextVal = __CASTVAL;
        await classification.renameOptions();
                }
    }
            }


    // ... ermittelte Befehle ausfuehren...
            if (nextVal !== __VALUE) {
    await runStoredCmds(__LOADEDCMDS, optSet, false); // Rest
                if (nextVal) {
                    return setOpt(opt, nextVal, reload);
                }


    // Als globale Daten speichern...
                const __LABEL = __CONFIG.Label.replace('$', __VALUE);
    updateScriptDB(optSet);


    return optSet;
                showAlert(__LABEL, "Ung\xFCltige Eingabe: " + __ANSWER);
}
            }
 
        }
// Installiert die Visualisierung und Steuerung der Optionen
     } catch (ex) {
// optSet: Platz fuer die gesetzten Optionen
         __LOG[1]("promptNextOpt: " + ex.message);
// optParams: Eventuell notwendige Parameter zur Initialisierung
// 'hideMenu': Optionen werden zwar geladen und genutzt, tauchen aber nicht im Benutzermenu auf
// 'menuAnchor': Startpunkt fuer das Optionsmenu auf der Seite
// 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar)
// 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar)
// 'formWidth': Anzahl der Elemente pro Zeile
// 'formBreak': Elementnummer des ersten Zeilenumbruchs
// return Liefert die gesetzten Optionen zurueck
function showOptions(optSet = undefined, optParams = { 'hideMenu' : false }) {
     if (! optParams.hideMenu) {
         buildMenu(optSet).then(() => __LOG[3]("Menu OK"));
     }
     }


    if ((optParams.menuAnchor !== undefined) && (myOptMem !== __OPTMEMINAKTIVE)) {
     return __VALUE;
        buildForm(optParams.menuAnchor, optSet, optParams);
    }
 
     return optSet;
}
}


// Setzt eine Option auf einen vorgegebenen Wert
// Setzt eine Option auf einen vorgegebenen Wert (Version mit Key)
// Fuer kontrollierte Auswahl des Values siehe setNextOpt()
// Fuer kontrollierte Auswahl des Values siehe setNextOptByName()
// opt: Config und vorheriger Value der Option
// optSet: Platz fuer die gesetzten Optionen (und Config)
// item: Key der Option
// value: (Bei allen Typen) Zu setzender Wert
// value: (Bei allen Typen) Zu setzender Wert
// reload: Seite mit neuem Wert neu laden
// reload: Seite mit neuem Wert neu laden
// onFulfilled: Reaktion auf Speicherung im resolve-Fall (1. Promise.then()-Parameter)
// onRejected: Reaktion auf Speicherung im reject-Fall (2. Promise.then()-Parameter)
// return Gesetzter Wert
// return Gesetzter Wert
function setOpt(opt, value, reload = false, onFulfilled = undefined, onRejected = undefined) {
function setOptByName(optSet, item, value, reload = false) {
     return setOptValue(opt, setStored(getOptName(opt), value, reload, getOptConfig(opt).Serial, onFulfilled, onRejected));
    const __OPT = getOptByName(optSet, item);
 
     return setOpt(__OPT, value, reload);
}
}


// Ermittelt die naechste moegliche Option
// Ermittelt die naechste moegliche Option (Version mit Key)
// opt: Config und Value der Option
// optSet: Platz fuer die gesetzten Optionen (und Config)
// value: Ggfs. zu setzender Wert
// item: Key der Option
// value: Default fuer ggfs. zu setzenden Wert
// return Zu setzender Wert
// return Zu setzender Wert
function getNextOpt(opt, value = undefined) {
function getNextOptByName(optSet, item, value = undefined) {
     const __CONFIG = getOptConfig(opt);
     const __OPT = getOptByName(optSet, item);
    const __VALUE = getOptValue(opt, value);


     switch (__CONFIG.Type) {
     return getNextOpt(__OPT, value);
    case __OPTTYPES.MC : return getValue(value, getNextValue(__CONFIG.Choice, __VALUE));
    case __OPTTYPES.SW : return getValue(value, ! __VALUE);
    case __OPTTYPES.TF : return getValue(value, ! __VALUE);
    case __OPTTYPES.SD : return getValue(value, __VALUE);
    case __OPTTYPES.SI : break;
    default :            break;
    }
 
    return __VALUE;
}
}


// Setzt die naechste moegliche Option
// Setzt die naechste moegliche Option (Version mit Key)
// opt: Config und Value der Option
// optSet: Platz fuer die gesetzten Optionen (und Config)
// item: Key der Option
// value: Default fuer ggfs. zu setzenden Wert
// value: Default fuer ggfs. zu setzenden Wert
// reload: Seite mit neuem Wert neu laden
// reload: Seite mit neuem Wert neu laden
// onFulfilled: Reaktion auf Speicherung im resolve-Fall (1. Promise.then()-Parameter)
// onRejected: Reaktion auf Speicherung im reject-Fall (2. Promise.then()-Parameter)
// return Gesetzter Wert
// return Gesetzter Wert
function setNextOpt(opt, value = undefined, reload = false, onFulfilled = undefined, onRejected = undefined) {
function setNextOptByName(optSet, item, value = undefined, reload = false) {
     return setOpt(opt, getNextOpt(opt, value), reload, onFulfilled, onRejected);
    const __OPT = getOptByName(optSet, item);
 
     return setNextOpt(__OPT, value, reload);
}
}


// Setzt die naechste moegliche Option oder fragt ab einer gewissen Anzahl interaktiv ab
// Setzt die naechste moegliche Option oder fragt ab einer gewissen Anzahl interaktiv ab (Version mit Key)
// opt: Config und Value der Option
// optSet: Platz fuer die gesetzten Optionen (und Config)
// item: Key der Option
// value: Default fuer ggfs. zu setzenden Wert
// value: Default fuer ggfs. zu setzenden Wert
// reload: Seite mit neuem Wert neu laden
// reload: Seite mit neuem Wert neu laden
// freeValue: Angabe, ob Freitext zugelassen ist (Default: false)
// freeValue: Angabe, ob Freitext zugelassen ist (Default: false)
// minChoice: Ab wievielen Auswahlmoeglichkeiten soll abgefragt werden? (Default: 3)
// minChoice: Ab wievielen Auswahlmoeglichkeiten soll abgefragt werden? (Default: 3)
// onFulfilled: Reaktion auf Speicherung im resolve-Fall (1. Promise.then()-Parameter)
// onRejected: Reaktion auf Speicherung im reject-Fall (2. Promise.then()-Parameter)
// return Gesetzter Wert
// return Gesetzter Wert
function promptNextOpt(opt, value = undefined, reload = false, freeValue = false, selValue = true, minChoice = 3, onFulfilled = undefined, onRejected = undefined) {
function promptNextOptByName(optSet, item, value = undefined, reload = false, freeValue = false, selValue = true, minChoice = 3) {
     const __CONFIG = getOptConfig(opt);
     const __OPT = getOptByName(optSet, item);
     const __CHOICE = __CONFIG.Choice;
 
     return promptNextOpt(__OPT, value, reload, freeValue, selValue, minChoice);
}
 
// Baut das Benutzermenu auf
// optSet: Gesetzte Optionen
function buildMenu(optSet) {
    __LOG[3]("buildMenu()");


     if (value || (! __CHOICE) || (__CHOICE.length < minChoice)) {
     for (let opt in optSet) {
         return setNextOpt(opt, value, reload, onFulfilled, onRejected);
         registerOption(optSet[opt]);
     }
     }
}


     const __VALUE = getOptValue(opt, value);
// Invalidiert eine (ueber Menu) gesetzte Option
// opt: Zu invalidierende Option
// force: Invalidiert auch Optionen mit 'AutoReset'-Attribut
function invalidateOpt(opt, force = false) {
     if (! opt.ReadOnly) {
        const __CONFIG = getOptConfig(opt);


    try {
        // Wert "ungeladen"...
         const __NEXTVAL = getNextValue(__CHOICE, __VALUE);
         opt.Loaded = (force || ! __CONFIG.AutoReset);
        let message = "";


         if (selValue) {
         if (opt.Loaded && __CONFIG.AutoReset) {
             for (let index = 0; index < __CHOICE.length; index++) {
             // Nur zuruecksetzen, gilt als geladen...
                message += (index + 1) + ") " + __CHOICE[index] + '\n';
            setOptValue(opt, initOptValue(__CONFIG));
            }
            message += "\nNummer oder Wert eingeben:";
        } else {
            message = __CHOICE.join(" / ") + "\n\nWert eingeben:";
         }
         }
    }
}


         const __ANSWER = prompt(message, __NEXTVAL);
// Invalidiert die (ueber Menu) gesetzten Optionen
// optSet: Set mit den Optionen
// force: Invalidiert auch Optionen mit 'AutoReset'-Attribut
// return Set mit den geladenen Optionen
function invalidateOpts(optSet, force = false) {
    for (let opt in optSet) {
         const __OPT = optSet[opt];


         if (__ANSWER) {
         if (__OPT.Loaded) {
             const __INDEX = parseInt(__ANSWER, 10) - 1;
             invalidateOpt(__OPT, force);
            let nextVal = (selValue ? __CHOICE[__INDEX] : undefined);
        }
    }


            if (nextVal === undefined) {
    return optSet;
                const __VALTYPE = getValue(__CONFIG.ValType, 'String');
}
                const __CASTVAL = this[__VALTYPE](__ANSWER);


                if (freeValue || (~ __CHOICE.indexOf(__CASTVAL))) {
// Laedt eine (ueber Menu) gesetzte Option
                    nextVal = __CASTVAL;
// opt: Zu ladende Option
                }
// force: Laedt auch Optionen mit 'AutoReset'-Attribut
            }
// return Gesetzter Wert der gelandenen Option
function loadOption(opt, force = false) {
    const __CONFIG = getOptConfig(opt);
    const __ISSHARED = getValue(__CONFIG.Shared, false, true);
    const __NAME = getOptName(opt);
    const __DEFAULT = getOptValue(opt, undefined, false, false);
    let value;


            if (nextVal !== __VALUE) {
    if (opt.Loaded && ! __ISSHARED) {
                if (nextVal) {
        __LOG[1]("Error: Oprion '" + __NAME + "' bereits geladen!");
                    return setOpt(opt, nextVal, reload, onFulfilled, onRejected);
    }
                }


                const __LABEL = substParam(__CONFIG.Label, __VALUE);
    if (opt.ReadOnly || __ISSHARED) {
 
        value = __DEFAULT;
                showAlert(__LABEL, "Ung\xFCltige Eingabe: " + __ANSWER);
    } else if (! force && __CONFIG.AutoReset) {
            }
        value = initOptValue(__CONFIG);
         }
    } else {
    } catch (ex) {
         value = (__CONFIG.Serial ?
        __LOG[0]("promptNextOpt: " + ex.message);
                        deserialize(__NAME, __DEFAULT) :
                        GM_getValue(__NAME, __DEFAULT));
     }
     }


     return __VALUE;
     __LOG[5]("LOAD " + __NAME + ": " + __LOG.changed(__DEFAULT, value));
}


// Setzt eine Option auf einen vorgegebenen Wert (Version mit Key)
    // Wert als geladen markieren...
// Fuer kontrollierte Auswahl des Values siehe setNextOptByName()
     opt.Loaded = true;
// optSet: Platz fuer die gesetzten Optionen (und Config)
// item: Key der Option
// value: (Bei allen Typen) Zu setzender Wert
// reload: Seite mit neuem Wert neu laden
// onFulfilled: Reaktion auf Speicherung im resolve-Fall (1. Promise.then()-Parameter)
// onRejected: Reaktion auf Speicherung im reject-Fall (2. Promise.then()-Parameter)
// return Gesetzter Wert
function setOptByName(optSet, item, value, reload = false, onFulfilled = undefined, onRejected = undefined) {
     const __OPT = getOptByName(optSet, item);


     return setOpt(__OPT, value, reload, onFulfilled, onRejected);
    // Wert intern setzen...
     return setOptValue(opt, value);
}
}


// Ermittelt die naechste moegliche Option (Version mit Key)
// Laedt die (ueber Menu) gesetzten Optionen
// optSet: Platz fuer die gesetzten Optionen (und Config)
// optSet: Set mit den Optionen
// item: Key der Option
// force: Laedt auch Optionen mit 'AutoReset'-Attribut
// value: Default fuer ggfs. zu setzenden Wert
// return Set mit den geladenen Optionen
// return Zu setzender Wert
function loadOptions(optSet, force = false) {
function getNextOptByName(optSet, item, value = undefined) {
     for (let opt in optSet) {
     const __OPT = getOptByName(optSet, item);
        const __OPT = optSet[opt];
 
        if (! __OPT.Loaded) {
            loadOption(__OPT, force);
        }
    }


     return getNextOpt(__OPT, value);
     return optSet;
}
}


// Setzt die naechste moegliche Option (Version mit Key)
// Entfernt eine (ueber Menu) gesetzte Option (falls nicht 'Permanent')
// optSet: Platz fuer die gesetzten Optionen (und Config)
// opt: Gesetzte Option
// item: Key der Option
// force: Entfernt auch Optionen mit 'Permanent'-Attribut
// value: Default fuer ggfs. zu setzenden Wert
// reset: Setzt bei Erfolg auf Initialwert der Option
// reload: Seite mit neuem Wert neu laden
function deleteOption(opt, force = false, reset = true) {
// onFulfilled: Reaktion auf Speicherung im resolve-Fall (1. Promise.then()-Parameter)
    const __CONFIG = getOptConfig(opt);
// onRejected: Reaktion auf Speicherung im reject-Fall (2. Promise.then()-Parameter)
 
// return Gesetzter Wert
    if (force || ! __CONFIG.Permanent) {
function setNextOptByName(optSet, item, value = undefined, reload = false, onFulfilled = undefined, onRejected = undefined) {
        const __NAME = getOptName(opt);
    const __OPT = getOptByName(optSet, item);
 
        __LOG[4]("DELETE " + __NAME);
 
        GM_deleteValue(__NAME);


    return setNextOpt(__OPT, value, reload, onFulfilled, onRejected);
        if (reset) {
            setOptValue(opt, initOptValue(__CONFIG));
        }
    }
}
}


// Setzt die naechste moegliche Option oder fragt ab einer gewissen Anzahl interaktiv ab (Version mit Key)
// Entfernt die (ueber Menu) gesetzten Optionen (falls nicht 'Permanent')
// optSet: Platz fuer die gesetzten Optionen (und Config)
// item: Key der Option
// value: Default fuer ggfs. zu setzenden Wert
// reload: Seite mit neuem Wert neu laden
// freeValue: Angabe, ob Freitext zugelassen ist (Default: false)
// minChoice: Ab wievielen Auswahlmoeglichkeiten soll abgefragt werden? (Default: 3)
// onFulfilled: Reaktion auf Speicherung im resolve-Fall (1. Promise.then()-Parameter)
// onRejected: Reaktion auf Speicherung im reject-Fall (2. Promise.then()-Parameter)
// return Gesetzter Wert
function promptNextOptByName(optSet, item, value = undefined, reload = false, freeValue = false, selValue = true, minChoice = 3, onFulfilled = undefined, onRejected = undefined) {
    const __OPT = getOptByName(optSet, item);
 
    return promptNextOpt(__OPT, value, reload, freeValue, selValue, minChoice, onFulfilled, onRejected);
}
 
// Baut das Benutzermenu auf (asynchron im Hintergrund)
// optSet: Gesetzte Optionen
// optSet: Gesetzte Optionen
// return Promise auf void
// optSelect: Liste von ausgewaehlten Optionen, true = entfernen, false = nicht entfernen
async function buildMenu(optSet) {
// force: Entfernt auch Optionen mit 'Permanent'-Attribut
     __LOG[3]("buildMenu()");
// reset: Setzt bei Erfolg auf Initialwert der Option
function deleteOptions(optSet, optSelect = undefined, force = false, reset = true) {
     const __DELETEALL = (optSelect === undefined) || (optSelect === true);
    const __OPTSELECT = getValue(optSelect, { });


     for (let opt in optSet) {
     for (let opt in optSet) {
         await registerOption(optSet[opt]).then(
         if (getValue(__OPTSELECT[opt], __DELETEALL)) {
                result => __LOG[6](`REGISTEROPTION[${opt}] = ${result}`),
            deleteOption(optSet[opt], force, reset);
                defaultCatch);
        }
     }
     }
}
}


// Invalidiert eine (ueber Menu) gesetzte Option
// Benennt eine Option um und laedt sie ggfs. nach
// opt: Zu invalidierende Option
// opt: Gesetzte Option
// force: Invalidiert auch Optionen mit 'AutoReset'-Attribut
// name: Neu zu setzender Name (Speicheradresse)
// return Promise auf resultierenden Wert
// reload: Wert nachladen statt beizubehalten
function invalidateOpt(opt, force = false) {
// force: Laedt auch Optionen mit 'AutoReset'-Attribut
     return Promise.resolve(opt.Promise).then(value => {
// return Umbenannte Option
            if (opt.Loaded && ! opt.ReadOnly) {
function renameOption(opt, name, reload = false, force = false) {
                const __CONFIG = getOptConfig(opt);
     const __NAME = getOptName(opt);
 
    if (__NAME !== name) {
        deleteOption(opt, true, ! reload);


                // Wert "ungeladen"...
        setOptName(opt, name);
                opt.Loaded = (force || ! __CONFIG.AutoReset);


                if (opt.Loaded && __CONFIG.AutoReset) {
        if (reload) {
                    // Nur zuruecksetzen, gilt als geladen...
            loadOption(opt, force);
                    setOptValue(opt, initOptValue(__CONFIG));
        }
                }
    }
            }


            return getOptValue(opt);
    return opt;
        }, defaultCatch);
}
}


// Invalidiert die (ueber Menu) gesetzten Optionen
// Ermittelt einen neuen Namen mit einem Prefix. Parameter fuer renameOptions()
// optSet: Object mit den Optionen
// name: Gesetzter Name (Speicheradresse)
// force: Invalidiert auch Optionen mit 'AutoReset'-Attribut
// prefix: Prefix, das vorangestellt werden soll
// return Promise auf Object mit den geladenen Optionen
// return Neu zu setzender Name (Speicheradresse)
async function invalidateOpts(optSet, force = false) {
function prefixName(name, prefix) {
     for (let opt in optSet) {
     return (prefix + name);
        const __OPT = optSet[opt];
}


        await invalidateOpt(__OPT, force);
// Ermittelt einen neuen Namen mit einem Postfix. Parameter fuer renameOptions()
    }
// name: Gesetzter Name (Speicheradresse)
 
// postfix: Postfix, das angehaengt werden soll
     return optSet;
// return Neu zu setzender Name (Speicheradresse)
function postfixName(name, postfix) {
     return (name + postfix);
}
}


// Laedt eine (ueber Menu) gesetzte Option
// Benennt selektierte Optionen nach einem Schema um und laedt sie ggfs. nach
// opt: Zu ladende Option
// optSet: Gesetzte Optionen
// force: Laedt auch Optionen mit 'AutoReset'-Attribut
// optSelect: Liste von ausgewaehlten Optionen, true = nachladen, false = nicht nachladen
// return Promise auf gesetzten Wert der gelandenen Option
// 'reload': Option nachladen?
function loadOption(opt, force = false) {
// 'force': Option auch mit 'AutoReset'-Attribut nachladen?
     if (! opt.Promise) {
// renameParam: Wird an renameFun uebergeen
         const __CONFIG = getOptConfig(opt);
// renameFun: function(name, param) zur Ermittlung des neuen Namens
        const __ISSHARED = getValue(__CONFIG.Shared, false, true);
// - name: Neu zu setzender Name (Speicheradresse)
        const __NAME = getOptName(opt);
// - param: Parameter "renameParam" von oben, z.B. Prefix oder Postfix
         const __DEFAULT = getOptValue(opt, undefined, false, false, false);
function renameOptions(optSet, optSelect, renameParam = undefined, renameFun = prefixName) {
        let value;
     if (renameFun === undefined) {
 
         __LOG[1]("RENAME: Illegale Funktion!");
         if (opt.Loaded && ! __ISSHARED) {
    }
            const __ERROR = "Error: Oprion '" + __NAME + "' bereits geladen!";
    for (let opt in optSelect) {
         const __OPTPARAMS = optSelect[opt];
         const __OPT = optSet[opt];


             __LOG[0](__MESSAGE);
        if (__OPT === undefined) {
             __LOG[1]("RENAME: Option '" + opt + "' nicht gefunden!");
        } else {
            const __NAME = getOptName(__OPT);
            const __NEWNAME = renameFun(__NAME, renameParam);
            const __ISSCALAR = ((typeof __OPTPARAMS) === 'boolean');
            // Laedt die unter dem neuen Namen gespeicherten Daten nach?
            const __RELOAD = (__ISSCALAR ? __OPTPARAMS : __OPTPARAMS.reload);
            // Laedt auch Optionen mit 'AutoReset'-Attribut?
            const __FORCE = (__ISSCALAR ? true : __OPTPARAMS.force);


             return Promise.reject(__MESSAGE);
             renameOption(__OPT, __NEWNAME, __RELOAD, __FORCE);
         }
         }
        if (opt.ReadOnly || __ISSHARED) {
            value = __DEFAULT;
        } else if (! force && __CONFIG.AutoReset) {
            value = initOptValue(__CONFIG);
        } else {
            value = (__CONFIG.Serial ?
                            deserialize(__NAME, __DEFAULT) :
                            GM.getValue(__NAME, __DEFAULT));
        }
        opt.Promise = Promise.resolve(value).then(value => {
                // Paranoide Sicherheitsabfrage (das sollte nie passieren!)...
                if (opt.Loaded || ! opt.Promise) {
                    showAlert("Error", "Unerwarteter Widerspruch zwischen opt.Loaded und opt.Promise", safeStringify(opt));
                }
                __LOG[5]("LOAD " + __NAME + ": " + __LOG.changed(__DEFAULT, value));
                // Wert intern setzen...
                const __VAL = setOptValue(opt, value);
                // Wert als geladen markieren...
                opt.Promise = undefined;
                opt.Loaded = true;
                return __VAL;
            }, defaultCatch);
     }
     }
    return opt.Promise;
}
}


// Laedt die (ueber Menu) gesetzten Optionen
// Setzt die Optionen in optSet auf die "Werkseinstellungen" des Skripts
// optSet: Object mit den Optionen
// optSet: Gesetzte Optionen
// force: Laedt auch Optionen mit 'AutoReset'-Attribut
// reload: Seite mit "Werkseinstellungen" neu laden
// return Array mit Promises neuer Ladevorgaenge (fuer Objekte mit 'name' und 'value')
function resetOptions(optSet, reload = true) {
function loadOptions(optSet, force = false) {
    // Alle (nicht 'Permanent') gesetzten Optionen entfernen...
    const __PROMISES = [];
    deleteOptions(optSet, true, false, ! reload);


     for (let opt in optSet) {
     if (reload) {
         const __OPT = optSet[opt];
         // ... und Seite neu laden (mit "Werkseinstellungen")...
 
        window.location.reload();
        if (! __OPT.Loaded) {
            const __PROMISE = loadOption(__OPT, force).then(value => {
                    __LOG[5]("LOADED " + opt + " << " + value);
 
                    return Promise.resolve({
                            'name'  : opt,
                            'value' : value
                        });
                }, defaultCatch);
 
            __PROMISES.push(__PROMISE);
        }
     }
     }
    return Promise.all(__PROMISES);
}
}


// Entfernt eine (ueber Menu) gesetzte Option (falls nicht 'Permanent')
// ==================== Abschnitt fuer diverse Utilities ====================
// opt: Gesetzte Option
// force: Entfernt auch Optionen mit 'Permanent'-Attribut
// reset: Setzt bei Erfolg auf Initialwert der Option (auch fuer nicht 'AutoReset')
// return Promise von GM.deleteValue() (oder void)
function deleteOption(opt, force = false, reset = true) {
    const __CONFIG = getOptConfig(opt);


     if (force || ! __CONFIG.Permanent) {
// Legt Input-Felder in einem Form-Konstrukt an, falls noetig
         const __NAME = getOptName(opt);
// form: <form>...</form>
 
// props: Map von name:value-Paaren
        __LOG[4]("DELETE " + __NAME);
// type: Typ der Input-Felder (Default: unsichtbare Daten)
 
// return Ergaenztes Form-Konstrukt
        return GM.deleteValue(__NAME).then(voidValue => {
function addInputField(form, props, type = "hidden") {
                if (reset || __CONFIG.AutoReset) {
     for (let fieldName in props) {
                    setOptValue(opt, initOptValue(__CONFIG));
         let field = form[fieldName];
                }
        if (! field) {
            }, defaultCatch);
            field = document.createElement("input");
            field.type = type;
            field.name = fieldName;
            form.appendChild(field);
        }
        field.value = props[fieldName];
     }
     }


     return Promise.resolve();
     return form;
}
}


// Entfernt die (ueber Menu) gesetzten Optionen (falls nicht 'Permanent')
// Legt unsichtbare Input-Daten in einem Form-Konstrukt an, falls noetig
// optSet: Gesetzte Optionen
// form: <form>...</form>
// optSelect: Liste von ausgewaehlten Optionen, true = entfernen, false = nicht entfernen
// props: Map von name:value-Paaren
// force: Entfernt auch Optionen mit 'Permanent'-Attribut
// return Ergaenztes Form-Konstrukt
// reset: Setzt bei Erfolg auf Initialwert der Option
function addHiddenField(form, props) {
// return Promise auf diesen Vorgang
     return addInputField(form, props, "hidden");
async function deleteOptions(optSet, optSelect = undefined, force = false, reset = true) {
}
     const __DELETEALL = ((optSelect === undefined) || (optSelect === true));
    const __OPTSELECT = getValue(optSelect, { });


     for (let opt in optSet) {
// Hilfsfunktion fuer alle Browser: Fuegt fuer ein Event eine Reaktion ein
         if (getValue(__OPTSELECT[opt], __DELETEALL)) {
// obj: Betroffenes Objekt, z.B. ein Eingabeelement
            await deleteOption(optSet[opt], force, reset);
// type: Name des Events, z.B. "click"
         }
// callback: Funktion als Reaktion
// capture: Event fuer Parent zuerst (true) oder Child (false als Default)
// return false bei Misserfolg
function addEvent(obj, type, callback, capture = false) {
     if (obj.addEventListener) {
         return obj.addEventListener(type, callback, capture);
    } else if (obj.attachEvent) {
        return obj.attachEvent("on" + type, callback);
    } else {
        __LOG[1]("Could not add " + type + " event:");
        __LOG[2](callback);
 
         return false;
     }
     }
    return Promise.resolve();
}
}


// Benennt eine Option um und laedt sie ggfs. nach
// Hilfsfunktion fuer alle Browser: Entfernt eine Reaktion fuer ein Event
// opt: Gesetzte Option
// obj: Betroffenes Objekt, z.B. ein Eingabeelement
// name: Neu zu setzender Name (Speicheradresse)
// type: Name des Events, z.B. "click"
// reload: Wert nachladen statt beizubehalten
// callback: Funktion als Reaktion
// force: Laedt auch Optionen mit 'AutoReset'-Attribut
// capture: Event fuer Parent zuerst (true) oder Child (false als Default)
// return Promise auf umbenannte Option
// return false bei Misserfolg
async function renameOption(opt, name, reload = false, force = false) {
function removeEvent(obj, type, callback, capture = false) {
     const __NAME = getOptName(opt);
    if (obj.removeEventListener) {
        return obj.removeEventListener(type, callback, capture);
    } else if (obj.detachEvent) {
        return obj.detachEvent("on" + type, callback);
     } else {
        __LOG[1]("Could not remove " + type + " event:");
        __LOG[2](callback);


     if (__NAME !== name) {
        return false;
        await deleteOption(opt, true, ! reload);
     }
}
 
// Hilfsfunktion fuer alle Browser: Fuegt fuer ein Event eine Reaktion ein
// id: ID des betroffenen Eingabeelements
// type: Name des Events, z.B. "click"
// callback: Funktion als Reaktion
// capture: Event fuer Parent zuerst (true) oder Child (false als Default)
// return false bei Misserfolg
function addDocEvent(id, type, callback, capture = false) {
    const __OBJ = document.getElementById(id);


        setOptName(opt, name);
    return addEvent(__OBJ, type, callback, capture);
}


        await invalidateOpt(opt, opt.Loaded);
// Hilfsfunktion fuer alle Browser: Entfernt eine Reaktion fuer ein Event
// id: ID des betroffenen Eingabeelements
// type: Name des Events, z.B. "click"
// callback: Funktion als Reaktion
// capture: Event fuer Parent zuerst (true) oder Child (false als Default)
// return false bei Misserfolg
function removeDocEvent(id, type, callback, capture = false) {
    const __OBJ = document.getElementById(id);


        if (reload) {
    return removeEvent(__OBJ, type, callback, capture);
            opt.Loaded = false;
}


            await loadOption(opt, force);
// Hilfsfunktion fuer die Ermittlung eines Elements der Seite
        }
// name: Name des Elements (siehe "name=")
     }
// index: Laufende Nummer des Elements (0-based), Default: 0
// doc: Dokument (document)
// return Gesuchtes Element mit der lfd. Nummer index oder undefined (falls nicht gefunden)
function getElement(name, index = 0, doc = document) {
    const __TAGS = document.getElementsByName(name);
     const __TABLE = (__TAGS === undefined) ? undefined : __TAGS[index];


     return Promise.resolve(opt);
     return __TABLE;
}
}


// Ermittelt einen neuen Namen mit einem Prefix. Parameter fuer renameOptions()
// Hilfsfunktion fuer die Ermittlung eines Elements der Seite (Default: Tabelle)
// name: Gesetzter Name (Speicheradresse)
// index: Laufende Nummer des Elements (0-based)
// prefix: Prefix, das vorangestellt werden soll
// tag: Tag des Elements ("table")
// return Neu zu setzender Name (Speicheradresse)
// doc: Dokument (document)
function prefixName(name, prefix) {
// return Gesuchtes Element oder undefined (falls nicht gefunden)
     return (prefix + name);
function getTable(index, tag = "table", doc = document) {
     const __TAGS = document.getElementsByTagName(tag);
    const __TABLE = (__TAGS === undefined) ? undefined : __TAGS[index];
 
    return __TABLE;
}
}


// Ermittelt einen neuen Namen mit einem Postfix. Parameter fuer renameOptions()
// Hilfsfunktion fuer die Ermittlung der Zeilen einer Tabelle
// name: Gesetzter Name (Speicheradresse)
// index: Laufende Nummer des Elements (0-based)
// postfix: Postfix, das angehaengt werden soll
// doc: Dokument (document)
// return Neu zu setzender Name (Speicheradresse)
// return Gesuchte Zeilen oder undefined (falls nicht gefunden)
function postfixName(name, postfix) {
function getRows(index, doc = document) {
     return (name + postfix);
     const __TABLE = getTable(index, "table", doc);
    const __ROWS = (__TABLE === undefined) ? undefined : __TABLE.rows;
 
    return __ROWS;
}
}


// Benennt selektierte Optionen nach einem Schema um und laedt sie ggfs. nach
// ==================== Abschnitt fuer Optionen auf der Seite ====================
// optSet: Gesetzte Optionen
// optSelect: Liste von ausgewaehlten Optionen, true = nachladen, false = nicht nachladen
// 'reload': Option nachladen?
// 'force': Option auch mit 'AutoReset'-Attribut nachladen?
// renameParam: Wird an renameFun uebergeen
// renameFun: function(name, param) zur Ermittlung des neuen Namens
// - name: Neu zu setzender Name (Speicheradresse)
// - param: Parameter "renameParam" von oben, z.B. Prefix oder Postfix
// return Promise auf diesen Vorgang
async function renameOptions(optSet, optSelect, renameParam = undefined, renameFun = prefixName) {
    if (renameFun === undefined) {
        __LOG[0]("RENAME: Illegale Funktion!");
    }
    for (let opt in optSelect) {
        const __OPTPARAMS = optSelect[opt];
        const __OPT = optSet[opt];


        if (__OPT === undefined) {
// Liefert den Funktionsaufruf zur Option als String
            __LOG[0]("RENAME: Option '" + opt + "' nicht gefunden!");
// opt: Auszufuehrende Option
        } else {
// isAlt: Angabe, ob AltAction statt Action gemeint ist
            const __NAME = getOptName(__OPT);
// value: Ggfs. zu setzender Wert
            const __NEWNAME = renameFun(__NAME, renameParam);
// serial: Serialization fuer String-Werte (Select, Textarea)
            const __ISSCALAR = ((typeof __OPTPARAMS) === 'boolean');
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
            // Laedt die unter dem neuen Namen gespeicherten Daten nach?
// return String mit dem (reinen) Funktionsaufruf
            const __RELOAD = (__ISSCALAR ? __OPTPARAMS : __OPTPARAMS.reload);
function getFormAction(opt, isAlt = false, value = undefined, serial = undefined, memory = undefined) {
            // Laedt auch Optionen mit 'AutoReset'-Attribut?
    const __STORAGE = getMemory(memory);
            const __FORCE = (__ISSCALAR ? true : __OPTPARAMS.force);
    const __MEMORY = __STORAGE.Value;
    const __MEMSTR = __STORAGE.Display;
    const __RUNPREFIX = __STORAGE.Prefix;


            await renameOption(__OPT, __NEWNAME, __RELOAD, __FORCE);
    if (__MEMORY !== undefined) {
         }
        const __RELOAD = "window.location.reload()";
    }
        const __SETITEM = function(item, val, quotes = true) {
}
                              return (__MEMSTR + ".setItem('" + __RUNPREFIX + item + "', " + (quotes ? "'" + val + "'" : val) + "),");
                          };
        const __SETITEMS = function(cmd, key = undefined, val = undefined) {
                              return ('(' + __SETITEM('cmd', cmd) + ((key === undefined) ? "" :
                                      __SETITEM('key', key) + __SETITEM('val', val, false)) + __RELOAD + ')');
                          };
        const __CONFIG = getOptConfig(opt);
        const __SERIAL = getValue(serial, getValue(__CONFIG.Serial, false));
        const __THISVAL = ((__CONFIG.ValType === "String") ? "'\\x22' + this.value + '\\x22'" : "this.value");
         const __TVALUE = getValue(__CONFIG.ValType, __THISVAL, "new " + __CONFIG.ValType + '(' + __THISVAL + ')');
        const __VALSTR = ((value !== undefined) ? safeStringify(value) : __SERIAL ? "JSON.stringify(" + __TVALUE + ')' : __TVALUE);
        const __ACTION = (isAlt ? getValue(__CONFIG.AltAction, __CONFIG.Action) : __CONFIG.Action);


// Setzt die Optionen in optSet auf die "Werkseinstellungen" des Skripts
        if (__ACTION !== undefined) {
// optSet: Gesetzte Optionen
            switch (__ACTION) {
// reload: Seite mit "Werkseinstellungen" neu laden
            case __OPTACTION.SET : //return "doActionSet('" + getOptName(opt) + "', " + getNextOpt(opt, __VALSTR) + ')';
// return Promise auf diesen Vorgang
                                  return __SETITEMS('SET', getOptName(opt), __VALSTR);
async function resetOptions(optSet, reload = true) {
            case __OPTACTION.NXT : //return "doActionNxt('" + getOptName(opt) + "', " + getNextOpt(opt, __VALSTR) + ')';
    // Alle (nicht 'Permanent') gesetzten Optionen entfernen...
                                  return __SETITEMS('NXT', getOptName(opt), __VALSTR);
    await deleteOptions(optSet, true, false, ! reload);
            case __OPTACTION.RST : //return "doActionRst()";
 
                                  return __SETITEMS('RST');
    // ... und ggfs. Seite neu laden (mit "Werkseinstellungen")...
             default :              break;
    refreshPage(reload);
             }
}
 
// ==================== Abschnitt fuer diverse Utilities ====================
 
// Legt Input-Felder in einem Form-Konstrukt an, falls noetig
// form: <form>...</form>
// props: Map von name:value-Paaren
// type: Typ der Input-Felder (Default: unsichtbare Daten)
// return Ergaenztes Form-Konstrukt
function addInputField(form, props, type = 'hidden') {
    for (let fieldName in props) {
        let field = form[fieldName];
        if (! field) {
            field = document.createElement('input');
             field.type = type;
             field.name = fieldName;
            form.appendChild(field);
         }
         }
        field.value = props[fieldName];
     }
     }


     return form;
     return undefined;
}
}


// Legt unsichtbare Input-Daten in einem Form-Konstrukt an, falls noetig
// Liefert die Funktionsaufruf zur Option als String
// form: <form>...</form>
// opt: Auszufuehrende Option
// props: Map von name:value-Paaren
// isAlt: Angabe, ob AltAction statt Action gemeint ist
// return Ergaenztes Form-Konstrukt
// value: Ggfs. zu setzender Wert
function addHiddenField(form, props) {
// type: Event-Typ fuer <input>, z.B. "click" fuer "onclick="
     return addInputField(form, props, 'hidden');
// serial: Serialization fuer String-Werte (Select, Textarea)
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
// return String mit dem (reinen) Funktionsaufruf
function getFormActionEvent(opt, isAlt = false, value = undefined, type = "click", serial = undefined, memory = undefined) {
    const __ACTION = getFormAction(opt, isAlt, value, serial, memory);
 
     return getValue(__ACTION, "", ' on' + type + '="' + __ACTION + '"');
}
}


// Hilfsfunktion fuer alle Browser: Fuegt fuer ein Event eine Reaktion ein
// Zeigt eine Option auf der Seite als Auswahlbox an
// obj: Betroffenes Objekt, z.B. ein Eingabeelement
// opt: Anzuzeigende Option
// type: Name des Events, z.B. "click"
// return String mit dem HTML-Code
// callback: Funktion als Reaktion
function getOptionSelect(opt) {
// capture: Event fuer Parent zuerst (true) oder Child (false als Default)
    const __CONFIG = getOptConfig(opt);
// return false bei Misserfolg
    const __NAME = getOptName(opt);
function addEvent(obj, type, callback, capture = false) {
     const __VALUE = getOptValue(opt);
     if (obj.addEventListener) {
    const __ACTION = getFormActionEvent(opt, false, undefined, "change", undefined);
        return obj.addEventListener(type, callback, capture);
     const __FORMLABEL = getValue(__CONFIG.FormLabel, __CONFIG.Label);
     } else if (obj.attachEvent) {
    const __LABEL = '<label for="' + __NAME + '">' + __FORMLABEL + '</label>';
        return obj.attachEvent('on' + type, callback);
     let element = '<select name="' + __NAME + '" id="' + __NAME + '"' + __ACTION + '>';
     } else {
        __LOG[0]("Could not add " + type + " event:");
        __LOG[2](callback);


         return false;
    if (__CONFIG.FreeValue && ! (~ __CONFIG.Choice.indexOf(__VALUE))) {
         element += '\n<option value="' + __VALUE + '" SELECTED>' + __VALUE + '</option>';
     }
     }
}
     for (let value of __CONFIG.Choice) {
 
         element += '\n<option value="' + value + '"' +
// Hilfsfunktion fuer alle Browser: Entfernt eine Reaktion fuer ein Event
                  ((value === __VALUE) ? ' SELECTED' : "") +
// obj: Betroffenes Objekt, z.B. ein Eingabeelement
                  '>' + value + '</option>';
// type: Name des Events, z.B. "click"
// callback: Funktion als Reaktion
// capture: Event fuer Parent zuerst (true) oder Child (false als Default)
// return false bei Misserfolg
function removeEvent(obj, type, callback, capture = false) {
     if (obj.removeEventListener) {
         return obj.removeEventListener(type, callback, capture);
    } else if (obj.detachEvent) {
        return obj.detachEvent('on' + type, callback);
    } else {
        __LOG[0]("Could not remove " + type + " event:");
        __LOG[2](callback);
 
        return false;
     }
     }
}
     element += '\n</select>';
 
// Hilfsfunktion fuer alle Browser: Fuegt fuer ein Event eine Reaktion ein
// id: ID des betroffenen Eingabeelements
// type: Name des Events, z.B. "click"
// callback: Funktion als Reaktion
// capture: Event fuer Parent zuerst (true) oder Child (false als Default)
// return false bei Misserfolg
function addDocEvent(id, type, callback, capture = false) {
     const __OBJ = document.getElementById(id);


     return addEvent(__OBJ, type, callback, capture);
     return __LABEL.replace('$', element);
}
}


// Hilfsfunktion fuer alle Browser: Entfernt eine Reaktion fuer ein Event
// Zeigt eine Option auf der Seite als Radiobutton an
// id: ID des betroffenen Eingabeelements
// opt: Anzuzeigende Option
// type: Name des Events, z.B. "click"
// return String mit dem HTML-Code
// callback: Funktion als Reaktion
function getOptionRadio(opt) {
// capture: Event fuer Parent zuerst (true) oder Child (false als Default)
    const __CONFIG = getOptConfig(opt);
// return false bei Misserfolg
    const __NAME = getOptName(opt);
function removeDocEvent(id, type, callback, capture = false) {
    const __VALUE = getOptValue(opt, false);
     const __OBJ = document.getElementById(id);
    const __ACTION = getFormActionEvent(opt, false, true, "click", false);
    const __ALTACTION = getFormActionEvent(opt, true, false, "click", false);
     const __ELEMENTON  = '<input type="radio" name="' + __NAME +
                        '" id="' + __NAME + 'ON" value="1"' +
                        (__VALUE ? ' CHECKED' : __ACTION) +
                        ' /><label for="' + __NAME + 'ON">' +
                        __CONFIG.Label + '</label>';
    const __ELEMENTOFF = '<input type="radio" name="' + __NAME +
                        '" id="' + __NAME + 'OFF" value="0"' +
                        (__VALUE ? __ALTACTION : ' CHECKED') +
                        ' /><label for="' + __NAME + 'OFF">' +
                        __CONFIG.AltLabel + '</label>';


     return removeEvent(__OBJ, type, callback, capture);
     return [ __ELEMENTON, __ELEMENTOFF ];
}
}


// Hilfsfunktion fuer die Ermittlung eines Elements der Seite
// Zeigt eine Option auf der Seite als Checkbox an
// name: Name des Elements (siehe "name=")
// opt: Anzuzeigende Option
// index: Laufende Nummer des Elements (0-based), Default: 0
// return String mit dem HTML-Code
// doc: Dokument (document)
function getOptionCheckbox(opt) {
// return Gesuchtes Element mit der lfd. Nummer index oder undefined (falls nicht gefunden)
    const __CONFIG = getOptConfig(opt);
function getElement(name, index = 0, doc = document) {
    const __NAME = getOptName(opt);
     const __TAGS = doc.getElementsByName(name);
    const __VALUE = getOptValue(opt, false);
     const __TABLE = (__TAGS ? __TAGS[index] : undefined);
     const __ACTION = getFormActionEvent(opt, __VALUE, ! __VALUE, "click", false);
     const __FORMLABEL = getValue(__CONFIG.FormLabel, __CONFIG.Label);


     return __TABLE;
     return '<input type="checkbox" name="' + __NAME +
          '" id="' + __NAME + '" value="' + __VALUE + '"' +
          (__VALUE ? ' CHECKED' : "") + __ACTION + ' /><label for="' +
          __NAME + '">' + __FORMLABEL + '</label>';
}
}


// Hilfsfunktion fuer die Ermittlung eines Elements der Seite (Default: Tabelle)
// Zeigt eine Option auf der Seite als Daten-Textfeld an
// index: Laufende Nummer des Elements (0-based)
// opt: Anzuzeigende Option
// tag: Tag des Elements ("table")
// return String mit dem HTML-Code
// doc: Dokument (document)
function getOptionTextarea(opt) {
// return Gesuchtes Element oder undefined (falls nicht gefunden)
    const __CONFIG = getOptConfig(opt);
function getTable(index, tag = 'table', doc = document) {
    const __NAME = getOptName(opt);
     const __TAGS = doc.getElementsByTagName(tag);
    const __VALUE = getOptValue(opt);
     const __TABLE = (__TAGS ? __TAGS[index] : undefined);
    const __ACTION = getFormActionEvent(opt, false, undefined, "submit", undefined);
    const __SUBMIT = getValue(__CONFIG.Submit, "");
    //const __ONSUBMIT = (__SUBMIT.length ? ' onKeyDown="' + __SUBMIT + '"': "");
    const __ONSUBMIT = (__SUBMIT ? ' onKeyDown="' + __SUBMIT + '"': "");
     const __FORMLABEL = getValue(__CONFIG.FormLabel, __CONFIG.Label);
     const __ELEMENTLABEL = '<label for="' + __NAME + '">' + __FORMLABEL + '</label>';
    const __ELEMENTTEXT = '<textarea name="' + __NAME + '" id="' + __NAME + '" cols="' + __CONFIG.Cols +
                          '" rows="' + __CONFIG.Rows + '"' + __ONSUBMIT + __ACTION + '>' +
                          safeStringify(__VALUE, __CONFIG.Replace, __CONFIG.Space) + '</textarea>';


     return __TABLE;
     return [ __ELEMENTLABEL, __ELEMENTTEXT ];
}
}


// Hilfsfunktion fuer die Ermittlung der Zeilen einer Tabelle
// Zeigt eine Option auf der Seite als Button an
// name: Name des Tabellen-Elements (siehe "name=")
// opt: Anzuzeigende Option
// index: Laufende Nummer des Tabellen-Elements (0-based), Default: 0
// return String mit dem HTML-Code
// doc: Dokument (document)
function getOptionButton(opt) {
// return Gesuchte Zeilen oder undefined (falls nicht gefunden)
    const __CONFIG = getOptConfig(opt);
function getElementRows(name, index = 0, doc = document) {
    const __NAME = getOptName(opt);
     const __TABLE = getElement(name, index, doc);
    const __VALUE = getOptValue(opt, false);
     const __ROWS = (__TABLE ? __TABLE.rows : undefined);
     const __ACTION = getFormActionEvent(opt, __VALUE, ! __VALUE, "click", false);
     const __BUTTONLABEL = (__VALUE ? __CONFIG.AltLabel : __CONFIG.Label);
    const __FORMLABEL = getValue(__CONFIG.FormLabel, __CONFIG.Label);


     return __ROWS;
     return '<label for="' + __NAME + '">' + __FORMLABEL +
          '</label><input type="button" name="' + __NAME +
          '" id="' + __NAME + '" value="' + __BUTTONLABEL + '"' +
          __ACTION + '/>';
}
}


// Hilfsfunktion fuer die Ermittlung der Zeilen einer Tabelle
// Zeigt eine Option auf der Seite an (je nach Typ)
// index: Laufende Nummer des Elements (0-based)
// opt: Anzuzeigende Option
// doc: Dokument (document)
// return String mit dem HTML-Code
// return Gesuchte Zeilen oder undefined (falls nicht gefunden)
function getOptionElement(opt) {
function getRows(index, doc = document) {
     const __CONFIG = getOptConfig(opt);
     const __TABLE = getTable(index, 'table', doc);
     const __TYPE = getValue(__CONFIG.FormType, __CONFIG.Type);
     const __ROWS = (__TABLE ? __TABLE.rows : undefined);
    let element = "";


     return __ROWS;
     if (! __CONFIG.Hidden) {
}
        switch (__TYPE) {
        case __OPTTYPES.MC : element = getOptionSelect(opt);
                            break;
        case __OPTTYPES.SW : if (__CONFIG.FormLabel !== undefined) {
                                element = getOptionCheckbox(opt);
                            } else {
                                element = getOptionRadio(opt);
                            }
                            break;
        case __OPTTYPES.TF : element = getOptionCheckbox(opt);
                            break;
        case __OPTTYPES.SD : element = getOptionTextarea(opt);
                            break;
        case __OPTTYPES.SI : element = getOptionButton(opt);
                            break;
        default :            break;
        }


// Hilfsfunktion fuer die Ermittlung der Zeilen einer Tabelle
        if (element.length === 2) {
// id: ID des Tabellen-Elements
            element = '<div>' + element[0] + '<br />' + element[1] + '</div>';
// doc: Dokument (document)
        }
// return Gesuchte Zeilen oder undefined (falls nicht gefunden)
     }
function getRowsById(id, doc = document) {
    const __TABLE = doc.getElementById(id);
     const __ROWS = (__TABLE ? __TABLE.rows : undefined);


     return __ROWS;
     return element;
}
}


// ==================== Abschnitt fuer Optionen auf der Seite ====================
// Baut das Benutzermenu auf der Seite auf
 
// optSet: Gesetzte Optionen
// Liefert den Funktionsaufruf zur Option als String
// optParams: Eventuell notwendige Parameter
// opt: Auszufuehrende Option
// 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar)
// isAlt: Angabe, ob AltAction statt Action gemeint ist
// 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar)
// value: Ggfs. zu setzender Wert
// 'formWidth': Anzahl der Elemente pro Zeile
// serial: Serialization fuer String-Werte (Select, Textarea)
// 'formBreak': Elementnummer des ersten Zeilenumbruchs
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
// return String mit dem HTML-Code
// return String mit dem (reinen) Funktionsaufruf
function getForm(optSet, optParams = { }) {
function getFormAction(opt, isAlt = false, value = undefined, serial = undefined, memory = undefined) {
    const __FORM = '<form id="options" method="POST"><table><tbody><tr>';
     const __STORAGE = getMemory(memory);
    const __FORMEND = '</tr></tbody></table></form>';
     const __MEMORY = __STORAGE.Value;
     const __FORMWIDTH = getValue(optParams.formWidth, 3);
     const __MEMSTR = __STORAGE.Display;
     const __FORMBREAK = getValue(optParams.formBreak, __FORMWIDTH);
     const __RUNPREFIX = __STORAGE.Prefix;
     const __SHOWFORM = getOptValue(optSet.showForm, true) ? optParams.showForm : { 'showForm' : true };
     let form = __FORM;
    let count = 0;  // Bisher angezeigte Optionen
    let column = 0; // Spalte der letzten Option (1-basierend)


     if (__MEMORY !== undefined) {
     for (let opt in optSet) {
         const __RELOAD = "window.location.reload()";
         if (checkItem(opt, __SHOWFORM, optParams.hideForm)) {
        const __SETITEM = function(item, val, quotes = true) {
            const __ELEMENT = getOptionElement(optSet[opt]);
                              return (__MEMSTR + ".setItem('" + __RUNPREFIX + item + "', " + (quotes ? "'" + val + "'" : val) + "),");
            const __TDOPT = (~ __ELEMENT.indexOf('|')) ? "" : ' colspan="2"';
                          };
        const __SETITEMS = function(cmd, key = undefined, val = undefined) {
                              return ('(' + __SETITEM('cmd', cmd) + ((key === undefined) ? "" :
                                      __SETITEM('key', key) + __SETITEM('val', val, false)) + __RELOAD + ')');
                          };
        const __CONFIG = getOptConfig(opt);
        const __SERIAL = getValue(serial, getValue(__CONFIG.Serial, false));
        const __THISVAL = ((__CONFIG.ValType === 'String') ? "'\\x22' + this.value + '\\x22'" : "this.value");
        const __TVALUE = getValue(__CONFIG.ValType, __THISVAL, "new " + __CONFIG.ValType + '(' + __THISVAL + ')');
        const __VALSTR = ((value !== undefined) ? safeStringify(value) : __SERIAL ? "JSON.stringify(" + __TVALUE + ')' : __TVALUE);
        const __ACTION = (isAlt ? getValue(__CONFIG.AltAction, __CONFIG.Action) : __CONFIG.Action);


        if (__ACTION !== undefined) {
            if (__ELEMENT) {
            switch (__ACTION) {
                if (++count > __FORMBREAK) {
            case __OPTACTION.SET : //return "doActionSet('" + getOptName(opt) + "', " + getNextOpt(opt, __VALSTR) + ')';
                    if (++column > __FORMWIDTH) {
                                  return __SETITEMS('SET', getOptName(opt), __VALSTR);
                        column = 1;
            case __OPTACTION.NXT : //return "doActionNxt('" + getOptName(opt) + "', " + getNextOpt(opt, __VALSTR) + ')';
                    }
                                  return __SETITEMS('NXT', getOptName(opt), __VALSTR);
                }
            case __OPTACTION.RST : //return "doActionRst()";
                if (column === 1) {
                                  return __SETITEMS('RST');
                    form += '</tr><tr>';
            default :              break;
                }
                form += '\n<td' + __TDOPT + '>' + __ELEMENT.replace('|', '</td><td>') + '</td>';
             }
             }
         }
         }
     }
     }
    form += '\n' + __FORMEND;


     return undefined;
     return form;
}
}


// Liefert die Funktionsaufruf zur Option als String
// Fuegt das Script in die Seite ein
// opt: Auszufuehrende Option
// optSet: Gesetzte Optionen
// isAlt: Angabe, ob AltAction statt Action gemeint ist
// optParams: Eventuell notwendige Parameter
// value: Ggfs. zu setzender Wert
// 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar)
// type: Event-Typ fuer <input>, z.B. "click" fuer "onclick="
// 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar)
// serial: Serialization fuer String-Werte (Select, Textarea)
// return String mit dem HTML-Code fuer das Script
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
function getScript(optSet, optParams = { }) {
// return String mit dem (reinen) Funktionsaufruf
    //const __SCRIPT = '<script type="text/javascript">function activateMenu() { console.log("TADAAA!"); }</script>';
function getFormActionEvent(opt, isAlt = false, value = undefined, type = 'click', serial = undefined, memory = undefined) {
    //const __SCRIPT = '<script type="text/javascript">\n\tfunction doActionNxt(key, value) { alert("SET " + key + " = " + value); }\n\tfunction doActionNxt(key, value) { alert("SET " + key + " = " + value); }\n\tfunction doActionRst(key, value) { alert("RESET"); }\n</script>';
     const __ACTION = getFormAction(opt, isAlt, value, serial, memory);
    //const __FORM = '<form method="POST"><input type="button" id="showOpts" name="showOpts" value="Optionen anzeigen" onclick="activateMenu()" /></form>';
     const __SCRIPT = "";


     return getValue(__ACTION, "", ' on' + type + '="' + __ACTION + '"');
     //window.eval('function activateMenu() { console.log("TADAAA!"); }');
}


// Hilfsfunktion: Wendet eine Konvertierung auf jede "Zeile" innerhalb eines Textes an
     return __SCRIPT;
// text: Urspruenglicher Text
// convFun: function(line, index, arr): Konvertiert line in "Zeile" line des Arrays arr
// separator: Zeilentrenner im Text (Default: '\n')
// thisArg: optionaler this-Parameter fuer die Konvertierung
// limit: optionale Begrenzung der Zeilen
// return String mit dem neuen Text
function eachLine(text, convFun, separator = '\n', thisArg = undefined, limit = undefined) {
    const __ARR = text.split(separator, limit);
    const __RES = __ARR.map(convFun, thisArg);
 
     return __RES.join(separator);
}
}


// Hilfsfunktion: Ergaenzt einen HTML-Code um einen Titel (ToolTip)
// Zeigt das Optionsmenu auf der Seite an (im Gegensatz zum Benutzermenu)
// html: Urspruenglicher HTML-Code (z.B. ein HTML-Element oder Text)
// anchor: Element, das als Anker fuer die Anzeige dient
// title: Im ToolTip angezeigter Text
// optSet: Gesetzte Optionen
// separator: Zeilentrenner im Text (Default: '|')
// optParams: Eventuell notwendige Parameter
// limit: optionale Begrenzung der Zeilen
// 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar)
// return String mit dem neuen HTML-Code
// 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar)
function withTitle(html, title, separator = '|', limit = undefined) {
// 'formWidth': Anzahl der Elemente pro Zeile
     if (title && title.length) {
// 'formBreak': Elementnummer des ersten Zeilenumbruchs
        return eachLine(html, line => '<abbr title="' + title + '">' + line + '</abbr>', separator, undefined, limit);
function buildForm(anchor, optSet, optParams = { }) {
    } else {
     __LOG[3]("buildForm()");
        return html;
    }
}


// Hilfsfunktion: Ermittelt einen Label- oder FormLabel-Eintrag (Default)
    const __FORM = getForm(optSet, optParams);
// label: Config-Eintrag fuer Label oder FormLabel
     const __SCRIPT = getScript(optSet, optParams);
// defLabel: Ersatzwert, falls label nicht angegeben
// isSelect: Angabe, ob ein Parameter angezeigt wird (Default: false)
// isForm: Angabe, ob ein FormLabel gesucht ist (Default: true)
// return Vollstaendiger Label- oder FormLabel-Eintrag
function formatLabel(label, defLabel = undefined, isSelect = false, isForm = true) {
     const __LABEL = getValue(label, defLabel);


     if (isSelect && __LABEL && (substParam(__LABEL, '_') === __LABEL)) {
     addForm(anchor, __FORM, __SCRIPT);
        return __LABEL + (isForm ? "|$" : " $");
    } else {
        return __LABEL;
    }
}
}


// Zeigt eine Option auf der Seite als Auswahlbox an
// Informationen zu hinzugefuegten Forms
// opt: Anzuzeigende Option
const __FORMS = { };
// return String mit dem HTML-Code
 
function getOptionSelect(opt) {
// Zeigt das Optionsmenu auf der Seite an (im Gegensatz zum Benutzermenu)
     const __CONFIG = getOptConfig(opt);
// anchor: Element, das als Anker fuer die Anzeige dient
     const __NAME = getOptName(opt);
// form: HTML-Form des Optionsmenu (hinten angefuegt)
    const __VALUE = getOptValue(opt);
// script: Script mit Reaktionen
    const __ACTION = getFormActionEvent(opt, false, undefined, 'change', undefined);
function addForm(anchor, form = "", script = "") {
    const __FORMLABEL = formatLabel(__CONFIG.FormLabel, __CONFIG.Label, true);
     const __OLDFORM = __FORMS[anchor];
    const __TITLE = substParam(getValue(__CONFIG.Title, __CONFIG.Label), __VALUE);
     const __REST = (__OLDFORM === undefined) ? anchor.innerHTML :
    const __LABEL = '<label for="' + __NAME + '">' + __FORMLABEL + '</label>';
                  anchor.innerHTML.substring(0, anchor.innerHTML.length - __OLDFORM.Script.length - __OLDFORM.Form.length);
    let element = '<select name="' + __NAME + '" id="' + __NAME + '"' + __ACTION + '>';


     if (__CONFIG.FreeValue && ! (~ __CONFIG.Choice.indexOf(__VALUE))) {
     __FORMS[anchor] = {
        element += '\n<option value="' + __VALUE + '" SELECTED>' + __VALUE + '</option>';
                          'Script' : script,
    }
                          'Form'   : form
    for (let value of __CONFIG.Choice) {
                      };
        element += '\n<option value="' + value + '"' +
                  ((value === __VALUE) ? ' SELECTED' : "") +
                  '>' + value + '</option>';
    }
    element += '\n</select>';


     return withTitle(substParam(__LABEL, element), __TITLE);
     anchor.innerHTML = __REST + script + form;
}
}


// Zeigt eine Option auf der Seite als Radiobutton an
// ==================== Abschnitt fuer Klasse Classification ====================
// opt: Anzuzeigende Option
 
// return String mit dem HTML-Code
// Basisklasse fuer eine Klassifikation der Optionen nach Kriterium (z.B. Erst- und Zweitteam oder Fremdteam)
function getOptionRadio(opt) {
function Classification() {
    const __CONFIG = getOptConfig(opt);
    'use strict';
    const __NAME = getOptName(opt);
    const __VALUE = getOptValue(opt, false);
    const __ACTION = getFormActionEvent(opt, false, true, 'click', false);
    const __ALTACTION = getFormActionEvent(opt, true, false, 'click', false);
    const __FORMLABEL = formatLabel(__CONFIG.FormLabel); // nur nutzen, falls angegeben
    const __TITLE = getValue(__CONFIG.Title, '$');
    const __TITLEON = substParam(__TITLE, __CONFIG.Label);
    const __TITLEOFF = substParam(getValue(__CONFIG.AltTitle, __TITLE), __CONFIG.AltLabel);
    const __ELEMENTON  = '<input type="radio" name="' + __NAME +
                        '" id="' + __NAME + 'ON" value="1"' +
                        (__VALUE ? ' CHECKED' : __ACTION) +
                        ' /><label for="' + __NAME + 'ON">' +
                        __CONFIG.Label + '</label>';
    const __ELEMENTOFF = '<input type="radio" name="' + __NAME +
                        '" id="' + __NAME + 'OFF" value="0"' +
                        (__VALUE ? __ALTACTION : ' CHECKED') +
                        ' /><label for="' + __NAME + 'OFF">' +
                        __CONFIG.AltLabel + '</label>';
    const __ELEMENT = [
                          withTitle(__FORMLABEL, __VALUE ? __TITLEON : __TITLEOFF),
                          withTitle(__ELEMENTON, __TITLEON),
                          withTitle(__ELEMENTOFF, __TITLEOFF)
                      ];


     return ((__FORMLABEL && __FORMLABEL.length) ? __ELEMENT : __ELEMENT.slice(1, 3));
     this.renameFun = prefixName;
    //this.renameParamFun = undefined;
    this.optSet = undefined;
    this.optSelect = { };
}
}


// Zeigt eine Option auf der Seite als Checkbox an
Class.define(Classification, Object, {
// opt: Anzuzeigende Option
                    'renameOptions' : function() {
// return String mit dem HTML-Code
                                          const __PARAM = this.renameParamFun();
function getOptionCheckbox(opt) {
 
    const __CONFIG = getOptConfig(opt);
                                          if (__PARAM !== undefined) {
    const __NAME = getOptName(opt);
                                              // Klassifizierte Optionen umbenennen...
    const __VALUE = getOptValue(opt, false);
                                              renameOptions(this.optSet, this.optSelect, __PARAM, this.renameFun);
    const __ACTION = getFormActionEvent(opt, __VALUE, ! __VALUE, 'click', false);
                                          }
    const __VALUELABEL = (__VALUE ? __CONFIG.Label : getValue(__CONFIG.AltLabel, __CONFIG.Label));
                                      },
    const __FORMLABEL = formatLabel(__CONFIG.FormLabel, __CONFIG.Label);
                    'deleteOptions' : function() {
    const __TITLE = substParam(getValue(__VALUE ? __CONFIG.Title : getValue(__CONFIG.AltTitle, __CONFIG.Title), '$'), __VALUELABEL);
                                          return deleteOptions(this.optSet, this.optSelect, true, true);
                                      }
                } );


    return withTitle('<input type="checkbox" name="' + __NAME +
// ==================== Ende Abschnitt fuer Klasse Classification ====================
                    '" id="' + __NAME + '" value="' + __VALUE + '"' +
                    (__VALUE ? ' CHECKED' : "") + __ACTION + ' /><label for="' +
                    __NAME + '">' + __FORMLABEL + '</label>', __TITLE);
}


// Zeigt eine Option auf der Seite als Daten-Textfeld an
// ==================== Abschnitt fuer Klasse TeamClassification ====================
// opt: Anzuzeigende Option
// return String mit dem HTML-Code
function getOptionTextarea(opt) {
    const __CONFIG = getOptConfig(opt);
    const __NAME = getOptName(opt);
    const __VALUE = getOptValue(opt);
    const __ACTION = getFormActionEvent(opt, false, undefined, 'submit', undefined);
    const __SUBMIT = getValue(__CONFIG.Submit, "");
    //const __ONSUBMIT = (__SUBMIT.length ? ' onKeyDown="' + __SUBMIT + '"': "");
    const __ONSUBMIT = (__SUBMIT ? ' onKeyDown="' + __SUBMIT + '"': "");
    const __FORMLABEL = formatLabel(__CONFIG.FormLabel, __CONFIG.Label);
    const __TITLE = substParam(getValue(__CONFIG.Title, '$'), __FORMLABEL);
    const __ELEMENTLABEL = '<label for="' + __NAME + '">' + __FORMLABEL + '</label>';
    const __ELEMENTTEXT = '<textarea name="' + __NAME + '" id="' + __NAME + '" cols="' + __CONFIG.Cols +
                          '" rows="' + __CONFIG.Rows + '"' + __ONSUBMIT + __ACTION + '>' +
                          safeStringify(__VALUE, __CONFIG.Replace, __CONFIG.Space) + '</textarea>';


    return [ withTitle(__ELEMENTLABEL, __TITLE), __ELEMENTTEXT ];
// Klasse fuer die Klassifikation der Optionen nach Team (Erst- und Zweitteam oder Fremdteam)
}
function TeamClassification() {
    'use strict';


// Zeigt eine Option auf der Seite als Button an
     Classification.call(this);
// opt: Anzuzeigende Option
// return String mit dem HTML-Code
function getOptionButton(opt) {
    const __CONFIG = getOptConfig(opt);
    const __NAME = getOptName(opt);
    const __VALUE = getOptValue(opt, false);
    const __ACTION = getFormActionEvent(opt, __VALUE, ! __VALUE, 'click', false);
    const __BUTTONLABEL = (__VALUE ? getValue(__CONFIG.AltLabel, __CONFIG.Label) : __CONFIG.Label);
     const __FORMLABEL = formatLabel(__CONFIG.FormLabel, __BUTTONLABEL);
    const __BUTTONTITLE = substParam(getValue(__VALUE ? getValue(__CONFIG.AltTitle, __CONFIG.Title) : __CONFIG.Title, '$'), __BUTTONLABEL);


     return '<label for="' + __NAME + '">' + __FORMLABEL + '</label>' +
     this.team = undefined;
          withTitle('<input type="button" name="" + ' + __NAME +
    this.teamParams = undefined;
                    '" id="' + __NAME + '" value="' + __BUTTONLABEL +
                    '"' + __ACTION + '/>', __BUTTONTITLE);
}
}


// Zeigt eine Option auf der Seite an (je nach Typ)
Class.define(TeamClassification, Classification, {
// opt: Anzuzeigende Option
                    'renameParamFun' : function() {
// return String mit dem HTML-Code
                                          const __MYTEAM = (this.team = getMyTeam(this.optSet, this.teamParams, this.team));
function getOptionElement(opt) {
 
    const __CONFIG = getOptConfig(opt);
                                          if (__MYTEAM.LdNr) {
    const __TYPE = getValue(__CONFIG.FormType, __CONFIG.Type);
                                              // Prefix fuer die Optionen mit gesonderten Behandlung...
    let element = "";
                                              return __MYTEAM.LdNr.toString() + '.' + __MYTEAM.LgNr.toString() + ':';
                                          } else {
                                              return undefined;
                                          }
                                      }
                } );
 
// ==================== Ende Abschnitt fuer Klasse TeamClassification ====================


    if (! __CONFIG.Hidden) {
// ==================== Abschnitt fuer Klasse Team ====================
        switch (__TYPE) {
        case __OPTTYPES.MC : element = getOptionSelect(opt);
                            break;
        case __OPTTYPES.SW : if (__CONFIG.FormLabel !== undefined) {
                                element = getOptionCheckbox(opt);
                            } else {
                                element = getOptionRadio(opt);
                            }
                            break;
        case __OPTTYPES.TF : element = getOptionCheckbox(opt);
                            break;
        case __OPTTYPES.SD : element = getOptionTextarea(opt);
                            break;
        case __OPTTYPES.SI : element = getOptionButton(opt);
                            break;
        default :            break;
        }


        if ((typeof element) !== 'string') {
// Klasse fuer Teamdaten
            element = '<div>' + Array.from(element).join('<br />') + '</div>';
function Team(team, land, liga) {
        }
    'use strict';
    }


     return element;
     this.Team = team;
    this.Land = land;
    this.Liga = liga;
    this.LdNr = getLandNr(land);
    this.LgNr = getLigaNr(liga);
}
}


// Gruppiert die Daten eines Objects nach einem Kriterium
Class.define(Team, Object, {
// data: Object mit Daten
                    '__TEAMITEMS' : // Items, die in Team als Teamdaten gesetzt werden...
// byFun: function(val), die das Kriterium ermittelt. Default: value
                                        'Team' : true,
// filterFun: function(key, index, arr), die das Kriterium key im Array arr an der Stelle index vergleicht. Default: Wert identisch
                                        'Liga' : true,
// sortFun: function(a, b), nach der die Kriterien sortiert werden. Default: Array.sort()
                                        'Land' : true,
// return Neues Object mit Eintraegen der Form <Kriterium> : [ <alle Keys zu diesem Kriterium> ]
                                        'LdNr' : true,
function groupData(data, byFun, filterFun, sortFun) {
                                        'LgNr' : true
    const __BYFUN = (byFun || (val => val));
                                    }
    const __FILTERFUN = (filterFun || ((key, index, arr) => (arr[index] === key)));
                } );
    const __KEYS = Object.keys(data);
 
    const __VALS = Object.values(data);
// ==================== Ende Abschnitt fuer Klasse Team ====================
    const __BYKEYS = __VALS.map(__BYFUN);
 
    const __BYKEYSET = new Set(__BYKEYS);
// ==================== Spezialisierter Abschnitt fuer Optionen ====================
    const __BYKEYARRAY = [...__BYKEYSET];
    const __SORTEDKEYS = __BYKEYARRAY.sort(sortFun);
    const __GROUPEDKEYS = __SORTEDKEYS.map(byVal => __KEYS.filter((key, index, arr) => __FILTERFUN(byVal, index, __BYKEYS)));
    const __ASSIGN = ((keyArr, valArr) => Object.assign({ }, ...keyArr.map((key, index) => ({ [key] : valArr[index] }))));


    return __ASSIGN(__SORTEDKEYS, __GROUPEDKEYS);
// Gesetzte Optionen (wird von initOptions() angelegt und von loadOptions() gefuellt):
}
const __OPTSET = { };
 
// Teamparameter fuer getrennte Speicherung der Optionen fuer Erst- und Zweitteam...
const __TEAMCLASS = new TeamClassification();


// Baut das Benutzermenu auf der Seite auf
// Optionen mit Daten, die ZAT- und Team-bezogen gemerkt werden...
// optSet: Gesetzte Optionen
__TEAMCLASS.optSelect = {
// optParams: Eventuell notwendige Parameter
                      'ligaSize'   : true
// 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar)
                  };
// 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar)
// 'formWidth': Anzahl der Elemente pro Zeile
// 'formBreak': Elementnummer des ersten Zeilenumbruchs
// return String mit dem HTML-Code
function getForm(optSet, optParams = { }) {
    const __FORM = '<form id="options" method="POST"><table><tbody><tr>';
    const __FORMEND = '</tr></tbody></table></form>';
    const __FORMWIDTH = getValue(optParams.formWidth, 3);
    const __FORMBREAK = getValue(optParams.formBreak, __FORMWIDTH);
    const __SHOWFORM = getOptValue(optSet.showForm, true) ? optParams.showForm : { 'showForm' : true };
    const __PRIOOPTS = groupData(optSet, opt => getOptConfig(opt).FormPrio);
    let form = __FORM;
    let count = 0;  // Bisher angezeigte Optionen
    let column = 0;  // Spalte der letzten Option (1-basierend)


    for (let optKeys of Object.values(__PRIOOPTS)) {
// Gibt die Teamdaten zurueck und aktualisiert sie ggfs. in der Option
        for (let optKey of optKeys) {
// optSet: Platz fuer die gesetzten Optionen
            if (checkItem(optKey, __SHOWFORM, optParams.hideForm)) {
// teamParams: Dynamisch ermittelte Teamdaten ('Team', 'Liga', 'Land', 'LdNr' und 'LgNr')
                const __ELEMENT = getOptionElement(optSet[optKey]);
// myTeam: Objekt fuer die Teamdaten
                const __TDOPT = ((~ __ELEMENT.indexOf('|')) ? "" : ' colspan="2"');
// return Die Teamdaten oder undefined bei Fehler
function getMyTeam(optSet = undefined, teamParams = undefined, myTeam = new Team()) {
    if (teamParams !== undefined) {
        addProps(myTeam, teamParams, myTeam.__TEAMITEMS);
        __LOG[2]("Ermittelt: " + safeStringify(myTeam));
        // ... und abspeichern...
        setOpt(optSet.team, myTeam, false);
    } else {
        const __TEAM = getOptValue(optSet.team); // Gespeicherte Parameter


                if (__ELEMENT) {
        if ((__TEAM !== undefined) && (__TEAM.Land !== undefined)) {
                    if (++count > __FORMBREAK) {
            addProps(myTeam, __TEAM, myTeam.__TEAMITEMS);
                        if (++column > __FORMWIDTH) {
            __LOG[2]("Gespeichert: " + safeStringify(myTeam));
                            column = 1;
        } else {
                        }
            __LOG[1]("Unbekannt: " + safeStringify(__TEAM));
                    }
                    if (column === 1) {
                        form += '</tr><tr>';
                    }
                    form += '\n<td' + __TDOPT + '>' + __ELEMENT.replace('|', '</td><td>') + '</td>';
                }
            }
         }
         }
     }
     }
    form += '\n' + __FORMEND;


     return form;
     //return ((myTeam.length > 0) ? myTeam : undefined);
    return myTeam;
}
}


// Fuegt das Script in die Seite ein
// Behandelt die Optionen und laedt das Benutzermenu
// optSet: Gesetzte Optionen
// optConfig: Konfiguration der Optionen
// optParams: Eventuell notwendige Parameter
// optSet: Platz fuer die gesetzten Optionen
// optParams: Eventuell notwendige Parameter zur Initialisierung
// 'hideMenu': Optionen werden zwar geladen und genutzt, tauchen aber nicht im Benutzermenu auf
// 'Tab': Tabelle mit dem Spielplan
// 'Zei': Startzeile des Spielplans mit dem ersten ZAT
// 'Spa': Spalte der Tabellenzelle mit der Spielart (z.B. "Liga : Heim")
// 'teamParams': Getrennte Daten-Option wird genutzt, hier: Team() mit 'LdNr'/'LgNr' des Erst- bzw. Zweitteams
// 'menuAnchor': Startpunkt fuer das Optionsmenu auf der Seite
// 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar)
// 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar)
// 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar)
// 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar)
// return String mit dem HTML-Code fuer das Script
// 'formWidth': Anzahl der Elemente pro Zeile
function getScript(optSet, optParams = { }) {
// 'formBreak': Elementnummer des ersten Zeilenumbruchs
     //const __SCRIPT = '<script type="text/javascript">function activateMenu() { console.log("TADAAA!"); }</script>';
// return Gefuelltes Objekt mit den gesetzten Optionen
     //const __SCRIPT = '<script type="text/javascript">\n\tfunction doActionNxt(key, value) { alert("SET " + key + " = " + value); }\n\tfunction doActionNxt(key, value) { alert("SET " + key + " = " + value); }\n\tfunction doActionRst(key, value) { alert("RESET"); }\n</script>';
function buildOptions(optConfig, optSet = undefined, optParams = { 'hideMenu' : false }) {
     //const __FORM = '<form method="POST"><input type="button" id="showOpts" name="showOpts" value="Optionen anzeigen" onclick="activateMenu()" /></form>';
     // Klassifikation ueber Land und Liga des Teams...
    const __SCRIPT = "";
     __TEAMCLASS.optSet = optSet;  // Classification mit optSet verknuepfen
     __TEAMCLASS.teamParams = optParams.teamParams;  // Ermittelte Parameter


     //window.eval('function activateMenu() { console.log("TADAAA!"); }');
     optSet = startOptions(optConfig, optSet, __TEAMCLASS);


     return __SCRIPT;
     // Werte aus der HTML-Seite ermitteln...
}
    const __BOXSAISONS = document.getElementsByTagName("option");
    const __SAISON = getSaisonFromComboBox(__BOXSAISONS);
    const __LIGASIZE = getLigaSizeFromSpielplan(optParams.Tab.rows, optParams.Zei, optParams.Spa, getOptValue(optSet.saison));


// Zeigt das Optionsmenu auf der Seite an (im Gegensatz zum Benutzermenu)
    // ... und abspeichern...
// anchor: Element, das als Anker fuer die Anzeige dient
    setOpt(optSet.saison, __SAISON, false);
// optSet: Gesetzte Optionen
     setOpt(optSet.ligaSize, __LIGASIZE, false);
// optParams: Eventuell notwendige Parameter
// 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar)
// 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar)
// 'formWidth': Anzahl der Elemente pro Zeile
// 'formBreak': Elementnummer des ersten Zeilenumbruchs
function buildForm(anchor, optSet, optParams = { }) {
     __LOG[3]("buildForm()");


     const __FORM = getForm(optSet, optParams);
     showOptions(optSet, optParams);
    const __SCRIPT = getScript(optSet, optParams);


     addForm(anchor, __FORM, __SCRIPT);
     return optSet;
}
}


// Informationen zu hinzugefuegten Forms
// ==================== Ende Abschnitt fuer Optionen ====================
const __FORMS = { };


// Zeigt das Optionsmenu auf der Seite an (im Gegensatz zum Benutzermenu)
// ==================== Abschnitt fuer Spielplan und ZATs ====================
// anchor: Element, das als Anker fuer die Anzeige dient
// form: HTML-Form des Optionsmenu (hinten angefuegt)
// script: Script mit Reaktionen
function addForm(anchor, form = "", script = "") {
    const __OLDFORM = __FORMS[anchor];
    const __REST = (__OLDFORM === undefined) ? anchor.innerHTML :
                  anchor.innerHTML.substring(0, anchor.innerHTML.length - __OLDFORM.Script.length - __OLDFORM.Form.length);


    __FORMS[anchor] = {
// Beschreibungstexte aller Runden
                          'Script' : script,
const __POKALRUNDEN = [ "", "1. Runde", "2. Runde", "3. Runde", "Achtelfinale", "Viertelfinale", "Halbfinale", "Finale" ];
                          'Form'   : form
const __QUALIRUNDEN = [ "", "Quali 1", "Quali 2", "Quali 3" ];
                      };
const __OSCRUNDEN  = [ "", "Viertelfinale", "Halbfinale", "Finale" ];
const __OSERUNDEN   = [ "", "Runde 1", "Runde 2", "Runde 3", "Runde 4", "Achtelfinale", "Viertelfinale", "Halbfinale", "Finale" ];
const __HINRUECK    = [ " Hin", " R\xFCck", "" ];


    anchor.innerHTML = __REST + script + form;
// ==================== Abschnitt fuer Klasse RundenLink ====================
}


// ==================== Abschnitt fuer Klasse Classification ====================
function RundenLink(saison, team) {
 
// Basisklasse fuer eine Klassifikation der Optionen nach Kriterium (z.B. Erst- und Zweitteam oder Fremdteam)
function Classification() {
     'use strict';
     'use strict';


     this.renameFun = prefixName;
     this.uri = new URI("http://os.ongapo.com/?erganzeigen=1&stataktion=Statistik+ausgeben");
     //this.renameParamFun = undefined;
     this.runde = 0;
     this.optSet = undefined;
     this.prop = "";
     this.optSelect = { };
     this.label = "";
}


Class.define(Classification, Object, {
    if (saison) {
                    'renameOptions' : function() {
        this.setSaison(saison);
                                          const __PARAM = this.renameParamFun();
    }
 
    if (team) {
                                          if (__PARAM !== undefined) {
        this.setTeam(team);
                                              // Klassifizierte Optionen umbenennen...
     }
                                              return renameOptions(this.optSet, this.optSelect, __PARAM, this.renameFun);
                                          } else {
                                              return Promise.resolve();
                                          }
                                      },
                    'deleteOptions' : function(ignList) {
                                          const __OPTSELECT = addProps([], this.optSelect, null, ignList);
 
                                          return deleteOptions(this.optSet, __OPTSELECT, true, true);
                                      }
                });
 
// ==================== Ende Abschnitt fuer Klasse Classification ====================
 
// ==================== Abschnitt fuer Klasse TeamClassification ====================
 
// Klasse fuer die Klassifikation der Optionen nach Team (Erst- und Zweitteam oder Fremdteam)
function TeamClassification() {
    'use strict';
 
     Classification.call(this);
 
    this.team = undefined;
    this.teamParams = undefined;
}
}


Class.define(TeamClassification, Classification, {
Class.define(RundenLink, Object, {
                    'renameParamFun' : function() {
        'setSaison'   : function(saison) {
                                          const __MYTEAM = (this.team = getMyTeam(this.optSet, this.teamParams, this.team));
                            this.uri.setQueryPar('saauswahl', saison);
                        },
        'setTeam'      : function(team) {
                            this.uri.setQueryPar('landauswahl', team.LdNr);
                            this.uri.setQueryPar('ligaauswahl', team.LgNr);
                        },
        'setPage'      : function(page, label) {
                            this.uri.home();
                            this.uri.down(page + ".php");
                            this.setLabel(label);
                        },
        'setRunde'    : function(prop, runde) {
                            this.prop = prop;
                            this.runde = runde;
                        },
        'setLabel'    : function(label) {
                            this.label = (label || "");
                        },
        'setAnzeigen'  : function(show = true) {
                            this.uri.setQueryPar('erganzeigen', (show ? 1 : 0));
                        },
        'getLabel'    : function() {
                            return (this.label || "Link");
                        },
        'getHTML'      : function(target = undefined) {
                            if ((this.runde <= 0) || (! this.uri.getLeaf())) {
                                return this.label;
                            } else {
                                if (this.prop) {
                                    this.uri.setQueryPar(this.prop, this.runde);
                                }


                                          if (__MYTEAM.LdNr) {
                                return "<a " + URI.prototype.formatParams({
                                              // Prefix fuer die Optionen mit gesonderten Behandlung...
                                                                      'href'   : this.uri.getPath(),
                                              return __MYTEAM.LdNr.toString() + '.' + __MYTEAM.LgNr.toString() + ':';
                                                                      'target' : (target ? target : '_blank')
                                          } else {
                                                                  }, function(value) {
                                              return undefined;
                                                                        return '"' + value + '"';
                                          }
                                                                    }, ' ', '=') + '>' + this.getLabel() + "</a>";
                                      }
                            }
                });
                        }
    });


// ==================== Ende Abschnitt fuer Klasse TeamClassification ====================
// ==================== Ende Abschnitt fuer Klasse RundenLink ====================


// ==================== Abschnitt fuer Klasse Team ====================
// Liefert einen vor den ersten ZAT zurueckgesetzten Spielplanzeiger
 
// saison: Enthaelt die Nummer der laufenden Saison
// Klasse fuer Teamdaten
// ligaSize: Anzahl der Teams in dieser Liga (Gegner + 1)
 
// - ZATs pro Abrechnungsmonat
/*class*/ function Team /*{
// - Saison
    constructor*/(team, land, liga, teamId) {
// - ZAT
         'use strict';
// - GameType
 
// - Heim/Auswaerts
        this.Team = team;
// - Gegner
        this.Land = land;
// - Tore
         this.Liga = liga;
// - Gegentore
         this.TmNr = (teamId || 0);
// - Ligengroesse
         this.LdNr = getLandNr(land);
// - Ligaspieltag
         this.LgNr = getLigaNr(liga);
// - Pokalrunde
    }
// - Eurorunde
//}
// - Hin/Rueck
 
// - ZAT Rueck
Class.define(Team, Object, {
// - ZAT Korr
                    '__TEAMITEMS' : {  // Items, die in Team als Teamdaten gesetzt werden...
function firstZAT(saison, ligaSize) {
                                        'Team' : true,
    return {
                                        'Liga' : true,
         'anzZATpMonth' : ((saison < 2) ? 7 : 6),    // Erste Saison 7 ZAT, danach 6 ZAT...
                                        'Land' : true,
         'saison'      : saison,
                                        'TmNr' : true,
         'ZAT'          : 0,
                                        'LdNr' : true,
         'gameType'    : "spielfrei",
                                        'LgNr' : true
         'heim'        : true,
                                    }
        'gegner'      : "",
                });
        'gFor'        : 0,
        'gAga'        : 0,
        'ligaSize'     : ligaSize,
        'ligaSpieltag' : 0,
        'pokalRunde'   : 1,
        'euroRunde'   : 0,
        'hinRueck'     : 2,    // 0: Hin, 1: Rueck, 2: unbekannt
        'ZATrueck'     : 0,
        'ZATkorr'     : 0
    };
}


// ==================== Ende Abschnitt fuer Klasse Team ====================
// Liefert den ZAT als String
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT
// longStats: Formatiert die Langversion des Textes
function getZAT(currZAT, longStats) {
    return (longStats ? currZAT.gameType + ' ' + (currZAT.heim ? "Heim" : "Ausw\xE4rts") + ' ' : "") +
          (longStats ? '[' + currZAT.ligaSpieltag + ' ' + currZAT.pokalRunde + ' ' + currZAT.euroRunde + "] " : "") +
          (longStats ? '[' + currZAT.ZATrueck + __HINRUECK[currZAT.hinRueck] +
                        ' ' + ((currZAT.ZATkorr < 0) ? "" : '+') + currZAT.ZATkorr + "] " : "") +
          (longStats ? currZAT.gegner + ((currZAT.gFor > -1) ? " (" + currZAT.gFor + " : " + currZAT.gAga + ')' : "") + ' ' : "") +
          'S' + currZAT.saison + "-Z" + ((currZAT.ZAT < 10) ? '0' : "") + currZAT.ZAT;
}


// ==================== Abschnitt fuer Klasse Verein ====================
// Liefert die ZATs der Sonderspieltage fuer 10er- (2) und 20er-Ligen (4)
 
// saison: Enthaelt die Nummer der laufenden Saison
// Klasse fuer Vereinsdaten
// return [ 10erHin, 10erRueck, 20erHin, 20erRueck ], ZAT-Nummern der Zusatzspieltage
 
function getLigaExtra(saison) {
/*class*/ function Verein /*extends Team {
     if (saison < 3) {
     constructor*/(team, land, liga, teamId, manager, flags) {
         return [ 8, 64, 32, 46 ];
         'use strict';
    } else {
 
         return [ 9, 65, 33, 57 ];
        Team.call(this, team, land, liga, teamId);
 
         this.Manager = manager;
        this.Flags = (flags || []);
     }
     }
//}
}


Class.define(Verein, Team, {
// Spult die Daten um anzZAT ZATs vor und schreibt Parameter
                    '__TEAMITEMS' : {  // Items, die in Verein als Teamdaten gesetzt werden...
// anhand des Spielplans fort. Also Spieltag, Runde, etc.
                                        'Team'    : true,
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT
                                        'Liga'    : true,
// anzZAT: Anzahl der ZAT, um die vorgespult wird
                                        'Land'    : true,
function incZAT(currZAT, anzZAT = 1) {
                                        'TmNr'    : true,
    const __LIGAEXTRA = getLigaExtra(currZAT.saison);
                                        'LdNr'    : true,
    const __LIGAFIRST = 3 - (__LIGAEXTRA[0] % 2);
                                        'LgNr'    : true,
                                        'Manager' : true,
                                        'Flags'  : true
                                    }
                });


// ==================== Ende Abschnitt fuer Klasse Verein ====================
    for (let i = anzZAT; i > 0; i--) {
        currZAT.ZAT++;
        if ((currZAT.ZAT - __LIGAFIRST + 1) % 2 === 1) {
            currZAT.ligaSpieltag++;
        } else {
            const __POS = __LIGAEXTRA.indexOf(currZAT.ZAT);


// ==================== Spezialisierter Abschnitt fuer Optionen ====================
            if (~ __POS) {
 
                if (__POS < 2 * (currZAT.ligaSize % 9)) {
// Gesetzte Optionen (wird von initOptions() angelegt und von loadOptions() gefuellt):
                    currZAT.ligaSpieltag++;
const __OPTSET = { };
                }
 
             }
// Teamparameter fuer getrennte Speicherung der Optionen fuer Erst- und Zweitteam...
const __TEAMCLASS = new TeamClassification();
 
// Optionen mit Daten, die ZAT- und Team-bezogen gemerkt werden...
__TEAMCLASS.optSelect = {
                      'ligaSize'  : true
                  };
 
// Gibt die Teamdaten zurueck und aktualisiert sie ggfs. in der Option
// optSet: Platz fuer die gesetzten Optionen
// teamParams: Dynamisch ermittelte Teamdaten ('Team', 'Liga', 'Land', 'TmNr', 'LdNr' und 'LgNr')
// myTeam: Objekt fuer die Teamdaten
// return Die Teamdaten oder undefined bei Fehler
function getMyTeam(optSet = undefined, teamParams = undefined, myTeam = new Team()) {
    if (teamParams !== undefined) {
        addProps(myTeam, teamParams, myTeam.__TEAMITEMS);
        __LOG[2]("Ermittelt: " + safeStringify(myTeam));
        // ... und abspeichern, falls erweunscht...
        if (optSet && optSet.team) {
             setOpt(optSet.team, myTeam, false);
         }
         }
    } else {
         if ((currZAT.ZAT > 12) && ((currZAT.ZAT % 10) === 5)) {   // passt fuer alle Saisons: 12, 20, 30, 40, 48, 58, 68 / 3, 15, 27, 39, 51, 63, 69
         const __TEAM = ((optSet && optSet.team) ? getOptValue(optSet.team) : undefined);  // Gespeicherte Parameter
             currZAT.pokalRunde++;
 
        if ((__TEAM !== undefined) && (__TEAM.Land !== undefined)) {
            addProps(myTeam, __TEAM, myTeam.__TEAMITEMS);
             __LOG[2]("Gespeichert: " + safeStringify(myTeam));
        } else {
            __LOG[6]("Team nicht ermittelt: " + safeStringify(__TEAM));
         }
         }
    }
        if (((currZAT.ZAT + currZAT.ZATkorr) % 6) === 4) {
 
            if (currZAT.ZAT < 63) {
    return myTeam;
                currZAT.ZATrueck = currZAT.ZAT + 2;
}
                currZAT.euroRunde++;
 
                currZAT.hinRueck = 0;
// Behandelt die Optionen und laedt das Benutzermenu
            } else {
// optConfig: Konfiguration der Optionen
                currZAT.euroRunde = 11;    // Finale
// optSet: Platz fuer die gesetzten Optionen
                currZAT.hinRueck = 2;
// optParams: Eventuell notwendige Parameter zur Initialisierung
            }
// 'hideMenu': Optionen werden zwar geladen und genutzt, tauchen aber nicht im Benutzermenu auf
        }
// 'Tab': Tabelle mit dem Spielplan
        if (currZAT.ZAT === currZAT.ZATrueck) {
// 'Zei': Startzeile des Spielplans mit dem ersten ZAT
            currZAT.hinRueck = 1;        // 5, 7; 11, 13;  (17, 19) / 23,  25; 29, 31; 35,  37; 41,  43; 47, 49; 53,  55; 59,  61; 69
// 'Spa': Spalte der Tabellenzelle mit der Spielart (z.B. "Liga : Heim")
            if (currZAT.saison < 3) {    // 4, 6; 10, 14*; (16, 22*) / 24**, 26; 34, 36; 38*, 42; 44*, 50; 52, 54; 56*, 60; 62*, 66; 70
// 'teamParams': Getrennte Daten-Option wird genutzt, hier: Team() mit 'LdNr'/'LgNr' des Erst- bzw. Zweitteams
                if (currZAT.ZAT === 22) {
// 'menuAnchor': Startpunkt fuer das Optionsmenu auf der Seite
                    currZAT.ZATkorr = 4;
// 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar)
                } else if ((currZAT.ZAT - 6) % 20 > 6) {
// 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar)
                    currZAT.ZATkorr = 2;
// 'formWidth': Anzahl der Elemente pro Zeile
                } else {
// 'formBreak': Elementnummer des ersten Zeilenumbruchs
                    currZAT.ZATkorr = 0;
// return Promise auf gefuelltes Objekt mit den gesetzten Optionen
                }
function buildOptions(optConfig, optSet = undefined, optParams = { 'hideMenu' : false }) {
                if ((currZAT.ZAT === 22) || (currZAT.ZAT === 30)) {
    // Klassifikation ueber Land und Liga des Teams...
                    currZAT.euroRunde--;   // Frueher: 3. Quali-Rueckspiel erst knapp vor 1. Hauptrunde
    __TEAMCLASS.optSet = optSet; // Classification mit optSet verknuepfen
                }
    __TEAMCLASS.teamParams = optParams.teamParams; // Ermittelte Parameter
            }
        }
    }
}


    return startOptions(optConfig, optSet, __TEAMCLASS).then(optSet => {
// Liefert die Beschreibung des Spiels am aktuellen ZAT
                    // Werte aus der HTML-Seite ermitteln...
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT
                    const __BOXSAISONS = document.getElementsByTagName('option');
// showLink: Angabe, ob ein Link eingefuegt werden soll
                    const __SAISON = getSelectionFromComboBox(__BOXSAISONS, 0, 'Number');
// return Beschreibung des Spiels
                    const __LIGASIZE = (optParams.Tab ? getLigaSizeFromSpielplan(optParams.Tab.rows, optParams.Zei, optParams.Spa, getOptValue(optSet.saison)) : undefined);
function getZusatz(currZAT, showLink = true) {
    const __LINK = new RundenLink(currZAT.saison, __TEAMCLASS.team);


                    // ... und abspeichern...
    if (currZAT.gameType === "Liga") {
                    setOpt(optSet.saison, __SAISON, false);
        if (currZAT.ZAT < 70) {
                    setOpt(optSet.ligaSize, __LIGASIZE, false);
            __LINK.setRunde("stauswahl", currZAT.ligaSpieltag);
            __LINK.setPage("ls", __LINK.runde + ". Spieltag");
        } else {
            __LINK.setLabel("Relegation");
        }
    } else if (currZAT.gameType === "LP") {
        __LINK.setRunde("stauswahl", currZAT.pokalRunde);
        __LINK.setPage("lp", __POKALRUNDEN[__LINK.runde]);
    } else if ((currZAT.gameType === "OSCQ") || (currZAT.gameType === "OSEQ")) {
        __LINK.setRunde("runde", currZAT.euroRunde);
        __LINK.setPage(((currZAT.gameType === "OSCQ") ? "oscq" : "oseq"), __QUALIRUNDEN[__LINK.runde] + __HINRUECK[currZAT.hinRueck]);
    } else if (currZAT.gameType === "OSC") {
        if (currZAT.euroRunde < 9) {
            const __GRUPPENPHASE = ((currZAT.euroRunde < 6) ? "HR-Grp. " : "ZR-Grp. ");


                    return showOptions(optSet, optParams);
            __LINK.setRunde("", (currZAT.euroRunde % 3) * 2 + 1 + currZAT.hinRueck);
                }, defaultCatch);
            __LINK.setPage(((currZAT.euroRunde < 6) ? "oschr" : "osczr"), __GRUPPENPHASE + "Spiel " + __LINK.runde);
        } else {
            __LINK.setPage("oscfr", __OSCRUNDEN[currZAT.euroRunde - 8] + __HINRUECK[currZAT.hinRueck]);
        }
    } else if (currZAT.gameType === "OSE") {
        __LINK.setRunde("runde", currZAT.euroRunde - 3);
        __LINK.setPage("ose", __OSERUNDEN[__LINK.runde] + __HINRUECK[currZAT.hinRueck]);
    } else {
        __LINK.setLabel();  // irgendwie besser lesbar! ("Friendly" bzw. "spielfrei"/"Frei"/"reserviert")
    }
 
    return (showLink ? __LINK.getHTML() : "");
}
}


// ==================== Ende Abschnitt fuer Optionen ====================
// ==================== Abschnitt fuer Statistiken des Spielplans ====================


// ==================== Abschnitt fuer Spielplan und ZATs ====================
// Liefert eine auf 0 zurueckgesetzte Ergebnissumme
 
// - Siege
// Beschreibungstexte aller Runden
// - Unentschieden
const __POKALRUNDEN = [ "", "1. Runde", "2. Runde", "3. Runde", "Achtelfinale", "Viertelfinale", "Halbfinale", "Finale" ];
// - Niederlagen
const __QUALIRUNDEN = [ "", "Quali 1", "Quali 2", "Quali 3" ];
// - Tore
const __OSCRUNDEN  = [ "", "Viertelfinale", "Halbfinale", "Finale" ];
// - Gegentore
const __OSERUNDEN  = [ "", "Runde 1", "Runde 2", "Runde 3", "Runde 4", "Achtelfinale", "Viertelfinale", "Halbfinale", "Finale" ];
// - Siegpunkte
const __HINRUECK   = [ " Hin", " R\xFCck", "" ];
function emptyStats() {
    return {
        'S'    : 0,
        'U'    : 0,
        'N'    : 0,
        'gFor' : 0,
        'gAga' : 0,
        'P'   : 0
    };
}


// ==================== Abschnitt fuer Klasse RundenLink ====================
// Liefert die Stats als String
// stats: Enthaelt die summierten Stats
// longStats: Formatiert die Langversion des Textes
function getStats(stats, longStats) {
    return (longStats ? '[' + stats.S + ' ' + stats.U + ' ' + stats.N + "] " : "/ ") +
          stats.gFor + ':' + stats.gAga + ' ' + ((stats.gFor < stats.gAga) ? "" : (stats.gFor > stats.gAga) ? '+' : "") +
          (stats.gFor - stats.gAga) + " (" + stats.P + ')';
}


function RundenLink(saison, team) {
// Summiert ein Ergebnis auf die Stats und liefert den neuen Text zurueck
     'use strict';
// stats: Enthaelt die summierten Stats
// longStats: Formatiert die Langversion des Textes
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT (mit dem Ergebnis)
function addResultToStats(stats, longStats, currZAT) {
     let ret = "";


     this.uri = new URI("http://os.ongapo.com/?erganzeigen=1&stataktion=Statistik+ausgeben");
     if (currZAT.gFor > -1) {
    this.runde = 0;
        let p = 0;
    this.prop = "";
    this.label = "";


    if (saison) {
        if (currZAT.gFor > currZAT.gAga) {
        this.setSaison(saison);
            stats.S++;
    }
            p = 3;
    if (team) {
        } else if (currZAT.gFor === currZAT.gAga) {
         this.setTeam(team);
            stats.U++;
            p = 1;
         } else {
            stats.N++;
        }
        stats.P += p;
        stats.gFor += currZAT.gFor;
        stats.gAga += currZAT.gAga;
 
        ret = getStats(stats, longStats);
     }
     }
    return ret;
}
}


Class.define(RundenLink, Object, {
// ==================== Abschnitt fuer interne IDs auf den Seiten ====================
         'setSaison'   : function(saison) {
 
                            this.uri.setQueryPar('saauswahl', saison);
const __GAMETYPES = {   // "Blind FSS gesucht!"
                        },
         'unbekannt' : -1,
         'setTeam'      : function(team) {
        "reserviert" :  0,
                            this.uri.setQueryPar('landauswahl', team.LdNr);
        "Frei"      :  0,
                            this.uri.setQueryPar('ligaauswahl', team.LgNr);
         "spielfrei"  : 0,
                            this.uri.setQueryPar('hl',         team.TmNr);                        },
        "Friendly"  :  1,
         'setPage'      : function(page, label) {
        "Liga"      :  2,
                            this.uri.home();
        "LP"        :  3,
                            this.uri.down(page + ".php");
        "OSEQ"      :  4,
                            this.setLabel(label);
         "OSE"        : 5,
                        },
        "OSCQ"      :  6,
         'setRunde'     : function(prop, runde) {
        "OSC"       :  7
                            this.prop = prop;
    };
                            this.runde = runde;
 
                        },
const __LIGANRN = {
         'setLabel'     : function(label) {
         'unbekannt' : 0,
                            this.label = (label || "");
        '1. Liga'    :  1,
                        },
        '2. Liga A'  :  2,
         'setAnzeigen'  : function(show = true) {
         '2. Liga B' : 3,
                            this.uri.setQueryPar('erganzeigen', (show ? 1 : 0));
         '3. Liga A'  : 4,
                        },
        '3. Liga B' : 5,
         'getLabel'     : function() {
         '3. Liga C' : 6,
                            return (this.label || "Link");
         '3. Liga D' : 7
                        },
    };
         'getHTML'     : function(target = undefined) {
                            if ((this.runde <= 0) || (! this.uri.getLeaf())) {
                                return this.label;
                            } else {
                                if (this.prop) {
                                    this.uri.setQueryPar(this.prop, this.runde);
                                }


                                return "<a " + URI.prototype.formatParams({
const __LANDNRN = {
                                                                      'href'  : this.uri.getPath(),
        'unbekannt'             :   0,
                                                                      'target' : (target ? target : '_blank')
        'Albanien'              : 45,
                                                                  }, function(value) {
        'Andorra'               : 95,
                                                                        return '"' + value + '"';
        'Armenien'              : 83,
                                                                    }, ' ', '=') + '>' + this.getLabel() + "</a>";
        'Aserbaidschan'         : 104,
                            }
        'Belgien'                :  12,
                        }
        'Bosnien-Herzegowina'   :  66,
    });
        'Bulgarien'             :  42,
 
        'D\xE4nemark'            :  8,
// ==================== Ende Abschnitt fuer Klasse RundenLink ====================
        'Deutschland'           :  6,
 
        'England'               :  1,
// Liefert einen vor den ersten ZAT zurueckgesetzten Spielplanzeiger
        'Estland'               :  57,
// saison: Enthaelt die Nummer der laufenden Saison
        'Far\xF6er'              :  68,
// ligaSize: Anzahl der Teams in dieser Liga (Gegner + 1)
        'Finnland'              :  40,
// - ZATs pro Abrechnungsmonat
        'Frankreich'            :  32,
// - Saison
        'Georgien'              :  49,
// - ZAT
        'Griechenland'          :  30,
// - GameType
        'Irland'                :  5,
// - Heim/Auswaerts
        'Island'                :  29,
// - Gegner
        'Israel'                : 23,
// - Tore
        'Italien'                : 10,
// - Gegentore
        'Kasachstan'            : 105,
// - Ligengroesse
        'Kroatien'              :  24,
// - Ligaspieltag
        'Lettland'              :  97,
// - Pokalrunde
        'Liechtenstein'          :  92,
// - Eurorunde
        'Litauen'                :  72,
// - Hin/Rueck
        'Luxemburg'              :  93,
// - ZAT Rueck
        'Malta'                  :  69,
// - ZAT Korr
        'Mazedonien'            :  86,
function firstZAT(saison, ligaSize) {
        'Moldawien'              :  87,
    return {
        'Niederlande'            :  11,
         'anzZATpMonth' : ((saison < 2) ? 7 : 6),   // Erste Saison 7 ZAT, danach 6 ZAT...
         'Nordirland'             :   4,
         'saison'       : saison,
         'Norwegen'               :   9,
         'ZAT'          : 0,
         '\xD6sterreich'          : 14,
         'gameType'     : 'spielfrei',
         'Polen'                 : 25,
         'heim'        : true,
        'Portugal'               :  17,
         'gegner'       : "",
         'Rum\xE4nien'           :  28,
         'gFor'        : 0,
         'Russland'              : 19,
         'gAga'        : 0,
         'San Marino'             : 98,
         'ligaSize'     : ligaSize,
         'Schottland'             :  2,
         'ligaSpieltag' : 0,
         'Schweden'              : 27,
         'pokalRunde'   : 1,
         'Schweiz'               :  37,
         'euroRunde'   : 0,
         'Serbien und Montenegro' : 41,
         'hinRueck'     : 2,   // 0: Hin, 1: Rueck, 2: unbekannt
         'Slowakei'               : 70,
         'ZATrueck'     : 0,
         'Slowenien'             : 21,
         'ZATkorr'     : 0
         'Spanien'               : 13,
         'Tschechien'             : 18,
         'T\xFCrkei'             : 39,
        'Ukraine'                : 20,
        'Ungarn'                : 26,
        'Wales'                  :   3,
         'Weissrussland'         : 71,
         'Zypern'                 : 38
     };
     };
}


// Liefert den ZAT als String
// ==================== Abschnitt fuer Daten des Spielplans ====================
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT
 
// longStats: Formatiert die Langversion des Textes
// Gibt die ID fuer den Namen eines Wettbewerbs zurueck
function getZAT(currZAT, longStats) {
// gameType: Name des Wettbewerbs eines Spiels
     return (longStats ? currZAT.gameType + ' ' + (currZAT.heim ? "Heim" : "Ausw\xE4rts") + ' ' : "") +
// return OS2-ID fuer den Spieltyp (1 bis 7), 0 fuer spielfrei/Frei/reserviert, -1 fuer ungueltig
          (longStats ? '[' + currZAT.ligaSpieltag + ' ' + currZAT.pokalRunde + ' ' + currZAT.euroRunde + "] " : "") +
function getGameTypeID(gameType) {
          (longStats ? '[' + currZAT.ZATrueck + __HINRUECK[currZAT.hinRueck] +
     return getValue(__GAMETYPES[gameType], __GAMETYPES.unbekannt);
                        ' ' + ((currZAT.ZATkorr < 0) ? "" : '+') + currZAT.ZATkorr + "] " : "") +
          (longStats ? currZAT.gegner + ((currZAT.gFor > -1) ? " (" + currZAT.gFor + " : " + currZAT.gAga + ')' : "") + ' ' : "") +
          'S' + currZAT.saison + "-Z" + ((currZAT.ZAT < 10) ? '0' : "") + currZAT.ZAT;
}
}


// Liefert die ZATs der Sonderspieltage fuer 10er- (2) und 20er-Ligen (4)
// Gibt die ID des Landes mit dem uebergebenen Namen zurueck.
// saison: Enthaelt die Nummer der laufenden Saison
// land: Name des Landes
// return [ 10erHin, 10erRueck, 20erHin, 20erRueck ], ZAT-Nummern der Zusatzspieltage
// return OS2-ID des Landes, 0 fuer ungueltig
function getLigaExtra(saison) {
function getLandNr(land) {
     if (saison < 3) {
     return getValue(__LANDNRN[land], __LANDNRN.unbekannt);
        return [ 8, 64, 32, 46 ];
    } else {
        return [ 9, 65, 33, 57 ];
    }
}
}


// Spult die Daten um anzZAT ZATs vor und schreibt Parameter
// Gibt die ID der Liga mit dem uebergebenen Namen zurueck.
// anhand des Spielplans fort. Also Spieltag, Runde, etc.
// land: Name der Liga
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT
// return OS2-ID der Liga, 0 fuer ungueltig
// anzZAT: Anzahl der ZAT, um die vorgespult wird
function getLigaNr(liga) {
function incZAT(currZAT, anzZAT = 1) {
    return getValue(__LIGANRN[liga], __LIGANRN.unbekannt);
     const __LIGAEXTRA = getLigaExtra(currZAT.saison);
}
     const __LIGAFIRST = 3 - (__LIGAEXTRA[0] % 2);
 
// Ermittelt den Spielgegner aus einer Tabellenzelle und liefert den Namen zurueck
// cell: Tabellenzelle mit dem Namen des Gegners
// return Der Name des Gegners
function getGegnerFromCell(cell) {
     const __GEGNER = cell.textContent;
     const __POS = __GEGNER.indexOf(" (");


     for (let i = anzZAT; i > 0; i--) {
     if (~ __POS) {
         currZAT.ZAT++;
         return __GEGNER.substr(0, __POS);
        if ((currZAT.ZAT - __LIGAFIRST + 1) % 2 === 1) {
    } else {
            currZAT.ligaSpieltag++;
        return __GEGNER;
        } else {
    }
            const __POS = __LIGAEXTRA.indexOf(currZAT.ZAT);
}


            if (~ __POS) {
// Ermittelt das Spiel-Ergebnis aus einer Tabellenzelle, etwa "2 : 1", und liefert zwei Werte zurueck
                if (__POS < 2 * (currZAT.ligaSize % 9)) {
// cell: Tabellenzelle mit Eintrag "2 : 1"
                    currZAT.ligaSpieltag++;
// return { '2', '1' } im Beispiel
                }
function getErgebnisFromCell(cell) {
            }
    const __ERGEBNIS = cell.textContent.split(" : ", 2);
        }
 
        if ((currZAT.ZAT > 12) && ((currZAT.ZAT % 10) === 5)) {    // passt fuer alle Saisons: 12, 20, 30, 40, 48, 58, 68 / 3, 15, 27, 39, 51, 63, 69
     return __ERGEBNIS;
            currZAT.pokalRunde++;
        }
        if (((currZAT.ZAT + currZAT.ZATkorr) % 6) === 4) {
            if (currZAT.ZAT < 63) {
                currZAT.ZATrueck = currZAT.ZAT + 2;
                currZAT.euroRunde++;
                currZAT.hinRueck = 0;
            } else {
                currZAT.euroRunde = 11;    // Finale
                currZAT.hinRueck = 2;
            }
        }
        if (currZAT.ZAT === currZAT.ZATrueck) {
            currZAT.hinRueck = 1;        // 5, 7; 11, 13;  (17, 19)  / 23,  25; 29, 31; 35,  37; 41,  43; 47, 49; 53,  55; 59,  61; 69
            if (currZAT.saison < 3) {   // 4, 6; 10, 14*; (16, 22*) / 24**, 26; 34, 36; 38*, 42; 44*, 50; 52, 54; 56*, 60; 62*, 66; 70
                if (currZAT.ZAT === 22) {
                    currZAT.ZATkorr = 4;
                } else if ((currZAT.ZAT - 6) % 20 > 6) {
                    currZAT.ZATkorr = 2;
                } else {
                    currZAT.ZATkorr = 0;
                }
                if ((currZAT.ZAT === 22) || (currZAT.ZAT === 30)) {
                    currZAT.euroRunde--;   // Frueher: 3. Quali-Rueckspiel erst knapp vor 1. Hauptrunde
                }
            }
        }
     }
}
}


// Liefert die Beschreibung des Spiels am aktuellen ZAT
// Ermittelt die Spielart aus einer Tabellenzelle, etwa "Liga : Heim", und liefert zwei Werte zurueck
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT
// cell: Tabellenzelle mit Eintrag "Liga : Heim" (Spielplan) oder "Liga  Heim: " (Managerbuero)
// showLink: Angabe, ob ein Link eingefuegt werden soll
// return { "Liga", "Heim" } im Beispiel
// return Beschreibung des Spiels
function getSpielArtFromCell(cell) {
function getZusatz(currZAT, showLink = true) {
     const __TEXT = cell.textContent.replace('\xA0', "").replace(':', "").replace("  ", ' ');
     const __LINK = new RundenLink(currZAT.saison, __TEAMCLASS.team);
    const __SPIELART = __TEXT.split(' ', 2);


     if (currZAT.gameType === 'Liga') {
     return __SPIELART;
        if (currZAT.ZAT < 70) {
}
            __LINK.setRunde('stauswahl', currZAT.ligaSpieltag);
            __LINK.setPage('ls', __LINK.runde + ". Spieltag");
        } else {
            __LINK.setLabel("Relegation");
        }
    } else if (currZAT.gameType === 'LP') {
        __LINK.setRunde('stauswahl', currZAT.pokalRunde);
        __LINK.setPage('lp', __POKALRUNDEN[__LINK.runde]);
    } else if ((currZAT.gameType === 'OSCQ') || (currZAT.gameType === 'OSEQ')) {
        __LINK.setRunde('runde', currZAT.euroRunde);
        __LINK.setPage(((currZAT.gameType === 'OSCQ') ? 'oscq' : 'oseq'), __QUALIRUNDEN[__LINK.runde] + __HINRUECK[currZAT.hinRueck]);
    } else if (currZAT.gameType === 'OSC') {
        if (currZAT.euroRunde < 9) {
            const __GRUPPENPHASE = ((currZAT.euroRunde < 6) ? "HR-Grp. " : "ZR-Grp. ");


            __LINK.setRunde("", (currZAT.euroRunde % 3) * 2 + 1 + currZAT.hinRueck);
// Ermittelt den Namen des Spielgegners aus einer Tabellenzelle und setzt gegner im Spielplanzeiger
            __LINK.setPage(((currZAT.euroRunde < 6) ? 'oschr' : 'osczr'), __GRUPPENPHASE + "Spiel " + __LINK.runde);
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT
        } else {
// cell: Tabellenzelle mit dem Namen des Gegners
            __LINK.setPage('oscfr', __OSCRUNDEN[currZAT.euroRunde - 8] + __HINRUECK[currZAT.hinRueck]);
function setGegnerFromCell(currZAT, cell) {
        }
     const __GEGNER = getGegnerFromCell(cell);
    } else if (currZAT.gameType === 'OSE') {
        __LINK.setRunde('runde', currZAT.euroRunde - 3);
        __LINK.setPage('ose', __OSERUNDEN[__LINK.runde] + __HINRUECK[currZAT.hinRueck]);
     } else if (currZAT.gameType === 'Supercup') {
        __LINK.setRunde("", 1);
        __LINK.setPage('supercup', currZAT.gameType);
    } else {
        __LINK.setLabel();  // irgendwie besser lesbar! ("Friendly" bzw. "spielfrei"/"Frei"/"reserviert")
    }


     return (showLink ? __LINK.getHTML() : "");
     currZAT.gegner = __GEGNER;
}
}


// ==================== Abschnitt fuer Statistiken des Spielplans ====================
// Ermittelt das Spiel-Ergebnis aus einer Tabellenzelle und setzt tore/gtore im Spielplanzeiger
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT
// cell: Tabellenzelle mit Eintrag "2 : 1"
function setErgebnisFromCell(currZAT, cell) {
    const __ERGEBNIS = getErgebnisFromCell(cell);


// Liefert eine auf 0 zurueckgesetzte Ergebnissumme
    if (__ERGEBNIS.length === 2) {
// - Siege
         currZAT.gFor = parseInt(__ERGEBNIS[0], 10);
// - Unentschieden
         currZAT.gAga = parseInt(__ERGEBNIS[1], 10);
// - Niederlagen
    } else {
// - Tore
         currZAT.gFor = -1;
// - Gegentore
         currZAT.gAga = -1;
// - Siegpunkte
     }
function emptyStats() {
    return {
         'S'    : 0,
         'U'    : 0,
        'N'    : 0,
         'gFor' : 0,
         'gAga' : 0,
        'P'    : 0
     };
}
}


// Liefert die Stats als String
// Ermittelt die Spielart aus einer Tabellenzelle und setzt gameType/heim im Spielplanzeiger
// stats: Enthaelt die summierten Stats
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT
// longStats: Formatiert die Langversion des Textes
// cell: Tabellenzelle mit Eintrag "Liga : Heim" oder "Liga Heim"
function getStats(stats, longStats) {
function setSpielArtFromCell(currZAT, cell) {
     return (longStats ? '[' + stats.S + ' ' + stats.U + ' ' + stats.N + "] " : "/ ") +
     const __SPIELART = getSpielArtFromCell(cell);
          stats.gFor + ':' + stats.gAga + ' ' + ((stats.gFor < stats.gAga) ? "" : (stats.gFor > stats.gAga) ? '+' : "") +
 
          (stats.gFor - stats.gAga) + " (" + stats.P + ')';
    currZAT.gameType = __SPIELART[0];
    currZAT.heim    = (__SPIELART.length < 2) || (__SPIELART[1] === "Heim");
}
}


// Summiert ein Ergebnis auf die Stats und liefert den neuen Text zurueck
// Gibt die ID fuer den Namen eines Wettbewerbs zurueck
// stats: Enthaelt die summierten Stats
// cell: Tabellenzelle mit Link auf den Spielberichts-Link
// longStats: Formatiert die Langversion des Textes
// gameType: Name des Wettbewerbs eines Spiels
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT (mit dem Ergebnis)
// label: Anzuklickender Text des neuen Links
function addResultToStats(stats, longStats, currZAT) {
// return HTML-Link auf die Preview-Seite fuer diesen Spielbericht
function getBilanzLinkFromCell(cell, gameType, label) {
    const __GAMETYPEID = getGameTypeID(gameType);
     let ret = "";
     let ret = "";


     if (currZAT.gFor > -1) {
     if (cell.textContent !== "Vorschau") {  // Nur falls Link nicht bereits vorhanden
        let p = 0;
        if (__GAMETYPEID > 1) {             // nicht moeglich fuer "Friendly" bzw. "spielfrei"/"Frei"/"reserviert"
            const __SEARCHFUN = ":os_bericht(";
            let paarung = cell.innerHTML.substr(cell.innerHTML.indexOf(__SEARCHFUN) + __SEARCHFUN.length);


        if (currZAT.gFor > currZAT.gAga) {
            paarung = paarung.substr(0, paarung.indexOf(')'));
             stats.S++;
             paarung = paarung.substr(0, paarung.lastIndexOf(','));
             p = 3;
             paarung = paarung.substr(0, paarung.lastIndexOf(','));
        } else if (currZAT.gFor === currZAT.gAga) {
             ret = ' <a href="javascript:spielpreview(' + paarung + ',' + __GAMETYPEID + ')">' + label + "</a>";
             stats.U++;
            p = 1;
        } else {
            stats.N++;
         }
         }
        stats.P += p;
        stats.gFor += currZAT.gFor;
        stats.gAga += currZAT.gAga;
        ret = getStats(stats, longStats);
     }
     }


Zeile 3.668: Zeile 3.416:
}
}


// ==================== Abschnitt fuer interne IDs auf den Seiten ====================
// Addiert einen Link auf die Bilanz hinter den Spielberichts-Link
// cell: Tabellenzelle mit Link auf den Spielberichts-Link
// gameType: Name des Wettbewerbs eines Spiels
// label: Anzuklickender Text des neuen Links
function addBilanzLinkToCell(cell, gameType, label) {
    const __BILANZLINK = getBilanzLinkFromCell(cell, gameType, label);


const __GAMETYPENRN = {    // "Blind FSS gesucht!"
    if (__BILANZLINK !== "") {
         'unbekannt'  : -1,
         cell.innerHTML += __BILANZLINK;
        'reserviert' :  0,
    }
        'Frei'      :  0,
}
        'spielfrei'  :  0,
 
        'Friendly'  :  1,
// ==================== Abschnitt fuer sonstige Parameter des Spielplans ====================
        'Liga'      :  2,
        'LP'        :  3,
        'OSEQ'      :  4,
        'OSE'        :  5,
        'OSCQ'      :  6,
        'OSC'        :  7,
        'Supercup'  : 10
    };


const __GAMETYPEALIASES = {
const __TEAMSEARCHHAUPT = {  // Parameter zum Team "<b>Willkommen im Managerb&uuml;ro von TEAM</b><br>LIGA LAND<a href=..."
        'unbekannt'  : "unbekannt",
         'Zeile' : 0,
         'reserviert' : undefined,
         'Spalte' : 1,
         'Frei'       : undefined,
         'start'  : " von ",
         'spielfrei'  : "",
         'middle' : "</b><br>",
         'Friendly'   : "FSS",
         'liga'   : ". Liga",
         'Liga'       :  undefined,
         'land'   : ' ',
        'LP'        : "Pokal",
         'end'   : "<a href="
         'OSEQ'       :  undefined,
        'OSE'        :  undefined,
        'OSCQ'      : undefined,
        'OSC'       :  undefined,
         'Supercup'   : "Super"
     };
     };
const __GAMETYPES = reverseMapping(__GAMETYPENRN);


const __LIGANRN = {
const __TEAMSEARCHTEAM = { // Parameter zum Team "<b>TEAM - LIGA <a href=...>LAND</a></b>"
         'unbekannt'  : 0,
         'Zeile'  : 0,
         '1. Liga'   : 1,
         'Spalte' : 0,
         '2. Liga A'  : 2,
         'start'  : "<b>",
         '2. Liga B' : 3,
         'middle' : " - ",
         '3. Liga A'  :  4,
         'liga'  : ". Liga",
         '3. Liga B' : 5,
         'land'   : 'target="_blank">',
        '3. Liga C' :  6,
         'end'   : "</a></b>"
         '3. Liga D' : 7
     };
     };
const __LIGATYPES = reverseMapping(__LIGANRN);


const __LANDNRN = {
// Ermittelt, wie das eigene Team heisst und aus welchem Land bzw. Liga es kommt (zur Unterscheidung von Erst- und Zweitteam)
        'unbekannt'              :   0,
// cell: Tabellenzelle mit den Parametern zum Team "startTEAMmiddleLIGA...landLANDend", LIGA = "#liga[ (A|B|C|D)]"
        'Albanien'              : 45,
// teamSeach: Muster fuer die Suche, die Eintraege fuer 'start', 'middle', 'liga', 'land' und 'end' enthaelt
        'Andorra'               :  95,
// return Im Beispiel { 'Team' : "TEAM", 'Liga' : "LIGA", 'Land' : "LAND", 'LdNr' : LAND-NUMMER, 'LgNr' : LIGA-NUMMER },
        'Armenien'               :  83,
//        z.B. { 'Team' : "Choromonets Odessa", 'Liga' : "1. Liga", 'Land' : "Ukraine", 'LdNr' : 20, 'LgNr' : 1 }
        'Aserbaidschan'         : 104,
function getTeamParamsFromTable(table, teamSearch = undefined) {
        'Belgien'               :  12,
    const __TEAMSEARCH   = getValue(teamSearch, __TEAMSEARCHHAUPT);
        'Bosnien-Herzegowina'   :  66,
    const __TEAMCELLROW = getValue(__TEAMSEARCH.Zeile, 0);
        'Bulgarien'             : 42,
    const __TEAMCELLCOL = getValue(__TEAMSEARCH.Spalte, 0);
        'D\xE4nemark'           :   8,
    const __TEAMCELLSTR  = (table === undefined) ? "" : table.rows[__TEAMCELLROW].cells[__TEAMCELLCOL].innerHTML;
        'Deutschland'           :   6,
    const __SEARCHSTART = __TEAMSEARCH.start;
        'England'               :   1,
    const __SEARCHMIDDLE = __TEAMSEARCH.middle;
        'Estland'               : 57,
    const __SEARCHLIGA  = __TEAMSEARCH.liga;
        'Far\xF6er'             : 68,
    const __SEARCHLAND  = __TEAMSEARCH.land;
        'Finnland'               : 40,
    const __SEARCHEND    = __TEAMSEARCH.end;
        'Frankreich'             : 32,
    const __INDEXSTART  = __TEAMCELLSTR.indexOf(__SEARCHSTART);
        'Georgien'               : 49,
    const __INDEXEND    = __TEAMCELLSTR.indexOf(__SEARCHEND);
        'Griechenland'           : 30,
 
        'Irland'                :   5,
    let teamParams = __TEAMCELLSTR.substring(__INDEXSTART + __SEARCHSTART.length, __INDEXEND);
        'Island'                : 29,
    const __INDEXLIGA = teamParams.indexOf(__SEARCHLIGA);
        'Israel'                : 23,
    const __INDEXMIDDLE = teamParams.indexOf(__SEARCHMIDDLE);
        'Italien'                10,
 
        'Kasachstan'            : 105,
    let land = (~ __INDEXLIGA) ? teamParams.substring(__INDEXLIGA + __SEARCHLIGA.length) : undefined;
        'Kroatien'              :  24,
    const __TEAMNAME = (~ __INDEXMIDDLE) ? teamParams.substring(0, __INDEXMIDDLE) : undefined;
        'Lettland'              :  97,
    let liga = ((~ __INDEXLIGA) && (~ __INDEXMIDDLE)) ? teamParams.substring(__INDEXMIDDLE + __SEARCHMIDDLE.length) : undefined;
        'Liechtenstein'          :  92,
 
        'Litauen'                :  72,
    if (land !== undefined) {
        'Luxemburg'              :  93,
         if (land.charAt(2) === ' ') {    // Land z.B. hinter "2. Liga A " statt "1. Liga "
        'Malta'                  :  69,
             land = land.substr(2);
        'Mazedonien'            :  86,
         }
        'Moldawien'              :  87,
         if (liga !== undefined) {
        'Niederlande'            :  11,
            liga = liga.substring(0, liga.length - land.length);
        'Nordirland'            :  4,
         }
        'Norwegen'              :   9,
         const __INDEXLAND = land.indexOf(__SEARCHLAND);
        '\xD6sterreich'          :  14,
         if (~ __INDEXLAND) {
        'Polen'                  : 25,
             land = land.substr(__INDEXLAND + __SEARCHLAND.length);
        'Portugal'              : 17,
         }
        'Rum\xE4nien'            :  28,
    }
        'Russland'              :  19,
 
         'San Marino'             :  98,
     const __TEAM = new Team(__TEAMNAME, land, liga);
        'Schottland'             2,
         'Schweden'              :  27,
         'Schweiz'                :  37,
        'Serbien und Montenegro' :  41,
         'Slowakei'              :  70,
         'Slowenien'              :  21,
         'Spanien'                :  13,
        'Tschechien'             :  18,
         'T\xFCrkei'              :  39,
        'Ukraine'                :  20,
        'Ungarn'                :  26,
        'Wales'                  :  3,
        'Weissrussland'          :  71,
        'Zypern'                :  38
     };
const __LAENDER = reverseMapping(__LANDNRN);


const __TLALAND = {
     return __TEAM;
        undefined : 'unbekannt',
        'ALB'    : 'Albanien',
        'AND'    : 'Andorra',
        'ARM'    : 'Armenien',
        'AZE'    : 'Aserbaidschan',
        'BEL'    : 'Belgien',
        'BIH'    : 'Bosnien-Herzegowina',
        'BUL'    : 'Bulgarien',
        'DEN'    : 'D\xE4nemark',
        'GER'    : 'Deutschland',
        'ENG'    : 'England',
        'EST'    : 'Estland',
        'FRO'    : 'Far\xF6er',
        'FIN'    : 'Finnland',
        'FRA'    : 'Frankreich',
        'GEO'    : 'Georgien',
        'GRE'    : 'Griechenland',
        'IRL'    : 'Irland',
        'ISL'    : 'Island',
        'ISR'    : 'Israel',
        'ITA'    : 'Italien',
        'KAZ'    : 'Kasachstan',
        'CRO'    : 'Kroatien',
        'LVA'    : 'Lettland',
        'LIE'    : 'Liechtenstein',
        'LTU'    : 'Litauen',
        'LUX'    : 'Luxemburg',
        'MLT'    : 'Malta',
        'MKD'    : 'Mazedonien',
        'MDA'    : 'Moldawien',
        'NED'    : 'Niederlande',
        'NIR'    : 'Nordirland',
        'NOR'    : 'Norwegen',
        'AUT'    : '\xD6sterreich',
        'POL'    : 'Polen',
        'POR'    : 'Portugal',
        'ROM'    : 'Rum\xE4nien',
        'RUS'    : 'Russland',
        'SMR'    : 'San Marino',
        'SCO'    : 'Schottland',
        'SWE'    : 'Schweden',
        'SUI'    : 'Schweiz',
        'SCG'    : 'Serbien und Montenegro',
        'SVK'    : 'Slowakei',
        'SVN'    : 'Slowenien',
        'ESP'    : 'Spanien',
        'CZE'    : 'Tschechien',
        'TUR'    : 'T\xFCrkei',
        'UKR'    : 'Ukraine',
        'HUN'    : 'Ungarn',
        'WAL'    : 'Wales',
        'BLR'    : 'Weissrussland',
        'CYP'    : 'Zypern'
    };
const __LANDTLAS = reverseMapping(__TLALAND);
 
// ==================== Abschnitt fuer Daten des Spielplans ====================
 
// Gibt die ID fuer den Namen eines Wettbewerbs zurueck
// gameType: Name des Wettbewerbs eines Spiels
// defValue: Default-Wert
// return OS2-ID fuer den Spieltyp (1 bis 7 oder 10), 0 fuer "spielfrei"/"Frei"/"reserviert", -1 fuer ungueltig
function getGameTypeID(gameType, defValue = __GAMETYPENRN.unbekannt) {
     return getValue(__GAMETYPENRN[gameType], defValue);
}
}


// Gibt den Namen eines Wettbewerbs zurueck
// Verarbeitet die URL der Seite und ermittelt die Nummer der gewuenschten Unterseite
// id: OS2-ID des Wettbewerbs eines Spiels (1 bis 7 oder 10), 0 fuer "spielfrei"/"Frei"/"reserviert", -1 fuer ungueltig
// url: Adresse der Seite
// defValue: Default-Wert
// leafs: Liste von Filenamen mit der Default-Seitennummer (falls Query-Parameter nicht gefunden)
// return Spieltyp fuer die uebergebene OS2-ID
// item: Query-Parameter, der die Nummer der Unterseite angibt
function getGameType(id, defValue) {
// return Parameter aus der URL der Seite als Nummer
     return getValue(__GAMETYPES[id], defValue);
function getPageIdFromURL(url, leafs, item = "page") {
}
     const __URI = new URI(url);
    const __LEAF = __URI.getLeaf();
 
    for (let leaf in leafs) {
        if (__LEAF === leaf) {
            const __DEFAULT = leafs[leaf];


// Gibt den alternativen (Kurznamen) fuer den Namen eines Wettbewerbs zurueck
            return getValue(__URI.getQueryPar(item), __DEFAULT);
// gameType: Name des Wettbewerbs eines Spiels
        }
// return Normalerweise den uebergebenen Parameter, in Einzelfaellen eine Kurzversion
    }
function getGameTypeAlias(gameType) {
    return getValue(__GAMETYPEALIASES[gameType], getValue(gameType, __GAMETYPEALIASES.unbekannt));
}


// Gibt den Namen des Landes mit dem uebergebenen Kuerzel (TLA) zurueck.
     return -1;
// tla: Kuerzel (TLA) des Landes
// defValue: Default-Wert
// return Name des Landes, 'unbekannt' fuer undefined
function getLandName(tla, defValue = __TLALAND[undefined]) {
     return getValue(__TLALAND[tla], defValue);
}
}


// Gibt die ID des Landes mit dem uebergebenen Namen zurueck.
// Verarbeitet die URL der Seite und ermittelt die Nummer der gewuenschten Unterseite
// land: Name des Landes
// saisons: Alle "option"-Eintraege der Combo-Box
// defValue: Default-Wert
// return Nummer der ausgewaehlten Saison (Default: 0)
// return OS2-ID des Landes, 0 fuer ungueltig
function getSaisonFromComboBox(saisons) {
function getLandNr(land, defValue = __LANDNRN.unbekannt) {
     let saison = 0;
     return getValue(__LANDNRN[land], defValue);
}


// Gibt die ID der Liga mit dem uebergebenen Namen zurueck.
    for (let i = 0; i < saisons.length; i++) {
// land: Name der Liga
        const __SAISON = saisons[i];
// defValue: Default-Wert
// return OS2-ID der Liga, 0 fuer ungueltig
function getLigaNr(liga, defValue = __LIGANRN.unbekannt) {
    return getValue(__LIGANRN[liga], defValue);
}


// Kehrt das Mapping eines Objekts um und liefert ein neues Objekt zurueck.
        if (__SAISON.outerHTML.match(/selected/)) {
// obj: Objekt mit key => value
            saison = __SAISON.textContent;
// convFun: Konvertierfunktion fuer die Werte
         }
// return Neues Objekt mit value => key (doppelte value-Werte fallen heraus!)
function reverseMapping(obj, convFun) {
    if (! obj) {
         return obj;
     }
     }


     const __RET = { };
     return saison;
}


     for (let key in obj) {
// Ermittelt aus dem Spielplan die Ligengroesse ueber die Sonderspieltage
        const __VALUE = obj[key];
// rows: Tabellenzeilen mit dem Spielplan
// startIdx: Index der Zeile mit dem ersten ZAT
// colArtIdx: Index der Spalte der Tabellenzelle mit der Spielart (z.B. "Liga : Heim")
// saison: Enthaelt die Nummer der laufenden Saison
// return 10 bei 36 Spielen, 18 bei 34 Spielen, 20 bei 38 Spielen
function getLigaSizeFromSpielplan(rows, startIdx, colArtIdx, saison) {
    const __LIGAEXTRA = getLigaExtra(saison);
     const __TEST10ER = getSpielArtFromCell(rows[startIdx + __LIGAEXTRA[0] - 1].cells[colArtIdx]);
    const __TEST20ER = getSpielArtFromCell(rows[startIdx + __LIGAEXTRA[2] - 1].cells[colArtIdx]);


         __RET[__VALUE] = (convFun ? convFun(key) : key);
    if (__TEST20ER[0] === "Liga") {
         return 20;
    } else if (__TEST10ER[0] === "Liga") {
        return 10;
    } else {
        return 18;
     }
     }
    return __RET;
}
}


// ==================== Abschnitt fuer sonstige Parameter ====================
// ==================== Ende Abschnitt fuer Spielplan und ZATs ====================
 
// ==================== Hauptprogramm ====================
 
// Verarbeitet Ansicht "Saisonplan"
function procSpielplan() {
    const __ROWOFFSETUPPER = 1;    // Header-Zeile
    const __ROWOFFSETLOWER = 0;


// Formatiert eine Zelle um (mit einfachen Parametern)
    const __COLUMNINDEX = {
// cell: Zu formatierende Zelle
        'Art' : 1,
// bold: Inhalt fett darstellen (true = ja, false = nein)
        'Geg' : 2,
// color: Falls angegeben, die Schriftfarbe
        'Erg' : 3,
// bgColor: Falls angegeben, die Hintergrundfarbe
        'Ber' : 4,
// return Die formatierte Zelle
        'Zus' : 5,
function formatCell(cell, bold = true, color = undefined, bgColor = undefined) {
         'Kom' : 6
    if (cell) {
    };
         if (bold) {
            cell.style.fontWeight = 'bold';
        }
        if (color) {
            cell.style.color = color;
        }
        if (bgColor) {
            cell.style.backgroundColor = bgColor;
        }
    }


     return cell;
     const __TEAMPARAMS = getTeamParamsFromTable(getTable(1), __TEAMSEARCHTEAM); // Link mit Team, Liga, Land...
}


// Ermittelt die auszugewaehlenden Werte eines Selects (Combo-Box) als Array zurueck
    buildOptions(__OPTCONFIG, __OPTSET, {
// element: 'select'-Element oder dessen Name auf der HTML-Seite mit 'option'-Eintraegen der Combo-Box
                    'Tab'       : getTable(2),
// valType: Typ-Klasse der Optionswerte ('String', 'Number', ...)
                    'Zei'       : __ROWOFFSETUPPER,
// valFun: Funktion zur Ermittlung des Wertes eines 'option'-Eintrags (getSelectedOptionText, getSelectedValue, ...)
                    'Spa'       : __COLUMNINDEX.Art,
// defValue: Default-Wert, falls nichts selektiert ist
                    'teamParams' : __TEAMPARAMS,
// return Array mit den Options-Werten
                    'menuAnchor' : getTable(0, "div"),
function getSelectionArray(element, valType = 'String', valFun = getSelectedValue, defValue = undefined) {
                    'hideForm'  : {
    const __SELECT = ((typeof element) === 'string' ? getValue(document.getElementsByName(element), [])[0] : element);
                                        'team'        : true
                                    },
                    'formWidth' : 3,
                    'formBreak' : 4
                });


     return (__SELECT ? [].map.call(__SELECT.options, function(option) {
     const __ZAT = firstZAT(getOptValue(__OPTSET.saison), getOptValue(__OPTSET.ligaSize));
                                                        return this[valType](getValue(valFun(option), defValue));
                                                    }) : undefined);
}


// Ermittelt den ausgewaehlten Wert eines Selects (Combo-Box) und gibt diesen zurueck
     const __ROWS = getRows(2);
// element: 'select'-Element oder dessen Name auf der HTML-Seite mit 'option'-Eintraegen der Combo-Box
// valType: Typ-Klasse der Optionswerte ('String', 'Number', ...)
// valFun: Funktion zur Ermittlung des Wertes eines 'option'-Eintrags (getSelectedOptionText, getSelectedValue, ...)
// defValue: Default-Wert, falls nichts selektiert ist
// return Ausgewaehlter Wert
function getSelection(element, valType = 'String', valFun = getSelectedOptionText, defValue = undefined) {
     const __SELECT = ((typeof element) === 'string' ? getValue(document.getElementsByName(element), [])[0] : element);


     return this[valType](getValue(valFun(__SELECT), defValue));
     let ligaStats = emptyStats();
}
    let euroStats = emptyStats();


// Ermittelt den ausgewaehlten Wert einer Combo-Box und gibt diesen zurueck
    for (let i = __ROWOFFSETUPPER; i < __ROWS.length - __ROWOFFSETLOWER; i++) {
// comboBox: Alle 'option'-Eintraege der Combo-Box
        const __CELLS = __ROWS[i].cells;    // Aktuelle Eintraege
// defValue: Default-Wert, falls nichts selektiert ist
// valType: Typ-Klasse der Optionswerte ('String', 'Number', ...)
// return Ausgewaehlter Wert
function getSelectionFromComboBox(comboBox, defValue = undefined, valType = 'String') {
    let selection;


    for (let i = 0; i < comboBox.length; i++) {
        incZAT(__ZAT);
        const __ENTRY = comboBox[i];


         if (__ENTRY.outerHTML.match(/selected/)) {
         setGegnerFromCell(__ZAT, __CELLS[__COLUMNINDEX.Geg]);
            selection = __ENTRY.textContent;
        setSpielArtFromCell(__ZAT, __CELLS[__COLUMNINDEX.Art]);
         }
         setErgebnisFromCell(__ZAT, __CELLS[__COLUMNINDEX.Erg]);
    }


    return this[valType](getValue(selection, defValue));
        if (getOptValue(__OPTSET.shortKom)) {
}
            const __CELLKOM = __CELLS[__COLUMNINDEX.Kom];
            const __CELLART = __CELLS[__COLUMNINDEX.Art];


// Liefert den Text (textContent) einer selektierten Option
            __CELLKOM.innerHTML = __CELLKOM.innerHTML.replace("Vorbericht(e)", 'V').replace("Kommentar(e)", 'K').replace("&amp;amp;", '/').replace('&', '/');
// element: 'select'-Element auf der HTML-Seite mit 'option'-Eintraegen der Combo-Box
            __CELLART.innerHTML = __CELLART.innerHTML.replace(": Heim", "(H)").replace(": Ausw\xE4rts", "(A)").replace("Friendly", "FSS");
// return Wert der Selektion (textContent)
        }
function getSelectedOptionText(element) {
    const __SELECTEDOPTIONS = getValue(element, { }).selectedOptions;
    const __OPTION = getValue(__SELECTEDOPTIONS, { })[0];


    return (__OPTION ? __OPTION.textContent : undefined);
        __CELLS[__COLUMNINDEX.Zus].className = __CELLS[__COLUMNINDEX.Art].className;
}


// Liefert den 'value' einer selektierten Option
        if (__CELLS[__COLUMNINDEX.Zus].textContent === "") {
// element: 'select'-Element auf der HTML-Seite mit 'option'-Eintraegen der Combo-Box
            const __CELLBER = __CELLS[__COLUMNINDEX.Ber];
// return Wert der Selektion ('value')
            let stats = "";
function getSelectedValue(element) {
    return getValue(element, { }).value;
}


// ==================== Ende Abschnitt fuer sonstige Parameter ====================
            addBilanzLinkToCell(__CELLBER, __ZAT.gameType, "Bilanz");


// Ermittelt den Spielgegner aus einer Tabellenzelle und liefert den Namen zurueck
            if (getOptValue(__OPTSET.shortKom)) {
// cell: Tabellenzelle mit dem Namen des Gegners
                __CELLBER.innerHTML = __CELLBER.innerHTML.replace("Klick", "(*)").replace("Bilanz", 'V').replace("Vorschau", 'V');
// return Der Name des Gegners
            }
function getGegnerFromCell(cell) {
    const __GEGNER = cell.textContent;
    const __POS = __GEGNER.indexOf(" (");


    if (~ __POS) {
            if (__ZAT.gameType === "Liga") {
        return __GEGNER.substr(0, __POS);
                if (__ZAT.ZAT < 70) {
    } else {
                    stats = addResultToStats(ligaStats, getOptValue(__OPTSET.longStats), __ZAT);
        return __GEGNER;
                }
    }
            } else if ((__ZAT.gameType === "OSCQ") || (__ZAT.gameType === "OSEQ") || (__ZAT.gameType === "OSE")) {
}
                if (__ZAT.hinRueck !== 1) {
 
                    euroStats = emptyStats();
// Ermittelt das Spiel-Ergebnis aus einer Tabellenzelle, etwa "2 : 1", und liefert zwei Werte zurueck
                }
// cell: Tabellenzelle mit Eintrag "2 : 1"
                stats = addResultToStats(euroStats, getOptValue(__OPTSET.longStats), __ZAT);
// return { '2', '1' } im Beispiel
             } else if (__ZAT.gameType === "OSC") {
function getErgebnisFromCell(cell) {
                if ((__ZAT.hinRueck !== 1) && ((__ZAT.euroRunde >= 9) || ((__ZAT.euroRunde % 3) === 0))) {
    const __ERGEBNIS = cell.textContent.split(" : ", 2);
                    euroStats = emptyStats();
 
                }
    return __ERGEBNIS;
                stats = addResultToStats(euroStats, getOptValue(__OPTSET.longStats), __ZAT);
}
            }
 
// Ermittelt die Spielart aus einer Tabellenzelle, etwa "Liga : Heim", und liefert zwei Werte zurueck
// cell: Tabellenzelle mit Eintrag "Liga : Heim" (Spielplan) oder "Liga  Heim: " (Managerbuero)
// return { "Liga", "Heim" } im Beispiel
function getSpielArtFromCell(cell) {
    const __TEXT = cell.textContent.replace('\xA0', "").replace(':', "").replace("  ", ' ');
    const __SPIELART = __TEXT.split(' ', 2);
 
    return __SPIELART;
}
 
// Ermittelt den Namen des Spielgegners aus einer Tabellenzelle und setzt gegner im Spielplanzeiger
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT
// cell: Tabellenzelle mit dem Namen des Gegners
function setGegnerFromCell(currZAT, cell) {
    const __GEGNER = getGegnerFromCell(cell);
 
    currZAT.gegner = __GEGNER;
}
 
// Ermittelt das Spiel-Ergebnis aus einer Tabellenzelle und setzt tore/gtore im Spielplanzeiger
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT
// cell: Tabellenzelle mit Eintrag "2 : 1"
// return Modifizierter Spielplanzeiger
function setErgebnisFromCell(currZAT, cell) {
    const __ERGEBNIS = getErgebnisFromCell(cell);
 
    if (__ERGEBNIS.length === 2) {
        currZAT.gFor = parseInt(__ERGEBNIS[0], 10);
        currZAT.gAga = parseInt(__ERGEBNIS[1], 10);
    } else {
        currZAT.gFor = -1;
        currZAT.gAga = -1;
    }
 
    return currZAT;
}
 
// Ermittelt die Spielart aus einer Tabellenzelle und setzt gameType/heim im Spielplanzeiger
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT
// cell: Tabellenzelle mit Eintrag "Liga : Heim" oder "Liga Heim"
function setSpielArtFromCell(currZAT, cell) {
    const __SPIELART = getSpielArtFromCell(cell);
 
    currZAT.gameType = __SPIELART[0];
    currZAT.heim    = (__SPIELART.length < 2) || (__SPIELART[1] === 'Heim');
}
 
// Gibt die ID fuer den Namen eines Wettbewerbs zurueck
// cell: Tabellenzelle mit Link auf den Spielberichts-Link
// gameType: Name des Wettbewerbs eines Spiels
// label: Anzuklickender Text des neuen Links
// return HTML-Link auf die Preview-Seite fuer diesen Spielbericht
function getBilanzLinkFromCell(cell, gameType, label) {
    const __GAMETYPEID = getGameTypeID(gameType);
    let ret = "";
 
    if (cell.textContent !== 'Vorschau') {  // Nur falls Link nicht bereits vorhanden
        if (__GAMETYPEID > 1) {             // nicht moeglich fuer "Friendly" bzw. "spielfrei"/"Frei"/"reserviert"
            const __SEARCHFUN = ":os_bericht(";
            let paarung = cell.innerHTML.substr(cell.innerHTML.indexOf(__SEARCHFUN) + __SEARCHFUN.length);
 
            paarung = paarung.substr(0, paarung.indexOf(')'));
             paarung = paarung.substr(0, paarung.lastIndexOf(','));
            paarung = paarung.substr(0, paarung.lastIndexOf(','));
            ret = ' <a href="javascript:spielpreview(' + paarung + ',' + __GAMETYPEID + ')">' + label + "</a>";
        }
    }
 
    return ret;
}
 
// Addiert einen Link auf die Bilanz hinter den Spielberichts-Link
// cell: Tabellenzelle mit Link auf den Spielberichts-Link
// gameType: Name des Wettbewerbs eines Spiels
// label: Anzuklickender Text des neuen Links
function addBilanzLinkToCell(cell, gameType, label) {
    const __BILANZLINK = getBilanzLinkFromCell(cell, gameType, label);
 
    if (__BILANZLINK !== "") {
        cell.innerHTML += __BILANZLINK;
    }
}
 
// ==================== Abschnitt fuer sonstige Parameter des Spielplans ====================
 
const __TEAMSEARCHHAUPT = {  // Parameter zum Team "<b>Willkommen im Managerb&uuml;ro von TEAM</b><br>LIGA LAND<a href=..."
        'Tabelle'  : 1,
        'Zeile'    : 0,
        'Spalte'    : 1,
        'start'    : " von ",
        'middle'    : "</b><br>",
        'liga'      : ". Liga",
        'land'      : ' ',
        'end'      : "<a href="
    };
 
const __TEAMSEARCHTEAM = {  // Parameter zum Team "<b>TEAM - LIGA <a href=...>LAND</a></b>"
        'Tabelle'  : 1,
        'Zeile'    : 0,
        'Spalte'    : 0,
        'start'    : "<b>",
        'middle'    : " - ",
        'liga'      : ". Liga",
        'land'      : 'target="_blank">',
        'end'      : "</a></b>"
    };
 
const __TEAMIDSEARCHHAUPT = {  // Parameter zur Team-ID "<b>Deine Spiele in</b>...<a href="livegame/index.php?spiele=TEAMID,0">LIVEGAME</a>"
        'Tabelle'  : 0,
        'Zeile'    : 6,
        'Spalte'    : 0,
        'start'    : '<a href="livegame/index.php?spiele=',
        'end'      : ',0">LIVEGAME</a>'
    };
 
const __TEAMIDSEARCHTEAM = {  // Parameter zur Team-ID "<b>Deine Spiele in</b>...<a href="livegame/index.php?spiele=TEAMID,0">LIVEGAME</a>"
        'Tabelle'  : 0,
        'Zeile'    : 1,
        'Spalte'    : 1,
        'start'    : '<a hspace="20" href="javascript:tabellenplatz(',
        'end'      : ')">Tabellenpl\xE4tze</a>'
    };
 
// Ermittelt, wie das eigene Team heisst und aus welchem Land bzw. Liga es kommt (zur Unterscheidung von Erst- und Zweitteam)
// teamSearch: Muster fuer die Suche nach Team, die Eintraege fuer 'start', 'middle', 'liga', 'land' und 'end' enthaelt, ausserdem die
//              Adresse der Tabellenzelle mit den Parametern zum Team "startTEAMmiddleLIGA...landLANDend", LIGA = "#liga[ (A|B|C|D)]"
// teamIdSearch: Muster fuer die Suche nach Team-ID, die Eintraege fuer 'start' und 'end' enthaelt, ausserdem die
//              Adresse der Tabellenzelle mit den Parametern zur Team-ID "startTEAMIDend"
// doc: Optionale Angabe des Dokuments, in dem die Tabelle gesucht wird  (Default: document)
// return Im Beispiel { 'Team' : "TEAM", 'Liga' : "LIGA", 'Land' : "LAND", 'TmNr' : TEAMID, 'LdNr' : LAND-NUMMER, 'LgNr' : LIGA-NUMMER },
//        z.B. { 'Team' : "Choromonets Odessa", 'Liga' : "1. Liga", 'Land' : "Ukraine", 'TmNr' : 930, 'LdNr' : 20, 'LgNr' : 1 }
function getTeamParamsFromTable(teamSearch, teamIdSearch, doc = document) {
    // Ermittlung von Team, Liga und Land...
    const __TEAMSEARCH  = getValue(teamSearch, __TEAMSEARCHHAUPT);
    const __TEAMTABLE    = getTable(getValue(__TEAMSEARCH.Tabelle, 1), 'table', doc);
    const __TEAMCELLROW  = getValue(__TEAMSEARCH.Zeile, 0);
    const __TEAMCELLCOL  = getValue(__TEAMSEARCH.Spalte, 0);
    const __TEAMCELLSTR  = (__TEAMTABLE === undefined) ? "" : __TEAMTABLE.rows[__TEAMCELLROW].cells[__TEAMCELLCOL].innerHTML;
    const __SEARCHSTART  = __TEAMSEARCH.start;
    const __SEARCHMIDDLE = __TEAMSEARCH.middle;
    const __SEARCHLIGA  = __TEAMSEARCH.liga;
    const __SEARCHLAND  = __TEAMSEARCH.land;
    const __SEARCHEND    = __TEAMSEARCH.end;
    const __INDEXSTART  = __TEAMCELLSTR.indexOf(__SEARCHSTART);
    const __INDEXEND    = __TEAMCELLSTR.indexOf(__SEARCHEND);
 
    let teamParams = __TEAMCELLSTR.substring(__INDEXSTART + __SEARCHSTART.length, __INDEXEND);
    const __INDEXLIGA = teamParams.indexOf(__SEARCHLIGA);
    const __INDEXMIDDLE = teamParams.indexOf(__SEARCHMIDDLE);


    let land = ((~ __INDEXLIGA) ? teamParams.substring(__INDEXLIGA + __SEARCHLIGA.length) : undefined);
            if (getOptValue(__OPTSET.showStats)) {
    const __TEAMNAME = ((~ __INDEXMIDDLE) ? teamParams.substring(0, __INDEXMIDDLE) : undefined);
                if (stats !== "") {
    let liga = (((~ __INDEXLIGA) && (~ __INDEXMIDDLE)) ? teamParams.substring(__INDEXMIDDLE + __SEARCHMIDDLE.length) : undefined);
                    stats = ' ' + stats;
 
                }
    if (land !== undefined) {
            } else {
        if (land.charAt(2) === ' ') {   // Land z.B. hinter "2. Liga A " statt "1. Liga "
                stats = "";
             land = land.substr(2);
            }
             __CELLS[__COLUMNINDEX.Zus].innerHTML = getZusatz(__ZAT, true) + stats;
         }
         }
        if (liga !== undefined) {
            liga = liga.substring(0, liga.length - land.length);
        }
        const __INDEXLAND = land.indexOf(__SEARCHLAND);
        if (~ __INDEXLAND) {
            land = land.substr(__INDEXLAND + __SEARCHLAND.length);
        }
    }


    // Ermittlung der Team-ID (indirekt ueber den Livegame- bzw. Tabellenplatz-Link)...
        if (getOptValue(__OPTSET.sepMonths) && (__ZAT.ZAT % __ZAT.anzZATpMonth === 0) && (i < __ROWS.length - __ROWOFFSETLOWER - 1)) {
    const __TEAMIDSEARCH  = getValue(teamIdSearch, __TEAMIDSEARCHHAUPT);
            // Format der Trennlinie zwischen den Monaten...
    const __TEAMIDTABLE    = getTable(getValue(__TEAMIDSEARCH.Tabelle, 0), 'table', doc);
            const __BORDERSTRING = getOptValue(__OPTSET.sepStyle) + ' ' + getOptValue(__OPTSET.sepColor) + ' ' + getOptValue(__OPTSET.sepWidth);
    const __TEAMIDCELLROW  = getValue(__TEAMIDSEARCH.Zeile, 6);
    const __TEAMIDCELLCOL  = getValue(__TEAMIDSEARCH.Spalte, 0);
    const __TEAMIDCELLSTR  = (__TEAMIDTABLE === undefined) ? "" : __TEAMIDTABLE.rows[__TEAMIDCELLROW].cells[__TEAMIDCELLCOL].innerHTML;
    const __SEARCHIDSTART  = __TEAMIDSEARCH.start;
    const __SEARCHIDEND    = __TEAMIDSEARCH.end;
    const __INDEXIDSTART  = __TEAMIDCELLSTR.indexOf(__SEARCHIDSTART);
    const __INDEXIDEND    = __TEAMIDCELLSTR.indexOf(__SEARCHIDEND);
    const __TEAMIDSTR      = __TEAMIDCELLSTR.substring(__INDEXIDSTART + __SEARCHIDSTART.length, __INDEXIDEND);
    const __TEAMID        = Number.parseInt(__TEAMIDSTR, 10);


    const __TEAM = new Team(__TEAMNAME, land, liga, __TEAMID);
/*
 
            for (let entry of __CELLS) {
    return __TEAM;
                entry.style.borderBottom = __BORDERSTRING;
}
            }
 
*/
// Verarbeitet die URL der Seite und ermittelt die Nummer der gewuenschten Unterseite
            for (let j = 0; j < __CELLS.length; j++) {
// url: Adresse der Seite
                __CELLS[j].style.borderBottom = __BORDERSTRING;
// leafs: Liste von Filenamen mit der Default-Seitennummer (falls Query-Parameter nicht gefunden)
             }
// item: Query-Parameter, der die Nummer der Unterseite angibt
// return Parameter aus der URL der Seite als Nummer
function getPageIdFromURL(url, leafs, item = 'page') {
    const __URI = new URI(url);
    const __LEAF = __URI.getLeaf();
 
    for (let leaf in leafs) {
        if (__LEAF === leaf) {
            const __DEFAULT = leafs[leaf];
 
             return getValue(__URI.getQueryPar(item), __DEFAULT);
         }
         }
     }
     }
    return -1;
}
}


// Ermittelt aus dem Spielplan die Ligengroesse ueber die Sonderspieltage
try {
// rows: Tabellenzeilen mit dem Spielplan
    // URL-Legende:
// startIdx: Index der Zeile mit dem ersten ZAT
    // s=0: Teamuebersicht
// colArtIdx: Index der Spalte der Tabellenzelle mit der Spielart (z.B. "Liga : Heim")
    // s=1: Vertragsdaten
// saison: Enthaelt die Nummer der laufenden Saison
    // s=2: Einzelwerte
// return 10 bei 36 Spielen, 18 bei 34 Spielen, 20 bei 38 Spielen
    // s=3: Statistik Saison
function getLigaSizeFromSpielplan(rows, startIdx, colArtIdx, saison) {
    // s=4: Statistik Gesamt
     const __LIGAEXTRA = getLigaExtra(saison);
    // s=5: Teaminfo
     const __TEST10ER = getSpielArtFromCell(rows[startIdx + __LIGAEXTRA[0] - 1].cells[colArtIdx]);
     // s=6: Saisonplan
     const __TEST20ER = getSpielArtFromCell(rows[startIdx + __LIGAEXTRA[2] - 1].cells[colArtIdx]);
     // s=7: Vereinshistorie
    // s=8: Transferhistorie
     // s=9: Leihhistorie


     if (__TEST20ER[0] === 'Liga') {
     // Verzweige in unterschiedliche Verarbeitungen je nach Wert von s:
        return 20;
    switch (getPageIdFromURL(window.location.href, {
    } else if (__TEST10ER[0] === 'Liga') {
                                                      'showteam.php' : 0,  // Teamansicht Hauptfenster
         return 10;
                                                      'st.php'       : 0  // Teamansicht Popupfenster
    } else {
                                                  }, 's')) {
         return 18;
         case 6  : procSpielplan(); break;
         default : break;
     }
     }
} catch (ex) {
    showAlert('[' + ex.lineNumber + "] " + __DBMOD.Name, ex.message, ex);
} finally {
    __LOG[2]("SCRIPT END");
}
}
// ==================== Ende Abschnitt fuer sonstige Parameter des Spielplans ====================
// ==================== Ende Abschnitt fuer Spielplan und ZATs ====================
// ==================== Hauptprogramm ====================
// Verarbeitet Ansicht "Saisonplan"
function procSpielplan() {
    const __ROWOFFSETUPPER = 1;    // Header-Zeile
    const __ROWOFFSETLOWER = 0;
    const __CLASSFREI = 'DMI';
    const __COLUMNINDEX = {
        'ZAT' : 0,
        'Art' : 1,
        'Geg' : 2,
        'Erg' : 3,
        'Ber' : 4,
        'Zus' : 5,
        'Kom' : 6
    };
    const __TEAMPARAMS = getTeamParamsFromTable(__TEAMSEARCHTEAM, __TEAMIDSEARCHTEAM);
    return buildOptions(__OPTCONFIG, __OPTSET, {
                            'Tab'        : getTable(2),
                            'Zei'        : __ROWOFFSETUPPER,
                            'Spa'        : __COLUMNINDEX.Art,
                            'teamParams' : __TEAMPARAMS,
                            'menuAnchor' : getTable(0, 'div'),
                            'hideForm'  : {
                                              'team'        : true
                                          },
                            'formWidth'  : 3,
                            'formBreak'  : 4
                        }).then(optSet => {
            const __ZAT = firstZAT(getOptValue(__OPTSET.saison), getOptValue(__OPTSET.ligaSize));
            const __ROWS = getRows(2);
            if (! __ROWS) {
                __LOG[0]("Kein Spielplan vorhanden!");
                return;
            }
            let ligaStats = emptyStats();
            let euroStats = emptyStats();
            for (let i = __ROWOFFSETUPPER; i < __ROWS.length - __ROWOFFSETLOWER; i++) {
                const __CELLS = __ROWS[i].cells;    // Aktuelle Eintraege
                const __ARTCLASS = __CELLS[__COLUMNINDEX.Art].className;
                incZAT(__ZAT);
                setGegnerFromCell(__ZAT, __CELLS[__COLUMNINDEX.Geg]);
                setSpielArtFromCell(__ZAT, __CELLS[__COLUMNINDEX.Art]);
                setErgebnisFromCell(__ZAT, __CELLS[__COLUMNINDEX.Erg]);
                if (getOptValue(__OPTSET.shortKom)) {
                    const __CELLKOM = __CELLS[__COLUMNINDEX.Kom];
                    const __CELLART = __CELLS[__COLUMNINDEX.Art];
                    __CELLKOM.innerHTML = __CELLKOM.innerHTML.replace("Vorbericht(e)", 'V').replace("Kommentar(e)", 'K').replace("&amp;", '/').replace('&', '/');
                    __CELLART.innerHTML = __CELLART.innerHTML.replace(": Heim", "(H)").replace(": Ausw\xE4rts", "(A)").replace(__ZAT.gameType, getGameTypeAlias(__ZAT.gameType));
                }
                __CELLS[__COLUMNINDEX.Erg].className = __ARTCLASS;
                __CELLS[__COLUMNINDEX.Zus].className = __ARTCLASS;
                if (__ZAT.gameType === 'spielfrei') {
                    __CELLS[__COLUMNINDEX.ZAT].className = __CLASSFREI;
                }
                if (__CELLS[__COLUMNINDEX.Zus].textContent === "") {
                    const __CELLBER = __CELLS[__COLUMNINDEX.Ber];
                    let stats = "";
                    addBilanzLinkToCell(__CELLBER, __ZAT.gameType, "Bilanz");
                    if (getOptValue(__OPTSET.shortKom)) {
                        __CELLBER.innerHTML = __CELLBER.innerHTML.replace("Klick", "(*)").replace("Bilanz", 'V').replace("Vorschau", 'V');
                    }
                    if (__ZAT.gameType === 'Liga') {
                        if (__ZAT.ZAT < 70) {
                            stats = addResultToStats(ligaStats, getOptValue(__OPTSET.longStats), __ZAT);
                        }
                    } else if ((__ZAT.gameType === 'OSCQ') || (__ZAT.gameType === 'OSEQ') || (__ZAT.gameType === 'OSE')) {
                        if (__ZAT.hinRueck !== 1) {
                            euroStats = emptyStats();
                        }
                        stats = addResultToStats(euroStats, getOptValue(__OPTSET.longStats), __ZAT);
                    } else if (__ZAT.gameType === 'OSC') {
                        if ((__ZAT.hinRueck !== 1) && ((__ZAT.euroRunde >= 9) || ((__ZAT.euroRunde % 3) === 0))) {
                            euroStats = emptyStats();
                        }
                        stats = addResultToStats(euroStats, getOptValue(__OPTSET.longStats), __ZAT);
                    }
                    if (getOptValue(__OPTSET.showStats)) {
                        if (stats !== "") {
                            stats = ' ' + stats;
                        }
                    } else {
                        stats = "";
                    }
                    __CELLS[__COLUMNINDEX.Zus].innerHTML = getZusatz(__ZAT, true) + stats;
                }
                if (getOptValue(__OPTSET.sepMonths) && (__ZAT.ZAT % __ZAT.anzZATpMonth === 0) && (i < __ROWS.length - __ROWOFFSETLOWER - 1)) {
                    // Format der Trennlinie zwischen den Monaten...
                    const __BORDERSTRING = getOptValue(__OPTSET.sepStyle) + ' ' + getOptValue(__OPTSET.sepColor) + ' ' + getOptValue(__OPTSET.sepWidth);
/*
                    for (let entry of __CELLS) {
                        entry.style.borderBottom = __BORDERSTRING;
                    }
*/
                    for (let j = 0; j < __CELLS.length; j++) {
                        __CELLS[j].style.borderBottom = __BORDERSTRING;
                    }
                }
            }
        });
}
(() => {
    (async () => {
        try {
            // URL-Legende:
            // s=0: Teamuebersicht
            // s=1: Vertragsdaten
            // s=2: Einzelwerte
            // s=3: Statistik Saison
            // s=4: Statistik Gesamt
            // s=5: Teaminfo
            // s=6: Saisonplan
            // s=7: Vereinshistorie
            // s=8: Transferhistorie
            // s=9: Leihhistorie
            // Verzweige in unterschiedliche Verarbeitungen je nach Wert von s:
            switch (getPageIdFromURL(window.location.href, {
                                                              'showteam.php' : 0,  // Teamansicht Hauptfenster
                                                              'st.php'      : 0  // Teamansicht Popupfenster
                                                          }, 's')) {
                case 6  : await procSpielplan().catch(defaultCatch); break;
                default : break;
            }
            return 'OK';
        } catch (ex) {
            return defaultCatch(ex);
        }
    })().then(rc => {
            __LOG[1]('SCRIPT END', __DBMOD.Name, '(' + rc + ')');
        })
})();


// *** EOF ***
// *** EOF ***
</pre>
</pre>

Bitte beachte, dass alle Beiträge zu Online-Soccer-Wiki von anderen Mitwirkenden bearbeitet, geändert oder gelöscht werden können. Reiche hier keine Texte ein, falls du nicht willst, dass diese ohne Einschränkung geändert werden können.

Du bestätigst hiermit auch, dass du diese Texte selbst geschrieben hast oder diese von einer gemeinfreien Quelle kopiert hast (weitere Einzelheiten unter Online-Soccer-Wiki:Urheberrechte). ÜBERTRAGE OHNE GENEHMIGUNG KEINE URHEBERRECHTLICH GESCHÜTZTEN INHALTE!

Abbrechen Bearbeitungshilfe (wird in einem neuen Fenster geöffnet)