// Copyright © 2004 - 2012 Interact Computer Services Ltd.
// All rights reserved. Use is subject to license terms.
// For more information contact Interact at info@interact-uk.com

function alBrowser ()
{
  this.ie       = false /*@cc_on || true @*/;   
  this.ie4      = this.ie && (document.getElementById == null);   
  this.ie5      = this.ie && (document.namespaces == null) && (!this.ie4);   
  this.ie6      = this.ie && (document.implementation != null) && (document.implementation.hasFeature != null);   
  this.ie55     = this.ie && (document.namespaces != null) && (!this.ie6);   
  /*@cc_on  
  this.ie7       = @_jscript_version == '5.7';  
  @*/  
  this.ns4      = !this.ie &&  (document.layers != null) &&  (window.confirm != null) && (document.createElement == null);   
  this.opera    = (self.opera != null);   
  this.gecko    = (document.getBoxObjectFor != null);   
  this.khtml    = (navigator.vendor == "KDE");   
  this.konq     = ((navigator.vendor == 'KDE') || (document.childNodes) && (!document.all) && (!navigator.taintEnabled));   
  this.safari   = (document.childNodes) && (!document.all) && (!navigator.taintEnabled) && (!navigator.accentColorName);   
  this.safari12 = (parseInt(0).toFixed == null) && (this.safari && (window.XMLHttpRequest != null));   
  this.safari20 = (parseInt(0).toFixed != null) && this.safari && !this.safari12;   
  this.safari11 = this.safari && !this.safari12 && !this.safari20;   
}

var AL_FocusObject    = null;
var AL_LastEvent      = null;
var AL_Browser        = new alBrowser ();
var AL_EventFunctions = null;
var AL_EventDef       = null;
var AL_EventAuto      = false;
var AL_EventObj       = null;
var AL_EventBlock     = false;
var AL_DocEvents      = null;
var AL_DocAllowed     = null;
var AL_Document       = document;
var AL_ID_Replace     = /[~]+/g;
var AL_IS_Number      = new RegExp ("^\\s*(\\+|-)?((\\d+(\\.\\d+)?)|(\\.\\d+))\\s*$");

var AL_Titles         = null;
var AL_titleId        = 1;
var AL_titleDiv       = null;
var AL_titleLeft      = 0;
var AL_titleTop       = 0;
var AL_titleStop      = null;
var AL_hlStop         = null;

var AL_zIndex         = 100;
var AL_zObject        = null;
var AL_maskDiv        = null;

var AL_Initialised    = false;

function AL_setHtmlDocument (doc)
{
  AL_Document = doc;
}

function AL_CommonInitialise ()
{
  if (!AL_Initialised)
  {
    AL_Initialised = true;
    AL_DocAllowed  = new AL_Vector ();
    
    AL_DocAllowed.put ("activate");
    AL_DocAllowed.put ("beforeactivate");
    AL_DocAllowed.put ("beforecut");
    AL_DocAllowed.put ("beforedeactivate");
    AL_DocAllowed.put ("beforeeditfocus");
    AL_DocAllowed.put ("beforepaste");
    AL_DocAllowed.put ("click");
    AL_DocAllowed.put ("contextmenu");
    AL_DocAllowed.put ("controlselect");
    AL_DocAllowed.put ("cut");
    AL_DocAllowed.put ("dblclick");
    AL_DocAllowed.put ("deactivate");
    AL_DocAllowed.put ("drag");
    AL_DocAllowed.put ("dragend");
    AL_DocAllowed.put ("dragenter");
    AL_DocAllowed.put ("dragleave");
    AL_DocAllowed.put ("dragover");
    AL_DocAllowed.put ("dragstart");
    AL_DocAllowed.put ("drop");
    AL_DocAllowed.put ("focusin");
    AL_DocAllowed.put ("focusout");
    AL_DocAllowed.put ("help");
    AL_DocAllowed.put ("keydown");
    AL_DocAllowed.put ("keypress");
    AL_DocAllowed.put ("keyup");
    AL_DocAllowed.put ("mousedown");
    AL_DocAllowed.put ("mousemove");
    AL_DocAllowed.put ("mouseout");
    AL_DocAllowed.put ("mouseover");
    AL_DocAllowed.put ("mouseup");
    AL_DocAllowed.put ("mousewheel");
    AL_DocAllowed.put ("move");
    AL_DocAllowed.put ("moveend");
    AL_DocAllowed.put ("movestart");
    AL_DocAllowed.put ("paste");
    AL_DocAllowed.put ("propertychange");
    AL_DocAllowed.put ("readystatechange");
    AL_DocAllowed.put ("resizeend");
    AL_DocAllowed.put ("resizestart");
    AL_DocAllowed.put ("selectionchange");
    AL_DocAllowed.put ("stop");
    
    alEventAdd ("mouseover", alTitler, null);
    alEventAdd ("mouseout",  alTitler, null);

    if (!document.activeElement)
    {
      document.addEventListener ("focus", _dom_trackActiveElement,     true);
      document.addEventListener ("blur",  _dom_trackActiveElementLost, true);
    }
  }
}

function _dom_trackActiveElement (evt)
{
  if (evt && evt.target)
  { 
    document.activeElement = evt.target == document ? null : evt.target;
  }
}

function _dom_trackActiveElementLost (evt)
{
  document.activeElement = null;
}

function alGetTop ()
{
  return (AL_zIndex);
}

function alMakeTop (obj, force, centre)
{
  if (obj != null) if (force || (obj != AL_zObject))
  {
    if (centre && (AL_LastEvent != null))
    {
      var dims  = getDimensions (obj);
      var dxy   = getScrollXY   ();
      
      var hx    = Math.floor (dims[2] / 2);
      var hy    = Math.floor (dims[3] / 2);
      
      var dx    = Math.floor (AL_LastEvent.realX - hx);
      var dy    = Math.floor (AL_LastEvent.realY - hy);
      
      if ((dx - hx) < dxy[0]) dx = dxy[0];
      if ((dy - hy) < dxy[1]) dy = dxy[1];
      
      if ((dx + dims[2]) > (dxy[0] + AL_WindowWidth))  dx = dxy[0] + AL_WindowWidth  - dims[2];
      if ((dy + dims[3]) > (dxy[1] + AL_WindowHeight)) dy = dxy[1] + AL_WindowHeight - dims[3];
      
      obj.style.left = dx + "px";
      obj.style.top  = dy + "px";
    }
    
    obj.style.zIndex = AL_zIndex++;
    AL_zObject       = obj;
  }
}

function alSetTitle (name, title)
{
  if (!AL_Titles)
  {
    AL_Titles = new AL_Index ();
  }

  if (title)
  {
    AL_Titles.put (name, text2html (title, false, true));
  }
  else
  {
    AL_Titles.remove (name);
  }
}

function alTitleHide ()
{
  if (AL_titleDiv)
  {
    AL_titleDiv.tit_id        = 0;
    AL_titleDiv.className     = "siteTip";
    AL_titleDiv.style.display = "none";
  }
}

function alTitleIn (obj, isin, top, left, title)
{
  if (obj) if (obj.ititle || obj.atitle || obj.title || title)
  {
    if (AL_titleStop)
    {
      if (obj != AL_titleStop) if (obj.parentNode != AL_titleStop)
      {
        return;
      }
    }

    if (obj.ititle && AL_Titles)
    {
      title = AL_Titles.resolve (obj.ititle, null);
    }

    if (!obj.atitle) obj.atitle = obj.title ? ((obj.title.charAt (0) == '#') ? obj.title.substr (1) : text2html (obj.title, false, true)) : "";
    if ( obj.title)  obj.title  = "";
    
    if (AL_titleDiv == null)
    {
      AL_titleDiv = document.body.appendChild (document.createElement ("DIV"));
      
      AL_titleDiv.tit_id        = 0;
      AL_titleDiv.className     = "siteTip";
      AL_titleDiv.style.display = "none";
    }
    
    if (isin && !obj.disabled && (title || obj.atitle))
    {
      if (!obj.tit_id)
      {
        obj.tit_id = AL_titleId++;
      }
    
//    if (!obj.disabled)
      {
        var ww  = getWindowWidth  ();
        var wh  = getWindowHeight ();
        
        if ((left + 200) > ww) left = ww - 200;
        if ((top  + 200) > wh) top  = wh - 200;
        
        if (left < 0) left = 0;
        if (top  < 0) top  = 0;

        var goon  = (AL_titleDiv.tit_id == obj.tit_id) ? false : true;
        
        if (!goon)
        {
               if (Math.abs (AL_titleLeft - left) > 10) goon = true;
          else if (Math.abs (AL_titleTop  - top)  > 10) goon = true;
        }

        if (goon)
        {
//        if (obj.disabled)    AL_titleDiv.className += " siteTipDisabled";
          if (obj.atitleClass) AL_titleDiv.className += " " + obj.atitleClass;
          
          AL_titleDiv.innerHTML     = title ? title : obj.atitle;
          AL_titleDiv.tit_id        = obj.tit_id;
          AL_titleDiv.style.left    = left + "px";
          AL_titleDiv.style.top     = (top + 15) + "px";
//        AL_titleDiv.style.zIndex  = 1000000;
          AL_titleDiv.style.display = "block";
          
          AL_titleLeft = left;
          AL_titleTop  = top;
        }
      }
    }
    else
    {
      AL_titleDiv.tit_id        = 0;
      AL_titleDiv.className     = "siteTip";
      AL_titleDiv.style.display = "none";
    }
  }
}

