//DEFER Indicates the script block contains only functions
//and no in-line script. Deferring the parsing of scripts until they are needed can improve
//performance by decreasing the time it takes to load a document.

//-- browsercheck -------------------


function IsOldMS()
// changed to function() to avoid occasional script errors
{
  var MSIEIndex = navigator.userAgent.indexOf("MSIE");
  return ((MSIEIndex >= 0) && (navigator.userAgent.substring((MSIEIndex + 5),(MSIEIndex + 6)) < 4));
}


function IsNets()
// changed to function() to avoid occasional script errors
{
  var MSIEIndex = navigator.userAgent.indexOf("MSIE");
  return ((MSIEIndex == -1) || (navigator.userAgent.indexOf("Windows") == -1));
}

function IsNS6 () {
  return (document.getElementById);
}  

//--- documents and forms -------------


function SetLayerHtml( aDocument, aLayerName, aHtmlContent)
// Ersetzt den HTML-Inhalt des Layers
{
  var txtA = findLayer( aDocument, aLayerName);
  if( null != txtA)
  {
    if (IsNS6()) {
      txtA.innerHTML = aHtmlContent;
    } 
    else if( IsNets())
    {
      txtA.document.clear();
      txtA.document.write(aHtmlContent);
      txtA.document.close();             // sonst sieht man nix im NS4.05 / ergä. 11.05.01 Gey
    }
    else
      txtA.innerHTML = aHtmlContent;
  }
}


function ShowLayerEx( aShowName, aLayerL)
// Zeigt aShowName an und verbirgt alle in aLayerL enthaltenen Layer
// - aShowName darf in aLayerL enthalten sein
// - aLayerL muß ein Array() mit Layernamen (string) oder 'null' sein
{
  // viele verstecken
  if( null != aLayerL)
  {
    var sHideName = "";
    for( var i = 0;  i < aLayerL.length;  i++)
    {
      sHideName = aLayerL[i];
      if( sHideName != aShowName)
        hide( sHideName);
    }
  }

  // und den einen anzeigen
  show( aShowName);
}


function showLayer(aName, visible)
{
  if (visible)
    show(aName);
  else
    hide(aName);
}


function show(name)
/* Funktion Schicht anzeigen */
{
  // Netscape 6.x
  if (document.getElementById) {
    aObj = document.getElementById(name);
    if ((aObj!=null) && (null!=aObj.style)) {aObj.style.visibility = "visible";}
  }
  else if (document.layers!=null)
  {
    aObj = document.layers['' + name];
    if (aObj!=null) {aObj.visibility = "show";}
  }
  else if (document.all != null)
  {
    aObj = document.all['' + name];
    if ((aObj!=null) && (aObj.style!=null)) {aObj.style.visibility = "visible";}
  }
  for (i=0; i<document.links.length; i++) {
    if ((document.links[i].style!=null) && (document.links[i].name!=null)) {
      if ((document.links[i].name=="_"+name) || (document.links[i].name==name+"_")) {
        document.links[i].style.color=document.alinkColor;}
      else {document.links[i].style.color=document.linkColor;}
    }
    else {
      if ((document.links[i].name=="_"+name) || (document.links[i].name==name+"_")) {
        document.links[i].color=document.alinkColor;}
      else {document.links[i].color=document.linkColor;}
    }
  }
}


function hide(name)
/* Funktion Schicht verbergen */
{
  // Netscape 6.x
  if (document.getElementById) {
    aObj = document.getElementById('' + name);
    if ((aObj!=null) && (null!=aObj.style)) {aObj.style.visibility = "hidden";}
  }
  else if (document.layers!=null) {
    aObj = document.layers['' + name];
    if (aObj!=null) {aObj.visibility = "hide";}
  }
  else if (document.all!=null) {
    aObj = document.all['' + name];
    if ((aObj!=null) && (aObj.style!=null)) {aObj.style.visibility = "hidden";}
  }
}

function loadForms() {
  for (i=0; i<document.forms.length; i++) {loadFormSettings(document.forms[i]);}
}

function saveForms() {
  for (i=0; i<document.forms.length; i++) {saveFormSettings(document.forms[i]);}
}

function loadFormSettings(aForm)
{
  var aValue;
  for (var i=0; i<aForm.elements.length; i++)
  {
    var elem = aForm.elements[i];
    if( (null != elem) && (null != elem.name) && ("L__LGG" != elem.name) &&
        ("hidden" != elem.type) )
    {
      aStr = getCookieValue( elem.name);
      if( null != aStr)
      {
        if( null != elem.value)            //MSIE -- easy-beesy
          elem.value = aStr;
        else                               //NETSCAPE
        {
          for (var k=0; k < elem.options.length; k++)
            elem.options[k].selected = (elem.options[k].value == aStr);
          if( 0 > elem.selectedIndex)
            elem.selectedIndex = 0;
        }
      }
    }
  }
}


