
/*
 *
 * File:      $RCSfile: layout.js,v $
 * Version:   $Revision: 2.0 $
 * Revised:   $Date:  $
 *            $Author: mbm $
 *
 * Created:   2009-06-01
 * Author:    sectra:mbm
 * Project:   Web
 *
 *
 * Description
 *   Non-obtrusive page behaviors for Sectra web sites.
 *
 * Compatibility:
 *   IE      >= 5.5
 *   Mozilla >= 5.0
 *   Opera   >= 7.0
 *   Firefox >= 1.0
 *   Safari  >= 1.0
 *   Gecko   >= 1.0
 *
 * Dependencies:
 *   - jQuery
 *   - si_iecss
 *   - si_dommenu
 *
 * General comments:
 *   Based on previously used pg_layout.js. There are still tons of 'oldish'
 *   code that can can be further optimized using jQuery constructs. 
 *
 *   [c1]: When reloading a page in FF, it the scripts are thrown out of 
 *         context before the actual page, making event handlers still 
 *         attached to elements in the page to cause script errors on, for 
 *         example, mouse over. A test is therefore performed in each event 
 *         handler before calling functions in the script. 
 * 
 *         Also, is seems that the default (function call) context "leaves" 
 *         slightly before the scripts are removed from the window object, so 
 *         for testing for presence of a function in the window context to be 
 *         safe the function must be called on the window context as well.
 *
 *   Classes:
 *   - DETECT
 *   - SiTools
 *   - SiHtml
 *   - SiURL
 *   - SiDomHelp
 *   - SiCookies
 *   - SiTargetGroup
 *   - SiFlash
 *   - SiMedia
 *   - SiMailLinks
 *   - SiActiveLinks
 *   - SiSplash
 *   - SiMenu
 *   - SiDocumentPopup
 *   - SiTrack
 *   - SiUnsupported
 *   - SiDebug
 *   - SiLayout
 *
 */

/* FIXA:

class . -> sisplashform

.sifoldinglist 

*/


/*===========================================================================
 *
 * Configuration
 *
 */

SIL_CONFIG = {

  TARGET_GROUPS: {
    COOKIE_NAME:             'si_tgtgroup',
    DEFAULT_NAME:            'deptmgr'
  },

  ANALYTICS: {
    // Account ID, override for sub-sites:
    CODE:                    'UA-2624518-1',
    DOMAIN:                  'none'
  },

  ACTIVE_LINKS: {
    SELECTOR: {
      // Install active links on everything below...
      ROOT:                  '#message, #highlights, #minisearchform',
      // ...matching:
      ELEM:                  'A, INPUT, MAP'
    },
    // CSS and image properties:
    CURRENT_PAGE_CLASS:      'sipcurrentpage',
    HOVER_CLASS:             'sipbuttonhover',
    IMAGE: {
      DEFAULT_SUBSTR:        'default',
      ACTIVE_SUBSTR:         'active',
      HOVER_SUBSTR:          'hover'
    }
  },

  FOLDING_LIST: {
    // Selector for things to fold:
    SELECTOR:                '.sifoldinglist li'
  },

  EXPAND_CONTAINER: {
    // Selector for things to expand/collapse:
    SELECTOR:                '.expandcontainer'
  },

  DOCUMENTPOPUP: {
    // Selector for links that should show up in a separate window:
    SELECTOR:                'A[href*=.pdf], A[href*=.tif], A[href*=.jpg], A[href*=.gif]',
    // CSS for indication of those links:
    CLASS:                   'siplinkdecorationpopup'
  },

  FLASH: {
    REQUIRE_VERSION:         8,
    PLAYER: {
      ID:                    'swfplayer',
      // CSS for flash controls:
      CLASSNAME:             'swf'
    },
    BLOCKER: {
      // CSS for flash blocker handling:
      CLASSNAME:             'flashblock',
      REPLACEMENT_CLASSNAME: 'noflash'
    }
  },

  MEDIA: {
    // Selector for media contaniers:
    SELECTOR:                'DIV.mediacontainer',
    PLAYER: {
      ID:                    'mediaCtrl',
      UI: {
        // Media contanier widgets:
        CLOSEBTN:            '/common/styles2/images/_fw_mediacontanier_close.gif',
        SETTINGSBTN:         '/common/styles2/images/_fw_mediacontanier_settings.gif',
        BGCOLOR:             '#2b2b2b'
      }
    },
    WMV: {
      PLAYER: {
        CLASSNAME:           'wmv',
        STDBY_MSG:           'Loading Windows Media Player components...'
      }
    },
    FLV: {
      PLAYER: {
        CLASSNAME:           'flv swf',
        URL:                 '/medical/swf/flvplayer/main.swf'
      }
    }
  },

  SPLASH: {
    // URL pattern for bringing up the splash window on page call:
    LOCATION_PATTERN:        /.*sipsplash=(.*)/,
    // Link selector for bringing up the splash window on link click:
    LINK_SELECTOR:           'A.sipinlineform',
    // Form button selector for commiting splash window:
    DONEBUTTON_SELECTOR:     'INPUT:submit[class*=done]',
    // Default splash window form handler:
    URL: {
      PREFIX_PATTERN:        /\?/,
      PREFIX:                '/common/php2/submit.php?form='
    },
    // Splash window UI CSS:
    UI: {
      OUTSIDE_ID:            'sipsplashbg',
      CANVAS_CLASS:          'sipsplashcanvas',
      DECORATION: {
        FRAME_BASE_CLASS:    'sipsplashdecoration',
        FRAME_INDEX_CLASS:   'sipsplashdecorationr',
        CONTAINER_CLASS:     'sipsplashcontainer'
      }
    }
  },

  MINISEARCH: {
    // Inline search form 'default' text:
    INPUT_DEFAULT_VALUE:     'Find at sectra.com',
    // Inline search form 'default' style:
    INPUT_DEFAULT_CLASS:     'sipemptyinput',
    // Inline search form selector:
    SELECTOR:                '#findwords'
  },

  KBD_FOCUS: {
    // First content element in a page, skipping headers, menus and other fix stuff:
    PAGE_SELECTOR:           '#message H1',
    // First form in a form page:
    FORM_SELECTOR:           'FORM[id!=minisearchform] INPUT:text, FORM[id!=minisearchform] SELECT, FORM[id!=minisearchform] TEXTAREA'
  },

  UNSUPPORTED_FIXES: {
    // Finding IE CSS object:
    IESTYLES_ID:             'si_iecss',
    // Finding PNG animals:
    PNG_SELECTOR:            'IMG[src*=.png]'
  },

  // Detecting test sever:
  TEST_URL_PATTERN:          /(http:\/\/tarrekaise|http:\/\/tjidtjak|http:\/\/localhost|http:\/\/web-devel|http:\/\/edit)/
}


// #PRAGMA COMPACT SKIP START

// Configuration of the debug menu:
SIP_DEBUG = {
  ENABLE:       true,
  DREAMWEAVER:  ['C:\\progra~1\\Adobe\\Adobe Dreamweaver CS3\\Dreamweaver.exe', 'C:\\progra~1\\Macromedia\\Dreamweaver 8\\Dreamweaver.exe'],
  CODEEDITOR:   ['C:\\VStudio\\Common\\MSDev98\\Bin\\MSDEV.EXE', 'C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\IDE\\devenv.exe', 'C:\\WINDOWS\\NOTEPAD.EXE', 'C:\\WINNT\\NOTEPAD.EXE'],
  EXPLORE:      ['explorer.exe'],
  SITE_ROOT:    'W:\\Sites\\www.sectra.se\\Version_6\\root'
}

// #PRAGMA COMPACT SKIP END



/*===========================================================================
 *
 * Browser detection 
 *   Note: prefer capability test to browser detection!
 *
 */

DETECT = {};
DETECT.is_opera     = (navigator.userAgent.indexOf('Opera')!=-1)?true:false;
DETECT.is_chrome    = (navigator.userAgent.indexOf('Chrome')!=-1)?true:false;
DETECT.is_safari    = ((navigator.userAgent.indexOf('Safari')!=-1)?true:false) && !DETECT.is_chrome;
DETECT.is_webkit    = (navigator.userAgent.indexOf('KHTML')!=-1)?true:false;
DETECT.is_ie        = ((navigator.appName=='Microsoft Internet Explorer')?true:false) && !DETECT.is_opera;
DETECT.is_gecko     = (navigator.product=='Gecko') && !DETECT.is_safari;
DETECT.versionStr   = navigator.userAgent.replace(/.*(MSIE|Opera|Firefox|Netscape|Safari|Mozilla)[^\d\.]+([\d\.]*).*/i, '$2');
DETECT.majorVersion = parseFloat(DETECT.versionStr.replace(/(\d*).*/, '$1'));
DETECT.version      = parseFloat(DETECT.versionStr.replace(/(\d*)\.?(\d*)/, '$1.$2'));
DETECT.is_ie6       = DETECT.is_ie && DETECT.majorVersion >= 6;
DETECT.is_ieLt6     = DETECT.is_ie && !DETECT.is_ie6;
DETECT.is_ie7       = DETECT.is_ie && DETECT.majorVersion >= 7;
DETECT.is_ieLt7     = DETECT.is_ie && !DETECT.is_ie7;
DETECT.is_ie8       = DETECT.is_ie && DETECT.majorVersion >= 8;
DETECT.is_ieLt8     = DETECT.is_ie && !DETECT.is_ie8;

if(DETECT.is_gecko)
{
  if(navigator.userAgent.indexOf('Netscape')==-1)
  {
    DETECT.is_ns   = false;
    DETECT.is_moz  = true;
  }
  else
  {
    DETECT.is_ns   = ((navigator.appName=='Netscape')?true:false) && !DETECT.is_opera  && !DETECT.is_safari;
    DETECT.is_moz  = false;
  }
}



/*===========================================================================
 *
 * Class script
 *
 */

(function()
{
  var isFn = function(fn) {return(typeof fn == 'function');};
  Class = function(){};
  Class.create = function(template)
  {
    var k = function(magic){
      // call construct only if there's no magic cookie
      if (magic != isFn && isFn(this.construct))
        this.construct.apply(this, arguments);
    };
    k.prototype = new this(isFn); // use our private method as magic cookie
    for (key in template)
      (function(fn, sfn){ // create a closure
         k.prototype[key] = !isFn(fn) || !isFn(sfn) ?
           fn
         : // add _super method
          function()
          {
            this._super = sfn;
            return(fn.apply(this, arguments));
          };
       })(template[key], k.prototype[key]);
    k.prototype.constructor = k;
    k.extend = this.extend || this.create;
    k.prototype.toString = function(){return(this.ToString.apply(this, arguments));};
    return(k);
  };
})();