function alTitler (e)
{
  var evt = new alEvent (e);
  var tgt = evt.target;

  if (tgt) if (tgt.ititle || tgt.atitle || tgt.title)
  {
    alTitleIn (tgt, (evt.type == "mouseover") ? true : false, evt.realY, evt.realX);
  }
  
  return (true);
}

function alHighlightReset (obj, cname)
{
  if (cname)
  {
    obj.className = cname;
  }
  
  obj.hln = null;
  obj.hlc = null;
  
  if (obj.hlz)
  {
    obj.hlx = obj.hlz;
  }
}

function alHighlight (e)
{
  var evt = new alEvent (e);

  alHighlightMe (evt.target, (evt.type == "mouseover") ? true : false, false, evt);
}

function alHighlightMe (obj, msin, ignore, evt, tgt)
{
  if (obj.hloid) obj = document.getElementById (obj.hloid); if (!obj) return;
  if (obj.hlo)   obj = obj.hlo;                             if (!obj) return;

  if (evt)
  {
    if (!tgt)
    {
      tgt = evt.target;
    }

    if (tgt) if (tgt.atitle || tgt.title)
    {
      alTitleIn (tgt, msin, evt.realY, evt.realX);
    }
  }

  if (obj.hlstop)
  {
    return;
  }

  if (AL_hlStop)
  {
    if (obj != AL_hlStop) if (obj.parentNode != AL_hlStop)
    {
      return;
    }
  }
  
  if (obj.hlx)
  {
    obj.hln = obj.className;
    obj.hlc = obj.hln + " " + obj.hlx;
    obj.hlz = obj.hlx;
    obj.hlx = null;
  }
  
  if (obj.hlc == null)
  {
    var pos = obj.className.indexOf (' ');
    
    if (pos > 0)
    {
      obj.hlc = obj.className.substr (0, pos) + "_hl" + obj.className.substr (pos);
      obj.hln = obj.className;
    }
    else if (obj.className.length > 0)
    {
      obj.hlc = obj.className + "_hl";
      obj.hln = obj.className;
    }
    else
    {
      if (!obj.hlc)
      {
        obj.hlc = "_hl";
      }
      
      obj.hln = "";
    }
    
    if (!obj.hlm && (obj.nodeName.toUpperCase () == "TR"))
    {
      if (obj.id.indexOf ("hl_") == 0)
      {
        var rows = findTable (obj).rows;
        var lim  = 0;
        var rbx  = obj.rowIndex - obj.id.split ('_')[1]; // substr (3);
        var rdx  = rbx;
        var done = false;
        
        while (!done && (rdx < rows.length))
        {
          if ((lim == 0) || (rows[rdx].id.split ('_')[1] > 0))
          {
            rows[rdx].hlm = true;
            rows[rdx].hli = rows[rdx].id.split ('_')[1];
            
            rdx++;
            lim++;
          }
          else
          {
            done = true;
          }
        }

        while (rdx-- > rbx)
        {
          rows[rdx].hll = lim;
        }
      }
    }
  }
  
  var cname = (obj.disabled || !msin) ? obj.hln : obj.hlc;
  
  if (obj.className != cname)
  {
    if (!ignore && obj.hlm)
    {
      var rows = findTable (obj).rows;
      var rdx  = obj.rowIndex - obj.hli;
      var lim  = rdx + obj.hll;
      
      do
      {
        alHighlightMe (rows[rdx], msin, true);
        
      } while (++rdx < lim);
    }
    else
    {
      obj.className = cname;
    }
  }
  
  if (obj.highlightInform)
  {
    obj.highlightInform (msin);
  }
}

function alMaximise (obj)
{
  obj.parentNode.style.width  = obj.scrollWidth  + "px";
  obj.parentNode.style.height = obj.scrollHeight + "px";
}

function alElementById (e)
{
  if (typeof (e) == 'string')
  {
         if (document.getElementById) e = document.getElementById (e);
    else if (document.all)            e = document.all[e];
    else
    {
      e = null;
    }
  }

  return (e);
}

function alEvent (evt)
{
  if (!evt)
  {
    evt = window.event;
  }
  
  this.evt  = evt;
  this.isIE = AL_Browser.ie;
  
  if (!this.evt && AL_FocusObject) if (AL_FocusObject.contentWindow)
  {
    this.evt = AL_FocusObject.contentWindow.event;
  }
  
  if (this.evt)
  {
    this.type          = this.evt.type;
    this.target        = this.evt.altTarget ? this.evt.altTarget : (this.evt.target || this.evt.srcElement);
    this.currentTarget = this.evt.currentTarget || this.target;
    this.button        = this.evt.button        || this.evt.which;
    this.keyCode       = this.evt.keyCode;
    this.charCode      = this.evt.charCode      || this.evt.keyCode;
    
    if (typeof (this.evt.charCode) != "undefined")
    {
      this.isChar = this.evt.charCode ? true : false;
    }
    else
    {
      this.isChar = true;
    }
    
    if (this.isIE)
    {
      this.relatedTarget = this.evt.toElement;
      
      if (this.relatedTarget == null)
      {
        this.relatedTarget = this.evt.fromElement;
      }
      
      this.realX = this.evt.clientX + document.documentElement.scrollLeft + document.body.scrollLeft;
      this.realY = this.evt.clientY + document.documentElement.scrollTop  + document.body.scrollTop;
    }
    else
    {
      this.relatedTarget = this.evt.relatedTarget;
      
      this.realX = this.evt.clientX + window.scrollX;
      this.realY = this.evt.clientY + window.scrollY;
    }
    
    if (!evt)
    {
      var dims = getDimensions (AL_FocusObject);
      
      this.clientX = dims[0] + this.evt.clientX;
      this.clientY = dims[1] + this.evt.clientY;
      
      this.target  = AL_FocusObject;
      
      if (this.isIE)
      {
        this.realX = this.clientX + document.documentElement.scrollLeft + document.body.scrollLeft;
        this.realY = this.clientY + document.documentElement.scrollTop  + document.body.scrollTop;
      }
      else
      {
        this.realX = this.clientX + window.scrollX;
        this.realY = this.clientY + window.scrollY;
      }
    }
    
    AL_LastEvent = this;
  }
  else
  {
    this.target = AL_FocusObject;
    
    if (this.target)
    {
      var dims = getDimensions (AL_FocusObject);
      
      this.clientX = dims[0];
      this.clientY = dims[1];
      
      if (this.isIE)
      {
        this.realX = this.clientX + document.documentElement.scrollLeft + document.body.scrollLeft;
        this.realY = this.clientY + document.documentElement.scrollTop  + document.body.scrollTop;
      }
      else
      {
        this.realX = this.clientX + window.scrollX;
        this.realY = this.clientY + window.scrollY;
      }
    }
  }
  
  this.cancel = function (bubble)
  {
    if (this.evt)
    {
      this.evt.cancelBubble = true;

      if (!bubble)
      {
        if (this.isIE)
        {
          this.evt.returnValue  = false;
        }
        else
        {
          this.evt.preventDefault ();
        }
      }
    }
  }
}

function alEventCancel (e)
{
  var evt = new alEvent (e);
  
  evt.cancel ();
  return (false);
}

function alDocEvent (e)
{
  alHandleEvent (e, document);
}

function alHandleEvent (e, tgt)
{
  var evt = e || window.event;
  var fnc = null;
  var blk = false;
  var tgb = AL_EventObj;
  
  if (!tgt)
  {
    tgt = evt.target || evt.srcElement;
  }

  if (evt.type == "keypress")
  {
    tgt = null;
    tgt = evt.target || evt.srcElement;
  }
  
  if (evt.type == "contextmenu")
  {
    fnc = null;
  }
  
  if (AL_EventObj != null)
  {
    tgt = AL_EventObj;
    blk = AL_EventBlock;
  }

  if (tgt)
  {
    do
    {
      eval ("fnc = tgt.ale_" + evt.type);
      
      if (!fnc)
      {
        tgt = tgt.ale_stop ? null : tgt.parentNode;
      }

    } while (!blk && !fnc && tgt);
  }

  if (AL_EventDef)
  {
    if (!fnc && (evt.type.charAt (0) == 'k'))
    {
      tgt = AL_EventDef;
      tgb = null;

      do
      {
        eval ("fnc = tgt.ale_" + evt.type);
      
        if (!fnc)
        {
          tgt = tgt.ale_stop ? null : tgt.parentNode;
        }

      } while (!blk && !fnc && tgt);

      if (fnc)
      {
        evt.altTarget = AL_EventDef;
      }
    }
    else if (AL_EventAuto && ((evt.target || evt.srcElement) != AL_EventDef))
    {
      switch (evt.type)
      {
        case "mouseover"  :
        case "mouseout"   :
        case "mousewheel" :

          break;

        default :

          AL_EventDef = null;
          break;
      }
    }
  }
    
  if (fnc)
  {
    if ((typeof (fnc) == "string") || String.prototype.isPrototypeOf (fnc))
    {
      eval ("if (tgt.ale_object) tgt.ale_object." + fnc.substr (1) + "(evt, tgb)");
    }
    else
    {
      fnc (evt, tgb);
    }

    evt.altTarget = null;
  }
}