function copyFormValues( sourceForm, destForm )
{
  if ((null == sourceForm) || (null == destForm))
    return;

  var elem = null;
  var j;
  for( var i=0;  i < sourceForm.elements.length;  i++)
  {
    elem = sourceForm.elements[i];
    if( (null != elem) && (null != elem.name) && ("hidden" != elem.type) )
    {
      aName = elem.name;

      //MSIE -- easy-beesy
      aVal  = elem.value;

      //NETSCAPE
      if ((null == aVal) && (null != elem.options))
        aVal = elem.options[elem.selectedIndex].value;

      if (null == aVal)
        continue;           // statt return / fixed 26.04.01 Gey

      for( j=0;  j < destForm.elements.length;  j++)
      {
        e2 = destForm.elements[j];

        if( (null != e2) && (e2.name==aName))
        {
          if( null != e2.value)   //MSIE -- easy-beesy
          {
            e2.value = elem.value;
          }
          else
          {                              //NETSCAPE
            for( var k=0;  k < elem.options.length;  k++)
              e2.options[k].selected = (elem.options[k].value == aVal);
          }
        }
      }

    }
  }
}


function SubmitForm( aForm, aMethod, aTarget)
// Toolfunktion, ersetzt direkten Aufruf von submit()
{
  aForm.method = aMethod;
  aForm.target = aTarget;
  aForm.submit();
}


function getCookieValue(Name)
{
  var search = Name + "=";
  if ((navigator.cookieEnabled == true) && (document.cookie.length > 0))
  { // if there are any cookies
    offset = document.cookie.indexOf(search);
    if (offset != -1)  // if cookie exists
    {
      offset += search.length;
      // set index of beginning of value
      end = document.cookie.indexOf(";", offset);
      // set index of end of cookie value
      if (end == -1) {end = document.cookie.length;}
      return unescape(document.cookie.substring(offset, end));
    }
  }
  return null;
}


function setCookieValue(aKey, aValue)
// Sets cookie values.
{
  if (navigator.cookieEnabled == false) return;
  var today   = new Date()
  var expires = new Date()
  expires.setTime(today.getTime() + 1000*60*60*24*14);  //14 Tage halten
  document.cookie = aKey+"="+aValue + ";expires=" + expires.toGMTString();
}


function saveFormSettings(aForm)
{
  var aStr = "";
  if ((null==aForm) || (null==aForm.elements)) {
    return false;
  }  
  for (var i=0; i<aForm.elements.length; i++) {
    if ((aForm.elements[i]!=null) && (aForm.elements[i].name!=null)
    && (aForm.elements[i].name!="L__LGG")) {
      //MSIE -- easy-beesy
      aVal = aForm.elements[i].value;
      //NETSCAPE
      if ((aVal==null) && (aForm.elements[i].options!=null)) {
        aVal = aForm.elements[i].options[aForm.elements[i].selectedIndex].value;
      }
      setCookieValue(aForm.elements[i].name, escape(aVal));
    }
  }
  return true;
}


function GetFormData( aForm)
{
  var s = "";
  var inp = null;

  for( var i = 0;  i < aForm.elements.length;  i++)
  {
    inp = aForm.elements[i];
    if( null != inp)
    {
      if( "" != s)
        s += "&";

      s += inp.name + "=" + SafeEscape(inp.value);
    }
  }

  return s;
}


function SetFormValue( aForm, aName, aValue)
// setzt einen Formularwert (NICHT FÜR LISTEN GEEIGNET)
{
  var inp = findScriptFormElement( aForm, aName);
  if( null != inp)
    inp.value = aValue;
  else
    alert("script error: form '"+aForm.name+"' element '"+aName+"' missing");
}


function GetFormValue( aForm, aName)
// liefert einen Formularwert (NICHT FÜR LISTEN GEEIGNET)
{
  var inp = findScriptFormElement( aForm, aName);
  if( null != inp)
    return inp.value;

  alert("script error: form '"+aForm.name+"' element '"+aName+"' missing");
  return "";
}


function findScriptFormElement(aForm, eName)
{
  if ((null != aForm) && (aForm.getElementById)) {
    return aForm.getElementById(eName);
  }  
  if((null == aForm) || (0 == aForm.elements.length))
    return null;

  var obj = null;

  // erster Versuch: über den Namen (ua. getestet mit NetScape 4.7)
  obj = aForm.elements[eName];
  if( "object" == typeof obj)
    if( (null != obj) && (obj.name == eName))
      return obj;

  // zweiter Versuch: alles abgrasen
  for (var i=0; i<aForm.elements.length; i++)
  {
    obj = aForm.elements[i];
    if( (null != obj) && (obj.name == eName))
      return obj;
  }

  return null;
}


function findScriptElement(aName, aDoc)
{
  if (aDoc==null) {aDoc=document;}
  if (aDoc==null) {return null;}

  var e = null;

  // was baumelt denn so am Dokument herum / ergä 07.11.00 Gey
  if( aDoc[aName])
  {
    e = aDoc[aName];
    if( null != e)   return e;
  }

  // NetScape: layers
  if( null != aDoc.layers)
  {
    // der Layer selbst
    e = aDoc.layers[aName];
    if( null != e)   return e;

    // innerhalb des Layers
    for( var i=0; i<aDoc.layers.length; i++)
    {
      e = findScriptElement( aName, aDoc.layers[i].document);
      if( null != e)   return e;
    }
  }

  // MS: document.all
  if( null != aDoc.all)
  {
    e = aDoc.all(aName);
    if( null != e)   return e;
  }

  // Netscape 6.x
  if (aDoc.getElementById) {
    e = document.getElementById(aName);
    if( null != e)   return e;
  }

  // FORMS
  if((null != aDoc.forms) && (0 < aDoc.forms.length))
  {
    for (var i=0; i<aDoc.forms.length; i++)
    {
      // das Formular selbst
      if (aDoc.forms[i] == aName)   return aDoc.forms[i];

      e = findScriptFormElement(aDoc.forms[i], aName);
      if( null != e)   return e;
    }
  }

  // war wohl nichts
  return null;
}