/*===========================================================================
 *
 * Static class SiTools
 *   Utility functions
 *
 */

SiTools = {

  /*
   * mkId()
   *   Converts an arbitrary string to something usabale as an ID
   *
   * In:
   *   value: string to convert
   *
   * Returns:
   *   Propposed ID
   */

  mkId: function(value)
  {
    return(value.replace(/[^a-z0-9_]+/ig, ''));
  },


  /*
   * mkArray()
   *   Wraps the given value in an array, if not already an array.
   *
   * In:
   *   value: value to make sure it is an array
   *
   * Returns:
   *   Array containing the given value, or the given array
   */

  mkArray: function(value)
  {
    if(value!=null && value.sort==null)
    {
      var arr = new Array();
      arr.push(value);
      return(arr);
    }
    else
      return(value);
  },


  /*
   * getLength()
   *   Gets the "length" of the given "thing", or 0 if the "thing" does not have a length. 
   *
   * In:
   *   thing: Object that might have a length
   *
   * Returns:
   *   Length of the "thing"
   */

  getLength: function(thing)
  {
    if(thing==null || thing.length==null)
      return(0);
    else
      return(thing.length);
  },


  /*
   * narrowIndex()
   *   Returns a value corresopinding the the given index, or if the index is out of bounds, the closet value. 
   *
   * In:
   *   indexable: array to index
   *   index:     index
   *
   * Returns:
   *   A value from the array
   *
   */

  narrowIndex: function(indexable, index)
  {
    if(indexable==null || indexable.length==0)
      return(null);
    else if(index>=indexable.length)
      return(indexable[indexable.length-1]);
    else if(index == null || index < 0)
      return(indexable[0]);
    else
      return(indexable[index]);
  },


  /*
   * contains(), starts(), ends()
   *   Tests if an string or array contains, starts or ends a given value.
   *
   * In:
   *   haystack: object to scan
   *   needle:   value to scan for
   *
   * Returns:
   *   True if needle was found in haystack, at beginning or end, respectively.
   *
   */

  contains: function(haystack, needle)
  {
    if(haystack == null || needle == null)
      return(false);
    else if(haystack.indexOf)
      return(haystack.indexOf(needle) != -1);
    else
    {
      for(var i=0; haystack!=null && i<haystack.length; i++)
      {
        if(haystack[i]==needle)
          return(true);
      }
      return(false);
    }
  },

  starts: function(haystack, needle)
  {
    if(haystack == null || needle == null)
      return(false);
    else if(haystack.indexOf)
      return(haystack.substr(0, needle.length) == needle);
    else
      return(haystack[0] == needle);
  },

  ends: function(haystack, needle)
  {
    if(haystack == null || needle == null)
      return(false);
    else if(haystack.indexOf)
      return(haystack.substr(haystack.length - needle.length) == needle);
    else
      return(haystack[haystack.length-1] == needle);
  }

}



/*===========================================================================
 *
 * class SiHtml
 *   Simple HTML code generation
 *
 */