function alEventDefault (obj, auto)
{
  AL_EventDef  = obj ? obj : null;
  AL_EventAuto = auto ? true : false;

  if (obj && document.activeElement) if (obj != document.activeElement)
  {
    document.activeElement.blur ();
  }

  obj.focus ();
}

function alEventCapture (obj, block)
{
  if (!obj)        obj = document;
  if (obj == null) obj = document;
  
  AL_EventObj   = obj;
  AL_EventBlock = block ? true : false;
}

function alEventCaptureCancel ()
{
  AL_EventObj = null;
}

function alEventAdd (which, method, obj)
{
  if (!AL_Initialised)
  {
    AL_CommonInitialise ()
  }

  if (which == "contextmenu")
  {
    obj = obj;
  }

  if (!obj)        obj = document;
  if (obj == null) obj = document;

  obj = alElementById (obj); eval ("obj.ale_" + which + " = method");
  
  if (AL_DocAllowed.contains (which))
  {
    obj = document;
  }
  
  if (AL_DocEvents == null)
  {
    AL_DocEvents = new AL_Vector ();
  }
  
  if ((obj != document) || !AL_DocEvents.contains (which))
  {
    AL_DocEvents.put (which);
/*
    eval ("obj.on" + which + " = alHandleEvent");

    return;
*/
    if (obj.attachEvent)
    {
      obj.attachEvent ("on" + which, alHandleEvent);
    }
    else if (obj.addEventListener)
    {
      obj.addEventListener (which, alHandleEvent, false);
    }
    else
    {
      eval ("obj.on" + which + " = alHandleEvent");
    }
  }
}

function alEventRemove (which, method, obj)
{
  if (!obj)        obj = document;
  if (obj == null) obj = document;

  obj = alElementById (obj);
  
  eval ("obj.ale_" + which + " = null");
/*  
  if (obj.detachEvent)
  {
    obj.detachEvent ("on" + which, method);
  }
  else if (obj.removeEventListener)
  {
    obj.removeEventListener (which, method, true);
  }
*/
}

function endsWith (stxt, ctxt)
{
  var matches = false;
  
  if (stxt.length >= ctxt.length)
  {
    if (stxt.substr (stxt.length - ctxt.length) == ctxt)
    {
      matches = true;
    }
  }
  
  return (matches);
}

function startsWith (stxt, ctxt)
{
  var matches = false;
  
  if (stxt.length >= ctxt.length)
  {
    if (stxt.substr (0, ctxt.length) == ctxt)
    {
      matches = true;
    }
  }
  
  return (matches);
}

function doNavigate (vtype, vcategory, vitem)
{
  var sfrm  = null;
  var ok    = false;
  
  if (vtype == 'link')
  {
    sfrm = document.getElementById ("linkForm");
    
    if (sfrm != null)
    {
      sfrm.action = vitem;
    }
  }
  else
  {
    sfrm = document.getElementById ("navigateForm");
    
    if (sfrm != null)
    {
      document.getElementById ("sidType").value     = vtype;
      document.getElementById ("sidCategory").value = vcategory;
      document.getElementById ("sidItem").value     = vitem;
    }
    
    if (sfrm != null)
    {
      ok = true;
      sfrm.submit ();
    }
  }
  
  return (ok);
}

function findTag (e, tag)
{
  tName = e.tagName.toUpperCase ();

       if (tName == tag)    return e;
  else if (tName == "BODY") return null;

  return (findTag (e.parentNode));
}

function whichTable (e)
{
  tName = e.tagName.toUpperCase ();

       if (tName == "TABLE") return e;
  else if (tName == "BODY")  return null;

  return (whichTable (e.parentNode));
}

function findTable (e, inner, part)
{
  switch (e.tagName.toUpperCase ())
  {
    case "THEAD" :
    case "TBODY" :
    case "TFOOT" :
    
      if (!part)
      {
        break;
      }
      
    case "TABLE" :

      if (inner || (e.parentNode.tagName.toUpperCase () != "TD"))
      {
        return e;
      }
      
      break;
      
    case "BODY"  :
    
      return (null);
      break;
  }

  return (findTable (e.parentNode, inner, part));
}

function findInnerCell (e)
{
  tName = e.tagName.toUpperCase ();

  switch (tName)
  {
    case "TD" :
    case "TH" :
    
      break;
      
    default   :
    
      var cn  = e.childNodes;
      var idx = -1;
      
      e = null;
      
      if (cn) if (cn.length > 0)
      {
        while ((e == null) && (++idx < cn.length))
        {
          if (cn.item (idx).nodeType == 1)
          {
            e = findInnerCell (cn.item (idx));
          }
        }
      }
      
      break;
  }

  return (e);
}

function findCell (e)
{
  tName = e.tagName.toUpperCase ();

  if (tName == "TD")   return e;
  if (tName == "TH")   return e;
  if (tName == "BODY") return null;

  return (findCell (e.parentNode));
}

function findCellTag (e, tag, sid)
{
  tName = e.tagName.toUpperCase ();

  if (tName == tag)
  {
    if (sid) if (e.id.indexOf (sid) == 0)
    {
      sid = null;
    }
    
    if (!sid)
    {
      return (e);
    }
  }

  if (tName == "TD")   return e;
  if (tName == "TH")   return e;
  if (tName == "BODY") return null;

  return (findCellTag (e.parentNode, tag, sid));
}

function findRowTag (e, tag, sid)
{
  tName = e.tagName.toUpperCase ();

  if (tName == tag)
  {
    if (sid) if (e.id.indexOf (sid) == 0)
    {
      sid = null;
    }
    
    if (!sid)
    {
      return (e);
    }
  }
  
  if (tName == "TR")    return e;
  if (tName == "TABLE") return null;
  if (tName == "BODY")  return null;

  return (findRowTag (e.parentNode, tag, sid));
}

function findRow (e)
{
  tName = e.tagName.toUpperCase ();

  if (tName == "TR")    return e;
  if (tName == "TABLE") return null;
  if (tName == "BODY")  return null;

  return (findRow (e.parentNode));
}

function removeSpace (sval)
{
  sval = compress (sval);
  
  var pos = 0;
  var lim = sval.length;
  
  do
  {
    pos = sval.indexOf (' ');
    
    if (pos > 0)
    {
      sval = sval.substr (0, pos) + sval.substr (pos + 1);
    }
    
  } while (pos > 0);
  
  return (sval);
}

function compressLR (sval, nval)
{
  if (sval)
  {
    var pos  = 0;
    var lim  = sval.length;
    var done = false;
    
    while (!done && (pos < lim))
    {
      if (sval.charAt (pos) <= ' ')
      {
        pos++;
      }
      else
      {
        done = true;
      }
    }
    
    if (pos > 0)
    {
      sval = sval.substr (pos);
      lim -= pos;
    }

    done = false;
    
    while (!done && (lim > 0))
    {
      if (sval.charAt (lim - 1) <= ' ')
      {
        lim--;
      }
      else
      {
        done = true;
      }
    }
    
    if (lim < sval.length)
    {
      sval = sval.substr (0, lim);
    }
    
    if (nval && (sval.length == 0))
    {
      sval = nval;
    }
  }
  
  return (sval);
}

function compress (sval, nval)
{
  sval = compressLR (sval);
  
  var pos  = 0;
  var lim  = sval.length;
  var done = false;
  
  pos  = 0;
  done = false;

  while (pos < lim)
  {
    if (sval.charAt (pos) <= ' ')
    {
      done = false;
      lim  = ++pos;
      
      while (!done && (lim < sval.length))
      {
        if (sval.charAt (lim) <= ' ')
        {
          lim++;
        }
        else
        {
          done = true;
        }
      }
      
      if ((lim - pos) > 1)
      {
        sval = sval.substr (0, pos) + sval.substr (lim);
      }
      
      lim = sval.length;
    }

    pos++;
  }
  
  if (nval && (sval.length == 0))
  {
    sval = nval;
  }
  
  return (sval);
}

function normaliseString (title)
{
  var tStr  = title;
  var tLim  = tStr.length;
  var tPos  = -1;
  var ch    = 0;

  while (++tPos < tLim)
  {
    ch = tStr.charAt (tPos);
    ch = ch.toUpperCase ();

    if (((ch < 'A') || (ch > 'Z')) && ((ch < '0') || (ch > '9')))
    {
      tStr = tStr.substr (0, tPos) + '_' + tStr.substr (tPos + 1);
    }
  }

  return (tStr)
}

function GetCookie(sName)
{
  var aCookie = document.cookie.split ("; ");
  var cValue  = "";
  var aCrumb  = null;

  var limit   = aCookie.length;
  var index   = -1;

  while ((cValue == "") && (++index < limit))
  {
    aCrumb = aCookie[index].split ("=");

    if (aCrumb.length == 2)
    {
      if (sName == aCrumb[0])
      {
        cValue = unescape (aCrumb[1]);
      }
    }
  }

  return (cValue)
}

function htmlEncode (txt)
{
  if (txt != null)
  {
    if (txt.indexOf ('&') >= 0) txt = txt.replace (/&/g, "&amp;");
    if (txt.indexOf ('<') >= 0) txt = txt.replace (/>/g, "&gt;");
    if (txt.indexOf ('>') >= 0) txt = txt.replace (/</g, "&lt;");
  }
  else
  {
    txt = "&nbsp;";
  }
  
  return (txt);
}