function jsColToPasCol(jsColor)
//converts JavaScript colorstring #RRGGBB in einen Pascal colorstring $BBGGRR
{
  if( null == jsColor)
    return "";

  if( 7 == jsColor.length)
    return "$"+jsColor.substring(5,7)+jsColor.substring(3,5)+jsColor.substring(1,3);

  return jsColor;
}


function getObj(aID, myDoc) {
  var aDoc = myDoc==null? document : myDoc;
  // Netscape 6.x
  if (aDoc.getElementById) {
    return aDoc.getElementById(aID)
  }
  // IE
  else if (document.all!=null) {
    return aDoc.all(aID);
  }
  // Netscape 4.x
  else if (aDoc.layers!=null) {
    //Image?
    for (var j=0; j<aDoc.images.length; j++) {
      if (aDoc.images[j].name==aID) {return aDoc.images[j];}
    }
    //Layer?
    if (aDoc.layers['' + aID]!=null) {
      return aDoc.layers['' + aID];
    }
    //Formularelement?
    aChild = findScriptElement(aID, myDoc);
    if (aChild != null) {return aChild;}
    //Element auf untergeordnetem Layer?
    for (var j=0; j<aDoc.layers.length; j++) {
      if (aDoc.layers[j].name==aID) {return aDoc.layers[j];}
      aChild = getObj(aID, aDoc.layers[j].document);
      if (aChild != null) {return aChild;}
    }
  }
}  
  
function _getObj(aID, myDoc) {
  var aDoc = myDoc==null? document : myDoc;
  if (aDoc.layers!=null) {
    //Image?
    for (var j=0; j<aDoc.images.length; j++) {
      if (aDoc.images[j].name==aID) {return aDoc.images[j];}
    }
    //Layer?
    if (aDoc.layers['' + aID]!=null) {
      return aDoc.layers['' + aID];
    }
    //Formularelement?
    aChild = findScriptElement(aID, myDoc);
    if (aChild != null) {return aChild;}
    //Element auf untergeordnetem Layer?
    for (var j=0; j<aDoc.layers.length; j++) {
      if (aDoc.layers[j].name==aID) {return aDoc.layers[j];}
      aChild = getObj(aID, aDoc.layers[j].document);
      if (aChild != null) {return aChild;}
    }
  }
  else if (aDoc.all != null) {return aDoc.all(aID);}
}

function getFrameChild(parWin, frameName)
// liefert Zeiger auf den untergeordneten Frame mit angegebenem Name oder NULL
{
  if ((null == parWin) || (null == parWin.frames))
    return null;

  for( var i = 0;  i<parWin.frames.length;  i++)
  {
    if( parWin.frames[i].name==frameName)
      return parWin.frames[i];

    aChild = getFrameChild(parWin.frames[i], frameName);
    if (aChild!=null)
      return aChild;
  }

  return null;
}


function findFrameFromTop(aFrameName)
// findet eine bestimmten Frame und beginnt die Suche beim obersten Frameset
// liefert Zeiger auf den gesuchten Frame oder NULL
// ACHTUNG: Scriptfehler lauert, falls innerhalb eines URL-fremden Framesets!
{
  return getFrameChild(top, aFrameName);
}


function GetTopWindow()
// Setzen Sie die Eigenschaft "this.SpaixTopMost = true;" im Script des obersten
// zu durchsuchenden Dokuments bzw. Framesets. Die Suche wird dann nicht weiter nach
// oben fortgesetzt. Dies verhindert Scriptfehler (s.o.), falls die Anwendung innerhalb
// eines Frames in einem Frameset einer anderen URL läuft und der gesuchte Frame nicht
// gefunden wurde.
//
// Rückgabewert: Zeiger auf das oberste Spaix-Window oder NULL
{
  var wnd = window;
  var frm = null;

  // aufi' gehts
  while( null != wnd)
  {
    // "Topmost"-Flag gesetzt?
    if( "boolean" == (typeof wnd.SpaixTopMost).toLowerCase())
      return wnd;

    // geht es noch höher hinaus?
    if( wnd.parent == wnd)
      return null;

    // noch eine Frame-Ebene nach oben
    wnd = wnd.parent;
  }

  // das war wohl nix
  return null;
}