SiHtml = Class.create({

  /*
   * construct()
   *   Constructs ad initializes an SiHtml object. If given a tagName; the object corressponds to an HTML tag, if not; the object corressponds to a HTML document snippet.
   *
   * In:
   *   tagName:    (optional) tag name
   *   attributes: (optional) attributes associative array
   *
   * Returns:
   *   n/a
   */

  construct: function(tagName, attributes)
  {
    this.tagName = tagName;
    this.attributes = new Array();
    this.childNodes = new Array();
    this.addAttributes(attributes);
  },


  /*
   * addAttributes()
   *   Add attribuets given in an associative array
   *
   * In:
   *   Attributes structure
   *
   * Returns:
   *   n/a
   */

  addAttributes: function(attributes)
  {
    for(var name in attributes)
      this.addAttribute(name == 'className' ? 'class' : name, attributes[name]);
  },


  /*
   * addAttribute()
   *   Add a single attribute/value
   *
   * In:
   *   name:         (optional) name of attribute
   *   value:        (optional) value of attribute
   *   defaultValue: (optional) valuie to use if value was empty
   *
   * Returns:
   *   n/a
   */

  addAttribute: function(name, value, defaultValue)
  {
    if(!value && defaultValue)
      value = defaultValue;
    if(value && value.replace)
      value = value.replace(/"/g, '&quot;');
    if(!name)
      name = value;
    if(value)
      this.attributes.push(name + '="' + value + '"');
  },


  /*
   * addChild()
   *   Add a child node
   *
   * In:
   *   value: child nod to add, string or SiHtml object
   *
   * Returns:
   *   n/a
   */

  addChild: function(value)
  {
    this.childNodes.push(value);
  },


  /*
   * ToString()
   *   Converts the objeft to a (HTML) string
   *
   * Returns:
   *   HTML code
   */

  ToString: function()
  {
    var html = '';
    if(this.tagName)
    {
      html += '<' + this.tagName;
      if(this.attributes.length > 0)   
        html += ' \t' + this.attributes.join('\n\t');
    }
    if(this.childNodes.length > 0)
    {
      if(this.tagName)
        html += '>\n'
      html += this.childNodes.join('');
      if(this.tagName)
        html += '</' + this.tagName + '>\n';
    }
    else if(this.tagName)
      html += ' />\n';
    return(html);
  }
  
});



/*===========================================================================
 *
 * static class SiURL
 *   Helper functions for handling URLs and paths
 *
 */

SiURL = {
  
  /*
   * strip()
   *   Strips query arguments, hash bookmarks and default document names from a path
   *
   * In:
   *   path: URL or path to strip
   *
   * Returns:
   *   URL or path stripped
   */

  strip: function(path)
  {
    return(path!=null ? path.replace(/[#|?].*$/, '').replace(/index.\w+/i, '') : null);
  },


  /*
   * mkLocal()
   *   Returns the papth of an URL
   *
   * In:
   *   url: URL to convert
   *
   * Returns:
   *   Path (from the server document root)
   */

  mkLocal: function(url)
  {
    return(url!=null ? url.replace(/^[^:]*:\/\/[^\/]*/, '') : null);
  },


  /*
   * getCurrentPath()
   *   Returns the path of the current document.
   *
   * Returns:
   *   Path of the current document
   */

  getCurrentPath: function()
  {
    return(SiURL.mkLocal(SiURL.strip(window.location.href)));
  },


  /*
   * isTestServer()
   *   Tests if an URL is located on a testing server or not
   *
   * In:
   *   url: (optional) URL to test, default is the current document's URL
   *
   * Returns:
   *   true:  testing server
   *   false: public server
   */

  isTestServer: function(url)
  {
return(false);  
    url = url!=null ? url : window.location.href;
    return(url.match(SIL_CONFIG.TEST_URL_PATTERN)!=null);
  },


  /*
   * isCurrent()
   *   Tests if an URL mathces the current document
   *
   * In:
   *   link: URL to test
   *
   * Returns:
   *   true:  The given URL corresponds to the current document
   *   false: The given URL does not correspond to the current document
   */

  isCurrent: function(link)
  {
    return(SiURL.mkLocal(link) == SiURL.getCurrentPath());
  },
  
//APA  
isDynamic: function(url)
{
  return(url.indexOf('.php')!=-1 || url.indexOf('/cgi-bin/')!=-1);
}
  

}



/*===========================================================================
 *
 * static class SiDomHelp
 *   Helper functions for the browser DOM
 *
 */

SiDomHelp = {

  /*
   * mkElementId()
   *   Makes sure an element has an ID, and returns that ID
   *
   * In:
   *   element: element
   *
   * Returns:
   *   element ID
   * 
   * Postcondition:
   *   If not previously assigned an ID, the element now has one
   */

  mkElementId: function(element)
  {
    if(!element.id)
    {
      if(element.parentNode!=null)
      {
        var index;
        for(index=0; index<element.parentNode.childNodes.length; index++)
        {
          if(element.parentNode.childNodes[index]==element)
            break;
        }
        element.id=SiDomHelp.mkElementId(element.parentNode) + '_' + element.tagName + index;
      }
      else
        element.id='__root__';
    }
    return(element.id);
  },


  /*
   * isClass()
   *   Tests for a class
   *
   * In:
   *   element:   element to test
   *   className: class name to test for
   *
   * Returns:
   *   true if the element has the class
   */

  isClass: function(element, className)
  {
    return(element!=null && element.className!=null && element.className.indexOf(className)!=-1);
  },


  /*
   * getOuterHTML()
   *   Returns the outer HTML of an element, or at least a fair guess of what it might be if the DOM does not support the .outerHTML property
   *
   * In:
   *   element: DOM element
   *
   * Returns:
   *   outerHTML, or a guess, of the given element.
   */

  getOuterHTML: function(element)
  {
    if(element.outerHTML != null)
      return(element.outerHTML);
    else
    {
      var html = '<' + element.tagName;
      if(element.className)
        html += ' class="' + element.className + '"';
      html += '>' + element.innerHTML + '</' + element.tagName + '>';
      return(html);
    }
  },
  
  
  /*
   * topWindow()
   *   Returns the topmost window (frame) that is loaded from the current site; 
   *   there may still be encapsulating windows from other sites.
   *
   * In:
   *   win: (optional) current window
   *
   * Returns:
   *   The topmost window (frame) that is loaded from the same site as 'win'.
   */

  topWindow: function(win)
  {
    var top = win != null ? win : window;
    try
    {
      /* Traverse up in the window hierarchy; the access of 
       * top.parent.location.href throws an exception if top.parent is loaded 
       * from another site
       */
      while(top.parent != top && top.parent.location.href != null)
        top = top.parent;
    }
    catch(e){}
    return(top);
  },



  /*
   * _getAbsolutePosition()
   *   (Internal)
   *   Calculates the absolute position if an element
   */

  _getAbsolutePosition: function(element)
  {
    var offset={x: 0, y: 0};

    while(element!=null && element.tagName!=null && element.style!=null)
    {
      if((element.style!=null) && (element.style.position=='absolute'))
      {
        // In NS6, this might be '0pt' although set to '0px'!
        offset.x+=1*element.style.left.replace(/\w+$/, '');
        offset.y+=1*element.style.top.replace(/\w+$/, '');
        
        if(element.parentNode!=null)
          element=element.parentNode;
        else
          element=element.parentElement;
      }
      else
      {
        offset.x+=element.offsetLeft;
        offset.y+=element.offsetTop;

        if(element.offsetParent!=null)
          element=element.offsetParent;
        else if(element.parentNode!=null)
          element=element.parentNode;
        else
          element=element.parentElement;
      }
    }
    return(offset);
  },


  /*
   * getAbsoluteLeft()
   *   Returns the absolute position of a relatively or absolutely positioned object.
   *
   * In:
   *   element: DOM object
   *
   * Returns:
   *   the left of the object (px), or 0 (zero) if not available
   */

  getAbsoluteLeft: function(element)
  {
    return(SiDomHelp._getAbsolutePosition(element).x);
  },


  /*
   * getAbsoluteTop()
   *   Returns the absolute position of a relatively or absolutely positioned object.
   *
   * In:
   *   element: DOM object
   *
   * Returns:
   *   the top of the object (px), or 0 (zero) if not available
   */

  getAbsoluteTop: function(element)
  {
    return(SiDomHelp._getAbsolutePosition(element).y);
  },


  /*
   * getAbsolutePoint()
   *   Returns the absolute position of a relatively or absolutely positioned object.
   *
   * In:
   *   element: DOM object
   *
   * Returns:
   *   the position of the object (px/px), or 0/0 (zero) if not available
   *     - x: 
   *     - y: 
   */

  getAbsolutePoint: function(element)
  {
    return(SiDomHelp._getAbsolutePosition(element));
  },


  /*
   * _getAbsoluteDimension()
   *   (Internal)
   *   Calculates the absolute dimension if an element
   */

  _getAbsoluteDimension: function(element)
  {
    var offset={width: 0, height: 0};

    if(element!=null && element.style!=null)
    {
      if(false && element.tagName=='DIV') 
        offset={width:  1*element.style.width.replace(/\w+$/, ''), 
                height: 1*element.style.height.replace(/\w+$/, '')};
      else if(element.tagName!='TBODY')
        offset={width:  element.offsetWidth, 
                height: element.offsetHeight};
    }

    return(offset);
  },


  /*
   * getAbsoluteWidth()
   *   Returns the absolute dimension of a relatively or absolutely positioned object.
   *
   * In:
   *   element: DOM object
   *
   * Returns:
   *   the width of the object (px), or 0 (zero) if not available
   */

  getAbsoluteWidth: function(element)
  {
    return(SiDomHelp._getAbsoluteDimension(element).width);
  },


  /*
   * getAbsoluteHeight()
   *   Returns the absolute dimension of a relatively or absolutely positioned object.
   *
   * In:
   *   element: DOM object
   *
   * Returns:
   *   the height of the object (px), or 0 (zero) if not available
   */

  getAbsoluteHeight: function(element)
  {
    return(SiDomHelp._getAbsoluteDimension(element).height);
  },


  /*
   * getAbsoluteSize()
   *   Returns the absolute dimension of a relatively or absolutely positioned object.
   *
   * In:
   *   element: DOM object
   *
   * Returns:
   *   the size of the object (px/px), or 0/0 (zero) if not available
   *     - width: 
   *     - height: 
   */

  getAbsoluteSize: function(element)
  {
    return(SiDomHelp._getAbsoluteDimension(element));
  },


//APA:
  getStyle: function(element, propertyName)
  {
    var value;
    if(element.currentStyle!=null)
      value = element.currentStyle[propertyName];
    else
      value = document.defaultView.getComputedStyle(element,'').getPropertyValue(propertyName.replace(/([A-Z])/g, '-$1').toLowerCase());
    if(value)
      value = value.replace(/(\d+)\w+$/, '$1');
    else
      value = null;
    if(!isNaN(value))
      return(parseInt(value));
    else
      return(value);
  },



  /*
   * getDocumentScroller()
   *   Returns the document 'scrolling' element
   *
   * Returns:
   *   DOM element performing scrolling of the document
   */

  getDocumentScroller: function()
  {
    return(window.document.body.parentNode); // i.e. window.document.html
  },


  /*
   * scrollIntoView()
   *   Makes a node visible within the document viewport, scrolling the document if needed
   *
   * In:
   *   node:      Node to scroll
   *   scroller: (optional) Scrolling element, default getDocumentScroller()
   *
   * Returns:
   *   n/a
   */

  scrollIntoView: function(node, scroller)
  {
    scroller   = scroller != null ? scroller : SiDomHelp.getDocumentScroller();
    var top    = SiDomHelp.getAbsoluteTop(node);
    var height = SiDomHelp.getAbsoluteHeight(node);
    if(top < scroller.scrollTop || height >= scroller.clientHeight)
      scroller.scrollTop = top;
    else if(top + height > scroller.clientHeight + scroller.scrollTop)
      scroller.scrollTop = top + height - scroller.clientHeight;
  }

}



/*===========================================================================
 *
 * static class Cookies
 *   Helper functions for handling cookies
 *
 */

SiCookies = {
  
  /*
   * set()
   *   Set a cookie
   *
   * In:
   *   name:       name of cookie
   *   value:      value of cookie, or null to remove the cookie
   *   persistent: true to create a persistent cookie
   *
   * Returns:
   *   n/a
   *
   * Postcondition:
   *   Cookie created or updated
   */
  
  set: function(name, value, persistent)
  {
    name=SiTools.mkId(name);
    if(value!==null)
    {
      var expires;
      if(persistent)
        expires='expires=' + (new Date((new Date()).getTime() + 86400 * 30 * 1000)).toGMTString() + '; ';
      else
        expires='';
      document.cookie = name + '=' + escape(value) + '; ' + expires + 'path=/';
    }
    else
      SiCookies.remove(name);
  },


  /*
   * remove()
   *   Remove a cookie
   *
   * In:
   *   name:             name of cookie to remove
   *   _allowDirtyName: (internal)
   *
   * Returns:
   *   n/a
   *
   * Postcondition:
   *   Cookie removed, if previously present
   */

  remove: function(name, _allowDirtyName)
  {
    if(!_allowDirtyName)
      name=SiTools.mkId(name);
    document.cookie = name + '=; expires=Mon, 1 Jan 1990 00:00:00 UTC; path=/';
  },


  /*
   * removeAll()
   *   Remove all cookies (accessible in the domain)
   *
   * Returns:
   *   n/a
   *
   * Postcondition:
   *   All cookies accessible in the domain removed
   */

  removeAll: function()
  {
    var cookies = document.cookie.split('; ');
    var count = 0;
    for (var i=0; i < cookies.length; i++)
    {
      if(cookies[i])
      {
        var crumb = cookies[i].split('=');
        SiCookies.remove(crumb[0], true);
        count++;
      }
    }
    return(count);
  },


  /*
   * get()
   *   Get a cookie
   *
   * In:
   *   name: name of cookie
   *
   * Returns:
   *   Value of the cookie if present, null otherwise
   */

  get: function(name)
  {
    name=SiTools.mkId(name);
    var cookie = document.cookie.split('; ');
    for (var i=0; i < cookie.length; i++)
    {
      var crumb = cookie[i].split('=');
      if (name == crumb[0])
      {
        var rc = unescape(crumb[1]);
        if(rc=='null')
          rc=null;
        return(rc);
      }
    }
    return(null);
  }
}



/*===========================================================================
 *
 * static class Target groups
 *   Helper functions for handling target groups
 *
 */

SiTargetGroup = {

  /*
   * get()
   *   Get the current target group name
   *
   * Returns:
   *   Name of the current target group, or null if not set
   */

  get: function()
  {
    return(SiCookies.get(SIL_CONFIG.TARGET_GROUPS.COOKIE_NAME));
  },


  /*
   * set()
   *   Set the name of the current target group
   *
   * In:
   *   value: new target group name, or null to reset 
   *
   * Returns:
   *   n/a
   *
   * Postcondition:
   *   Target group cookie created, updated or removed.
   */

  set: function(value)
  {
    return(SiCookies.set(SIL_CONFIG.TARGET_GROUPS.COOKIE_NAME, value));
  }
  
}  



/*===========================================================================
 *
 * static class Flash content
 *   Flash Player instantiation
 *
 */

SiFlash = {

  /*
   * getVersion()
   *   Returns the version of the installed Flash player plugin, or tests the version against a given value. 
   *
   * In:
   *   requireMajor: (optional) Version to test against.
   *
   * Returns:
   *   w/o requireMajor: the Flash Player version
   *   w requireMajor:   null if the Flash Player version was lower than required
   */

  getVersion: function(requireMajor)
  {
    var swfVersion = null;

    if(requireMajor!=null)
      requireMajor = '.' + requireMajor;
    else
      requireMajor = '';

    if(navigator.plugins && navigator.mimeTypes.length)
    {
      var plug = navigator.plugins['Shockwave Flash'];
      if(plug && plug.description)
        swfVersion = plug.description.replace(/([a-zA-Z]|\s)+/, '').replace(/(\s+r|\s+b[0-9]+)/, '.').split('.');
      if(swfVersion && requireMajor!='' && requireMajor>swfVersion[0])
        swfVersion = null;
    }
    else
    { 
      var axo = null;
      try
      {
        axo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash' + requireMajor);
      }
      catch(e){}
      if(axo!=null)
      {
        try
        {
          swfVersion = [6,0,21];
          axo.AllowScriptAccess = 'always';
          swfVersion = null;
          swfVersion = axo.GetVariable('$version').split(' ')[1].split(',');
        }
        catch(e){}
      }
    }
    return(swfVersion);
  },


  /*
   * createHtml()
   *   Creates Flash Player instantiation HTML code
   *
   * In:
   *   (see corresponding arguments in SiFlash.create)
   *
   * Returns:
   *   HTML code
   */

  createHtml: function(URL, 
                       variables, 
                       styles, 
                       baseURL, 
                       wmode,
                       bgcolor,
                       width, 
                       height, 
                       ctrlId,
                       ctrlClass)
  {
    if(SiFlash.getVersion(SIL_CONFIG.FLASH.REQUIRE_VERSION)==null)
      return(false);

    // Set default values:
    if(!bgcolor)
      bgcolor = '#ffffff';
    if(wmode===false)
      wmode = null;
    else if(!wmode)
      wmode = 'opaque';
    if(!ctrlId)
      ctrlId = SIL_CONFIG.FLASH.PLAYER.ID;
    if(!ctrlClass)
      ctrlClass = SIL_CONFIG.FLASH.PLAYER.CLASS;

    // Convert args to arrays:
    URL       = SiTools.mkArray(URL);
    variables = SiTools.mkArray(variables);
    styles    = SiTools.mkArray(styles);
    baseURL   = SiTools.mkArray(baseURL);
    wmode     = SiTools.mkArray(wmode);
    bgcolor   = SiTools.mkArray(bgcolor);
    width     = SiTools.mkArray(width);
    height    = SiTools.mkArray(height);
    ctrlId    = SiTools.mkArray(ctrlId);

    // Generated HTML control code:
    var html  = new SiHtml();

    // Nrof controls to create:
    var count = Math.max(Math.max(SiTools.getLength(ctrlId), SiTools.getLength(URL)), Math.max(SiTools.getLength(variables), SiTools.getLength(styles)));

    // For each control to create:
    for(var i=0; i<count; i++)
    {
      var nURL       = SiTools.narrowIndex(URL,       i);
      var nStyles    = SiTools.narrowIndex(styles,    i);
      var nBaseURL   = SiTools.narrowIndex(baseURL,   i);
      var nWmode     = SiTools.narrowIndex(wmode,     i);
      var nBgcolor   = SiTools.narrowIndex(bgcolor,   i);
      var nWidth     = SiTools.narrowIndex(width,     i);
      var nHeight    = SiTools.narrowIndex(height,    i);
      var nCtrlId    = SiTools.narrowIndex(ctrlId,    i);
      var nCtrlClass = SiTools.narrowIndex(ctrlClass, i);


      // Get the flashvars string, it can be passed as an URL encoded string or 
      // as an associative array:
      var varSet    = SiTools.narrowIndex(variables, i);
      var varString = '';
      if(varSet!=null && varSet.indexOf==null)
      {
        for(var name in varSet)
        {
          if(varString!='')
            varString += '&';
          varString += name + '=' +   varSet[name];
        }
      }
      else
        varString = varSet;

      // Get hold of the base URL:    
      if(nBaseURL=='@')
        nBaseURL = nURL.replace(/[^\/]*$/, '');
      else if(!nBaseURL)
        nBaseURL = window.location.href.replace(/[^\/]*$/, '');

      var obj = new SiHtml('object', {className: nCtrlClass,
                                      type:      'application/x-shockwave-flash',
                                      style:     nStyles,
                                      width:     nWidth,
                                      height:    nHeight,
                                      id:        nCtrlId});
      if(!DETECT.is_ie)
        obj.addAttribute('data', nURL);
        
      if(wmode)
        obj.addChild(new SiHtml('param', {name: 'wmode', value: nWmode}));
        
      obj.addChild(new SiHtml('param', {name: 'movie',     value: nURL}));
      obj.addChild(new SiHtml('param', {name: 'bgcolor',   value: nBgcolor}));
      obj.addChild(new SiHtml('param', {name: 'FlashVars', value: varString || ''}));
      obj.addChild(new SiHtml('param', {name: 'base',      value: nBaseURL  || ''}));
      obj.addChild(new SiHtml('param', {name: 'quality',   value: 'high'}));
      obj.addChild(new SiHtml('param', {name: 'autoStart', value: '-1'}));

      var embed = new SiHtml('embed', {className:   nCtrlClass,
                                       quality:     'high',
                                       type:        'application/x-shockwave-flash',
                                       bgcolor:     nBgcolor,
                                       src:         nURL,
                                       style:       nStyles,
                                       width:       nWidth,
                                       height:      nHeight,
                                       id:          nCtrlId,
                                       name:        nCtrlId,
                                       flashvars:   varString || '',
                                       base:        baseURL || '',
                                       pluginspage: 'http://www.macromedia.com/go/getflashplayer'});
      if(wmode)
        embed.addAttribute('wmode', nWmode);

      obj.addChild(embed);

      html.addChild(obj);
    }
    return(html.toString());
  },


  /*
   * SiFlash.testBlocker()
   *   Tests the given container, previously populated with flash content via 
   *   SiFlash.create(), for the Flash Blocker pattern, that is, absence of 
   *   OBJECT tags. If the Flash Blocker has taken control of the container, 
   *   reinstall the default (static) content saved by SiFlash.create(). 
   *
   * In:
   *   containerID: ID of the container presumaby containing Flash instantiation code
   *
   * Returns:
   *   n/a
   * 
   * Postcondition:
   *   If the Flash Blocker was found; the original HTML is restored
   */

  testBlocker: function(containerID)
  {
    var container = window.document.getElementById(containerID);
    if(container==null)
      return;
    if(container.getElementsByTagName('OBJECT').length!=0)
      return;
    if(container.si_blockHtml)
    {
      var innermost;
      for(innermost = container; innermost.firstChild != null; innermost = innermost.firstChild);
      innermost.style.marginTop = innermost.style.marginRight = innermost.style.marginBottom = innermost.style.marginLeft = '0px';
      innermost.innerHTML = container.si_blockHtml;
    }
    else if(container._si_alternateHtml)
      container.innerHTML = container._si_alternateHtml;
    else if(container._si_origHtml)
      container.innerHTML = container._si_origHtml;
  },


  /*
   * injectHtml()
   *   Inserts Flash Player instantiation HTML code in the given container, and issues a test for presence of the Flash Blocker. 
   *
   * In:
   *   html:        Flash Player instantiation HTML code
   *   containerID: Element to populate
   *
   * Returns:
   *   true:  container element was populated
   *   false: container element was not found 
   * 
   * Postcondition:
   *   The container element is populated with the given Flash Player instantiation HTML code. If the Flash Blocker is found after yielding, the original HTML code is restored.
   */

  injectHtml: function(html, containerID)
  {
    // Replace taget's inner objects (possibly ststic image(s)):
    var container;
    if(containerID==null)
      containerID = 'banner';
    if(containerID.tagName!=null)
      container = containerID;
    else
      container = window.document.getElementById(containerID);
    if(container!=null)
    {
      containerID = SiDomHelp.mkElementId(container);

      // Yield and test for Flash block:
      setTimeout('SiFlash.testBlocker("' + containerID + '")', 100);

      container._si_origHtml = container.innerHTML;
      container.si_blockHtml = '';
      for(var i=0; i<container.childNodes.length; i++)
      {
        var node = container.childNodes[i];
        if(SiDomHelp.isClass(node, SIL_CONFIG.FLASH.BLOCKER.CLASSNAME))
          container.si_blockHtml += SiDomHelp.getOuterHTML(node).replace(/flashblock/g, SIL_CONFIG.FLASH.BLOCKER.REPLACEMENT_CLASSNAME);
      }
      
      container.innerHTML='';
      var obj = document.createElement('span');
      obj.style.width='100%';
      obj.style.height='100%';
      obj.innerHTML = html;
      container.appendChild(obj);
      return(true);
    }
    else
      return(false);
  },


  /*
   * SiFlash.create()
   *   Writes code to the document to load an SWF movie, circumvents the "grey 
   *   box of death" or "Click to activate and use this control"-misfeature (aka
   *   "EOLAS problem") in IE. 
   *
   *   This approach avoids the layout flicker of the otherwise neather approach 
   *   with scripted "cut/paste-replace" <object> tags included in the HTML page.
   *
   *   Called by inline-script during document load (containerID==null) or after 
   *   load from an event handler (containerID!=null).
   *
   *   See http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/overview/activating_activex.asp.
   *
   * In:
   *   URL:         URL of the Flash movie to load
   *   variables:   Variables to pass to the Flash movie. Variables can be 
   *                passed as an URL encoded string or as an associative array.
   *   styles:      (optional) Styles to assign to the new Flash control
   *   containerID: (optional) ID of element to receive the Flash control HTML
   *   baseURL:     (optional) Base URL for relative paths in the Flash movie
   "                   URL: Given URL is the base
   *                   "@": Path of the Flash movie is the base
   *                   Default: Path of the current document is the base
   *   wmode:       (optional) Window mode, default is "opaque"
   *   bgcolor:     (optional) Background color, default is #ffffff
   *   width:       (optional) Width of the new Flash control
   *   height:      (optional) Height of the new Flash control
   *   ctrlId:      ID of the new Flash control
   *   ctrlClass:   Class name of the new Flash control, default is 'swf'
   *
   * One or more of the attributes id, URL, vars and styles may be arrays to 
   * create multiple controls.
   *   
   *
   * Pre condition: 
   *   Document is loading (use containerID==null)
   *   Document is loaded (use containerID!=null)
   *
   * Post condition: 
   *   The container element is populated with Flash Player instantiation HTML code. If the Flash Blocker is found after yielding, the original HTML code is restored.
   */

  create: function(URL, 
                   variables, 
                   styles, 
                   containerID, 
                   baseURL, 
                   wmode,
                   bgcolor,
                   width, 
                   height, 
                   ctrlId,
                   ctrlClass)
  {
    return(SiFlash.injectHtml(SiFlash.createHtml(URL, 
                                                 variables, 
                                                 styles, 
                                                 baseURL, 
                                                 wmode,
                                                 bgcolor,
                                                 width, 
                                                 height, 
                                                 ctrlId,
                                                 ctrlClass), 
                              containerID));
  },

  /*
   * APA: _killSwfControls()
   *   Kills all flash player controls on the page, if any.
   */

  killAll: function()
  {
    var count=0;
    $('OBJECT').each(function() // APA: 'EMBED'??
    {
      debugger;
      if(this.type.indexOf('shockwave-flash')!=-1)
      {
        var container = this.parentNode.parentNode;
        if(container._si_origHtml)
          container.innerHTML = container._si_origHtml;
        else
          container.innerHTML = '';
        count++;
      }
    });
    return(count);
  }
}


/*===========================================================================
 *
 * static class Media content
 *   FLV Player instantiation. 
 */

SiFlvPlayer = {

  create: function(configuration, styles)
  {
    if(!styles)
      styles = 'width:100%;height:500px';
    var cfg = new Array(SiTargetGroup.get(), SIL_CONFIG.TARGET_GROUPS.DEFAULT_NAME);
    for(var i = 0; i < cfg.length; i++)
      cfg[i] = configuration.replace(/%targetgroup%/, cfg[i]);
    cfg = (SiTools.ends(configuration, '.flv') ? 'video=' : 'config=') + cfg.join(';');
    SiFlash.create(SIL_CONFIG.MEDIA.FLV.PLAYER.URL,         // URL
                   cfg,                                     // variables
                   styles,                                  // styles
                   'banner',                                // containerID
                   '@',                                     // baseURL
                    null,                                   // wmode
                    null,                                   // bgcolor
                    null,                                   // width
                    null,                                   // height
                    SIL_CONFIG.MEDIA.PLAYER.ID,             // ctrlId
                    SIL_CONFIG.MEDIA.FLV.PLAYER.CLASSNAME); // ctrlClass
  }

}

/*===========================================================================
 *
 * static class Media content
 *   Media Player instantiation. 
 *   All media links contained in "media containers" are made to open an inline
 *   Media Player when clicked upon. Only one (1) Media Player can be 
 *   simultaneously open in a document; any already opened playes are closed 
 *   when clicking other media links. 
 *
 *   If Flash Player is installed and not blocked, videos will be played using 
 *   the "FLV player". Otherwise videos will be played usng the system media 
 *   player.
 */

SiMedia = {

  /*
   * install()
   *   Creates inline media players for all media links in the DOM.
   *
   * Returns:
   *   n/a
   */

  install: function()
  {
    $(SIL_CONFIG.MEDIA.SELECTOR).each(function(){SiMedia._containerInit(this);});
  },


  /*
   * reset()
   *   Resets (the currenty active media) control.
   *
   * Returns:
   *   n/a
   *
   * Post condition: 
   *   If a media player was open, it is closed.
   */

  reset: function()
  {
    $('#' + SIL_CONFIG.MEDIA.PLAYER.ID).each(function()
    {
      var ctrl = this;
      
      // Try to stop the movie first:
      try
      {
        ctrl.Pause();
        ctrl.URL = null;
      }
      catch(e){}
      
      // Find the container:
      while(ctrl!=null && ctrl._si_origHtml==null)
        ctrl = ctrl.parentNode;

      // Kill the player + yield before reinstalling original HTML code to avoid lockups in IE:
      ctrl.innerHTML = '<br/><br /><br /><br />';
      setTimeout(function()
      {
        ctrl.innerHTML = ctrl._si_origHtml;
        SiMedia._containerInit(ctrl);
      }, 10);
    });
  },


  /*
   * _launch()
   *   Launches a media player called from a media link.
   */

  _launch: function(type, URL, container)
  {
    SiMedia.reset();
    
    var prefixHtml = new SiHtml('a', {style: 'display: inline; float: right; margin: -40px 0px 30px 0px; background: none',
                                      href: '#',
                                      onclick: 'SiMedia.reset(this);return false;'});
    prefixHtml.addChild(new SiHtml('img', {style: 'margin: 0px', src: SIL_CONFIG.MEDIA.PLAYER.UI.CLOSEBTN}));
    prefixHtml = prefixHtml.ToString();
    
                     //APA:+ '<a style="display: inline; float: right; margin: -40px 0px 40px 0px" href="#" onclick="siL_configMediaControl(this);return false;"><img src="' + SIL_CONFIG.MEDIA.PLAYER.UI.SETTINGSBTN + '" /></a>'
    var wmfHtml    = SiMedia._createHtml(URL);
    var flvHtml    = SiFlash.createHtml(SIL_CONFIG.MEDIA.FLV.PLAYER.URL,          // URL
                                        'video=' + URL.replace(/\.wmv$/, '.flv'), // variables
                                        null,                                     // styles
                                        null,                                     // baseURL
                                        null,                                     // wmode
                                        SIL_CONFIG.MEDIA.PLAYER.UI.BGCOLOR,       // bgcolor
                                        null,                                     // width
                                        null,                                     // height
                                        SIL_CONFIG.MEDIA.PLAYER.ID);              // ctrlId
                                        
    container._si_alternateHtml = prefixHtml + wmfHtml;
    if(container._si_origHtml==null)
      container._si_origHtml = container.innerHTML;
    if(flvHtml)
      SiFlash.injectHtml(prefixHtml + flvHtml, container);
    else
      container.innerHTML = prefixHtml + wmfHtml;
    SiDomHelp.scrollIntoView(container.parentNode);
  },


  /*
   * createHtml()
   *  Creates Media Player instantiation HTML code
   */

  _createHtml: function(URL)
  {
    var style = 'background: #000000 url(/common/images/_fw_mediawaitscreen.jpg) no-repeat center center';

    var obj = new SiHtml('object', {className: SIL_CONFIG.MEDIA.WMV.PLAYER.CLASSNAME, 
                                    id:        SIL_CONFIG.MEDIA.PLAYER.ID, 
                                    classid:   'CLSID:22D6F312-B0F6-11D0-94AB-0080C74C7E95', 
                                    standby:   SIL_CONFIG.MEDIA.WMV.PLAYER.STDBY_MSG, 
                                    type:      'application/x-oleobject',
                                    style:     style});
    obj.addChild(new SiHtml('param', {name: 'FileName',          value: URL}));
    obj.addChild(new SiHtml('param', {name: 'autostart',         value: 'true'}));
    obj.addChild(new SiHtml('param', {name: 'EnableContextMenu', value: 'true'}));
    obj.addChild(new SiHtml('param', {name: 'ShowControls',      value: 'true'}));
    obj.addChild(new SiHtml('param', {name: 'ShowStatusBar',     value: 'false'}));
    obj.addChild(new SiHtml('param', {name: 'ShowDisplay',       value: 'false'}));
    obj.addChild(new SiHtml('embed', {className:         SIL_CONFIG.MEDIA.WMV.PLAYER.CLASSNAME,
                                      type:              'application/x-mplayer2',
                                      src:               URL,
                                      name:              SIL_CONFIG.MEDIA.PLAYER.ID,
                                      id:                SIL_CONFIG.MEDIA.PLAYER.ID,
                                      EnableContextMenu: '1',
                                      ShowControls:      '1',
                                      ShowStatusBar:     '0',
                                      ShowDisplay:       '0',
                                      autostart:         '1',
                                      style:             style}));

    return(obj.ToString());
  },


  /*
   * _containerInit()
   *   Initializes a media container
   */

  _containerInit: function(container)
  {
    $(container).find('A').each(function()
    {
      var fileType = this.href.replace(/.*\.(\w+)$/, '$1');
      switch(fileType)
      {
        case 'wmv':
        case 'flv':
          //Note: use native click handler as jq won't let us set this twice (?):
          this.onclick = function()
          {
            SiMedia._launch(fileType, this.href, this.parentNode);
            return(false);
          };
          break;
      }
    });
  }
}



/*===========================================================================
 *
 * static class SiMailLinks
 *   Decoding e-mail links
 *
 */

SiMailLinks = {

  /*
   * install()
   *   Decodes the link and display name of all e-mail links in the DOM
   *
   * Returns:
   *   n/a
   * 
   * Postcondition:
   *   Encoded e-mail links are decoded.
   */

  install: function()
  {
    $('A[href*=/ilmail/?], A[href*=/mailto/?]').each(function()
    {
      this.href      = SiMailLinks._decode(this.href);
      this.innerHTML = SiMailLinks._decode(this.innerHTML);
    });
  },


  /*
   * _decode()
   *   Decodes the link and display of a e-mail link.
   */

  _decode: function(value)
  {
    return(value.replace(/.*\/mailto[^\?]*\?/, 'mailto:')
                .replace(/.*\/ilmail[^\?]*\?/, 'mailto:')
                .replace(/\{at?\}/g, '@')
                .replace(/\(at?\)/g, '@')
                .replace(/\/at?\//g, '@')
                .replace(/\{d(ot)?\}/g, '.')
                .replace(/\(d(ot)?\)/g, '.')
                .replace(/\/d(ot)?\//g, '.')
                .replace(/@removethis/, ''));
  }
}



/*===========================================================================
 *
 * static class SiActiveLinks
 *   Creation of active links, i.e. hover effects, 'this document' links indicated as 'current'
 *
 */

SiActiveLinks = {

  /*
   * install()
   *   Makes links in the DOM 'active', installs hovecr scripts etc.
   *
   * Returns:
   *   n/a
   * 
   * Postcondition:
   *   Hover scripts installed, 'this document' links indicated as 'current'
   */

  install: function()
  {
    $(SIL_CONFIG.ACTIVE_LINKS.SELECTOR.ROOT).find(SIL_CONFIG.ACTIVE_LINKS.SELECTOR.ELEM).each(function(){SiActiveLinks._attachLink(this)});
  },


  /*
   * _attachLink()
   *   Attaches hover scripts to the given link
   */

  _attachLink: function(linkElm)
  {
    // Skip page links and empty links:
    var href = linkElm.getAttribute('href', 2);
    href = SiURL.strip(href);
    if(href=='' || href!=null && href.charAt(0)=='#')
      return;

    // Find a related element containing a image:
    var imageElm = linkElm;
    var imageUrl = imageElm.src;
    if(!imageUrl)
      imageUrl = $(imageElm).css('background-image');
    if(imageUrl=='none')
    {
      imageElm = $(linkElm).find('IMG').get(0);
      if(imageElm)
        imageUrl = imageElm.src;
    }
    if(imageUrl=='none')
    {
      imageElm = linkElm.parentNode;
      imageUrl = $(imageElm).css('background-image');
    }
    if(imageUrl=='none')
    {
      imageElm = $(linkElm.parentNode).find('IMG').get(0);
      if(imageElm)
        imageUrl = imageElm.src;
    }
    if(imageUrl=='none')
      imageElm = null;


    // This is a link to the current page; set 'current' properties:  
    if(SiURL.isCurrent(href))
    {
      SiActiveLinks._setImage(imageElm, imageUrl.replace(new RegExp('\\b' + SIL_CONFIG.ACTIVE_LINKS.IMAGE.DEFAULT_SUBSTR + '\\b'), SIL_CONFIG.ACTIVE_LINKS.IMAGE.ACTIVE_SUBSTR));
      $(linkElm).addClass(SIL_CONFIG.ACTIVE_LINKS.CURRENT_PAGE_CLASS);
      if(linkElm!=imageElm)
        $(imageElm).addClass(SIL_CONFIG.ACTIVE_LINKS.CURRENT_PAGE_CLASS);
    } 
    // Set up hover scripts:
    else if(imageElm && imageUrl.indexOf(SIL_CONFIG.ACTIVE_LINKS.IMAGE.DEFAULT_SUBSTR)!=-1)
      SiActiveLinks._assignEvents(linkElm, imageElm, imageUrl);
  },


  /*
   * _setImage()
   *   Sets the (foreground or background) image of an element
   */

  _setImage: function(element, url)
  {
    if((element==null)||(url==null))
      return;
    if(element.tagName=='IMG' || (element.tagName=='INPUT' && element.src!=null && element.src!=''))
    {
      // Trap image load errors; reset to default image if error is called:
      if(!element.onerror)
      {
        element.onerror = function()
        {
          // Avoid posting events to itself in case of error loading default image:
          if(!element.src.match(new RegExp('\\b' + SIL_CONFIG.ACTIVE_LINKS.IMAGE.DEFAULT_SUBSTR + '\\b')))
            element.src = element.src.replace(new RegExp('\\b(' + SIL_CONFIG.ACTIVE_LINKS.IMAGE.HOVER_SUBSTR + '|' + SIL_CONFIG.ACTIVE_LINKS.IMAGE.ACTIVE_SUBSTR + ')\\b'), SIL_CONFIG.ACTIVE_LINKS.IMAGE.DEFAULT_SUBSTR);
        }
      }
      element.src=url;
    }
    else
      element.style.backgroundImage=url;
  },


  /*
   * _assignEvents()
   *   Assigns image switching mouse event hanndlers to a link
   */

  _assignEvents: function(linkElm, imageElm, imageUrl)
  {
    if(linkElm._si_hoverkilroy)
      return;      
    linkElm._si_hoverkilroy = true;

    var hoverImg = imageUrl.replace(new RegExp('\\b' + SIL_CONFIG.ACTIVE_LINKS.IMAGE.DEFAULT_SUBSTR + '\\b'), SIL_CONFIG.ACTIVE_LINKS.IMAGE.HOVER_SUBSTR);
    SiActiveLinks._cache(hoverImg);

    $(linkElm).mouseover(function()
    {
      // [c1]
      if(window.SiActiveLinks._setImage!=null)
        window.SiActiveLinks._setImage(imageElm, hoverImg);
      if(true)
        $(imageElm).addClass(SIL_CONFIG.ACTIVE_LINKS.HOVER_CLASS);
    });

    $(linkElm).mouseout(function()
    {
      // [c1]
      if(window.SiActiveLinks._setImage!=null)
        window.SiActiveLinks._setImage(imageElm, imageUrl);
      if(true)
        $(imageElm).removeClass(SIL_CONFIG.ACTIVE_LINKS.HOVER_CLASS);
    });
  },


  /*
   * _cache()
   *   Caches the given inage
   */

  _cache: function(imageUrl)
  {
    if(SiActiveLinks._imageCache==null)
      SiActiveLinks._imageCache = new Array();
    imageUrl = imageUrl.replace(/url\(["']*([^"']*)["']*\)/i, '$1');
    for(var i=0; i<SiActiveLinks._imageCache.length; i++)
    {
      if(SiActiveLinks._imageCache[i].src==imageUrl)
        return;
    }
    var img = new Image();
    img.src = imageUrl;
    SiActiveLinks._imageCache.push(img);
  }

}



/*===========================================================================
 *
 * static class SiSplash
 *   Splash (contact) "windows".
 *
 *   Splash windows are used to allow the user to fill in various forms 
 *   without leaving the current web page. 
 *
 *   Splash windows can be displayed either by the user clicking on a link 
 *   with the "splash class", or requested via the document URL using a 
 *   "splash argument". This is typically used when entering the site from a 
 *   campaign banner or similar. When the user is has completed the form, a 
 *   (unique) cookie, the name based on the form URL, is set to remember this 
 *   form as ‘done’. This will prevent the form from showing again via the 
 *   document URL. Note that the cookie is set regardless of if the splash 
 *   form was displayed as a result of the user clicking a link or if the 
 *   splash form was requested via the document URL. Also note that the user 
 *   can always get to the splash form via a link, even if the ‘done’ cookie 
 *   is set.
 *
 *   The splash window calls up the corresponding form page in an <IFRAME> 
 *   with an additional argument “framed”. The form should be displayed 
 *   without page decorations when called this way. This allows for nice 
 *   degrading of splash link clicks, and also allows a user to open the 
 *   form in a separate window or tab (Shift+click, Ctrl+click), as the form 
 *   in these cases can be displayed with page decorations. 
 *
 *   Splash windows are modal but cancelable. When displayed, the rest of the 
 *   document is dimmed and "disabled". If the user clicks outside the splash 
 *   window, the splash window is closed and the document reappears. 
 *
 *   Only one (1) splash window can be simultaneously displayed.
 */

SiSplash = {

  _id:     null,
  _canvas: null,
  _anchor: null,


  /*
   * install()
   *   - For the topmost window: Installs splash script popup on all splash links
   *   - For child (splash) window: Attahces splash close handler to 'done' form button(s)
   *
   * Returns:
   *   n/a
   * 
   * Postcondition:
   *   - Topmost window: event handler installed on all splash links
   *   - For child (splash) window: event handler installed on 'done' form button(s)
   */

  install: function()
  {
    if(SiDomHelp.topWindow()==window)
    {
      // For top window: launch splash form for all splashform links:
      $(SIL_CONFIG.SPLASH.LINK_SELECTOR).click(function(event)
      {
        if(!event.ctrlKey && !event.shiftKey)
          return(!SiSplash.show(this.href, this));
        else
          return(true);
      });
    }
    else
    {
      // For child window (i.e. splash form iframe): handle 'done' form button:
      $(SIL_CONFIG.SPLASH.DONEBUTTON_SELECTOR).click(function(event)
      {
        SiSplash.done(); 
        return(false);
      });
    }
  },


  /*
   * show()
   *   Creates splash popup if requested via the document URL, if not previously 'done'.
   *
   * show(splashUrl, anchorElement)
   *   Shows splash popup
   *
   * In:
   *   splashUrl:     URL to the splash document, default form handler prefix will be inserted if not present.
   *   anchorElement: anchor element to open the splash relative
   *
   * Returns:
   *   n/a
   * 
   * Postcondition:
   *   Splash window is opened
   */

  show: function(splashUrl, anchorElement)
  {
    if(SiSplash._canvas!=null)
      return;
      
    var forceOpen = false;
    if(splashUrl==null)
    {
      var winUrl=window.location.href;
      if(winUrl.match(SIL_CONFIG.SPLASH.LOCATION_PATTERN))
        splashUrl=winUrl.replace(SIL_CONFIG.SPLASH.LOCATION_PATTERN, '$1');
    }
    else
      forceOpen = true;

    if(splashUrl!=null)
    {
      if(splashUrl.indexOf('.htm')==-1)
        splashUrl += '.html';
      if(!splashUrl.match(SIL_CONFIG.SPLASH.URL.PREFIX_PATTERN))
        splashUrl = SIL_CONFIG.SPLASH.URL.PREFIX + splashUrl;
      splashUrl = SiURL.mkLocal(splashUrl);
      var splashID = 'splash_' + splashUrl;    
      if(forceOpen || !SiCookies.get(splashID))
      {
        SiSplash._createCanvas(splashUrl, anchorElement);
        SiSplash._id = splashID;
      }
    }
    return(true);
  },


  /*
   * done()
   *   Confirms that a the current splash window is 'done'; stores the 'done' flag in an persistent cookie and closes the window. 
   *
   * Returns:
   *   n/a
   * 
   * Postcondition:
   *   'Done' cookie stored and splash window closed.
   */

  done: function()
  {
    var topWin = SiDomHelp.topWindow();
    if(window==topWin)
    {
      SiCookies.set(SiSplash._id, 'kilroy', true);
      SiSplash.close();
    }
    else if(topWin.SiSplash!=null)
      topWin.SiSplash.done();
    else
      alert('Warning: Page called out of context');
  },


  /*
   * close()
   *   Closes the current splash window.
   *
   * Returns:
   *   n/a
   *
   * Postcondition:
   *   Splash window closed.
   */

  close: function()
  {
    var topWin = SiDomHelp.topWindow();
    if(window==topWin)
    {
      if(SiSplash._canvas!=null)
      {
        SiSplash._canvas.style.visibility='hidden';
        SiSplash._canvas.parentNode.removeChild(SiSplash._canvas);
        SiSplash._canvas = null;
      }
    }
    else if(topWin.SiSplash!=null)
      topWin.SiSplash.close();
    else
      alert('Warning: Page called out of context');
  },


  /*
   * _layout()
   *   Layouts the splash window accordig to the size if the hosted document
   */

  _layout: function(show)
  {
    if(SiSplash._canvas==null)
      return;

    var box    = SiSplash._canvas.childNodes[SiSplash._canvas.childNodes.length-1];
    var frame  = SiSplash._canvas.getElementsByTagName('IFRAME')[0];

    var docHeight = box.offsetHeight;
    var docWidth  = box.offsetWidth;

    try
    {
      var doc;
      var win;
      if(frame.contentDocument!=null)
      {
        doc = frame.contentDocument;
        win = doc.defaultView;
      }
      else if(frame.contentWindow!=null)
      {
        win = frame.contentWindow;
        doc = win.document;
      }
      if(doc!=null && doc.body!=null)
      {
        if(doc.body.parentNode.scrollWidth > 64)
          docWidth  = doc.body.parentNode.scrollWidth;
        if(doc.body.parentNode.scrollHeight > 64)
          docHeight = doc.body.parentNode.scrollHeight;
        frame.style.height = docHeight + 'px';
        frame.style.width = docWidth + 'px';
        
        if(win.SiLayout.initialize!=null)
          win.SiLayout.initialize();
      }
    }
    catch(e){};
    
    var scroller = SiDomHelp.getDocumentScroller();
    if(SiSplash._anchor!=null && box!=null)
    {
      var anchorPos = SiDomHelp.getAbsolutePoint(SiSplash._anchor);
      if(anchorPos.y - scroller.scrollTop > scroller.clientHeight/2)
        box.style.top = Math.max(scroller.scrollTop, anchorPos.y - docHeight) + 'px';
      else
        box.style.top = anchorPos.y + 'px';
      var cw = scroller.clientWidth - 64;
      if(anchorPos.x + docWidth > cw)
        box.style.left = Math.max(0, cw - docWidth) + 'px';
      else
        box.style.left = anchorPos.x + 'px';
    }
    else
    {
      box.style.top = (scroller.clientHeight - docHeight)/2 + 'px';
      box.style.left = (scroller.clientWidth - docWidth)/2 + 'px';
    }
  },


  /*
   * _createCanvas()
   *   Creates the splash canvas with splash window decorations and hosting <iframe>.
   */

  _createCanvas: function(splashUrl, anchorElement)
  {
    SiSplash._anchor = anchorElement;
    if(SiSplash._canvas!=null)
      SiSplash._canvas.innerHTML = '';
    else
      SiSplash._canvas = document.createElement('DIV');
    var canvas = SiSplash._canvas;
    
    canvas.className=SIL_CONFIG.SPLASH.UI.CANVAS_CLASS;
    canvas.onclick=function(event)
    {
      var element;
      if(window.event!=null) // Typically IE
        element=window.event.srcElement;
      else // Typically W3C compliant
        element=event.target;
      if(element.id==SIL_CONFIG.SPLASH.UI.OUTSIDE_ID)
        SiSplash.close();
    }

    var cover = document.createElement('DIV');
    cover.id = SIL_CONFIG.SPLASH.UI.OUTSIDE_ID;
    cover.style.height = SiDomHelp.getDocumentScroller().scrollHeight + 'px';
    canvas.appendChild(cover);

    var box = document.createElement('TABLE');
    box.className = 'sipsplashbox';
    var container;
    for(var r=0; r<3; r++)
    {
      var row = box.insertRow(-1);
      for(var c=0; c<3; c++)
      {
        var cell = row.insertCell(-1);
        cell.className = SIL_CONFIG.SPLASH.UI.DECORATION.FRAME_BASE_CLASS + ' ' + SIL_CONFIG.SPLASH.UI.DECORATION.FRAME_INDEX_CLASS + r + 'c' + c;
        if(r==1 && c==1)
          container = cell;
      }
    }
    container.className = SIL_CONFIG.SPLASH.UI.DECORATION.CONTAINER_CLASS;
    if(splashUrl!=null)
      container.innerHTML = '<iframe onload="SiSplash._layout(true)" scrolling="no" frameborder="0" src="' + splashUrl + '&layout=framed" />';
    canvas.appendChild(box);
    
    window.document.body.appendChild(canvas);
    SiSplash._layout(false);
  }
}



/*===========================================================================
 *
 * static class SiMenu
 *   Menu system.
 */

SiMenu = {
  install: function()
  {
    $('#toc').each(function()
    {
      if(window.sim_init!=null)
        sim_init();
    });
  }
}



/*===========================================================================
 *
 * static class SiDocumentPopup
 *   Makes links to documents (e.g. PDF files) to load content via the 
 *   streamdown script (setting an attachement HTTP header which makes them escape the browser).
 *
 */

SiDocumentPopup = {

  /*
   * install()
   *   - Installs click handler on all document links
   *   - Adds "document popup" class to all document links, i.e. shows a "popup" icon next to the links. 
   *
   * Returns:
   *   n/a
   * 
   * Postcondition:
   *   Click hanlders installed in all document liks
   */

  install: function()
  {
    $(SIL_CONFIG.DOCUMENTPOPUP.SELECTOR).click(SiDocumentPopup._popup)
                                        .addClass(SIL_CONFIG.DOCUMENTPOPUP.CLASS);
  },


  /*
   * _popup()
   *   Called when user clicks a document link. 
   *   Cancels the click and launches loading via the 'streamdown' script.
   */

  _popup: function()
  {
    /* Get the file title from:
     *   a) the link's or link's parent's title attribute
     *   b) first title ot alt attribute of the children
     */
    var title = this.title || this.parentNode.title;
    if(!title)
      title = $(this).find('*[title]').attr('title') || $(this).find('*[alt]').attr('alt');
    if(title)
      title = '&filename=' + encodeURI(title) + '.' + this.href.replace(/.*\.([^.]*)$/, '$1');
    else
      title = '';
    window.location.href='/common/php2/streamdown.php?file=' + this.href + title;
    return(false);
  }
}



/*===========================================================================
 *
 * static class SiTrack
 *   Tracking code installation
 *
 */

SiTrack = {

  /*
   * install()
   *   Installs Google Analytics tracking scripts
   *
   * Returns:
   *   n/a
   * 
   * Postcondition:
   *   Analytics code linked to the document
   */

  install: function()
  {
    if(!SiURL.isTestServer())
    {
      var pageTracker;
      var script = document.createElement('script');
      script.src = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.") + 'google-analytics.com/ga.js';
      script.type = 'text/javascript';
      script._si_loadkilroy = false;

      // 
      script.onload = function () 
      {
        script._si_loadkilroy = true;
        SiTrack.initiate();
      };

      // 
      script.onreadystatechange = function() 
      {
        if (('loaded' === script.readyState || 'complete' === script.readyState) && !script._si_loadkilroy)
        {
          script._si_loadkilroy = true;
          SiTrack.initiate();
        }
      };
      document.getElementsByTagName('head')[0].appendChild(script);
    }
  },


  /*
   * initiate()
   *   Call Google Analytics tracking
   *
   * Returns:
   *   n/a
   * 
   * Postcondition:
   *   The page is tracked.
   */

  initiate: function()
  {
    if(!SiURL.isTestServer() && window._gat!=null)
    {
      try
      {
        SiTrack._pageTracker = _gat._getTracker(SIL_CONFIG.ANALYTICS.CODE);
        SiTrack._pageTracker._setDomainName(SIL_CONFIG.ANALYTICS.DOMAIN);
        SiTrack._pageTracker._setAllowLinker(true);
        SiTrack._pageTracker._initData();
        SiTrack._pageTracker._trackPageview();
      }
      catch(e){}
    }
  },

  /*
   * initiate()
   *   Call Google Analytics tracking
   *
   * Returns:
   *   n/a
   * 
   * Postcondition:
   *   The page is tracked.
   */

  footprint: function(value)
  {
    if(!SiURL.isTestServer() && SiTrack._pageTracker!=null)
    {
      try
      {
        SiTrack._pageTracker._trackPageview(value);
      }
      catch(e){}
    }
  }
}



/*===========================================================================
 *
 * static class SiUnsupported
 *   Resolving unsupported features, i.e. making IE6 to behave
 *
 */

SiUnsupported = {

  /*
   * install()
   *   Installs handling of unsupported features on related objects in the DOM
   *
   * Returns:
   *   n/a
   * 
   * Postcondition:
   *   Unsupported features installed
   */

  install: function()
  {
    // Set up magic IE styles:
    if(DETECT.is_ieLt7 && window.si_iecss_init!=null)
    {
      si_iecss_init(SIL_CONFIG.UNSUPPORTED_FIXES.IESTYLES_ID);
      $('STYLE').each(function()
      {
        if(!this.disabled)
          si_iecss_init(this);
      });
    }

    if(DETECT.is_ieLt7)
    {
      $(SIL_CONFIG.UNSUPPORTED_FIXES.PNG_SELECTOR).each(function()
      {
        // Create a substitute element:
        var substitute = document.createElement('span');
        substitute.innerHTML = '&nbsp;';
        this.insertAdjacentElement('afterEnd', substitute);

        // Copy the current style to the div to keep the complete positioning:
        for(var name in this.currentStyle)
          substitute.style[name]=this.currentStyle[name];

        // Get implicit size correct:
        if(!substitute.style.width || substitute.style.width=='auto')
          substitute.style.width = this.offsetWidth;
        if(!substitute.style.height || substitute.style.height=='auto')
          substitute.style.height = this.offsetHeight;

        // Set the magic alpha filter:
        substitute.style.filter='progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + this.src + '", sizingMethod="scale")';

        // Hide the original image (don't remove it as it still might be referred to by other scripts):
        this.style.display='none';
      });
    }
  }
}




/*===========================================================================
 *
 * static class SiDebug
 *   Debug menu
 *
 */

// #PRAGMA COMPACT SKIP START

SiDebug = {


  /*
   * install()
   *   Creates the debug menu if the page is loaded from a test server
   *
   * Returns:
   *   n/a
   * 
   * Postcondition:
   *   Debug menu possibly created
   */

  install: function()
  {
    if(!SIP_DEBUG.ENABLE)
      return;

    if(!SiURL.isTestServer())
      return;

    if(SiDomHelp.topWindow()._si_debugkilroy==true)
      return;
    SiDomHelp.topWindow()._si_debugkilroy=true;

    var menu = document.createElement('div');
    menu.style.position='absolute';
    menu.style.left='0px';
    menu.style.top='0px';
    menu.style.width='140px';
    menu.style.padding='0px';
    menu.style.zIndex='100';

    menu.onmouseover=function(){
      this.style.clip='rect(auto auto auto auto)';
    }
    
    menu.onmouseout=function(){
      this.style.clip='rect(0px 20px 20px 0px)';
    }
    
    menu.onmouseout();

    var html = '<img src="/common/styles/images/_fw_authoringmenuico.gif" width="20" height="20" />';
    html += '<div style="border: 4px double #2060a0; background: #ffffff; padding: 2px 4px 2px 4px; margin: 0px; font: normal 9px Arial, Helvetica, sans-serif">';
    html += SiDebug._link('<span style="float: right; font-weight: bold; font-size: 7pt; background-color: #ffffff; margin: 1px; padding: 0px 2px"><a href="/admin/guide/stb/page_popup.html">?</a></span>Authoring menu', null, 'font-weight: bold; font-size: 8pt; padding: 0px 4px; color: #ffffff; background-color: #2060a0; margin-bottom: 4px; ');
    html += SiDebug._link('Edit file in Dreamweaver', 'SiDebug._command(null, \'DREAMWEAVER\')');
    html += SiDebug._link('Edit file in Code Editor', 'SiDebug._command(null, \'CODEEDITOR\')');
    html += SiDebug._link('Explore work folder', 'SiDebug._command(null, \'EXPLORE\')');
    html += SiDebug._link('Copy work location', 'SiDebug._command(null, \'COPY\')');
    html += SiDebug._link('---');
    html += SiDebug._link('Start debugger', 'javascript:debugger');
    html += SiDebug._link('List cookies', 'SiDebug._command(null, \'LISTCOOKIES\')');
    html += SiDebug._link('Remove cookies', 'SiDebug._command(null, \'RMCOOKIES\')');
    html += SiDebug._link('Kill SWF Ctrls', 'SiDebug._command(null, \'KILLSWF\')');
    html += SiDebug._link('---');
    html += SiDebug._link('Open at www', window.location.href.replace(/http:\/\/[^\/]*(.*)/, 'http://www.sectra.se$1'));
    html += SiDebug._link('Open at web-devel', window.location.href.replace(/http:\/\/[^\/]*(.*)/, 'http://web-devel.sectra.se$1'));
    html += SiDebug._link('Open at edit', window.location.href.replace(/http:\/\/[^\/]*(.*)/, 'http://edit.sectra.se$1'));
    html += SiDebug._link('Open at localhost', window.location.href.replace(/http:\/\/[^\/]*(.*)/, 'http://localhost$1'));
    html += SiDebug._link('Open at tarrekaise', window.location.href.replace(/http:\/\/[^\/]*(.*)/, 'http://tarrekaise.sectra.se:8089$1'));
    html += SiDebug._link('---');
    html += SiDebug._link('EDIT', 'http://edit.sectra.se/admin/composer/edit.php');
    html += SiDebug._link('---');
    html += SiDebug._link('Group reset', '/common/php2/targetgroup.php?reset');
    html += SiDebug._link('Group set all', '/common/php2/targetgroup.php?all');
    html += SiDebug._link('Group show / edit', '/common/php2/targetgroup.php?show');
    html += SiDebug._link('Show group CSS', '/common/php2/targetgroup.php?css');
    html += SiDebug._link('Show group JS', '/common/php2/targetgroup.php?js');
    html += SiDebug._link('---');
    html += SiDebug._link('Browser:<br/>&nbsp;&nbsp;<b>' + navigator.userAgent + '</b>');
    html += '</div>';
    menu.innerHTML = html;
    window.document.body.appendChild(menu);
  },


  /*
   * _link()
   *   Returns code for a debug menu link
   */

  _link: function(caption, action, style)
  {
    if(!style)
      style='';
    style = '; display: block; margin: 0px; padding: 0px; ' + style;
    if(caption.charAt(0)=='-')
      return('<hr size="1" color="#2060a0" noshade="1" width="80" />');
    else if(action)
    {
      if(action.indexOf('(')!=-1)
        return('<a style="color: #203060' + style + '" href="#" onclick="' + action + '; return false">&bull;&nbsp;' + caption + '</a>');
      else
        return('<a style="color: #203060' + style + '" href="' + action + '">&bull;&nbsp;' + caption + '</a>');
    }
    else
      return('<span style="color: #000000' + style + '">' + caption + '</span>');
  },


  /*
   * _command()
   *   Runs a debug menu command
   */

  _command: function(url, tool)
  {
    if(url==null)
      url = SiURL.getCurrentPath();
    if(url.charAt(url.length-1)=='/')
      url += 'index.html';

    switch(tool)
    {
      case null:
        tool = 'DREAMWEAVER';
        break;
    }

    switch(tool)
    {
      case 'KILLSWF':
        var count = SiFlash.killAll();
        if(count)
          alert('Killed ' + count + ' SWF controls')
        else
          alert('No SWF controls to kill')
        break;
      case 'COPY':
        window.clipboardData.setData('Text', SIP_DEBUG.SITE_ROOT + url.replace(/\//g, '\\'));
        break;
      case 'LISTCOOKIES':
      case 'RMCOOKIES':
        var cookies = document.cookie.split('; ');
        var msg='';
        for (var i=0; i < cookies.length; i++)
        {
          if(cookies[i])
          {
            var crumb = cookies[i].split('=');
            msg += '- ' + crumb[0] + ':\n      "' + crumb[1] + '"\n';
          }
        }
        if(msg)
        {
          if(tool=='RMCOOKIES')
          {
            if(confirm('Remove the cookies at ' + window.location.hostname + '?\n' + msg))
              alert('Removed ' + SiCookies.removeAll() + ' cookies');
          }
          else   
            alert('Cookies at ' + window.location.hostname + ':\n' + msg);
        }
        else
          alert('No cookies at ' + window.location.hostname + '.');
        break;
      case 'EXPLORE':
        url = url.replace(/\/[^\/]*\.[^\/]*$/, '/').replace(/\//g, '\\');
      default:
        SiDebug._edit(url, tool);
        break;
    }
  },


  /*
   * _edit()
   *   Tries to start an editor
   */

  _edit: function(url, editor)
  {
    var errMsg;
    for(var i=0; i<SIP_DEBUG[editor].length; i++)
    {
      try
      {
        var wsh = new ActiveXObject('WScript.Shell');
        wsh.Exec(SIP_DEBUG[editor][i] + ' "' + SIP_DEBUG.SITE_ROOT + url.replace(/\//g, '\\') + '"');
        return;
      }
      catch(e)
      {
        errMsg = e.message;
      }
    }
    if(confirm('Could not start ' + editor + ': ' + errMsg + '\n\nDo you want to show help?'))
      window.open('/admin/guide/install_and_configure.html#Configurewebbrowsers');
  }


  /*
   * _killSwfControl()
   *   Kills a flash player control.
   */
/*APA:
  _killSwfControl: function(control)
  {
    if(control.type.indexOf('shockwave-flash')==-1)
      return(false);
    var container = control.parentNode.parentNode;
    container.innerHTML = container._si_origHtml;
    return(true);
  },
*/

  /*
   * _killSwfControls()
   *   Kills all flash player controls on the page, if any.
   */
/*APA:
  _killSwfControls: function()
  {
    var objs = window.document.getElementsByTagName('OBJECT');
    if(objs.length==0)
      objs = window.document.getElementsByTagName('EMBED');
    var count=0;
    for(var i=0; i<objs.length; i++)
    {
      if(SiDebug._killSwfControl(objs[i]))
        count++;
    }
    return(count);
  }  
*/  
}

// #PRAGMA COMPACT SKIP END


/*===========================================================================
 *
 * static class SiLayout
 *   Main Layout class
 *
 */

SiLayout = {

  /*
   * initImmediate()
   *   Installations to run immediate.
   */

  initImmediate: function()
  {
    // Debug menu:
    SiDebug.install();

    // Create active links:
    SiActiveLinks.install();
    
    // Handling of splashforms:
    SiSplash.install();

    // Handling of media files:
    SiMedia.install();
    
    // Mail links:
    SiMailLinks.install();
    
    // Handling of folding lists:
    $(SIL_CONFIG.FOLDING_LIST.SELECTOR).click(function() 
    {
      //debugger;
	    $(this).children().toggle('fast');
      
      if(!$(this).hasClass('open'))
        $(this).addClass('open');
      else
        $(this).removeClass('open');
	    return(false);
    }).children().hide();

    // Handling of expandcontainers:
    $(SIL_CONFIG.EXPAND_CONTAINER.SELECTOR).click(function(event) 
    {
      //debugger;
	    if(event.target.tagName!='A')
	    {
	      $(this).children(':nth-child(+n+4)').toggle('fast');
	      return(false);
	    }
	    else
  	    return(true);
    }).find(':nth-child(+n+4)').hide();


    /*
    // Stylized headigs:
    $('#message h1').each(function() 
    {
      var w = this.offsetWidth - SiDomHelp.getStyle(this, 'paddingLeft') - SiDomHelp.getStyle(this, 'paddingRight') - SiDomHelp.getStyle(this, 'marginLeft') - SiDomHelp.getStyle(this, 'marginRight');
      var h = this.offsetHeight - SiDomHelp.getStyle(this, 'paddingTop') - SiDomHelp.getStyle(this, 'paddingBottom');
      if(h>5)
      {
        SiFlash.create('/common/swf/Text.swf',   // URL
                       'text=' + this.innerHTML, // variables
                       null,                     // styles
                       this,                     // containerID
                       null,                     // baseURL
                       null,                     // wmode
                       null,                     // bgcolor
                       w,                        // width
                       h,                        // height
                       null);                    // ctrlId
      }
    });
    */

    // Menu system:
    SiMenu.install();

    // Document popups:
    SiDocumentPopup.install();

    // Make IE6 behave:
    SiUnsupported.install();

    // Set keyboard focus I(II):
    $(SIL_CONFIG.KBD_FOCUS.PAGE_SELECTOR).eq(0).each(function()
    {
      if(document.createRange!=null)
      {
        // DOM compliant, set selection to the H1:
        var range = window.getSelection();
        range.collapse(this, 0);
      }
      else //APA: if(document.body.createTextRange!=null)
      {
        /* IE: set the tabIndex attribute on the H1 and focus it. A negative 
         * tabIndex will make the element to remain unfocusable but still respond 
         * to the focus() method:
         */
        try
        {
          this.tabIndex = -1;
          this.focus();
        }
        catch(e){}
      }
    });

    // Set keyboard focus II(II). Focus first form field in the document:
    $(SIL_CONFIG.KBD_FOCUS.FORM_SELECTOR).eq(0).select();


    /*
     * Set up defualt text & styl in the minisearch field:
     */
    $(SIL_CONFIG.MINISEARCH.SELECTOR).attr('value', SIL_CONFIG.MINISEARCH.INPUT_DEFAULT_VALUE)
                                     .addClass(SIL_CONFIG.MINISEARCH.INPUT_DEFAULT_CLASS)
                                     .focus(function()
                                     {
                                       if(this.value == SIL_CONFIG.MINISEARCH.INPUT_DEFAULT_VALUE)
                                       {
                                         this.value = '';
                                         $(this).removeClass(SIL_CONFIG.MINISEARCH.INPUT_DEFAULT_CLASS);
                                       }
                                     })
                                     .blur(function()
                                     {
                                       if(this.value == '' || this.value == SIL_CONFIG.MINISEARCH.INPUT_DEFAULT_VALUE)
                                       {
                                         this.value = SIL_CONFIG.MINISEARCH.INPUT_DEFAULT_VALUE;
                                         $(this).addClass(SIL_CONFIG.MINISEARCH.INPUT_DEFAULT_CLASS);
                                       }
                                     });
    // Make Ctrl+Shift+F focus the minisearch field:
    $(document).keydown(function(event)
    {
      if(event.keyCode==70 && event.ctrlKey && event.shiftKey) // Ctrl+Shift+F
        $(SIL_CONFIG.MINISEARCH.SELECTOR).focus();
    });


    // Call document defined scripts:
    if(window.whenDocumentLoaded!=null)
      whenDocumentLoaded();
      
  },


  /*
   * initDeferred()
   *   Installations to run deferred.
   */

  initDeferred: function()
  {
    // Google analytics:
    SiTrack.install();

    // Call document defined scripts:
    if(window.whenDocumentComplete!=null)
      whenDocumentComplete();  
  }  
}



/*===========================================================================
 *
 * "Main"
 *
 */

// Run only for browsers that has a DOM:
if(window.document.getElementsByTagName!=null)
{
  $(document).ready(SiLayout.initImmediate);
  $(window).load(SiLayout.initDeferred);
}

// EoF