function htmlDecode (txt)
{
  if (txt != null)
  {
    if (txt.indexOf ("&nbsp;") >= 0) txt = txt.replace (/&nbsp;/g, " ");
    if (txt.indexOf ("&amp;")  >= 0) txt = txt.replace (/&amp;/g,  "&");
    if (txt.indexOf ("&lt;")   >= 0) txt = txt.replace (/&lt;/g,   "<");
    if (txt.indexOf ("&gt;")   >= 0) txt = txt.replace (/&gt;/g,   ">");
  }
  else
  {
    txt = "";
  }
  
  return (txt);
}

function encodeString (zzz)
{
  var xl  = zzz.length;
  var ch  = null;
  var c1  = 0;
  var c2  = 0;
  
  while (xl-- > 0)
  {
    ch = zzz.charAt (xl);
    
    if (((ch >= '0') && (ch <= '9')) ||
        ((ch >= 'A') && (ch <= 'Z')) ||
        ((ch >= 'a') && (ch <= 'z')) || (ch == '.') || (ch == '-') || (ch == '*') || (ch == '_') || (ch == ' '))
    {
    }
    else
    {
      c1 = zzz.charCodeAt (xl);
      c2 = c1 & 0x0F;
      c1 >>>= 4;
      
      c1 += (c1 > 9) ? 55 : 48;
      c2 += (c2 > 9) ? 55 : 48;

      zzz = zzz.substr (0, xl) + '%' + String.fromCharCode (c1, c2) + zzz.substr (xl + 1);
    }
  }
  
  if (zzz.indexOf (' ') >= 0)
  {
    zzz = zzz.replace (/\ /g, "+");
  }
  
  return (zzz);
}

function decodeString (zzz)
{
  var p1  = -1;
  var c1  = 0;
  var c2  = 0;
  
  if (zzz.indexOf ('+') >= 0)
  {
    zzz = zzz.replace (/\+/g, " ");
  }
  
  do
  {
    p1 = zzz.indexOf ('%', p1 + 1);
    
    if (p1 >= 0)
    {
      c1 = zzz.charCodeAt (p1 + 1);
      c2 = zzz.charCodeAt (p1 + 2);
      
      c1 -= (c1 >= 65) ? 55 : 48;
      c2 -= (c2 >= 65) ? 55 : 48;
      
      c1 <<= 4;
      c1  |= c2;
      
      zzz = zzz.substr (0, p1) + String.fromCharCode (c1) + zzz.substr (p1 + 3);
    }
    
  } while (p1 > 0);
  
  return (zzz);
}

function sortOptions (obj)
{
  var opts = obj.options;
  var oIdx = -1;
  var oLim = opts.length;
  var oTxt = "";
  
  while (++oIdx < oLim)
  {
    if (opts[oIdx].text >= oTxt)
    {
      oTxt = opts[oIdx].text;
    }
    else
    {
      xTxt = opts[oIdx].text;
      xIdx = oIdx;
      done = false;

      while (!done && (xIdx > 0))
      {
        xIdx--;
        
        if (xTxt >= opts[xIdx].text)
        {
          done  = true;
          xIdx += 1;
        }
      }
      
      obj.insertBefore (opts[oIdx], opts[xIdx]);
    }
  }
}

function insertOption (opt, out, sortit, base, ssel)
{
  if (sortit)
  {
    var dopts = out.options;
    var didx  = dopts.length;
    var otxt  = opt.text.toLowerCase ();
    
    base = base ? base : 0;
    
    while ((opt != null) && (didx > base))
    {
      if (otxt >= dopts[--didx].text.toLowerCase ())
      {
        if (++didx < dopts.length)
        {
          out.insertBefore (opt, dopts[didx]);
        }
        else
        {
          out.appendChild (opt);
        }
        
        if (ssel)
        {
          dopts[didx].selected = true;
        }
        
        opt = null;
      }
    }
    
    if (opt != null)
    {
      if (dopts.length > base)
      {
        out.insertBefore (opt, dopts[base]);
      }
      else
      {
        out.appendChild (opt);
      }
        
      if (ssel)
      {
        dopts[dopts.length - 1].selected = true;
      }
    }
  }
  else
  {
    if (AL_Browser.ie)
    {
      out.appendChild (opt);
    }
    else
    {
      out.options.add (opt);
    }
  }
}

function transferSelected (oin, out, sortit, sidx, base)
{
  base = base ? base : 0;
  sidx = sidx ? sidx : 0;
  
  if (oin.multiple)
  {
    transferSelect (oin, out, sortit, null, null, false, base);
  }
  else if (oin.selectedIndex >= 0)
  {
    insertOption (oin.removeChild (oin.options[oin.selectedIndex]), out, sortit, base);

    if (sidx < oin.options.length)
    {
      oin.selectedIndex = sidx;
    }
  }
}

function transferSelect (oin, out, sortit, sfunc, sarg, sall, base, shadow)
{
  var opts  = oin.options;
  var oIdx  = opts.length;
  var opt   = null;
  var doit  = false;
  var dopts = out.options;
  var didx  = dopts.length;
  
  sall = sall ? true : false;
  base = base ? base : 0;
  
  while (oIdx-- > 0)
  {
    if (sall || opts[oIdx].selected) if (opts[oIdx].id != "ignore")
    {
      opts[oIdx].selected = false;

      doit = (shadow && opts[oIdx].shadow) ? false : true;
      opt  = oin.removeChild (opts[oIdx]);
      
      if (sfunc != null)
      {
        doit = sfunc (opt, sarg);
      }
      
      if (doit)
      {
        if (sortit)
        {
          var otxt  = opt.text.toLowerCase ();
          
          while ((opt != null) && (didx > base))
          {
            if (otxt >= dopts[--didx].text.toLowerCase ())
            {
              if (++didx < dopts.length)
              {
                out.insertBefore (opt, dopts[didx]);
              }
              else
              {
                out.appendChild (opt);
              }
              
              opt = null;
            }
          }
          
          if (opt != null)
          {
            if (dopts.length > base)
            {
              out.insertBefore (opt, dopts[base]);
            }
            else
            {
              out.appendChild (opt);
            }
          }
        }
        else
        {
          if (AL_Browser.ie)
          {
            out.appendChild (opt);
          }
          else
          {
            out.options.add (opt);
          }
        }
      }
    }
  }
}

function reduceSelect (sobj, vobj, skip, text, sorted, sidx, ids)
{
  var sopts = sobj.options;
  var vopts = vobj.options;
  var vidx  = vopts.length;
  var value = null;
  var done  = false;

  skip = skip ? skip : 0;
  sidx = sidx ? sidx : sopts.length;
  
  if (sidx > sopts.length)
  {
    sidx = sopts.length;
  }
  
  while (vidx-- > skip)
  {
    value = text ? vopts[vidx].text : vopts[vidx].value;
    sidx  = sopts.length;
    done  = false;
    
    do
    {
      sidx--;
      
      if (ids) if (sopts[sidx].id == ids)
      {
        continue;
      }
      
      if (text)
      {
        if (sopts[sidx].text == value)
        {
          sobj.removeChild (sopts[sidx]); done = true;
        }
        else if (sorted) if (sopts[sidx].text < value)
        {
          sidx += 1;
          done  = true;
        }
      }
      else
      {
        if (sopts[sidx].value == value)
        {
          sobj.removeChild (sopts[sidx]); done = true;
        }
        else if (sorted) if (sopts[sidx].value < value)
        {
          sidx += 1;
          done  = true;
        }
      }
      
    } while (!done && (sidx > 0));
  }
}

function renderSelect (sobj, all, sep, skip, text, quote, rexp, rstr)
{
  var txt   = "";

  skip = skip ? skip : 0;
  rstr = rstr ? rstr : "";
  
  if (!sobj.multiple && !all)
  {
    if (text)
    {
      txt = (sobj.selectedIndex >= skip) ? sobj.options[sobj.selectedIndex].text : "";
    }
    else
    {
      txt = (sobj.selectedIndex >= skip) ? sobj.options[sobj.selectedIndex].value : "";
    }
    
    if (rexp)  txt = txt.replace (rexp, rstr)
    if (quote) txt = '"' + txt + '"';
  }
  else
  {
    var bits  = new Array ();
    var opts  = sobj.options;
    var idx   = skip - 1;
    var ttx   = null;
    
    sep = sep ? sep : ",";
    
    while (++idx < opts.length)
    {
      if (opts[idx].selected || all)
      {
        if (txt.length > 0)
        {
          txt += sep;
        }
        
        ttx = text ? opts[idx].text : opts[idx].value;
    
        if (rexp)  ttx = ttx.replace (rexp, rstr)
        if (quote) ttx = '"' + ttx + '"';
        
        txt += ttx;
      }
    }
  }
  
  return (txt);
}