function findFrame( aFrameName)
// Findet eine bestimmten Frame und beginnt die Suche im aktuellen Window
// Wir arbeiten uns dann schrittweise nach oben vor, um Probleme mit Seiten
// innerhalb fremder Framesets zu vermeiden (sonst Scriptfehler: Zugriff verweigert)
//
// Setzen Sie die Eigenschaft "this.SpaixTopMost = true;" im Script des obersten
// zu durchsuchenden Dokuments bzw. Framesets. Die Suche wird dann nicht weiter nach
// oben fortgesetzt. Dies verhindert Scriptfehler (s.o.), falls die Anwendung innerhalb
// eines Frames in einem Frameset einer anderen URL läuft und der gesuchte Frame nicht
// gefunden wurde.
//
// Rückgabewert: Zeiger auf den gesuchten Frame oder NULL
{
  var wnd = window;
  var frm = null;

  // aufi' gehts
  while( null != wnd)
  {
    // Frame in diesem Fenster enthalten?
    frm = getFrameChild( wnd, aFrameName);
    if( null != frm)
      return frm;

    // Notbremse ziehen?
    if( "boolean" == (typeof wnd.SpaixTopMost).toLowerCase())
      return null;

    // geht es noch höher hinaus?
    if( wnd.parent == wnd)
      return null;

    // noch eine Frame-Ebene nach oben
    wnd = wnd.parent;
  }

  // das war wohl nix
  return null;
}


function SetCaptionFrame( aHtmlUrl, aCaptionText)
// Toolfunktion zum setzen des Textes im Caption-Frame
// Aufruf zB. SetCaptionFrame( "<#IS__HTMLURL>", "zu setzender Text");
// -> weil <#IS__HTMLURL> hier nicht ersetzt wird
{
  var frm = findFrame("Caption");
  if( null != frm)
    frm.location.replace( aHtmlUrl+"/_spxCaption.asp?TP__TEXT="+SafeEscape(aCaptionText));
}


function setInfoFrame(aCaption, aBody, htmlUrl, aLGG, aMake)
{
  aWin    = top.frmInfo;
  if( null == aWin) {aWin    = findFrame("frmInfo");}
  if( null != aWin) {
    if( null != htmlUrl) {newFile = htmlUrl+'/_frmInfo.asp';}
    else {
      oldFile = aWin.location.href;
      ind     = oldFile.indexOf("?");
      if (ind > 0) {newFile = oldFile.substring(0, ind);}
      else {newFile = oldFile;}
    }
    urlStr  = newFile + "?caption="+escape(aCaption)+"&body="+escape(aBody)
            + "&L__LGG="+escape(aLGG);
    if ((null != aMake) && ("" != aMake))
      urlStr = urlStr + "&P__MAKE=" + escape(aMake) + "&INCR=1";
    aWin.location.replace(urlStr);
  }
  aWin    = top.frmVersion;
  if( null == aWin) {aWin    = findFrame("frmVersion");}
  if( null != aWin) {
    if( null != htmlUrl) {newFile = htmlUrl+'/_frmVersion.asp';}
    else {
      oldFile = aWin.location.href;
      ind     = oldFile.indexOf("?");
      if (ind > 0) {newFile = oldFile.substring(0, ind);}
      else {newFile = oldFile;}
    }  
    urlStr  = newFile + "?L__LGG="+escape(aLGG);
    if ((null != aMake) && ("" != aMake))
      urlStr = urlStr + "&P__MAKE=" + escape(aMake);
    aWin.location.replace(urlStr);
  }
}

function countMe(aHtmlUrl, varMake, varSection, aLgg, varId, varAction, varCaption, varInfo) {
  var sParams = "LGG=" + aLgg;
  if (""!=varMake) sParams += "&make=" + SafeEscape(varMake);
  if (""!=varSection) sParams += "&section=" + varSection;
  if (""!=varId) sParams += "&id=" + varId;
  if (""!=varAction) sParams += "&action=" + SafeEscape(varAction);
  if (""!=varCaption) sParams += "&caption=" + SafeEscape(varCaption);
  if (""!=varInfo) sParams += "&info=" + SafeEscape(varInfo);
  var frm = findFrame("frmVersion");
  if( null != frm)
    frm.location.replace( aHtmlUrl+"/_frmVersion.asp?" + sParams);
}

function findLayer( aDocument, aLayername)
{
  // Netscape 6
  if (aDocument.getElementById) {
    return aDocument.getElementById(aLayername);
  }  
  // Netscape 4
  else if( IsNets()) {
    return aDocument[aLayername];
  }  
  // IE  
  else if (aDocument.all != null)
    return aDocument.all(aLayername);
  else return null;
}


//--- Sortieren -----------------------------------


function QuickSort( aArray, aLeft, aRight)
// Sortiert das Array aArray von Index aLeft bis einschließlich aRight
// - aArray muß Elemente enthalten, die eine Eigenschaft "sortkey" haben
// - aArray darf keine undefinierten oder null-Werte enthalten
// - die Elemente werden aufsteigend nach "sortkey" sortiert
{
  // weniger als zwei Werte lassen sich so schlecht sortieren
  if( aLeft >= aRight)
    return;

  // und Action
  var iL = aLeft;
  var iR = aRight;

  var sortPivot = aArray[Math.round((aLeft+aRight)/2)].sortkey;
  var objL, objR;

  while( iL <= iR)
  {
    objL = aArray[iL];
    while( objL.sortkey < sortPivot)
      objL = aArray[++iL];

    objR = aArray[iR];
    while( objR.sortkey > sortPivot)
      objR = aArray[--iR];

    if( iL <= iR)
    {
      aArray[iL] = objR;
      aArray[iR] = objL;
      iL++;
      iR--;
    }
  }

  // Teilbereiche rekursiv
  QuickSort( aArray, aLeft, iR);
  QuickSort( aArray, iL, aRight);
}