function setupSelectText (sval, sep, sort, vs)
{
  var bits  = sort ? new AL_Vector (sval, sep) : null;
  var vals  = bits ? bits.values : sval.split (sep ? sep : ';');
  var blim  = vals.length;
  var name  = null;
  var value = null;
  var stxt  = "";
  
  vs  = vs ? vs : ':';
  idx = -1;
  
  while (++idx < blim)
  {
    pos = vals[idx].indexOf (vs);
    
    if (pos >= 0)
    {
      name  = compressLR (vals[idx].substr (0, pos));
      value = compressLR (vals[idx].substr (pos + 1));
    }
    else
    {
      name  = compressLR (vals[idx]);
      value = compressLR (vals[idx]);
    }
    
    stxt += "<option \"" + value + "\">" + name + "</option>";
  }
  
  return ((stxt.length > 0) ? stxt : null);
}

function setupSelect (sobj, sval, sep, keep, sort, vs, base)
{
  var opts  = sobj.options;
  var idx   = opts.length;
  
  if (!keep)
  {
    base = base ? base : 0;
    
    while (idx-- > base)
    {
      sobj.removeChild (opts[idx]);
    }
  }
  
  if (sval)
  {
    var bits  = sort ? new AL_Vector (sval, sep) : null;
    var vals  = bits ? bits.values : sval.split (sep ? sep : ';');
    var blim  = vals.length;
    var opt   = null;
    var name  = null;
    var value = null;
    
    vs  = vs ? vs : ':';
    idx = -1;
    
    while (++idx < blim)
    {
      pos = vals[idx].indexOf (vs);
      
      if (pos >= 0)
      {
        name  = compressLR (vals[idx].substr (0, pos));
        value = compressLR (vals[idx].substr (pos + 1));
      }
      else
      {
        name  = compressLR (vals[idx]);
        value = compressLR (vals[idx]);
      }
      
      opt = document.createElement ("OPTION");
      
      opt.innerHTML = text2html (name);
      opt.value     = value;
      
      sobj.appendChild (opt);
    }
  }
}

function generateSelectObj (sobj, nodes, choice)
{
  if (nodes) if (nodes.length > 0)
  {
    var mult  = sobj.multiple;
    var name  = null;
    var text  = null;
    var value = null;
    var title = null;
    var idx   = -1;

    while (++idx < nodes.length)
    {
      name  = getNodeText (nodes[idx], true, null, true,  false, false, "./name");
      text  = getNodeText (nodes[idx], true, name, true,  false, false, "./text");
      value = getNodeText (nodes[idx], true, name, false, false, false, "./value");
      title = getNodeText (nodes[idx], true, null, false, false, false, "./title");
      
      if (name)
      {
        opt = sobj.appendChild (document.createElement ("OPTION"));
        
        opt.innerHTML = text;
        opt.sname     = name;
        opt.value     = value;
        opt.title     = title;
        
        if (!choice) if (boolAttribute (nodes[idx], "selected"))
        {
          if (mult)
          {
            opt.selected = true;
          }
          else
          {
            choice = value;
          }
        }
      }
    }
    
    if (choice)
    {
      setSelect (sobj, choice);
    }
  }
  
  return (sobj.selectedIndex);
}

function generateSelect (sobj, nodes, choice, first, sbits, onc, hnull)
{
  var cell  = sobj.parentNode;
  
  if (sobj.nodeName.toUpperCase () != "SELECT")
  {
    cell = sobj;
    sobj = null;
  }

  if (nodes) if (nodes.length == 0)
  {
    nodes = null;
  }
  
  if (nodes || !hnull)
  {
    var stxt  = first ? ("<option>" + first + "</option>") : "";
    var name  = null;
    var text  = null;
    var value = null;
    var title = null;
    var idx   = -1;
    var lim   = nodes ? nodes.length : 0;
    
    while (++idx < lim)
    {
      name  = getNodeText (nodes[idx], true, null, true, false, false, "./name");
      text  = getNodeText (nodes[idx], true, null, true, false, false, "./text");
      value = getNodeText (nodes[idx], true, null, true, false, false, "./value");
      title = getNodeText (nodes[idx], true, null, true, false, false, "./title");

      stxt += "<option value=\"" + (value ? value : name) + "\""
      
      if (title)
      {
        stxt += " title=\"" + title + "\"";
      }
      
      stxt += ">" + (text ? text : name) + "</option>";
    }
    
    if (AL_Browser.ie || !sobj)
    {
      cell.innerHTML = "<select" + (sbits ? sbits : "") + ">" + stxt + "</select>";
      sobj           = cell.children ? cell.children.item (0) : cell.childNodes[0];
      
      if (onc)
      {
        sobj.onchange = onc;
      }
    }
    else
    {
      sobj.innerHTML = stxt;
    }
    
    sobj.selectedIndex = 0;
    
    if (choice)
    {
      setSelect (sobj, choice);
    }
  }
  else
  {
    if (hnull)
    {
      cell.innerHTML = hnull;
    }
  }
  
  return (sobj);
}

function setSelect (sobj, sval, sep, reset, text)
{
  var ok    = false;

  if (sval)
  {
    var opts  = sobj.options;
    var index = -1;

    if (sep)
    {
      var bits  = new AL_Vector (sval, sep);
      var blim  = bits.entries ();
      
      if (blim > 1)
      {
        index = opts.length;
        
        while ((index-- > 0) && (blim > 0))
        {
          if (reset)
          {
            opts[index].selected = bits.contains (text ? opts[index].text : opts[index].value); if (opts[index].selected) ok = true;
          }
          else
          {
            if (bits.contains (text ? opts[index].text : opts[index].value))
            {
              opts[index].selected = true; blim--; ok = true;
            }
          }
        }
      }
      else
      {
        sep = null;
      }
    }
    
    if (!sep)
    {
      while (++index < opts.length)
      {
        if (text)
        {
          if (opts[index].text == sval)
          {
            ok = true;
          }
        }
        else
        {
          if (opts[index].value == sval)
          {
            ok = true;
          }
        }
        
        if (ok)
        {
          if (sobj.multiple)
          {
            opts[index].selected = true;
          }
          else
          {
            sobj.selectedIndex = index;
          }
          
           index  = opts.length;
        }
      }
    }
  }

  return (ok);
}

function getRadioValue (name)
{
  var rval  = null;
  var rset  = document.getElementsByName (name);
  var ridx  = rset ? rset.length : 0;

  while (ridx-- > 0)
  {
    if (rset[ridx].checked)
    {
      rval = rset[ridx].value;
      ridx = 0;
    }
  }

  return (rval);
}

function isValidEmail (emailAddress) 
{
  var rem = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
//  var rem = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/;
  
  return (rem.test (emailAddress));
}

function isValidPostcodeUK (postcode)
{
//  var rpc = /^\\s*[A-Z]{1,2}[0-9][0-9A-Z]?\\s+[0-9][ABD-HJLNP-UW-Z]{2}\\ s*$/;
  var rpc = /[A-Z]{1,2}[0-9][0-9A-Z]? [0-9][ABD-HJLNP-UW-Z]{2}/;
  
  return (rpc.test (postcode));
}

function isValidPhoneNumber (phoneno)
{
  var rtn = /^\(\d{3}\) \d{3}-\d{4}$/;

  return (rtn.test (phoneno));
}

function isValidDecimal (dval, formal)
{
  var rdp = /^\d+\.\d+$/;
  var rdn = /^\d+(\.\d+)?$/;
  
  return (formal ? rdp.test (dval) : rdn.test (dval));
}

function absoluteURL (rurl)
{
  var aurl  = document.URL;
  
  pos = aurl.lastIndexOf ('/');
  
  if (pos >= 0)
  {
    aurl = aurl.substr (0, (pos + 1)) + rurl;
  }
  else
  {
    aurl = rurl;
  }
  
  return (aurl);
}

function getStyleValue (obj, attr, adef)
{
  var aval  = eval ("obj.style." + attr);
  
  if (aval != null) if (aval.length == 0)
  {
    aval = null;
  }
  
  if (aval == null)
  {
    if (obj.currentStyle)
    {
      aval = eval ("obj.currentStyle." + attr);
    }
    else
    {
      aval = eval ("getComputedStyle (obj, '')." + attr);
    }
  }
  
  if (aval != null) if ((aval.length == 0) || (aval == "auto"))
  {
    aval = null;
  }
  
  return ((aval != null) ? aval : adef);
}

function alMaskWindow (render, obj)
{
  obj = obj ? obj : document;
  
  if (render)
  {
    if (obj.AL_maskDiv == null)
    {
      obj.AL_maskDiv = document.createElement ("DIV");
      
      obj.AL_maskDiv.innerHTML    = "&nbsp;";
      obj.AL_maskDiv.className    = "windowMask";
      
      obj.appendChild (obj.AL_maskDiv);
    }

    var h = 0;
    var w = 0;
    
    if (obj == document)
    {
      h = getWindowHeight ();
      w = getWindowWidth ()
    }
    else
    {
      h = obj.scrollHeight;
      w = obj.scrollWidth;
    }

    obj.AL_maskDiv.style.width   = w + "px";
    obj.AL_maskDiv.style.height  = h + "px";
    obj.AL_maskDiv.style.zIndex  = AL_zIndex;
    obj.AL_maskDiv.style.display = "block";
  }
  else
  {
    if (obj.AL_maskDiv != null)
    {
      obj.AL_maskDiv.style.display = "none";
    }
  }
  
  return (AL_zIndex + 1);
}

function getScrollXY ()
{
  var scrOfX  = 0;
  var scrOfY  = 0;
  
  if (typeof (window.pageYOffset) == 'number')
  {
    scrOfY = window.pageYOffset;
    scrOfX = window.pageXOffset;
  }
  else if (document.body && document.body.scrollLeft)
  {
    scrOfY = document.body.scrollTop;
    scrOfX = document.body.scrollLeft;
  }
  else if (document.documentElement && document.documentElement.scrollLeft)
  {
    scrOfY = document.documentElement.scrollTop;
    scrOfX = document.documentElement.scrollLeft;
  }

  return ([scrOfX, scrOfY]);
}

function setScrollLeft (pos)
{
  if (document.body && document.body.scrollLeft)
  {
    document.body.scrollLeft = pos;
  }
  else if (document.documentElement && document.documentElement.scrollLeft)
  {
    document.documentElement.scrollLeft = pos;
  }
}

function setScrollTop (pos)
{
  if (document.body && document.body.scrollTop)
  {
    document.body.scrollTop = pos;
  }
  else if (document.documentElement && document.documentElement.scrollTop)
  {
    document.documentElement.scrollTop = pos;
  }
}

function getDimensions (obj, base)
{
  obj = alElementById (obj);
  
  if (obj != null)
  {
    if ((obj == document) || (obj == document.body))
    {
      obj = [0, 0, getWindowWidth (), getWindowHeight ()];
    }
    else
    {
      var sobj    = obj;
      var oleft   = 0;
      var otop    = 0;
      var owidth  = (obj.clientWidth  > 0) ? obj.clientWidth  : obj.offsetWidth;
      var oheight = (obj.clientHeight > 0) ? obj.clientHeight : obj.offsetHeight;

      if (obj.style.position == "absolute")
      {
        oleft = obj.offsetLeft;
        otop  = obj.offsetTop;
      }
      else
      {
        base = base ? base : null;
        
        do
        {
          oleft += obj.offsetLeft;
          otop  += obj.offsetTop;
          obj    = obj.offsetParent;

        } while (obj && (obj != base));
      }
      
      if (owidth == 0)
      {
        otop    = parseInt (sobj.style.top,    10);
        oleft   = parseInt (sobj.style.left,   10);
        owidth  = parseInt (sobj.style.width,  10);
        oheight = parseInt (sobj.style.height, 10);
      }

      obj = [oleft, otop, owidth, oheight];
    }
  }
  
  return (obj);
}

function alCancelEvent (e)
{
  new alEvent (e).cancel ();
  
  return (false);
}

function alSetStyleString (obj, style)
{
  if (style) if (style.length > 0)
  {
    var parts = style.split (';');
    var idx   = -1;
    var pos   = 0;
    
    while (++idx < parts.length)
    {
      try
      {
        pos = parts[idx].indexOf (':');
        
        if (pos > 0)
        {
          eval ("obj.style." + compressLR (parts[idx].substr (0, pos)) + " = \"" + compressLR (parts[idx].substr (pos + 1)) + "\";");
        }
        else
        {
          obj.className += " " + parts[idx];
        }
      }
      
      catch (e)
      {
      }
    }
  }
}

function alSetHtmlAttributes (obj, nodes)
{
  if (obj && nodes) if (nodes.length > 0)
  {
    var type  = null;
    var key   = null;
    var value = null;
    var idx   = -1;
    
    while (++idx < nodes.length)
    {
      type  = nodes[idx].getAttribute ("type");
      key   = getSingleNode (nodes[idx], "./key",   null, true);
      value = getSingleNode (nodes[idx], "./value", null, true);
      
      if (type == null)
      {
        type = "property";
      }
      
      switch (type)
      {
        case "property" : eval ("obj."       + key + " = value;"); break;
        case "style"    : eval ("obj.style." + key + " = value;"); break;
        case "event"    :
        
          {
            var pos  = value.indexOf ('~');
            var name = null;
            var func = null;
            
            if (pos > 0)
            {
              if (AL_EventFunctions == null)
              {
                AL_EventFunctions = new AL_Index ();
              }

              name  = value.substr (0, pos);
              value = value.substr (pos + 1);
              func  = AL_EventFunctions.resolve (name, null)
            }
            
            if (func == null)
            {
              func = eval (value);
              
              if ((func != null) && (name != null))
              {
                AL_EventFunctions.put (name, func);
              }
            }
            
            if (func != null)
            {
              if (key.charAt (2) == '-')
              {
                alEventRemove (key.substr (3), func, this.object); break;
              }
              else
              {
                alEventAdd (key.substr (2), func, this.object); break;
              }
            }
          }
          
          break;
      }
    }
  }
}

var alClipboardInit   = false;
var alClipboardTrans  = null;
var alClipboardClipC  = null;
var alClipboardClipS  = null;
var alClipboardString = null;
var alClipboardID     = null;

function alClipboardSetup ()
{
  netscape.security.PrivilegeManager.enablePrivilege ('UniversalXPConnect');

  alClipboardClipC  = Components.classes['@mozilla.org/widget/clipboard;1'].createInstance (Components.interfaces.nsIClipboard);
  alClipboardClipS  = Components.classes["@mozilla.org/widget/clipboard;1"].getService (Components.interfaces.nsIClipboard);
  alClipboardTrans  = Components.classes['@mozilla.org/widget/transferable;1'].createInstance (Components.interfaces.nsITransferable);
  alClipboardString = Components.classes["@mozilla.org/supports-string;1"].createInstance (Components.interfaces.nsISupportsString);
  alClipboardID     = Components.interfaces.nsIClipboard;
  
  alClipboardTrans.addDataFlavor ('text/unicode');
  
  alClipboardInit = true;
}

function gotClipboard ()
{
  return ((window.clipboardData || window.netscape) ? true : false);
}

function setClipboard (text)
{
  if (!text)
  {
    text = "";
  }
  
  if (window.clipboardData)
  {
    window.clipboardData.setData ("Text", text);
  }
  else if (window.netscape)
  {
    if (!alClipboardInit)
    {
      alClipboardSetup ();
    }

    if (alClipboardClipC && alClipboardTrans)
    {
      alClipboardString.data = text;
      
      alClipboardTrans.setTransferData ("text/unicode", alClipboardString, (text.length * 2));
      
      var clipid  = Components.interfaces.nsIClipboard;
      
      if (clipid)
      {
        alClipboardClipC.setData (alClipboardTrans,
                                  null,
                                  alClipboardID.kGlobalClipboard);
      }
    }
  }

  return (false);
}

function getClipboard ()
{
  var txt = null;
  
  if (window.clipboardData)
  {
    txt = window.clipboardData.getData ("Text");
  }
  else if (window.netscape)
  {
    if (!alClipboardInit)
    {
      alClipboardSetup ();
    }

    if (alClipboardClipS && alClipboardTrans)
    {
      alClipboardClipS.getData (alClipboardTrans,
                                alClipboardClipS.kGlobalClipboard);

      var str       = new Object ();
      var strLength = new Object ();

      alClipboardTrans.getTransferData ("text/unicode", str, strLength); 

      if (str) str = str.value.QueryInterface (Components.interfaces.nsISupportsString);
      if (str) txt = str.data.substring (0, (strLength.value / 2));
    }
  }

  return (txt ? txt : null);
}

function styleRuleValue (sel, rule)
{
  var sheets  = document.styleSheets;
  var rules   = null;
  var value   = null;
  var sidx    = -1;
  var ridx    = -1;
  
  sel = sel.toLowerCase ();
  
  while (++sidx < sheets.length)
  {
    rules = sheets[sidx].cssRules ? sheets[sidx].cssRules : sheets[sidx].rules;
    ridx  = -1;
    
    while (++ridx < rules.length)
    {
      if (rules[ridx].selectorText.toLowerCase () == sel)
      {
        eval ("value = rules[ridx].style." + rule);
        
        ridx = rules.length;
        sidx = sheets.length;
      }
    }
  }
  
  return (value);
}

var alStyleNode   = null;
var alStyleIndex  = -1;

function alStyleSheet ()
{
  this.ssheet = null;
  this.index  = null;
  
  if (document.createStyleSheet)
  {
    if (alStyleIndex < 0)
    {
      alStyleIndex = document.styleSheets.length;
    }
    
    this.ssheet = document.createStyleSheet (null, alStyleIndex);
  }
  else
  {
    var snode = document.createElementNS ("http://www.w3.org/1999/xhtml", "html:style");
  
    document.getElementsByTagName ("head").item (0).appendChild (snode);
    
    this.ssheet = document.styleSheets[document.styleSheets.length - 1];
  }

  this.findRule = function (id)
  {
    if (this.index == null)
    {
      var rules = this.ssheet.cssRules ? this.ssheet.cssRules : this.ssheet.rules;
      var idx   = -1;
      
      this.index = new AL_Index ();
      
      while (++idx < rules.length)
      {
        this.index.put (rules[idx].selectorText.toLowerCase (), rules[idx])
      }
    }
    
    return (this.index.resolve (id.toLowerCase (), null));
  }
    
  this.addRule = function (rid, text)
  {
    var rule  = this.findRule (rid);
    
    if (rule == null)
    {
      if (this.ssheet.addRule)
      {
        this.ssheet.addRule (rid, text);
        rule = this.ssheet.rules[this.ssheet.rules.length - 1];
      }
      else if (this.ssheet.insertRule)
      {
        this.ssheet.insertRule (rid + "{" + text + "}", this.ssheet.cssRules.length);
        rule = this.ssheet.cssRules[this.ssheet.cssRules.length - 1];
      }
      else
      {
        rule = this.ssheet.appendChild (document.createTextNode (rid + " { " + text + " }"));
      }
      
      if (this.index != null)
      {
        this.index.put (rid.toLowerCase (), rule);
      }
    }
    
    return ((rule != null) ? rule : this.findRule (rid));
  }
}