//--- diverse Tools --------------------------------


function AddToArray( aArray, aObj)
// auch in nur einer Zeile kann man sich zweimal verschreiben :-(
{
  aArray[aArray.length] = aObj;
}


function StrToFloat( aValue)
// Liefert den String als Wert zurück, bei Fehlern 0
// Dezimalpunkt oder Komma ist egal, beides verwendbar
{
  var sVal  = String(aValue).replace(",", ".");
  var nTemp = parseFloat(sVal);
  if( isNaN(nTemp))
    nTemp = 0;
  return nTemp;
}


function NumToStr( aValue, aDec)
// Formatiert den numerischen Wert aValue mit aDec Nachkommastellen und liefert
// den mit Komma getrennten String zurück
{
  // manchmal ist aValue gar keine Zahl
  if( aValue.isNAN)
    return String(aValue);

  // Multiplikator zusammenbauen
  var iMult = 1;
  for( var iDec = 0; iDec < aDec; iDec++)
  {
    iMult *= 10;
  }

  // multiplizieren, konvertieren, String auseinanderpflücken und neu zusammensetzen
  var sV = String( Math.round(aValue * iMult));
  var sH = "";
  if( aDec > 0)
  {
    while( sV.length <= aDec)   // manchmal sind die Nummern zu klein
    {
      sV = "0" + sV;
    }
    sH = sV.substring( sV.length-aDec, sV.length);
    sV = sV.substring( 0, sV.length-aDec) + ",";
  }
  return sV + sH;
}


function runden( aWert, aNachkommastellen)
// Math.round() ist ja schön und gut, aber praktisch eher witzlos
{
  var result = aWert;
  var mult   = 1;

  // Null Nachkommastellen ist der einfache Fall
  if( 0 == aNachkommastellen)
    return Math.round( aWert);

  // Normalfall: angegebene Nachkommastellen > 0
  while( 0 < aNachkommastellen)
  {
    aNachkommastellen--;
    mult = mult / 10;
  }

  // aber auch angegebene Nachkommastellen < 0 ist technisch kein Problem
  while( 0 > aNachkommastellen)
  {
    aNachkommastellen++;
    mult = mult * 10;
  }

  // nun endlich das Ergebnis ausrechnen
  return mult * Math.round( aWert/mult );
}


function ClearEvent( aWindow)
// Löscht einen eventuell bestehenden Event und unterbindet die Weiterleitung nach oben
{
  if( null != aWindow.event)
  {
    aWindow.event.cancelBubble = true;
    aWindow.event.returnValue  = false;
  }
}


function SelectInput( aFormNumber, aInput)
// Fokussiert das angegebene Input-Element
{
  document.forms[aFormNumber].activeElement = aInput;
  aInput.select();
}


function DeleteAll( aStr, aSearchExpr)
// Löscht in aStr alle mit aSearchExpr (regulärer Ausdruck!) gefundenen Stellen
{
  var iPos  = aStr.search( aSearchExpr);
  while( (0 <= iPos))
  {
    aStr  = aStr.replace( aSearchExpr, "");
    iPos  = aStr.search( aSearchExpr);
  }
  return aStr;
}


function ReplaceAll( aStr, aSearchExpr, aReplaceStr)
// Ersetzt in aStr alle mit aSearchExpr (regulärer Ausdruck!)
// gefundenen Stellen durch aReplaceStr
// ACHTUNG: Zum Löschen besser DeleteAll() verwenden, sonst Scriptfehler möglich
{
  var iLast = -1;                // Bremse gegen unerwünschte Endlosschleifen
  var iPos  = aStr.search( aSearchExpr);

  // beim Löschen ist die Rekursionsbremse eher hinderlich:
  if( "" == aReplaceStr)
    return DeleteAll( aStr, aSearchExpr);

  // das klappt so nur, wenn aReplaceStr nicht leer ist:
  while( (0 <= iPos) && (iLast < iPos))
  {
    aStr  = aStr.replace( aSearchExpr, aReplaceStr);
    iLast = iPos;
    iPos  = aStr.search( aSearchExpr);
  }

  // iPos muß jetzt kleiner 0 sein
  if( 0 <= iPos)
    alert("internal script error: ReplaceAll()")

  return aStr;
}


function ReplaceISPageName( aUrl, aReplaceWith)
/* Ersetzt alle Vorkommen des Seitenbezeichners in der URL
   Gefunden/ersetzt werden folgende Formen:

        "IS__NEXTPAGE=<seitenname>"
        "IS__<seitenname>.x="
        "IS__<seitenname>.y="

   <seitenname> kann nur Buchstaben, Ziffern oder den Unterstrich enthalten
   Damit ist es dann eigentlich völlig Wurscht, wie die aktuelle Seite gerade heißt.
*/
{
  var s = aUrl;

  expr1 = /(\bIS__NEXTPAGE=\w+)/i;          // IS__NEXTPAGE=<seitenname>
  expr2 = /(\bIS__\w+\b\.[xX]=)/i;          // IS__<seitenname>.x=
  expr3 = /(\bIS__\w+\b\.[yY]=)/i;          // IS__<seitenname>.y=

  exprT = /___REPLACE_HERE___/;                            // temporäre Ersetzung
  sTemp = "___REPLACE_HERE___";                                // temporäre Ersetzung

  if( 0 <= s.search( expr1))
  {
    s = ReplaceAll( s, expr1, sTemp);
    s = ReplaceAll( s, exprT, "IS__NEXTPAGE="+aReplaceWith);
  }

  if( 0 <= s.search( expr2))
  {
    s = ReplaceAll( s, expr2, sTemp);
    s = ReplaceAll( s, exprT, "IS__"+aReplaceWith+".x=");
  }

  if( 0 <= s.search( expr3))
  {
    s = ReplaceAll( s, expr3, sTemp);
    s = ReplaceAll( s, exprT, "IS__"+aReplaceWith+".y=");
  }

  return s;
}


function RemoveTagFromUrlQuery( aURL, aTagToRemove)
// Entfernt alle Stellen der Form "Tag=Value" aus dem Query-Teil der URL
// Ist in der URL kein '?' vorhanden, wird die URL unverändert zurückgegeben
// Bei aTagToRemove ist Groß/Klein-Schreibung egal
{
  // Position des trennenden ? ermitteln
  var iPos  = aURL.indexOf("?");
  if( 0 > iPos)
    return aURL;

  // URL in "protocol://path?" und "query" aufteilen
  var sBase  = aURL.substr( 0, iPos+1);
  var sQuery = aURL.substr( iPos+1, aURL.length);
  var sUpper = "";

  // Groß/Klein ist bei unseren Tags egal
  aTagToRemove = aTagToRemove.toUpperCase();

  // für die Suche temporär vorn und hinten ein & ergänzen
  sQuery = "&" + sQuery + "&";

  // alles passende suchen und rauswerfen
  while( true)
  {
    // nächstes Auftreten suchen
    sUpper = sQuery.toUpperCase();        // lieber separat wegen Herrn NetScape
    iPos   = sUpper.indexOf("&"+aTagToRemove+"=");
    if( 0 > iPos)
      break;

    // sUpper und sQuery sind - bis auf groß/klein - hier noch völlig identisch
    if( sUpper.length != sQuery.length)
    {
      alert("ASSERTION failed in  RemoveTagFromUrlQuery()");
      break;
    }

    // Query in vorderen und hinteren Teil trennen
    // der Teil "&Tag=" fällt hierbei schon heraus
    sUpper = sQuery.substr( iPos + aTagToRemove.length + 2, sQuery.length);
    sQuery = sQuery.substr( 0, iPos);

    // das begrenzende & im hinteren Teil suchen, alles dahinter übernehmen
    iPos   = sUpper.indexOf("&");
    if( 0 <= iPos)
      sQuery = sQuery + sUpper.substr( iPos, sUpper.length);
  }

  // die beiden angefügten & wieder abschütteln
  sQuery = sQuery.substr( 1, sQuery.length-2);

  // URL komplett zusammenbauen und abliefern
  return sBase + sQuery;
}


function MakeValidID( aStr)
// Stellt sicher, daß aStr alle an eine ID='...' gestellten Anforderungen
// erfüllt (außer Eindeutigkeit)
{
  var result = "";
  var tmp    = "";

  // Erlaubt sind nur Buchstaben und Ziffern.
  // Kein Leerzeichen, kein Unterstrich, nix.
  expr = /[A-Za-z0-9]/;

  // Alle geprüften Buchstaben verwenden, alle anderen ersatzlos entsorgen
  for( var i = 0;  i < aStr.length;  i++)
  {
    tmp = aStr.substr( i, 1);
    if( expr.test(tmp))
      result += tmp;
  }

  // Rückgabewert setzen
  return result;
}



//--- UI tools -----------------------------------------------------------

// Listboxen

function AddListboxEntry( aListbox, aEntry)
// Lineare Suche, daher nicht besonders performant.
// Reicht aber für eine Handvoll Einträge aus.
{
  // prüfen, ob schon drin
  for( var i = 0;  i < aListbox.options.length;  i++)
    if( aEntry == aListbox.options[i].text.toUpperCase())
      return;

  // nicht drin, dann anhängen
  aListbox.options[ aListbox.options.length] = new Option(aEntry);
}


function AddListboxEntryValue( aListbox, aEntry, aValue)
// Lineare Suche, daher nicht besonders performant.
// Reicht aber für eine Handvoll Einträge aus.
{
  // prüfen, ob schon drin
  for( var i = 0;  i < aListbox.options.length;  i++)
    if( aEntry == aListbox.options[i].text.toUpperCase())
      return;

  // nicht drin, dann anhängen
  var opt = new Option(aEntry);
  aListbox.options[ aListbox.options.length] = opt;
  opt.value = aValue;
}


function GetSelectedListboxEntry( aListbox)
// Liefert den TEXT des selektierten Eintrages einer Listbox
// Querverweis: GetSelectedListboxValue()
{
  var i = aListbox.selectedIndex;
  if( (0 <= i) && (i < aListbox.options.length))
    return aListbox.options[i].text;
  else
    return "";
}