function alStyle (id, text, ss)
{
  var snode = null;
  
  if (!ss)
  {
    ss = null;
  }
  
  this.ssheet = (ss != null) ? ss : alStyleNode;

  if (this.ssheet == null)
  {
    alStyleNode = new alStyleSheet ();
    this.ssheet = alStyleNode;
  }
  
  this.id   = id;
  this.rule = this.ssheet.addRule (id, text ? text : "fred:blue");
  
  this.setRule = function (name, value, altname)
  {
    if (this.rule == null)
    {
      this.rule = this.ssheet.findRule (this.id);
    }
    
    if (this.rule != null)
    {
      if (this.rule.style.setProperty)
      {
        eval ("this.rule.style." + (altname ? altname : name) + " = value");
//      this.rule.style.setProperty (name, value, null);
      }
      else
      {
        eval ("this.rule.style." + (altname ? altname : name) + " = value");
      }
    }
  }
  
  this.clearRule = function (name, altname)
  {
    if (this.rule == null)
    {
      this.rule = this.ssheet.findRule (this.id);
    }
    
    if (this.rule != null)
    {
      if (this.rule.style.removeProperty)
      {
        this.rule.style.removeProperty (name);
      }
      else
      {
        eval ("this.rule.style." + (altname ? altname : name) + " = ''");
      }
    }
  }
}

function applyStyle (style, stxt)
{
  if (stxt != null) if (stxt.length > 0)
  {
    var sset  = stxt.split (";");
    var idx   = -1;
    var pos   = 0;
    
    while (++idx < sset.length)
    {
      pos = sset[idx].indexOf ('=');
      
      if (pos > 0)
      {
        style.setRule (sset[idx].substr (0, pos),
                       sset[idx].substr (pos + 1));
      }
    }
  }
}

function FormatLeading (val, width)
{
  var str = "";

  while (width-- > 0)
  {
    str = (val % 10) + str;
    val = Math.floor (val / 10);
  }

  return (str);
}

function FormatNumberBy3 (val,
                          dp,
                          sep,
                          def)
{
  if (val)
  {
    if (val.match (AL_IS_Number))
    {
      if (arguments.length < 3) sep = ",";
      if (arguments.length < 2) dp  = ".";
      
      val = val.toString ();

      if (val.indexOf (',') < 0)
      {
        var pos   = val.indexOf (dp);
        var ival  = (pos >= 0) ? val.substr (0, pos)  : val;
        var dval  = (pos >= 0) ? val.substr (pos + 1) : null;
        
        pos = ival.length;
        
        while (pos > 3)
        {
          pos -= 3;
          ival = ival.substr (0, pos) + sep + ival.substr (pos);
        }
        
        if (dval != null)
        {
          ival += dp + dval;
        }
        
        val = ival;
      }
    }
  }
  else
  {
    val = (def || (def == null)) ? def : "0";
  }

  return (val);
}

function html2text (txt)
{
  if (txt)
  {
    if (txt.indexOf ("<br>") >= 0) txt = txt.replace (/<br>/g, "\r\n");
    if (txt.indexOf ("<BR>") >= 0) txt = txt.replace (/<BR>/g, "\r\n");
    
    if (txt.indexOf ('<') >= 0)
    {
      var ps  = 0;
      var pe  = 0;

      do
      {
        ps = txt.indexOf ('<');
        
        if (ps >= 0)
        {
          pe = txt.indexOf ('>', ps);
          
          if (pe > ps)
          {
            txt = txt.substr (0, ps) + txt.substr (pe + 1);
          }
          else
          {
            ps = -1;
          }
        }
        
      } while (ps >= 0);
    }
    
    if (txt.indexOf ("&") >= 0)
    {
      if (txt.indexOf ("&nbsp;") >= 0) txt = txt.replace (/&nbsp;/g, " ");
      if (txt.indexOf ("&lt;")   >= 0) txt = txt.replace (/&lt;/g,   "<");
      if (txt.indexOf ("&gt;")   >= 0) txt = txt.replace (/&gt;/g,   ">");
      if (txt.indexOf ("&amp;")  >= 0) txt = txt.replace (/&amp;/g,  "&");
    }
  }
  
  return (compressLR (txt));
}

function text2html (txt, space, compress)
{
  if (txt)
  {
    if (txt.indexOf ("<html>") == 0)
    {
      txt = alStripHtml (txt);
    }
    else
    {
      if (txt.indexOf ("&")    >= 0) txt = txt.replace (/&/g,    "&amp;");
      if (txt.indexOf ("<")    >= 0) txt = txt.replace (/</g,    "&lt;");
      if (txt.indexOf (">")    >= 0) txt = txt.replace (/>/g,    "&gt;");
      if (txt.indexOf ("\r\n") >= 0) txt = txt.replace (/\r\n/g, "<BR/>");
      if (txt.indexOf ("\n")   >= 0) txt = txt.replace (/\n/g,   "<BR/>");

      if (compress)
      {
        txt = txt.replace (/\s/g, " ");

        if (txt.indexOf ("<BR/> ") >= 0) txt = txt.replace (/\<BR\/\>\s/g, "<BR/>");
        if (txt.indexOf (" <BR/>") >= 0) txt = txt.replace (/\s\<BR\/\>/g, "<BR/>");

        while (txt.indexOf ("<BR/><BR/>") >= 0)
        {
          txt = txt.replace (/\<BR\/\>\<BR\/\>/g, "<BR/>");
        }
      }
    }

    if (space)
    {
      if (txt.indexOf (" ") >= 0)
      {
        txt = txt.replace (/\s/g, "&nbsp;");
      }
    }
  }

  return (txt);
}