function SelectListboxEntry( aListbox, aEntry)
// Selektiert den ersten angegebenen Eintrag(TEXT), wenn er in der Listbox enthalten ist.
// Wird der Eintrag nicht gefunden, bleibt die Listbox unverändert.
// Rückgabewert: true, wenn der Eintrag gefunden und selektiert wurde
// QUERVERWEIS: SelectListboxValue()
{
  for( var i = 0;  i < aListbox.options.length;  i++)
  {
    if( aListbox.options[i].text == aEntry)
    {
      aListbox.selectedIndex = i;
      return true;
    }
  }

  return false;
}


function GetSelectedListboxValue( aListbox)
// Liefert den VALUE des selektierten Eintrages einer Listbox
// QUERVERWEIS: GetSelectedListboxEntry()
{
  var i = aListbox.selectedIndex;
  if( (0 <= i) && (i < aListbox.options.length))
    return aListbox.options[i].value;
  else
    return "";
}


function SelectListboxValue( aListbox, aEntry)
// Selektiert den ersten angegebenen VALUE, wenn er in der Listbox enthalten ist.
// Wird der Eintrag nicht gefunden, bleibt die Listbox unverändert.
// Rückgabewert: true, wenn der Eintrag gefunden und selektiert wurde
// QUERVERWEIS: SelectListboxEntry()
{
  if ((null==aListbox) || (null==aListbox.options)) {
    return false;
  }  
  for( var i = 0;  i < aListbox.options.length;  i++)
  {
    if( aListbox.options[i].value == aEntry)
    {
      aListbox.selectedIndex = i;
      return true;
    }
  }

  return false;
}


function InputSetOnChangeHandler( aInputName)
// Anklemmen der OnChange-default-Handler für das Eingabeelement,
// wird für die korrekte Funktion bei Auswahl per Tastatur benötigt
// INFO: Der default-Handler ruft einfach onclick() auf, siehe dort
{
  var inp = eval( aInputName);
  inp.onfocus  = new Function("InputSetFocus( "+aInputName+", true);");
  inp.onblur   = new Function("InputSetFocus( "+aInputName+", false);");
  inp.onchange = new Function("InputOnChange( "+aInputName+");");                        // siehe dort
}


function InputSetFocus( aInput, aSetFocus)
// Merkt sich das momentan fokussierte Element in document.focused
{
  if( aSetFocus)
    document.focused = aInput;
  else if( aInput == document.focused)
    document.focused = "";
}


function InputOnChange( aInput)
// Ist aInput fokussiert, wird dessen onclick()-Handler aufgerufen
// Ist aInput nicht fokussiert, passiert nix.
{
  if( aInput == document.focused)
    aInput.onclick();
}



//--- JavaScript extensions :-) ------------------------------------------


function SafeEscapeSpaces( aStr)
// verwandelt alle Spaces in "%20" (statt in "+")
{
  return ReplaceAll( aStr, /\ /, "%20");
}


function SafeEscape( aStr)
/* escape() reicht manchmal nicht aus:

  RFC 2396 - Uniform Resource Identifiers (URI): Generic Syntax
  (http://www.ietf.org/rfc/rfc2396.txt) sagt zum Thema URI/URL/URN:

  <ZITAT>
    This 'generic URI' syntax consists of a sequence of four main components:

      <scheme>://<authority><path>?<query>

    ... The query component is a string of information to be interpreted by
    the resource. Within a query component, the characters ";", "/", "?",
    ":", "@", "&", "=", "+", ",", and "$" are reserved."
  </ZITAT>

  Auch in RFC 1738 - Uniform Resource Locators (URL), einsehbar unter
  (http://www.ieft.org/rfc/rfc1738.txt), steht letztlich nichts anderes:

  <ZITAT>
    In most URL schemes, the sequences of characters in different parts
    of a URL are used to represent sequences of octets used in Internet
    protocols. For example, in the ftp scheme, the host name, directory
    name and file names are such sequences of octets, represented by
    parts of the URL.  Within those parts, an octet may be represented by
    the chararacter which has that octet as its code within the US-ASCII
    [20] coded character set.

    In addition, octets may be encoded by a character triplet consisting
    of the character "%" followed by the two hexadecimal digits (from
    "0123456789ABCDEF") which forming the hexadecimal value of the octet.
    (The characters "abcdef" may also be used in hexadecimal encodings.)
    ...
    safe           = "$" | "-" | "_" | "." | "+"
    ...
    escape         = "%" hex hex
  </ZITAT>

  Daraus ergibt sich also, daß die Codierung von SPACE als "+" nicht nur
  fehlerträchtig, sondern offenbar tatsächlich gegen jeden Standard ist.
  Zumindest ist weder in RFC C2396 noch in der älteren RFC 1738 irgendwo
  das Zeichen "+" als escape-Zeichen für SPACE definiert. Trotzdem akzeptiert
  es der IIS als Ersatzzeichen für SPACE ... und tappt dabei natürlich in
  die Falle, wenn es sich um ein echtes "+" handelt.

  Die Funktion escape() codiert zwar das SPACE korrekt als %20, läßt aber das
  (reservierte!) Zeichen "+" unberührt, mit obigem Ergebnis.

  Fazit: Spaces immer mit %20, "+" immer mit %2B codieren.
*/
{
  aStr = escape(aStr);

  // be sure SPACE is always escaped correctly
  aStr = SafeEscapeSpaces( aStr);

  // always escape any "+" char
  regExp = /\+/;
  while( 0 <= aStr.search(regExp))   aStr = aStr.replace( regExp, "%2B");

  return aStr;
}