function encoder (txt)
{
  if (txt.indexOf ('&') >= 0)  txt = txt.replace (/&/g, "&amp;");
  if (txt.indexOf ('<') >= 0)  txt = txt.replace (/</g, "&lt;");
  if (txt.indexOf ('>') >= 0)  txt = txt.replace (/>/g, "&gt;");
  if (txt.indexOf ('\'') >= 0) txt = txt.replace (/\'/g, "&apos;");
  if (txt.indexOf ('\"') >= 0) txt = txt.replace (/\"/g, "&quot;");
  
  return (txt);
}

function dequote (txt)
{
  if (txt.indexOf ('\'') >= 0) txt = txt.replace (/\'/g, "&apos;");
  if (txt.indexOf ('\"') >= 0) txt = txt.replace (/\"/g, "&quot;");
  
  return (txt);
}

function enquote (txt)
{
  if (txt.indexOf ('\'') >= 0) txt = txt.replace (/\&apos;/g, "'");
  if (txt.indexOf ('\"') >= 0) txt = txt.replace (/\&quot;/g, "\"");
  
  return (txt);
}

function cloneObject (obj)
{
  var clone = null;

	if (obj)
  {
    if (obj instanceof Array)
    {
      var idx   = -1;

      clone = new Array ();

      while (++idx < obj.length)
      {
        clone[idx] = cloneObject (obj[idx]);
      }
    }
    else if (typeof (obj) == 'object')
	  {
	    clone = new Object ();

	    for (var i in obj)
	    {
		    clone[i] = cloneObject (obj[i]);
		  }
    }
  }

	return (clone ? clone : obj);
}

function destroyObject (obj, skip)
{
	if (obj) if (typeof (obj) == 'object')
	{
	  for (var i in obj)
	  {
	    if (skip)
	    {
	      obj[i] == null;
	    }
	    else
	    {
	      if (obj[i]) if (typeof (obj[i]) == 'object') if (!obj[i].inviolable)
	      {
          if (obj[i].destroy)
          {
            obj[i].destroy ();
          }
          else
          {
  		      destroyObject (obj[i]);
          }
          
		      obj[i] = null;
  		  }
  		}
		}
  }
}

var groupCache = {};

function elementsById (id, clear, zap)
{
  var nodes = groupCache[id] ? groupCache[id] : null;
  
  if (clear)
  {
    if (nodes)
    {
      groupCache[id] = null;
      
      if (zap)
      {
        while (nodes.length > 0)
        {
          nodes.pop ();
        }
        
        nodes = null;
      }
    }
  }
  else
  {
    if (!nodes)
    {
      nodes          = [];
      groupCache[id] = nodes;
    }

    var idx = nodes.length;

    while (idx-- > 0)
    {
      if (nodes[idx].id != '')
      {
        nodes.splice (idx, 1);
      }
    }

    while (idx = document.getElementById (id))
    {
      nodes.push (idx); idx.sid = idx.id; idx.id = '';
    }
  }
 
  return (nodes);
}

function alBracketStrip (value, bstart, bend)
{
  if (value)
  {
    var pos = value.indexOf (bstart);
    
    if (pos >= 0)
    {
      value = value.substr (pos + bstart.length);
    }
    
    pos = value.indexOf (bend);
    
    if (pos >= 0)
    {
      value = value.substr (0, pos);
    }
  }
  
  return (value);
}

function alStripHtml (value)
{
       if (value.indexOf ("<body>") >= 0) value = alBracketStrip (value, "<body>", "</body>");
  else if (value.indexOf ("<BODY>") >= 0) value = alBracketStrip (value, "<BODY>", "</BODY>");
  else if (value.indexOf ("<html>") >= 0) value = alBracketStrip (value, "<html>", "</html>");
  else if (value.indexOf ("<HTML>") >= 0) value = alBracketStrip (value, "<HTML>", "</HTML>");
  
  return (value);
}

var al_EAction  = null;

function AL_Email_Href (address,
                        subject,
                        body,
                        cc,
                        bcc)
{
  var href  = "";

  if (subject || body || cc || bcc)
  {
    if (subject) {href += href ? '&' : '?'; href += "subject=" + escape (subject);}
    if (body)    {href += href ? '&' : '?'; href += "body="    + escape (body);}
    if (cc)      {href += href ? '&' : '?'; href += "cc="      + escape (cc);}
    if (bcc)     {href += href ? '&' : '?'; href += "bcc="     + escape (bcc);}
  }

  return ("mailto:" + escape (address) + href);
}

function AL_Email (address,
                   subject,
                   body,
                   cc,
                   bcc)
{
  var href  = AL_Email_Href (address,
                             subject,
                             body,
                             cc,
                             bcc);

  if (AL_Browser.ie)
  {
    if (!al_EAction)
    {
      al_EAction = document.body.appendChild (document.createElement ("A"));

      al_EAction.target  = "f_work";
      al_EAction.onclick = AL_GuiStopPrompt;
    }

    al_EAction.href = href;
    al_EAction.click ();
  }
  else
  {
    if (!al_EAction)
    {
      al_EAction  = document.body.appendChild (document.createElement ("FORM"));

      al_EAction.style.display = "none";
      al_EAction.target        = "f_work";
      al_EAction.method        = "post";
      al_EAction.enctype       = "application/x-www-form-urlencoded"
    }

    al_EAction.action = href;
    al_EAction.submit ();
  }
}

var al_DAction  = null;
var al_DArgs    = null;

function AL_Download (url, args)
{
  if (AL_Browser.ie)
  {
    if (!al_DAction)
    {
      al_DAction = document.body.appendChild (document.createElement ("A"));

      al_DAction.target  = "f_work";
      al_DAction.onclick = AL_GuiStopPrompt;
    }

    al_DAction.href = args ? (url + "?" + args) : url;
    al_DAction.click ();
  }
  else
  {
    if (!al_DAction)
    {
      al_DAction = document.body.appendChild (document.createElement ("FORM"));
      al_DArgs   = al_DAction.appendChild    (document.createElement ("INPUT"));
      
      al_DAction.style.display  = "none";
      
      al_DAction.target  = "f_work";
      al_DAction.method  = "post";
      al_DAction.enctype = "multipart/form-data";
      
      al_DArgs.name = "__args";
      al_DArgs.type = "hidden";
    }
    
    al_DArgs.value    = args ? args : "";
    al_DAction.action = url;
    al_DAction.submit ();
  }
}

function AL_Serialise (obj, stack)
{
  var ret   = null;
  var news  = stack ? false : true;

  if (obj != undefined)
  {
    switch (obj.constructor)
    {
      case Array  :

        var idx   = -1;
        var oidx  = -1;

        if (stack)
        {
          idx = stack.length;

          while ((idx-- > 0) && (oidx < 0))
          {
            if (stack[idx] == obj)
            {
              oidx = idx;
            }
          }
        }

        ret = '[';

        if (oidx < 0)
        {
          if (news)
          {
            stack = new Array ();
          }

          stack.push (obj); idx = -1;

          while (++idx < obj.length)
          {
            if (idx > 0)
            {
              ret += ',';
            }

            ret += AL_Serialise (obj[idx], stack);
          }
        }
        else
        {
          ret += '%' + oidx;
        }

        ret += ']';

        break;

      case String :

        ret = "'" + escape (obj) + "'";
        break;

      case Number :

        ret = '#' + (isFinite (obj) ? obj.toString () : '') + '#';
        break;

      case Date   :

        ret = '$' + obj.toString () + '$';
        break;

      default     :

        if (typeof (obj) == 'object')
        {
          var idx   = -1;
          var oidx  = -1;

          if (stack)
          {
            idx = stack.length;

            while ((idx-- > 0) && (oidx < 0))
            {
              if (stack[idx] == obj)
              {
                oidx = idx;
              }
            }
          }

          ret = '{';

          if (oidx < 0)
          {
            if (news)
            {
              stack = new Array ();
            }

            stack.push (obj);

            var vobj  = new Array ();
            var attr  = null;

            if (obj.canSerialise && obj.serialiser)
            {
              vobj.push ('@' + obj.serialiser);
            }

            for (attr in obj)
            {
              if (typeof (obj[attr]) != "function")
              {
                vobj.push (attr + ':' + AL_Serialise (obj[attr], stack));
              }
            }

            if (vobj.length > 0)
            {
              ret += vobj.join (',');
            }
          }
          else
          {
            ret += '%' + oidx;
          }

          ret += '}';
        }
        else
        {
          ret = '(' + escape (obj.toString ()) + ')';
        }

        break;
    }
  }

  if (news && stack)
  {
    while (stack.length > 0)
    {
      stack.pop ();
    }
  }

  return (ret);
}

function AL_ClonerIndex (idx)
{
  this.index = idx;
}

function AL_Deserialise_Parts (str, ps, stack, sdups)
{
  var ch    = str.charAt (ps);
  var pe    = str.indexOf ((ch == '[') ? ']' : '}', ps);

  if (str.charAt (ps + 1) == '%')
  {
    stack.push (str.substring (ps + 2, pe));
  }
  else
  {
    var obj   = (ch == '[') ? new Array () : new Object ();

    if (pe > (ps + 1))
    {
      var bits  = str.substring (ps + 1, pe).split (",");
      var idx   = -1;

      if (ch == '[')
      {
        while (++idx < bits.length)
        {
          obj[idx] = AL_Deserialise_Part (bits[idx], stack, sdups);
        }
      }
      else
      {
        var apos  = 0;
        var func  = null;

        while (++idx < bits.length)
        {
          if ((idx == 0) && (bits[idx].charAt (0) == '@'))
          {
            func = bits[idx].substr (1);
          }
          else
          {
            apos = bits[idx].indexOf (':'); eval ("obj." + bits[idx].substr (0, apos) + " = AL_Deserialise_Part (bits[idx].substr (apos + 1), stack, sdups)");
          }
        }

        if (func)
        {
          eval ("obj = " + func + "(obj)");
        }
      }
    }

               stack.push (obj);
    if (sdups) sdups.push (obj);
  }

  str = str.substr (0, ps) + '~' + (stack.length - 1) + '~' + str.substr (pe + 1);

  return (str);
}

function AL_Deserialise_Part (str, stack, sdups)
{
  var which = str.charAt (0);
  var obj   = null;

  str = str.substring (1, str.lastIndexOf ((which == '(') ? ')' : which));

  switch (which)
  {
    case '~'  :
    
      if (typeof (stack[str]) == "string")
      {
        obj = new AL_ClonerIndex (stack[str]);
      }
      else
      {
        obj = stack[str];
      }

      break;

    case '\'' : obj = unescape   (str); break;
    case '#'  : obj = new Number (str).valueOf (); break;
    case '$'  : obj = new Date   (str); break;

    case '('  : obj = eval (unescape (str)); break;
  }

  return (obj);
}

function AL_Deserialise_Restore (obj, sdups)
{
	if (obj)
  {
    if (obj instanceof AL_ClonerIndex)
    {
      obj = sdups[sdups.length - obj.index - 1];
    }
    else if (obj instanceof Array)
	  {
      var idx = obj.length;

	    while (idx-- > 0)
	    {
        obj[idx] = AL_Deserialise_Restore (obj[idx], sdups)
		  }
    }
    else if (typeof (obj) == 'object')
	  {
	    for (var i in obj)
	    {
        obj[i] = AL_Deserialise_Restore (obj[i], sdups)
		  }
    }
  }

  return (obj);
}

function AL_Deserialise (str)
{
  var stack = null;
  var sdups = null;
  var obj   = null;
  var idx   = -1;

  if (str.length > 0)
  {
    var po  = 0;
    var pa  = 0;

    if ((str.indexOf ('{') >= 0) ||
        (str.indexOf ('[') >= 0))
    {
                                 stack = new Array ();
      if (str.indexOf ('%') > 0) sdups = new Array ();
    }

    do
    {
      po = str.lastIndexOf ('{');
      pa = str.lastIndexOf ('[');

      if ((po >= 0) || (pa >= 0))
      {
        str = AL_Deserialise_Parts (str, (pa > po) ? pa : po, stack, sdups);
      }

    } while ((po >= 0) || (pa >= 0));

    obj = AL_Deserialise_Part (str, stack);
  }

  if (sdups)
  {
    AL_Deserialise_Restore (obj, sdups);
  }

  if (stack) while (stack.length > 0) stack.pop ();
  if (sdups) while (sdups.length > 0) sdups.pop ();

  stack = null;
  sdups = null;

  return (obj);
}