function SafeEscapeURL( aUrl)
// escape() einer kompletten URL unter Beachtung der Parameter-Trenner '?,'=' und '&'
{
  // die Parameter sind durch ein '?' abgetrennt
  var iPos = aUrl.indexOf("?");
  if( 0 > iPos)
    return SafeEscapeSpaces(aUrl);

  // alles bis einschließlich des '?' einfach übernehmen, dabei alle Spaces korrekt kodieren
  s    = SafeEscapeSpaces( aUrl.substr( 0, iPos+1));
  aUrl = aUrl.slice( iPos+1);

  // die Parameter einzeln 'escapen'
  var sKey, sVal;
  var bAmp, bEqu;
  while( 0 < aUrl.length)
  {
    // nächstes Teilstück bis '&' extrahieren
    iPos = aUrl.indexOf("&");
    if( 0 <= iPos)
    {
      bAmp = true;
      sKey = aUrl.substr( 0, iPos);
      aUrl = aUrl.slice( iPos+1);
    }
    else
    {
      bAmp = false;
      sKey = aUrl;
      aUrl = "";
    }

    // Das Teilstück an der Stelle '=' aufteilen
    iPos = sKey.indexOf("=");
    if( 0 <= iPos)
    {
      bEqu = true;
      sVal = sKey.slice( iPos+1);
      sKey = sKey.substr( 0, iPos);
    }
    else
    {
      bEqu = false;
      sVal = "";
    }

    // escapen und zusammenbauen
    s += SafeEscape( sKey);
    if( bEqu)  s += "=";
    s += SafeEscape( sVal);
    if( bAmp)  s += "&";
  }

  // und das Ergebnis zurückgeben
  return s;
}


function loadImage(src)
{
  if (document.images)
  {
    var rslt = new Image();
    rslt.src = src;
    return rslt;
  }
}


//--- Debug ----------------------


function ASSERT( aExpr, aMsg)
// ich bin die Release-Version
{
  return;
}


//--- UI tools --------------------


function IcoStart()
// Beginn
{
  return '<table cellspacing="0" cellpadding="0" align=center border=0>'
       + '<tr>'
       + '<td width="100">  <\/td>';       // for Alignment
}


function IcoEntry( aHRef, aText, aPicUrl)
// ein Eintrag, Layout sollte analog zur ersten Seite (_frmbody.asp) sein
{
  return '<td width="70" height="20" align=center valign=top> <a href="'+aHRef+'">'
       + '<img class="btnImg" src="'+aPicUrl+'" border=0 alt="'+aText+'">'
       + '<\/a> '
       + '<\/td>'
       + '<td width="100">  <\/td>';       // for Alignment
}


function IcoEnd()
// Abschluß
{
  return '<\/tr>'
       + '<\/table>';
}


function PageCaption( aPicUrl, aText)
// Seitenüberschrift + Icon
{
  return '<table width="95%" align=center border=0>'
       + '  <tr height="60">'
       + '    <td width="100"> <img src="'+aPicUrl+'" alt="'+aText+'"> <\/td>'
       + '    <td align=center valign=bottom> <h1> '+aText+' <\/h1> <\/td>'
       + '    <td width="100"> <!-- Ausrichtung --> <\/td>'
       + '  <\/tr>'
       + '<\/table>';
}

function CheckNumericValue( aFormNumber, aInputName, aMsg, aGrAlsNull, aMax)
// Prüft ob Wert numerisch ist und ungleich Null ist
// - aGrAlsNull gibt an, ob der Wert > 0 sein muß
// - aMax ist optional und gibt den größten möglichen Wert an
// Ansonsten Warnmeldung und das betreffende Input-Feld wird fokussiert.
// Rückgabewert true wenn alles ok, sonst false
{
  // das betreffende Eingabefeld besorgen
  var inp = document.forms[aFormNumber].elements[aInputName];
  if( ("undefined" == typeof inp) || (null == inp))
  {
    alert("script error: element '"+aInputName+"' not found");
    return false;
  }

  // kommas in punkte verwandeln
  var otxt = inp.value;
  var txt  = otxt.replace(",", ".");
  inp.value = txt;

  // Wert gültig?
  var bError = true;
  if ((0 != txt.length) && (! isNaN(txt)))     // Wert ist numerisch?
  {
    bError = false;
    var nValue = txt.valueOf();

    if( aGrAlsNull && (0 >= nValue))    bError = true;     // größer Null?
    if( (aMax) && (nValue > aMax))      bError = true;     // Maximalwert?
  }

  // Fehler?
  if( bError)
  {
    alert( aMsg);
    SelectInput(aFormNumber,inp);
    ClearEvent(window);
  }

  // Rückgabewert setzen
  return (! bError);
}

// EOF